From aefff4915632185e286c8c94f6f5ccb939fc51d7 Mon Sep 17 00:00:00 2001 From: Colin Ian King <colin.king@canonical.com> Date: Tue, 15 May 2018 09:54:33 +0100 Subject: [PATCH 0001/1506] drm/xen-front: fix spelling mistake: "conector" -> "connector" Trivial fix to spelling mistake in DRM_INFO message. Signed-off-by: Colin Ian King <colin.king@canonical.com> Reviewed-by: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com> Signed-off-by: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180515085433.8245-1-colin.king@canonical.com --- drivers/gpu/drm/xen/xen_drm_front.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xen/xen_drm_front.c b/drivers/gpu/drm/xen/xen_drm_front.c index 3345ac71b391f..93bf9f092086b 100644 --- a/drivers/gpu/drm/xen/xen_drm_front.c +++ b/drivers/gpu/drm/xen/xen_drm_front.c @@ -623,7 +623,7 @@ static int displback_initwait(struct xen_drm_front_info *front_info) if (ret < 0) return ret; - DRM_INFO("Have %d conector(s)\n", cfg->num_connectors); + DRM_INFO("Have %d connector(s)\n", cfg->num_connectors); /* Create event channels for all connectors and publish */ ret = xen_drm_front_evtchnl_create_all(front_info); if (ret < 0) -- GitLab From 584a0146ec4989f30d0aef46ce1ea6f6ba22a690 Mon Sep 17 00:00:00 2001 From: Philippe Cornu <philippe.cornu@st.com> Date: Mon, 9 Apr 2018 17:24:27 +0200 Subject: [PATCH 0002/1506] drm: clarify adjusted_mode documentation for bridges This patch clarifies the adjusted_mode documentation for bridges. Signed-off-by: Philippe Cornu <philippe.cornu@st.com> Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> Reviewed-by: Archit Taneja <architt@codeaurora.org> Link: https://patchwork.freedesktop.org/patch/msgid/20180409152427.12449-1-philippe.cornu@st.com --- include/drm/drm_bridge.h | 16 ++++++++++++++++ include/drm/drm_crtc.h | 11 +++++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index 3270fec469798..9917651a7fddd 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -178,6 +178,22 @@ struct drm_bridge_funcs { * then this would be &drm_encoder_helper_funcs.mode_set. The display * pipe (i.e. clocks and timing signals) is off when this function is * called. + * + * The adjusted_mode parameter is the mode output by the CRTC for the + * first bridge in the chain. It can be different from the mode + * parameter that contains the desired mode for the connector at the end + * of the bridges chain, for instance when the first bridge in the chain + * performs scaling. The adjusted mode is mostly useful for the first + * bridge in the chain and is likely irrelevant for the other bridges. + * + * For atomic drivers the adjusted_mode is the mode stored in + * &drm_crtc_state.adjusted_mode. + * + * NOTE: + * + * If a need arises to store and access modes adjusted for other + * locations than the connection between the CRTC and the first bridge, + * the DRM framework will have to be extended with DRM bridge states. */ void (*mode_set)(struct drm_bridge *bridge, struct drm_display_mode *mode, diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index a2d81d2907a93..5cf7adeae6a57 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -134,10 +134,13 @@ struct drm_crtc_state { * * Internal display timings which can be used by the driver to handle * differences between the mode requested by userspace in @mode and what - * is actually programmed into the hardware. It is purely driver - * implementation defined what exactly this adjusted mode means. Usually - * it is used to store the hardware display timings used between the - * CRTC and encoder blocks. + * is actually programmed into the hardware. + * + * For drivers using drm_bridge, this stores hardware display timings + * used between the CRTC and the first bridge. For other drivers, the + * meaning of the adjusted_mode field is purely driver implementation + * defined information, and will usually be used to store the hardware + * display timings used between the CRTC and encoder blocks. */ struct drm_display_mode adjusted_mode; -- GitLab From 1c6ccad8a4b110bac3f9ff6db954ab5a74c2e861 Mon Sep 17 00:00:00 2001 From: Tina Zhang <tina.zhang@intel.com> Date: Mon, 14 May 2018 13:59:18 +0800 Subject: [PATCH 0003/1506] drm/i915/gvt: Deliver guest cursor hotspot info Guest OS driver uses PV info registers to deliver cursor hotspot info to host. This patch is used to get cursor hotspot info from virtual registers and deliver it to host userspace. v4->v5: - remove CI warning. v3->v4: - return UINT_MAX when x_hot/y_hot is invalid. (Zhenyu) - correct version. v2->v3: - add validate_hotspot(). (Zhenyu) v1->v2: - name as cursor_x_hot/cursor_y_hot. (Zhenyu) - use i915_reg_t definition instead of magic numbers. (Zhenyu) Signed-off-by: Tina Zhang <tina.zhang@intel.com> Cc: Zhenyu Wang <zhenyuw@linux.intel.com> Cc: Zhi Wang <zhi.a.wang@intel.com> Cc: Gerd Hoffmann <kraxel@redhat.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> --- drivers/gpu/drm/i915/gvt/dmabuf.c | 22 ++++++++++++++++------ drivers/gpu/drm/i915/gvt/fb_decoder.c | 3 +++ drivers/gpu/drm/i915/gvt/handlers.c | 4 ++-- drivers/gpu/drm/i915/gvt/vgpu.c | 3 +++ drivers/gpu/drm/i915/i915_pvinfo.h | 5 ++++- 5 files changed, 28 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/dmabuf.c b/drivers/gpu/drm/i915/gvt/dmabuf.c index 6f4f8e941fc20..d2eb2f7754b9f 100644 --- a/drivers/gpu/drm/i915/gvt/dmabuf.c +++ b/drivers/gpu/drm/i915/gvt/dmabuf.c @@ -192,6 +192,14 @@ static struct drm_i915_gem_object *vgpu_create_gem(struct drm_device *dev, return obj; } +static bool validate_hotspot(struct intel_vgpu_cursor_plane_format *c) +{ + if (c && c->x_hot <= c->width && c->y_hot <= c->height) + return true; + else + return false; +} + static int vgpu_get_plane_info(struct drm_device *dev, struct intel_vgpu *vgpu, struct intel_vgpu_fb_info *info, @@ -229,12 +237,14 @@ static int vgpu_get_plane_info(struct drm_device *dev, info->x_pos = c.x_pos; info->y_pos = c.y_pos; - /* The invalid cursor hotspot value is delivered to host - * until we find a way to get the cursor hotspot info of - * guest OS. - */ - info->x_hot = UINT_MAX; - info->y_hot = UINT_MAX; + if (validate_hotspot(&c)) { + info->x_hot = c.x_hot; + info->y_hot = c.y_hot; + } else { + info->x_hot = UINT_MAX; + info->y_hot = UINT_MAX; + } + info->size = (((info->stride * c.height * c.bpp) / 8) + (PAGE_SIZE - 1)) >> PAGE_SHIFT; } else { diff --git a/drivers/gpu/drm/i915/gvt/fb_decoder.c b/drivers/gpu/drm/i915/gvt/fb_decoder.c index 1c120683e9588..5e7468bd1b368 100644 --- a/drivers/gpu/drm/i915/gvt/fb_decoder.c +++ b/drivers/gpu/drm/i915/gvt/fb_decoder.c @@ -36,6 +36,7 @@ #include <uapi/drm/drm_fourcc.h> #include "i915_drv.h" #include "gvt.h" +#include "i915_pvinfo.h" #define PRIMARY_FORMAT_NUM 16 struct pixel_format { @@ -384,6 +385,8 @@ int intel_vgpu_decode_cursor_plane(struct intel_vgpu *vgpu, plane->y_pos = (val & _CURSOR_POS_Y_MASK) >> _CURSOR_POS_Y_SHIFT; plane->y_sign = (val & _CURSOR_SIGN_Y_MASK) >> _CURSOR_SIGN_Y_SHIFT; + plane->x_hot = vgpu_vreg_t(vgpu, vgtif_reg(cursor_x_hot)); + plane->y_hot = vgpu_vreg_t(vgpu, vgtif_reg(cursor_y_hot)); return 0; } diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c index 4b6532fb789a2..d5e2066610484 100644 --- a/drivers/gpu/drm/i915/gvt/handlers.c +++ b/drivers/gpu/drm/i915/gvt/handlers.c @@ -1204,8 +1204,8 @@ static int pvinfo_mmio_write(struct intel_vgpu *vgpu, unsigned int offset, ret = handle_g2v_notification(vgpu, data); break; /* add xhot and yhot to handled list to avoid error log */ - case 0x78830: - case 0x78834: + case _vgtif_reg(cursor_x_hot): + case _vgtif_reg(cursor_y_hot): case _vgtif_reg(pdp[0].lo): case _vgtif_reg(pdp[0].hi): case _vgtif_reg(pdp[1].lo): diff --git a/drivers/gpu/drm/i915/gvt/vgpu.c b/drivers/gpu/drm/i915/gvt/vgpu.c index 2e0a02a80fe4d..bf75300c1ec16 100644 --- a/drivers/gpu/drm/i915/gvt/vgpu.c +++ b/drivers/gpu/drm/i915/gvt/vgpu.c @@ -58,6 +58,9 @@ void populate_pvinfo_page(struct intel_vgpu *vgpu) vgpu_vreg_t(vgpu, vgtif_reg(avail_rs.fence_num)) = vgpu_fence_sz(vgpu); + vgpu_vreg_t(vgpu, vgtif_reg(cursor_x_hot)) = UINT_MAX; + vgpu_vreg_t(vgpu, vgtif_reg(cursor_y_hot)) = UINT_MAX; + gvt_dbg_core("Populate PVINFO PAGE for vGPU %d\n", vgpu->id); gvt_dbg_core("aperture base [GMADR] 0x%llx size 0x%llx\n", vgpu_aperture_gmadr_base(vgpu), vgpu_aperture_sz(vgpu)); diff --git a/drivers/gpu/drm/i915/i915_pvinfo.h b/drivers/gpu/drm/i915/i915_pvinfo.h index 195203f298dfc..d61914a117566 100644 --- a/drivers/gpu/drm/i915/i915_pvinfo.h +++ b/drivers/gpu/drm/i915/i915_pvinfo.h @@ -93,7 +93,10 @@ struct vgt_if { u32 rsv5[4]; u32 g2v_notify; - u32 rsv6[7]; + u32 rsv6[5]; + + u32 cursor_x_hot; + u32 cursor_y_hot; struct { u32 lo; -- GitLab From f75f91574617a3c6fbc821c6b156f5777a59d0ed Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Tue, 15 May 2018 15:31:49 +0100 Subject: [PATCH 0004/1506] drm/i915: Shrink search list for active timelines When switching to the kernel context, we force the switch to occur after all currently active requests (so that we know the GPU won't switch immediately away and the kernel context remains current as we work). To do so we have to inspect all the timelines and add a fence from the active work to queue our switch afterwards. We can use the tracked set of active rings to shrink our search for active timelines. v2: Use a local to shrink the list_for_each_entry() Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180515143149.4795-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_context.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 33f8a4b3c9817..4bf18b5c6f1da 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -596,41 +596,44 @@ last_request_on_engine(struct i915_timeline *timeline, static bool engine_has_idle_kernel_context(struct intel_engine_cs *engine) { - struct i915_timeline *timeline; + struct list_head * const active_rings = &engine->i915->gt.active_rings; + struct intel_ring *ring; - list_for_each_entry(timeline, &engine->i915->gt.timelines, link) { - if (last_request_on_engine(timeline, engine)) + lockdep_assert_held(&engine->i915->drm.struct_mutex); + + list_for_each_entry(ring, active_rings, active_link) { + if (last_request_on_engine(ring->timeline, engine)) return false; } return intel_engine_has_kernel_context(engine); } -int i915_gem_switch_to_kernel_context(struct drm_i915_private *dev_priv) +int i915_gem_switch_to_kernel_context(struct drm_i915_private *i915) { struct intel_engine_cs *engine; - struct i915_timeline *timeline; enum intel_engine_id id; - lockdep_assert_held(&dev_priv->drm.struct_mutex); + lockdep_assert_held(&i915->drm.struct_mutex); - i915_retire_requests(dev_priv); + i915_retire_requests(i915); - for_each_engine(engine, dev_priv, id) { + for_each_engine(engine, i915, id) { + struct intel_ring *ring; struct i915_request *rq; if (engine_has_idle_kernel_context(engine)) continue; - rq = i915_request_alloc(engine, dev_priv->kernel_context); + rq = i915_request_alloc(engine, i915->kernel_context); if (IS_ERR(rq)) return PTR_ERR(rq); /* Queue this switch after all other activity */ - list_for_each_entry(timeline, &dev_priv->gt.timelines, link) { + list_for_each_entry(ring, &i915->gt.active_rings, active_link) { struct i915_request *prev; - prev = last_request_on_engine(timeline, engine); + prev = last_request_on_engine(ring->timeline, engine); if (prev) i915_sw_fence_await_sw_fence_gfp(&rq->submit, &prev->submit, -- GitLab From e7f2af7894b1ac76f2062f32724d51f23438249b Mon Sep 17 00:00:00 2001 From: Colin Ian King <colin.king@canonical.com> Date: Wed, 9 May 2018 11:16:06 +0100 Subject: [PATCH 0005/1506] drm/i915/dp: fix spelling mistakes: "seqeuncer" and "seqeuencer" Trivial fix to spelling mistakes in WARN warning message text and in comments: "seqeuncer", "seqeuencer" -> "sequencer" Signed-off-by: Colin Ian King <colin.king@canonical.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180509101606.17483-1-colin.king@canonical.com --- drivers/gpu/drm/i915/intel_dp.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index dde92e4af5d34..2cc58596ff5ab 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -513,7 +513,7 @@ vlv_power_sequencer_kick(struct intel_dp *intel_dp) uint32_t DP; if (WARN(I915_READ(intel_dp->output_reg) & DP_PORT_EN, - "skipping pipe %c power seqeuncer kick due to port %c being active\n", + "skipping pipe %c power sequencer kick due to port %c being active\n", pipe_name(pipe), port_name(intel_dig_port->base.port))) return; @@ -554,7 +554,7 @@ vlv_power_sequencer_kick(struct intel_dp *intel_dp) /* * Similar magic as in intel_dp_enable_port(). * We _must_ do this port enable + disable trick - * to make this power seqeuencer lock onto the port. + * to make this power sequencer lock onto the port. * Otherwise even VDD force bit won't work. */ I915_WRITE(intel_dp->output_reg, DP); @@ -3066,11 +3066,11 @@ static void vlv_detach_power_sequencer(struct intel_dp *intel_dp) edp_panel_vdd_off_sync(intel_dp); /* - * VLV seems to get confused when multiple power seqeuencers + * VLV seems to get confused when multiple power sequencers * have the same port selected (even if only one has power/vdd * enabled). The failure manifests as vlv_wait_port_ready() failing * CHV on the other hand doesn't seem to mind having the same port - * selected in multiple power seqeuencers, but let's clear the + * selected in multiple power sequencers, but let's clear the * port select always when logically disconnecting a power sequencer * from a port. */ @@ -5698,7 +5698,7 @@ intel_dp_init_panel_power_sequencer_registers(struct intel_dp *intel_dp, /* * On some VLV machines the BIOS can leave the VDD - * enabled even on power seqeuencers which aren't + * enabled even on power sequencers which aren't * hooked up to any port. This would mess up the * power domain tracking the first time we pick * one of these power sequencers for use since @@ -5706,7 +5706,7 @@ intel_dp_init_panel_power_sequencer_registers(struct intel_dp *intel_dp, * already on and therefore wouldn't grab the power * domain reference. Disable VDD first to avoid this. * This also avoids spuriously turning the VDD on as - * soon as the new power seqeuencer gets initialized. + * soon as the new power sequencer gets initialized. */ if (force_disable_vdd) { u32 pp = ironlake_get_pp_control(intel_dp); -- GitLab From b8444cf85b629413ad23f5b6ed9bf5267f38acab Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Wed, 16 May 2018 19:33:48 +0100 Subject: [PATCH 0006/1506] drm/i915: Remove tasklet flush before disable The idea was to try and let the existing tasklet run to completion before we began the reset, but it involves a racy check against anything else that tries to run the tasklet. Rather than acknowledge and ignore the race, let it be and don't try and be too clever. The tasklet will resume execution after reset (after spinning a bit during reset), but before we allow it to resume we will have cleared all the pending state. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180516183355.10553-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 0a2070112b66e..0dc369a9ec4d0 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3035,16 +3035,7 @@ i915_gem_reset_prepare_engine(struct intel_engine_cs *engine) * calling engine->init_hw() and also writing the ELSP. * Turning off the execlists->tasklet until the reset is over * prevents the race. - * - * Note that this needs to be a single atomic operation on the - * tasklet (flush existing tasks, prevent new tasks) to prevent - * a race between reset and set-wedged. It is not, so we do the best - * we can atm and make sure we don't lock the machine up in the more - * common case of recursively being called from set-wedged from inside - * i915_reset. */ - if (!atomic_read(&engine->execlists.tasklet.count)) - tasklet_kill(&engine->execlists.tasklet); tasklet_disable(&engine->execlists.tasklet); /* -- GitLab From f351d087d8329a08eca9e69872c3906c139e1f11 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Wed, 16 May 2018 19:33:49 +0100 Subject: [PATCH 0007/1506] drm/i915: Only sync tasklets once for recursive reset preparation When setting up reset, we may need to recursively prepare an engine. In which case we should only synchronously flush the tasklets on the outer most call, the inner calls will then be inside an atomic section where the tasklet will never be run (and so the sync will never complete). Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180516183355.10553-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 2 +- drivers/gpu/drm/i915/i915_gem.h | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 0dc369a9ec4d0..982393907b806 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3036,7 +3036,7 @@ i915_gem_reset_prepare_engine(struct intel_engine_cs *engine) * Turning off the execlists->tasklet until the reset is over * prevents the race. */ - tasklet_disable(&engine->execlists.tasklet); + __tasklet_disable_sync_once(&engine->execlists.tasklet); /* * We're using worker to queue preemption requests from the tasklet in diff --git a/drivers/gpu/drm/i915/i915_gem.h b/drivers/gpu/drm/i915/i915_gem.h index 525920404ede4..5bf24cfc218cc 100644 --- a/drivers/gpu/drm/i915/i915_gem.h +++ b/drivers/gpu/drm/i915/i915_gem.h @@ -26,6 +26,7 @@ #define __I915_GEM_H__ #include <linux/bug.h> +#include <linux/interrupt.h> struct drm_i915_private; @@ -72,4 +73,10 @@ struct drm_i915_private; void i915_gem_park(struct drm_i915_private *i915); void i915_gem_unpark(struct drm_i915_private *i915); +static inline void __tasklet_disable_sync_once(struct tasklet_struct *t) +{ + if (atomic_inc_return(&t->count) == 1) + tasklet_unlock_wait(t); +} + #endif /* __I915_GEM_H__ */ -- GitLab From ef2fb7204638f0c67446a90b75e1eae4330682f8 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Wed, 16 May 2018 19:33:50 +0100 Subject: [PATCH 0008/1506] drm/i915/execlists: Refactor out complete_preempt_context() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As a complement to inject_preempt_context(), follow up with the function to handle its completion. This will be useful should we wish to extend the duties of the preempt-context for execlists. v2: And do the same for the guc. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Jeff McGee <jeff.mcgee@intel.com> Cc: MichaÅ‚ Winiarski <michal.winiarski@intel.com> Reviewed-by: Jeff McGee <jeff.mcgee@intel.com> #v1 Link: https://patchwork.freedesktop.org/patch/msgid/20180516183355.10553-3-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_guc_submission.c | 26 ++++++++++++++------- drivers/gpu/drm/i915/intel_lrc.c | 23 ++++++++++-------- 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_guc_submission.c b/drivers/gpu/drm/i915/intel_guc_submission.c index 2feb650969665..ca38ac9ff4fad 100644 --- a/drivers/gpu/drm/i915/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/intel_guc_submission.c @@ -623,6 +623,21 @@ static void wait_for_guc_preempt_report(struct intel_engine_cs *engine) report->report_return_status = INTEL_GUC_REPORT_STATUS_UNKNOWN; } +static void complete_preempt_context(struct intel_engine_cs *engine) +{ + struct intel_engine_execlists *execlists = &engine->execlists; + + GEM_BUG_ON(!execlists_is_active(execlists, EXECLISTS_ACTIVE_PREEMPT)); + + execlists_cancel_port_requests(execlists); + execlists_unwind_incomplete_requests(execlists); + + wait_for_guc_preempt_report(engine); + intel_write_status_page(engine, I915_GEM_HWS_PREEMPT_INDEX, 0); + + execlists_clear_active(execlists, EXECLISTS_ACTIVE_PREEMPT); +} + /** * guc_submit() - Submit commands through GuC * @engine: engine associated with the commands @@ -793,15 +808,8 @@ static void guc_submission_tasklet(unsigned long data) if (execlists_is_active(execlists, EXECLISTS_ACTIVE_PREEMPT) && intel_read_status_page(engine, I915_GEM_HWS_PREEMPT_INDEX) == - GUC_PREEMPT_FINISHED) { - execlists_cancel_port_requests(&engine->execlists); - execlists_unwind_incomplete_requests(execlists); - - wait_for_guc_preempt_report(engine); - - execlists_clear_active(execlists, EXECLISTS_ACTIVE_PREEMPT); - intel_write_status_page(engine, I915_GEM_HWS_PREEMPT_INDEX, 0); - } + GUC_PREEMPT_FINISHED) + complete_preempt_context(engine); if (!execlists_is_active(execlists, EXECLISTS_ACTIVE_PREEMPT)) guc_dequeue(engine); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 7c6164d14bd85..fafa0e9bd0cde 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -552,8 +552,18 @@ static void inject_preempt_context(struct intel_engine_cs *engine) if (execlists->ctrl_reg) writel(EL_CTRL_LOAD, execlists->ctrl_reg); - execlists_clear_active(&engine->execlists, EXECLISTS_ACTIVE_HWACK); - execlists_set_active(&engine->execlists, EXECLISTS_ACTIVE_PREEMPT); + execlists_clear_active(execlists, EXECLISTS_ACTIVE_HWACK); + execlists_set_active(execlists, EXECLISTS_ACTIVE_PREEMPT); +} + +static void complete_preempt_context(struct intel_engine_execlists *execlists) +{ + GEM_BUG_ON(!execlists_is_active(execlists, EXECLISTS_ACTIVE_PREEMPT)); + + execlists_cancel_port_requests(execlists); + execlists_unwind_incomplete_requests(execlists); + + execlists_clear_active(execlists, EXECLISTS_ACTIVE_PREEMPT); } static bool __execlists_dequeue(struct intel_engine_cs *engine) @@ -1064,14 +1074,7 @@ static void execlists_submission_tasklet(unsigned long data) if (status & GEN8_CTX_STATUS_COMPLETE && buf[2*head + 1] == execlists->preempt_complete_status) { GEM_TRACE("%s preempt-idle\n", engine->name); - - execlists_cancel_port_requests(execlists); - execlists_unwind_incomplete_requests(execlists); - - GEM_BUG_ON(!execlists_is_active(execlists, - EXECLISTS_ACTIVE_PREEMPT)); - execlists_clear_active(execlists, - EXECLISTS_ACTIVE_PREEMPT); + complete_preempt_context(execlists); continue; } -- GitLab From 5adfb772f8ac1224fe4d651f3628a2e03190f5af Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Wed, 16 May 2018 19:33:51 +0100 Subject: [PATCH 0009/1506] drm/i915: Move engine reset prepare/finish to backends MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation to more carefully handling incomplete preemption during reset by execlists, we move the existing code wholesale to the backends under a couple of new reset vfuncs. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: MichaÅ‚ Winiarski <michal.winiarski@intel.com> CC: Michel Thierry <michel.thierry@intel.com> Cc: Jeff McGee <jeff.mcgee@intel.com> Reviewed-by: Jeff McGee <jeff.mcgee@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180516183355.10553-4-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 38 +++----------------- drivers/gpu/drm/i915/intel_lrc.c | 47 +++++++++++++++++++++++-- drivers/gpu/drm/i915/intel_ringbuffer.c | 23 ++++++++++-- drivers/gpu/drm/i915/intel_ringbuffer.h | 9 +++-- 4 files changed, 76 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 982393907b806..abf661d406410 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3004,7 +3004,7 @@ i915_gem_find_active_request(struct intel_engine_cs *engine) struct i915_request * i915_gem_reset_prepare_engine(struct intel_engine_cs *engine) { - struct i915_request *request = NULL; + struct i915_request *request; /* * During the reset sequence, we must prevent the engine from @@ -3027,31 +3027,7 @@ i915_gem_reset_prepare_engine(struct intel_engine_cs *engine) */ kthread_park(engine->breadcrumbs.signaler); - /* - * Prevent request submission to the hardware until we have - * completed the reset in i915_gem_reset_finish(). If a request - * is completed by one engine, it may then queue a request - * to a second via its execlists->tasklet *just* as we are - * calling engine->init_hw() and also writing the ELSP. - * Turning off the execlists->tasklet until the reset is over - * prevents the race. - */ - __tasklet_disable_sync_once(&engine->execlists.tasklet); - - /* - * We're using worker to queue preemption requests from the tasklet in - * GuC submission mode. - * Even though tasklet was disabled, we may still have a worker queued. - * Let's make sure that all workers scheduled before disabling the - * tasklet are completed before continuing with the reset. - */ - if (engine->i915->guc.preempt_wq) - flush_workqueue(engine->i915->guc.preempt_wq); - - if (engine->irq_seqno_barrier) - engine->irq_seqno_barrier(engine); - - request = i915_gem_find_active_request(engine); + request = engine->reset.prepare(engine); if (request && request->fence.error == -EIO) request = ERR_PTR(-EIO); /* Previous reset failed! */ @@ -3202,13 +3178,8 @@ void i915_gem_reset_engine(struct intel_engine_cs *engine, if (request) request = i915_gem_reset_request(engine, request, stalled); - if (request) { - DRM_DEBUG_DRIVER("resetting %s to restart from tail of request 0x%x\n", - engine->name, request->global_seqno); - } - /* Setup the CS to resume from the breadcrumb of the hung request */ - engine->reset_hw(engine, request); + engine->reset.reset(engine, request); } void i915_gem_reset(struct drm_i915_private *dev_priv, @@ -3256,7 +3227,8 @@ void i915_gem_reset(struct drm_i915_private *dev_priv, void i915_gem_reset_finish_engine(struct intel_engine_cs *engine) { - tasklet_enable(&engine->execlists.tasklet); + engine->reset.finish(engine); + kthread_unpark(engine->breadcrumbs.signaler); intel_uncore_forcewake_put(engine->i915, FORCEWAKE_ALL); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index fafa0e9bd0cde..a8f2704e377cb 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1827,8 +1827,39 @@ static int gen9_init_render_ring(struct intel_engine_cs *engine) return 0; } -static void reset_common_ring(struct intel_engine_cs *engine, - struct i915_request *request) +static struct i915_request * +execlists_reset_prepare(struct intel_engine_cs *engine) +{ + struct intel_engine_execlists * const execlists = &engine->execlists; + + GEM_TRACE("%s\n", engine->name); + + /* + * Prevent request submission to the hardware until we have + * completed the reset in i915_gem_reset_finish(). If a request + * is completed by one engine, it may then queue a request + * to a second via its execlists->tasklet *just* as we are + * calling engine->init_hw() and also writing the ELSP. + * Turning off the execlists->tasklet until the reset is over + * prevents the race. + */ + __tasklet_disable_sync_once(&execlists->tasklet); + + /* + * We're using worker to queue preemption requests from the tasklet in + * GuC submission mode. + * Even though tasklet was disabled, we may still have a worker queued. + * Let's make sure that all workers scheduled before disabling the + * tasklet are completed before continuing with the reset. + */ + if (engine->i915->guc.preempt_wq) + flush_workqueue(engine->i915->guc.preempt_wq); + + return i915_gem_find_active_request(engine); +} + +static void execlists_reset(struct intel_engine_cs *engine, + struct i915_request *request) { struct intel_engine_execlists * const execlists = &engine->execlists; unsigned long flags; @@ -1908,6 +1939,13 @@ static void reset_common_ring(struct intel_engine_cs *engine, unwind_wa_tail(request); } +static void execlists_reset_finish(struct intel_engine_cs *engine) +{ + tasklet_enable(&engine->execlists.tasklet); + + GEM_TRACE("%s\n", engine->name); +} + static int intel_logical_ring_emit_pdps(struct i915_request *rq) { struct i915_hw_ppgtt *ppgtt = rq->ctx->ppgtt; @@ -2237,7 +2275,10 @@ logical_ring_default_vfuncs(struct intel_engine_cs *engine) { /* Default vfuncs which can be overriden by each engine. */ engine->init_hw = gen8_init_common_ring; - engine->reset_hw = reset_common_ring; + + engine->reset.prepare = execlists_reset_prepare; + engine->reset.reset = execlists_reset; + engine->reset.finish = execlists_reset_finish; engine->context_pin = execlists_context_pin; engine->context_unpin = execlists_context_unpin; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 8f19349a6055e..af5a178366ed2 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -531,9 +531,20 @@ static int init_ring_common(struct intel_engine_cs *engine) return ret; } -static void reset_ring_common(struct intel_engine_cs *engine, - struct i915_request *request) +static struct i915_request *reset_prepare(struct intel_engine_cs *engine) { + if (engine->irq_seqno_barrier) + engine->irq_seqno_barrier(engine); + + return i915_gem_find_active_request(engine); +} + +static void reset_ring(struct intel_engine_cs *engine, + struct i915_request *request) +{ + GEM_TRACE("%s seqno=%x\n", + engine->name, request ? request->global_seqno : 0); + /* * RC6 must be prevented until the reset is complete and the engine * reinitialised. If it occurs in the middle of this sequence, the @@ -597,6 +608,10 @@ static void reset_ring_common(struct intel_engine_cs *engine, } } +static void reset_finish(struct intel_engine_cs *engine) +{ +} + static int intel_rcs_ctx_init(struct i915_request *rq) { int ret; @@ -2006,7 +2021,9 @@ static void intel_ring_default_vfuncs(struct drm_i915_private *dev_priv, intel_ring_init_semaphores(dev_priv, engine); engine->init_hw = init_ring_common; - engine->reset_hw = reset_ring_common; + engine->reset.prepare = reset_prepare; + engine->reset.reset = reset_ring; + engine->reset.finish = reset_finish; engine->context_pin = intel_ring_context_pin; engine->context_unpin = intel_ring_context_unpin; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 010750e8ee447..1e8bacba77542 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -423,8 +423,13 @@ struct intel_engine_cs { void (*irq_disable)(struct intel_engine_cs *engine); int (*init_hw)(struct intel_engine_cs *engine); - void (*reset_hw)(struct intel_engine_cs *engine, - struct i915_request *rq); + + struct { + struct i915_request *(*prepare)(struct intel_engine_cs *engine); + void (*reset)(struct intel_engine_cs *engine, + struct i915_request *rq); + void (*finish)(struct intel_engine_cs *engine); + } reset; void (*park)(struct intel_engine_cs *engine); void (*unpark)(struct intel_engine_cs *engine); -- GitLab From 1329115c6c4370e93813b44084ee06610c3279bd Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Wed, 16 May 2018 19:33:52 +0100 Subject: [PATCH 0010/1506] drm/i915: Split execlists/guc reset preparations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the next patch, we will make the execlists reset prepare callback take into account preemption by flushing the context-switch handler. This is not applicable to the GuC submission backend, so split the two into their own backend callbacks. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: MichaÅ‚ Winiarski <michal.winiarski@intel.com> CC: Michel Thierry <michel.thierry@intel.com> Cc: Jeff McGee <jeff.mcgee@intel.com> Reviewed-by: Jeff McGee <jeff.mcgee@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180516183355.10553-5-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_guc_submission.c | 34 +++++++++++++++++++++ drivers/gpu/drm/i915/intel_lrc.c | 12 ++------ 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_guc_submission.c b/drivers/gpu/drm/i915/intel_guc_submission.c index ca38ac9ff4fad..637e852888ec1 100644 --- a/drivers/gpu/drm/i915/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/intel_guc_submission.c @@ -815,6 +815,37 @@ static void guc_submission_tasklet(unsigned long data) guc_dequeue(engine); } +static struct i915_request * +guc_reset_prepare(struct intel_engine_cs *engine) +{ + struct intel_engine_execlists * const execlists = &engine->execlists; + + GEM_TRACE("%s\n", engine->name); + + /* + * Prevent request submission to the hardware until we have + * completed the reset in i915_gem_reset_finish(). If a request + * is completed by one engine, it may then queue a request + * to a second via its execlists->tasklet *just* as we are + * calling engine->init_hw() and also writing the ELSP. + * Turning off the execlists->tasklet until the reset is over + * prevents the race. + */ + __tasklet_disable_sync_once(&execlists->tasklet); + + /* + * We're using worker to queue preemption requests from the tasklet in + * GuC submission mode. + * Even though tasklet was disabled, we may still have a worker queued. + * Let's make sure that all workers scheduled before disabling the + * tasklet are completed before continuing with the reset. + */ + if (engine->i915->guc.preempt_wq) + flush_workqueue(engine->i915->guc.preempt_wq); + + return i915_gem_find_active_request(engine); +} + /* * Everything below here is concerned with setup & teardown, and is * therefore not part of the somewhat time-critical batch-submission @@ -1275,6 +1306,9 @@ int intel_guc_submission_enable(struct intel_guc *guc) &engine->execlists; execlists->tasklet.func = guc_submission_tasklet; + + engine->reset.prepare = guc_reset_prepare; + engine->park = guc_submission_park; engine->unpark = guc_submission_unpark; diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index a8f2704e377cb..acbdf36d1c286 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1845,16 +1845,6 @@ execlists_reset_prepare(struct intel_engine_cs *engine) */ __tasklet_disable_sync_once(&execlists->tasklet); - /* - * We're using worker to queue preemption requests from the tasklet in - * GuC submission mode. - * Even though tasklet was disabled, we may still have a worker queued. - * Let's make sure that all workers scheduled before disabling the - * tasklet are completed before continuing with the reset. - */ - if (engine->i915->guc.preempt_wq) - flush_workqueue(engine->i915->guc.preempt_wq); - return i915_gem_find_active_request(engine); } @@ -2256,6 +2246,8 @@ static void execlists_set_default_submission(struct intel_engine_cs *engine) engine->schedule = execlists_schedule; engine->execlists.tasklet.func = execlists_submission_tasklet; + engine->reset.prepare = execlists_reset_prepare; + engine->park = NULL; engine->unpark = NULL; -- GitLab From 73377dbcc754f1e673b60f238c237c5e909f92b1 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Wed, 16 May 2018 19:33:53 +0100 Subject: [PATCH 0011/1506] drm/i915/execlists: Split out CSB processing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pull the CSB event processing into its own routine so that we can reuse it during reset to flush any missed interrupts/events. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: MichaÅ‚ Winiarski <michal.winiarski@intel.com> CC: Michel Thierry <michel.thierry@intel.com> Cc: Jeff McGee <jeff.mcgee@intel.com> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180516183355.10553-6-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_lrc.c | 91 ++++++++++++++++++-------------- 1 file changed, 52 insertions(+), 39 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index acbdf36d1c286..f38391e6431a4 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -958,34 +958,14 @@ static void execlists_cancel_requests(struct intel_engine_cs *engine) local_irq_restore(flags); } -/* - * Check the unread Context Status Buffers and manage the submission of new - * contexts to the ELSP accordingly. - */ -static void execlists_submission_tasklet(unsigned long data) +static void process_csb(struct intel_engine_cs *engine) { - struct intel_engine_cs * const engine = (struct intel_engine_cs *)data; struct intel_engine_execlists * const execlists = &engine->execlists; struct execlist_port *port = execlists->port; - struct drm_i915_private *dev_priv = engine->i915; + struct drm_i915_private *i915 = engine->i915; bool fw = false; - /* - * We can skip acquiring intel_runtime_pm_get() here as it was taken - * on our behalf by the request (see i915_gem_mark_busy()) and it will - * not be relinquished until the device is idle (see - * i915_gem_idle_work_handler()). As a precaution, we make sure - * that all ELSP are drained i.e. we have processed the CSB, - * before allowing ourselves to idle and calling intel_runtime_pm_put(). - */ - GEM_BUG_ON(!dev_priv->gt.awake); - - /* - * Prefer doing test_and_clear_bit() as a two stage operation to avoid - * imposing the cost of a locked atomic transaction when submitting a - * new request (outside of the context-switch interrupt). - */ - while (test_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted)) { + do { /* The HWSP contains a (cacheable) mirror of the CSB */ const u32 *buf = &engine->status_page.page_addr[I915_HWS_CSB_BUF0_INDEX]; @@ -993,28 +973,27 @@ static void execlists_submission_tasklet(unsigned long data) if (unlikely(execlists->csb_use_mmio)) { buf = (u32 * __force) - (dev_priv->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_BUF_LO(engine, 0))); - execlists->csb_head = -1; /* force mmio read of CSB ptrs */ + (i915->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_BUF_LO(engine, 0))); + execlists->csb_head = -1; /* force mmio read of CSB */ } /* Clear before reading to catch new interrupts */ clear_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted); smp_mb__after_atomic(); - if (unlikely(execlists->csb_head == -1)) { /* following a reset */ + if (unlikely(execlists->csb_head == -1)) { /* after a reset */ if (!fw) { - intel_uncore_forcewake_get(dev_priv, - execlists->fw_domains); + intel_uncore_forcewake_get(i915, execlists->fw_domains); fw = true; } - head = readl(dev_priv->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_PTR(engine))); + head = readl(i915->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_PTR(engine))); tail = GEN8_CSB_WRITE_PTR(head); head = GEN8_CSB_READ_PTR(head); execlists->csb_head = head; } else { const int write_idx = - intel_hws_csb_write_index(dev_priv) - + intel_hws_csb_write_index(i915) - I915_HWS_CSB_BUF0_INDEX; head = execlists->csb_head; @@ -1023,8 +1002,8 @@ static void execlists_submission_tasklet(unsigned long data) } GEM_TRACE("%s cs-irq head=%d [%d%s], tail=%d [%d%s]\n", engine->name, - head, GEN8_CSB_READ_PTR(readl(dev_priv->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_PTR(engine)))), fw ? "" : "?", - tail, GEN8_CSB_WRITE_PTR(readl(dev_priv->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_PTR(engine)))), fw ? "" : "?"); + head, GEN8_CSB_READ_PTR(readl(i915->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_PTR(engine)))), fw ? "" : "?", + tail, GEN8_CSB_WRITE_PTR(readl(i915->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_PTR(engine)))), fw ? "" : "?"); while (head != tail) { struct i915_request *rq; @@ -1034,7 +1013,8 @@ static void execlists_submission_tasklet(unsigned long data) if (++head == GEN8_CSB_ENTRIES) head = 0; - /* We are flying near dragons again. + /* + * We are flying near dragons again. * * We hold a reference to the request in execlist_port[] * but no more than that. We are operating in softirq @@ -1143,15 +1123,48 @@ static void execlists_submission_tasklet(unsigned long data) if (head != execlists->csb_head) { execlists->csb_head = head; writel(_MASKED_FIELD(GEN8_CSB_READ_PTR_MASK, head << 8), - dev_priv->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_PTR(engine))); + i915->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_PTR(engine))); } - } + } while (test_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted)); - if (!execlists_is_active(execlists, EXECLISTS_ACTIVE_PREEMPT)) - execlists_dequeue(engine); + if (unlikely(fw)) + intel_uncore_forcewake_put(i915, execlists->fw_domains); +} - if (fw) - intel_uncore_forcewake_put(dev_priv, execlists->fw_domains); +/* + * Check the unread Context Status Buffers and manage the submission of new + * contexts to the ELSP accordingly. + */ +static void execlists_submission_tasklet(unsigned long data) +{ + struct intel_engine_cs * const engine = (struct intel_engine_cs *)data; + + GEM_TRACE("%s awake?=%d, active=%x, irq-posted?=%d\n", + engine->name, + engine->i915->gt.awake, + engine->execlists.active, + test_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted)); + + /* + * We can skip acquiring intel_runtime_pm_get() here as it was taken + * on our behalf by the request (see i915_gem_mark_busy()) and it will + * not be relinquished until the device is idle (see + * i915_gem_idle_work_handler()). As a precaution, we make sure + * that all ELSP are drained i.e. we have processed the CSB, + * before allowing ourselves to idle and calling intel_runtime_pm_put(). + */ + GEM_BUG_ON(!engine->i915->gt.awake); + + /* + * Prefer doing test_and_clear_bit() as a two stage operation to avoid + * imposing the cost of a locked atomic transaction when submitting a + * new request (outside of the context-switch interrupt). + */ + if (test_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted)) + process_csb(engine); + + if (!execlists_is_active(&engine->execlists, EXECLISTS_ACTIVE_PREEMPT)) + execlists_dequeue(engine); /* If the engine is now idle, so should be the flag; and vice versa. */ GEM_BUG_ON(execlists_is_active(&engine->execlists, -- GitLab From 63572937cebf5d229a87fb11b201864f7d0b8171 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Wed, 16 May 2018 19:33:54 +0100 Subject: [PATCH 0012/1506] drm/i915/execlists: Flush pending preemption events during reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Catch up with the inflight CSB events, after disabling the tasklet before deciding which request was truly guilty of hanging the GPU. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: MichaÅ‚ Winiarski <michal.winiarski@intel.com> CC: Michel Thierry <michel.thierry@intel.com> Cc: Jeff McGee <jeff.mcgee@intel.com> Cc: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180516183355.10553-7-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_lrc.c | 36 +++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index f38391e6431a4..a83273c66d49e 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1844,6 +1844,7 @@ static struct i915_request * execlists_reset_prepare(struct intel_engine_cs *engine) { struct intel_engine_execlists * const execlists = &engine->execlists; + struct i915_request *request, *active; GEM_TRACE("%s\n", engine->name); @@ -1858,7 +1859,40 @@ execlists_reset_prepare(struct intel_engine_cs *engine) */ __tasklet_disable_sync_once(&execlists->tasklet); - return i915_gem_find_active_request(engine); + /* + * We want to flush the pending context switches, having disabled + * the tasklet above, we can assume exclusive access to the execlists. + * For this allows us to catch up with an inflight preemption event, + * and avoid blaming an innocent request if the stall was due to the + * preemption itself. + */ + if (test_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted)) + process_csb(engine); + + /* + * The last active request can then be no later than the last request + * now in ELSP[0]. So search backwards from there, so that if the GPU + * has advanced beyond the last CSB update, it will be pardoned. + */ + active = NULL; + request = port_request(execlists->port); + if (request) { + unsigned long flags; + + spin_lock_irqsave(&engine->timeline.lock, flags); + list_for_each_entry_from_reverse(request, + &engine->timeline.requests, + link) { + if (__i915_request_completed(request, + request->global_seqno)) + break; + + active = request; + } + spin_unlock_irqrestore(&engine->timeline.lock, flags); + } + + return active; } static void execlists_reset(struct intel_engine_cs *engine, -- GitLab From 3f6e9822308127104a7bb007ca569f2c57d03b67 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Wed, 16 May 2018 19:33:55 +0100 Subject: [PATCH 0013/1506] drm/i915: Stop parking the signaler around reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We cannot call kthread_park() from softirq context, so let's avoid it entirely during the reset. We wanted to suspend the signaler so that it would not mark a request as complete at the same time as we marked it as being in error. Instead of parking the signaling, stop the engine from advancing so that the GPU doesn't emit the breadcrumb for our chosen "guilty" request. v2: Refactor setting STOP_RING so that we don't have the same code thrice Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: MichaÅ‚t Winiarski <michal.winiarski@intel.com> CC: Michel Thierry <michel.thierry@intel.com> Cc: Jeff McGee <jeff.mcgee@intel.com> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180516183355.10553-8-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 14 ------------ drivers/gpu/drm/i915/intel_engine_cs.c | 29 +++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_lrc.c | 6 +++++ drivers/gpu/drm/i915/intel_ringbuffer.c | 2 ++ drivers/gpu/drm/i915/intel_ringbuffer.h | 2 ++ drivers/gpu/drm/i915/intel_uncore.c | 12 +++------- 6 files changed, 42 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index abf661d406410..b0fe452ce17cd 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3015,18 +3015,6 @@ i915_gem_reset_prepare_engine(struct intel_engine_cs *engine) */ intel_uncore_forcewake_get(engine->i915, FORCEWAKE_ALL); - /* - * Prevent the signaler thread from updating the request - * state (by calling dma_fence_signal) as we are processing - * the reset. The write from the GPU of the seqno is - * asynchronous and the signaler thread may see a different - * value to us and declare the request complete, even though - * the reset routine have picked that request as the active - * (incomplete) request. This conflict is not handled - * gracefully! - */ - kthread_park(engine->breadcrumbs.signaler); - request = engine->reset.prepare(engine); if (request && request->fence.error == -EIO) request = ERR_PTR(-EIO); /* Previous reset failed! */ @@ -3229,8 +3217,6 @@ void i915_gem_reset_finish_engine(struct intel_engine_cs *engine) { engine->reset.finish(engine); - kthread_unpark(engine->breadcrumbs.signaler); - intel_uncore_forcewake_put(engine->i915, FORCEWAKE_ALL); } diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index 6bfd7e3ed1524..d4e159ae65a61 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -769,6 +769,35 @@ u64 intel_engine_get_last_batch_head(const struct intel_engine_cs *engine) return bbaddr; } +int intel_engine_stop_cs(struct intel_engine_cs *engine) +{ + struct drm_i915_private *dev_priv = engine->i915; + const u32 base = engine->mmio_base; + const i915_reg_t mode = RING_MI_MODE(base); + int err; + + if (INTEL_GEN(dev_priv) < 3) + return -ENODEV; + + GEM_TRACE("%s\n", engine->name); + + I915_WRITE_FW(mode, _MASKED_BIT_ENABLE(STOP_RING)); + + err = 0; + if (__intel_wait_for_register_fw(dev_priv, + mode, MODE_IDLE, MODE_IDLE, + 1000, 0, + NULL)) { + GEM_TRACE("%s: timed out on STOP_RING -> IDLE\n", engine->name); + err = -ETIMEDOUT; + } + + /* A final mmio read to let GPU writes be hopefully flushed to memory */ + POSTING_READ_FW(mode); + + return err; +} + const char *i915_cache_level_str(struct drm_i915_private *i915, int type) { switch (type) { diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index a83273c66d49e..493e6bd9e28ad 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1879,6 +1879,12 @@ execlists_reset_prepare(struct intel_engine_cs *engine) if (request) { unsigned long flags; + /* + * Prevent the breadcrumb from advancing before we decide + * which request is currently active. + */ + intel_engine_stop_cs(engine); + spin_lock_irqsave(&engine->timeline.lock, flags); list_for_each_entry_from_reverse(request, &engine->timeline.requests, diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index af5a178366ed2..6f200a7471767 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -533,6 +533,8 @@ static int init_ring_common(struct intel_engine_cs *engine) static struct i915_request *reset_prepare(struct intel_engine_cs *engine) { + intel_engine_stop_cs(engine); + if (engine->irq_seqno_barrier) engine->irq_seqno_barrier(engine); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 1e8bacba77542..61f385a924845 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -878,6 +878,8 @@ int intel_init_bsd_ring_buffer(struct intel_engine_cs *engine); int intel_init_blt_ring_buffer(struct intel_engine_cs *engine); int intel_init_vebox_ring_buffer(struct intel_engine_cs *engine); +int intel_engine_stop_cs(struct intel_engine_cs *engine); + u64 intel_engine_get_active_head(const struct intel_engine_cs *engine); u64 intel_engine_get_last_batch_head(const struct intel_engine_cs *engine); diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 448293eb638d3..b36a3b5736a0e 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -1702,15 +1702,9 @@ static void gen3_stop_engine(struct intel_engine_cs *engine) { struct drm_i915_private *dev_priv = engine->i915; const u32 base = engine->mmio_base; - const i915_reg_t mode = RING_MI_MODE(base); - - I915_WRITE_FW(mode, _MASKED_BIT_ENABLE(STOP_RING)); - if (__intel_wait_for_register_fw(dev_priv, - mode, MODE_IDLE, MODE_IDLE, - 500, 0, - NULL)) - DRM_DEBUG_DRIVER("%s: timed out on STOP_RING\n", - engine->name); + + if (intel_engine_stop_cs(engine)) + DRM_DEBUG_DRIVER("%s: timed out on STOP_RING\n", engine->name); I915_WRITE_FW(RING_HEAD(base), I915_READ_FW(RING_TAIL(base))); POSTING_READ_FW(RING_HEAD(base)); /* paranoia */ -- GitLab From 579e2f6d999991d2d2dd39c7185cba0a97137cee Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Wed, 15 Mar 2017 17:39:50 +0000 Subject: [PATCH 0014/1506] drm/i915/gvt: Use offsetofend() rather than offsetof + sizeof Compute the offset of the end of the crc32 field using offsetofend() rather than open-coding. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Zhenyu Wang <zhenyuw@linux.intel.com> Cc: Zhi Wang <zhi.a.wang@intel.com> Reviewed-by: Mika Kuoppala <mika.kuoppala@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> --- drivers/gpu/drm/i915/gvt/firmware.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gvt/firmware.c b/drivers/gpu/drm/i915/gvt/firmware.c index a73e1d418c228..4ac18b4472476 100644 --- a/drivers/gpu/drm/i915/gvt/firmware.c +++ b/drivers/gpu/drm/i915/gvt/firmware.c @@ -162,7 +162,7 @@ static int verify_firmware(struct intel_gvt *gvt, h = (struct gvt_firmware_header *)fw->data; - crc32_start = offsetof(struct gvt_firmware_header, crc32) + 4; + crc32_start = offsetofend(struct gvt_firmware_header, crc32); mem = fw->data + crc32_start; #define VERIFY(s, a, b) do { \ -- GitLab From 3257ec797d3a8c5232389eb1952d4451e80f3931 Mon Sep 17 00:00:00 2001 From: Maxime Ripard <maxime.ripard@bootlin.com> Date: Thu, 17 May 2018 15:37:59 +0200 Subject: [PATCH 0015/1506] drm/vc4: plane: Expand the lower bits by repeating the higher bits The vc4 HVS uses an internal RGB888 representation of the frames, and will by default expand formats using a lower depth using zeros. This causes an issue when we try to use other compositing software such as pixman that fill the missing bits by repeating the higher significant bits. As such, we can't check the display output in a reliable way by doing a software composition and an hardware one and compare both. To prevent this, force the same behaviour so that we can do such things. Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Signed-off-by: Eric Anholt <eric@anholt.net> Link: https://patchwork.freedesktop.org/patch/msgid/20180517133759.25626-1-maxime.ripard@bootlin.com --- drivers/gpu/drm/vc4/vc4_plane.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 3483c05cc3d6d..6e8984aee613f 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -544,6 +544,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane, /* Control word */ vc4_dlist_write(vc4_state, SCALER_CTL0_VALID | + VC4_SET_FIELD(SCALER_CTL0_RGBA_EXPAND_ROUND, SCALER_CTL0_RGBA_EXPAND) | (format->pixel_order << SCALER_CTL0_ORDER_SHIFT) | (format->hvs << SCALER_CTL0_PIXEL_FORMAT_SHIFT) | VC4_SET_FIELD(tiling, SCALER_CTL0_TILING) | -- GitLab From 5d435b46fa68c53af8dc3a69ff2936b8f17aa294 Mon Sep 17 00:00:00 2001 From: Philippe Cornu <philippe.cornu@st.com> Date: Tue, 15 May 2018 22:37:36 +0200 Subject: [PATCH 0016/1506] drm/bridge: spelling and coding style minor fixes Minor fixes detected with "scripts/checkpatch.pl --strict" Signed-off-by: Philippe Cornu <philippe.cornu@st.com> Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180515203736.9224-1-philippe.cornu@st.com --- include/drm/drm_bridge.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index 9917651a7fddd..70131ab57e8f2 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -97,7 +97,7 @@ struct drm_bridge_funcs { /** * @mode_fixup: * - * This callback is used to validate and adjust a mode. The paramater + * This callback is used to validate and adjust a mode. The parameter * mode is the display mode that should be fed to the next element in * the display chain, either the final &drm_connector or the next * &drm_bridge. The parameter adjusted_mode is the input mode the bridge @@ -301,15 +301,15 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge, struct drm_bridge *previous); bool drm_bridge_mode_fixup(struct drm_bridge *bridge, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode); + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); enum drm_mode_status drm_bridge_mode_valid(struct drm_bridge *bridge, const struct drm_display_mode *mode); void drm_bridge_disable(struct drm_bridge *bridge); void drm_bridge_post_disable(struct drm_bridge *bridge); void drm_bridge_mode_set(struct drm_bridge *bridge, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode); + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); void drm_bridge_pre_enable(struct drm_bridge *bridge); void drm_bridge_enable(struct drm_bridge *bridge); -- GitLab From 50525c332b55f899fb231d786931d0b45a3f3d41 Mon Sep 17 00:00:00 2001 From: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> Date: Tue, 15 May 2018 16:59:27 +0300 Subject: [PATCH 0017/1506] drm: content-type property for HDMI connector MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added content_type property to drm_connector_state in order to properly handle external HDMI TV content-type setting. v2: * Moved helper function which attaches content type property to the drm core, as was suggested. Removed redundant connector state initialization. v3: * Removed caps in drm_content_type_enum_list. After some discussion it turned out that HDMI Spec 1.4 was wrongly assuming that IT Content(itc) bit doesn't affect Content type states, however itc bit needs to be manupulated as well. In order to not expose additional property for itc, for sake of simplicity it was decided to bind those together in same "content type" property. v4: * Added it_content checking in intel_digital_connector_atomic_check. Fixed documentation for new content type enum. v5: * Moved patch revision's description to commit messages. v6: * Minor naming fix for the content type enumeration string. v7: * Fix parameter name for documentation and parameter alignment in order not to get warning. Added Content Type description to new HDMI connector properties section. v8: * Thrown away unneeded numbers from HDMI content-type property description. Switch to strings desription instead of plain definitions. v9: * Moved away hdmi specific content-type enum from drm_connector_state. Content type property should probably not be bound to any specific connector interface in drm_connector_state. Same probably should be done to hdmi_picture_aspect_ration enum which is also contained in drm_connector_state. Added special helper function to get derive hdmi specific relevant infoframe fields. v10: * Added usage description to HDMI properties kernel doc. v11: * Created centralized function for filling HDMI AVI infoframe, based on correspondent DRM property value. Acked-by: Hans Verkuil <hans.verkuil@cisco.com> Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180515135928.31092-2-stanislav.lisovskiy@intel.com [vsyrjala: clean up checkpatch multiple blank lines warnings] Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> --- Documentation/gpu/drm-kms.rst | 6 ++ Documentation/gpu/kms-properties.csv | 1 + drivers/gpu/drm/drm_atomic.c | 4 + drivers/gpu/drm/drm_connector.c | 113 +++++++++++++++++++++++++++ drivers/gpu/drm/drm_edid.c | 8 ++ include/drm/drm_connector.h | 13 +++ include/drm/drm_mode_config.h | 5 ++ include/uapi/drm/drm_mode.h | 7 ++ 8 files changed, 157 insertions(+) diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index 1dffd1ac4cd44..e233c2626bd01 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -517,6 +517,12 @@ Standard Connector Properties .. kernel-doc:: drivers/gpu/drm/drm_connector.c :doc: standard connector properties +HDMI Specific Connector Properties +----------------------------- + +.. kernel-doc:: drivers/gpu/drm/drm_connector.c + :doc: HDMI connector properties + Plane Composition Properties ---------------------------- diff --git a/Documentation/gpu/kms-properties.csv b/Documentation/gpu/kms-properties.csv index 07ed22ea3bd67..bfde04eddd148 100644 --- a/Documentation/gpu/kms-properties.csv +++ b/Documentation/gpu/kms-properties.csv @@ -17,6 +17,7 @@ Owner Module/Drivers,Group,Property Name,Type,Property Values,Object attached,De ,Virtual GPU,“suggested Xâ€,RANGE,"Min=0, Max=0xffffffff",Connector,property to suggest an X offset for a connector ,,“suggested Yâ€,RANGE,"Min=0, Max=0xffffffff",Connector,property to suggest an Y offset for a connector ,Optional,"""aspect ratio""",ENUM,"{ ""None"", ""4:3"", ""16:9"" }",Connector,TDB +,Optional,"""content type""",ENUM,"{ ""No Data"", ""Graphics"", ""Photo"", ""Cinema"", ""Game"" }",Connector,TBD i915,Generic,"""Broadcast RGB""",ENUM,"{ ""Automatic"", ""Full"", ""Limited 16:235"" }",Connector,"When this property is set to Limited 16:235 and CTM is set, the hardware will be programmed with the result of the multiplication of CTM by the limited range matrix to ensure the pixels normaly in the range 0..1.0 are remapped to the range 16/255..235/255." ,,“audioâ€,ENUM,"{ ""force-dvi"", ""off"", ""auto"", ""on"" }",Connector,TBD ,SDVO-TV,“modeâ€,ENUM,"{ ""NTSC_M"", ""NTSC_J"", ""NTSC_443"", ""PAL_B"" } etc.",Connector,TBD diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index dc850b4b6e219..07fef42869aa2 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1270,6 +1270,8 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector, state->link_status = val; } else if (property == config->aspect_ratio_property) { state->picture_aspect_ratio = val; + } else if (property == config->content_type_property) { + state->content_type = val; } else if (property == connector->scaling_mode_property) { state->scaling_mode = val; } else if (property == connector->content_protection_property) { @@ -1355,6 +1357,8 @@ drm_atomic_connector_get_property(struct drm_connector *connector, *val = state->link_status; } else if (property == config->aspect_ratio_property) { *val = state->picture_aspect_ratio; + } else if (property == config->content_type_property) { + *val = state->content_type; } else if (property == connector->scaling_mode_property) { *val = state->scaling_mode; } else if (property == connector->content_protection_property) { diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index 9b9ba5d5ec0cb..002b244391f9f 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -720,6 +720,14 @@ static const struct drm_prop_enum_list drm_aspect_ratio_enum_list[] = { { DRM_MODE_PICTURE_ASPECT_16_9, "16:9" }, }; +static const struct drm_prop_enum_list drm_content_type_enum_list[] = { + { DRM_MODE_CONTENT_TYPE_NO_DATA, "No Data" }, + { DRM_MODE_CONTENT_TYPE_GRAPHICS, "Graphics" }, + { DRM_MODE_CONTENT_TYPE_PHOTO, "Photo" }, + { DRM_MODE_CONTENT_TYPE_CINEMA, "Cinema" }, + { DRM_MODE_CONTENT_TYPE_GAME, "Game" }, +}; + static const struct drm_prop_enum_list drm_panel_orientation_enum_list[] = { { DRM_MODE_PANEL_ORIENTATION_NORMAL, "Normal" }, { DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP, "Upside Down" }, @@ -996,6 +1004,84 @@ int drm_mode_create_dvi_i_properties(struct drm_device *dev) } EXPORT_SYMBOL(drm_mode_create_dvi_i_properties); +/** + * DOC: HDMI connector properties + * + * content type (HDMI specific): + * Indicates content type setting to be used in HDMI infoframes to indicate + * content type for the external device, so that it adjusts it's display + * settings accordingly. + * + * The value of this property can be one of the following: + * + * No Data: + * Content type is unknown + * Graphics: + * Content type is graphics + * Photo: + * Content type is photo + * Cinema: + * Content type is cinema + * Game: + * Content type is game + * + * Drivers can set up this property by calling + * drm_connector_attach_content_type_property(). Decoding to + * infoframe values is done through + * drm_hdmi_get_content_type_from_property() and + * drm_hdmi_get_itc_bit_from_property(). + */ + +/** + * drm_connector_attach_content_type_property - attach content-type property + * @connector: connector to attach content type property on. + * + * Called by a driver the first time a HDMI connector is made. + */ +int drm_connector_attach_content_type_property(struct drm_connector *connector) +{ + if (!drm_mode_create_content_type_property(connector->dev)) + drm_object_attach_property(&connector->base, + connector->dev->mode_config.content_type_property, + DRM_MODE_CONTENT_TYPE_NO_DATA); + return 0; +} +EXPORT_SYMBOL(drm_connector_attach_content_type_property); + + +/** + * drm_hdmi_avi_infoframe_content_type() - fill the HDMI AVI infoframe + * content type information, based + * on correspondent DRM property. + * @frame: HDMI AVI infoframe + * @conn_state: DRM display connector state + * + */ +void drm_hdmi_avi_infoframe_content_type(struct hdmi_avi_infoframe *frame, + const struct drm_connector_state *conn_state) +{ + switch (conn_state->content_type) { + case DRM_MODE_CONTENT_TYPE_GRAPHICS: + frame->content_type = HDMI_CONTENT_TYPE_GRAPHICS; + break; + case DRM_MODE_CONTENT_TYPE_CINEMA: + frame->content_type = HDMI_CONTENT_TYPE_CINEMA; + break; + case DRM_MODE_CONTENT_TYPE_GAME: + frame->content_type = HDMI_CONTENT_TYPE_GAME; + break; + case DRM_MODE_CONTENT_TYPE_PHOTO: + frame->content_type = HDMI_CONTENT_TYPE_PHOTO; + break; + default: + /* Graphics is the default(0) */ + frame->content_type = HDMI_CONTENT_TYPE_GRAPHICS; + } + + frame->itc = conn_state->content_type != DRM_MODE_CONTENT_TYPE_NO_DATA; +} +EXPORT_SYMBOL(drm_hdmi_avi_infoframe_content_type); + /** * drm_create_tv_properties - create TV specific connector properties * @dev: DRM device @@ -1260,6 +1346,33 @@ int drm_mode_create_aspect_ratio_property(struct drm_device *dev) } EXPORT_SYMBOL(drm_mode_create_aspect_ratio_property); +/** + * drm_mode_create_content_type_property - create content type property + * @dev: DRM device + * + * Called by a driver the first time it's needed, must be attached to desired + * connectors. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_mode_create_content_type_property(struct drm_device *dev) +{ + if (dev->mode_config.content_type_property) + return 0; + + dev->mode_config.content_type_property = + drm_property_create_enum(dev, 0, "content type", + drm_content_type_enum_list, + ARRAY_SIZE(drm_content_type_enum_list)); + + if (dev->mode_config.content_type_property == NULL) + return -ENOMEM; + + return 0; +} +EXPORT_SYMBOL(drm_mode_create_content_type_property); + /** * drm_mode_create_suggested_offset_properties - create suggests offset properties * @dev: DRM device diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 40e1e24f2ff08..82f1ab09169da 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -4872,6 +4872,14 @@ drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame, frame->picture_aspect = HDMI_PICTURE_ASPECT_NONE; + /* + * As some drivers don't support atomic, we can't use connector state. + * So just initialize the frame with default values, just the same way + * as it's done with other properties here. + */ + frame->content_type = HDMI_CONTENT_TYPE_GRAPHICS; + frame->itc = 0; + /* * Populate picture aspect ratio from either * user input (if specified) or from the CEA mode list. diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 675cc3f8cf852..ee4c48218c85b 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -418,6 +418,14 @@ struct drm_connector_state { */ enum hdmi_picture_aspect picture_aspect_ratio; + /** + * @content_type: Connector property to control the + * HDMI infoframe content type setting. + * The %DRM_MODE_CONTENT_TYPE_\* values much + * match the values. + */ + unsigned int content_type; + /** * @scaling_mode: Connector property to control the * upscaling, mostly used for built-in panels. @@ -1089,11 +1097,16 @@ int drm_mode_create_tv_properties(struct drm_device *dev, unsigned int num_modes, const char * const modes[]); int drm_mode_create_scaling_mode_property(struct drm_device *dev); +int drm_connector_attach_content_type_property(struct drm_connector *dev); int drm_connector_attach_scaling_mode_property(struct drm_connector *connector, u32 scaling_mode_mask); int drm_connector_attach_content_protection_property( struct drm_connector *connector); int drm_mode_create_aspect_ratio_property(struct drm_device *dev); +int drm_mode_create_content_type_property(struct drm_device *dev); +void drm_hdmi_avi_infoframe_content_type(struct hdmi_avi_infoframe *frame, + const struct drm_connector_state *conn_state); + int drm_mode_create_suggested_offset_properties(struct drm_device *dev); int drm_mode_connector_set_path_property(struct drm_connector *connector, diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h index 33b3a96d66d0a..fb45839179dd4 100644 --- a/include/drm/drm_mode_config.h +++ b/include/drm/drm_mode_config.h @@ -726,6 +726,11 @@ struct drm_mode_config { * HDMI infoframe aspect ratio setting. */ struct drm_property *aspect_ratio_property; + /** + * @content_type_property: Optional connector property to control the + * HDMI infoframe content type setting. + */ + struct drm_property *content_type_property; /** * @degamma_lut_property: Optional CRTC property to set the LUT used to * convert the framebuffer's colors to linear gamma. diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index 4b3a1bb58e680..971c016b368cd 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -96,6 +96,13 @@ extern "C" { #define DRM_MODE_PICTURE_ASPECT_64_27 3 #define DRM_MODE_PICTURE_ASPECT_256_135 4 +/* Content type options */ +#define DRM_MODE_CONTENT_TYPE_NO_DATA 0 +#define DRM_MODE_CONTENT_TYPE_GRAPHICS 1 +#define DRM_MODE_CONTENT_TYPE_PHOTO 2 +#define DRM_MODE_CONTENT_TYPE_CINEMA 3 +#define DRM_MODE_CONTENT_TYPE_GAME 4 + /* Aspect ratio flag bitmask (4 bits 22:19) */ #define DRM_MODE_FLAG_PIC_AR_MASK (0x0F<<19) #define DRM_MODE_FLAG_PIC_AR_NONE \ -- GitLab From 6553b123eae8dd117f6adb4a42e2e6ef8bff321d Mon Sep 17 00:00:00 2001 From: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> Date: Tue, 15 May 2018 16:59:28 +0300 Subject: [PATCH 0018/1506] i915: content-type property for HDMI connector MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added encoding of drm content_type property from drm_connector_state within AVI infoframe in order to properly handle external HDMI TV content-type setting. This requires also manipulationg ITC bit, as stated in HDMI spec. v2: * Moved helper function which attaches content type property to the drm core, as was suggested. Removed redundant connector state initialization. v3: * Removed caps in drm_content_type_enum_list. After some discussion it turned out that HDMI Spec 1.4 was wrongly assuming that IT Content(itc) bit doesn't affect Content type states, however itc bit needs to be manupulated as well. In order to not expose additional property for itc, for sake of simplicity it was decided to bind those together in same "content type" property. v4: * Added it_content checking in intel_digital_connector_atomic_check. Fixed documentation for new content type enum. v5: * Moved patch revision's description to commit messages. v6: * Minor naming fix for the content type enumeration string. v7: * Fix parameter name for documentation and parameter alignment in order not to get warning. Added Content Type description to new HDMI connector properties section. v8: * Thrown away unneeded numbers from HDMI content-type property description. Switch to strings desription instead of plain definitions. v9: * Moved away hdmi specific content-type enum from drm_connector_state. Content type property should probably not be bound to any specific connector interface in drm_connector_state. Same probably should be done to hdmi_picture_aspect_ration enum which is also contained in drm_connector_state. Added special helper function to get derive hdmi specific relevant infoframe fields. v10: * Added usage description to HDMI properties kernel doc. v11: * Created centralized function for filling HDMI AVI infoframe, based on correspondent DRM property value. Acked-by: Hans Verkuil <hans.verkuil@cisco.com> Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180515135928.31092-3-stanislav.lisovskiy@intel.com [vsyrjala: clean up checkpatch multiple blank lines warnings] Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> --- drivers/gpu/drm/i915/intel_atomic.c | 1 + drivers/gpu/drm/i915/intel_hdmi.c | 17 +++++++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 40285d1b91b7f..61ddb5871d8a5 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -124,6 +124,7 @@ int intel_digital_connector_atomic_check(struct drm_connector *conn, if (new_conn_state->force_audio != old_conn_state->force_audio || new_conn_state->broadcast_rgb != old_conn_state->broadcast_rgb || new_conn_state->base.picture_aspect_ratio != old_conn_state->base.picture_aspect_ratio || + new_conn_state->base.content_type != old_conn_state->base.content_type || new_conn_state->base.scaling_mode != old_conn_state->base.scaling_mode) crtc_state->mode_changed = true; diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index ee929f31f7db7..ea958ed0777d6 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -461,7 +461,8 @@ static void intel_write_infoframe(struct drm_encoder *encoder, } static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder, - const struct intel_crtc_state *crtc_state) + const struct intel_crtc_state *crtc_state, + const struct drm_connector_state *conn_state) { struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); const struct drm_display_mode *adjusted_mode = @@ -491,6 +492,9 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder, intel_hdmi->rgb_quant_range_selectable, is_hdmi2_sink); + drm_hdmi_avi_infoframe_content_type(&frame.avi, + conn_state); + /* TODO: handle pixel repetition for YCBCR420 outputs */ intel_write_infoframe(encoder, crtc_state, &frame); } @@ -586,7 +590,7 @@ static void g4x_set_infoframes(struct drm_encoder *encoder, I915_WRITE(reg, val); POSTING_READ(reg); - intel_hdmi_set_avi_infoframe(encoder, crtc_state); + intel_hdmi_set_avi_infoframe(encoder, crtc_state, conn_state); intel_hdmi_set_spd_infoframe(encoder, crtc_state); intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state); } @@ -727,7 +731,7 @@ static void ibx_set_infoframes(struct drm_encoder *encoder, I915_WRITE(reg, val); POSTING_READ(reg); - intel_hdmi_set_avi_infoframe(encoder, crtc_state); + intel_hdmi_set_avi_infoframe(encoder, crtc_state, conn_state); intel_hdmi_set_spd_infoframe(encoder, crtc_state); intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state); } @@ -770,7 +774,7 @@ static void cpt_set_infoframes(struct drm_encoder *encoder, I915_WRITE(reg, val); POSTING_READ(reg); - intel_hdmi_set_avi_infoframe(encoder, crtc_state); + intel_hdmi_set_avi_infoframe(encoder, crtc_state, conn_state); intel_hdmi_set_spd_infoframe(encoder, crtc_state); intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state); } @@ -823,7 +827,7 @@ static void vlv_set_infoframes(struct drm_encoder *encoder, I915_WRITE(reg, val); POSTING_READ(reg); - intel_hdmi_set_avi_infoframe(encoder, crtc_state); + intel_hdmi_set_avi_infoframe(encoder, crtc_state, conn_state); intel_hdmi_set_spd_infoframe(encoder, crtc_state); intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state); } @@ -856,7 +860,7 @@ static void hsw_set_infoframes(struct drm_encoder *encoder, I915_WRITE(reg, val); POSTING_READ(reg); - intel_hdmi_set_avi_infoframe(encoder, crtc_state); + intel_hdmi_set_avi_infoframe(encoder, crtc_state, conn_state); intel_hdmi_set_spd_infoframe(encoder, crtc_state); intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state); } @@ -2065,6 +2069,7 @@ intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *c intel_attach_force_audio_property(connector); intel_attach_broadcast_rgb_property(connector); intel_attach_aspect_ratio_property(connector); + drm_connector_attach_content_type_property(connector); connector->state->picture_aspect_ratio = HDMI_PICTURE_ASPECT_NONE; } -- GitLab From 6102a8ee8ad60c51b5194e425c3cc8ce43aca384 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Mon, 14 May 2018 20:24:19 +0300 Subject: [PATCH 0019/1506] drm/i915: Clean up ADPA pipe select bits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clean up the ADPA pipe select bits. To make the whole situation a bit less ugly we'll start to share the same code between .get_hw_state() and the port state asserts. v2: Order the defines shift,mask,value (Jani) Reviewed-by: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180514172423.9302-1-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/i915_reg.h | 11 ++++---- drivers/gpu/drm/i915/intel_crt.c | 40 ++++++++++++++-------------- drivers/gpu/drm/i915/intel_display.c | 24 ++++------------- drivers/gpu/drm/i915/intel_drv.h | 2 ++ 4 files changed, 33 insertions(+), 44 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index f11bb213ec078..ae3c262169966 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4133,11 +4133,12 @@ enum { #define ADPA_DAC_ENABLE (1<<31) #define ADPA_DAC_DISABLE 0 -#define ADPA_PIPE_SELECT_MASK (1<<30) -#define ADPA_PIPE_A_SELECT 0 -#define ADPA_PIPE_B_SELECT (1<<30) -#define ADPA_PIPE_SELECT(pipe) ((pipe) << 30) -/* CPT uses bits 29:30 for pch transcoder select */ +#define ADPA_PIPE_SEL_SHIFT 30 +#define ADPA_PIPE_SEL_MASK (1<<30) +#define ADPA_PIPE_SEL(pipe) ((pipe) << 30) +#define ADPA_PIPE_SEL_SHIFT_CPT 29 +#define ADPA_PIPE_SEL_MASK_CPT (3<<29) +#define ADPA_PIPE_SEL_CPT(pipe) ((pipe) << 29) #define ADPA_CRT_HOTPLUG_MASK 0x03ff0000 /* bit 25-16 */ #define ADPA_CRT_HOTPLUG_MONITOR_NONE (0<<24) #define ADPA_CRT_HOTPLUG_MONITOR_MASK (3<<24) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index de0e22322c76e..211d601cd1b16 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -63,33 +63,35 @@ static struct intel_crt *intel_attached_crt(struct drm_connector *connector) return intel_encoder_to_crt(intel_attached_encoder(connector)); } +bool intel_crt_port_enabled(struct drm_i915_private *dev_priv, + i915_reg_t adpa_reg, enum pipe *pipe) +{ + u32 val; + + val = I915_READ(adpa_reg); + + /* asserts want to know the pipe even if the port is disabled */ + if (HAS_PCH_CPT(dev_priv)) + *pipe = (val & ADPA_PIPE_SEL_MASK_CPT) >> ADPA_PIPE_SEL_SHIFT_CPT; + else + *pipe = (val & ADPA_PIPE_SEL_MASK) >> ADPA_PIPE_SEL_SHIFT; + + return val & ADPA_DAC_ENABLE; +} + static bool intel_crt_get_hw_state(struct intel_encoder *encoder, enum pipe *pipe) { - struct drm_device *dev = encoder->base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_crt *crt = intel_encoder_to_crt(encoder); - u32 tmp; bool ret; if (!intel_display_power_get_if_enabled(dev_priv, encoder->power_domain)) return false; - ret = false; - - tmp = I915_READ(crt->adpa_reg); - - if (!(tmp & ADPA_DAC_ENABLE)) - goto out; + ret = intel_crt_port_enabled(dev_priv, crt->adpa_reg, pipe); - if (HAS_PCH_CPT(dev_priv)) - *pipe = PORT_TO_PIPE_CPT(tmp); - else - *pipe = PORT_TO_PIPE(tmp); - - ret = true; -out: intel_display_power_put(dev_priv, encoder->power_domain); return ret; @@ -168,11 +170,9 @@ static void intel_crt_set_dpms(struct intel_encoder *encoder, if (HAS_PCH_LPT(dev_priv)) ; /* Those bits don't exist here */ else if (HAS_PCH_CPT(dev_priv)) - adpa |= PORT_TRANS_SEL_CPT(crtc->pipe); - else if (crtc->pipe == 0) - adpa |= ADPA_PIPE_A_SELECT; + adpa |= ADPA_PIPE_SEL_CPT(crtc->pipe); else - adpa |= ADPA_PIPE_B_SELECT; + adpa |= ADPA_PIPE_SEL(crtc->pipe); if (!HAS_PCH_SPLIT(dev_priv)) I915_WRITE(BCLRPAT(crtc->pipe), 0); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ad588d5641988..6daa8d97a0aa3 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1360,21 +1360,6 @@ static bool lvds_pipe_enabled(struct drm_i915_private *dev_priv, return true; } -static bool adpa_pipe_enabled(struct drm_i915_private *dev_priv, - enum pipe pipe, u32 val) -{ - if ((val & ADPA_DAC_ENABLE) == 0) - return false; - if (HAS_PCH_CPT(dev_priv)) { - if ((val & PORT_TRANS_SEL_MASK) != PORT_TRANS_SEL_CPT(pipe)) - return false; - } else { - if ((val & ADPA_PIPE_SELECT_MASK) != ADPA_PIPE_SELECT(pipe)) - return false; - } - return true; -} - static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv, enum pipe pipe, i915_reg_t reg, u32 port_sel) @@ -1405,16 +1390,17 @@ static void assert_pch_hdmi_disabled(struct drm_i915_private *dev_priv, static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv, enum pipe pipe) { + enum pipe port_pipe; u32 val; assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_B, TRANS_DP_PORT_SEL_B); assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_C, TRANS_DP_PORT_SEL_C); assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_D, TRANS_DP_PORT_SEL_D); - val = I915_READ(PCH_ADPA); - I915_STATE_WARN(adpa_pipe_enabled(dev_priv, pipe, val), - "PCH VGA enabled on transcoder %c, should be disabled\n", - pipe_name(pipe)); + I915_STATE_WARN(intel_crt_port_enabled(dev_priv, PCH_ADPA, &port_pipe) && + port_pipe == pipe, + "PCH VGA enabled on transcoder %c, should be disabled\n", + pipe_name(pipe)); val = I915_READ(PCH_LVDS); I915_STATE_WARN(lvds_pipe_enabled(dev_priv, pipe, val), diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index d7dbca1aabffb..423795050970e 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1377,6 +1377,8 @@ void gen9_enable_guc_interrupts(struct drm_i915_private *dev_priv); void gen9_disable_guc_interrupts(struct drm_i915_private *dev_priv); /* intel_crt.c */ +bool intel_crt_port_enabled(struct drm_i915_private *dev_priv, + i915_reg_t adpa_reg, enum pipe *pipe); void intel_crt_init(struct drm_i915_private *dev_priv); void intel_crt_reset(struct drm_encoder *encoder); -- GitLab From a44628b9293b81b53b00adbf90b3dd6e3b9dbc32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Mon, 14 May 2018 21:28:27 +0300 Subject: [PATCH 0020/1506] drm/i915: Clean up LVDS pipe select bits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clean up the LVDS pipe select bits. To make the whole situation a bit less ugly we'll start to share the same code between .get_hw_state() and the port state asserts. v2: Order the defines shift,mask,value (Jani) Drop ruperfluous braces and whitesapce changes (Jani) Combine masks in compute_is_dual_link_lvds() (Jani) v3: Fix LVDS_PIPE_SEL_MASK_CPT Reviewed-by: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180514182827.28629-1-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/i915_reg.h | 9 +++-- drivers/gpu/drm/i915/intel_display.c | 33 ++++-------------- drivers/gpu/drm/i915/intel_drv.h | 2 ++ drivers/gpu/drm/i915/intel_lvds.c | 52 +++++++++++++++------------- 4 files changed, 42 insertions(+), 54 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index ae3c262169966..753b8f110e2e4 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4392,9 +4392,12 @@ enum { */ #define LVDS_PORT_EN (1 << 31) /* Selects pipe B for LVDS data. Must be set on pre-965. */ -#define LVDS_PIPEB_SELECT (1 << 30) -#define LVDS_PIPE_MASK (1 << 30) -#define LVDS_PIPE(pipe) ((pipe) << 30) +#define LVDS_PIPE_SEL_SHIFT 30 +#define LVDS_PIPE_SEL_MASK (1 << 30) +#define LVDS_PIPE_SEL(pipe) ((pipe) << 30) +#define LVDS_PIPE_SEL_SHIFT_CPT 29 +#define LVDS_PIPE_SEL_MASK_CPT (3 << 29) +#define LVDS_PIPE_SEL_CPT(pipe) ((pipe) << 29) /* LVDS dithering flag on 965/g4x platform */ #define LVDS_ENABLE_DITHER (1 << 25) /* LVDS sync polarity flags. Set to invert (i.e. negative) */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6daa8d97a0aa3..a1c6cc75f49cd 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1214,9 +1214,8 @@ void assert_panel_unlocked(struct drm_i915_private *dev_priv, enum pipe pipe) pp_reg = PP_CONTROL(0); port_sel = I915_READ(PP_ON_DELAYS(0)) & PANEL_PORT_SELECT_MASK; - if (port_sel == PANEL_PORT_SELECT_LVDS && - I915_READ(PCH_LVDS) & LVDS_PIPEB_SELECT) - panel_pipe = PIPE_B; + if (port_sel == PANEL_PORT_SELECT_LVDS) + intel_lvds_port_enabled(dev_priv, PCH_LVDS, &panel_pipe); /* XXX: else fix for eDP */ } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { /* presumably write lock depends on pipe, not port select */ @@ -1224,8 +1223,7 @@ void assert_panel_unlocked(struct drm_i915_private *dev_priv, enum pipe pipe) panel_pipe = pipe; } else { pp_reg = PP_CONTROL(0); - if (I915_READ(LVDS) & LVDS_PIPEB_SELECT) - panel_pipe = PIPE_B; + intel_lvds_port_enabled(dev_priv, LVDS, &panel_pipe); } val = I915_READ(pp_reg); @@ -1344,22 +1342,6 @@ static bool hdmi_pipe_enabled(struct drm_i915_private *dev_priv, return true; } -static bool lvds_pipe_enabled(struct drm_i915_private *dev_priv, - enum pipe pipe, u32 val) -{ - if ((val & LVDS_PORT_EN) == 0) - return false; - - if (HAS_PCH_CPT(dev_priv)) { - if ((val & PORT_TRANS_SEL_MASK) != PORT_TRANS_SEL_CPT(pipe)) - return false; - } else { - if ((val & LVDS_PIPE_MASK) != LVDS_PIPE(pipe)) - return false; - } - return true; -} - static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv, enum pipe pipe, i915_reg_t reg, u32 port_sel) @@ -1391,7 +1373,6 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv, enum pipe pipe) { enum pipe port_pipe; - u32 val; assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_B, TRANS_DP_PORT_SEL_B); assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_C, TRANS_DP_PORT_SEL_C); @@ -1402,10 +1383,10 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv, "PCH VGA enabled on transcoder %c, should be disabled\n", pipe_name(pipe)); - val = I915_READ(PCH_LVDS); - I915_STATE_WARN(lvds_pipe_enabled(dev_priv, pipe, val), - "PCH LVDS enabled on transcoder %c, should be disabled\n", - pipe_name(pipe)); + I915_STATE_WARN(intel_lvds_port_enabled(dev_priv, PCH_LVDS, &port_pipe) && + port_pipe == pipe, + "PCH LVDS enabled on transcoder %c, should be disabled\n", + pipe_name(pipe)); assert_pch_hdmi_disabled(dev_priv, pipe, PCH_HDMIB); assert_pch_hdmi_disabled(dev_priv, pipe, PCH_HDMIC); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 423795050970e..911d4960ba7a8 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1824,6 +1824,8 @@ void intel_infoframe_init(struct intel_digital_port *intel_dig_port); /* intel_lvds.c */ +bool intel_lvds_port_enabled(struct drm_i915_private *dev_priv, + i915_reg_t lvds_reg, enum pipe *pipe); void intel_lvds_init(struct drm_i915_private *dev_priv); struct intel_encoder *intel_get_lvds_encoder(struct drm_device *dev); bool intel_is_dual_link_lvds(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 8691c86f579c7..cc4cc8669af37 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -85,34 +85,35 @@ static struct intel_lvds_connector *to_lvds_connector(struct drm_connector *conn return container_of(connector, struct intel_lvds_connector, base.base); } +bool intel_lvds_port_enabled(struct drm_i915_private *dev_priv, + i915_reg_t lvds_reg, enum pipe *pipe) +{ + u32 val; + + val = I915_READ(lvds_reg); + + /* asserts want to know the pipe even if the port is disabled */ + if (HAS_PCH_CPT(dev_priv)) + *pipe = (val & LVDS_PIPE_SEL_MASK_CPT) >> LVDS_PIPE_SEL_SHIFT_CPT; + else + *pipe = (val & LVDS_PIPE_SEL_MASK) >> LVDS_PIPE_SEL_SHIFT; + + return val & LVDS_PORT_EN; +} + static bool intel_lvds_get_hw_state(struct intel_encoder *encoder, enum pipe *pipe) { - struct drm_device *dev = encoder->base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base); - u32 tmp; bool ret; if (!intel_display_power_get_if_enabled(dev_priv, encoder->power_domain)) return false; - ret = false; + ret = intel_lvds_port_enabled(dev_priv, lvds_encoder->reg, pipe); - tmp = I915_READ(lvds_encoder->reg); - - if (!(tmp & LVDS_PORT_EN)) - goto out; - - if (HAS_PCH_CPT(dev_priv)) - *pipe = PORT_TO_PIPE_CPT(tmp); - else - *pipe = PORT_TO_PIPE(tmp); - - ret = true; - -out: intel_display_power_put(dev_priv, encoder->power_domain); return ret; @@ -255,14 +256,11 @@ static void intel_pre_enable_lvds(struct intel_encoder *encoder, temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP; if (HAS_PCH_CPT(dev_priv)) { - temp &= ~PORT_TRANS_SEL_MASK; - temp |= PORT_TRANS_SEL_CPT(pipe); + temp &= ~LVDS_PIPE_SEL_MASK_CPT; + temp |= LVDS_PIPE_SEL_CPT(pipe); } else { - if (pipe == 1) { - temp |= LVDS_PIPEB_SELECT; - } else { - temp &= ~LVDS_PIPEB_SELECT; - } + temp &= ~LVDS_PIPE_SEL_MASK; + temp |= LVDS_PIPE_SEL(pipe); } /* set the corresponsding LVDS_BORDER bit */ @@ -908,7 +906,11 @@ static bool compute_is_dual_link_lvds(struct intel_lvds_encoder *lvds_encoder) * register is uninitialized. */ val = I915_READ(lvds_encoder->reg); - if (!(val & ~(LVDS_PIPE_MASK | LVDS_DETECTED))) + if (HAS_PCH_CPT(dev_priv)) + val &= ~(LVDS_DETECTED | LVDS_PIPE_SEL_MASK_CPT); + else + val &= ~(LVDS_DETECTED | LVDS_PIPE_SEL_MASK); + if (val == 0) val = dev_priv->vbt.bios_lvds_val; return (val & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP; -- GitLab From 762034675ee7476180eb3e7fc6c7b52db71654ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Mon, 14 May 2018 20:24:21 +0300 Subject: [PATCH 0021/1506] drm/i915: Clean up SDVO pipe select bits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clean up the SDVO pipe select bits. To make the whole situation a bit less ugly we'll start to share the same code between .get_hw_state() and the port state asserts. v2: Order the defines shift,mask,value (Jani) Reviewed-by: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180514172423.9302-3-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/i915_reg.h | 10 +++--- drivers/gpu/drm/i915/intel_display.c | 46 ++++++++++------------------ drivers/gpu/drm/i915/intel_drv.h | 2 ++ drivers/gpu/drm/i915/intel_hdmi.c | 25 +++------------ drivers/gpu/drm/i915/intel_sdvo.c | 38 ++++++++++++++--------- 5 files changed, 52 insertions(+), 69 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 753b8f110e2e4..f1c83233a70a9 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4297,9 +4297,9 @@ enum { /* Gen 3 SDVO bits: */ #define SDVO_ENABLE (1 << 31) -#define SDVO_PIPE_SEL(pipe) ((pipe) << 30) +#define SDVO_PIPE_SEL_SHIFT 30 #define SDVO_PIPE_SEL_MASK (1 << 30) -#define SDVO_PIPE_B_SELECT (1 << 30) +#define SDVO_PIPE_SEL(pipe) ((pipe) << 30) #define SDVO_STALL_SELECT (1 << 29) #define SDVO_INTERRUPT_ENABLE (1 << 26) /* @@ -4339,12 +4339,14 @@ enum { #define SDVOB_HOTPLUG_ENABLE (1 << 23) /* SDVO only */ /* Gen 6 (CPT) SDVO/HDMI bits: */ -#define SDVO_PIPE_SEL_CPT(pipe) ((pipe) << 29) +#define SDVO_PIPE_SEL_SHIFT_CPT 29 #define SDVO_PIPE_SEL_MASK_CPT (3 << 29) +#define SDVO_PIPE_SEL_CPT(pipe) ((pipe) << 29) /* CHV SDVO/HDMI bits: */ -#define SDVO_PIPE_SEL_CHV(pipe) ((pipe) << 24) +#define SDVO_PIPE_SEL_SHIFT_CHV 24 #define SDVO_PIPE_SEL_MASK_CHV (3 << 24) +#define SDVO_PIPE_SEL_CHV(pipe) ((pipe) << 24) /* DVO port control */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a1c6cc75f49cd..817d5d3f65ebe 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1323,25 +1323,6 @@ static bool dp_pipe_enabled(struct drm_i915_private *dev_priv, return true; } -static bool hdmi_pipe_enabled(struct drm_i915_private *dev_priv, - enum pipe pipe, u32 val) -{ - if ((val & SDVO_ENABLE) == 0) - return false; - - if (HAS_PCH_CPT(dev_priv)) { - if ((val & SDVO_PIPE_SEL_MASK_CPT) != SDVO_PIPE_SEL_CPT(pipe)) - return false; - } else if (IS_CHERRYVIEW(dev_priv)) { - if ((val & SDVO_PIPE_SEL_MASK_CHV) != SDVO_PIPE_SEL_CHV(pipe)) - return false; - } else { - if ((val & SDVO_PIPE_SEL_MASK) != SDVO_PIPE_SEL(pipe)) - return false; - } - return true; -} - static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv, enum pipe pipe, i915_reg_t reg, u32 port_sel) @@ -1357,16 +1338,21 @@ static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv, } static void assert_pch_hdmi_disabled(struct drm_i915_private *dev_priv, - enum pipe pipe, i915_reg_t reg) + enum pipe pipe, enum port port, + i915_reg_t hdmi_reg) { - u32 val = I915_READ(reg); - I915_STATE_WARN(hdmi_pipe_enabled(dev_priv, pipe, val), - "PCH HDMI (0x%08x) enabled on transcoder %c, should be disabled\n", - i915_mmio_reg_offset(reg), pipe_name(pipe)); + enum pipe port_pipe; + bool state; + + state = intel_sdvo_port_enabled(dev_priv, hdmi_reg, &port_pipe); + + I915_STATE_WARN(state && port_pipe == pipe, + "PCH HDMI %c enabled on transcoder %c, should be disabled\n", + port_name(port), pipe_name(pipe)); - I915_STATE_WARN(HAS_PCH_IBX(dev_priv) && (val & SDVO_ENABLE) == 0 - && (val & SDVO_PIPE_B_SELECT), - "IBX PCH hdmi port still using transcoder B\n"); + I915_STATE_WARN(HAS_PCH_IBX(dev_priv) && !state && port_pipe == PIPE_B, + "IBX PCH HDMI %c still using transcoder B\n", + port_name(port)); } static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv, @@ -1388,9 +1374,9 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv, "PCH LVDS enabled on transcoder %c, should be disabled\n", pipe_name(pipe)); - assert_pch_hdmi_disabled(dev_priv, pipe, PCH_HDMIB); - assert_pch_hdmi_disabled(dev_priv, pipe, PCH_HDMIC); - assert_pch_hdmi_disabled(dev_priv, pipe, PCH_HDMID); + assert_pch_hdmi_disabled(dev_priv, pipe, PORT_B, PCH_HDMIB); + assert_pch_hdmi_disabled(dev_priv, pipe, PORT_C, PCH_HDMIC); + assert_pch_hdmi_disabled(dev_priv, pipe, PORT_D, PCH_HDMID); } static void _vlv_enable_pll(struct intel_crtc *crtc, diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 911d4960ba7a8..12002fc77235a 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -2064,6 +2064,8 @@ void intel_init_ipc(struct drm_i915_private *dev_priv); void intel_enable_ipc(struct drm_i915_private *dev_priv); /* intel_sdvo.c */ +bool intel_sdvo_port_enabled(struct drm_i915_private *dev_priv, + i915_reg_t sdvo_reg, enum pipe *pipe); bool intel_sdvo_init(struct drm_i915_private *dev_priv, i915_reg_t reg, enum port port); diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index ee929f31f7db7..ba5ea61fb7b96 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1161,33 +1161,16 @@ static void intel_hdmi_prepare(struct intel_encoder *encoder, static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder, enum pipe *pipe) { - struct drm_device *dev = encoder->base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); - u32 tmp; bool ret; if (!intel_display_power_get_if_enabled(dev_priv, encoder->power_domain)) return false; - ret = false; - - tmp = I915_READ(intel_hdmi->hdmi_reg); - - if (!(tmp & SDVO_ENABLE)) - goto out; - - if (HAS_PCH_CPT(dev_priv)) - *pipe = PORT_TO_PIPE_CPT(tmp); - else if (IS_CHERRYVIEW(dev_priv)) - *pipe = SDVO_PORT_TO_PIPE_CHV(tmp); - else - *pipe = PORT_TO_PIPE(tmp); - - ret = true; + ret = intel_sdvo_port_enabled(dev_priv, intel_hdmi->hdmi_reg, pipe); -out: intel_display_power_put(dev_priv, encoder->power_domain); return ret; @@ -1421,8 +1404,8 @@ static void intel_disable_hdmi(struct intel_encoder *encoder, intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, false); intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, false); - temp &= ~SDVO_PIPE_B_SELECT; - temp |= SDVO_ENABLE; + temp &= ~SDVO_PIPE_SEL_MASK; + temp |= SDVO_ENABLE | SDVO_PIPE_SEL(PIPE_A); /* * HW workaround, need to write this twice for issue * that may result in first write getting masked. diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 96e213ec202d8..848b03a542d69 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1403,27 +1403,37 @@ static bool intel_sdvo_connector_get_hw_state(struct intel_connector *connector) return false; } +bool intel_sdvo_port_enabled(struct drm_i915_private *dev_priv, + i915_reg_t sdvo_reg, enum pipe *pipe) +{ + u32 val; + + val = I915_READ(sdvo_reg); + + /* asserts want to know the pipe even if the port is disabled */ + if (HAS_PCH_CPT(dev_priv)) + *pipe = (val & SDVO_PIPE_SEL_MASK_CPT) >> SDVO_PIPE_SEL_SHIFT_CPT; + else if (IS_CHERRYVIEW(dev_priv)) + *pipe = (val & SDVO_PIPE_SEL_MASK_CHV) >> SDVO_PIPE_SEL_SHIFT_CHV; + else + *pipe = (val & SDVO_PIPE_SEL_MASK) >> SDVO_PIPE_SEL_SHIFT; + + return val & SDVO_ENABLE; +} + static bool intel_sdvo_get_hw_state(struct intel_encoder *encoder, enum pipe *pipe) { - struct drm_device *dev = encoder->base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_sdvo *intel_sdvo = to_sdvo(encoder); u16 active_outputs = 0; - u32 tmp; + bool ret; - tmp = I915_READ(intel_sdvo->sdvo_reg); intel_sdvo_get_active_outputs(intel_sdvo, &active_outputs); - if (!(tmp & SDVO_ENABLE) && (active_outputs == 0)) - return false; - - if (HAS_PCH_CPT(dev_priv)) - *pipe = PORT_TO_PIPE_CPT(tmp); - else - *pipe = PORT_TO_PIPE(tmp); + ret = intel_sdvo_port_enabled(dev_priv, intel_sdvo->sdvo_reg, pipe); - return true; + return ret || active_outputs; } static void intel_sdvo_get_config(struct intel_encoder *encoder, @@ -1550,8 +1560,8 @@ static void intel_disable_sdvo(struct intel_encoder *encoder, intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, false); intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, false); - temp &= ~SDVO_PIPE_B_SELECT; - temp |= SDVO_ENABLE; + temp &= ~SDVO_PIPE_SEL_MASK; + temp |= SDVO_ENABLE | SDVO_PIPE_SEL(PIPE_A); intel_sdvo_write_sdvox(intel_sdvo, temp); temp &= ~SDVO_ENABLE; -- GitLab From 4add0f6bde0506677a224e761cc9f764d24dbe96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Mon, 14 May 2018 20:24:22 +0300 Subject: [PATCH 0022/1506] drm/i915: Clean up TV pipe select bits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Parametrize the TV pipe select bits. For consistency with the new way of doing things, let's read out the pipe select bits even when the port is disable, even though we don't need that behaviour for asserts in this case. v2: Order the defines shift,mask,value (Jani) Clear the stale pipe select bit in load detection (Jani) Reviewed-by: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180514172423.9302-4-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/i915_reg.h | 4 +++- drivers/gpu/drm/i915/intel_tv.c | 20 ++++++-------------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index f1c83233a70a9..dae213d4c13ab 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4696,7 +4696,9 @@ enum { /* Enables the TV encoder */ # define TV_ENC_ENABLE (1 << 31) /* Sources the TV encoder input from pipe B instead of A. */ -# define TV_ENC_PIPEB_SELECT (1 << 30) +# define TV_ENC_PIPE_SEL_SHIFT 30 +# define TV_ENC_PIPE_SEL_MASK (1 << 30) +# define TV_ENC_PIPE_SEL(pipe) ((pipe) << 30) /* Outputs composite video (DAC A only) */ # define TV_ENC_OUTPUT_COMPOSITE (0 << 28) /* Outputs SVideo video (DAC B/C) */ diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 885fc3809f7f9..99bc2368dda03 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -798,16 +798,12 @@ static struct intel_tv *intel_attached_tv(struct drm_connector *connector) static bool intel_tv_get_hw_state(struct intel_encoder *encoder, enum pipe *pipe) { - struct drm_device *dev = encoder->base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); u32 tmp = I915_READ(TV_CTL); - if (!(tmp & TV_ENC_ENABLE)) - return false; + *pipe = (tmp & TV_ENC_PIPE_SEL_MASK) >> TV_ENC_PIPE_SEL_SHIFT; - *pipe = PORT_TO_PIPE(tmp); - - return true; + return tmp & TV_ENC_ENABLE; } static void @@ -1024,8 +1020,7 @@ static void intel_tv_pre_enable(struct intel_encoder *encoder, break; } - if (intel_crtc->pipe == 1) - tv_ctl |= TV_ENC_PIPEB_SELECT; + tv_ctl |= TV_ENC_PIPE_SEL(intel_crtc->pipe); tv_ctl |= tv_mode->oversample; if (tv_mode->progressive) @@ -1149,12 +1144,9 @@ intel_tv_detect_type(struct intel_tv *intel_tv, save_tv_ctl = tv_ctl = I915_READ(TV_CTL); /* Poll for TV detection */ - tv_ctl &= ~(TV_ENC_ENABLE | TV_TEST_MODE_MASK); + tv_ctl &= ~(TV_ENC_ENABLE | TV_ENC_PIPE_SEL_MASK | TV_TEST_MODE_MASK); tv_ctl |= TV_TEST_MODE_MONITOR_DETECT; - if (intel_crtc->pipe == 1) - tv_ctl |= TV_ENC_PIPEB_SELECT; - else - tv_ctl &= ~TV_ENC_PIPEB_SELECT; + tv_ctl |= TV_ENC_PIPE_SEL(intel_crtc->pipe); tv_dac &= ~(TVDAC_SENSE_MASK | DAC_A_MASK | DAC_B_MASK | DAC_C_MASK); tv_dac |= (TVDAC_STATE_CHG_EN | -- GitLab From b45a258897a4a37b6cbc0bf1dc21354432f3e8c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Mon, 14 May 2018 20:24:23 +0300 Subject: [PATCH 0023/1506] drm/i915: Clean up DVO pipe select bits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Parametrize the DVO pipe select bits. For consistency with the new way of doing things, let's read out the pipe select bits even when the port is disable, even though we don't need that behaviour for asserts in this case. v2: Order the defines shift,mask,value (Jani) Reviewed-by: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180514172423.9302-5-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/i915_reg.h | 4 +++- drivers/gpu/drm/i915/intel_dvo.c | 13 ++++--------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index dae213d4c13ab..196a0eb792725 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4357,7 +4357,9 @@ enum { #define _DVOC 0x61160 #define DVOC _MMIO(_DVOC) #define DVO_ENABLE (1 << 31) -#define DVO_PIPE_B_SELECT (1 << 30) +#define DVO_PIPE_SEL_SHIFT 30 +#define DVO_PIPE_SEL_MASK (1 << 30) +#define DVO_PIPE_SEL(pipe) ((pipe) << 30) #define DVO_PIPE_STALL_UNUSED (0 << 28) #define DVO_PIPE_STALL (1 << 28) #define DVO_PIPE_STALL_TV (2 << 28) diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index eb0c559b27156..a86f0398570f6 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -137,19 +137,15 @@ static bool intel_dvo_connector_get_hw_state(struct intel_connector *connector) static bool intel_dvo_get_hw_state(struct intel_encoder *encoder, enum pipe *pipe) { - struct drm_device *dev = encoder->base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_dvo *intel_dvo = enc_to_dvo(encoder); u32 tmp; tmp = I915_READ(intel_dvo->dev.dvo_reg); - if (!(tmp & DVO_ENABLE)) - return false; - - *pipe = PORT_TO_PIPE(tmp); + *pipe = (tmp & DVO_PIPE_SEL_MASK) >> DVO_PIPE_SEL_SHIFT; - return true; + return tmp & DVO_ENABLE; } static void intel_dvo_get_config(struct intel_encoder *encoder, @@ -276,8 +272,7 @@ static void intel_dvo_pre_enable(struct intel_encoder *encoder, dvo_val |= DVO_DATA_ORDER_FP | DVO_BORDER_ENABLE | DVO_BLANK_ACTIVE_HIGH; - if (pipe == 1) - dvo_val |= DVO_PIPE_B_SELECT; + dvo_val |= DVO_PIPE_SEL(pipe); dvo_val |= DVO_PIPE_STALL; if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) dvo_val |= DVO_HSYNC_ACTIVE_HIGH; -- GitLab From 57877b70739a5d49d95bedf94218ba125e8afef3 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 17 May 2018 12:56:47 +0100 Subject: [PATCH 0024/1506] drm/i915/execlists: HWACK checking superseded checking port[0].count The HWACK bit more generically solves the problem of resubmitting ESLP while the hardware is still processing the current ELSP write. We no longer need to check port[0].count itself. References: ba74cb10c775 ("drm/i915/execlists: Delay writing to ELSP until HW has processed the previous write") Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Michel Thierry <michel.thierry@intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180517115647.17205-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_lrc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 493e6bd9e28ad..ae5adad7cc639 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -612,8 +612,6 @@ static bool __execlists_dequeue(struct intel_engine_cs *engine) GEM_BUG_ON(!execlists_is_active(execlists, EXECLISTS_ACTIVE_USER)); GEM_BUG_ON(!port_count(&port[0])); - if (port_count(&port[0]) > 1) - return false; /* * If we write to ELSP a second time before the HW has had -- GitLab From 96d4f03c20d04c80026b1ec3643c090cf4f0eb20 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 17 May 2018 16:28:24 +0100 Subject: [PATCH 0025/1506] drm/i915: Nul-terminate legacy debug string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make sure that when we don't have any scheduler attributes for the request, the string is terminated. Fixes: 247870ac8ea7 ("drm/i915: Build request info on stack before printk") Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180517152824.11619-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_engine_cs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index d4e159ae65a61..e78c6e769e8cd 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -1143,7 +1143,7 @@ static void print_request(struct drm_printer *m, const char *prefix) { const char *name = rq->fence.ops->get_timeline_name(&rq->fence); - char buf[80]; + char buf[80] = ""; int x = 0; x = print_sched_attr(rq->i915, &rq->sched.attr, buf, x, sizeof(buf)); -- GitLab From 560f6ad8edeaab1b14f1cb86083c7e0c1d37c749 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 17 May 2018 16:07:27 +0100 Subject: [PATCH 0026/1506] drm/i915: Remove unused enable_cmd_parser modparam The command parser is feature complete, stable and required by userspace. In commit 41736a8e3331 ("drm/i915: Use the precomputed value for whether to enable command parsing") I accidentally removed control from the modparam, and as no one has complained, remove the left over modparam completely! References: 41736a8e3331 ("drm/i915: Use the precomputed value for whether to enable command parsing") Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Jani Nikula <jani.nikula@linux.intel.com> Acked-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180517150727.10431-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_params.c | 3 --- drivers/gpu/drm/i915/i915_params.h | 1 - 2 files changed, 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 66ea3552c63ec..49fcc4679db67 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -130,9 +130,6 @@ i915_param_named_unsafe(invert_brightness, int, 0600, i915_param_named(disable_display, bool, 0400, "Disable display (default: false)"); -i915_param_named_unsafe(enable_cmd_parser, bool, 0400, - "Enable command parsing (true=enabled [default], false=disabled)"); - i915_param_named(mmio_debug, int, 0600, "Enable the MMIO debug code for the first N failures (default: off). " "This may negatively affect performance."); diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h index 6684025b7af8b..aebe0469ddaa3 100644 --- a/drivers/gpu/drm/i915/i915_params.h +++ b/drivers/gpu/drm/i915/i915_params.h @@ -58,7 +58,6 @@ struct drm_printer; param(unsigned int, inject_load_failure, 0) \ /* leave bools at the end to not create holes */ \ param(bool, alpha_support, IS_ENABLED(CONFIG_DRM_I915_ALPHA_SUPPORT)) \ - param(bool, enable_cmd_parser, true) \ param(bool, enable_hangcheck, true) \ param(bool, fastboot, false) \ param(bool, prefault_disable, false) \ -- GitLab From 6b7a6a7b4ba12715fabde30fea96f9df3df2da93 Mon Sep 17 00:00:00 2001 From: Oscar Mateo <oscar.mateo@intel.com> Date: Thu, 10 May 2018 14:59:55 -0700 Subject: [PATCH 0027/1506] drm/i915/icl: Read the correct Gen11 interrupt registers Stop reading some now deprecated interrupt registers in both debugfs and error state. Instead, read the new equivalents in the Gen11 interrupt repartitioning scheme. Note that the equivalent to the PM ISR & IIR cannot be read without affecting the current state of the system, so I've opted for leaving them out. See gen11_reset_one_iir() for more info. v2: else if !!! (Paulo) v3: another else if (Vinay) v4: - Rebased - Renamed patch - Improved the ordering of GENs - Improved the printing of per-GEN info v5: Avoid maybe-unitialized & add comment explaining the lack of PM ISR & IIR Suggested-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Signed-off-by: Oscar Mateo <oscar.mateo@intel.com> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Cc: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com> Cc: Sagar Arun Kamble <sagar.a.kamble@intel.com> Cc: Vinay Belgaumkar <vinay.belgaumkar@intel.com> Reviewed-by: Vinay Belgaumkar <vinay.belgaumkar@intel.com> [Paulo: fix commit message and coding style.] Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/1525989595-18220-1-git-send-email-oscar.mateo@intel.com --- drivers/gpu/drm/i915/i915_debugfs.c | 33 +++++++++++++++++++-------- drivers/gpu/drm/i915/i915_gpu_error.c | 11 ++++++++- drivers/gpu/drm/i915/i915_gpu_error.h | 2 +- 3 files changed, 34 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 13e7b9e4a6e6f..d78beaabc051c 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1162,19 +1162,28 @@ static int i915_frequency_info(struct seq_file *m, void *unused) intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL); - if (IS_GEN6(dev_priv) || IS_GEN7(dev_priv)) { - pm_ier = I915_READ(GEN6_PMIER); - pm_imr = I915_READ(GEN6_PMIMR); - pm_isr = I915_READ(GEN6_PMISR); - pm_iir = I915_READ(GEN6_PMIIR); - pm_mask = I915_READ(GEN6_PMINTRMSK); - } else { + if (INTEL_GEN(dev_priv) >= 11) { + pm_ier = I915_READ(GEN11_GPM_WGBOXPERF_INTR_ENABLE); + pm_imr = I915_READ(GEN11_GPM_WGBOXPERF_INTR_MASK); + /* + * The equivalent to the PM ISR & IIR cannot be read + * without affecting the current state of the system + */ + pm_isr = 0; + pm_iir = 0; + } else if (INTEL_GEN(dev_priv) >= 8) { pm_ier = I915_READ(GEN8_GT_IER(2)); pm_imr = I915_READ(GEN8_GT_IMR(2)); pm_isr = I915_READ(GEN8_GT_ISR(2)); pm_iir = I915_READ(GEN8_GT_IIR(2)); - pm_mask = I915_READ(GEN6_PMINTRMSK); + } else { + pm_ier = I915_READ(GEN6_PMIER); + pm_imr = I915_READ(GEN6_PMIMR); + pm_isr = I915_READ(GEN6_PMISR); + pm_iir = I915_READ(GEN6_PMIIR); } + pm_mask = I915_READ(GEN6_PMINTRMSK); + seq_printf(m, "Video Turbo Mode: %s\n", yesno(rpmodectl & GEN6_RP_MEDIA_TURBO)); seq_printf(m, "HW control enabled: %s\n", @@ -1182,8 +1191,12 @@ static int i915_frequency_info(struct seq_file *m, void *unused) seq_printf(m, "SW control enabled: %s\n", yesno((rpmodectl & GEN6_RP_MEDIA_MODE_MASK) == GEN6_RP_MEDIA_SW_MODE)); - seq_printf(m, "PM IER=0x%08x IMR=0x%08x ISR=0x%08x IIR=0x%08x, MASK=0x%08x\n", - pm_ier, pm_imr, pm_isr, pm_iir, pm_mask); + + seq_printf(m, "PM IER=0x%08x IMR=0x%08x, MASK=0x%08x\n", + pm_ier, pm_imr, pm_mask); + if (INTEL_GEN(dev_priv) <= 10) + seq_printf(m, "PM ISR=0x%08x IIR=0x%08x\n", + pm_isr, pm_iir); seq_printf(m, "pm_intrmsk_mbz: 0x%08x\n", rps->pm_intrmsk_mbz); seq_printf(m, "GT_PERF_STATUS: 0x%08x\n", gt_perf_status); diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index df234dc23274f..efb808272460c 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -1667,7 +1667,16 @@ static void capture_reg_state(struct i915_gpu_state *error) } /* 4: Everything else */ - if (INTEL_GEN(dev_priv) >= 8) { + if (INTEL_GEN(dev_priv) >= 11) { + error->ier = I915_READ(GEN8_DE_MISC_IER); + error->gtier[0] = I915_READ(GEN11_RENDER_COPY_INTR_ENABLE); + error->gtier[1] = I915_READ(GEN11_VCS_VECS_INTR_ENABLE); + error->gtier[2] = I915_READ(GEN11_GUC_SG_INTR_ENABLE); + error->gtier[3] = I915_READ(GEN11_GPM_WGBOXPERF_INTR_ENABLE); + error->gtier[4] = I915_READ(GEN11_CRYPTO_RSVD_INTR_ENABLE); + error->gtier[5] = I915_READ(GEN11_GUNIT_CSME_INTR_ENABLE); + error->ngtier = 6; + } else if (INTEL_GEN(dev_priv) >= 8) { error->ier = I915_READ(GEN8_DE_MISC_IER); for (i = 0; i < 4; i++) error->gtier[i] = I915_READ(GEN8_GT_IER(i)); diff --git a/drivers/gpu/drm/i915/i915_gpu_error.h b/drivers/gpu/drm/i915/i915_gpu_error.h index dac0f8c4c1cfa..58910f1dc67c2 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.h +++ b/drivers/gpu/drm/i915/i915_gpu_error.h @@ -58,7 +58,7 @@ struct i915_gpu_state { u32 eir; u32 pgtbl_er; u32 ier; - u32 gtier[4], ngtier; + u32 gtier[6], ngtier; u32 ccid; u32 derrmr; u32 forcewake; -- GitLab From c8af5274c3cbacb0905a26bcdef85901216e1134 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni <paulo.r.zanoni@intel.com> Date: Wed, 2 May 2018 14:58:51 -0700 Subject: [PATCH 0028/1506] drm/i915: enable the pipe/transcoder/planes later on HSW+ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For all platforms that run haswell_crtc_enable, our spec tells us to configure the transcoder clocks and do link training before it tells us to set pipeconf and the other pipe/transcoder/plane registers. Starting from Icelake, we get machine hangs if we try to touch the pipe/transcoder registers without having the clocks configured and not having some chicken bits set. So this patch changes haswell_crtc_enable() to issue the calls at the appropriate order mandated by the spec. While setting the appropriate chicken bits would also work here, it's better if we actually program the hardware the way it is intended to be programmed. And the chicken bit also has some theoretical downsides that may or may not affect us. Also, correctly programming the hardware does not prevent us from setting the chicken bits in a later patch in case we decide to. v2: Don't forget link training (Ville). Cc: Arthur J Runyan <arthur.j.runyan@intel.com> Cc: James Ausmus <james.ausmus@intel.com> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Reviewed-by: Manasi Navare <manasi.d.navare@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180502215851.30736-1-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/intel_display.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 817d5d3f65ebe..c9ec88acad9c1 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5581,6 +5581,11 @@ static void haswell_crtc_enable(struct intel_crtc_state *pipe_config, if (INTEL_GEN(dev_priv) >= 11) icl_map_plls_to_ports(crtc, pipe_config, old_state); + intel_encoders_pre_enable(crtc, pipe_config, old_state); + + if (!transcoder_is_dsi(cpu_transcoder)) + intel_ddi_enable_pipe_clock(pipe_config); + if (intel_crtc_has_dp_encoder(intel_crtc->config)) intel_dp_set_m_n(intel_crtc, M1_N1); @@ -5609,11 +5614,6 @@ static void haswell_crtc_enable(struct intel_crtc_state *pipe_config, intel_crtc->active = true; - intel_encoders_pre_enable(crtc, pipe_config, old_state); - - if (!transcoder_is_dsi(cpu_transcoder)) - intel_ddi_enable_pipe_clock(pipe_config); - /* Display WA #1180: WaDisableScalarClockGating: glk, cnl */ psl_clkgate_wa = (IS_GEMINILAKE(dev_priv) || IS_CANNONLAKE(dev_priv)) && intel_crtc->config->pch_pfit.enabled; -- GitLab From f25a49ab8ab9c1b5587837c8a386b276403f315c Mon Sep 17 00:00:00 2001 From: Colin Xu <colin.xu@intel.com> Date: Sat, 19 May 2018 12:28:54 +0800 Subject: [PATCH 0029/1506] drm/i915/gvt: Use vgpu_lock to protect per vgpu access The patch set splits out 2 small locks from the original big gvt lock: - vgpu_lock protects per-vGPU data and logic, especially the vGPU trap emulation path. - sched_lock protects gvt scheudler structure, context schedule logic and vGPU's schedule data. Use vgpu_lock to replace the gvt big lock. By doing this, the mmio read/write trap path, vgpu virtual event emulation and other vgpu related process, would be protected under per vgpu_lock. v9: - Change commit author since the patches are improved a lot compared with original version. Original author: Pei Zhang <pei.zhang@intel.com> - Rebase to latest gvt-staging. v8: - Correct coding and comment style. - Rebase to latest gvt-staging. v7: - Remove gtt_lock since already proteced by gvt_lock and vgpu_lock. - Fix a typo in intel_gvt_deactivate_vgpu, unlock the wrong lock. v6: - Rebase to latest gvt-staging. v5: - Rebase to latest gvt-staging. - intel_vgpu_page_track_handler should use vgpu_lock. v4: - Rebase to latest gvt-staging. - Protect vgpu->active access with vgpu_lock. - Do not wait gpu idle in vgpu_lock. v3: update to latest code base v2: add gvt->lock in function gvt_check_vblank_emulation Performance comparison on Kabylake platform. - Configuration: Host: Ubuntu 16.04. Guest 1 & 2: Ubuntu 16.04. glmark2 score comparison: - Configuration: Host: glxgears. Guests: glmark2. +--------------------------------+-----------------+ | Setup | glmark2 score | +--------------------------------+-----------------+ | unified lock, iommu=on | 58~62 (avg. 60) | +--------------------------------+-----------------+ | unified lock, iommu=igfx_off | 57~61 (avg. 59) | +--------------------------------+-----------------+ | per-logic lock, iommu=on | 60~68 (avg. 64) | +--------------------------------+-----------------+ | per-logic lock, iommu=igfx_off | 61~67 (avg. 64) | +--------------------------------+-----------------+ lock_stat comparison: - Configuration: Stop lock stat immediately after boot up. Boot 2 VM Guests. Run glmark2 in guests. Start perf lock_stat for 20 seconds and stop again. - Legend: c - contentions; w - waittime-avg +------------+-----------------+-----------+---------------+------------+ | | gvt_lock |sched_lock | vgpu_lock | gtt_lock | + lock type; +-----------------+-----------+---------------+------------+ | iommu set | c | w | c | w | c | w | c | w | +------------+-------+---------+----+------+------+--------+-----+------+ | unified; | 20697 | 839 |N/A | N/A | N/A | N/A | N/A | N/A | | on | | | | | | | | | +------------+-------+---------+----+------+------+--------+-----+------+ | unified; | 21838 | 658.15 |N/A | N/A | N/A | N/A | N/A | N/A | | igfx_off | | | | | | | | | +------------+-------+---------+----+------+------+--------+-----+------+ | per-logic; | 1553 | 1599.96 |9458|429.97| 5846 | 274.33 | 0 | 0.00 | | on | | | | | | | | | +------------+-------+---------+----+------+------+--------+-----+------+ | per-logic; | 1911 | 1678.32 |8335|445.16| 5451 | 244.80 | 0 | 0.00 | | igfx_off | | | | | | | | | +------------+-------+---------+----+------+------+--------+-----+------+ Signed-off-by: Pei Zhang <pei.zhang@intel.com> Signed-off-by: Colin Xu <colin.xu@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> --- drivers/gpu/drm/i915/gvt/display.c | 35 ++++++++++-------- drivers/gpu/drm/i915/gvt/gvt.c | 5 +-- drivers/gpu/drm/i915/gvt/gvt.h | 8 ++++ drivers/gpu/drm/i915/gvt/handlers.c | 4 ++ drivers/gpu/drm/i915/gvt/mmio.c | 12 +++--- drivers/gpu/drm/i915/gvt/page_track.c | 5 +-- drivers/gpu/drm/i915/gvt/scheduler.c | 9 +++-- drivers/gpu/drm/i915/gvt/vgpu.c | 53 ++++++++++++++------------- 8 files changed, 72 insertions(+), 59 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/display.c b/drivers/gpu/drm/i915/gvt/display.c index 6d8180e8d1e21..8e4a63c5b7d1f 100644 --- a/drivers/gpu/drm/i915/gvt/display.c +++ b/drivers/gpu/drm/i915/gvt/display.c @@ -337,26 +337,28 @@ void intel_gvt_check_vblank_emulation(struct intel_gvt *gvt) struct intel_gvt_irq *irq = &gvt->irq; struct intel_vgpu *vgpu; int pipe, id; + int found = false; - if (WARN_ON(!mutex_is_locked(&gvt->lock))) - return; - + mutex_lock(&gvt->lock); for_each_active_vgpu(gvt, vgpu, id) { for (pipe = 0; pipe < I915_MAX_PIPES; pipe++) { - if (pipe_is_enabled(vgpu, pipe)) - goto out; + if (pipe_is_enabled(vgpu, pipe)) { + found = true; + break; + } } + if (found) + break; } /* all the pipes are disabled */ - hrtimer_cancel(&irq->vblank_timer.timer); - return; - -out: - hrtimer_start(&irq->vblank_timer.timer, - ktime_add_ns(ktime_get(), irq->vblank_timer.period), - HRTIMER_MODE_ABS); - + if (!found) + hrtimer_cancel(&irq->vblank_timer.timer); + else + hrtimer_start(&irq->vblank_timer.timer, + ktime_add_ns(ktime_get(), irq->vblank_timer.period), + HRTIMER_MODE_ABS); + mutex_unlock(&gvt->lock); } static void emulate_vblank_on_pipe(struct intel_vgpu *vgpu, int pipe) @@ -393,8 +395,10 @@ static void emulate_vblank(struct intel_vgpu *vgpu) { int pipe; + mutex_lock(&vgpu->vgpu_lock); for_each_pipe(vgpu->gvt->dev_priv, pipe) emulate_vblank_on_pipe(vgpu, pipe); + mutex_unlock(&vgpu->vgpu_lock); } /** @@ -409,11 +413,10 @@ void intel_gvt_emulate_vblank(struct intel_gvt *gvt) struct intel_vgpu *vgpu; int id; - if (WARN_ON(!mutex_is_locked(&gvt->lock))) - return; - + mutex_lock(&gvt->lock); for_each_active_vgpu(gvt, vgpu, id) emulate_vblank(vgpu); + mutex_unlock(&gvt->lock); } /** diff --git a/drivers/gpu/drm/i915/gvt/gvt.c b/drivers/gpu/drm/i915/gvt/gvt.c index 61bd14fcb649f..769e06c3ae23e 100644 --- a/drivers/gpu/drm/i915/gvt/gvt.c +++ b/drivers/gpu/drm/i915/gvt/gvt.c @@ -271,11 +271,8 @@ static int gvt_service_thread(void *data) continue; if (test_and_clear_bit(INTEL_GVT_REQUEST_EMULATE_VBLANK, - (void *)&gvt->service_request)) { - mutex_lock(&gvt->lock); + (void *)&gvt->service_request)) intel_gvt_emulate_vblank(gvt); - mutex_unlock(&gvt->lock); - } if (test_bit(INTEL_GVT_REQUEST_SCHED, (void *)&gvt->service_request) || diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h index 05d15a095310d..3600553c8b56c 100644 --- a/drivers/gpu/drm/i915/gvt/gvt.h +++ b/drivers/gpu/drm/i915/gvt/gvt.h @@ -170,6 +170,7 @@ struct intel_vgpu_submission { struct intel_vgpu { struct intel_gvt *gvt; + struct mutex vgpu_lock; int id; unsigned long handle; /* vGPU handle used by hypervisor MPT modules */ bool active; @@ -294,6 +295,9 @@ struct intel_vgpu_type { }; struct intel_gvt { + /* GVT scope lock, protect GVT itself, and all resource currently + * not yet protected by special locks(vgpu and scheduler lock). + */ struct mutex lock; struct drm_i915_private *dev_priv; struct idr vgpu_idr; /* vGPU IDR pool */ @@ -314,6 +318,10 @@ struct intel_gvt { struct task_struct *service_thread; wait_queue_head_t service_thread_wq; + + /* service_request is always used in bit operation, we should always + * use it with atomic bit ops so that no need to use gvt big lock. + */ unsigned long service_request; struct { diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c index d5e2066610484..d60c2bee00fb2 100644 --- a/drivers/gpu/drm/i915/gvt/handlers.c +++ b/drivers/gpu/drm/i915/gvt/handlers.c @@ -316,6 +316,7 @@ static int gdrst_mmio_write(struct intel_vgpu *vgpu, unsigned int offset, } } + /* vgpu_lock already hold by emulate mmio r/w */ intel_gvt_reset_vgpu_locked(vgpu, false, engine_mask); /* sw will wait for the device to ack the reset request */ @@ -420,7 +421,10 @@ static int pipeconf_mmio_write(struct intel_vgpu *vgpu, unsigned int offset, vgpu_vreg(vgpu, offset) |= I965_PIPECONF_ACTIVE; else vgpu_vreg(vgpu, offset) &= ~I965_PIPECONF_ACTIVE; + /* vgpu_lock already hold by emulate mmio r/w */ + mutex_unlock(&vgpu->vgpu_lock); intel_gvt_check_vblank_emulation(vgpu->gvt); + mutex_lock(&vgpu->vgpu_lock); return 0; } diff --git a/drivers/gpu/drm/i915/gvt/mmio.c b/drivers/gpu/drm/i915/gvt/mmio.c index e4960aff68bd5..2be1be2cf49a0 100644 --- a/drivers/gpu/drm/i915/gvt/mmio.c +++ b/drivers/gpu/drm/i915/gvt/mmio.c @@ -67,7 +67,7 @@ static void failsafe_emulate_mmio_rw(struct intel_vgpu *vgpu, uint64_t pa, return; gvt = vgpu->gvt; - mutex_lock(&gvt->lock); + mutex_lock(&vgpu->vgpu_lock); offset = intel_vgpu_gpa_to_mmio_offset(vgpu, pa); if (reg_is_mmio(gvt, offset)) { if (read) @@ -85,7 +85,7 @@ static void failsafe_emulate_mmio_rw(struct intel_vgpu *vgpu, uint64_t pa, memcpy(pt, p_data, bytes); } - mutex_unlock(&gvt->lock); + mutex_unlock(&vgpu->vgpu_lock); } /** @@ -109,7 +109,7 @@ int intel_vgpu_emulate_mmio_read(struct intel_vgpu *vgpu, uint64_t pa, failsafe_emulate_mmio_rw(vgpu, pa, p_data, bytes, true); return 0; } - mutex_lock(&gvt->lock); + mutex_lock(&vgpu->vgpu_lock); offset = intel_vgpu_gpa_to_mmio_offset(vgpu, pa); @@ -156,7 +156,7 @@ int intel_vgpu_emulate_mmio_read(struct intel_vgpu *vgpu, uint64_t pa, gvt_vgpu_err("fail to emulate MMIO read %08x len %d\n", offset, bytes); out: - mutex_unlock(&gvt->lock); + mutex_unlock(&vgpu->vgpu_lock); return ret; } @@ -182,7 +182,7 @@ int intel_vgpu_emulate_mmio_write(struct intel_vgpu *vgpu, uint64_t pa, return 0; } - mutex_lock(&gvt->lock); + mutex_lock(&vgpu->vgpu_lock); offset = intel_vgpu_gpa_to_mmio_offset(vgpu, pa); @@ -220,7 +220,7 @@ int intel_vgpu_emulate_mmio_write(struct intel_vgpu *vgpu, uint64_t pa, gvt_vgpu_err("fail to emulate MMIO write %08x len %d\n", offset, bytes); out: - mutex_unlock(&gvt->lock); + mutex_unlock(&vgpu->vgpu_lock); return ret; } diff --git a/drivers/gpu/drm/i915/gvt/page_track.c b/drivers/gpu/drm/i915/gvt/page_track.c index 53e2bd79c97d9..256d0db8bbb15 100644 --- a/drivers/gpu/drm/i915/gvt/page_track.c +++ b/drivers/gpu/drm/i915/gvt/page_track.c @@ -157,11 +157,10 @@ int intel_vgpu_disable_page_track(struct intel_vgpu *vgpu, unsigned long gfn) int intel_vgpu_page_track_handler(struct intel_vgpu *vgpu, u64 gpa, void *data, unsigned int bytes) { - struct intel_gvt *gvt = vgpu->gvt; struct intel_vgpu_page_track *page_track; int ret = 0; - mutex_lock(&gvt->lock); + mutex_lock(&vgpu->vgpu_lock); page_track = intel_vgpu_find_page_track(vgpu, gpa >> PAGE_SHIFT); if (!page_track) { @@ -179,6 +178,6 @@ int intel_vgpu_page_track_handler(struct intel_vgpu *vgpu, u64 gpa, } out: - mutex_unlock(&gvt->lock); + mutex_unlock(&vgpu->vgpu_lock); return ret; } diff --git a/drivers/gpu/drm/i915/gvt/scheduler.c b/drivers/gpu/drm/i915/gvt/scheduler.c index c2d183b91500b..c0848dcf79c72 100644 --- a/drivers/gpu/drm/i915/gvt/scheduler.c +++ b/drivers/gpu/drm/i915/gvt/scheduler.c @@ -680,6 +680,7 @@ static int dispatch_workload(struct intel_vgpu_workload *workload) gvt_dbg_sched("ring id %d prepare to dispatch workload %p\n", ring_id, workload); + mutex_lock(&vgpu->vgpu_lock); mutex_lock(&dev_priv->drm.struct_mutex); ret = intel_gvt_scan_and_shadow_workload(workload); @@ -704,6 +705,7 @@ static int dispatch_workload(struct intel_vgpu_workload *workload) } mutex_unlock(&dev_priv->drm.struct_mutex); + mutex_unlock(&vgpu->vgpu_lock); return ret; } @@ -861,14 +863,14 @@ static void complete_current_workload(struct intel_gvt *gvt, int ring_id) int event; mutex_lock(&gvt->lock); + mutex_lock(&vgpu->vgpu_lock); /* For the workload w/ request, needs to wait for the context * switch to make sure request is completed. * For the workload w/o request, directly complete the workload. */ if (workload->req) { - struct drm_i915_private *dev_priv = - workload->vgpu->gvt->dev_priv; + struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv; struct intel_engine_cs *engine = dev_priv->engine[workload->ring_id]; wait_event(workload->shadow_ctx_status_wq, @@ -939,6 +941,7 @@ static void complete_current_workload(struct intel_gvt *gvt, int ring_id) if (gvt->scheduler.need_reschedule) intel_gvt_request_service(gvt, INTEL_GVT_REQUEST_EVENT_SCHED); + mutex_unlock(&vgpu->vgpu_lock); mutex_unlock(&gvt->lock); } @@ -991,9 +994,7 @@ static int workload_thread(void *priv) intel_uncore_forcewake_get(gvt->dev_priv, FORCEWAKE_ALL); - mutex_lock(&gvt->lock); ret = dispatch_workload(workload); - mutex_unlock(&gvt->lock); if (ret) { vgpu = workload->vgpu; diff --git a/drivers/gpu/drm/i915/gvt/vgpu.c b/drivers/gpu/drm/i915/gvt/vgpu.c index bf75300c1ec16..889d10f8ee96c 100644 --- a/drivers/gpu/drm/i915/gvt/vgpu.c +++ b/drivers/gpu/drm/i915/gvt/vgpu.c @@ -226,22 +226,20 @@ void intel_gvt_activate_vgpu(struct intel_vgpu *vgpu) */ void intel_gvt_deactivate_vgpu(struct intel_vgpu *vgpu) { - struct intel_gvt *gvt = vgpu->gvt; - - mutex_lock(&gvt->lock); + mutex_lock(&vgpu->vgpu_lock); vgpu->active = false; if (atomic_read(&vgpu->submission.running_workload_num)) { - mutex_unlock(&gvt->lock); + mutex_unlock(&vgpu->vgpu_lock); intel_gvt_wait_vgpu_idle(vgpu); - mutex_lock(&gvt->lock); + mutex_lock(&vgpu->vgpu_lock); } intel_vgpu_stop_schedule(vgpu); intel_vgpu_dmabuf_cleanup(vgpu); - mutex_unlock(&gvt->lock); + mutex_unlock(&vgpu->vgpu_lock); } /** @@ -255,14 +253,11 @@ void intel_gvt_destroy_vgpu(struct intel_vgpu *vgpu) { struct intel_gvt *gvt = vgpu->gvt; - mutex_lock(&gvt->lock); + mutex_lock(&vgpu->vgpu_lock); WARN(vgpu->active, "vGPU is still active!\n"); intel_gvt_debugfs_remove_vgpu(vgpu); - idr_remove(&gvt->vgpu_idr, vgpu->id); - if (idr_is_empty(&gvt->vgpu_idr)) - intel_gvt_clean_irq(gvt); intel_vgpu_clean_sched_policy(vgpu); intel_vgpu_clean_submission(vgpu); intel_vgpu_clean_display(vgpu); @@ -272,10 +267,16 @@ void intel_gvt_destroy_vgpu(struct intel_vgpu *vgpu) intel_vgpu_free_resource(vgpu); intel_vgpu_clean_mmio(vgpu); intel_vgpu_dmabuf_cleanup(vgpu); - vfree(vgpu); + mutex_unlock(&vgpu->vgpu_lock); + mutex_lock(&gvt->lock); + idr_remove(&gvt->vgpu_idr, vgpu->id); + if (idr_is_empty(&gvt->vgpu_idr)) + intel_gvt_clean_irq(gvt); intel_gvt_update_vgpu_types(gvt); mutex_unlock(&gvt->lock); + + vfree(vgpu); } #define IDLE_VGPU_IDR 0 @@ -301,6 +302,7 @@ struct intel_vgpu *intel_gvt_create_idle_vgpu(struct intel_gvt *gvt) vgpu->id = IDLE_VGPU_IDR; vgpu->gvt = gvt; + mutex_init(&vgpu->vgpu_lock); for (i = 0; i < I915_NUM_ENGINES; i++) INIT_LIST_HEAD(&vgpu->submission.workload_q_head[i]); @@ -327,7 +329,10 @@ struct intel_vgpu *intel_gvt_create_idle_vgpu(struct intel_gvt *gvt) */ void intel_gvt_destroy_idle_vgpu(struct intel_vgpu *vgpu) { + mutex_lock(&vgpu->vgpu_lock); intel_vgpu_clean_sched_policy(vgpu); + mutex_unlock(&vgpu->vgpu_lock); + vfree(vgpu); } @@ -345,8 +350,6 @@ static struct intel_vgpu *__intel_gvt_create_vgpu(struct intel_gvt *gvt, if (!vgpu) return ERR_PTR(-ENOMEM); - mutex_lock(&gvt->lock); - ret = idr_alloc(&gvt->vgpu_idr, vgpu, IDLE_VGPU_IDR + 1, GVT_MAX_VGPU, GFP_KERNEL); if (ret < 0) @@ -356,6 +359,7 @@ static struct intel_vgpu *__intel_gvt_create_vgpu(struct intel_gvt *gvt, vgpu->handle = param->handle; vgpu->gvt = gvt; vgpu->sched_ctl.weight = param->weight; + mutex_init(&vgpu->vgpu_lock); INIT_LIST_HEAD(&vgpu->dmabuf_obj_list_head); INIT_RADIX_TREE(&vgpu->page_track_tree, GFP_KERNEL); idr_init(&vgpu->object_idr); @@ -403,8 +407,6 @@ static struct intel_vgpu *__intel_gvt_create_vgpu(struct intel_gvt *gvt, if (ret) goto out_clean_sched_policy; - mutex_unlock(&gvt->lock); - return vgpu; out_clean_sched_policy: @@ -427,7 +429,6 @@ static struct intel_vgpu *__intel_gvt_create_vgpu(struct intel_gvt *gvt, idr_remove(&gvt->vgpu_idr, vgpu->id); out_free_vgpu: vfree(vgpu); - mutex_unlock(&gvt->lock); return ERR_PTR(ret); } @@ -459,12 +460,12 @@ struct intel_vgpu *intel_gvt_create_vgpu(struct intel_gvt *gvt, param.low_gm_sz = BYTES_TO_MB(param.low_gm_sz); param.high_gm_sz = BYTES_TO_MB(param.high_gm_sz); + mutex_lock(&gvt->lock); vgpu = __intel_gvt_create_vgpu(gvt, ¶m); - if (IS_ERR(vgpu)) - return vgpu; - - /* calculate left instance change for types */ - intel_gvt_update_vgpu_types(gvt); + if (!IS_ERR(vgpu)) + /* calculate left instance change for types */ + intel_gvt_update_vgpu_types(gvt); + mutex_unlock(&gvt->lock); return vgpu; } @@ -476,7 +477,7 @@ struct intel_vgpu *intel_gvt_create_vgpu(struct intel_gvt *gvt, * @engine_mask: engines to reset for GT reset * * This function is called when user wants to reset a virtual GPU through - * device model reset or GT reset. The caller should hold the gvt lock. + * device model reset or GT reset. The caller should hold the vgpu lock. * * vGPU Device Model Level Reset (DMLR) simulates the PCI level reset to reset * the whole vGPU to default state as when it is created. This vGPU function @@ -516,9 +517,9 @@ void intel_gvt_reset_vgpu_locked(struct intel_vgpu *vgpu, bool dmlr, * scheduler when the reset is triggered by current vgpu. */ if (scheduler->current_vgpu == NULL) { - mutex_unlock(&gvt->lock); + mutex_unlock(&vgpu->vgpu_lock); intel_gvt_wait_vgpu_idle(vgpu); - mutex_lock(&gvt->lock); + mutex_lock(&vgpu->vgpu_lock); } intel_vgpu_reset_submission(vgpu, resetting_eng); @@ -558,7 +559,7 @@ void intel_gvt_reset_vgpu_locked(struct intel_vgpu *vgpu, bool dmlr, */ void intel_gvt_reset_vgpu(struct intel_vgpu *vgpu) { - mutex_lock(&vgpu->gvt->lock); + mutex_lock(&vgpu->vgpu_lock); intel_gvt_reset_vgpu_locked(vgpu, true, 0); - mutex_unlock(&vgpu->gvt->lock); + mutex_unlock(&vgpu->vgpu_lock); } -- GitLab From 9a512e23f173a3598709b74d6ccf9a6616403967 Mon Sep 17 00:00:00 2001 From: Colin Xu <colin.xu@intel.com> Date: Sat, 19 May 2018 12:28:55 +0800 Subject: [PATCH 0030/1506] drm/i915/gvt: Use sched_lock to protect gvt scheduler logic. The scheduler lock(gvt->sched_lock) is used to protect gvt scheduler logic, including the gvt scheduler structure(gvt->scheduler and per vgpu schedule data(vgpu->sched_data, vgpu->sched_ctl). v9: - Change commit author since the patches are improved a lot compared with original version. Original author: Pei Zhang <pei.zhang@intel.com> - Rebase to latest gvt-staging. v8: - Correct coding wqstyle. - Rebase to latest gvt-staging. v7: - Remove gtt_lock since already proteced by gvt_lock and vgpu_lock. v6: - Rebase to latest gvt-staging. v5: - Rebase to latest gvt-staging. v4: - Rebase to latest gvt-staging. v3: update to latest code base Signed-off-by: Pei Zhang <pei.zhang@intel.com> Signed-off-by: Colin Xu <colin.xu@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> --- drivers/gpu/drm/i915/gvt/gvt.c | 1 + drivers/gpu/drm/i915/gvt/gvt.h | 8 ++++++ drivers/gpu/drm/i915/gvt/sched_policy.c | 36 ++++++++++++++++++++++--- drivers/gpu/drm/i915/gvt/scheduler.c | 8 +++--- 4 files changed, 45 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/gvt.c b/drivers/gpu/drm/i915/gvt/gvt.c index 769e06c3ae23e..22a3ddff38a3d 100644 --- a/drivers/gpu/drm/i915/gvt/gvt.c +++ b/drivers/gpu/drm/i915/gvt/gvt.c @@ -376,6 +376,7 @@ int intel_gvt_init_device(struct drm_i915_private *dev_priv) idr_init(&gvt->vgpu_idr); spin_lock_init(&gvt->scheduler.mmio_context_lock); mutex_init(&gvt->lock); + mutex_init(&gvt->sched_lock); gvt->dev_priv = dev_priv; init_device_info(gvt); diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h index 3600553c8b56c..362e3d506d2db 100644 --- a/drivers/gpu/drm/i915/gvt/gvt.h +++ b/drivers/gpu/drm/i915/gvt/gvt.h @@ -177,6 +177,11 @@ struct intel_vgpu { bool pv_notified; bool failsafe; unsigned int resetting_eng; + + /* Both sched_data and sched_ctl can be seen a part of the global gvt + * scheduler structure. So below 2 vgpu data are protected + * by sched_lock, not vgpu_lock. + */ void *sched_data; struct vgpu_sched_ctl sched_ctl; @@ -299,6 +304,9 @@ struct intel_gvt { * not yet protected by special locks(vgpu and scheduler lock). */ struct mutex lock; + /* scheduler scope lock, protect gvt and vgpu schedule related data */ + struct mutex sched_lock; + struct drm_i915_private *dev_priv; struct idr vgpu_idr; /* vGPU IDR pool */ diff --git a/drivers/gpu/drm/i915/gvt/sched_policy.c b/drivers/gpu/drm/i915/gvt/sched_policy.c index d053cbe1dc94c..09d7bb72b4ff3 100644 --- a/drivers/gpu/drm/i915/gvt/sched_policy.c +++ b/drivers/gpu/drm/i915/gvt/sched_policy.c @@ -228,7 +228,7 @@ void intel_gvt_schedule(struct intel_gvt *gvt) struct gvt_sched_data *sched_data = gvt->scheduler.sched_data; ktime_t cur_time; - mutex_lock(&gvt->lock); + mutex_lock(&gvt->sched_lock); cur_time = ktime_get(); if (test_and_clear_bit(INTEL_GVT_REQUEST_SCHED, @@ -244,7 +244,7 @@ void intel_gvt_schedule(struct intel_gvt *gvt) vgpu_update_timeslice(gvt->scheduler.current_vgpu, cur_time); tbs_sched_func(sched_data); - mutex_unlock(&gvt->lock); + mutex_unlock(&gvt->sched_lock); } static enum hrtimer_restart tbs_timer_fn(struct hrtimer *timer_data) @@ -359,39 +359,65 @@ static struct intel_gvt_sched_policy_ops tbs_schedule_ops = { int intel_gvt_init_sched_policy(struct intel_gvt *gvt) { + int ret; + + mutex_lock(&gvt->sched_lock); gvt->scheduler.sched_ops = &tbs_schedule_ops; + ret = gvt->scheduler.sched_ops->init(gvt); + mutex_unlock(&gvt->sched_lock); - return gvt->scheduler.sched_ops->init(gvt); + return ret; } void intel_gvt_clean_sched_policy(struct intel_gvt *gvt) { + mutex_lock(&gvt->sched_lock); gvt->scheduler.sched_ops->clean(gvt); + mutex_unlock(&gvt->sched_lock); } +/* for per-vgpu scheduler policy, there are 2 per-vgpu data: + * sched_data, and sched_ctl. We see these 2 data as part of + * the global scheduler which are proteced by gvt->sched_lock. + * Caller should make their decision if the vgpu_lock should + * be hold outside. + */ + int intel_vgpu_init_sched_policy(struct intel_vgpu *vgpu) { - return vgpu->gvt->scheduler.sched_ops->init_vgpu(vgpu); + int ret; + + mutex_lock(&vgpu->gvt->sched_lock); + ret = vgpu->gvt->scheduler.sched_ops->init_vgpu(vgpu); + mutex_unlock(&vgpu->gvt->sched_lock); + + return ret; } void intel_vgpu_clean_sched_policy(struct intel_vgpu *vgpu) { + mutex_lock(&vgpu->gvt->sched_lock); vgpu->gvt->scheduler.sched_ops->clean_vgpu(vgpu); + mutex_unlock(&vgpu->gvt->sched_lock); } void intel_vgpu_start_schedule(struct intel_vgpu *vgpu) { struct vgpu_sched_data *vgpu_data = vgpu->sched_data; + mutex_lock(&vgpu->gvt->sched_lock); if (!vgpu_data->active) { gvt_dbg_core("vgpu%d: start schedule\n", vgpu->id); vgpu->gvt->scheduler.sched_ops->start_schedule(vgpu); } + mutex_unlock(&vgpu->gvt->sched_lock); } void intel_gvt_kick_schedule(struct intel_gvt *gvt) { + mutex_lock(&gvt->sched_lock); intel_gvt_request_service(gvt, INTEL_GVT_REQUEST_EVENT_SCHED); + mutex_unlock(&gvt->sched_lock); } void intel_vgpu_stop_schedule(struct intel_vgpu *vgpu) @@ -406,6 +432,7 @@ void intel_vgpu_stop_schedule(struct intel_vgpu *vgpu) gvt_dbg_core("vgpu%d: stop schedule\n", vgpu->id); + mutex_lock(&vgpu->gvt->sched_lock); scheduler->sched_ops->stop_schedule(vgpu); if (scheduler->next_vgpu == vgpu) @@ -425,4 +452,5 @@ void intel_vgpu_stop_schedule(struct intel_vgpu *vgpu) } } spin_unlock_bh(&scheduler->mmio_context_lock); + mutex_unlock(&vgpu->gvt->sched_lock); } diff --git a/drivers/gpu/drm/i915/gvt/scheduler.c b/drivers/gpu/drm/i915/gvt/scheduler.c index c0848dcf79c72..847f295e6755b 100644 --- a/drivers/gpu/drm/i915/gvt/scheduler.c +++ b/drivers/gpu/drm/i915/gvt/scheduler.c @@ -715,7 +715,7 @@ static struct intel_vgpu_workload *pick_next_workload( struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler; struct intel_vgpu_workload *workload = NULL; - mutex_lock(&gvt->lock); + mutex_lock(&gvt->sched_lock); /* * no current vgpu / will be scheduled out / no workload @@ -761,7 +761,7 @@ static struct intel_vgpu_workload *pick_next_workload( atomic_inc(&workload->vgpu->submission.running_workload_num); out: - mutex_unlock(&gvt->lock); + mutex_unlock(&gvt->sched_lock); return workload; } @@ -862,8 +862,8 @@ static void complete_current_workload(struct intel_gvt *gvt, int ring_id) struct intel_vgpu_submission *s = &vgpu->submission; int event; - mutex_lock(&gvt->lock); mutex_lock(&vgpu->vgpu_lock); + mutex_lock(&gvt->sched_lock); /* For the workload w/ request, needs to wait for the context * switch to make sure request is completed. @@ -941,8 +941,8 @@ static void complete_current_workload(struct intel_gvt *gvt, int ring_id) if (gvt->scheduler.need_reschedule) intel_gvt_request_service(gvt, INTEL_GVT_REQUEST_EVENT_SCHED); + mutex_unlock(&gvt->sched_lock); mutex_unlock(&vgpu->vgpu_lock); - mutex_unlock(&gvt->lock); } struct workload_thread_param { -- GitLab From 4e0d64dba816adf18c17488d38ede67a3d0e9b40 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 17 May 2018 22:26:30 +0100 Subject: [PATCH 0031/1506] drm/i915: Move request->ctx aside In the next patch, we want to store the intel_context pointer inside i915_request, as it is frequently access via a convoluted dance when submitting the request to hw. Having two context pointers inside i915_request leads to confusion so first rename the existing i915_gem_context pointer to i915_request.gem_context. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180517212633.24934-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/gvt/scheduler.c | 4 +-- drivers/gpu/drm/i915/i915_debugfs.c | 4 +-- drivers/gpu/drm/i915/i915_gem.c | 10 +++--- drivers/gpu/drm/i915/i915_gpu_error.c | 18 ++++++----- drivers/gpu/drm/i915/i915_request.c | 12 +++---- drivers/gpu/drm/i915/i915_request.h | 2 +- drivers/gpu/drm/i915/i915_trace.h | 10 +++--- drivers/gpu/drm/i915/intel_engine_cs.c | 2 +- drivers/gpu/drm/i915/intel_guc_submission.c | 7 +++-- drivers/gpu/drm/i915/intel_lrc.c | 31 ++++++++++--------- drivers/gpu/drm/i915/intel_ringbuffer.c | 12 +++---- .../gpu/drm/i915/selftests/intel_hangcheck.c | 5 ++- drivers/gpu/drm/i915/selftests/intel_lrc.c | 2 +- 13 files changed, 64 insertions(+), 55 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/scheduler.c b/drivers/gpu/drm/i915/gvt/scheduler.c index c2d183b91500b..17f9f8d7e148e 100644 --- a/drivers/gpu/drm/i915/gvt/scheduler.c +++ b/drivers/gpu/drm/i915/gvt/scheduler.c @@ -205,7 +205,7 @@ static int populate_shadow_context(struct intel_vgpu_workload *workload) static inline bool is_gvt_request(struct i915_request *req) { - return i915_gem_context_force_single_submission(req->ctx); + return i915_gem_context_force_single_submission(req->gem_context); } static void save_ring_hw_state(struct intel_vgpu *vgpu, int ring_id) @@ -305,7 +305,7 @@ static int copy_workload_to_ring_buffer(struct intel_vgpu_workload *workload) struct i915_request *req = workload->req; if (IS_KABYLAKE(req->i915) && - is_inhibit_context(req->ctx, req->engine->id)) + is_inhibit_context(req->gem_context, req->engine->id)) intel_vgpu_restore_inhibit_context(vgpu, req); /* allocate shadow ring buffer */ diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index d78beaabc051c..52515445ac406 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -542,8 +542,8 @@ static int i915_gem_object_info(struct seq_file *m, void *data) struct i915_request, client_link); rcu_read_lock(); - task = pid_task(request && request->ctx->pid ? - request->ctx->pid : file->pid, + task = pid_task(request && request->gem_context->pid ? + request->gem_context->pid : file->pid, PIDTYPE_PID); print_file_stats(m, task ? task->comm : "<unknown>", stats); rcu_read_unlock(); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index b0fe452ce17cd..a20f8db5729dc 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3067,7 +3067,7 @@ static void skip_request(struct i915_request *request) static void engine_skip_context(struct i915_request *request) { struct intel_engine_cs *engine = request->engine; - struct i915_gem_context *hung_ctx = request->ctx; + struct i915_gem_context *hung_ctx = request->gem_context; struct i915_timeline *timeline = request->timeline; unsigned long flags; @@ -3077,7 +3077,7 @@ static void engine_skip_context(struct i915_request *request) spin_lock_nested(&timeline->lock, SINGLE_DEPTH_NESTING); list_for_each_entry_continue(request, &engine->timeline.requests, link) - if (request->ctx == hung_ctx) + if (request->gem_context == hung_ctx) skip_request(request); list_for_each_entry(request, &timeline->requests, link) @@ -3123,11 +3123,11 @@ i915_gem_reset_request(struct intel_engine_cs *engine, } if (stalled) { - i915_gem_context_mark_guilty(request->ctx); + i915_gem_context_mark_guilty(request->gem_context); skip_request(request); /* If this context is now banned, skip all pending requests. */ - if (i915_gem_context_is_banned(request->ctx)) + if (i915_gem_context_is_banned(request->gem_context)) engine_skip_context(request); } else { /* @@ -3137,7 +3137,7 @@ i915_gem_reset_request(struct intel_engine_cs *engine, */ request = i915_gem_find_active_request(engine); if (request) { - i915_gem_context_mark_innocent(request->ctx); + i915_gem_context_mark_innocent(request->gem_context); dma_fence_set_error(&request->fence, -EAGAIN); /* Rewind the engine to replay the incomplete rq */ diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index efb808272460c..37c9a42654ba7 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -1287,9 +1287,11 @@ static void error_record_engine_registers(struct i915_gpu_state *error, static void record_request(struct i915_request *request, struct drm_i915_error_request *erq) { - erq->context = request->ctx->hw_id; + struct i915_gem_context *ctx = request->gem_context; + + erq->context = ctx->hw_id; erq->sched_attr = request->sched.attr; - erq->ban_score = atomic_read(&request->ctx->ban_score); + erq->ban_score = atomic_read(&ctx->ban_score); erq->seqno = request->global_seqno; erq->jiffies = request->emitted_jiffies; erq->start = i915_ggtt_offset(request->ring->vma); @@ -1297,7 +1299,7 @@ static void record_request(struct i915_request *request, erq->tail = request->tail; rcu_read_lock(); - erq->pid = request->ctx->pid ? pid_nr(request->ctx->pid) : 0; + erq->pid = ctx->pid ? pid_nr(ctx->pid) : 0; rcu_read_unlock(); } @@ -1461,12 +1463,12 @@ static void gem_record_rings(struct i915_gpu_state *error) request = i915_gem_find_active_request(engine); if (request) { + struct i915_gem_context *ctx = request->gem_context; struct intel_ring *ring; - ee->vm = request->ctx->ppgtt ? - &request->ctx->ppgtt->base : &ggtt->base; + ee->vm = ctx->ppgtt ? &ctx->ppgtt->base : &ggtt->base; - record_context(&ee->context, request->ctx); + record_context(&ee->context, ctx); /* We need to copy these to an anonymous buffer * as the simplest method to avoid being overwritten @@ -1483,11 +1485,11 @@ static void gem_record_rings(struct i915_gpu_state *error) ee->ctx = i915_error_object_create(i915, - to_intel_context(request->ctx, + to_intel_context(ctx, engine)->state); error->simulated |= - i915_gem_context_no_error_capture(request->ctx); + i915_gem_context_no_error_capture(ctx); ee->rq_head = request->head; ee->rq_post = request->postfix; diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index 8928894dd9c77..fe8810a6a339d 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -384,7 +384,7 @@ static void __retire_engine_request(struct intel_engine_cs *engine, */ if (engine->last_retired_context) intel_context_unpin(engine->last_retired_context, engine); - engine->last_retired_context = rq->ctx; + engine->last_retired_context = rq->gem_context; } static void __retire_engine_upto(struct intel_engine_cs *engine, @@ -455,8 +455,8 @@ static void i915_request_retire(struct i915_request *request) i915_request_remove_from_client(request); /* Retirement decays the ban score as it is a sign of ctx progress */ - atomic_dec_if_positive(&request->ctx->ban_score); - intel_context_unpin(request->ctx, request->engine); + atomic_dec_if_positive(&request->gem_context->ban_score); + intel_context_unpin(request->gem_context, request->engine); __retire_engine_upto(request->engine, request); @@ -760,7 +760,7 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx) INIT_LIST_HEAD(&rq->active_list); rq->i915 = i915; rq->engine = engine; - rq->ctx = ctx; + rq->gem_context = ctx; rq->ring = ring; rq->timeline = ring->timeline; GEM_BUG_ON(rq->timeline == &engine->timeline); @@ -814,7 +814,7 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx) goto err_unwind; /* Keep a second pin for the dual retirement along engine and ring */ - __intel_context_pin(rq->ctx, engine); + __intel_context_pin(rq->gem_context, engine); /* Check that we didn't interrupt ourselves with a new request */ GEM_BUG_ON(rq->timeline->seqno != rq->fence.seqno); @@ -1113,7 +1113,7 @@ void __i915_request_add(struct i915_request *request, bool flush_caches) local_bh_disable(); rcu_read_lock(); /* RCU serialisation for set-wedged protection */ if (engine->schedule) - engine->schedule(request, &request->ctx->sched); + engine->schedule(request, &request->gem_context->sched); rcu_read_unlock(); i915_sw_fence_commit(&request->submit); local_bh_enable(); /* Kick the execlists tasklet if just scheduled */ diff --git a/drivers/gpu/drm/i915/i915_request.h b/drivers/gpu/drm/i915/i915_request.h index eddbd4245cb3a..dddecd9ffd0c0 100644 --- a/drivers/gpu/drm/i915/i915_request.h +++ b/drivers/gpu/drm/i915/i915_request.h @@ -93,7 +93,7 @@ struct i915_request { * i915_request_free() will then decrement the refcount on the * context. */ - struct i915_gem_context *ctx; + struct i915_gem_context *gem_context; struct intel_engine_cs *engine; struct intel_ring *ring; struct i915_timeline *timeline; diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h index 8cc3a256f29d3..5d4f78765083e 100644 --- a/drivers/gpu/drm/i915/i915_trace.h +++ b/drivers/gpu/drm/i915/i915_trace.h @@ -624,7 +624,7 @@ TRACE_EVENT(i915_request_queue, TP_fast_assign( __entry->dev = rq->i915->drm.primary->index; - __entry->hw_id = rq->ctx->hw_id; + __entry->hw_id = rq->gem_context->hw_id; __entry->ring = rq->engine->id; __entry->ctx = rq->fence.context; __entry->seqno = rq->fence.seqno; @@ -651,7 +651,7 @@ DECLARE_EVENT_CLASS(i915_request, TP_fast_assign( __entry->dev = rq->i915->drm.primary->index; - __entry->hw_id = rq->ctx->hw_id; + __entry->hw_id = rq->gem_context->hw_id; __entry->ring = rq->engine->id; __entry->ctx = rq->fence.context; __entry->seqno = rq->fence.seqno; @@ -696,7 +696,7 @@ TRACE_EVENT(i915_request_in, TP_fast_assign( __entry->dev = rq->i915->drm.primary->index; - __entry->hw_id = rq->ctx->hw_id; + __entry->hw_id = rq->gem_context->hw_id; __entry->ring = rq->engine->id; __entry->ctx = rq->fence.context; __entry->seqno = rq->fence.seqno; @@ -727,7 +727,7 @@ TRACE_EVENT(i915_request_out, TP_fast_assign( __entry->dev = rq->i915->drm.primary->index; - __entry->hw_id = rq->ctx->hw_id; + __entry->hw_id = rq->gem_context->hw_id; __entry->ring = rq->engine->id; __entry->ctx = rq->fence.context; __entry->seqno = rq->fence.seqno; @@ -815,7 +815,7 @@ TRACE_EVENT(i915_request_wait_begin, */ TP_fast_assign( __entry->dev = rq->i915->drm.primary->index; - __entry->hw_id = rq->ctx->hw_id; + __entry->hw_id = rq->gem_context->hw_id; __entry->ring = rq->engine->id; __entry->ctx = rq->fence.context; __entry->seqno = rq->fence.seqno; diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index e78c6e769e8cd..7983b8a1ad446 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -1020,7 +1020,7 @@ bool intel_engine_has_kernel_context(const struct intel_engine_cs *engine) */ rq = __i915_gem_active_peek(&engine->timeline.last_request); if (rq) - return rq->ctx == kernel_context; + return rq->gem_context == kernel_context; else return engine->last_retired_context == kernel_context; } diff --git a/drivers/gpu/drm/i915/intel_guc_submission.c b/drivers/gpu/drm/i915/intel_guc_submission.c index 637e852888ec1..a432a193f3c40 100644 --- a/drivers/gpu/drm/i915/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/intel_guc_submission.c @@ -513,8 +513,9 @@ static void guc_add_request(struct intel_guc *guc, struct i915_request *rq) { struct intel_guc_client *client = guc->execbuf_client; struct intel_engine_cs *engine = rq->engine; - u32 ctx_desc = lower_32_bits(intel_lr_context_descriptor(rq->ctx, - engine)); + u32 ctx_desc = + lower_32_bits(intel_lr_context_descriptor(rq->gem_context, + engine)); u32 ring_tail = intel_ring_set_tail(rq->ring, rq->tail) / sizeof(u64); spin_lock(&client->wq_lock); @@ -725,7 +726,7 @@ static bool __guc_dequeue(struct intel_engine_cs *engine) struct i915_request *rq, *rn; list_for_each_entry_safe(rq, rn, &p->requests, sched.link) { - if (last && rq->ctx != last->ctx) { + if (last && rq->gem_context != last->gem_context) { if (port == last_port) { __list_del_many(&p->requests, &rq->sched.link); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index ae5adad7cc639..1e9cc55d785c0 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -418,9 +418,10 @@ execlists_update_context_pdps(struct i915_hw_ppgtt *ppgtt, u32 *reg_state) static u64 execlists_update_context(struct i915_request *rq) { - struct intel_context *ce = to_intel_context(rq->ctx, rq->engine); + struct intel_context *ce = + to_intel_context(rq->gem_context, rq->engine); struct i915_hw_ppgtt *ppgtt = - rq->ctx->ppgtt ?: rq->i915->mm.aliasing_ppgtt; + rq->gem_context->ppgtt ?: rq->i915->mm.aliasing_ppgtt; u32 *reg_state = ce->lrc_reg_state; reg_state[CTX_RING_TAIL+1] = intel_ring_set_tail(rq->ring, rq->tail); @@ -679,7 +680,8 @@ static bool __execlists_dequeue(struct intel_engine_cs *engine) * second request, and so we never need to tell the * hardware about the first. */ - if (last && !can_merge_ctx(rq->ctx, last->ctx)) { + if (last && !can_merge_ctx(rq->gem_context, + last->gem_context)) { /* * If we are on the second port and cannot * combine this request with the last, then we @@ -698,14 +700,14 @@ static bool __execlists_dequeue(struct intel_engine_cs *engine) * the same context (even though a different * request) to the second port. */ - if (ctx_single_port_submission(last->ctx) || - ctx_single_port_submission(rq->ctx)) { + if (ctx_single_port_submission(last->gem_context) || + ctx_single_port_submission(rq->gem_context)) { __list_del_many(&p->requests, &rq->sched.link); goto done; } - GEM_BUG_ON(last->ctx == rq->ctx); + GEM_BUG_ON(last->gem_context == rq->gem_context); if (submit) port_assign(port, last); @@ -1437,7 +1439,7 @@ static void execlists_context_unpin(struct intel_engine_cs *engine, static int execlists_request_alloc(struct i915_request *request) { struct intel_context *ce = - to_intel_context(request->ctx, request->engine); + to_intel_context(request->gem_context, request->engine); int ret; GEM_BUG_ON(!ce->pin_count); @@ -1954,7 +1956,7 @@ static void execlists_reset(struct intel_engine_cs *engine, * future request will be after userspace has had the opportunity * to recreate its own state. */ - regs = to_intel_context(request->ctx, engine)->lrc_reg_state; + regs = to_intel_context(request->gem_context, engine)->lrc_reg_state; if (engine->default_state) { void *defaults; @@ -1967,7 +1969,8 @@ static void execlists_reset(struct intel_engine_cs *engine, i915_gem_object_unpin_map(engine->default_state); } } - execlists_init_reg_state(regs, request->ctx, engine, request->ring); + execlists_init_reg_state(regs, + request->gem_context, engine, request->ring); /* Move the RING_HEAD onto the breadcrumb, past the hanging batch */ regs[CTX_RING_BUFFER_START + 1] = i915_ggtt_offset(request->ring->vma); @@ -1989,7 +1992,7 @@ static void execlists_reset_finish(struct intel_engine_cs *engine) static int intel_logical_ring_emit_pdps(struct i915_request *rq) { - struct i915_hw_ppgtt *ppgtt = rq->ctx->ppgtt; + struct i915_hw_ppgtt *ppgtt = rq->gem_context->ppgtt; struct intel_engine_cs *engine = rq->engine; const int num_lri_cmds = GEN8_3LVL_PDPES * 2; u32 *cs; @@ -2028,15 +2031,15 @@ static int gen8_emit_bb_start(struct i915_request *rq, * it is unsafe in case of lite-restore (because the ctx is * not idle). PML4 is allocated during ppgtt init so this is * not needed in 48-bit.*/ - if (rq->ctx->ppgtt && - (intel_engine_flag(rq->engine) & rq->ctx->ppgtt->pd_dirty_rings) && - !i915_vm_is_48bit(&rq->ctx->ppgtt->base) && + if (rq->gem_context->ppgtt && + (intel_engine_flag(rq->engine) & rq->gem_context->ppgtt->pd_dirty_rings) && + !i915_vm_is_48bit(&rq->gem_context->ppgtt->base) && !intel_vgpu_active(rq->i915)) { ret = intel_logical_ring_emit_pdps(rq); if (ret) return ret; - rq->ctx->ppgtt->pd_dirty_rings &= ~intel_engine_flag(rq->engine); + rq->gem_context->ppgtt->pd_dirty_rings &= ~intel_engine_flag(rq->engine); } cs = intel_ring_begin(rq, 6); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 6f200a7471767..53703012ec75e 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -571,8 +571,8 @@ static void reset_ring(struct intel_engine_cs *engine, */ if (request) { struct drm_i915_private *dev_priv = request->i915; - struct intel_context *ce = to_intel_context(request->ctx, - engine); + struct intel_context *ce = + to_intel_context(request->gem_context, engine); struct i915_hw_ppgtt *ppgtt; if (ce->state) { @@ -584,7 +584,7 @@ static void reset_ring(struct intel_engine_cs *engine, CCID_EN); } - ppgtt = request->ctx->ppgtt ?: engine->i915->mm.aliasing_ppgtt; + ppgtt = request->gem_context->ppgtt ?: engine->i915->mm.aliasing_ppgtt; if (ppgtt) { u32 pd_offset = ppgtt->pd.base.ggtt_offset << 10; @@ -1458,7 +1458,7 @@ static inline int mi_set_context(struct i915_request *rq, u32 flags) *cs++ = MI_NOOP; *cs++ = MI_SET_CONTEXT; - *cs++ = i915_ggtt_offset(to_intel_context(rq->ctx, engine)->state) | flags; + *cs++ = i915_ggtt_offset(to_intel_context(rq->gem_context, engine)->state) | flags; /* * w/a: MI_SET_CONTEXT must always be followed by MI_NOOP * WaMiSetContext_Hang:snb,ivb,vlv @@ -1526,7 +1526,7 @@ static int remap_l3(struct i915_request *rq, int slice) static int switch_context(struct i915_request *rq) { struct intel_engine_cs *engine = rq->engine; - struct i915_gem_context *to_ctx = rq->ctx; + struct i915_gem_context *to_ctx = rq->gem_context; struct i915_hw_ppgtt *to_mm = to_ctx->ppgtt ?: rq->i915->mm.aliasing_ppgtt; struct i915_gem_context *from_ctx = engine->legacy_active_context; @@ -1597,7 +1597,7 @@ static int ring_request_alloc(struct i915_request *request) { int ret; - GEM_BUG_ON(!to_intel_context(request->ctx, request->engine)->pin_count); + GEM_BUG_ON(!to_intel_context(request->gem_context, request->engine)->pin_count); /* Flush enough space to reduce the likelihood of waiting after * we start building the request - in which case we will just diff --git a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c index 438e0b045a2c1..2c4e77c050dca 100644 --- a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c +++ b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c @@ -105,7 +105,10 @@ static int emit_recurse_batch(struct hang *h, struct i915_request *rq) { struct drm_i915_private *i915 = h->i915; - struct i915_address_space *vm = rq->ctx->ppgtt ? &rq->ctx->ppgtt->base : &i915->ggtt.base; + struct i915_address_space *vm = + rq->gem_context->ppgtt ? + &rq->gem_context->ppgtt->base : + &i915->ggtt.base; struct i915_vma *hws, *vma; unsigned int flags; u32 *batch; diff --git a/drivers/gpu/drm/i915/selftests/intel_lrc.c b/drivers/gpu/drm/i915/selftests/intel_lrc.c index 1b8a071251509..68cb9126b3e14 100644 --- a/drivers/gpu/drm/i915/selftests/intel_lrc.c +++ b/drivers/gpu/drm/i915/selftests/intel_lrc.c @@ -83,7 +83,7 @@ static int emit_recurse_batch(struct spinner *spin, struct i915_request *rq, u32 arbitration_command) { - struct i915_address_space *vm = &rq->ctx->ppgtt->base; + struct i915_address_space *vm = &rq->gem_context->ppgtt->base; struct i915_vma *hws, *vma; u32 *batch; int err; -- GitLab From 01278cb143955f4b592568d1756f1baf506245c2 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 17 May 2018 22:26:31 +0100 Subject: [PATCH 0032/1506] drm/i915: Move fiddling with engine->last_retired_context Move the knowledge about resetting the current context tracking on the engine from inside i915_gem_context.c into intel_engine_cs.c Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180517212633.24934-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_context.c | 12 ++---------- drivers/gpu/drm/i915/intel_engine_cs.c | 23 +++++++++++++++++++++++ drivers/gpu/drm/i915/intel_ringbuffer.h | 1 + 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 4bf18b5c6f1da..9e70f4dfa7033 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -514,16 +514,8 @@ void i915_gem_contexts_lost(struct drm_i915_private *dev_priv) lockdep_assert_held(&dev_priv->drm.struct_mutex); - for_each_engine(engine, dev_priv, id) { - engine->legacy_active_context = NULL; - engine->legacy_active_ppgtt = NULL; - - if (!engine->last_retired_context) - continue; - - intel_context_unpin(engine->last_retired_context, engine); - engine->last_retired_context = NULL; - } + for_each_engine(engine, dev_priv, id) + intel_engine_lost_context(engine); } void i915_gem_contexts_fini(struct drm_i915_private *i915) diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index 7983b8a1ad446..9e618aab6568d 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -1096,6 +1096,29 @@ void intel_engines_unpark(struct drm_i915_private *i915) } } +/** + * intel_engine_lost_context: called when the GPU is reset into unknown state + * @engine: the engine + * + * We have either reset the GPU or otherwise about to lose state tracking of + * the current GPU logical state (e.g. suspend). On next use, it is therefore + * imperative that we make no presumptions about the current state and load + * from scratch. + */ +void intel_engine_lost_context(struct intel_engine_cs *engine) +{ + struct i915_gem_context *ctx; + + lockdep_assert_held(&engine->i915->drm.struct_mutex); + + engine->legacy_active_context = NULL; + engine->legacy_active_ppgtt = NULL; + + ctx = fetch_and_zero(&engine->last_retired_context); + if (ctx) + intel_context_unpin(ctx, engine); +} + bool intel_engine_can_store_dword(struct intel_engine_cs *engine) { switch (INTEL_GEN(engine->i915)) { diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 61f385a924845..2b16185e36c4c 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -1053,6 +1053,7 @@ bool intel_engine_is_idle(struct intel_engine_cs *engine); bool intel_engines_are_idle(struct drm_i915_private *dev_priv); bool intel_engine_has_kernel_context(const struct intel_engine_cs *engine); +void intel_engine_lost_context(struct intel_engine_cs *engine); void intel_engines_park(struct drm_i915_private *i915); void intel_engines_unpark(struct drm_i915_private *i915); -- GitLab From 1fc44d9b1afb0afe46acd99bdfdf793805a850e1 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 17 May 2018 22:26:32 +0100 Subject: [PATCH 0033/1506] drm/i915: Store a pointer to intel_context in i915_request To ease the frequent and ugly pointer dance of &request->gem_context->engine[request->engine->id] during request submission, store that pointer as request->hw_context. One major advantage that we will exploit later is that this decouples the logical context state from the engine itself. v2: Set mock_context->ops so we don't crash and burn in selftests. Cleanups from Tvrtko. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Acked-by: Zhenyu Wang <zhenyuw@linux.intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180517212633.24934-3-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/gvt/mmio_context.c | 6 +- drivers/gpu/drm/i915/gvt/mmio_context.h | 2 +- drivers/gpu/drm/i915/gvt/scheduler.c | 141 +++++++----------- drivers/gpu/drm/i915/gvt/scheduler.h | 1 - drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_gem.c | 12 +- drivers/gpu/drm/i915/i915_gem_context.c | 17 ++- drivers/gpu/drm/i915/i915_gem_context.h | 21 ++- drivers/gpu/drm/i915/i915_gpu_error.c | 3 +- drivers/gpu/drm/i915/i915_perf.c | 25 ++-- drivers/gpu/drm/i915/i915_request.c | 34 ++--- drivers/gpu/drm/i915/i915_request.h | 1 + drivers/gpu/drm/i915/intel_engine_cs.c | 54 ++++--- drivers/gpu/drm/i915/intel_guc_submission.c | 10 +- drivers/gpu/drm/i915/intel_lrc.c | 125 +++++++++------- drivers/gpu/drm/i915/intel_lrc.h | 7 - drivers/gpu/drm/i915/intel_ringbuffer.c | 100 ++++++++----- drivers/gpu/drm/i915/intel_ringbuffer.h | 9 +- drivers/gpu/drm/i915/selftests/mock_context.c | 7 + drivers/gpu/drm/i915/selftests/mock_engine.c | 41 +++-- 20 files changed, 321 insertions(+), 296 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/mmio_context.c b/drivers/gpu/drm/i915/gvt/mmio_context.c index 0f949554d118c..708170e61625a 100644 --- a/drivers/gpu/drm/i915/gvt/mmio_context.c +++ b/drivers/gpu/drm/i915/gvt/mmio_context.c @@ -446,9 +446,9 @@ static void switch_mocs(struct intel_vgpu *pre, struct intel_vgpu *next, #define CTX_CONTEXT_CONTROL_VAL 0x03 -bool is_inhibit_context(struct i915_gem_context *ctx, int ring_id) +bool is_inhibit_context(struct intel_context *ce) { - u32 *reg_state = ctx->__engine[ring_id].lrc_reg_state; + const u32 *reg_state = ce->lrc_reg_state; u32 inhibit_mask = _MASKED_BIT_ENABLE(CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT); @@ -501,7 +501,7 @@ static void switch_mmio(struct intel_vgpu *pre, * itself. */ if (mmio->in_context && - !is_inhibit_context(s->shadow_ctx, ring_id)) + !is_inhibit_context(&s->shadow_ctx->__engine[ring_id])) continue; if (mmio->mask) diff --git a/drivers/gpu/drm/i915/gvt/mmio_context.h b/drivers/gpu/drm/i915/gvt/mmio_context.h index 0439eb8057a8a..5c3b9ff9f96aa 100644 --- a/drivers/gpu/drm/i915/gvt/mmio_context.h +++ b/drivers/gpu/drm/i915/gvt/mmio_context.h @@ -49,7 +49,7 @@ void intel_gvt_switch_mmio(struct intel_vgpu *pre, void intel_gvt_init_engine_mmio_context(struct intel_gvt *gvt); -bool is_inhibit_context(struct i915_gem_context *ctx, int ring_id); +bool is_inhibit_context(struct intel_context *ce); int intel_vgpu_restore_inhibit_context(struct intel_vgpu *vgpu, struct i915_request *req); diff --git a/drivers/gpu/drm/i915/gvt/scheduler.c b/drivers/gpu/drm/i915/gvt/scheduler.c index 17f9f8d7e148e..e1760030dda1f 100644 --- a/drivers/gpu/drm/i915/gvt/scheduler.c +++ b/drivers/gpu/drm/i915/gvt/scheduler.c @@ -54,11 +54,8 @@ static void set_context_pdp_root_pointer( static void update_shadow_pdps(struct intel_vgpu_workload *workload) { - struct intel_vgpu *vgpu = workload->vgpu; - int ring_id = workload->ring_id; - struct i915_gem_context *shadow_ctx = vgpu->submission.shadow_ctx; struct drm_i915_gem_object *ctx_obj = - shadow_ctx->__engine[ring_id].state->obj; + workload->req->hw_context->state->obj; struct execlist_ring_context *shadow_ring_context; struct page *page; @@ -128,9 +125,8 @@ static int populate_shadow_context(struct intel_vgpu_workload *workload) struct intel_vgpu *vgpu = workload->vgpu; struct intel_gvt *gvt = vgpu->gvt; int ring_id = workload->ring_id; - struct i915_gem_context *shadow_ctx = vgpu->submission.shadow_ctx; struct drm_i915_gem_object *ctx_obj = - shadow_ctx->__engine[ring_id].state->obj; + workload->req->hw_context->state->obj; struct execlist_ring_context *shadow_ring_context; struct page *page; void *dst; @@ -280,10 +276,8 @@ static int shadow_context_status_change(struct notifier_block *nb, return NOTIFY_OK; } -static void shadow_context_descriptor_update(struct i915_gem_context *ctx, - struct intel_engine_cs *engine) +static void shadow_context_descriptor_update(struct intel_context *ce) { - struct intel_context *ce = to_intel_context(ctx, engine); u64 desc = 0; desc = ce->lrc_desc; @@ -292,7 +286,7 @@ static void shadow_context_descriptor_update(struct i915_gem_context *ctx, * like GEN8_CTX_* cached in desc_template */ desc &= U64_MAX << 12; - desc |= ctx->desc_template & ((1ULL << 12) - 1); + desc |= ce->gem_context->desc_template & ((1ULL << 12) - 1); ce->lrc_desc = desc; } @@ -300,12 +294,11 @@ static void shadow_context_descriptor_update(struct i915_gem_context *ctx, static int copy_workload_to_ring_buffer(struct intel_vgpu_workload *workload) { struct intel_vgpu *vgpu = workload->vgpu; + struct i915_request *req = workload->req; void *shadow_ring_buffer_va; u32 *cs; - struct i915_request *req = workload->req; - if (IS_KABYLAKE(req->i915) && - is_inhibit_context(req->gem_context, req->engine->id)) + if (IS_KABYLAKE(req->i915) && is_inhibit_context(req->hw_context)) intel_vgpu_restore_inhibit_context(vgpu, req); /* allocate shadow ring buffer */ @@ -353,60 +346,56 @@ int intel_gvt_scan_and_shadow_workload(struct intel_vgpu_workload *workload) struct intel_vgpu_submission *s = &vgpu->submission; struct i915_gem_context *shadow_ctx = s->shadow_ctx; struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv; - int ring_id = workload->ring_id; - struct intel_engine_cs *engine = dev_priv->engine[ring_id]; - struct intel_ring *ring; + struct intel_engine_cs *engine = dev_priv->engine[workload->ring_id]; + struct intel_context *ce; int ret; lockdep_assert_held(&dev_priv->drm.struct_mutex); - if (workload->shadowed) + if (workload->req) return 0; + /* pin shadow context by gvt even the shadow context will be pinned + * when i915 alloc request. That is because gvt will update the guest + * context from shadow context when workload is completed, and at that + * moment, i915 may already unpined the shadow context to make the + * shadow_ctx pages invalid. So gvt need to pin itself. After update + * the guest context, gvt can unpin the shadow_ctx safely. + */ + ce = intel_context_pin(shadow_ctx, engine); + if (IS_ERR(ce)) { + gvt_vgpu_err("fail to pin shadow context\n"); + return PTR_ERR(ce); + } + shadow_ctx->desc_template &= ~(0x3 << GEN8_CTX_ADDRESSING_MODE_SHIFT); shadow_ctx->desc_template |= workload->ctx_desc.addressing_mode << GEN8_CTX_ADDRESSING_MODE_SHIFT; - if (!test_and_set_bit(ring_id, s->shadow_ctx_desc_updated)) - shadow_context_descriptor_update(shadow_ctx, - dev_priv->engine[ring_id]); + if (!test_and_set_bit(workload->ring_id, s->shadow_ctx_desc_updated)) + shadow_context_descriptor_update(ce); ret = intel_gvt_scan_and_shadow_ringbuffer(workload); if (ret) - goto err_scan; + goto err_unpin; if ((workload->ring_id == RCS) && (workload->wa_ctx.indirect_ctx.size != 0)) { ret = intel_gvt_scan_and_shadow_wa_ctx(&workload->wa_ctx); if (ret) - goto err_scan; - } - - /* pin shadow context by gvt even the shadow context will be pinned - * when i915 alloc request. That is because gvt will update the guest - * context from shadow context when workload is completed, and at that - * moment, i915 may already unpined the shadow context to make the - * shadow_ctx pages invalid. So gvt need to pin itself. After update - * the guest context, gvt can unpin the shadow_ctx safely. - */ - ring = intel_context_pin(shadow_ctx, engine); - if (IS_ERR(ring)) { - ret = PTR_ERR(ring); - gvt_vgpu_err("fail to pin shadow context\n"); - goto err_shadow; + goto err_shadow; } ret = populate_shadow_context(workload); if (ret) - goto err_unpin; - workload->shadowed = true; + goto err_shadow; + return 0; -err_unpin: - intel_context_unpin(shadow_ctx, engine); err_shadow: release_shadow_wa_ctx(&workload->wa_ctx); -err_scan: +err_unpin: + intel_context_unpin(ce); return ret; } @@ -414,7 +403,6 @@ static int intel_gvt_generate_request(struct intel_vgpu_workload *workload) { int ring_id = workload->ring_id; struct drm_i915_private *dev_priv = workload->vgpu->gvt->dev_priv; - struct intel_engine_cs *engine = dev_priv->engine[ring_id]; struct i915_request *rq; struct intel_vgpu *vgpu = workload->vgpu; struct intel_vgpu_submission *s = &vgpu->submission; @@ -437,7 +425,6 @@ static int intel_gvt_generate_request(struct intel_vgpu_workload *workload) return 0; err_unpin: - intel_context_unpin(shadow_ctx, engine); release_shadow_wa_ctx(&workload->wa_ctx); return ret; } @@ -517,21 +504,13 @@ static int prepare_shadow_batch_buffer(struct intel_vgpu_workload *workload) return ret; } -static int update_wa_ctx_2_shadow_ctx(struct intel_shadow_wa_ctx *wa_ctx) +static void update_wa_ctx_2_shadow_ctx(struct intel_shadow_wa_ctx *wa_ctx) { - struct intel_vgpu_workload *workload = container_of(wa_ctx, - struct intel_vgpu_workload, - wa_ctx); - int ring_id = workload->ring_id; - struct intel_vgpu_submission *s = &workload->vgpu->submission; - struct i915_gem_context *shadow_ctx = s->shadow_ctx; - struct drm_i915_gem_object *ctx_obj = - shadow_ctx->__engine[ring_id].state->obj; - struct execlist_ring_context *shadow_ring_context; - struct page *page; - - page = i915_gem_object_get_page(ctx_obj, LRC_STATE_PN); - shadow_ring_context = kmap_atomic(page); + struct intel_vgpu_workload *workload = + container_of(wa_ctx, struct intel_vgpu_workload, wa_ctx); + struct i915_request *rq = workload->req; + struct execlist_ring_context *shadow_ring_context = + (struct execlist_ring_context *)rq->hw_context->lrc_reg_state; shadow_ring_context->bb_per_ctx_ptr.val = (shadow_ring_context->bb_per_ctx_ptr.val & @@ -539,9 +518,6 @@ static int update_wa_ctx_2_shadow_ctx(struct intel_shadow_wa_ctx *wa_ctx) shadow_ring_context->rcs_indirect_ctx.val = (shadow_ring_context->rcs_indirect_ctx.val & (~INDIRECT_CTX_ADDR_MASK)) | wa_ctx->indirect_ctx.shadow_gma; - - kunmap_atomic(shadow_ring_context); - return 0; } static int prepare_shadow_wa_ctx(struct intel_shadow_wa_ctx *wa_ctx) @@ -670,12 +646,9 @@ static int prepare_workload(struct intel_vgpu_workload *workload) static int dispatch_workload(struct intel_vgpu_workload *workload) { struct intel_vgpu *vgpu = workload->vgpu; - struct intel_vgpu_submission *s = &vgpu->submission; - struct i915_gem_context *shadow_ctx = s->shadow_ctx; struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv; int ring_id = workload->ring_id; - struct intel_engine_cs *engine = dev_priv->engine[ring_id]; - int ret = 0; + int ret; gvt_dbg_sched("ring id %d prepare to dispatch workload %p\n", ring_id, workload); @@ -687,10 +660,6 @@ static int dispatch_workload(struct intel_vgpu_workload *workload) goto out; ret = prepare_workload(workload); - if (ret) { - intel_context_unpin(shadow_ctx, engine); - goto out; - } out: if (ret) @@ -765,27 +734,23 @@ static struct intel_vgpu_workload *pick_next_workload( static void update_guest_context(struct intel_vgpu_workload *workload) { + struct i915_request *rq = workload->req; struct intel_vgpu *vgpu = workload->vgpu; struct intel_gvt *gvt = vgpu->gvt; - struct intel_vgpu_submission *s = &vgpu->submission; - struct i915_gem_context *shadow_ctx = s->shadow_ctx; - int ring_id = workload->ring_id; - struct drm_i915_gem_object *ctx_obj = - shadow_ctx->__engine[ring_id].state->obj; + struct drm_i915_gem_object *ctx_obj = rq->hw_context->state->obj; struct execlist_ring_context *shadow_ring_context; struct page *page; void *src; unsigned long context_gpa, context_page_num; int i; - gvt_dbg_sched("ring id %d workload lrca %x\n", ring_id, - workload->ctx_desc.lrca); - - context_page_num = gvt->dev_priv->engine[ring_id]->context_size; + gvt_dbg_sched("ring id %d workload lrca %x\n", rq->engine->id, + workload->ctx_desc.lrca); + context_page_num = rq->engine->context_size; context_page_num = context_page_num >> PAGE_SHIFT; - if (IS_BROADWELL(gvt->dev_priv) && ring_id == RCS) + if (IS_BROADWELL(gvt->dev_priv) && rq->engine->id == RCS) context_page_num = 19; i = 2; @@ -858,6 +823,7 @@ static void complete_current_workload(struct intel_gvt *gvt, int ring_id) scheduler->current_workload[ring_id]; struct intel_vgpu *vgpu = workload->vgpu; struct intel_vgpu_submission *s = &vgpu->submission; + struct i915_request *rq; int event; mutex_lock(&gvt->lock); @@ -866,11 +832,8 @@ static void complete_current_workload(struct intel_gvt *gvt, int ring_id) * switch to make sure request is completed. * For the workload w/o request, directly complete the workload. */ - if (workload->req) { - struct drm_i915_private *dev_priv = - workload->vgpu->gvt->dev_priv; - struct intel_engine_cs *engine = - dev_priv->engine[workload->ring_id]; + rq = fetch_and_zero(&workload->req); + if (rq) { wait_event(workload->shadow_ctx_status_wq, !atomic_read(&workload->shadow_ctx_active)); @@ -886,8 +849,6 @@ static void complete_current_workload(struct intel_gvt *gvt, int ring_id) workload->status = 0; } - i915_request_put(fetch_and_zero(&workload->req)); - if (!workload->status && !(vgpu->resetting_eng & ENGINE_MASK(ring_id))) { update_guest_context(workload); @@ -896,10 +857,13 @@ static void complete_current_workload(struct intel_gvt *gvt, int ring_id) INTEL_GVT_EVENT_MAX) intel_vgpu_trigger_virtual_event(vgpu, event); } - mutex_lock(&dev_priv->drm.struct_mutex); + /* unpin shadow ctx as the shadow_ctx update is done */ - intel_context_unpin(s->shadow_ctx, engine); - mutex_unlock(&dev_priv->drm.struct_mutex); + mutex_lock(&rq->i915->drm.struct_mutex); + intel_context_unpin(rq->hw_context); + mutex_unlock(&rq->i915->drm.struct_mutex); + + i915_request_put(rq); } gvt_dbg_sched("ring id %d complete workload %p status %d\n", @@ -1270,7 +1234,6 @@ alloc_workload(struct intel_vgpu *vgpu) atomic_set(&workload->shadow_ctx_active, 0); workload->status = -EINPROGRESS; - workload->shadowed = false; workload->vgpu = vgpu; return workload; diff --git a/drivers/gpu/drm/i915/gvt/scheduler.h b/drivers/gpu/drm/i915/gvt/scheduler.h index 6c644782193ea..21eddab4a9cd4 100644 --- a/drivers/gpu/drm/i915/gvt/scheduler.h +++ b/drivers/gpu/drm/i915/gvt/scheduler.h @@ -83,7 +83,6 @@ struct intel_vgpu_workload { struct i915_request *req; /* if this workload has been dispatched to i915? */ bool dispatched; - bool shadowed; int status; struct intel_vgpu_mm *shadow_mm; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 34c125e2d90c0..e33c380b43e3d 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1950,6 +1950,7 @@ struct drm_i915_private { */ struct i915_perf_stream *exclusive_stream; + struct intel_context *pinned_ctx; u32 specific_ctx_id; struct hrtimer poll_check_timer; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index a20f8db5729dc..03874b50ada92 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3181,14 +3181,14 @@ void i915_gem_reset(struct drm_i915_private *dev_priv, i915_retire_requests(dev_priv); for_each_engine(engine, dev_priv, id) { - struct i915_gem_context *ctx; + struct intel_context *ce; i915_gem_reset_engine(engine, engine->hangcheck.active_request, stalled_mask & ENGINE_MASK(id)); - ctx = fetch_and_zero(&engine->last_retired_context); - if (ctx) - intel_context_unpin(ctx, engine); + ce = fetch_and_zero(&engine->last_retired_context); + if (ce) + intel_context_unpin(ce); /* * Ostensibily, we always want a context loaded for powersaving, @@ -4897,13 +4897,13 @@ void __i915_gem_object_release_unless_active(struct drm_i915_gem_object *obj) static void assert_kernel_context_is_current(struct drm_i915_private *i915) { - struct i915_gem_context *kernel_context = i915->kernel_context; + struct i915_gem_context *kctx = i915->kernel_context; struct intel_engine_cs *engine; enum intel_engine_id id; for_each_engine(engine, i915, id) { GEM_BUG_ON(__i915_gem_active_peek(&engine->timeline.last_request)); - GEM_BUG_ON(engine->last_retired_context != kernel_context); + GEM_BUG_ON(engine->last_retired_context->gem_context != kctx); } } diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 9e70f4dfa7033..b69b18ef81203 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -127,14 +127,8 @@ static void i915_gem_context_free(struct i915_gem_context *ctx) for (n = 0; n < ARRAY_SIZE(ctx->__engine); n++) { struct intel_context *ce = &ctx->__engine[n]; - if (!ce->state) - continue; - - WARN_ON(ce->pin_count); - if (ce->ring) - intel_ring_free(ce->ring); - - __i915_gem_object_release_unless_active(ce->state->obj); + if (ce->ops) + ce->ops->destroy(ce); } kfree(ctx->name); @@ -266,6 +260,7 @@ __create_hw_context(struct drm_i915_private *dev_priv, struct drm_i915_file_private *file_priv) { struct i915_gem_context *ctx; + unsigned int n; int ret; ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); @@ -283,6 +278,12 @@ __create_hw_context(struct drm_i915_private *dev_priv, ctx->i915 = dev_priv; ctx->sched.priority = I915_PRIORITY_NORMAL; + for (n = 0; n < ARRAY_SIZE(ctx->__engine); n++) { + struct intel_context *ce = &ctx->__engine[n]; + + ce->gem_context = ctx; + } + INIT_RADIX_TREE(&ctx->handles_vma, GFP_KERNEL); INIT_LIST_HEAD(&ctx->handles_list); diff --git a/drivers/gpu/drm/i915/i915_gem_context.h b/drivers/gpu/drm/i915/i915_gem_context.h index ace3b129c1896..749a4ff566f5b 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.h +++ b/drivers/gpu/drm/i915/i915_gem_context.h @@ -45,6 +45,11 @@ struct intel_ring; #define DEFAULT_CONTEXT_HANDLE 0 +struct intel_context_ops { + void (*unpin)(struct intel_context *ce); + void (*destroy)(struct intel_context *ce); +}; + /** * struct i915_gem_context - client state * @@ -144,11 +149,14 @@ struct i915_gem_context { /** engine: per-engine logical HW state */ struct intel_context { + struct i915_gem_context *gem_context; struct i915_vma *state; struct intel_ring *ring; u32 *lrc_reg_state; u64 lrc_desc; int pin_count; + + const struct intel_context_ops *ops; } __engine[I915_NUM_ENGINES]; /** ring_size: size for allocating the per-engine ring buffer */ @@ -263,25 +271,22 @@ to_intel_context(struct i915_gem_context *ctx, return &ctx->__engine[engine->id]; } -static inline struct intel_ring * +static inline struct intel_context * intel_context_pin(struct i915_gem_context *ctx, struct intel_engine_cs *engine) { return engine->context_pin(engine, ctx); } -static inline void __intel_context_pin(struct i915_gem_context *ctx, - const struct intel_engine_cs *engine) +static inline void __intel_context_pin(struct intel_context *ce) { - struct intel_context *ce = to_intel_context(ctx, engine); - GEM_BUG_ON(!ce->pin_count); ce->pin_count++; } -static inline void intel_context_unpin(struct i915_gem_context *ctx, - struct intel_engine_cs *engine) +static inline void intel_context_unpin(struct intel_context *ce) { - engine->context_unpin(engine, ctx); + GEM_BUG_ON(!ce->ops); + ce->ops->unpin(ce); } /* i915_gem_context.c */ diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 37c9a42654ba7..47721437a4c58 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -1485,8 +1485,7 @@ static void gem_record_rings(struct i915_gpu_state *error) ee->ctx = i915_error_object_create(i915, - to_intel_context(ctx, - engine)->state); + request->hw_context->state); error->simulated |= i915_gem_context_no_error_capture(ctx); diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index 019bd2d073ad4..4f0eb84b3c00d 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -1221,7 +1221,7 @@ static int oa_get_render_ctx_id(struct i915_perf_stream *stream) dev_priv->perf.oa.specific_ctx_id = stream->ctx->hw_id; } else { struct intel_engine_cs *engine = dev_priv->engine[RCS]; - struct intel_ring *ring; + struct intel_context *ce; int ret; ret = i915_mutex_lock_interruptible(&dev_priv->drm); @@ -1234,19 +1234,19 @@ static int oa_get_render_ctx_id(struct i915_perf_stream *stream) * * NB: implied RCS engine... */ - ring = intel_context_pin(stream->ctx, engine); + ce = intel_context_pin(stream->ctx, engine); mutex_unlock(&dev_priv->drm.struct_mutex); - if (IS_ERR(ring)) - return PTR_ERR(ring); + if (IS_ERR(ce)) + return PTR_ERR(ce); + dev_priv->perf.oa.pinned_ctx = ce; /* * Explicitly track the ID (instead of calling * i915_ggtt_offset() on the fly) considering the difference * with gen8+ and execlists */ - dev_priv->perf.oa.specific_ctx_id = - i915_ggtt_offset(to_intel_context(stream->ctx, engine)->state); + dev_priv->perf.oa.specific_ctx_id = i915_ggtt_offset(ce->state); } return 0; @@ -1262,17 +1262,14 @@ static int oa_get_render_ctx_id(struct i915_perf_stream *stream) static void oa_put_render_ctx_id(struct i915_perf_stream *stream) { struct drm_i915_private *dev_priv = stream->dev_priv; + struct intel_context *ce; - if (HAS_LOGICAL_RING_CONTEXTS(dev_priv)) { - dev_priv->perf.oa.specific_ctx_id = INVALID_CTX_ID; - } else { - struct intel_engine_cs *engine = dev_priv->engine[RCS]; + dev_priv->perf.oa.specific_ctx_id = INVALID_CTX_ID; + ce = fetch_and_zero(&dev_priv->perf.oa.pinned_ctx); + if (ce) { mutex_lock(&dev_priv->drm.struct_mutex); - - dev_priv->perf.oa.specific_ctx_id = INVALID_CTX_ID; - intel_context_unpin(stream->ctx, engine); - + intel_context_unpin(ce); mutex_unlock(&dev_priv->drm.struct_mutex); } } diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index fe8810a6a339d..fc499bcbd105f 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -383,8 +383,8 @@ static void __retire_engine_request(struct intel_engine_cs *engine, * the subsequent request. */ if (engine->last_retired_context) - intel_context_unpin(engine->last_retired_context, engine); - engine->last_retired_context = rq->gem_context; + intel_context_unpin(engine->last_retired_context); + engine->last_retired_context = rq->hw_context; } static void __retire_engine_upto(struct intel_engine_cs *engine, @@ -456,7 +456,7 @@ static void i915_request_retire(struct i915_request *request) /* Retirement decays the ban score as it is a sign of ctx progress */ atomic_dec_if_positive(&request->gem_context->ban_score); - intel_context_unpin(request->gem_context, request->engine); + intel_context_unpin(request->hw_context); __retire_engine_upto(request->engine, request); @@ -657,7 +657,7 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx) { struct drm_i915_private *i915 = engine->i915; struct i915_request *rq; - struct intel_ring *ring; + struct intel_context *ce; int ret; lockdep_assert_held(&i915->drm.struct_mutex); @@ -681,22 +681,21 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx) * GGTT space, so do this first before we reserve a seqno for * ourselves. */ - ring = intel_context_pin(ctx, engine); - if (IS_ERR(ring)) - return ERR_CAST(ring); - GEM_BUG_ON(!ring); + ce = intel_context_pin(ctx, engine); + if (IS_ERR(ce)) + return ERR_CAST(ce); ret = reserve_gt(i915); if (ret) goto err_unpin; - ret = intel_ring_wait_for_space(ring, MIN_SPACE_FOR_ADD_REQUEST); + ret = intel_ring_wait_for_space(ce->ring, MIN_SPACE_FOR_ADD_REQUEST); if (ret) goto err_unreserve; /* Move our oldest request to the slab-cache (if not in use!) */ - rq = list_first_entry(&ring->request_list, typeof(*rq), ring_link); - if (!list_is_last(&rq->ring_link, &ring->request_list) && + rq = list_first_entry(&ce->ring->request_list, typeof(*rq), ring_link); + if (!list_is_last(&rq->ring_link, &ce->ring->request_list) && i915_request_completed(rq)) i915_request_retire(rq); @@ -761,8 +760,9 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx) rq->i915 = i915; rq->engine = engine; rq->gem_context = ctx; - rq->ring = ring; - rq->timeline = ring->timeline; + rq->hw_context = ce; + rq->ring = ce->ring; + rq->timeline = ce->ring->timeline; GEM_BUG_ON(rq->timeline == &engine->timeline); spin_lock_init(&rq->lock); @@ -814,14 +814,14 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx) goto err_unwind; /* Keep a second pin for the dual retirement along engine and ring */ - __intel_context_pin(rq->gem_context, engine); + __intel_context_pin(ce); /* Check that we didn't interrupt ourselves with a new request */ GEM_BUG_ON(rq->timeline->seqno != rq->fence.seqno); return rq; err_unwind: - rq->ring->emit = rq->head; + ce->ring->emit = rq->head; /* Make sure we didn't add ourselves to external state before freeing */ GEM_BUG_ON(!list_empty(&rq->active_list)); @@ -832,7 +832,7 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx) err_unreserve: unreserve_gt(i915); err_unpin: - intel_context_unpin(ctx, engine); + intel_context_unpin(ce); return ERR_PTR(ret); } @@ -1018,8 +1018,8 @@ i915_request_await_object(struct i915_request *to, void __i915_request_add(struct i915_request *request, bool flush_caches) { struct intel_engine_cs *engine = request->engine; - struct intel_ring *ring = request->ring; struct i915_timeline *timeline = request->timeline; + struct intel_ring *ring = request->ring; struct i915_request *prev; u32 *cs; int err; diff --git a/drivers/gpu/drm/i915/i915_request.h b/drivers/gpu/drm/i915/i915_request.h index dddecd9ffd0c0..1bbbb7a9fa037 100644 --- a/drivers/gpu/drm/i915/i915_request.h +++ b/drivers/gpu/drm/i915/i915_request.h @@ -95,6 +95,7 @@ struct i915_request { */ struct i915_gem_context *gem_context; struct intel_engine_cs *engine; + struct intel_context *hw_context; struct intel_ring *ring; struct i915_timeline *timeline; struct intel_signal_node signaling; diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index 9e618aab6568d..26f9f8aab9493 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -645,6 +645,12 @@ static int init_phys_status_page(struct intel_engine_cs *engine) return 0; } +static void __intel_context_unpin(struct i915_gem_context *ctx, + struct intel_engine_cs *engine) +{ + intel_context_unpin(to_intel_context(ctx, engine)); +} + /** * intel_engines_init_common - initialize cengine state which might require hw access * @engine: Engine to initialize. @@ -658,7 +664,8 @@ static int init_phys_status_page(struct intel_engine_cs *engine) */ int intel_engine_init_common(struct intel_engine_cs *engine) { - struct intel_ring *ring; + struct drm_i915_private *i915 = engine->i915; + struct intel_context *ce; int ret; engine->set_default_submission(engine); @@ -670,18 +677,18 @@ int intel_engine_init_common(struct intel_engine_cs *engine) * be available. To avoid this we always pin the default * context. */ - ring = intel_context_pin(engine->i915->kernel_context, engine); - if (IS_ERR(ring)) - return PTR_ERR(ring); + ce = intel_context_pin(i915->kernel_context, engine); + if (IS_ERR(ce)) + return PTR_ERR(ce); /* * Similarly the preempt context must always be available so that * we can interrupt the engine at any time. */ - if (engine->i915->preempt_context) { - ring = intel_context_pin(engine->i915->preempt_context, engine); - if (IS_ERR(ring)) { - ret = PTR_ERR(ring); + if (i915->preempt_context) { + ce = intel_context_pin(i915->preempt_context, engine); + if (IS_ERR(ce)) { + ret = PTR_ERR(ce); goto err_unpin_kernel; } } @@ -690,7 +697,7 @@ int intel_engine_init_common(struct intel_engine_cs *engine) if (ret) goto err_unpin_preempt; - if (HWS_NEEDS_PHYSICAL(engine->i915)) + if (HWS_NEEDS_PHYSICAL(i915)) ret = init_phys_status_page(engine); else ret = init_status_page(engine); @@ -702,10 +709,11 @@ int intel_engine_init_common(struct intel_engine_cs *engine) err_breadcrumbs: intel_engine_fini_breadcrumbs(engine); err_unpin_preempt: - if (engine->i915->preempt_context) - intel_context_unpin(engine->i915->preempt_context, engine); + if (i915->preempt_context) + __intel_context_unpin(i915->preempt_context, engine); + err_unpin_kernel: - intel_context_unpin(engine->i915->kernel_context, engine); + __intel_context_unpin(i915->kernel_context, engine); return ret; } @@ -718,6 +726,8 @@ int intel_engine_init_common(struct intel_engine_cs *engine) */ void intel_engine_cleanup_common(struct intel_engine_cs *engine) { + struct drm_i915_private *i915 = engine->i915; + intel_engine_cleanup_scratch(engine); if (HWS_NEEDS_PHYSICAL(engine->i915)) @@ -732,9 +742,9 @@ void intel_engine_cleanup_common(struct intel_engine_cs *engine) if (engine->default_state) i915_gem_object_put(engine->default_state); - if (engine->i915->preempt_context) - intel_context_unpin(engine->i915->preempt_context, engine); - intel_context_unpin(engine->i915->kernel_context, engine); + if (i915->preempt_context) + __intel_context_unpin(i915->preempt_context, engine); + __intel_context_unpin(i915->kernel_context, engine); i915_timeline_fini(&engine->timeline); } @@ -1007,8 +1017,8 @@ bool intel_engines_are_idle(struct drm_i915_private *dev_priv) */ bool intel_engine_has_kernel_context(const struct intel_engine_cs *engine) { - const struct i915_gem_context * const kernel_context = - engine->i915->kernel_context; + const struct intel_context *kernel_context = + to_intel_context(engine->i915->kernel_context, engine); struct i915_request *rq; lockdep_assert_held(&engine->i915->drm.struct_mutex); @@ -1020,7 +1030,7 @@ bool intel_engine_has_kernel_context(const struct intel_engine_cs *engine) */ rq = __i915_gem_active_peek(&engine->timeline.last_request); if (rq) - return rq->gem_context == kernel_context; + return rq->hw_context == kernel_context; else return engine->last_retired_context == kernel_context; } @@ -1107,16 +1117,16 @@ void intel_engines_unpark(struct drm_i915_private *i915) */ void intel_engine_lost_context(struct intel_engine_cs *engine) { - struct i915_gem_context *ctx; + struct intel_context *ce; lockdep_assert_held(&engine->i915->drm.struct_mutex); engine->legacy_active_context = NULL; engine->legacy_active_ppgtt = NULL; - ctx = fetch_and_zero(&engine->last_retired_context); - if (ctx) - intel_context_unpin(ctx, engine); + ce = fetch_and_zero(&engine->last_retired_context); + if (ce) + intel_context_unpin(ce); } bool intel_engine_can_store_dword(struct intel_engine_cs *engine) diff --git a/drivers/gpu/drm/i915/intel_guc_submission.c b/drivers/gpu/drm/i915/intel_guc_submission.c index a432a193f3c40..133367a178633 100644 --- a/drivers/gpu/drm/i915/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/intel_guc_submission.c @@ -513,9 +513,7 @@ static void guc_add_request(struct intel_guc *guc, struct i915_request *rq) { struct intel_guc_client *client = guc->execbuf_client; struct intel_engine_cs *engine = rq->engine; - u32 ctx_desc = - lower_32_bits(intel_lr_context_descriptor(rq->gem_context, - engine)); + u32 ctx_desc = lower_32_bits(rq->hw_context->lrc_desc); u32 ring_tail = intel_ring_set_tail(rq->ring, rq->tail) / sizeof(u64); spin_lock(&client->wq_lock); @@ -553,8 +551,8 @@ static void inject_preempt_context(struct work_struct *work) preempt_work[engine->id]); struct intel_guc_client *client = guc->preempt_client; struct guc_stage_desc *stage_desc = __get_stage_desc(client); - u32 ctx_desc = lower_32_bits(intel_lr_context_descriptor(client->owner, - engine)); + u32 ctx_desc = lower_32_bits(to_intel_context(client->owner, + engine)->lrc_desc); u32 data[7]; /* @@ -726,7 +724,7 @@ static bool __guc_dequeue(struct intel_engine_cs *engine) struct i915_request *rq, *rn; list_for_each_entry_safe(rq, rn, &p->requests, sched.link) { - if (last && rq->gem_context != last->gem_context) { + if (last && rq->hw_context != last->hw_context) { if (port == last_port) { __list_del_many(&p->requests, &rq->sched.link); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 1e9cc55d785c0..b97c5d4c7877c 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -164,7 +164,8 @@ #define WA_TAIL_BYTES (sizeof(u32) * WA_TAIL_DWORDS) static int execlists_context_deferred_alloc(struct i915_gem_context *ctx, - struct intel_engine_cs *engine); + struct intel_engine_cs *engine, + struct intel_context *ce); static void execlists_init_reg_state(u32 *reg_state, struct i915_gem_context *ctx, struct intel_engine_cs *engine, @@ -189,12 +190,7 @@ static inline bool need_preempt(const struct intel_engine_cs *engine, !i915_request_completed(last)); } -/** - * intel_lr_context_descriptor_update() - calculate & cache the descriptor - * descriptor for a pinned context - * @ctx: Context to work on - * @engine: Engine the descriptor will be used with - * +/* * The context descriptor encodes various attributes of a context, * including its GTT address and some flags. Because it's fairly * expensive to calculate, we'll just do it once and cache the result, @@ -222,9 +218,9 @@ static inline bool need_preempt(const struct intel_engine_cs *engine, */ static void intel_lr_context_descriptor_update(struct i915_gem_context *ctx, - struct intel_engine_cs *engine) + struct intel_engine_cs *engine, + struct intel_context *ce) { - struct intel_context *ce = to_intel_context(ctx, engine); u64 desc; BUILD_BUG_ON(MAX_CONTEXT_HW_ID > (BIT(GEN8_CTX_ID_WIDTH))); @@ -418,8 +414,7 @@ execlists_update_context_pdps(struct i915_hw_ppgtt *ppgtt, u32 *reg_state) static u64 execlists_update_context(struct i915_request *rq) { - struct intel_context *ce = - to_intel_context(rq->gem_context, rq->engine); + struct intel_context *ce = rq->hw_context; struct i915_hw_ppgtt *ppgtt = rq->gem_context->ppgtt ?: rq->i915->mm.aliasing_ppgtt; u32 *reg_state = ce->lrc_reg_state; @@ -496,14 +491,14 @@ static void execlists_submit_ports(struct intel_engine_cs *engine) execlists_clear_active(execlists, EXECLISTS_ACTIVE_HWACK); } -static bool ctx_single_port_submission(const struct i915_gem_context *ctx) +static bool ctx_single_port_submission(const struct intel_context *ce) { return (IS_ENABLED(CONFIG_DRM_I915_GVT) && - i915_gem_context_force_single_submission(ctx)); + i915_gem_context_force_single_submission(ce->gem_context)); } -static bool can_merge_ctx(const struct i915_gem_context *prev, - const struct i915_gem_context *next) +static bool can_merge_ctx(const struct intel_context *prev, + const struct intel_context *next) { if (prev != next) return false; @@ -680,8 +675,8 @@ static bool __execlists_dequeue(struct intel_engine_cs *engine) * second request, and so we never need to tell the * hardware about the first. */ - if (last && !can_merge_ctx(rq->gem_context, - last->gem_context)) { + if (last && + !can_merge_ctx(rq->hw_context, last->hw_context)) { /* * If we are on the second port and cannot * combine this request with the last, then we @@ -700,14 +695,14 @@ static bool __execlists_dequeue(struct intel_engine_cs *engine) * the same context (even though a different * request) to the second port. */ - if (ctx_single_port_submission(last->gem_context) || - ctx_single_port_submission(rq->gem_context)) { + if (ctx_single_port_submission(last->hw_context) || + ctx_single_port_submission(rq->hw_context)) { __list_del_many(&p->requests, &rq->sched.link); goto done; } - GEM_BUG_ON(last->gem_context == rq->gem_context); + GEM_BUG_ON(last->hw_context == rq->hw_context); if (submit) port_assign(port, last); @@ -1339,6 +1334,37 @@ static void execlists_schedule(struct i915_request *request, spin_unlock_irq(&engine->timeline.lock); } +static void execlists_context_destroy(struct intel_context *ce) +{ + GEM_BUG_ON(!ce->state); + GEM_BUG_ON(ce->pin_count); + + intel_ring_free(ce->ring); + __i915_gem_object_release_unless_active(ce->state->obj); +} + +static void __execlists_context_unpin(struct intel_context *ce) +{ + intel_ring_unpin(ce->ring); + + ce->state->obj->pin_global--; + i915_gem_object_unpin_map(ce->state->obj); + i915_vma_unpin(ce->state); + + i915_gem_context_put(ce->gem_context); +} + +static void execlists_context_unpin(struct intel_context *ce) +{ + lockdep_assert_held(&ce->gem_context->i915->drm.struct_mutex); + GEM_BUG_ON(ce->pin_count == 0); + + if (--ce->pin_count) + return; + + __execlists_context_unpin(ce); +} + static int __context_pin(struct i915_gem_context *ctx, struct i915_vma *vma) { unsigned int flags; @@ -1362,21 +1388,15 @@ static int __context_pin(struct i915_gem_context *ctx, struct i915_vma *vma) return i915_vma_pin(vma, 0, GEN8_LR_CONTEXT_ALIGN, flags); } -static struct intel_ring * -execlists_context_pin(struct intel_engine_cs *engine, - struct i915_gem_context *ctx) +static struct intel_context * +__execlists_context_pin(struct intel_engine_cs *engine, + struct i915_gem_context *ctx, + struct intel_context *ce) { - struct intel_context *ce = to_intel_context(ctx, engine); void *vaddr; int ret; - lockdep_assert_held(&ctx->i915->drm.struct_mutex); - - if (likely(ce->pin_count++)) - goto out; - GEM_BUG_ON(!ce->pin_count); /* no overflow please! */ - - ret = execlists_context_deferred_alloc(ctx, engine); + ret = execlists_context_deferred_alloc(ctx, engine, ce); if (ret) goto err; GEM_BUG_ON(!ce->state); @@ -1395,7 +1415,7 @@ execlists_context_pin(struct intel_engine_cs *engine, if (ret) goto unpin_map; - intel_lr_context_descriptor_update(ctx, engine); + intel_lr_context_descriptor_update(ctx, engine, ce); ce->lrc_reg_state = vaddr + LRC_STATE_PN * PAGE_SIZE; ce->lrc_reg_state[CTX_RING_BUFFER_START+1] = @@ -1404,8 +1424,7 @@ execlists_context_pin(struct intel_engine_cs *engine, ce->state->obj->pin_global++; i915_gem_context_get(ctx); -out: - return ce->ring; + return ce; unpin_map: i915_gem_object_unpin_map(ce->state->obj); @@ -1416,33 +1435,33 @@ execlists_context_pin(struct intel_engine_cs *engine, return ERR_PTR(ret); } -static void execlists_context_unpin(struct intel_engine_cs *engine, - struct i915_gem_context *ctx) +static const struct intel_context_ops execlists_context_ops = { + .unpin = execlists_context_unpin, + .destroy = execlists_context_destroy, +}; + +static struct intel_context * +execlists_context_pin(struct intel_engine_cs *engine, + struct i915_gem_context *ctx) { struct intel_context *ce = to_intel_context(ctx, engine); lockdep_assert_held(&ctx->i915->drm.struct_mutex); - GEM_BUG_ON(ce->pin_count == 0); - if (--ce->pin_count) - return; - - intel_ring_unpin(ce->ring); + if (likely(ce->pin_count++)) + return ce; + GEM_BUG_ON(!ce->pin_count); /* no overflow please! */ - ce->state->obj->pin_global--; - i915_gem_object_unpin_map(ce->state->obj); - i915_vma_unpin(ce->state); + ce->ops = &execlists_context_ops; - i915_gem_context_put(ctx); + return __execlists_context_pin(engine, ctx, ce); } static int execlists_request_alloc(struct i915_request *request) { - struct intel_context *ce = - to_intel_context(request->gem_context, request->engine); int ret; - GEM_BUG_ON(!ce->pin_count); + GEM_BUG_ON(!request->hw_context->pin_count); /* Flush enough space to reduce the likelihood of waiting after * we start building the request - in which case we will just @@ -1956,7 +1975,7 @@ static void execlists_reset(struct intel_engine_cs *engine, * future request will be after userspace has had the opportunity * to recreate its own state. */ - regs = to_intel_context(request->gem_context, engine)->lrc_reg_state; + regs = request->hw_context->lrc_reg_state; if (engine->default_state) { void *defaults; @@ -2327,8 +2346,6 @@ logical_ring_default_vfuncs(struct intel_engine_cs *engine) engine->reset.finish = execlists_reset_finish; engine->context_pin = execlists_context_pin; - engine->context_unpin = execlists_context_unpin; - engine->request_alloc = execlists_request_alloc; engine->emit_flush = gen8_emit_flush; @@ -2563,7 +2580,7 @@ static void execlists_init_reg_state(u32 *regs, struct drm_i915_private *dev_priv = engine->i915; struct i915_hw_ppgtt *ppgtt = ctx->ppgtt ?: dev_priv->mm.aliasing_ppgtt; u32 base = engine->mmio_base; - bool rcs = engine->id == RCS; + bool rcs = engine->class == RENDER_CLASS; /* A context is actually a big batch buffer with several * MI_LOAD_REGISTER_IMM commands followed by (reg, value) pairs. The @@ -2710,10 +2727,10 @@ populate_lr_context(struct i915_gem_context *ctx, } static int execlists_context_deferred_alloc(struct i915_gem_context *ctx, - struct intel_engine_cs *engine) + struct intel_engine_cs *engine, + struct intel_context *ce) { struct drm_i915_gem_object *ctx_obj; - struct intel_context *ce = to_intel_context(ctx, engine); struct i915_vma *vma; uint32_t context_size; struct intel_ring *ring; diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h index 4ec7d8dd13c80..1593194e930c0 100644 --- a/drivers/gpu/drm/i915/intel_lrc.h +++ b/drivers/gpu/drm/i915/intel_lrc.h @@ -104,11 +104,4 @@ struct i915_gem_context; void intel_lr_context_resume(struct drm_i915_private *dev_priv); -static inline uint64_t -intel_lr_context_descriptor(struct i915_gem_context *ctx, - struct intel_engine_cs *engine) -{ - return to_intel_context(ctx, engine)->lrc_desc; -} - #endif /* _INTEL_LRC_H_ */ diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 53703012ec75e..0c0c9f531e4ec 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -571,8 +571,7 @@ static void reset_ring(struct intel_engine_cs *engine, */ if (request) { struct drm_i915_private *dev_priv = request->i915; - struct intel_context *ce = - to_intel_context(request->gem_context, engine); + struct intel_context *ce = request->hw_context; struct i915_hw_ppgtt *ppgtt; if (ce->state) { @@ -1186,7 +1185,31 @@ intel_ring_free(struct intel_ring *ring) kfree(ring); } -static int context_pin(struct intel_context *ce) +static void intel_ring_context_destroy(struct intel_context *ce) +{ + GEM_BUG_ON(ce->pin_count); + + if (ce->state) + __i915_gem_object_release_unless_active(ce->state->obj); +} + +static void intel_ring_context_unpin(struct intel_context *ce) +{ + lockdep_assert_held(&ce->gem_context->i915->drm.struct_mutex); + GEM_BUG_ON(ce->pin_count == 0); + + if (--ce->pin_count) + return; + + if (ce->state) { + ce->state->obj->pin_global--; + i915_vma_unpin(ce->state); + } + + i915_gem_context_put(ce->gem_context); +} + +static int __context_pin(struct intel_context *ce) { struct i915_vma *vma = ce->state; int ret; @@ -1275,25 +1298,19 @@ alloc_context_vma(struct intel_engine_cs *engine) return ERR_PTR(err); } -static struct intel_ring * -intel_ring_context_pin(struct intel_engine_cs *engine, - struct i915_gem_context *ctx) +static struct intel_context * +__ring_context_pin(struct intel_engine_cs *engine, + struct i915_gem_context *ctx, + struct intel_context *ce) { - struct intel_context *ce = to_intel_context(ctx, engine); - int ret; - - lockdep_assert_held(&ctx->i915->drm.struct_mutex); - - if (likely(ce->pin_count++)) - goto out; - GEM_BUG_ON(!ce->pin_count); /* no overflow please! */ + int err; if (!ce->state && engine->context_size) { struct i915_vma *vma; vma = alloc_context_vma(engine); if (IS_ERR(vma)) { - ret = PTR_ERR(vma); + err = PTR_ERR(vma); goto err; } @@ -1301,8 +1318,8 @@ intel_ring_context_pin(struct intel_engine_cs *engine, } if (ce->state) { - ret = context_pin(ce); - if (ret) + err = __context_pin(ce); + if (err) goto err; ce->state->obj->pin_global++; @@ -1310,32 +1327,37 @@ intel_ring_context_pin(struct intel_engine_cs *engine, i915_gem_context_get(ctx); -out: /* One ringbuffer to rule them all */ - return engine->buffer; + GEM_BUG_ON(!engine->buffer); + ce->ring = engine->buffer; + + return ce; err: ce->pin_count = 0; - return ERR_PTR(ret); + return ERR_PTR(err); } -static void intel_ring_context_unpin(struct intel_engine_cs *engine, - struct i915_gem_context *ctx) +static const struct intel_context_ops ring_context_ops = { + .unpin = intel_ring_context_unpin, + .destroy = intel_ring_context_destroy, +}; + +static struct intel_context * +intel_ring_context_pin(struct intel_engine_cs *engine, + struct i915_gem_context *ctx) { struct intel_context *ce = to_intel_context(ctx, engine); lockdep_assert_held(&ctx->i915->drm.struct_mutex); - GEM_BUG_ON(ce->pin_count == 0); - if (--ce->pin_count) - return; + if (likely(ce->pin_count++)) + return ce; + GEM_BUG_ON(!ce->pin_count); /* no overflow please! */ - if (ce->state) { - ce->state->obj->pin_global--; - i915_vma_unpin(ce->state); - } + ce->ops = &ring_context_ops; - i915_gem_context_put(ctx); + return __ring_context_pin(engine, ctx, ce); } static int intel_init_ring_buffer(struct intel_engine_cs *engine) @@ -1346,10 +1368,6 @@ static int intel_init_ring_buffer(struct intel_engine_cs *engine) intel_engine_setup_common(engine); - err = intel_engine_init_common(engine); - if (err) - goto err; - timeline = i915_timeline_create(engine->i915, engine->name); if (IS_ERR(timeline)) { err = PTR_ERR(timeline); @@ -1371,8 +1389,14 @@ static int intel_init_ring_buffer(struct intel_engine_cs *engine) GEM_BUG_ON(engine->buffer); engine->buffer = ring; + err = intel_engine_init_common(engine); + if (err) + goto err_unpin; + return 0; +err_unpin: + intel_ring_unpin(ring); err_ring: intel_ring_free(ring); err: @@ -1458,7 +1482,7 @@ static inline int mi_set_context(struct i915_request *rq, u32 flags) *cs++ = MI_NOOP; *cs++ = MI_SET_CONTEXT; - *cs++ = i915_ggtt_offset(to_intel_context(rq->gem_context, engine)->state) | flags; + *cs++ = i915_ggtt_offset(rq->hw_context->state) | flags; /* * w/a: MI_SET_CONTEXT must always be followed by MI_NOOP * WaMiSetContext_Hang:snb,ivb,vlv @@ -1549,7 +1573,7 @@ static int switch_context(struct i915_request *rq) hw_flags = MI_FORCE_RESTORE; } - if (to_intel_context(to_ctx, engine)->state && + if (rq->hw_context->state && (to_ctx != from_ctx || hw_flags & MI_FORCE_RESTORE)) { GEM_BUG_ON(engine->id != RCS); @@ -1597,7 +1621,7 @@ static int ring_request_alloc(struct i915_request *request) { int ret; - GEM_BUG_ON(!to_intel_context(request->gem_context, request->engine)->pin_count); + GEM_BUG_ON(!request->hw_context->pin_count); /* Flush enough space to reduce the likelihood of waiting after * we start building the request - in which case we will just @@ -2028,8 +2052,6 @@ static void intel_ring_default_vfuncs(struct drm_i915_private *dev_priv, engine->reset.finish = reset_finish; engine->context_pin = intel_ring_context_pin; - engine->context_unpin = intel_ring_context_unpin; - engine->request_alloc = ring_request_alloc; engine->emit_breadcrumb = i9xx_emit_breadcrumb; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 2b16185e36c4c..20c4e13efc0de 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -436,10 +436,9 @@ struct intel_engine_cs { void (*set_default_submission)(struct intel_engine_cs *engine); - struct intel_ring *(*context_pin)(struct intel_engine_cs *engine, - struct i915_gem_context *ctx); - void (*context_unpin)(struct intel_engine_cs *engine, - struct i915_gem_context *ctx); + struct intel_context *(*context_pin)(struct intel_engine_cs *engine, + struct i915_gem_context *ctx); + int (*request_alloc)(struct i915_request *rq); int (*init_context)(struct i915_request *rq); @@ -555,7 +554,7 @@ struct intel_engine_cs { * to the kernel context and trash it as the save may not happen * before the hardware is powered down. */ - struct i915_gem_context *last_retired_context; + struct intel_context *last_retired_context; /* We track the current MI_SET_CONTEXT in order to eliminate * redudant context switches. This presumes that requests are not diff --git a/drivers/gpu/drm/i915/selftests/mock_context.c b/drivers/gpu/drm/i915/selftests/mock_context.c index 501becc47c0cd..8904f1ce64e3d 100644 --- a/drivers/gpu/drm/i915/selftests/mock_context.c +++ b/drivers/gpu/drm/i915/selftests/mock_context.c @@ -30,6 +30,7 @@ mock_context(struct drm_i915_private *i915, const char *name) { struct i915_gem_context *ctx; + unsigned int n; int ret; ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); @@ -43,6 +44,12 @@ mock_context(struct drm_i915_private *i915, INIT_RADIX_TREE(&ctx->handles_vma, GFP_KERNEL); INIT_LIST_HEAD(&ctx->handles_list); + for (n = 0; n < ARRAY_SIZE(ctx->__engine); n++) { + struct intel_context *ce = &ctx->__engine[n]; + + ce->gem_context = ctx; + } + ret = ida_simple_get(&i915->contexts.hw_ida, 0, MAX_CONTEXT_HW_ID, GFP_KERNEL); if (ret < 0) diff --git a/drivers/gpu/drm/i915/selftests/mock_engine.c b/drivers/gpu/drm/i915/selftests/mock_engine.c index 26bf29d970078..33eddfc1f8cec 100644 --- a/drivers/gpu/drm/i915/selftests/mock_engine.c +++ b/drivers/gpu/drm/i915/selftests/mock_engine.c @@ -72,25 +72,37 @@ static void hw_delay_complete(struct timer_list *t) spin_unlock(&engine->hw_lock); } -static struct intel_ring * -mock_context_pin(struct intel_engine_cs *engine, - struct i915_gem_context *ctx) +static void mock_context_unpin(struct intel_context *ce) { - struct intel_context *ce = to_intel_context(ctx, engine); + if (--ce->pin_count) + return; - if (!ce->pin_count++) - i915_gem_context_get(ctx); + i915_gem_context_put(ce->gem_context); +} - return engine->buffer; +static void mock_context_destroy(struct intel_context *ce) +{ + GEM_BUG_ON(ce->pin_count); } -static void mock_context_unpin(struct intel_engine_cs *engine, - struct i915_gem_context *ctx) +static const struct intel_context_ops mock_context_ops = { + .unpin = mock_context_unpin, + .destroy = mock_context_destroy, +}; + +static struct intel_context * +mock_context_pin(struct intel_engine_cs *engine, + struct i915_gem_context *ctx) { struct intel_context *ce = to_intel_context(ctx, engine); - if (!--ce->pin_count) - i915_gem_context_put(ctx); + if (!ce->pin_count++) { + i915_gem_context_get(ctx); + ce->ring = engine->buffer; + ce->ops = &mock_context_ops; + } + + return ce; } static int mock_request_alloc(struct i915_request *request) @@ -185,7 +197,6 @@ struct intel_engine_cs *mock_engine(struct drm_i915_private *i915, engine->base.status_page.page_addr = (void *)(engine + 1); engine->base.context_pin = mock_context_pin; - engine->base.context_unpin = mock_context_unpin; engine->base.request_alloc = mock_request_alloc; engine->base.emit_flush = mock_emit_flush; engine->base.emit_breadcrumb = mock_emit_breadcrumb; @@ -238,11 +249,13 @@ void mock_engine_free(struct intel_engine_cs *engine) { struct mock_engine *mock = container_of(engine, typeof(*mock), base); + struct intel_context *ce; GEM_BUG_ON(timer_pending(&mock->hw_delay)); - if (engine->last_retired_context) - intel_context_unpin(engine->last_retired_context, engine); + ce = fetch_and_zero(&engine->last_retired_context); + if (ce) + intel_context_unpin(ce); mock_ring_free(engine->buffer); -- GitLab From 867985d4a4319819a971645a262f3340f7d30343 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 17 May 2018 22:26:33 +0100 Subject: [PATCH 0034/1506] drm/i915: Pull the context->pin_count dec into the common intel_context_unpin As all backends implement the same pin_count mechanism and do a dec-and-test as their first step, pull that into the common intel_context_unpin(). This also pulls into the caller, eliminating the indirect call in the usual steady state case. The intel_context_pin() side is a little more complicated as it combines the lookup/alloc as well as pinning the state, and so is left for a later date. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180517212633.24934-4-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_context.h | 4 ++++ drivers/gpu/drm/i915/intel_lrc.c | 13 +------------ drivers/gpu/drm/i915/intel_ringbuffer.c | 6 ------ drivers/gpu/drm/i915/selftests/mock_engine.c | 3 --- 4 files changed, 5 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_context.h b/drivers/gpu/drm/i915/i915_gem_context.h index 749a4ff566f5b..c3262b4dd2ee6 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.h +++ b/drivers/gpu/drm/i915/i915_gem_context.h @@ -285,6 +285,10 @@ static inline void __intel_context_pin(struct intel_context *ce) static inline void intel_context_unpin(struct intel_context *ce) { + GEM_BUG_ON(!ce->pin_count); + if (--ce->pin_count) + return; + GEM_BUG_ON(!ce->ops); ce->ops->unpin(ce); } diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index b97c5d4c7877c..9abd26f22b477 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1343,7 +1343,7 @@ static void execlists_context_destroy(struct intel_context *ce) __i915_gem_object_release_unless_active(ce->state->obj); } -static void __execlists_context_unpin(struct intel_context *ce) +static void execlists_context_unpin(struct intel_context *ce) { intel_ring_unpin(ce->ring); @@ -1354,17 +1354,6 @@ static void __execlists_context_unpin(struct intel_context *ce) i915_gem_context_put(ce->gem_context); } -static void execlists_context_unpin(struct intel_context *ce) -{ - lockdep_assert_held(&ce->gem_context->i915->drm.struct_mutex); - GEM_BUG_ON(ce->pin_count == 0); - - if (--ce->pin_count) - return; - - __execlists_context_unpin(ce); -} - static int __context_pin(struct i915_gem_context *ctx, struct i915_vma *vma) { unsigned int flags; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 0c0c9f531e4ec..001cf6bcb3497 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1195,12 +1195,6 @@ static void intel_ring_context_destroy(struct intel_context *ce) static void intel_ring_context_unpin(struct intel_context *ce) { - lockdep_assert_held(&ce->gem_context->i915->drm.struct_mutex); - GEM_BUG_ON(ce->pin_count == 0); - - if (--ce->pin_count) - return; - if (ce->state) { ce->state->obj->pin_global--; i915_vma_unpin(ce->state); diff --git a/drivers/gpu/drm/i915/selftests/mock_engine.c b/drivers/gpu/drm/i915/selftests/mock_engine.c index 33eddfc1f8cec..f1ac7453053e4 100644 --- a/drivers/gpu/drm/i915/selftests/mock_engine.c +++ b/drivers/gpu/drm/i915/selftests/mock_engine.c @@ -74,9 +74,6 @@ static void hw_delay_complete(struct timer_list *t) static void mock_context_unpin(struct intel_context *ce) { - if (--ce->pin_count) - return; - i915_gem_context_put(ce->gem_context); } -- GitLab From 38992c57c9c8425dc9cb75efe6f9b9255ea627a0 Mon Sep 17 00:00:00 2001 From: Jyri Sarha <jsarha@ti.com> Date: Thu, 26 Apr 2018 11:06:59 +0300 Subject: [PATCH 0035/1506] drm/panel: Remove drm_panel_detach() calls from all panel drivers Remove all drm_panel_detach() calls from all panel drivers and update the kerneldoc for drm_panel_detach(). Setting the connector and drm to NULL when the DRM panel device is going away hardly serves any purpose. Usually the whole memory structure is freed right after the remove call. However, calling the detach function from the master DRM device, and setting the connector pointer to NULL, has the logic of marking the panel again as available for another DRM master to attach. The usual situation would be the same DRM master device binding again. Signed-off-by: Jyri Sarha <jsarha@ti.com> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/464b8d330d6b4c94cfb5aad2ca9ea7eb2c52d934.1524727888.git.jsarha@ti.com --- drivers/gpu/drm/drm_panel.c | 6 ++++++ drivers/gpu/drm/panel/panel-innolux-p079zca.c | 1 - drivers/gpu/drm/panel/panel-jdi-lt070me05000.c | 1 - drivers/gpu/drm/panel/panel-lvds.c | 1 - drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c | 1 - drivers/gpu/drm/panel/panel-seiko-43wvf1g.c | 1 - drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c | 1 - drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c | 1 - drivers/gpu/drm/panel/panel-simple.c | 1 - drivers/gpu/drm/panel/panel-sitronix-st7789v.c | 1 - 10 files changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c index 308d442a531b2..71e407574276b 100644 --- a/drivers/gpu/drm/drm_panel.c +++ b/drivers/gpu/drm/drm_panel.c @@ -94,6 +94,9 @@ EXPORT_SYMBOL(drm_panel_remove); * * An error is returned if the panel is already attached to another connector. * + * When unloading, the driver should detach from the panel by calling + * drm_panel_detach(). + * * Return: 0 on success or a negative error code on failure. */ int drm_panel_attach(struct drm_panel *panel, struct drm_connector *connector) @@ -115,6 +118,9 @@ EXPORT_SYMBOL(drm_panel_attach); * Detaches a panel from the connector it is attached to. If a panel is not * attached to any connector this is effectively a no-op. * + * This function should not be called by the panel device itself. It + * is only for the drm device that called drm_panel_attach(). + * * Return: 0 on success or a negative error code on failure. */ int drm_panel_detach(struct drm_panel *panel) diff --git a/drivers/gpu/drm/panel/panel-innolux-p079zca.c b/drivers/gpu/drm/panel/panel-innolux-p079zca.c index 57df39b5c5899..bb53e08507643 100644 --- a/drivers/gpu/drm/panel/panel-innolux-p079zca.c +++ b/drivers/gpu/drm/panel/panel-innolux-p079zca.c @@ -292,7 +292,6 @@ static int innolux_panel_remove(struct mipi_dsi_device *dsi) DRM_DEV_ERROR(&dsi->dev, "failed to detach from DSI host: %d\n", err); - drm_panel_detach(&innolux->base); innolux_panel_del(innolux); return 0; diff --git a/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c b/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c index 0a94ab79a6c0f..99caa7835e7b1 100644 --- a/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c +++ b/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c @@ -500,7 +500,6 @@ static int jdi_panel_remove(struct mipi_dsi_device *dsi) dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret); - drm_panel_detach(&jdi->base); jdi_panel_del(jdi); return 0; diff --git a/drivers/gpu/drm/panel/panel-lvds.c b/drivers/gpu/drm/panel/panel-lvds.c index 5185819c5b797..8a1687887ae91 100644 --- a/drivers/gpu/drm/panel/panel-lvds.c +++ b/drivers/gpu/drm/panel/panel-lvds.c @@ -282,7 +282,6 @@ static int panel_lvds_remove(struct platform_device *pdev) { struct panel_lvds *lvds = dev_get_drvdata(&pdev->dev); - drm_panel_detach(&lvds->panel); drm_panel_remove(&lvds->panel); panel_lvds_disable(&lvds->panel); diff --git a/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c b/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c index 74a806121f80e..cb4dfb98be0f1 100644 --- a/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c +++ b/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c @@ -299,7 +299,6 @@ static int wuxga_nt_panel_remove(struct mipi_dsi_device *dsi) if (ret < 0) dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret); - drm_panel_detach(&wuxga_nt->base); wuxga_nt_panel_del(wuxga_nt); return 0; diff --git a/drivers/gpu/drm/panel/panel-seiko-43wvf1g.c b/drivers/gpu/drm/panel/panel-seiko-43wvf1g.c index 71c09ed436ae4..75f9253905510 100644 --- a/drivers/gpu/drm/panel/panel-seiko-43wvf1g.c +++ b/drivers/gpu/drm/panel/panel-seiko-43wvf1g.c @@ -292,7 +292,6 @@ static int seiko_panel_remove(struct platform_device *pdev) { struct seiko_panel *panel = dev_get_drvdata(&pdev->dev); - drm_panel_detach(&panel->base); drm_panel_remove(&panel->base); seiko_panel_disable(&panel->base); diff --git a/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c b/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c index 6bf8730f1a211..02fc0f5423d40 100644 --- a/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c +++ b/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c @@ -418,7 +418,6 @@ static int sharp_panel_remove(struct mipi_dsi_device *dsi) if (err < 0) dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err); - drm_panel_detach(&sharp->base); sharp_panel_del(sharp); return 0; diff --git a/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c index 494aa9b1628a7..e5cae0050f52d 100644 --- a/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c +++ b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c @@ -327,7 +327,6 @@ static int sharp_nt_panel_remove(struct mipi_dsi_device *dsi) if (ret < 0) dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret); - drm_panel_detach(&sharp_nt->base); sharp_nt_panel_del(sharp_nt); return 0; diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index cbf1ab404ee77..062b6b416b896 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -364,7 +364,6 @@ static int panel_simple_remove(struct device *dev) { struct panel_simple *panel = dev_get_drvdata(dev); - drm_panel_detach(&panel->base); drm_panel_remove(&panel->base); panel_simple_disable(&panel->base); diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c index 358c64ef19222..74284e5afc5d9 100644 --- a/drivers/gpu/drm/panel/panel-sitronix-st7789v.c +++ b/drivers/gpu/drm/panel/panel-sitronix-st7789v.c @@ -419,7 +419,6 @@ static int st7789v_remove(struct spi_device *spi) { struct st7789v *ctx = spi_get_drvdata(spi); - drm_panel_detach(&ctx->panel); drm_panel_remove(&ctx->panel); if (ctx->backlight) -- GitLab From 0c08754b59da5557532d946599854e6df28edc22 Mon Sep 17 00:00:00 2001 From: Jyri Sarha <jsarha@ti.com> Date: Thu, 26 Apr 2018 11:07:00 +0300 Subject: [PATCH 0036/1506] drm/panel: Add device_link from panel device to DRM device Add device_link from panel device (supplier) to DRM device (consumer) when drm_panel_attach() is called. This patch should protect the master DRM driver if an attached panel driver unbinds while it is in use. The device_link should make sure the DRM device is unbound before the panel driver becomes unavailable. The device_link is removed when drm_panel_detach() is called. The drm_panel_detach() should be called by the consumer DRM driver, not the panel driver, otherwise both drivers are racing to delete the same link. Signed-off-by: Jyri Sarha <jsarha@ti.com> Reviewed-by: Eric Anholt <eric@anholt.net> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/b53584fd988d045c13de22d81825395b0ae0aad7.1524727888.git.jsarha@ti.com --- drivers/gpu/drm/drm_panel.c | 10 ++++++++++ include/drm/drm_panel.h | 1 + 2 files changed, 11 insertions(+) diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c index 71e407574276b..965530a6f4cd3 100644 --- a/drivers/gpu/drm/drm_panel.c +++ b/drivers/gpu/drm/drm_panel.c @@ -24,6 +24,7 @@ #include <linux/err.h> #include <linux/module.h> +#include <drm/drm_device.h> #include <drm/drm_crtc.h> #include <drm/drm_panel.h> @@ -104,6 +105,13 @@ int drm_panel_attach(struct drm_panel *panel, struct drm_connector *connector) if (panel->connector) return -EBUSY; + panel->link = device_link_add(connector->dev->dev, panel->dev, 0); + if (!panel->link) { + dev_err(panel->dev, "failed to link panel to %s\n", + dev_name(connector->dev->dev)); + return -EINVAL; + } + panel->connector = connector; panel->drm = connector->dev; @@ -125,6 +133,8 @@ EXPORT_SYMBOL(drm_panel_attach); */ int drm_panel_detach(struct drm_panel *panel) { + device_link_del(panel->link); + panel->connector = NULL; panel->drm = NULL; diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h index 14ac240a1f646..26a1b5fd8796c 100644 --- a/include/drm/drm_panel.h +++ b/include/drm/drm_panel.h @@ -89,6 +89,7 @@ struct drm_panel { struct drm_device *drm; struct drm_connector *connector; struct device *dev; + struct device_link *link; const struct drm_panel_funcs *funcs; -- GitLab From d9f9565c1f7f51904a5009671595a50b8ab0462b Mon Sep 17 00:00:00 2001 From: Philippe CORNU <philippe.cornu@st.com> Date: Mon, 23 Apr 2018 16:10:50 +0200 Subject: [PATCH 0037/1506] drm/panel: otm8009a: Fix backlight updates Backlight updates was not working anymore since the good implementation of the DSI low-power mode in the DSI host driver. After a longer analysis, the backlight updates in DSI video mode require the DSI high- speed mode. Note: it is important to keep the DSI low-power mode for the rest of the driver as init sequence, sleep in/out... DSI commands work in low-power mode. Signed-off-by: Philippe Cornu <philippe.cornu@st.com> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180423141054.13128-2-philippe.cornu@st.com --- .../gpu/drm/panel/panel-orisetech-otm8009a.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c index 90f1ae4af93c0..0fd2e0144d2bb 100644 --- a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c +++ b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c @@ -98,6 +98,20 @@ static void otm8009a_dcs_write_buf(struct otm8009a *ctx, const void *data, DRM_WARN("mipi dsi dcs write buffer failed\n"); } +static void otm8009a_dcs_write_buf_hs(struct otm8009a *ctx, const void *data, + size_t len) +{ + struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); + + /* data will be sent in dsi hs mode (ie. no lpm) */ + dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; + + otm8009a_dcs_write_buf(ctx, data, len); + + /* restore back the dsi lpm mode */ + dsi->mode_flags |= MIPI_DSI_MODE_LPM; +} + #define dcs_write_seq(ctx, seq...) \ ({ \ static const u8 d[] = { seq }; \ @@ -387,7 +401,7 @@ static int otm8009a_backlight_update_status(struct backlight_device *bd) */ data[0] = MIPI_DCS_SET_DISPLAY_BRIGHTNESS; data[1] = bd->props.brightness; - otm8009a_dcs_write_buf(ctx, data, ARRAY_SIZE(data)); + otm8009a_dcs_write_buf_hs(ctx, data, ARRAY_SIZE(data)); /* set Brightness Control & Backlight on */ data[1] = 0x24; @@ -399,7 +413,7 @@ static int otm8009a_backlight_update_status(struct backlight_device *bd) /* Update Brightness Control & Backlight */ data[0] = MIPI_DCS_WRITE_CONTROL_DISPLAY; - otm8009a_dcs_write_buf(ctx, data, ARRAY_SIZE(data)); + otm8009a_dcs_write_buf_hs(ctx, data, ARRAY_SIZE(data)); return 0; } -- GitLab From 36830ce4eb2b5f6fe796c457b4043160c0e1e1fe Mon Sep 17 00:00:00 2001 From: Philippe CORNU <philippe.cornu@st.com> Date: Mon, 23 Apr 2018 16:10:51 +0200 Subject: [PATCH 0038/1506] drm/panel: otm8009a: Fix glitches by moving backlight enable to otm8009a_enable() The backlight 1st update was in the otm8009a_prepare() function for a bad reason: backlight was not working in video mode and the otm8009a_prepare() is in command mode for the init sequence. As the backlight is now fixed (no low-power mode), it is good to put it back in the otm8009a_enable() function, avoiding also image glitches visible on some "slow" devices. Signed-off-by: Philippe Cornu <philippe.cornu@st.com> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180423141054.13128-3-philippe.cornu@st.com --- .../gpu/drm/panel/panel-orisetech-otm8009a.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c index 0fd2e0144d2bb..de4a16d5275ce 100644 --- a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c +++ b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c @@ -330,13 +330,6 @@ static int otm8009a_prepare(struct drm_panel *panel) ctx->prepared = true; - /* - * Power on the backlight. Note: end-user still controls brightness - * Note: ctx->prepared must be true before updating the backlight. - */ - ctx->bl_dev->props.power = FB_BLANK_UNBLANK; - backlight_update_status(ctx->bl_dev); - return 0; } @@ -344,6 +337,16 @@ static int otm8009a_enable(struct drm_panel *panel) { struct otm8009a *ctx = panel_to_otm8009a(panel); + if (ctx->enabled) + return 0; + + /* + * Power on the backlight. Note: end-user still controls brightness + * Note: ctx->prepared must be true before updating the backlight. + */ + ctx->bl_dev->props.power = FB_BLANK_UNBLANK; + backlight_update_status(ctx->bl_dev); + ctx->enabled = true; return 0; -- GitLab From 6982b943123d5867997a6d0f8b5976ac3ddb2fa6 Mon Sep 17 00:00:00 2001 From: Philippe CORNU <philippe.cornu@st.com> Date: Mon, 23 Apr 2018 16:10:52 +0200 Subject: [PATCH 0039/1506] drm/panel: otm8009a: No message if probe success Remove the message in case of probe success. This comes from a suggestion followed in the recent integration of the raydium rm68200 panel. Signed-off-by: Philippe Cornu <philippe.cornu@st.com> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180423141054.13128-4-philippe.cornu@st.com --- drivers/gpu/drm/panel/panel-orisetech-otm8009a.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c index de4a16d5275ce..4c638b7b9943f 100644 --- a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c +++ b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c @@ -14,8 +14,6 @@ #include <linux/regulator/consumer.h> #include <video/mipi_display.h> -#define DRV_NAME "orisetech_otm8009a" - #define OTM8009A_BACKLIGHT_DEFAULT 240 #define OTM8009A_BACKLIGHT_MAX 255 @@ -461,7 +459,7 @@ static int otm8009a_probe(struct mipi_dsi_device *dsi) ctx->panel.dev = dev; ctx->panel.funcs = &otm8009a_drm_funcs; - ctx->bl_dev = backlight_device_register(DRV_NAME "_backlight", dev, ctx, + ctx->bl_dev = backlight_device_register(dev_name(dev), dev, ctx, &otm8009a_backlight_ops, NULL); if (IS_ERR(ctx->bl_dev)) { dev_err(dev, "failed to register backlight device\n"); @@ -483,11 +481,6 @@ static int otm8009a_probe(struct mipi_dsi_device *dsi) return ret; } - DRM_INFO(DRV_NAME "_panel %ux%u@%u %ubpp dsi %udl - ready\n", - default_mode.hdisplay, default_mode.vdisplay, - default_mode.vrefresh, - mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes); - return 0; } @@ -513,7 +506,7 @@ static struct mipi_dsi_driver orisetech_otm8009a_driver = { .probe = otm8009a_probe, .remove = otm8009a_remove, .driver = { - .name = DRV_NAME "_panel", + .name = "panel-orisetech-otm8009a", .of_match_table = orisetech_otm8009a_of_match, }, }; -- GitLab From 12a6cbd4f3f10b01b8a190de3766e70492df316b Mon Sep 17 00:00:00 2001 From: Philippe CORNU <philippe.cornu@st.com> Date: Mon, 23 Apr 2018 16:10:53 +0200 Subject: [PATCH 0040/1506] drm/panel: otm8009a: Use new backlight API The backlight API provides new functions to enable and disable the backlight and which hide the intricacies of achieving the correct result. Signed-off-by: Philippe Cornu <philippe.cornu@st.com> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180423141054.13128-5-philippe.cornu@st.com --- .../gpu/drm/panel/panel-orisetech-otm8009a.c | 26 +++++++------------ 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c index 4c638b7b9943f..87fa316e1d7b0 100644 --- a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c +++ b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c @@ -260,11 +260,7 @@ static int otm8009a_disable(struct drm_panel *panel) if (!ctx->enabled) return 0; /* This is not an issue so we return 0 here */ - /* Power off the backlight. Note: end-user still controls brightness */ - ctx->bl_dev->props.power = FB_BLANK_POWERDOWN; - ret = backlight_update_status(ctx->bl_dev); - if (ret) - return ret; + backlight_disable(ctx->bl_dev); ret = mipi_dsi_dcs_set_display_off(dsi); if (ret) @@ -338,12 +334,7 @@ static int otm8009a_enable(struct drm_panel *panel) if (ctx->enabled) return 0; - /* - * Power on the backlight. Note: end-user still controls brightness - * Note: ctx->prepared must be true before updating the backlight. - */ - ctx->bl_dev->props.power = FB_BLANK_UNBLANK; - backlight_update_status(ctx->bl_dev); + backlight_enable(ctx->bl_dev); ctx->enabled = true; @@ -459,11 +450,14 @@ static int otm8009a_probe(struct mipi_dsi_device *dsi) ctx->panel.dev = dev; ctx->panel.funcs = &otm8009a_drm_funcs; - ctx->bl_dev = backlight_device_register(dev_name(dev), dev, ctx, - &otm8009a_backlight_ops, NULL); + ctx->bl_dev = devm_backlight_device_register(dev, dev_name(dev), + dsi->host->dev, ctx, + &otm8009a_backlight_ops, + NULL); if (IS_ERR(ctx->bl_dev)) { - dev_err(dev, "failed to register backlight device\n"); - return PTR_ERR(ctx->bl_dev); + ret = PTR_ERR(ctx->bl_dev); + dev_err(dev, "failed to register backlight: %d\n", ret); + return ret; } ctx->bl_dev->props.max_brightness = OTM8009A_BACKLIGHT_MAX; @@ -491,8 +485,6 @@ static int otm8009a_remove(struct mipi_dsi_device *dsi) mipi_dsi_detach(dsi); drm_panel_remove(&ctx->panel); - backlight_device_unregister(ctx->bl_dev); - return 0; } -- GitLab From eea740a98df9ff914001bd066389b6e8f1024991 Mon Sep 17 00:00:00 2001 From: Thierry Reding <treding@nvidia.com> Date: Thu, 26 Apr 2018 15:58:53 +0200 Subject: [PATCH 0041/1506] drm/bridge: cdns: Mark runtime PM operations as maybe unused Building the driver in a configuration with !PM currently causes a warning about these operations being unused. Mark them as such to shut up the compiler. Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180426135853.30895-1-thierry.reding@gmail.com --- drivers/gpu/drm/bridge/cdns-dsi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/bridge/cdns-dsi.c b/drivers/gpu/drm/bridge/cdns-dsi.c index c255fc3e1be5d..f2d43f24acfbe 100644 --- a/drivers/gpu/drm/bridge/cdns-dsi.c +++ b/drivers/gpu/drm/bridge/cdns-dsi.c @@ -1337,7 +1337,7 @@ static const struct mipi_dsi_host_ops cdns_dsi_ops = { .transfer = cdns_dsi_transfer, }; -static int cdns_dsi_resume(struct device *dev) +static int __maybe_unused cdns_dsi_resume(struct device *dev) { struct cdns_dsi *dsi = dev_get_drvdata(dev); @@ -1350,7 +1350,7 @@ static int cdns_dsi_resume(struct device *dev) return 0; } -static int cdns_dsi_suspend(struct device *dev) +static int __maybe_unused cdns_dsi_suspend(struct device *dev) { struct cdns_dsi *dsi = dev_get_drvdata(dev); -- GitLab From 9c04400f7ea6bbdfd0f069f082188c34c2d6a929 Mon Sep 17 00:00:00 2001 From: "spanda@codeaurora.org" <spanda@codeaurora.org> Date: Tue, 15 May 2018 11:22:44 +0530 Subject: [PATCH 0042/1506] dt-bindings: drm/panel: Document Innolux TV123WAM panel bindings Innolux TV123WAM is a 12.3" eDP display panel with 2160x1440 resolution, which can be supported by simple panel driver. Changes in v1: - Make use of simple panel driver instead of creating a new driver for this panel (Sean Paul). - Combine dt-binding and driver changes into one patch as done by other existing panel support changes. Changes in v2: - Separate driver change from dt-binding documentation (Rob Herring). - Add the properties from simple-panel binding that are applicable to this panel (Rob Herring). Signed-off-by: Sandeep Panda <spanda@codeaurora.org> Reviewed-by: Rob Herring <robh@kernel.org> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/1526363564-13823-5-git-send-email-spanda@codeaurora.org --- .../display/panel/innolux,tv123wam.txt | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/panel/innolux,tv123wam.txt diff --git a/Documentation/devicetree/bindings/display/panel/innolux,tv123wam.txt b/Documentation/devicetree/bindings/display/panel/innolux,tv123wam.txt new file mode 100644 index 0000000000000..a9b35265fa13a --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/innolux,tv123wam.txt @@ -0,0 +1,20 @@ +Innolux TV123WAM 12.3 inch eDP 2K display panel + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. + +Required properties: +- compatible: should be "innolux,tv123wam" +- power-supply: regulator to provide the supply voltage + +Optional properties: +- enable-gpios: GPIO pin to enable or disable the panel +- backlight: phandle of the backlight device attached to the panel + +Example: + panel_edp: panel-edp { + compatible = "innolux,tv123wam"; + enable-gpios = <&msmgpio 31 GPIO_ACTIVE_LOW>; + power-supply = <&pm8916_l2>; + backlight = <&backlight>; + }; -- GitLab From da50bd4258db62810de4e0f3d75cf7d3d67466b1 Mon Sep 17 00:00:00 2001 From: "spanda@codeaurora.org" <spanda@codeaurora.org> Date: Tue, 15 May 2018 11:22:43 +0530 Subject: [PATCH 0043/1506] drm/panel: simple: Add Innolux TV123WAM panel driver support Add support for Innolux TV123WAM, which is a 12.3" eDP display panel with 2160x1440 resolution. Changes in v1: - Add the compatibility string, display_mode and panel_desc structures in alphabetical order (Sean Paul). Signed-off-by: Sandeep Panda <spanda@codeaurora.org> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/1526363564-13823-4-git-send-email-spanda@codeaurora.org --- drivers/gpu/drm/panel/panel-simple.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 062b6b416b896..2209aeddae3c4 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -1216,6 +1216,30 @@ static const struct panel_desc innolux_n156bge_l21 = { }, }; +static const struct drm_display_mode innolux_tv123wam_mode = { + .clock = 206016, + .hdisplay = 2160, + .hsync_start = 2160 + 48, + .hsync_end = 2160 + 48 + 32, + .htotal = 2160 + 48 + 32 + 80, + .vdisplay = 1440, + .vsync_start = 1440 + 3, + .vsync_end = 1440 + 3 + 10, + .vtotal = 1440 + 3 + 10 + 27, + .vrefresh = 60, + .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC, +}; + +static const struct panel_desc innolux_tv123wam = { + .modes = &innolux_tv123wam_mode, + .num_modes = 1, + .bpc = 8, + .size = { + .width = 259, + .height = 173, + }, +}; + static const struct drm_display_mode innolux_zj070na_01p_mode = { .clock = 51501, .hdisplay = 1024, @@ -2168,6 +2192,9 @@ static const struct of_device_id platform_of_match[] = { }, { .compatible = "innolux,n156bge-l21", .data = &innolux_n156bge_l21, + }, { + .compatible = "innolux,tv123wam", + .data = &innolux_tv123wam, }, { .compatible = "innolux,zj070na-01p", .data = &innolux_zj070na_01p, -- GitLab From 2554f154b46f7d8a933f0616e8170bf4d970a2bf Mon Sep 17 00:00:00 2001 From: Lucas Stach <l.stach@pengutronix.de> Date: Wed, 11 Apr 2018 17:27:41 +0200 Subject: [PATCH 0044/1506] drm/panel: simple: AUO P320HVN03 uses SPWG data ordering The patch adding support for the AUO P320HVN03 panel was written against a preliminary datasheet, which specified JEIDA data ordering. Testing with real hardware has shown that the actually used data ordering is SPWG. Fixes: 70c0d5b783f5 (drm/panel: simple: add support for AUO P320HVN03) Signed-off-by: Lucas Stach <l.stach@pengutronix.de> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180411152741.22483-1-l.stach@pengutronix.de --- drivers/gpu/drm/panel/panel-simple.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 2209aeddae3c4..ba2631a7de0bb 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -686,7 +686,7 @@ static const struct panel_desc auo_p320hvn03 = { .enable = 450, .unprepare = 500, }, - .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA, + .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, }; static const struct drm_display_mode auo_t215hvn01_mode = { -- GitLab From c9b6be7dc13e2f87592ee4c9812cb450dba484d5 Mon Sep 17 00:00:00 2001 From: Stefan Agner <stefan@agner.ch> Date: Thu, 19 Apr 2018 23:20:03 +0200 Subject: [PATCH 0045/1506] drm/panel: simple: Fix data type in KEO TX31D200VM0BAA timings All values in a struct struct timing_entry (every entry in struct display_timing) require an integer. Choose the closest safe integer of 32. This avoids a warning seen with clang: drivers/gpu/drm/panel/panel-simple.c:1250:27: warning: implicit conversion from 'double' to 'u32' (aka 'unsigned int') changes value from 33.5 to 33 [-Wliteral-conversion] .vfront_porch = { 6, 21, 33.5 }, ~ ^~~~ drivers/gpu/drm/panel/panel-simple.c:1251:26: warning: implicit conversion from 'double' to 'u32' (aka 'unsigned int') changes value from 33.5 to 33 [-Wliteral-conversion] .vback_porch = { 6, 21, 33.5 }, ~ ^~~~ Signed-off-by: Stefan Agner <stefan@agner.ch> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180419212003.8155-1-stefan@agner.ch --- drivers/gpu/drm/panel/panel-simple.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index ba2631a7de0bb..964c261cfb78a 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -1270,8 +1270,8 @@ static const struct display_timing koe_tx31d200vm0baa_timing = { .hback_porch = { 16, 36, 56 }, .hsync_len = { 8, 8, 8 }, .vactive = { 480, 480, 480 }, - .vfront_porch = { 6, 21, 33.5 }, - .vback_porch = { 6, 21, 33.5 }, + .vfront_porch = { 6, 21, 33 }, + .vback_porch = { 6, 21, 33 }, .vsync_len = { 8, 8, 8 }, .flags = DISPLAY_FLAGS_DE_HIGH, }; -- GitLab From 9d7e70020c244940dc34f19b8d2da6b3f6516946 Mon Sep 17 00:00:00 2001 From: Daniel Stone <daniels@collabora.com> Date: Fri, 30 Mar 2018 15:11:15 +0100 Subject: [PATCH 0046/1506] drm/cirrus: Place GEM BOs in drm_framebuffer Since drm_framebuffer can now store GEM objects directly, place them there rather than in our own subclass. As this makes the framebuffer create_handle and destroy functions the same as the GEM framebuffer helper, we can reuse those. Signed-off-by: Daniel Stone <daniels@collabora.com> Reviewed-by: Thierry Reding <treding@nvidia.com> Cc: Dave Airlie <airlied@redhat.com> Cc: Gerd Hoffmann <kraxel@redhat.com> Cc: virtualization@lists.linux-foundation.org Link: https://patchwork.freedesktop.org/patch/msgid/20180330141138.28987-1-daniels@collabora.com --- drivers/gpu/drm/cirrus/cirrus_drv.h | 1 - drivers/gpu/drm/cirrus/cirrus_fbdev.c | 8 ++++---- drivers/gpu/drm/cirrus/cirrus_main.c | 25 ++++--------------------- drivers/gpu/drm/cirrus/cirrus_mode.c | 4 ++-- 4 files changed, 10 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.h b/drivers/gpu/drm/cirrus/cirrus_drv.h index be2d7e4880621..70b23629be0a9 100644 --- a/drivers/gpu/drm/cirrus/cirrus_drv.h +++ b/drivers/gpu/drm/cirrus/cirrus_drv.h @@ -119,7 +119,6 @@ struct cirrus_connector { struct cirrus_framebuffer { struct drm_framebuffer base; - struct drm_gem_object *obj; }; struct cirrus_mc { diff --git a/drivers/gpu/drm/cirrus/cirrus_fbdev.c b/drivers/gpu/drm/cirrus/cirrus_fbdev.c index 32fbfba2c623a..a74d328469589 100644 --- a/drivers/gpu/drm/cirrus/cirrus_fbdev.c +++ b/drivers/gpu/drm/cirrus/cirrus_fbdev.c @@ -29,7 +29,7 @@ static void cirrus_dirty_update(struct cirrus_fbdev *afbdev, int x2, y2; unsigned long flags; - obj = afbdev->gfb.obj; + obj = afbdev->gfb.base.obj[0]; bo = gem_to_cirrus_bo(obj); /* @@ -250,9 +250,9 @@ static int cirrus_fbdev_destroy(struct drm_device *dev, drm_fb_helper_unregister_fbi(&gfbdev->helper); - if (gfb->obj) { - drm_gem_object_put_unlocked(gfb->obj); - gfb->obj = NULL; + if (gfb->base.obj[0]) { + drm_gem_object_put_unlocked(gfb->base.obj[0]); + gfb->base.obj[0] = NULL; } vfree(gfbdev->sysram); diff --git a/drivers/gpu/drm/cirrus/cirrus_main.c b/drivers/gpu/drm/cirrus/cirrus_main.c index 26df1e8cd490d..f1ee4139ff193 100644 --- a/drivers/gpu/drm/cirrus/cirrus_main.c +++ b/drivers/gpu/drm/cirrus/cirrus_main.c @@ -10,30 +10,13 @@ */ #include <drm/drmP.h> #include <drm/drm_crtc_helper.h> +#include <drm/drm_gem_framebuffer_helper.h> #include "cirrus_drv.h" -static int cirrus_create_handle(struct drm_framebuffer *fb, - struct drm_file* file_priv, - unsigned int* handle) -{ - struct cirrus_framebuffer *cirrus_fb = to_cirrus_framebuffer(fb); - - return drm_gem_handle_create(file_priv, cirrus_fb->obj, handle); -} - -static void cirrus_user_framebuffer_destroy(struct drm_framebuffer *fb) -{ - struct cirrus_framebuffer *cirrus_fb = to_cirrus_framebuffer(fb); - - drm_gem_object_put_unlocked(cirrus_fb->obj); - drm_framebuffer_cleanup(fb); - kfree(fb); -} - static const struct drm_framebuffer_funcs cirrus_fb_funcs = { - .create_handle = cirrus_create_handle, - .destroy = cirrus_user_framebuffer_destroy, + .create_handle = drm_gem_fb_create_handle, + .destroy = drm_gem_fb_destroy, }; int cirrus_framebuffer_init(struct drm_device *dev, @@ -44,7 +27,7 @@ int cirrus_framebuffer_init(struct drm_device *dev, int ret; drm_helper_mode_fill_fb_struct(dev, &gfb->base, mode_cmd); - gfb->obj = obj; + gfb->base.obj[0] = obj; ret = drm_framebuffer_init(dev, &gfb->base, &cirrus_fb_funcs); if (ret) { DRM_ERROR("drm_framebuffer_init failed: %d\n", ret); diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c index c91b9b054e3f7..91b9c42013fff 100644 --- a/drivers/gpu/drm/cirrus/cirrus_mode.c +++ b/drivers/gpu/drm/cirrus/cirrus_mode.c @@ -110,7 +110,7 @@ static int cirrus_crtc_do_set_base(struct drm_crtc *crtc, /* push the previous fb to system ram */ if (!atomic && fb) { cirrus_fb = to_cirrus_framebuffer(fb); - obj = cirrus_fb->obj; + obj = cirrus_fb->base.obj[0]; bo = gem_to_cirrus_bo(obj); ret = cirrus_bo_reserve(bo, false); if (ret) @@ -120,7 +120,7 @@ static int cirrus_crtc_do_set_base(struct drm_crtc *crtc, } cirrus_fb = to_cirrus_framebuffer(crtc->primary->fb); - obj = cirrus_fb->obj; + obj = cirrus_fb->base.obj[0]; bo = gem_to_cirrus_bo(obj); ret = cirrus_bo_reserve(bo, false); -- GitLab From 121df61e5a301a6b4ef9efd4d1b190f73ef01419 Mon Sep 17 00:00:00 2001 From: Daniel Stone <daniels@collabora.com> Date: Fri, 30 Mar 2018 15:11:16 +0100 Subject: [PATCH 0047/1506] drm/cirrus: cirrus_framebuffer -> drm_framebuffer Now cirrus_framebuffer is just an empty wrapper around drm_framebuffer, we can drop it. Signed-off-by: Daniel Stone <daniels@collabora.com> Reviewed-by: Thierry Reding <treding@nvidia.com> Cc: Dave Airlie <airlied@redhat.com> Cc: Gerd Hoffmann <kraxel@redhat.com> Cc: virtualization@lists.linux-foundation.org Link: https://patchwork.freedesktop.org/patch/msgid/20180330141138.28987-2-daniels@collabora.com --- drivers/gpu/drm/cirrus/cirrus_drv.h | 9 ++------- drivers/gpu/drm/cirrus/cirrus_fbdev.c | 20 ++++++++++---------- drivers/gpu/drm/cirrus/cirrus_main.c | 20 ++++++++++---------- drivers/gpu/drm/cirrus/cirrus_mode.c | 12 +++--------- 4 files changed, 25 insertions(+), 36 deletions(-) diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.h b/drivers/gpu/drm/cirrus/cirrus_drv.h index 70b23629be0a9..ce9db7aab2255 100644 --- a/drivers/gpu/drm/cirrus/cirrus_drv.h +++ b/drivers/gpu/drm/cirrus/cirrus_drv.h @@ -92,7 +92,6 @@ #define to_cirrus_crtc(x) container_of(x, struct cirrus_crtc, base) #define to_cirrus_encoder(x) container_of(x, struct cirrus_encoder, base) -#define to_cirrus_framebuffer(x) container_of(x, struct cirrus_framebuffer, base) struct cirrus_crtc { struct drm_crtc base; @@ -117,10 +116,6 @@ struct cirrus_connector { struct drm_connector base; }; -struct cirrus_framebuffer { - struct drm_framebuffer base; -}; - struct cirrus_mc { resource_size_t vram_size; resource_size_t vram_base; @@ -151,7 +146,7 @@ struct cirrus_device { struct cirrus_fbdev { struct drm_fb_helper helper; - struct cirrus_framebuffer gfb; + struct drm_framebuffer gfb; void *sysram; int size; int x1, y1, x2, y2; /* dirty rect */ @@ -197,7 +192,7 @@ int cirrus_dumb_create(struct drm_file *file, struct drm_mode_create_dumb *args); int cirrus_framebuffer_init(struct drm_device *dev, - struct cirrus_framebuffer *gfb, + struct drm_framebuffer *gfb, const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object *obj); diff --git a/drivers/gpu/drm/cirrus/cirrus_fbdev.c b/drivers/gpu/drm/cirrus/cirrus_fbdev.c index a74d328469589..b643ac92801c8 100644 --- a/drivers/gpu/drm/cirrus/cirrus_fbdev.c +++ b/drivers/gpu/drm/cirrus/cirrus_fbdev.c @@ -22,14 +22,14 @@ static void cirrus_dirty_update(struct cirrus_fbdev *afbdev, struct drm_gem_object *obj; struct cirrus_bo *bo; int src_offset, dst_offset; - int bpp = afbdev->gfb.base.format->cpp[0]; + int bpp = afbdev->gfb.format->cpp[0]; int ret = -EBUSY; bool unmap = false; bool store_for_later = false; int x2, y2; unsigned long flags; - obj = afbdev->gfb.base.obj[0]; + obj = afbdev->gfb.obj[0]; bo = gem_to_cirrus_bo(obj); /* @@ -82,7 +82,7 @@ static void cirrus_dirty_update(struct cirrus_fbdev *afbdev, } for (i = y; i < y + height; i++) { /* assume equal stride for now */ - src_offset = dst_offset = i * afbdev->gfb.base.pitches[0] + (x * bpp); + src_offset = dst_offset = i * afbdev->gfb.pitches[0] + (x * bpp); memcpy_toio(bo->kmap.virtual + src_offset, afbdev->sysram + src_offset, width * bpp); } @@ -204,7 +204,7 @@ static int cirrusfb_create(struct drm_fb_helper *helper, gfbdev->sysram = sysram; gfbdev->size = size; - fb = &gfbdev->gfb.base; + fb = &gfbdev->gfb; if (!fb) { DRM_INFO("fb is NULL\n"); return -EINVAL; @@ -246,19 +246,19 @@ static int cirrusfb_create(struct drm_fb_helper *helper, static int cirrus_fbdev_destroy(struct drm_device *dev, struct cirrus_fbdev *gfbdev) { - struct cirrus_framebuffer *gfb = &gfbdev->gfb; + struct drm_framebuffer *gfb = &gfbdev->gfb; drm_fb_helper_unregister_fbi(&gfbdev->helper); - if (gfb->base.obj[0]) { - drm_gem_object_put_unlocked(gfb->base.obj[0]); - gfb->base.obj[0] = NULL; + if (gfb->obj[0]) { + drm_gem_object_put_unlocked(gfb->obj[0]); + gfb->obj[0] = NULL; } vfree(gfbdev->sysram); drm_fb_helper_fini(&gfbdev->helper); - drm_framebuffer_unregister_private(&gfb->base); - drm_framebuffer_cleanup(&gfb->base); + drm_framebuffer_unregister_private(gfb); + drm_framebuffer_cleanup(gfb); return 0; } diff --git a/drivers/gpu/drm/cirrus/cirrus_main.c b/drivers/gpu/drm/cirrus/cirrus_main.c index f1ee4139ff193..60d54e10a34d4 100644 --- a/drivers/gpu/drm/cirrus/cirrus_main.c +++ b/drivers/gpu/drm/cirrus/cirrus_main.c @@ -20,15 +20,15 @@ static const struct drm_framebuffer_funcs cirrus_fb_funcs = { }; int cirrus_framebuffer_init(struct drm_device *dev, - struct cirrus_framebuffer *gfb, + struct drm_framebuffer *gfb, const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object *obj) { int ret; - drm_helper_mode_fill_fb_struct(dev, &gfb->base, mode_cmd); - gfb->base.obj[0] = obj; - ret = drm_framebuffer_init(dev, &gfb->base, &cirrus_fb_funcs); + drm_helper_mode_fill_fb_struct(dev, gfb, mode_cmd); + gfb->obj[0] = obj; + ret = drm_framebuffer_init(dev, gfb, &cirrus_fb_funcs); if (ret) { DRM_ERROR("drm_framebuffer_init failed: %d\n", ret); return ret; @@ -43,7 +43,7 @@ cirrus_user_framebuffer_create(struct drm_device *dev, { struct cirrus_device *cdev = dev->dev_private; struct drm_gem_object *obj; - struct cirrus_framebuffer *cirrus_fb; + struct drm_framebuffer *fb; u32 bpp; int ret; @@ -57,19 +57,19 @@ cirrus_user_framebuffer_create(struct drm_device *dev, if (obj == NULL) return ERR_PTR(-ENOENT); - cirrus_fb = kzalloc(sizeof(*cirrus_fb), GFP_KERNEL); - if (!cirrus_fb) { + fb = kzalloc(sizeof(*fb), GFP_KERNEL); + if (!fb) { drm_gem_object_put_unlocked(obj); return ERR_PTR(-ENOMEM); } - ret = cirrus_framebuffer_init(dev, cirrus_fb, mode_cmd, obj); + ret = cirrus_framebuffer_init(dev, fb, mode_cmd, obj); if (ret) { drm_gem_object_put_unlocked(obj); - kfree(cirrus_fb); + kfree(fb); return ERR_PTR(ret); } - return &cirrus_fb->base; + return fb; } static const struct drm_mode_config_funcs cirrus_mode_funcs = { diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c index 91b9c42013fff..b529f8c8e2a63 100644 --- a/drivers/gpu/drm/cirrus/cirrus_mode.c +++ b/drivers/gpu/drm/cirrus/cirrus_mode.c @@ -101,17 +101,13 @@ static int cirrus_crtc_do_set_base(struct drm_crtc *crtc, int x, int y, int atomic) { struct cirrus_device *cdev = crtc->dev->dev_private; - struct drm_gem_object *obj; - struct cirrus_framebuffer *cirrus_fb; struct cirrus_bo *bo; int ret; u64 gpu_addr; /* push the previous fb to system ram */ if (!atomic && fb) { - cirrus_fb = to_cirrus_framebuffer(fb); - obj = cirrus_fb->base.obj[0]; - bo = gem_to_cirrus_bo(obj); + bo = gem_to_cirrus_bo(fb->obj[0]); ret = cirrus_bo_reserve(bo, false); if (ret) return ret; @@ -119,9 +115,7 @@ static int cirrus_crtc_do_set_base(struct drm_crtc *crtc, cirrus_bo_unreserve(bo); } - cirrus_fb = to_cirrus_framebuffer(crtc->primary->fb); - obj = cirrus_fb->base.obj[0]; - bo = gem_to_cirrus_bo(obj); + bo = gem_to_cirrus_bo(crtc->primary->fb->obj[0]); ret = cirrus_bo_reserve(bo, false); if (ret) @@ -133,7 +127,7 @@ static int cirrus_crtc_do_set_base(struct drm_crtc *crtc, return ret; } - if (&cdev->mode_info.gfbdev->gfb == cirrus_fb) { + if (&cdev->mode_info.gfbdev->gfb == crtc->primary->fb) { /* if pushing console in kmap it */ ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); if (ret) -- GitLab From 3823da3aeb47c1b5f07974cf7c87443da2a93ad0 Mon Sep 17 00:00:00 2001 From: Daniel Stone <daniels@collabora.com> Date: Fri, 30 Mar 2018 15:11:17 +0100 Subject: [PATCH 0048/1506] drm/virtio: Place GEM BOs in drm_framebuffer Since drm_framebuffer can now store GEM objects directly, place them there rather than in our own subclass. As this makes the framebuffer create_handle and destroy functions the same as the GEM framebuffer helper, we can reuse those. Signed-off-by: Daniel Stone <daniels@collabora.com> Reviewed-by: Thierry Reding <treding@nvidia.com> Cc: Dave Airlie <airlied@redhat.com> Cc: Gerd Hoffmann <kraxel@redhat.com> Cc: virtualization@lists.linux-foundation.org Link: https://patchwork.freedesktop.org/patch/msgid/20180330141138.28987-3-daniels@collabora.com --- drivers/gpu/drm/virtio/virtgpu_display.c | 30 ++++-------------------- drivers/gpu/drm/virtio/virtgpu_drv.h | 1 - drivers/gpu/drm/virtio/virtgpu_fb.c | 8 +++---- drivers/gpu/drm/virtio/virtgpu_plane.c | 4 ++-- 4 files changed, 11 insertions(+), 32 deletions(-) diff --git a/drivers/gpu/drm/virtio/virtgpu_display.c b/drivers/gpu/drm/virtio/virtgpu_display.c index a5edd86603d9e..d6dd769a7ad3f 100644 --- a/drivers/gpu/drm/virtio/virtgpu_display.c +++ b/drivers/gpu/drm/virtio/virtgpu_display.c @@ -28,6 +28,7 @@ #include "virtgpu_drv.h" #include <drm/drm_crtc_helper.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_gem_framebuffer_helper.h> #define XRES_MIN 32 #define YRES_MIN 32 @@ -48,16 +49,6 @@ static const struct drm_crtc_funcs virtio_gpu_crtc_funcs = { .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, }; -static void virtio_gpu_user_framebuffer_destroy(struct drm_framebuffer *fb) -{ - struct virtio_gpu_framebuffer *virtio_gpu_fb - = to_virtio_gpu_framebuffer(fb); - - drm_gem_object_put_unlocked(virtio_gpu_fb->obj); - drm_framebuffer_cleanup(fb); - kfree(virtio_gpu_fb); -} - static int virtio_gpu_framebuffer_surface_dirty(struct drm_framebuffer *fb, struct drm_file *file_priv, @@ -71,20 +62,9 @@ virtio_gpu_framebuffer_surface_dirty(struct drm_framebuffer *fb, return virtio_gpu_surface_dirty(virtio_gpu_fb, clips, num_clips); } -static int -virtio_gpu_framebuffer_create_handle(struct drm_framebuffer *fb, - struct drm_file *file_priv, - unsigned int *handle) -{ - struct virtio_gpu_framebuffer *virtio_gpu_fb = - to_virtio_gpu_framebuffer(fb); - - return drm_gem_handle_create(file_priv, virtio_gpu_fb->obj, handle); -} - static const struct drm_framebuffer_funcs virtio_gpu_fb_funcs = { - .create_handle = virtio_gpu_framebuffer_create_handle, - .destroy = virtio_gpu_user_framebuffer_destroy, + .create_handle = drm_gem_fb_create_handle, + .destroy = drm_gem_fb_destroy, .dirty = virtio_gpu_framebuffer_surface_dirty, }; @@ -97,7 +77,7 @@ virtio_gpu_framebuffer_init(struct drm_device *dev, int ret; struct virtio_gpu_object *bo; - vgfb->obj = obj; + vgfb->base.obj[0] = obj; bo = gem_to_virtio_gpu_obj(obj); @@ -105,7 +85,7 @@ virtio_gpu_framebuffer_init(struct drm_device *dev, ret = drm_framebuffer_init(dev, &vgfb->base, &virtio_gpu_fb_funcs); if (ret) { - vgfb->obj = NULL; + vgfb->base.obj[0] = NULL; return ret; } diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h index d25c8ca224aa1..65605e207bbe8 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.h +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h @@ -124,7 +124,6 @@ struct virtio_gpu_output { struct virtio_gpu_framebuffer { struct drm_framebuffer base; - struct drm_gem_object *obj; int x1, y1, x2, y2; /* dirty rect */ spinlock_t dirty_lock; uint32_t hw_res_handle; diff --git a/drivers/gpu/drm/virtio/virtgpu_fb.c b/drivers/gpu/drm/virtio/virtgpu_fb.c index 8af69ab58b89f..a121b1c79522f 100644 --- a/drivers/gpu/drm/virtio/virtgpu_fb.c +++ b/drivers/gpu/drm/virtio/virtgpu_fb.c @@ -46,7 +46,7 @@ static int virtio_gpu_dirty_update(struct virtio_gpu_framebuffer *fb, int bpp = fb->base.format->cpp[0]; int x2, y2; unsigned long flags; - struct virtio_gpu_object *obj = gem_to_virtio_gpu_obj(fb->obj); + struct virtio_gpu_object *obj = gem_to_virtio_gpu_obj(fb->base.obj[0]); if ((width <= 0) || (x + width > fb->base.width) || @@ -121,7 +121,7 @@ int virtio_gpu_surface_dirty(struct virtio_gpu_framebuffer *vgfb, unsigned int num_clips) { struct virtio_gpu_device *vgdev = vgfb->base.dev->dev_private; - struct virtio_gpu_object *obj = gem_to_virtio_gpu_obj(vgfb->obj); + struct virtio_gpu_object *obj = gem_to_virtio_gpu_obj(vgfb->base.obj[0]); struct drm_clip_rect norect; struct drm_clip_rect *clips_ptr; int left, right, top, bottom; @@ -305,8 +305,8 @@ static int virtio_gpu_fbdev_destroy(struct drm_device *dev, drm_fb_helper_unregister_fbi(&vgfbdev->helper); - if (vgfb->obj) - vgfb->obj = NULL; + if (vgfb->base.obj[0]) + vgfb->base.obj[0] = NULL; drm_fb_helper_fini(&vgfbdev->helper); drm_framebuffer_cleanup(&vgfb->base); diff --git a/drivers/gpu/drm/virtio/virtgpu_plane.c b/drivers/gpu/drm/virtio/virtgpu_plane.c index 71ba455af915b..dc5b5b2b7aab3 100644 --- a/drivers/gpu/drm/virtio/virtgpu_plane.c +++ b/drivers/gpu/drm/virtio/virtgpu_plane.c @@ -154,7 +154,7 @@ static void virtio_gpu_primary_plane_update(struct drm_plane *plane, if (plane->state->fb) { vgfb = to_virtio_gpu_framebuffer(plane->state->fb); - bo = gem_to_virtio_gpu_obj(vgfb->obj); + bo = gem_to_virtio_gpu_obj(vgfb->base.obj[0]); handle = bo->hw_res_handle; if (bo->dumb) { virtio_gpu_cmd_transfer_to_host_2d @@ -208,7 +208,7 @@ static void virtio_gpu_cursor_plane_update(struct drm_plane *plane, if (plane->state->fb) { vgfb = to_virtio_gpu_framebuffer(plane->state->fb); - bo = gem_to_virtio_gpu_obj(vgfb->obj); + bo = gem_to_virtio_gpu_obj(vgfb->base.obj[0]); handle = bo->hw_res_handle; } else { handle = 0; -- GitLab From ecb8a947855c9658cd0382f3cab39f91a7ebe86a Mon Sep 17 00:00:00 2001 From: Daniel Stone <daniels@collabora.com> Date: Fri, 30 Mar 2018 15:11:33 +0100 Subject: [PATCH 0049/1506] drm/armada: Move GEM BO to drm_framebuffer Since drm_framebuffer can now store GEM objects directly, place them there rather than in our own subclass. As this makes the framebuffer create_handle and destroy functions the same as the GEM framebuffer helper, we can reuse those. Signed-off-by: Daniel Stone <daniels@collabora.com> Reviewed-by: Thierry Reding <treding@nvidia.com> Reviewed-by: Russell King <linux@armlinux.org.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20180330141138.28987-19-daniels@collabora.com --- drivers/gpu/drm/armada/armada_fb.c | 23 ++++------------------- drivers/gpu/drm/armada/armada_fb.h | 3 +-- 2 files changed, 5 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_fb.c b/drivers/gpu/drm/armada/armada_fb.c index ac92bce07ecd9..edd15126bde93 100644 --- a/drivers/gpu/drm/armada/armada_fb.c +++ b/drivers/gpu/drm/armada/armada_fb.c @@ -7,30 +7,15 @@ */ #include <drm/drm_crtc_helper.h> #include <drm/drm_fb_helper.h> +#include <drm/drm_gem_framebuffer_helper.h> #include "armada_drm.h" #include "armada_fb.h" #include "armada_gem.h" #include "armada_hw.h" -static void armada_fb_destroy(struct drm_framebuffer *fb) -{ - struct armada_framebuffer *dfb = drm_fb_to_armada_fb(fb); - - drm_framebuffer_cleanup(&dfb->fb); - drm_gem_object_put_unlocked(&dfb->obj->obj); - kfree(dfb); -} - -static int armada_fb_create_handle(struct drm_framebuffer *fb, - struct drm_file *dfile, unsigned int *handle) -{ - struct armada_framebuffer *dfb = drm_fb_to_armada_fb(fb); - return drm_gem_handle_create(dfile, &dfb->obj->obj, handle); -} - static const struct drm_framebuffer_funcs armada_fb_funcs = { - .destroy = armada_fb_destroy, - .create_handle = armada_fb_create_handle, + .destroy = drm_gem_fb_destroy, + .create_handle = drm_gem_fb_create_handle, }; struct armada_framebuffer *armada_framebuffer_create(struct drm_device *dev, @@ -78,7 +63,7 @@ struct armada_framebuffer *armada_framebuffer_create(struct drm_device *dev, dfb->fmt = format; dfb->mod = config; - dfb->obj = obj; + dfb->fb.obj[0] = &obj->obj; drm_helper_mode_fill_fb_struct(dev, &dfb->fb, mode); diff --git a/drivers/gpu/drm/armada/armada_fb.h b/drivers/gpu/drm/armada/armada_fb.h index 48073c4f54d8d..5c130ff5da770 100644 --- a/drivers/gpu/drm/armada/armada_fb.h +++ b/drivers/gpu/drm/armada/armada_fb.h @@ -10,13 +10,12 @@ struct armada_framebuffer { struct drm_framebuffer fb; - struct armada_gem_object *obj; uint8_t fmt; uint8_t mod; }; #define drm_fb_to_armada_fb(dfb) \ container_of(dfb, struct armada_framebuffer, fb) -#define drm_fb_obj(fb) drm_fb_to_armada_fb(fb)->obj +#define drm_fb_obj(fb) drm_to_armada_gem((fb)->obj[0]) struct armada_framebuffer *armada_framebuffer_create(struct drm_device *, const struct drm_mode_fb_cmd2 *, struct armada_gem_object *); -- GitLab From bc61c97502e26af1be54022883d14ee0c03379fc Mon Sep 17 00:00:00 2001 From: Daniel Stone <daniels@collabora.com> Date: Fri, 30 Mar 2018 15:11:34 +0100 Subject: [PATCH 0050/1506] drm/gma500: Move GEM BO to drm_framebuffer Since drm_framebuffer can now store GEM objects directly, place them there rather than in our own subclass. As this makes the framebuffer create_handle and destroy functions the same as the GEM framebuffer helper, we can reuse those. Signed-off-by: Daniel Stone <daniels@collabora.com> Reviewed-by: Thierry Reding <treding@nvidia.com> Cc: Patrik Jakobsson <patrik.r.jakobsson@gmail.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180330141138.28987-20-daniels@collabora.com --- drivers/gpu/drm/gma500/accel_2d.c | 2 +- drivers/gpu/drm/gma500/framebuffer.c | 62 +++++--------------------- drivers/gpu/drm/gma500/framebuffer.h | 1 - drivers/gpu/drm/gma500/gma_display.c | 10 ++--- drivers/gpu/drm/gma500/gtt.h | 2 + drivers/gpu/drm/gma500/oaktrail_crtc.c | 3 +- 6 files changed, 20 insertions(+), 60 deletions(-) diff --git a/drivers/gpu/drm/gma500/accel_2d.c b/drivers/gpu/drm/gma500/accel_2d.c index c51d9259c7a7c..204c8e452eb77 100644 --- a/drivers/gpu/drm/gma500/accel_2d.c +++ b/drivers/gpu/drm/gma500/accel_2d.c @@ -251,7 +251,7 @@ static void psbfb_copyarea_accel(struct fb_info *info, if (!fb) return; - offset = psbfb->gtt->offset; + offset = to_gtt_range(fb->obj[0])->offset; stride = fb->pitches[0]; switch (fb->format->depth) { diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c index cb0a2ae916e09..8fa4ef192c1eb 100644 --- a/drivers/gpu/drm/gma500/framebuffer.c +++ b/drivers/gpu/drm/gma500/framebuffer.c @@ -33,6 +33,7 @@ #include <drm/drm.h> #include <drm/drm_crtc.h> #include <drm/drm_fb_helper.h> +#include <drm/drm_gem_framebuffer_helper.h> #include "psb_drv.h" #include "psb_intel_reg.h" @@ -40,14 +41,9 @@ #include "framebuffer.h" #include "gtt.h" -static void psb_user_framebuffer_destroy(struct drm_framebuffer *fb); -static int psb_user_framebuffer_create_handle(struct drm_framebuffer *fb, - struct drm_file *file_priv, - unsigned int *handle); - static const struct drm_framebuffer_funcs psb_fb_funcs = { - .destroy = psb_user_framebuffer_destroy, - .create_handle = psb_user_framebuffer_create_handle, + .destroy = drm_gem_fb_destroy, + .create_handle = drm_gem_fb_create_handle, }; #define CMAP_TOHW(_val, _width) ((((_val) << (_width)) + 0x7FFF - (_val)) >> 16) @@ -96,17 +92,18 @@ static int psbfb_pan(struct fb_var_screeninfo *var, struct fb_info *info) struct psb_fbdev *fbdev = info->par; struct psb_framebuffer *psbfb = &fbdev->pfb; struct drm_device *dev = psbfb->base.dev; + struct gtt_range *gtt = to_gtt_range(psbfb->base.obj[0]); /* * We have to poke our nose in here. The core fb code assumes * panning is part of the hardware that can be invoked before * the actual fb is mapped. In our case that isn't quite true. */ - if (psbfb->gtt->npage) { + if (gtt->npage) { /* GTT roll shifts in 4K pages, we need to shift the right number of pages */ int pages = info->fix.line_length >> 12; - psb_gtt_roll(dev, psbfb->gtt, var->yoffset * pages); + psb_gtt_roll(dev, gtt, var->yoffset * pages); } return 0; } @@ -117,13 +114,14 @@ static int psbfb_vm_fault(struct vm_fault *vmf) struct psb_framebuffer *psbfb = vma->vm_private_data; struct drm_device *dev = psbfb->base.dev; struct drm_psb_private *dev_priv = dev->dev_private; + struct gtt_range *gtt = to_gtt_range(psbfb->base.obj[0]); int page_num; int i; unsigned long address; int ret; unsigned long pfn; unsigned long phys_addr = (unsigned long)dev_priv->stolen_base + - psbfb->gtt->offset; + gtt->offset; page_num = vma_pages(vma); address = vmf->address - (vmf->pgoff << PAGE_SHIFT); @@ -246,7 +244,7 @@ static int psb_framebuffer_init(struct drm_device *dev, return -EINVAL; drm_helper_mode_fill_fb_struct(dev, &fb->base, mode_cmd); - fb->gtt = gt; + fb->base.obj[0] = >->gem; ret = drm_framebuffer_init(dev, &fb->base, &psb_fb_funcs); if (ret) { dev_err(dev->dev, "framebuffer init failed: %d\n", ret); @@ -518,8 +516,8 @@ static int psb_fbdev_destroy(struct drm_device *dev, struct psb_fbdev *fbdev) drm_framebuffer_unregister_private(&psbfb->base); drm_framebuffer_cleanup(&psbfb->base); - if (psbfb->gtt) - drm_gem_object_unreference_unlocked(&psbfb->gtt->gem); + if (psbfb->base.obj[0]) + drm_gem_object_unreference_unlocked(psbfb->base.obj[0]); return 0; } @@ -576,44 +574,6 @@ static void psb_fbdev_fini(struct drm_device *dev) dev_priv->fbdev = NULL; } -/** - * psb_user_framebuffer_create_handle - add hamdle to a framebuffer - * @fb: framebuffer - * @file_priv: our DRM file - * @handle: returned handle - * - * Our framebuffer object is a GTT range which also contains a GEM - * object. We need to turn it into a handle for userspace. GEM will do - * the work for us - */ -static int psb_user_framebuffer_create_handle(struct drm_framebuffer *fb, - struct drm_file *file_priv, - unsigned int *handle) -{ - struct psb_framebuffer *psbfb = to_psb_fb(fb); - struct gtt_range *r = psbfb->gtt; - return drm_gem_handle_create(file_priv, &r->gem, handle); -} - -/** - * psb_user_framebuffer_destroy - destruct user created fb - * @fb: framebuffer - * - * User framebuffers are backed by GEM objects so all we have to do is - * clean up a bit and drop the reference, GEM will handle the fallout - */ -static void psb_user_framebuffer_destroy(struct drm_framebuffer *fb) -{ - struct psb_framebuffer *psbfb = to_psb_fb(fb); - struct gtt_range *r = psbfb->gtt; - - /* Let DRM do its clean up */ - drm_framebuffer_cleanup(fb); - /* We are no longer using the resource in GEM */ - drm_gem_object_unreference_unlocked(&r->gem); - kfree(fb); -} - static const struct drm_mode_config_funcs psb_mode_funcs = { .fb_create = psb_user_framebuffer_create, .output_poll_changed = drm_fb_helper_output_poll_changed, diff --git a/drivers/gpu/drm/gma500/framebuffer.h b/drivers/gpu/drm/gma500/framebuffer.h index 395f20b07aabc..23dc3c5f8f0de 100644 --- a/drivers/gpu/drm/gma500/framebuffer.h +++ b/drivers/gpu/drm/gma500/framebuffer.h @@ -31,7 +31,6 @@ struct psb_framebuffer { struct drm_framebuffer base; struct address_space *addr_space; struct fb_info *fbdev; - struct gtt_range *gtt; }; struct psb_fbdev { diff --git a/drivers/gpu/drm/gma500/gma_display.c b/drivers/gpu/drm/gma500/gma_display.c index f3c48a2be71b8..c8f071c47dafa 100644 --- a/drivers/gpu/drm/gma500/gma_display.c +++ b/drivers/gpu/drm/gma500/gma_display.c @@ -60,7 +60,7 @@ int gma_pipe_set_base(struct drm_crtc *crtc, int x, int y, struct drm_psb_private *dev_priv = dev->dev_private; struct gma_crtc *gma_crtc = to_gma_crtc(crtc); struct drm_framebuffer *fb = crtc->primary->fb; - struct psb_framebuffer *psbfb = to_psb_fb(fb); + struct gtt_range *gtt = to_gtt_range(fb->obj[0]); int pipe = gma_crtc->pipe; const struct psb_offset *map = &dev_priv->regmap[pipe]; unsigned long start, offset; @@ -78,10 +78,10 @@ int gma_pipe_set_base(struct drm_crtc *crtc, int x, int y, /* We are displaying this buffer, make sure it is actually loaded into the GTT */ - ret = psb_gtt_pin(psbfb->gtt); + ret = psb_gtt_pin(gtt); if (ret < 0) goto gma_pipe_set_base_exit; - start = psbfb->gtt->offset; + start = gtt->offset; offset = y * fb->pitches[0] + x * fb->format->cpp[0]; REG_WRITE(map->stride, fb->pitches[0]); @@ -129,7 +129,7 @@ int gma_pipe_set_base(struct drm_crtc *crtc, int x, int y, gma_pipe_cleaner: /* If there was a previous display we can now unpin it */ if (old_fb) - psb_gtt_unpin(to_psb_fb(old_fb)->gtt); + psb_gtt_unpin(to_gtt_range(old_fb->obj[0])); gma_pipe_set_base_exit: gma_power_end(dev); @@ -491,7 +491,7 @@ void gma_crtc_disable(struct drm_crtc *crtc) crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); if (crtc->primary->fb) { - gt = to_psb_fb(crtc->primary->fb)->gtt; + gt = to_gtt_range(crtc->primary->fb->obj[0]); psb_gtt_unpin(gt); } } diff --git a/drivers/gpu/drm/gma500/gtt.h b/drivers/gpu/drm/gma500/gtt.h index cdbb350c9d5d2..cb0c3a2a1fd4b 100644 --- a/drivers/gpu/drm/gma500/gtt.h +++ b/drivers/gpu/drm/gma500/gtt.h @@ -53,6 +53,8 @@ struct gtt_range { int roll; /* Roll applied to the GTT entries */ }; +#define to_gtt_range(x) container_of(x, struct gtt_range, gem) + extern struct gtt_range *psb_gtt_alloc_range(struct drm_device *dev, int len, const char *name, int backed, u32 align); diff --git a/drivers/gpu/drm/gma500/oaktrail_crtc.c b/drivers/gpu/drm/gma500/oaktrail_crtc.c index 0fff269d3fe68..1b7fd6a9d8a51 100644 --- a/drivers/gpu/drm/gma500/oaktrail_crtc.c +++ b/drivers/gpu/drm/gma500/oaktrail_crtc.c @@ -600,7 +600,6 @@ static int oaktrail_pipe_set_base(struct drm_crtc *crtc, struct drm_psb_private *dev_priv = dev->dev_private; struct gma_crtc *gma_crtc = to_gma_crtc(crtc); struct drm_framebuffer *fb = crtc->primary->fb; - struct psb_framebuffer *psbfb = to_psb_fb(fb); int pipe = gma_crtc->pipe; const struct psb_offset *map = &dev_priv->regmap[pipe]; unsigned long start, offset; @@ -617,7 +616,7 @@ static int oaktrail_pipe_set_base(struct drm_crtc *crtc, if (!gma_power_begin(dev, true)) return 0; - start = psbfb->gtt->offset; + start = to_gtt_range(fb->obj[0])->offset; offset = y * fb->pitches[0] + x * fb->format->cpp[0]; REG_WRITE(map->stride, fb->pitches[0]); -- GitLab From 080205096579a07fa1b18fcd28ff4d41c3c6e4d7 Mon Sep 17 00:00:00 2001 From: Daniel Stone <daniels@collabora.com> Date: Fri, 30 Mar 2018 15:11:35 +0100 Subject: [PATCH 0051/1506] drm/msm: Move GEM BOs to drm_framebuffer Since drm_framebuffer can now store GEM objects directly, place them there rather than in our own subclass. As this makes the framebuffer create_handle function the same as the GEM framebuffer helper, we can reuse that. Signed-off-by: Daniel Stone <daniels@collabora.com> Reviewed-by: Thierry Reding <treding@nvidia.com> Cc: Rob Clark <robdclark@gmail.com> Cc: linux-arm-msm@vger.kernel.org Link: https://patchwork.freedesktop.org/patch/msgid/20180330141138.28987-21-daniels@collabora.com --- drivers/gpu/drm/msm/msm_fb.c | 54 ++++++++---------------------------- 1 file changed, 11 insertions(+), 43 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_fb.c b/drivers/gpu/drm/msm/msm_fb.c index 7a16242bf8bf2..2a7348aeb38d1 100644 --- a/drivers/gpu/drm/msm/msm_fb.c +++ b/drivers/gpu/drm/msm/msm_fb.c @@ -17,6 +17,7 @@ #include <drm/drm_crtc.h> #include <drm/drm_crtc_helper.h> +#include <drm/drm_gem_framebuffer_helper.h> #include "msm_drv.h" #include "msm_kms.h" @@ -25,49 +26,20 @@ struct msm_framebuffer { struct drm_framebuffer base; const struct msm_format *format; - struct drm_gem_object *planes[MAX_PLANE]; }; #define to_msm_framebuffer(x) container_of(x, struct msm_framebuffer, base) static struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos); -static int msm_framebuffer_create_handle(struct drm_framebuffer *fb, - struct drm_file *file_priv, - unsigned int *handle) -{ - struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb); - return drm_gem_handle_create(file_priv, - msm_fb->planes[0], handle); -} - -static void msm_framebuffer_destroy(struct drm_framebuffer *fb) -{ - struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb); - int i, n = fb->format->num_planes; - - DBG("destroy: FB ID: %d (%p)", fb->base.id, fb); - - drm_framebuffer_cleanup(fb); - - for (i = 0; i < n; i++) { - struct drm_gem_object *bo = msm_fb->planes[i]; - - drm_gem_object_put_unlocked(bo); - } - - kfree(msm_fb); -} - static const struct drm_framebuffer_funcs msm_framebuffer_funcs = { - .create_handle = msm_framebuffer_create_handle, - .destroy = msm_framebuffer_destroy, + .create_handle = drm_gem_fb_create_handle, + .destroy = drm_gem_fb_destroy, }; #ifdef CONFIG_DEBUG_FS void msm_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m) { - struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb); int i, n = fb->format->num_planes; seq_printf(m, "fb: %dx%d@%4.4s (%2d, ID:%d)\n", @@ -77,7 +49,7 @@ void msm_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m) for (i = 0; i < n; i++) { seq_printf(m, " %d: offset=%d pitch=%d, obj: ", i, fb->offsets[i], fb->pitches[i]); - msm_gem_describe(msm_fb->planes[i], m); + msm_gem_describe(fb->obj[i], m); } } #endif @@ -90,12 +62,11 @@ void msm_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m) int msm_framebuffer_prepare(struct drm_framebuffer *fb, struct msm_gem_address_space *aspace) { - struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb); int ret, i, n = fb->format->num_planes; uint64_t iova; for (i = 0; i < n; i++) { - ret = msm_gem_get_iova(msm_fb->planes[i], aspace, &iova); + ret = msm_gem_get_iova(fb->obj[i], aspace, &iova); DBG("FB[%u]: iova[%d]: %08llx (%d)", fb->base.id, i, iova, ret); if (ret) return ret; @@ -107,26 +78,23 @@ int msm_framebuffer_prepare(struct drm_framebuffer *fb, void msm_framebuffer_cleanup(struct drm_framebuffer *fb, struct msm_gem_address_space *aspace) { - struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb); int i, n = fb->format->num_planes; for (i = 0; i < n; i++) - msm_gem_put_iova(msm_fb->planes[i], aspace); + msm_gem_put_iova(fb->obj[i], aspace); } uint32_t msm_framebuffer_iova(struct drm_framebuffer *fb, struct msm_gem_address_space *aspace, int plane) { - struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb); - if (!msm_fb->planes[plane]) + if (!fb->obj[plane]) return 0; - return msm_gem_iova(msm_fb->planes[plane], aspace) + fb->offsets[plane]; + return msm_gem_iova(fb->obj[plane], aspace) + fb->offsets[plane]; } struct drm_gem_object *msm_framebuffer_bo(struct drm_framebuffer *fb, int plane) { - struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb); - return msm_fb->planes[plane]; + return drm_gem_fb_get_obj(fb, plane); } const struct msm_format *msm_framebuffer_format(struct drm_framebuffer *fb) @@ -202,7 +170,7 @@ static struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev, msm_fb->format = format; - if (n > ARRAY_SIZE(msm_fb->planes)) { + if (n > ARRAY_SIZE(fb->obj)) { ret = -EINVAL; goto fail; } @@ -221,7 +189,7 @@ static struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev, goto fail; } - msm_fb->planes[i] = bos[i]; + msm_fb->base.obj[i] = bos[i]; } drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd); -- GitLab From 7f7105f99b75aca4f8c2a748ed6b82c7f8be3293 Mon Sep 17 00:00:00 2001 From: Ondrej Zary <linux@rainbow-software.org> Date: Fri, 9 Mar 2018 23:22:04 +0100 Subject: [PATCH 0052/1506] drm/i915: Disable LVDS on Radiant P845 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Radiant P845 does not have LVDS, only VGA. Cc: stable@vger.kernel.org Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=105468 Signed-off-by: Ondrej Zary <linux@rainbow-software.org> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180309222204.4771-1-linux@rainbow-software.org --- drivers/gpu/drm/i915/intel_lvds.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index cc4cc8669af37..907d0bf853efe 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -825,6 +825,14 @@ static const struct dmi_system_id intel_no_lvds[] = { DMI_EXACT_MATCH(DMI_BOARD_NAME, "D525MW"), }, }, + { + .callback = intel_no_lvds_dmi_callback, + .ident = "Radiant P845", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Radiant Systems Inc"), + DMI_MATCH(DMI_PRODUCT_NAME, "P845"), + }, + }, { } /* terminating entry */ }; -- GitLab From a393e9649582894078130f5741877bbafa0bd8a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Thu, 17 May 2018 20:03:05 +0300 Subject: [PATCH 0053/1506] drm/i915: Use intel_ddi_dp_voltage_max() for HSW/BDW too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use intel_ddi_dp_voltage_max() for HSW/BDW too instead of letting these fall through the if ladder in a weird way. This function will look at the actual buf trans tables we have for HSW/BDW to determine the max vswing level. It looks to me like the current code leads HSW port A down the IVB port A path, HSW port B+ and BDW fall through to the very end. Both cases do result in the correct max vswing level 2, but it's very hard to see that from the code. Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180517170309.28630-1-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula <jani.nikula@intel.com> --- drivers/gpu/drm/i915/intel_dp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 2cc58596ff5ab..4755bb1b0b404 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -3220,12 +3220,12 @@ uint8_t intel_dp_voltage_max(struct intel_dp *intel_dp) { struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); - enum port port = dp_to_dig_port(intel_dp)->base.port; + struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; + enum port port = encoder->port; - if (INTEL_GEN(dev_priv) >= 9) { - struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; + if (HAS_DDI(dev_priv)) return intel_ddi_dp_voltage_max(encoder); - } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) + else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) return DP_TRAIN_VOLTAGE_SWING_LEVEL_3; else if (IS_GEN7(dev_priv) && port == PORT_A) return DP_TRAIN_VOLTAGE_SWING_LEVEL_2; -- GitLab From 4718a365cf12094ed131089518003ac7ecb66743 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Thu, 17 May 2018 20:03:06 +0300 Subject: [PATCH 0054/1506] drm/i915: Use the same vswing->max_preemph mapping on HSW/BDW as on SKL+ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All DDI platforms support the full set of preemph settings for each supported vswing, so let's use the same code for them. We'll also move the code into intel_ddi.c so that it sits closer to the actual buf trans tables. Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180517170309.28630-2-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula <jani.nikula@intel.com> --- drivers/gpu/drm/i915/intel_ddi.c | 20 ++++++++++++++++++++ drivers/gpu/drm/i915/intel_dp.c | 30 ++++-------------------------- drivers/gpu/drm/i915/intel_drv.h | 2 ++ 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index b98ac0541f190..1665bc588241c 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -2115,6 +2115,26 @@ u8 intel_ddi_dp_voltage_max(struct intel_encoder *encoder) DP_TRAIN_VOLTAGE_SWING_MASK; } +/* + * We assume that the full set of pre-emphasis values can be + * used on all DDI platforms. Should that change we need to + * rethink this code. + */ +u8 intel_ddi_dp_pre_emphasis_max(struct intel_encoder *encoder, u8 voltage_swing) +{ + switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) { + case DP_TRAIN_VOLTAGE_SWING_LEVEL_0: + return DP_TRAIN_PRE_EMPH_LEVEL_3; + case DP_TRAIN_VOLTAGE_SWING_LEVEL_1: + return DP_TRAIN_PRE_EMPH_LEVEL_2; + case DP_TRAIN_VOLTAGE_SWING_LEVEL_2: + return DP_TRAIN_PRE_EMPH_LEVEL_1; + case DP_TRAIN_VOLTAGE_SWING_LEVEL_3: + default: + return DP_TRAIN_PRE_EMPH_LEVEL_0; + } +} + static void cnl_ddi_vswing_program(struct intel_encoder *encoder, int level, enum intel_output_type type) { diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 4755bb1b0b404..538b10084a9d6 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -3239,33 +3239,11 @@ uint8_t intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t voltage_swing) { struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); - enum port port = dp_to_dig_port(intel_dp)->base.port; + struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; + enum port port = encoder->port; - if (INTEL_GEN(dev_priv) >= 9) { - switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) { - case DP_TRAIN_VOLTAGE_SWING_LEVEL_0: - return DP_TRAIN_PRE_EMPH_LEVEL_3; - case DP_TRAIN_VOLTAGE_SWING_LEVEL_1: - return DP_TRAIN_PRE_EMPH_LEVEL_2; - case DP_TRAIN_VOLTAGE_SWING_LEVEL_2: - return DP_TRAIN_PRE_EMPH_LEVEL_1; - case DP_TRAIN_VOLTAGE_SWING_LEVEL_3: - return DP_TRAIN_PRE_EMPH_LEVEL_0; - default: - return DP_TRAIN_PRE_EMPH_LEVEL_0; - } - } else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) { - switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) { - case DP_TRAIN_VOLTAGE_SWING_LEVEL_0: - return DP_TRAIN_PRE_EMPH_LEVEL_3; - case DP_TRAIN_VOLTAGE_SWING_LEVEL_1: - return DP_TRAIN_PRE_EMPH_LEVEL_2; - case DP_TRAIN_VOLTAGE_SWING_LEVEL_2: - return DP_TRAIN_PRE_EMPH_LEVEL_1; - case DP_TRAIN_VOLTAGE_SWING_LEVEL_3: - default: - return DP_TRAIN_PRE_EMPH_LEVEL_0; - } + if (HAS_DDI(dev_priv)) { + return intel_ddi_dp_pre_emphasis_max(encoder, voltage_swing); } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) { case DP_TRAIN_VOLTAGE_SWING_LEVEL_0: diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 12002fc77235a..22af249393a48 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1410,6 +1410,8 @@ void intel_ddi_compute_min_voltage_level(struct drm_i915_private *dev_priv, u32 bxt_signal_levels(struct intel_dp *intel_dp); uint32_t ddi_signal_levels(struct intel_dp *intel_dp); u8 intel_ddi_dp_voltage_max(struct intel_encoder *encoder); +u8 intel_ddi_dp_pre_emphasis_max(struct intel_encoder *encoder, + u8 voltage_swing); int intel_ddi_toggle_hdcp_signalling(struct intel_encoder *intel_encoder, bool enable); void icl_map_plls_to_ports(struct drm_crtc *crtc, -- GitLab From b752e995829e3644015300103a31c48de2634169 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Thu, 17 May 2018 20:03:07 +0300 Subject: [PATCH 0055/1506] drm/i915: Check for IVB instead of gen7 when we think about IVB CPU eDP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Almost all of the GEN7 checks in the DP code are actually looking for IVB. HSW doesn't even take these codepaths, and VLV is excluded on account of not having port A. So let's change the checks to IS_IVB to make the code less confusing. Reviewed-by: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180517170309.28630-3-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/intel_dp.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 538b10084a9d6..263e4b1d1db9b 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1989,7 +1989,7 @@ static void intel_dp_prepare(struct intel_encoder *encoder, /* Split out the IBX/CPU vs CPT settings */ - if (IS_GEN7(dev_priv) && port == PORT_A) { + if (IS_IVYBRIDGE(dev_priv) && port == PORT_A) { if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) intel_dp->DP |= DP_SYNC_HS_HIGH; if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) @@ -2669,7 +2669,7 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder, if (!(tmp & DP_PORT_EN)) goto out; - if (IS_GEN7(dev_priv) && port == PORT_A) { + if (IS_IVYBRIDGE(dev_priv) && port == PORT_A) { *pipe = PORT_TO_PIPE_CPT(tmp); } else if (HAS_PCH_CPT(dev_priv) && port != PORT_A) { enum pipe p; @@ -2908,7 +2908,7 @@ _intel_dp_set_link_train(struct intel_dp *intel_dp, } I915_WRITE(DP_TP_CTL(port), temp); - } else if ((IS_GEN7(dev_priv) && port == PORT_A) || + } else if ((IS_IVYBRIDGE(dev_priv) && port == PORT_A) || (HAS_PCH_CPT(dev_priv) && port != PORT_A)) { *DP &= ~DP_LINK_TRAIN_MASK_CPT; @@ -3227,7 +3227,7 @@ intel_dp_voltage_max(struct intel_dp *intel_dp) return intel_ddi_dp_voltage_max(encoder); else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) return DP_TRAIN_VOLTAGE_SWING_LEVEL_3; - else if (IS_GEN7(dev_priv) && port == PORT_A) + else if (IS_IVYBRIDGE(dev_priv) && port == PORT_A) return DP_TRAIN_VOLTAGE_SWING_LEVEL_2; else if (HAS_PCH_CPT(dev_priv) && port != PORT_A) return DP_TRAIN_VOLTAGE_SWING_LEVEL_3; @@ -3256,7 +3256,7 @@ intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t voltage_swing) default: return DP_TRAIN_PRE_EMPH_LEVEL_0; } - } else if (IS_GEN7(dev_priv) && port == PORT_A) { + } else if (IS_IVYBRIDGE(dev_priv) && port == PORT_A) { switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) { case DP_TRAIN_VOLTAGE_SWING_LEVEL_0: return DP_TRAIN_PRE_EMPH_LEVEL_2; @@ -3565,7 +3565,7 @@ intel_dp_set_signal_levels(struct intel_dp *intel_dp) signal_levels = chv_signal_levels(intel_dp); } else if (IS_VALLEYVIEW(dev_priv)) { signal_levels = vlv_signal_levels(intel_dp); - } else if (IS_GEN7(dev_priv) && port == PORT_A) { + } else if (IS_IVYBRIDGE(dev_priv) && port == PORT_A) { signal_levels = gen7_edp_signal_levels(train_set); mask = EDP_LINK_TRAIN_VOL_EMP_MASK_IVB; } else if (IS_GEN6(dev_priv) && port == PORT_A) { @@ -3655,7 +3655,7 @@ intel_dp_link_down(struct intel_encoder *encoder, DRM_DEBUG_KMS("\n"); - if ((IS_GEN7(dev_priv) && port == PORT_A) || + if ((IS_IVYBRIDGE(dev_priv) && port == PORT_A) || (HAS_PCH_CPT(dev_priv) && port != PORT_A)) { DP &= ~DP_LINK_TRAIN_MASK_CPT; DP |= DP_LINK_TRAIN_PAT_IDLE_CPT; -- GitLab From 4d82c2b5f09f5b09ac55e557c0436eb4b29c07fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Thu, 17 May 2018 20:03:08 +0300 Subject: [PATCH 0056/1506] drm/i915: Rename SNB/IVB CPU eDP signal level funcs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To make the intent more clear, let's rename the signal level funcs for the SNB/IVB CPU eDP. Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180517170309.28630-4-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula <jani.nikula@intel.com> --- drivers/gpu/drm/i915/intel_dp.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 263e4b1d1db9b..cd4c60bfc4c2f 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -3488,9 +3488,9 @@ gen4_signal_levels(uint8_t train_set) return signal_levels; } -/* Gen6's DP voltage swing and pre-emphasis control */ +/* SNB CPU eDP voltage swing and pre-emphasis control */ static uint32_t -gen6_edp_signal_levels(uint8_t train_set) +snb_cpu_edp_signal_levels(uint8_t train_set) { int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK | DP_TRAIN_PRE_EMPHASIS_MASK); @@ -3516,9 +3516,9 @@ gen6_edp_signal_levels(uint8_t train_set) } } -/* Gen7's DP voltage swing and pre-emphasis control */ +/* IVB CPU eDP voltage swing and pre-emphasis control */ static uint32_t -gen7_edp_signal_levels(uint8_t train_set) +ivb_cpu_edp_signal_levels(uint8_t train_set) { int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK | DP_TRAIN_PRE_EMPHASIS_MASK); @@ -3566,10 +3566,10 @@ intel_dp_set_signal_levels(struct intel_dp *intel_dp) } else if (IS_VALLEYVIEW(dev_priv)) { signal_levels = vlv_signal_levels(intel_dp); } else if (IS_IVYBRIDGE(dev_priv) && port == PORT_A) { - signal_levels = gen7_edp_signal_levels(train_set); + signal_levels = ivb_cpu_edp_signal_levels(train_set); mask = EDP_LINK_TRAIN_VOL_EMP_MASK_IVB; } else if (IS_GEN6(dev_priv) && port == PORT_A) { - signal_levels = gen6_edp_signal_levels(train_set); + signal_levels = snb_cpu_edp_signal_levels(train_set); mask = EDP_LINK_TRAIN_VOL_EMP_MASK_SNB; } else { signal_levels = gen4_signal_levels(train_set); -- GitLab From 45101e939ea34c3f0794175845eb946e839e7873 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Thu, 17 May 2018 20:03:09 +0300 Subject: [PATCH 0057/1506] drm/i915: Rename the remaining gen4 references to g4x in the DP code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit i965 does not have native DP. Let's rename the remaining gen4 references in the DP code to g4x. Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180517170309.28630-5-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula <jani.nikula@intel.com> --- drivers/gpu/drm/i915/intel_dp.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index cd4c60bfc4c2f..1020709400954 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -56,7 +56,7 @@ struct dp_link_dpll { struct dpll dpll; }; -static const struct dp_link_dpll gen4_dpll[] = { +static const struct dp_link_dpll g4x_dpll[] = { { 162000, { .p1 = 2, .p2 = 10, .n = 2, .m1 = 23, .m2 = 8 } }, { 270000, @@ -1550,8 +1550,8 @@ intel_dp_set_clock(struct intel_encoder *encoder, int i, count = 0; if (IS_G4X(dev_priv)) { - divisor = gen4_dpll; - count = ARRAY_SIZE(gen4_dpll); + divisor = g4x_dpll; + count = ARRAY_SIZE(g4x_dpll); } else if (HAS_PCH_SPLIT(dev_priv)) { divisor = pch_dpll; count = ARRAY_SIZE(pch_dpll); @@ -3451,7 +3451,7 @@ static uint32_t chv_signal_levels(struct intel_dp *intel_dp) } static uint32_t -gen4_signal_levels(uint8_t train_set) +g4x_signal_levels(uint8_t train_set) { uint32_t signal_levels = 0; @@ -3572,7 +3572,7 @@ intel_dp_set_signal_levels(struct intel_dp *intel_dp) signal_levels = snb_cpu_edp_signal_levels(train_set); mask = EDP_LINK_TRAIN_VOL_EMP_MASK_SNB; } else { - signal_levels = gen4_signal_levels(train_set); + signal_levels = g4x_signal_levels(train_set); mask = DP_VOLTAGE_MASK | DP_PRE_EMPHASIS_MASK; } -- GitLab From c734f496770801f97ae1a59607634b972b002cdf Mon Sep 17 00:00:00 2001 From: Daniel Stone <daniels@collabora.com> Date: Fri, 18 May 2018 14:47:03 +0100 Subject: [PATCH 0058/1506] drm/mtk: Remove impossible internal error We cannot create a framebuffer with no objects, so there's no point testing for it. v2: Remove the error entirely. (Sean, CK, Thierry) Signed-off-by: Daniel Stone <daniels@collabora.com> Acked-by: Thierry Reding <treding@nvidia.com> Cc: Sean Paul <seanpaul@chromium.org> Cc: CK Hu <ck.hu@mediatek.com> Cc: Philipp Zabel <p.zabel@pengutronix.de> Link: https://patchwork.freedesktop.org/patch/msgid/20180518134705.12533-1-daniels@collabora.com --- drivers/gpu/drm/mediatek/mtk_drm_plane.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.c b/drivers/gpu/drm/mediatek/mtk_drm_plane.c index 2f4b0ffee5989..149fc4372917b 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_plane.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.c @@ -95,11 +95,6 @@ static int mtk_plane_atomic_check(struct drm_plane *plane, if (!fb) return 0; - if (!mtk_fb_get_gem_obj(fb)) { - DRM_DEBUG_KMS("buffer is null\n"); - return -EFAULT; - } - if (!state->crtc) return 0; -- GitLab From 81a073d14c7a46f6e7282a5ffc24f112ac5429ed Mon Sep 17 00:00:00 2001 From: Daniel Stone <daniels@collabora.com> Date: Fri, 18 May 2018 14:47:04 +0100 Subject: [PATCH 0059/1506] drm/mtk: Move GEM BO to drm_framebuffer Since drm_framebuffer can now store GEM objects directly, place them there rather than in our own subclass. As this makes the framebuffer create_handle and destroy functions the same as the GEM framebuffer helper, we can reuse those. Signed-off-by: Daniel Stone <daniels@collabora.com> Reviewed-by: CK Hu <ck.hu@mediatek.com> Reviewed-by: Thierry Reding <treding@nvidia.com> Reviewed-by: Sean Paul <seanpaul@chromium.org> Cc: Philipp Zabel <p.zabel@pengutronix.de> Link: https://patchwork.freedesktop.org/patch/msgid/20180518134705.12533-2-daniels@collabora.com --- drivers/gpu/drm/mediatek/mtk_drm_fb.c | 38 ++++-------------------- drivers/gpu/drm/mediatek/mtk_drm_fb.h | 1 - drivers/gpu/drm/mediatek/mtk_drm_plane.c | 2 +- 3 files changed, 6 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_fb.c b/drivers/gpu/drm/mediatek/mtk_drm_fb.c index 0d8d506695f9f..f130e37123b5d 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_fb.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_fb.c @@ -15,6 +15,7 @@ #include <drm/drm_crtc_helper.h> #include <drm/drm_fb_helper.h> #include <drm/drm_gem.h> +#include <drm/drm_gem_framebuffer_helper.h> #include <linux/dma-buf.h> #include <linux/reservation.h> @@ -30,42 +31,13 @@ */ struct mtk_drm_fb { struct drm_framebuffer base; - /* For now we only support a single plane */ - struct drm_gem_object *gem_obj; }; #define to_mtk_fb(x) container_of(x, struct mtk_drm_fb, base) -struct drm_gem_object *mtk_fb_get_gem_obj(struct drm_framebuffer *fb) -{ - struct mtk_drm_fb *mtk_fb = to_mtk_fb(fb); - - return mtk_fb->gem_obj; -} - -static int mtk_drm_fb_create_handle(struct drm_framebuffer *fb, - struct drm_file *file_priv, - unsigned int *handle) -{ - struct mtk_drm_fb *mtk_fb = to_mtk_fb(fb); - - return drm_gem_handle_create(file_priv, mtk_fb->gem_obj, handle); -} - -static void mtk_drm_fb_destroy(struct drm_framebuffer *fb) -{ - struct mtk_drm_fb *mtk_fb = to_mtk_fb(fb); - - drm_framebuffer_cleanup(fb); - - drm_gem_object_put_unlocked(mtk_fb->gem_obj); - - kfree(mtk_fb); -} - static const struct drm_framebuffer_funcs mtk_drm_fb_funcs = { - .create_handle = mtk_drm_fb_create_handle, - .destroy = mtk_drm_fb_destroy, + .create_handle = drm_gem_fb_create_handle, + .destroy = drm_gem_fb_destroy, }; static struct mtk_drm_fb *mtk_drm_framebuffer_init(struct drm_device *dev, @@ -84,7 +56,7 @@ static struct mtk_drm_fb *mtk_drm_framebuffer_init(struct drm_device *dev, drm_helper_mode_fill_fb_struct(dev, &mtk_fb->base, mode); - mtk_fb->gem_obj = obj; + mtk_fb->base.obj[0] = obj; ret = drm_framebuffer_init(dev, &mtk_fb->base, &mtk_drm_fb_funcs); if (ret) { @@ -110,7 +82,7 @@ int mtk_fb_wait(struct drm_framebuffer *fb) if (!fb) return 0; - gem = mtk_fb_get_gem_obj(fb); + gem = fb->obj[0]; if (!gem || !gem->dma_buf || !gem->dma_buf->resv) return 0; diff --git a/drivers/gpu/drm/mediatek/mtk_drm_fb.h b/drivers/gpu/drm/mediatek/mtk_drm_fb.h index 9b2ae345a4e90..7f976b196a154 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_fb.h +++ b/drivers/gpu/drm/mediatek/mtk_drm_fb.h @@ -14,7 +14,6 @@ #ifndef MTK_DRM_FB_H #define MTK_DRM_FB_H -struct drm_gem_object *mtk_fb_get_gem_obj(struct drm_framebuffer *fb); int mtk_fb_wait(struct drm_framebuffer *fb); struct drm_framebuffer *mtk_drm_mode_fb_create(struct drm_device *dev, struct drm_file *file, diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.c b/drivers/gpu/drm/mediatek/mtk_drm_plane.c index 149fc4372917b..f7e6aa1b5b7d1 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_plane.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.c @@ -122,7 +122,7 @@ static void mtk_plane_atomic_update(struct drm_plane *plane, if (!crtc || WARN_ON(!fb)) return; - gem = mtk_fb_get_gem_obj(fb); + gem = fb->obj[0]; mtk_gem = to_mtk_gem_obj(gem); addr = mtk_gem->dma_addr; pitch = fb->pitches[0]; -- GitLab From 6a3e913cb8d5fb792782beb8766c0b81e8bfe1ac Mon Sep 17 00:00:00 2001 From: Daniel Stone <daniels@collabora.com> Date: Fri, 18 May 2018 14:47:05 +0100 Subject: [PATCH 0060/1506] drm/mtk: mtk_drm_fb -> drm_framebuffer Now that mtk_drm_fb is an empty wrapper around drm_framebuffer, we can just delete it. Signed-off-by: Daniel Stone <daniels@collabora.com> Reviewed-by: CK Hu <ck.hu@mediatek.com> Reviewed-by: Thierry Reding <treding@nvidia.com> Reviewed-by: Sean Paul <seanpaul@chromium.org> Cc: Philipp Zabel <p.zabel@pengutronix.de> Link: https://patchwork.freedesktop.org/patch/msgid/20180518134705.12533-3-daniels@collabora.com --- drivers/gpu/drm/mediatek/mtk_drm_fb.c | 40 ++++++++++----------------- 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_fb.c b/drivers/gpu/drm/mediatek/mtk_drm_fb.c index f130e37123b5d..be5f6f1daf554 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_fb.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_fb.c @@ -23,49 +23,37 @@ #include "mtk_drm_fb.h" #include "mtk_drm_gem.h" -/* - * mtk specific framebuffer structure. - * - * @fb: drm framebuffer object. - * @gem_obj: array of gem objects. - */ -struct mtk_drm_fb { - struct drm_framebuffer base; -}; - -#define to_mtk_fb(x) container_of(x, struct mtk_drm_fb, base) - static const struct drm_framebuffer_funcs mtk_drm_fb_funcs = { .create_handle = drm_gem_fb_create_handle, .destroy = drm_gem_fb_destroy, }; -static struct mtk_drm_fb *mtk_drm_framebuffer_init(struct drm_device *dev, +static struct drm_framebuffer *mtk_drm_framebuffer_init(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode, struct drm_gem_object *obj) { - struct mtk_drm_fb *mtk_fb; + struct drm_framebuffer *fb; int ret; if (drm_format_num_planes(mode->pixel_format) != 1) return ERR_PTR(-EINVAL); - mtk_fb = kzalloc(sizeof(*mtk_fb), GFP_KERNEL); - if (!mtk_fb) + fb = kzalloc(sizeof(*fb), GFP_KERNEL); + if (!fb) return ERR_PTR(-ENOMEM); - drm_helper_mode_fill_fb_struct(dev, &mtk_fb->base, mode); + drm_helper_mode_fill_fb_struct(dev, fb, mode); - mtk_fb->base.obj[0] = obj; + fb->obj[0] = obj; - ret = drm_framebuffer_init(dev, &mtk_fb->base, &mtk_drm_fb_funcs); + ret = drm_framebuffer_init(dev, fb, &mtk_drm_fb_funcs); if (ret) { DRM_ERROR("failed to initialize framebuffer\n"); - kfree(mtk_fb); + kfree(fb); return ERR_PTR(ret); } - return mtk_fb; + return fb; } /* @@ -100,7 +88,7 @@ struct drm_framebuffer *mtk_drm_mode_fb_create(struct drm_device *dev, struct drm_file *file, const struct drm_mode_fb_cmd2 *cmd) { - struct mtk_drm_fb *mtk_fb; + struct drm_framebuffer *fb; struct drm_gem_object *gem; unsigned int width = cmd->width; unsigned int height = cmd->height; @@ -123,13 +111,13 @@ struct drm_framebuffer *mtk_drm_mode_fb_create(struct drm_device *dev, goto unreference; } - mtk_fb = mtk_drm_framebuffer_init(dev, cmd, gem); - if (IS_ERR(mtk_fb)) { - ret = PTR_ERR(mtk_fb); + fb = mtk_drm_framebuffer_init(dev, cmd, gem); + if (IS_ERR(fb)) { + ret = PTR_ERR(fb); goto unreference; } - return &mtk_fb->base; + return fb; unreference: drm_gem_object_put_unlocked(gem); -- GitLab From 4c7c9a63f215da5576460b3a526e23d564de1360 Mon Sep 17 00:00:00 2001 From: Daniel Stone <daniels@collabora.com> Date: Fri, 30 Mar 2018 15:11:18 +0100 Subject: [PATCH 0061/1506] drm/rockchip: Place GEM BOs in drm_framebuffer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since drm_framebuffer can now store GEM objects directly, place them there rather than in our own subclass. As this makes the framebuffer create_handle and destroy functions the same as the GEM framebuffer helper, we can reuse those. Signed-off-by: Daniel Stone <daniels@collabora.com> Reviewed-by: Thierry Reding <treding@nvidia.com> Reviewed-by: Sean Paul <seanpaul@chromium.org> Acked-by: Heiko Stübner <heiko@sntech.de> Tested-by: Heiko Stübner <heiko@sntech.de> Cc: Sandy Huang <hjc@rock-chips.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180330141138.28987-4-daniels@collabora.com --- drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 36 ++++------------------ 1 file changed, 6 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c index d4f4118b482dd..d1820d09075e7 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c @@ -18,6 +18,7 @@ #include <drm/drm_atomic.h> #include <drm/drm_fb_helper.h> #include <drm/drm_crtc_helper.h> +#include <drm/drm_gem_framebuffer_helper.h> #include "rockchip_drm_drv.h" #include "rockchip_drm_fb.h" @@ -28,40 +29,15 @@ struct rockchip_drm_fb { struct drm_framebuffer fb; - struct drm_gem_object *obj[ROCKCHIP_MAX_FB_BUFFER]; }; struct drm_gem_object *rockchip_fb_get_gem_obj(struct drm_framebuffer *fb, unsigned int plane) { - struct rockchip_drm_fb *rk_fb = to_rockchip_fb(fb); - if (plane >= ROCKCHIP_MAX_FB_BUFFER) return NULL; - return rk_fb->obj[plane]; -} - -static void rockchip_drm_fb_destroy(struct drm_framebuffer *fb) -{ - struct rockchip_drm_fb *rockchip_fb = to_rockchip_fb(fb); - int i; - - for (i = 0; i < ROCKCHIP_MAX_FB_BUFFER; i++) - drm_gem_object_put_unlocked(rockchip_fb->obj[i]); - - drm_framebuffer_cleanup(fb); - kfree(rockchip_fb); -} - -static int rockchip_drm_fb_create_handle(struct drm_framebuffer *fb, - struct drm_file *file_priv, - unsigned int *handle) -{ - struct rockchip_drm_fb *rockchip_fb = to_rockchip_fb(fb); - - return drm_gem_handle_create(file_priv, - rockchip_fb->obj[0], handle); + return fb->obj[plane]; } static int rockchip_drm_fb_dirty(struct drm_framebuffer *fb, @@ -75,9 +51,9 @@ static int rockchip_drm_fb_dirty(struct drm_framebuffer *fb, } static const struct drm_framebuffer_funcs rockchip_drm_fb_funcs = { - .destroy = rockchip_drm_fb_destroy, - .create_handle = rockchip_drm_fb_create_handle, - .dirty = rockchip_drm_fb_dirty, + .destroy = drm_gem_fb_destroy, + .create_handle = drm_gem_fb_create_handle, + .dirty = rockchip_drm_fb_dirty, }; static struct rockchip_drm_fb * @@ -95,7 +71,7 @@ rockchip_fb_alloc(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cm drm_helper_mode_fill_fb_struct(dev, &rockchip_fb->fb, mode_cmd); for (i = 0; i < num_planes; i++) - rockchip_fb->obj[i] = obj[i]; + rockchip_fb->fb.obj[i] = obj[i]; ret = drm_framebuffer_init(dev, &rockchip_fb->fb, &rockchip_drm_fb_funcs); -- GitLab From 957428f9935ac6f41443431f61478023261c8d36 Mon Sep 17 00:00:00 2001 From: Daniel Stone <daniels@collabora.com> Date: Fri, 30 Mar 2018 15:11:19 +0100 Subject: [PATCH 0062/1506] drm/rockchip: rockchip_drm_fb -> drm_framebuffer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that rockchip_drm_fb is just a wrapper around drm_framebuffer, we can remove it. Signed-off-by: Daniel Stone <daniels@collabora.com> Reviewed-by: Thierry Reding <treding@nvidia.com> Reviewed-by: Sean Paul <seanpaul@chromium.org> Acked-by: Heiko Stübner <heiko@sntech.de> Tested-by: Heiko Stübner <heiko@sntech.de> Cc: Sandy Huang <hjc@rock-chips.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180330141138.28987-5-daniels@collabora.com --- drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 54 ++++++++------------- drivers/gpu/drm/rockchip/rockchip_drm_fb.h | 3 -- drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 4 +- 3 files changed, 21 insertions(+), 40 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c index d1820d09075e7..ea18cb2a76c0d 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c @@ -25,21 +25,6 @@ #include "rockchip_drm_gem.h" #include "rockchip_drm_psr.h" -#define to_rockchip_fb(x) container_of(x, struct rockchip_drm_fb, fb) - -struct rockchip_drm_fb { - struct drm_framebuffer fb; -}; - -struct drm_gem_object *rockchip_fb_get_gem_obj(struct drm_framebuffer *fb, - unsigned int plane) -{ - if (plane >= ROCKCHIP_MAX_FB_BUFFER) - return NULL; - - return fb->obj[plane]; -} - static int rockchip_drm_fb_dirty(struct drm_framebuffer *fb, struct drm_file *file, unsigned int flags, unsigned int color, @@ -56,41 +41,40 @@ static const struct drm_framebuffer_funcs rockchip_drm_fb_funcs = { .dirty = rockchip_drm_fb_dirty, }; -static struct rockchip_drm_fb * +static struct drm_framebuffer * rockchip_fb_alloc(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **obj, unsigned int num_planes) { - struct rockchip_drm_fb *rockchip_fb; + struct drm_framebuffer *fb; int ret; int i; - rockchip_fb = kzalloc(sizeof(*rockchip_fb), GFP_KERNEL); - if (!rockchip_fb) + fb = kzalloc(sizeof(*fb), GFP_KERNEL); + if (!fb) return ERR_PTR(-ENOMEM); - drm_helper_mode_fill_fb_struct(dev, &rockchip_fb->fb, mode_cmd); + drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd); for (i = 0; i < num_planes; i++) - rockchip_fb->fb.obj[i] = obj[i]; + fb->obj[i] = obj[i]; - ret = drm_framebuffer_init(dev, &rockchip_fb->fb, - &rockchip_drm_fb_funcs); + ret = drm_framebuffer_init(dev, fb, &rockchip_drm_fb_funcs); if (ret) { DRM_DEV_ERROR(dev->dev, "Failed to initialize framebuffer: %d\n", ret); - kfree(rockchip_fb); + kfree(fb); return ERR_PTR(ret); } - return rockchip_fb; + return fb; } static struct drm_framebuffer * rockchip_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd) { - struct rockchip_drm_fb *rockchip_fb; + struct drm_framebuffer *fb; struct drm_gem_object *objs[ROCKCHIP_MAX_FB_BUFFER]; struct drm_gem_object *obj; unsigned int hsub; @@ -129,13 +113,13 @@ rockchip_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, objs[i] = obj; } - rockchip_fb = rockchip_fb_alloc(dev, mode_cmd, objs, i); - if (IS_ERR(rockchip_fb)) { - ret = PTR_ERR(rockchip_fb); + fb = rockchip_fb_alloc(dev, mode_cmd, objs, i); + if (IS_ERR(fb)) { + ret = PTR_ERR(fb); goto err_gem_object_unreference; } - return &rockchip_fb->fb; + return fb; err_gem_object_unreference: for (i--; i >= 0; i--) @@ -218,13 +202,13 @@ rockchip_drm_framebuffer_init(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object *obj) { - struct rockchip_drm_fb *rockchip_fb; + struct drm_framebuffer *fb; - rockchip_fb = rockchip_fb_alloc(dev, mode_cmd, &obj, 1); - if (IS_ERR(rockchip_fb)) - return ERR_CAST(rockchip_fb); + fb = rockchip_fb_alloc(dev, mode_cmd, &obj, 1); + if (IS_ERR(fb)) + return ERR_CAST(fb); - return &rockchip_fb->fb; + return fb; } void rockchip_drm_mode_config_init(struct drm_device *dev) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.h b/drivers/gpu/drm/rockchip/rockchip_drm_fb.h index 2fe47f1ee98fe..f1265cb1aee86 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.h @@ -22,7 +22,4 @@ rockchip_drm_framebuffer_init(struct drm_device *dev, void rockchip_drm_framebuffer_fini(struct drm_framebuffer *fb); void rockchip_drm_mode_config_init(struct drm_device *dev); - -struct drm_gem_object *rockchip_fb_get_gem_obj(struct drm_framebuffer *fb, - unsigned int plane); #endif /* _ROCKCHIP_DRM_FB_H */ diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 2121345a61aff..45847d4a2e142 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -728,7 +728,7 @@ static void vop_plane_atomic_update(struct drm_plane *plane, return; } - obj = rockchip_fb_get_gem_obj(fb, 0); + obj = fb->obj[0]; rk_obj = to_rockchip_obj(obj); actual_w = drm_rect_width(src) >> 16; @@ -758,7 +758,7 @@ static void vop_plane_atomic_update(struct drm_plane *plane, int vsub = drm_format_vert_chroma_subsampling(fb->format->format); int bpp = fb->format->cpp[1]; - uv_obj = rockchip_fb_get_gem_obj(fb, 1); + uv_obj = fb->obj[1]; rk_uv_obj = to_rockchip_obj(uv_obj); offset = (src->x1 >> 16) * bpp / hsub; -- GitLab From e578a570dc7c20475774d1ff993825e3bd7a7011 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 18 May 2018 08:48:40 +0100 Subject: [PATCH 0063/1506] drm/i915/lvds: Move acpi lid notification registration to registration phase MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Delay registering ourselves with the acpi lid notification mechanism until we are registering the connectors after initialisation is complete. This prevents a possibility of trying to handle the lid notification before we are ready with the danger of chasing uninitialised function pointers. BUG: unable to handle kernel NULL pointer dereference at 0000000000000000 IP: (null) PGD 0 P4D 0 Oops: 0010 [#1] PREEMPT SMP PTI Modules linked in: arc4(+) iwldvm(+) i915(+) mac80211 i2c_algo_bit coretemp mei_wdt iwlwifi drm_kms_helper kvm_intel wmi_bmof iTCO_wdt iTCO_vendor_support kvm snd_hda_codec_conexant snd_hda_codec_generic drm psmouse cfg80211 irqbypass input_leds pcspkr i2c_i801 snd_hda_intel snd_hda_codec thinkpad_acpi snd_hda_core mei_me lpc_ich snd_hwdep e1000e wmi nvram snd_pcm mei snd_timer shpchp ptp pps_core rfkill syscopyarea snd intel_agp sysfillrect intel_gtt soundcore sysimgblt battery led_class fb_sys_fops ac rtc_cmos agpgart evdev mac_hid acpi_cpufreq ip_tables x_tables ext4 crc32c_generic crc16 mbcache jbd2 fscrypto crypto_simd glue_helper cryptd aes_x86_64 xts algif_skcipher af_alg dm_crypt dm_mod sd_mod uas usb_storage serio_raw atkbd libps2 ahci libahci uhci_hcd libata scsi_mod ehci_pci ehci_hcd usbcore usb_common i8042 serio CPU: 1 PID: 378 Comm: systemd-logind Not tainted 4.16.8-1-ARCH #1 Hardware name: LENOVO 7454CTO/7454CTO, BIOS 6DET72WW (3.22 ) 10/25/2012 RIP: 0010: (null) RSP: 0018:ffffaf4580c33a18 EFLAGS: 00010287 RAX: 0000000000000000 RBX: ffff947533558000 RCX: 000000000000003e RDX: ffffffffc0aa80c0 RSI: ffffaf4580c33a3c RDI: ffff947534e4c000 RBP: ffff947533558338 R08: ffff947534598930 R09: ffffffffc0a928b1 R10: ffffd8f181d5fd40 R11: 0000000000000000 R12: ffffffffc0a928b1 R13: ffff947533558368 R14: ffffffffc0a928a9 R15: ffff947534e4c000 FS: 00007f3dc4ddb940(0000) GS:ffff947539280000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000000 CR3: 000000006e214000 CR4: 00000000000406e0 Call Trace: ? intel_modeset_setup_hw_state+0x385/0xf60 [i915] ? __intel_display_resume+0x1e/0xc0 [i915] ? intel_display_resume+0xcc/0x120 [i915] ? intel_lid_notify+0xbc/0xc0 [i915] ? notifier_call_chain+0x47/0x70 ? blocking_notifier_call_chain+0x3e/0x60 ? acpi_lid_notify_state+0x8f/0x1d0 ? acpi_lid_update_state+0x49/0x70 ? acpi_lid_input_open+0x60/0x90 ? input_open_device+0x5d/0xa0 ? evdev_open+0x1ba/0x1e0 [evdev] ? chrdev_open+0xa3/0x1b0 ? cdev_put.part.0+0x20/0x20 ? do_dentry_open+0x14c/0x300 ? path_openat+0x30c/0x1240 ? current_time+0x16/0x60 ? do_filp_open+0x93/0x100 ? __check_object_size+0xfb/0x180 ? do_sys_open+0x186/0x210 ? do_syscall_64+0x74/0x190 ? entry_SYSCALL_64_after_hwframe+0x3d/0xa2 Code: Bad RIP value. RIP: (null) RSP: ffffaf4580c33a18 CR2: 0000000000000000 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=106559 Fixes: c1c7af608920 ("drm/i915: force mode set at lid open time") Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Reviewed-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180518074840.16194-1-chris@chris-wilson.co.uk Cc: stable@vger.kernel.org --- drivers/gpu/drm/i915/intel_lvds.c | 43 +++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 907d0bf853efe..a92bb63b2f2d4 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -572,6 +572,36 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val, return NOTIFY_OK; } +static int +intel_lvds_connector_register(struct drm_connector *connector) +{ + struct intel_lvds_connector *lvds = to_lvds_connector(connector); + int ret; + + ret = intel_connector_register(connector); + if (ret) + return ret; + + lvds->lid_notifier.notifier_call = intel_lid_notify; + if (acpi_lid_notifier_register(&lvds->lid_notifier)) { + DRM_DEBUG_KMS("lid notifier registration failed\n"); + lvds->lid_notifier.notifier_call = NULL; + } + + return 0; +} + +static void +intel_lvds_connector_unregister(struct drm_connector *connector) +{ + struct intel_lvds_connector *lvds = to_lvds_connector(connector); + + if (lvds->lid_notifier.notifier_call) + acpi_lid_notifier_unregister(&lvds->lid_notifier); + + intel_connector_unregister(connector); +} + /** * intel_lvds_destroy - unregister and free LVDS structures * @connector: connector to free @@ -584,9 +614,6 @@ static void intel_lvds_destroy(struct drm_connector *connector) struct intel_lvds_connector *lvds_connector = to_lvds_connector(connector); - if (lvds_connector->lid_notifier.notifier_call) - acpi_lid_notifier_unregister(&lvds_connector->lid_notifier); - if (!IS_ERR_OR_NULL(lvds_connector->base.edid)) kfree(lvds_connector->base.edid); @@ -607,8 +634,8 @@ static const struct drm_connector_funcs intel_lvds_connector_funcs = { .fill_modes = drm_helper_probe_single_connector_modes, .atomic_get_property = intel_digital_connector_atomic_get_property, .atomic_set_property = intel_digital_connector_atomic_set_property, - .late_register = intel_connector_register, - .early_unregister = intel_connector_unregister, + .late_register = intel_lvds_connector_register, + .early_unregister = intel_lvds_connector_unregister, .destroy = intel_lvds_destroy, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, .atomic_duplicate_state = intel_digital_connector_duplicate_state, @@ -1160,12 +1187,6 @@ void intel_lvds_init(struct drm_i915_private *dev_priv) lvds_encoder->a3_power = lvds & LVDS_A3_POWER_MASK; - lvds_connector->lid_notifier.notifier_call = intel_lid_notify; - if (acpi_lid_notifier_register(&lvds_connector->lid_notifier)) { - DRM_DEBUG_KMS("lid notifier registration failed\n"); - lvds_connector->lid_notifier.notifier_call = NULL; - } - return; failed: -- GitLab From dd0cf235d81f24c1ba80c4a000bafc9f2dce3840 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Sun, 6 May 2018 18:13:28 +0100 Subject: [PATCH 0064/1506] drm/i915: Speed up idle detection by kicking the tasklets We rely on ksoftirqd to run in a timely fashion in order to drain the execlists queue. Quite frequently, it does not. In some cases we may see latencies of over 200ms triggering our idle timeouts and forcing us to declare the driver wedged! Thus we can speed up idle detection by bypassing ksoftirqd in these cases and flush our tasklet to confirm if we are indeed still waiting for the ELSP to drain. v2: Put the execlists.first check back; it is required for handling reset! References: https://bugs.freedesktop.org/show_bug.cgi?id=106373 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180506171328.30034-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_engine_cs.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index 26f9f8aab9493..a2173e66a63b5 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -973,10 +973,19 @@ bool intel_engine_is_idle(struct intel_engine_cs *engine) return true; /* Waiting to drain ELSP? */ - if (READ_ONCE(engine->execlists.active)) - return false; + if (READ_ONCE(engine->execlists.active)) { + struct intel_engine_execlists *execlists = &engine->execlists; + + if (tasklet_trylock(&execlists->tasklet)) { + execlists->tasklet.func(execlists->tasklet.data); + tasklet_unlock(&execlists->tasklet); + } + + if (READ_ONCE(execlists->active)) + return false; + } - /* ELSP is empty, but there are ready requests? */ + /* ELSP is empty, but there are ready requests? E.g. after reset */ if (READ_ONCE(engine->execlists.first)) return false; -- GitLab From d6d12ec081776bdea7e0ad58f2a7e7f92e414e7f Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 18 May 2018 10:02:10 +0100 Subject: [PATCH 0065/1506] drm/i915: Make intel_engine_dump irqsafe To be useful later, enable intel_engine_dump() to be called from irq context (i.e. using saving and restoring irq start rather than assuming we enter with irqs enabled). Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180518090212.5349-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_engine_cs.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index a2173e66a63b5..847797215a732 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -1367,6 +1367,7 @@ void intel_engine_dump(struct intel_engine_cs *engine, const struct intel_engine_execlists * const execlists = &engine->execlists; struct i915_gpu_error * const error = &engine->i915->gpu_error; struct i915_request *rq, *last; + unsigned long flags; struct rb_node *rb; int count; @@ -1433,7 +1434,8 @@ void intel_engine_dump(struct intel_engine_cs *engine, drm_printf(m, "\tDevice is asleep; skipping register dump\n"); } - spin_lock_irq(&engine->timeline.lock); + local_irq_save(flags); + spin_lock(&engine->timeline.lock); last = NULL; count = 0; @@ -1475,16 +1477,17 @@ void intel_engine_dump(struct intel_engine_cs *engine, print_request(m, last, "\t\tQ "); } - spin_unlock_irq(&engine->timeline.lock); + spin_unlock(&engine->timeline.lock); - spin_lock_irq(&b->rb_lock); + spin_lock(&b->rb_lock); for (rb = rb_first(&b->waiters); rb; rb = rb_next(rb)) { struct intel_wait *w = rb_entry(rb, typeof(*w), node); drm_printf(m, "\t%s [%d] waiting for %x\n", w->tsk->comm, w->tsk->pid, w->seqno); } - spin_unlock_irq(&b->rb_lock); + spin_unlock(&b->rb_lock); + local_irq_restore(flags); drm_printf(m, "IRQ? 0x%lx (breadcrumbs? %s) (execlists? %s)\n", engine->irq_posted, -- GitLab From fe0c493538f42ee1cbc4701dc6f9eb2b82d856cf Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 18 May 2018 10:02:11 +0100 Subject: [PATCH 0066/1506] drm/i915/execlists: Handle copying default context state for atomic reset We want to be able to reset the GPU from inside a timer callback (hardirq context). One step requires us to copy the default context state over to the guilty context, which means we need to plan in advance to have that object accessible from within an atomic context. The atomic context prevents us from pinning the object or from peeking into the shmemfs backing store (all may sleep), so we choose to pin the default_state into memory when the engine becomes active. This compromise allows us to swap out the default state when idle, when required. References: 5692251c254a ("drm/i915/lrc: Scrub the GPU state of the guilty hanging request") Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180518090212.5349-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_engine_cs.c | 15 +++++++++++++++ drivers/gpu/drm/i915/intel_lrc.c | 15 ++++----------- drivers/gpu/drm/i915/intel_ringbuffer.h | 1 + 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index 847797215a732..0c1f084ee5936 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -1091,6 +1091,11 @@ void intel_engines_park(struct drm_i915_private *i915) if (engine->park) engine->park(engine); + if (engine->pinned_default_state) { + i915_gem_object_unpin_map(engine->default_state); + engine->pinned_default_state = NULL; + } + i915_gem_batch_pool_fini(&engine->batch_pool); engine->execlists.no_priolist = false; } @@ -1108,6 +1113,16 @@ void intel_engines_unpark(struct drm_i915_private *i915) enum intel_engine_id id; for_each_engine(engine, i915, id) { + void *map; + + /* Pin the default state for fast resets from atomic context. */ + map = NULL; + if (engine->default_state) + map = i915_gem_object_pin_map(engine->default_state, + I915_MAP_WB); + if (!IS_ERR_OR_NULL(map)) + engine->pinned_default_state = map; + if (engine->unpark) engine->unpark(engine); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 9abd26f22b477..46e7bf4a30a97 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1965,17 +1965,10 @@ static void execlists_reset(struct intel_engine_cs *engine, * to recreate its own state. */ regs = request->hw_context->lrc_reg_state; - if (engine->default_state) { - void *defaults; - - defaults = i915_gem_object_pin_map(engine->default_state, - I915_MAP_WB); - if (!IS_ERR(defaults)) { - memcpy(regs, /* skip restoring the vanilla PPHWSP */ - defaults + LRC_STATE_PN * PAGE_SIZE, - engine->context_size - PAGE_SIZE); - i915_gem_object_unpin_map(engine->default_state); - } + if (engine->pinned_default_state) { + memcpy(regs, /* skip restoring the vanilla PPHWSP */ + engine->pinned_default_state + LRC_STATE_PN * PAGE_SIZE, + engine->context_size - PAGE_SIZE); } execlists_init_reg_state(regs, request->gem_context, engine, request->ring); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 20c4e13efc0de..acef385c4c80d 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -342,6 +342,7 @@ struct intel_engine_cs { struct i915_timeline timeline; struct drm_i915_gem_object *default_state; + void *pinned_default_state; atomic_t irq_count; unsigned long irq_posted; -- GitLab From 2399a4a6f5dff645d7890135db1c965592e1b8f3 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 18 May 2018 10:02:12 +0100 Subject: [PATCH 0067/1506] drm/i915: Allow init_breadcrumbs to be used from irq context In order to support engine reset from irq (timer) context, we need to be able to re-initialise the breadcrumbs. So we need to promote the plain spin_lock_irq to a safe spin_lock_irqsave. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180518090212.5349-3-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_breadcrumbs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_breadcrumbs.c b/drivers/gpu/drm/i915/intel_breadcrumbs.c index 18e643df523e5..86a987b8ac667 100644 --- a/drivers/gpu/drm/i915/intel_breadcrumbs.c +++ b/drivers/gpu/drm/i915/intel_breadcrumbs.c @@ -846,8 +846,9 @@ static void cancel_fake_irq(struct intel_engine_cs *engine) void intel_engine_reset_breadcrumbs(struct intel_engine_cs *engine) { struct intel_breadcrumbs *b = &engine->breadcrumbs; + unsigned long flags; - spin_lock_irq(&b->irq_lock); + spin_lock_irqsave(&b->irq_lock, flags); /* * Leave the fake_irq timer enabled (if it is running), but clear the @@ -871,7 +872,7 @@ void intel_engine_reset_breadcrumbs(struct intel_engine_cs *engine) */ clear_bit(ENGINE_IRQ_BREADCRUMB, &engine->irq_posted); - spin_unlock_irq(&b->irq_lock); + spin_unlock_irqrestore(&b->irq_lock, flags); } void intel_engine_fini_breadcrumbs(struct intel_engine_cs *engine) -- GitLab From 39d3cc03e9ddd3c7b564acd07ba1691ba817837d Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 17 May 2018 15:24:41 +0100 Subject: [PATCH 0068/1506] drm/i915/selftests: Wait longer for the old active request When testing reset, we wait for 1s on the main thread for the hang to start. Meanwhile, we continue submitting requests on all the background threads, and we may have more threads than cores and so potentially starve the waiter from being woken within the timeout. As the hang timeout and the active timeouts are the same, it is hard to distinguish which caused the timeout. Bump the active thread timeouts to 5s, compared to the 1s timeout for the hang, so that we preferentially report the hang timing out, while hopefully ensuring that we do at least wake up the hang thread first before declaring the background active timeout. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20180517142442.16979-1-chris@chris-wilson.co.uk Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> --- .../gpu/drm/i915/selftests/intel_hangcheck.c | 48 +++++++++++++------ 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c index 2c4e77c050dca..2091e3a6a5be8 100644 --- a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c +++ b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c @@ -563,6 +563,30 @@ struct active_engine { #define TEST_SELF BIT(2) #define TEST_PRIORITY BIT(3) +static int active_request_put(struct i915_request *rq) +{ + int err = 0; + + if (!rq) + return 0; + + if (i915_request_wait(rq, 0, 5 * HZ) < 0) { + GEM_TRACE("%s timed out waiting for completion of fence %llx:%d, seqno %d.\n", + rq->engine->name, + rq->fence.context, + rq->fence.seqno, + i915_request_global_seqno(rq)); + GEM_TRACE_DUMP(); + + i915_gem_set_wedged(rq->i915); + err = -EIO; + } + + i915_request_put(rq); + + return err; +} + static int active_engine(void *data) { I915_RND_STATE(prng); @@ -611,24 +635,20 @@ static int active_engine(void *data) i915_request_add(new); mutex_unlock(&engine->i915->drm.struct_mutex); - if (old) { - if (i915_request_wait(old, 0, HZ) < 0) { - GEM_TRACE("%s timed out.\n", engine->name); - GEM_TRACE_DUMP(); - - i915_gem_set_wedged(engine->i915); - i915_request_put(old); - err = -EIO; - break; - } - i915_request_put(old); - } + err = active_request_put(old); + if (err) + break; cond_resched(); } - for (count = 0; count < ARRAY_SIZE(rq); count++) - i915_request_put(rq[count]); + for (count = 0; count < ARRAY_SIZE(rq); count++) { + int err__ = active_request_put(rq[count]); + + /* Keep the first error */ + if (!err) + err = err__; + } err_file: mock_file_free(engine->i915, file); -- GitLab From e8b58d6de1fe9119018ed9bbeecf373dcc397b8d Mon Sep 17 00:00:00 2001 From: Peter Rosin <peda@axentia.se> Date: Wed, 2 May 2018 09:40:24 +0200 Subject: [PATCH 0069/1506] drm/rockchip: lvds: avoid duplicating drm_bridge_attach drm_bridge_attach takes care of these assignments, so there is no need to open-code them a second time. Signed-off-by: Peter Rosin <peda@axentia.se> Signed-off-by: Heiko Stuebner <heiko@sntech.de> Link: https://patchwork.freedesktop.org/patch/msgid/20180502074025.12421-3-peda@axentia.se --- drivers/gpu/drm/rockchip/rockchip_lvds.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c index e67f4ea28c0e4..4bd94b167d2cd 100644 --- a/drivers/gpu/drm/rockchip/rockchip_lvds.c +++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c @@ -446,14 +446,12 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master, goto err_free_connector; } } else { - lvds->bridge->encoder = encoder; ret = drm_bridge_attach(encoder, lvds->bridge, NULL); if (ret) { DRM_DEV_ERROR(drm_dev->dev, "failed to attach bridge: %d\n", ret); goto err_free_encoder; } - encoder->bridge = lvds->bridge; } pm_runtime_enable(dev); -- GitLab From 6bb2a2af8b1b38a5e33984f5fdda2638317ed8fd Mon Sep 17 00:00:00 2001 From: Zhenyu Wang <zhenyuw@linux.intel.com> Date: Mon, 21 May 2018 16:17:52 +0800 Subject: [PATCH 0070/1506] drm/i915/gvt: Fix crash after request->hw_context change When we do shadowing, workload's request might not be allocated yet, so we still require shadow context's object. And when complete workload, delay to zero workload's request pointer after used for update guest context. v2: Move request alloc earlier as already try to track shadow status depending on request state, which also facilitate to use request->hw_context for target engine context reference. Fixes: 1fc44d9b1afb ("drm/i915: Store a pointer to intel_context in i915_request") Cc: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Cc: Zhi Wang <zhi.a.wang@intel.com> Cc: Weinan Li <weinan.z.li@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20180521081752.31056-1-zhenyuw@linux.intel.com --- drivers/gpu/drm/i915/gvt/scheduler.c | 52 +++++++++------------------- 1 file changed, 16 insertions(+), 36 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/scheduler.c b/drivers/gpu/drm/i915/gvt/scheduler.c index e1760030dda1f..7f5e01df95eee 100644 --- a/drivers/gpu/drm/i915/gvt/scheduler.c +++ b/drivers/gpu/drm/i915/gvt/scheduler.c @@ -348,6 +348,7 @@ int intel_gvt_scan_and_shadow_workload(struct intel_vgpu_workload *workload) struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv; struct intel_engine_cs *engine = dev_priv->engine[workload->ring_id]; struct intel_context *ce; + struct i915_request *rq; int ret; lockdep_assert_held(&dev_priv->drm.struct_mutex); @@ -386,46 +387,26 @@ int intel_gvt_scan_and_shadow_workload(struct intel_vgpu_workload *workload) goto err_shadow; } - ret = populate_shadow_context(workload); - if (ret) - goto err_shadow; - - return 0; - -err_shadow: - release_shadow_wa_ctx(&workload->wa_ctx); -err_unpin: - intel_context_unpin(ce); - return ret; -} - -static int intel_gvt_generate_request(struct intel_vgpu_workload *workload) -{ - int ring_id = workload->ring_id; - struct drm_i915_private *dev_priv = workload->vgpu->gvt->dev_priv; - struct i915_request *rq; - struct intel_vgpu *vgpu = workload->vgpu; - struct intel_vgpu_submission *s = &vgpu->submission; - struct i915_gem_context *shadow_ctx = s->shadow_ctx; - int ret; - - rq = i915_request_alloc(dev_priv->engine[ring_id], shadow_ctx); + rq = i915_request_alloc(engine, shadow_ctx); if (IS_ERR(rq)) { gvt_vgpu_err("fail to allocate gem request\n"); ret = PTR_ERR(rq); - goto err_unpin; + goto err_shadow; } - - gvt_dbg_sched("ring id %d get i915 gem request %p\n", ring_id, rq); - workload->req = i915_request_get(rq); - ret = copy_workload_to_ring_buffer(workload); + + ret = populate_shadow_context(workload); if (ret) - goto err_unpin; - return 0; + goto err_req; -err_unpin: + return 0; +err_req: + rq = fetch_and_zero(&workload->req); + i915_request_put(rq); +err_shadow: release_shadow_wa_ctx(&workload->wa_ctx); +err_unpin: + intel_context_unpin(ce); return ret; } @@ -609,7 +590,7 @@ static int prepare_workload(struct intel_vgpu_workload *workload) goto err_unpin_mm; } - ret = intel_gvt_generate_request(workload); + ret = copy_workload_to_ring_buffer(workload); if (ret) { gvt_vgpu_err("fail to generate request\n"); goto err_unpin_mm; @@ -823,7 +804,7 @@ static void complete_current_workload(struct intel_gvt *gvt, int ring_id) scheduler->current_workload[ring_id]; struct intel_vgpu *vgpu = workload->vgpu; struct intel_vgpu_submission *s = &vgpu->submission; - struct i915_request *rq; + struct i915_request *rq = workload->req; int event; mutex_lock(&gvt->lock); @@ -832,7 +813,6 @@ static void complete_current_workload(struct intel_gvt *gvt, int ring_id) * switch to make sure request is completed. * For the workload w/o request, directly complete the workload. */ - rq = fetch_and_zero(&workload->req); if (rq) { wait_event(workload->shadow_ctx_status_wq, !atomic_read(&workload->shadow_ctx_active)); @@ -863,7 +843,7 @@ static void complete_current_workload(struct intel_gvt *gvt, int ring_id) intel_context_unpin(rq->hw_context); mutex_unlock(&rq->i915->drm.struct_mutex); - i915_request_put(rq); + i915_request_put(fetch_and_zero(&workload->req)); } gvt_dbg_sched("ring id %d complete workload %p status %d\n", -- GitLab From 17e23993f297467bae946a46e44f945d8dae93f8 Mon Sep 17 00:00:00 2001 From: Dan Carpenter <dan.carpenter@oracle.com> Date: Fri, 18 May 2018 11:10:41 +0300 Subject: [PATCH 0071/1506] drm/v3d: Checking for NULL vs IS_ERR() The v3d_fence_create() only returns error pointers on error. It never returns NULL. Fixes: 57692c94dcbe ("drm/v3d: Introduce a new DRM driver for Broadcom V3D V3.x+") Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com> Signed-off-by: Eric Anholt <eric@anholt.net> Link: https://patchwork.freedesktop.org/patch/msgid/20180518081041.GC28335@mwanda --- drivers/gpu/drm/v3d/v3d_sched.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c index b07bece9417dc..808bc901f567f 100644 --- a/drivers/gpu/drm/v3d/v3d_sched.c +++ b/drivers/gpu/drm/v3d/v3d_sched.c @@ -114,8 +114,8 @@ static struct dma_fence *v3d_job_run(struct drm_sched_job *sched_job) v3d_invalidate_caches(v3d); fence = v3d_fence_create(v3d, q); - if (!fence) - return fence; + if (IS_ERR(fence)) + return NULL; if (job->done_fence) dma_fence_put(job->done_fence); -- GitLab From a5ff7a45c9c8fc4d2d9484c028a9d882da6d5f48 Mon Sep 17 00:00:00 2001 From: Daniel Stone <daniels@collabora.com> Date: Fri, 18 May 2018 15:30:07 +0100 Subject: [PATCH 0072/1506] drm/i915: Use intel_fb_obj() everywhere MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We already have a macro to pull the GEM object from a FB, so use it everywhere. We'll make use of this later to move the object storage. Signed-off-by: Daniel Stone <daniels@collabora.com> Reviewed-by: Ville Syrjälä <ville.syrjala@intel.com> Cc: Jani Nikula <jani.nikula@linux.intel.com> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com> Cc: intel-gfx@lists.freedesktop.org Link: https://patchwork.freedesktop.org/patch/msgid/20180518143008.4120-1-daniels@collabora.com --- drivers/gpu/drm/i915/i915_debugfs.c | 4 ++-- drivers/gpu/drm/i915/intel_display.c | 19 ++++++++++--------- drivers/gpu/drm/i915/intel_fbdev.c | 9 +++++---- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 52515445ac406..e9b1b8df6ef5d 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1908,7 +1908,7 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data) fbdev_fb->base.format->cpp[0] * 8, fbdev_fb->base.modifier, drm_framebuffer_read_refcount(&fbdev_fb->base)); - describe_obj(m, fbdev_fb->obj); + describe_obj(m, intel_fb_obj(&fbdev_fb->base)); seq_putc(m, '\n'); } #endif @@ -1926,7 +1926,7 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data) fb->base.format->cpp[0] * 8, fb->base.modifier, drm_framebuffer_read_refcount(&fb->base)); - describe_obj(m, fb->obj); + describe_obj(m, intel_fb_obj(&fb->base)); seq_putc(m, '\n'); } mutex_unlock(&dev->mode_config.fb_lock); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c9ec88acad9c1..1b2cf631305e3 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2474,6 +2474,7 @@ intel_fill_fb_info(struct drm_i915_private *dev_priv, { struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); struct intel_rotation_info *rot_info = &intel_fb->rot_info; + struct drm_i915_gem_object *obj = intel_fb_obj(fb); u32 gtt_offset_rotated = 0; unsigned int max_size = 0; int i, num_planes = fb->format->num_planes; @@ -2538,7 +2539,7 @@ intel_fill_fb_info(struct drm_i915_private *dev_priv, * fb layout agrees with the fence layout. We already check that the * fb stride matches the fence stride elsewhere. */ - if (i == 0 && i915_gem_object_is_tiled(intel_fb->obj) && + if (i == 0 && i915_gem_object_is_tiled(obj) && (x + width) * cpp > fb->pitches[i]) { DRM_DEBUG_KMS("bad fb plane %d offset: 0x%x\n", i, fb->offsets[i]); @@ -2623,9 +2624,9 @@ intel_fill_fb_info(struct drm_i915_private *dev_priv, max_size = max(max_size, offset + size); } - if (max_size * tile_size > intel_fb->obj->base.size) { + if (max_size * tile_size > obj->base.size) { DRM_DEBUG_KMS("fb too big for bo (need %u bytes, have %zu bytes)\n", - max_size * tile_size, intel_fb->obj->base.size); + max_size * tile_size, obj->base.size); return -EINVAL; } @@ -14082,14 +14083,15 @@ static void intel_setup_outputs(struct drm_i915_private *dev_priv) static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb) { struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); + struct drm_i915_gem_object *obj = intel_fb_obj(fb); drm_framebuffer_cleanup(fb); - i915_gem_object_lock(intel_fb->obj); - WARN_ON(!intel_fb->obj->framebuffer_references--); - i915_gem_object_unlock(intel_fb->obj); + i915_gem_object_lock(obj); + WARN_ON(!obj->framebuffer_references--); + i915_gem_object_unlock(obj); - i915_gem_object_put(intel_fb->obj); + i915_gem_object_put(obj); kfree(intel_fb); } @@ -14098,8 +14100,7 @@ static int intel_user_framebuffer_create_handle(struct drm_framebuffer *fb, struct drm_file *file, unsigned int *handle) { - struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); - struct drm_i915_gem_object *obj = intel_fb->obj; + struct drm_i915_gem_object *obj = intel_fb_obj(fb); if (obj->userptr.mm) { DRM_DEBUG("attempting to use a userptr for a framebuffer, denied\n"); diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index e9e02b58b7be6..fb2f9fce34cd2 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -47,7 +47,7 @@ static void intel_fbdev_invalidate(struct intel_fbdev *ifbdev) { - struct drm_i915_gem_object *obj = ifbdev->fb->obj; + struct drm_i915_gem_object *obj = intel_fb_obj(&ifbdev->fb->base); unsigned int origin = ifbdev->vma_flags & PLANE_HAS_FENCE ? ORIGIN_GTT : ORIGIN_CPU; @@ -193,7 +193,7 @@ static int intelfb_create(struct drm_fb_helper *helper, drm_framebuffer_put(&intel_fb->base); intel_fb = ifbdev->fb = NULL; } - if (!intel_fb || WARN_ON(!intel_fb->obj)) { + if (!intel_fb || WARN_ON(!intel_fb_obj(&intel_fb->base))) { DRM_DEBUG_KMS("no BIOS fb, allocating a new one\n"); ret = intelfb_alloc(helper, sizes); if (ret) @@ -265,7 +265,7 @@ static int intelfb_create(struct drm_fb_helper *helper, * If the object is stolen however, it will be full of whatever * garbage was left in there. */ - if (intel_fb->obj->stolen && !prealloc) + if (intel_fb_obj(fb)->stolen && !prealloc) memset_io(info->screen_base, 0, info->screen_size); /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ @@ -792,7 +792,8 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous * been restored from swap. If the object is stolen however, it will be * full of whatever garbage was left in there. */ - if (state == FBINFO_STATE_RUNNING && ifbdev->fb->obj->stolen) + if (state == FBINFO_STATE_RUNNING && + intel_fb_obj(&ifbdev->fb->base)->stolen) memset_io(info->screen_base, 0, info->screen_size); drm_fb_helper_set_suspend(&ifbdev->helper, state); -- GitLab From a268bcd7647d2c22bffdfbb111e5f7291b8494a6 Mon Sep 17 00:00:00 2001 From: Daniel Stone <daniels@collabora.com> Date: Fri, 18 May 2018 15:30:08 +0100 Subject: [PATCH 0073/1506] drm/i915: Move GEM BO inside drm_framebuffer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since drm_framebuffer can now store GEM objects directly, place them there rather than in our own subclass. v2: Only hold a single reference per framebuffer, not per plane. (Ville) v3: Drop NULL check in intel_fb_obj. (Ville) Signed-off-by: Daniel Stone <daniels@collabora.com> Reviewed-by: Ville Syrjälä <ville.syrjala@intel.com> Cc: Jani Nikula <jani.nikula@linux.intel.com> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com> Cc: intel-gfx@lists.freedesktop.org Link: https://patchwork.freedesktop.org/patch/msgid/20180518143008.4120-2-daniels@collabora.com --- drivers/gpu/drm/i915/intel_display.c | 4 ++-- drivers/gpu/drm/i915/intel_drv.h | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1b2cf631305e3..12226a2c8d390 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -14370,9 +14370,9 @@ static int intel_framebuffer_init(struct intel_framebuffer *intel_fb, i, fb->pitches[i], stride_alignment); goto err; } - } - intel_fb->obj = obj; + fb->obj[i] = &obj->base; + } ret = intel_fill_fb_info(dev_priv, fb); if (ret) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 22af249393a48..ac19da7f87908 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -194,7 +194,6 @@ enum intel_output_type { struct intel_framebuffer { struct drm_framebuffer base; - struct drm_i915_gem_object *obj; struct intel_rotation_info rot_info; /* for each plane in the normal GTT view */ @@ -1005,7 +1004,7 @@ struct cxsr_latency { #define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base) #define to_intel_plane(x) container_of(x, struct intel_plane, base) #define to_intel_plane_state(x) container_of(x, struct intel_plane_state, base) -#define intel_fb_obj(x) (x ? to_intel_framebuffer(x)->obj : NULL) +#define intel_fb_obj(x) ((x) ? to_intel_bo((x)->obj[0]) : NULL) struct intel_hdmi { i915_reg_t hdmi_reg; -- GitLab From 3e44255260dc3c329a92cf0aa64495951ccc4fb7 Mon Sep 17 00:00:00 2001 From: Daniel Stone <daniels@collabora.com> Date: Fri, 30 Mar 2018 15:11:20 +0100 Subject: [PATCH 0074/1506] drm/omap: Move GEM BO to drm_framebuffer Since drm_framebuffer can now store GEM objects directly, place them there rather than in our own subclass. As this makes the framebuffer create_handle and destroy functions the same as the GEM framebuffer helper, we can reuse those. Signed-off-by: Daniel Stone <daniels@collabora.com> Reviewed-by: Thierry Reding <treding@nvidia.com> Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk> Cc: Tomi Valkeinen <tomi.valkeinen@ti.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180330141138.28987-6-daniels@collabora.com --- drivers/gpu/drm/omapdrm/omap_fb.c | 60 ++++++++----------------------- 1 file changed, 15 insertions(+), 45 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/omap_fb.c b/drivers/gpu/drm/omapdrm/omap_fb.c index 5fd22ca739138..3d6b6f3d6808d 100644 --- a/drivers/gpu/drm/omapdrm/omap_fb.c +++ b/drivers/gpu/drm/omapdrm/omap_fb.c @@ -19,6 +19,7 @@ #include <drm/drm_crtc.h> #include <drm/drm_crtc_helper.h> +#include <drm/drm_gem_framebuffer_helper.h> #include "omap_dmm_tiler.h" #include "omap_drv.h" @@ -51,7 +52,6 @@ static const u32 formats[] = { /* per-plane info for the fb: */ struct plane { - struct drm_gem_object *bo; u32 pitch; u32 offset; dma_addr_t dma_addr; @@ -68,36 +68,9 @@ struct omap_framebuffer { struct mutex lock; }; -static int omap_framebuffer_create_handle(struct drm_framebuffer *fb, - struct drm_file *file_priv, - unsigned int *handle) -{ - struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); - return drm_gem_handle_create(file_priv, - omap_fb->planes[0].bo, handle); -} - -static void omap_framebuffer_destroy(struct drm_framebuffer *fb) -{ - struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); - int i, n = fb->format->num_planes; - - DBG("destroy: FB ID: %d (%p)", fb->base.id, fb); - - drm_framebuffer_cleanup(fb); - - for (i = 0; i < n; i++) { - struct plane *plane = &omap_fb->planes[i]; - - drm_gem_object_unreference_unlocked(plane->bo); - } - - kfree(omap_fb); -} - static const struct drm_framebuffer_funcs omap_framebuffer_funcs = { - .create_handle = omap_framebuffer_create_handle, - .destroy = omap_framebuffer_destroy, + .create_handle = drm_gem_fb_create_handle, + .destroy = drm_gem_fb_destroy, }; static u32 get_linear_addr(struct plane *plane, @@ -114,10 +87,7 @@ static u32 get_linear_addr(struct plane *plane, bool omap_framebuffer_supports_rotation(struct drm_framebuffer *fb) { - struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); - struct plane *plane = &omap_fb->planes[0]; - - return omap_gem_flags(plane->bo) & OMAP_BO_TILED; + return omap_gem_flags(fb->obj[0]) & OMAP_BO_TILED; } /* Note: DRM rotates counter-clockwise, TILER & DSS rotates clockwise */ @@ -176,7 +146,7 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, x = state->src_x >> 16; y = state->src_y >> 16; - if (omap_gem_flags(plane->bo) & OMAP_BO_TILED) { + if (omap_gem_flags(fb->obj[0]) & OMAP_BO_TILED) { u32 w = state->src_w >> 16; u32 h = state->src_h >> 16; @@ -201,12 +171,12 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, x += w - 1; /* Note: x and y are in TILER units, not pixels */ - omap_gem_rotated_dma_addr(plane->bo, orient, x, y, + omap_gem_rotated_dma_addr(fb->obj[0], orient, x, y, &info->paddr); info->rotation_type = OMAP_DSS_ROT_TILER; info->rotation = state->rotation ?: DRM_MODE_ROTATE_0; /* Note: stride in TILER units, not pixels */ - info->screen_width = omap_gem_tiled_stride(plane->bo, orient); + info->screen_width = omap_gem_tiled_stride(fb->obj[0], orient); } else { switch (state->rotation & DRM_MODE_ROTATE_MASK) { case 0: @@ -234,8 +204,8 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, plane = &omap_fb->planes[1]; if (info->rotation_type == OMAP_DSS_ROT_TILER) { - WARN_ON(!(omap_gem_flags(plane->bo) & OMAP_BO_TILED)); - omap_gem_rotated_dma_addr(plane->bo, orient, x/2, y/2, + WARN_ON(!(omap_gem_flags(fb->obj[1]) & OMAP_BO_TILED)); + omap_gem_rotated_dma_addr(fb->obj[1], orient, x/2, y/2, &info->p_uv_addr); } else { info->p_uv_addr = get_linear_addr(plane, format, 1, x, y); @@ -261,10 +231,10 @@ int omap_framebuffer_pin(struct drm_framebuffer *fb) for (i = 0; i < n; i++) { struct plane *plane = &omap_fb->planes[i]; - ret = omap_gem_pin(plane->bo, &plane->dma_addr); + ret = omap_gem_pin(fb->obj[i], &plane->dma_addr); if (ret) goto fail; - omap_gem_dma_sync_buffer(plane->bo, DMA_TO_DEVICE); + omap_gem_dma_sync_buffer(fb->obj[i], DMA_TO_DEVICE); } omap_fb->pin_count++; @@ -276,7 +246,7 @@ int omap_framebuffer_pin(struct drm_framebuffer *fb) fail: for (i--; i >= 0; i--) { struct plane *plane = &omap_fb->planes[i]; - omap_gem_unpin(plane->bo); + omap_gem_unpin(fb->obj[i]); plane->dma_addr = 0; } @@ -302,7 +272,7 @@ void omap_framebuffer_unpin(struct drm_framebuffer *fb) for (i = 0; i < n; i++) { struct plane *plane = &omap_fb->planes[i]; - omap_gem_unpin(plane->bo); + omap_gem_unpin(fb->obj[i]); plane->dma_addr = 0; } @@ -349,7 +319,7 @@ void omap_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m) struct plane *plane = &omap_fb->planes[i]; seq_printf(m, " %d: offset=%d pitch=%d, obj: ", i, plane->offset, plane->pitch); - omap_gem_describe(plane->bo, m); + omap_gem_describe(fb->obj[i], m); } } #endif @@ -454,7 +424,7 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev, goto fail; } - plane->bo = bos[i]; + fb->obj[i] = bos[i]; plane->offset = mode_cmd->offsets[i]; plane->pitch = pitch; plane->dma_addr = 0; -- GitLab From 2ecceeb53b19455ffa50b31fd3c20fe2974508a6 Mon Sep 17 00:00:00 2001 From: Daniel Stone <daniels@collabora.com> Date: Fri, 30 Mar 2018 15:11:21 +0100 Subject: [PATCH 0075/1506] drm/omap: Move buffer pitch/offset to drm_framebuffer drm_framebuffer already holds per-plane pitch and offsets, which is filled out for us when we create the framebuffer. Nuke our local copy in the plane struct. Signed-off-by: Daniel Stone <daniels@collabora.com> Reviewed-by: Thierry Reding <treding@nvidia.com> Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk> Cc: Tomi Valkeinen <tomi.valkeinen@ti.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180330141138.28987-7-daniels@collabora.com --- drivers/gpu/drm/omapdrm/omap_fb.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/omap_fb.c b/drivers/gpu/drm/omapdrm/omap_fb.c index 3d6b6f3d6808d..9d75eab0d1649 100644 --- a/drivers/gpu/drm/omapdrm/omap_fb.c +++ b/drivers/gpu/drm/omapdrm/omap_fb.c @@ -52,8 +52,6 @@ static const u32 formats[] = { /* per-plane info for the fb: */ struct plane { - u32 pitch; - u32 offset; dma_addr_t dma_addr; }; @@ -73,14 +71,16 @@ static const struct drm_framebuffer_funcs omap_framebuffer_funcs = { .destroy = drm_gem_fb_destroy, }; -static u32 get_linear_addr(struct plane *plane, +static u32 get_linear_addr(struct drm_framebuffer *fb, const struct drm_format_info *format, int n, int x, int y) { + struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); + struct plane *plane = &omap_fb->planes[n]; u32 offset; - offset = plane->offset + offset = fb->offsets[n] + (x * format->cpp[n] / (n == 0 ? 1 : format->hsub)) - + (y * plane->pitch / (n == 0 ? 1 : format->vsub)); + + (y * fb->pitches[n] / (n == 0 ? 1 : format->vsub)); return plane->dma_addr + offset; } @@ -191,10 +191,10 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, break; } - info->paddr = get_linear_addr(plane, format, 0, x, y); + info->paddr = get_linear_addr(fb, format, 0, x, y); info->rotation_type = OMAP_DSS_ROT_NONE; info->rotation = DRM_MODE_ROTATE_0; - info->screen_width = plane->pitch; + info->screen_width = fb->pitches[0]; } /* convert to pixels: */ @@ -208,7 +208,7 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, omap_gem_rotated_dma_addr(fb->obj[1], orient, x/2, y/2, &info->p_uv_addr); } else { - info->p_uv_addr = get_linear_addr(plane, format, 1, x, y); + info->p_uv_addr = get_linear_addr(fb, format, 1, x, y); } } else { info->p_uv_addr = 0; @@ -309,16 +309,14 @@ struct drm_connector *omap_framebuffer_get_next_connector( #ifdef CONFIG_DEBUG_FS void omap_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m) { - struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); int i, n = fb->format->num_planes; seq_printf(m, "fb: %dx%d@%4.4s\n", fb->width, fb->height, (char *)&fb->format->format); for (i = 0; i < n; i++) { - struct plane *plane = &omap_fb->planes[i]; seq_printf(m, " %d: offset=%d pitch=%d, obj: ", - i, plane->offset, plane->pitch); + i, fb->offsets[n], fb->pitches[i]); omap_gem_describe(fb->obj[i], m); } } @@ -425,8 +423,6 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev, } fb->obj[i] = bos[i]; - plane->offset = mode_cmd->offsets[i]; - plane->pitch = pitch; plane->dma_addr = 0; } -- GitLab From c7cbed560ce24a87eccf219bc4c78a19961a6074 Mon Sep 17 00:00:00 2001 From: Daniel Stone <daniels@collabora.com> Date: Mon, 21 May 2018 15:24:49 +0100 Subject: [PATCH 0076/1506] drm/gma500: Fix Medfield for drm_framebuffer move Commit bc61c97502e2 ("drm/gma500: Move GEM BO to drm_framebuffer") moved the gtt_range structure, from being in psb_framebuffer and embedding the GEM object, to being placed in the drm_framebuffer with the gtt_range being derived from the GEM object. The conversion missed out the Medfield subdriver, which was not being built in the default drm-misc config. Do the trivial fixup here. Signed-off-by: Daniel Stone <daniels@collabora.com> Reported-by: kbuild test robot <lkp@intel.com> Reviewed-by: Thierry Reding <treding@nvidia.com> Fixes: bc61c97502e2 ("drm/gma500: Move GEM BO to drm_framebuffer") Cc: Patrik Jakobsson <patrik.r.jakobsson@gmail.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180521142449.20800-1-daniels@collabora.com --- drivers/gpu/drm/gma500/mdfld_intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/gma500/mdfld_intel_display.c b/drivers/gpu/drm/gma500/mdfld_intel_display.c index 5c066448be5b7..881d613cc2e5e 100644 --- a/drivers/gpu/drm/gma500/mdfld_intel_display.c +++ b/drivers/gpu/drm/gma500/mdfld_intel_display.c @@ -196,7 +196,7 @@ static int mdfld__intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, if (!gma_power_begin(dev, true)) return 0; - start = psbfb->gtt->offset; + start = to_gtt_range(fb->obj[0])->offset; offset = y * fb->pitches[0] + x * fb->format->cpp[0]; REG_WRITE(map->stride, fb->pitches[0]); -- GitLab From d93fa1b47b8fcd149b5091f18385304f402a8e15 Mon Sep 17 00:00:00 2001 From: Jani Nikula <jani.nikula@intel.com> Date: Wed, 16 May 2018 11:01:10 +0300 Subject: [PATCH 0077/1506] Revert "drm/i915/edp: Allow alternate fixed mode for eDP if available." This reverts commit dc911f5bd8aacfcf8aabd5c26c88e04c837a938e. Per the report, no matter what display mode you select with xrandr, the i915 driver will always select the alternate fixed mode. For the reporter this means that the display will always run at 40Hz which is quite annoying. This may be due to the mode comparison. But there are some other potential issues. The choice of alt_fixed_mode seems dubious. It's the first non-preferred mode, but there are no guarantees that the only difference would be refresh rate. Similarly, there may be more than one preferred mode in the probed modes list, and the commit changes the preferred mode selection to choose the last one on the list instead of the first. (Note that the probed modes list is the raw, unfiltered, unsorted list of modes from drm_add_edid_modes(), not the pretty result after a drm_helper_probe_single_connector_modes() call.) Finally, we already have eerily similar code in place to find the downclock mode for DRRS that seems like could be reused here. Back to the drawing board. Note: This is a hand-crafted revert due to conflicts. If it fails to backport, please just try reverting the original commit directly. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=105469 Reported-by: Rune Petersen <rune@megahurts.dk> Reported-by: Mark Spencer <n7u4722r35@ynzlx.anonbox.net> Fixes: dc911f5bd8aa ("drm/i915/edp: Allow alternate fixed mode for eDP if available.") Cc: Clint Taylor <clinton.a.taylor@intel.com> Cc: David Weinehall <david.weinehall@linux.intel.com> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com> Cc: Paulo Zanoni <paulo.r.zanoni@intel.com> Cc: Jani Nikula <jani.nikula@intel.com> Cc: Chris Wilson <chris@chris-wilson.co.uk> Cc: Jim Bride <jim.bride@linux.intel.com> Cc: Jani Nikula <jani.nikula@linux.intel.com> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: intel-gfx@lists.freedesktop.org Cc: <stable@vger.kernel.org> # v4.14+ Signed-off-by: Jani Nikula <jani.nikula@intel.com> Reviewed-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180516080110.22770-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_dp.c | 38 ++++-------------------------- drivers/gpu/drm/i915/intel_drv.h | 2 -- drivers/gpu/drm/i915/intel_dsi.c | 2 +- drivers/gpu/drm/i915/intel_dvo.c | 2 +- drivers/gpu/drm/i915/intel_lvds.c | 3 +-- drivers/gpu/drm/i915/intel_panel.c | 6 ----- 6 files changed, 8 insertions(+), 45 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 1020709400954..be99e56cf7d91 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1679,23 +1679,6 @@ static int intel_dp_compute_bpp(struct intel_dp *intel_dp, return bpp; } -static bool intel_edp_compare_alt_mode(struct drm_display_mode *m1, - struct drm_display_mode *m2) -{ - bool bres = false; - - if (m1 && m2) - bres = (m1->hdisplay == m2->hdisplay && - m1->hsync_start == m2->hsync_start && - m1->hsync_end == m2->hsync_end && - m1->htotal == m2->htotal && - m1->vdisplay == m2->vdisplay && - m1->vsync_start == m2->vsync_start && - m1->vsync_end == m2->vsync_end && - m1->vtotal == m2->vtotal); - return bres; -} - /* Adjust link config limits based on compliance test requests. */ static void intel_dp_adjust_compliance_config(struct intel_dp *intel_dp, @@ -1860,16 +1843,8 @@ intel_dp_compute_config(struct intel_encoder *encoder, pipe_config->has_audio = intel_conn_state->force_audio == HDMI_AUDIO_ON; if (intel_dp_is_edp(intel_dp) && intel_connector->panel.fixed_mode) { - struct drm_display_mode *panel_mode = - intel_connector->panel.alt_fixed_mode; - struct drm_display_mode *req_mode = &pipe_config->base.mode; - - if (!intel_edp_compare_alt_mode(req_mode, panel_mode)) - panel_mode = intel_connector->panel.fixed_mode; - - drm_mode_debug_printmodeline(panel_mode); - - intel_fixed_panel_mode(panel_mode, adjusted_mode); + intel_fixed_panel_mode(intel_connector->panel.fixed_mode, + adjusted_mode); if (INTEL_GEN(dev_priv) >= 9) { int ret; @@ -6137,7 +6112,6 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, struct drm_i915_private *dev_priv = to_i915(dev); struct drm_connector *connector = &intel_connector->base; struct drm_display_mode *fixed_mode = NULL; - struct drm_display_mode *alt_fixed_mode = NULL; struct drm_display_mode *downclock_mode = NULL; bool has_dpcd; struct drm_display_mode *scan; @@ -6192,14 +6166,13 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, } intel_connector->edid = edid; - /* prefer fixed mode from EDID if available, save an alt mode also */ + /* prefer fixed mode from EDID if available */ list_for_each_entry(scan, &connector->probed_modes, head) { if ((scan->type & DRM_MODE_TYPE_PREFERRED)) { fixed_mode = drm_mode_duplicate(dev, scan); downclock_mode = intel_dp_drrs_init( intel_connector, fixed_mode); - } else if (!alt_fixed_mode) { - alt_fixed_mode = drm_mode_duplicate(dev, scan); + break; } } @@ -6236,8 +6209,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, pipe_name(pipe)); } - intel_panel_init(&intel_connector->panel, fixed_mode, alt_fixed_mode, - downclock_mode); + intel_panel_init(&intel_connector->panel, fixed_mode, downclock_mode); intel_connector->panel.backlight.power = intel_edp_backlight_power; intel_panel_setup_backlight(connector, pipe); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index ac19da7f87908..2bf383bb4b8dd 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -276,7 +276,6 @@ struct intel_encoder { struct intel_panel { struct drm_display_mode *fixed_mode; - struct drm_display_mode *alt_fixed_mode; struct drm_display_mode *downclock_mode; /* backlight */ @@ -1855,7 +1854,6 @@ void intel_overlay_reset(struct drm_i915_private *dev_priv); /* intel_panel.c */ int intel_panel_init(struct intel_panel *panel, struct drm_display_mode *fixed_mode, - struct drm_display_mode *alt_fixed_mode, struct drm_display_mode *downclock_mode); void intel_panel_fini(struct intel_panel *panel); void intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode, diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 51a1d6868b1ea..cf39ca90d8878 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -1846,7 +1846,7 @@ void intel_dsi_init(struct drm_i915_private *dev_priv) connector->display_info.width_mm = fixed_mode->width_mm; connector->display_info.height_mm = fixed_mode->height_mm; - intel_panel_init(&intel_connector->panel, fixed_mode, NULL, NULL); + intel_panel_init(&intel_connector->panel, fixed_mode, NULL); intel_panel_setup_backlight(connector, INVALID_PIPE); intel_dsi_add_properties(intel_connector); diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index a86f0398570f6..7b942b6c17000 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -531,7 +531,7 @@ void intel_dvo_init(struct drm_i915_private *dev_priv) */ intel_panel_init(&intel_connector->panel, intel_dvo_get_current_mode(intel_encoder), - NULL, NULL); + NULL); intel_dvo->panel_wants_dither = true; } diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index a92bb63b2f2d4..17f297dca2965 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -1177,8 +1177,7 @@ void intel_lvds_init(struct drm_i915_private *dev_priv) out: mutex_unlock(&dev->mode_config.mutex); - intel_panel_init(&intel_connector->panel, fixed_mode, NULL, - downclock_mode); + intel_panel_init(&intel_connector->panel, fixed_mode, downclock_mode); intel_panel_setup_backlight(connector, INVALID_PIPE); lvds_encoder->is_dual_link = compute_is_dual_link_lvds(lvds_encoder); diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 41d00b1603e30..b443278e569ce 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -1928,13 +1928,11 @@ intel_panel_init_backlight_funcs(struct intel_panel *panel) int intel_panel_init(struct intel_panel *panel, struct drm_display_mode *fixed_mode, - struct drm_display_mode *alt_fixed_mode, struct drm_display_mode *downclock_mode) { intel_panel_init_backlight_funcs(panel); panel->fixed_mode = fixed_mode; - panel->alt_fixed_mode = alt_fixed_mode; panel->downclock_mode = downclock_mode; return 0; @@ -1948,10 +1946,6 @@ void intel_panel_fini(struct intel_panel *panel) if (panel->fixed_mode) drm_mode_destroy(intel_connector->base.dev, panel->fixed_mode); - if (panel->alt_fixed_mode) - drm_mode_destroy(intel_connector->base.dev, - panel->alt_fixed_mode); - if (panel->downclock_mode) drm_mode_destroy(intel_connector->base.dev, panel->downclock_mode); -- GitLab From 84b510e22da7926522a257cfe295d3695346a0bd Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Mon, 21 May 2018 22:05:30 +0100 Subject: [PATCH 0078/1506] drm/i915/query: Protect tainted function pointer lookup Smatch identifies i915_query_ioctl() as being a potential victim of Spectre due to its use of a tainted user index into a function pointer array. Use array_index_nospec() to defang the user index before using it to lookup the function pointer. Fixes: a446ae2c6e65 ("drm/i915: add query uAPI") Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Lionel Landwerlin <lionel.g.landwerlin@intel.com> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180521210530.26008-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_query.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_query.c b/drivers/gpu/drm/i915/i915_query.c index 3ace929dd90ff..95f9d179afc43 100644 --- a/drivers/gpu/drm/i915/i915_query.c +++ b/drivers/gpu/drm/i915/i915_query.c @@ -4,6 +4,8 @@ * Copyright © 2018 Intel Corporation */ +#include <linux/nospec.h> + #include "i915_drv.h" #include "i915_query.h" #include <uapi/drm/i915_drm.h> @@ -111,10 +113,12 @@ int i915_query_ioctl(struct drm_device *dev, void *data, struct drm_file *file) func_idx = item.query_id - 1; - if (func_idx < ARRAY_SIZE(i915_query_funcs)) + ret = -EINVAL; + if (func_idx < ARRAY_SIZE(i915_query_funcs)) { + func_idx = array_index_nospec(func_idx, + ARRAY_SIZE(i915_query_funcs)); ret = i915_query_funcs[func_idx](dev_priv, &item); - else - ret = -EINVAL; + } /* Only write the length back to userspace if they differ. */ if (ret != item.length && put_user(ret, &user_item_ptr->length)) -- GitLab From 1abb70f5955d1a9021f96359a2c6502ca569b68d Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Tue, 22 May 2018 09:36:43 +0100 Subject: [PATCH 0079/1506] drm/i915/gtt: Allow pagedirectory allocations to fail As we handle the allocation failure of the page directory and tables by propagating the failure back to userspace, allow it to fail if direct reclaim is unable to satisfy the request (i.e. disable the oomkiller). The premise being that if we are unable to allocate a single page for the pagetable, we will not be able to handle the multitude of pages required for the gfx operation and we should back off to allow the system to recover. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=106609 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Matthew Auld <matthew.william.auld@gmail.com> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Reviewed-by: Matthew Auld <matthew.william.auld@gmail.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180522083643.29601-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_gtt.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 996ab2ad6c45c..fc5c0f746f265 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -42,7 +42,7 @@ #include "intel_drv.h" #include "intel_frontbuffer.h" -#define I915_GFP_DMA (GFP_KERNEL | __GFP_HIGHMEM) +#define I915_GFP_ALLOW_FAIL (GFP_KERNEL | __GFP_RETRY_MAYFAIL | __GFP_NOWARN) /** * DOC: Global GTT views @@ -489,7 +489,7 @@ static int __setup_page_dma(struct i915_address_space *vm, struct i915_page_dma *p, gfp_t gfp) { - p->page = vm_alloc_page(vm, gfp | __GFP_NOWARN | __GFP_NORETRY); + p->page = vm_alloc_page(vm, gfp | I915_GFP_ALLOW_FAIL); if (unlikely(!p->page)) return -ENOMEM; @@ -506,7 +506,7 @@ static int __setup_page_dma(struct i915_address_space *vm, static int setup_page_dma(struct i915_address_space *vm, struct i915_page_dma *p) { - return __setup_page_dma(vm, p, I915_GFP_DMA); + return __setup_page_dma(vm, p, __GFP_HIGHMEM); } static void cleanup_page_dma(struct i915_address_space *vm, @@ -614,7 +614,7 @@ static struct i915_page_table *alloc_pt(struct i915_address_space *vm) { struct i915_page_table *pt; - pt = kmalloc(sizeof(*pt), GFP_KERNEL | __GFP_NOWARN); + pt = kmalloc(sizeof(*pt), I915_GFP_ALLOW_FAIL); if (unlikely(!pt)) return ERR_PTR(-ENOMEM); @@ -651,7 +651,7 @@ static struct i915_page_directory *alloc_pd(struct i915_address_space *vm) { struct i915_page_directory *pd; - pd = kzalloc(sizeof(*pd), GFP_KERNEL | __GFP_NOWARN); + pd = kzalloc(sizeof(*pd), I915_GFP_ALLOW_FAIL); if (unlikely(!pd)) return ERR_PTR(-ENOMEM); @@ -685,7 +685,7 @@ static int __pdp_init(struct i915_address_space *vm, const unsigned int pdpes = i915_pdpes_per_pdp(vm); pdp->page_directory = kmalloc_array(pdpes, sizeof(*pdp->page_directory), - GFP_KERNEL | __GFP_NOWARN); + I915_GFP_ALLOW_FAIL); if (unlikely(!pdp->page_directory)) return -ENOMEM; @@ -1229,7 +1229,7 @@ static int gen8_init_scratch(struct i915_address_space *vm) { int ret; - ret = setup_scratch_page(vm, I915_GFP_DMA); + ret = setup_scratch_page(vm, __GFP_HIGHMEM); if (ret) return ret; @@ -1974,7 +1974,7 @@ static int gen6_init_scratch(struct i915_address_space *vm) { int ret; - ret = setup_scratch_page(vm, I915_GFP_DMA); + ret = setup_scratch_page(vm, __GFP_HIGHMEM); if (ret) return ret; -- GitLab From 5255e2f8d1177f3eddeae930dda58e4dc7b4373d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Tue, 8 May 2018 17:08:14 +0300 Subject: [PATCH 0080/1506] drm/i915: Replace vbt edp.support with int_lvds_support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace dev_priv->vbt.edp.support with dev_priv->vbt.int_lvds_support. We'll want to extend its use beyond the LVDS vs. eDP case in the future. v2: Nuke the edp.support from parse_edp() (Jani) Only clear int_lvds_support for gen5+ to preserve the current behaviour (Jani) Cc: Jani Nikula <jani.nikula@intel.com> Cc: Ondrej Zary <linux@rainbow-software.org> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180508140814.20105-1-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula <jani.nikula@intel.com> --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/intel_bios.c | 13 +++++++------ drivers/gpu/drm/i915/intel_lvds.c | 9 +++++---- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e33c380b43e3d..3302b3d4d974a 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1052,6 +1052,7 @@ struct intel_vbt_data { unsigned int lvds_vbt:1; unsigned int int_crt_support:1; unsigned int lvds_use_ssc:1; + unsigned int int_lvds_support:1; unsigned int display_clock_mode:1; unsigned int fdi_rx_polarity_inverted:1; unsigned int panel_type:4; @@ -1067,7 +1068,6 @@ struct intel_vbt_data { int vswing; bool low_vswing; bool initialized; - bool support; int bpp; struct edp_power_seq pps; } edp; diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 54270bdde1005..5c863e2714ec5 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -518,8 +518,9 @@ parse_driver_features(struct drm_i915_private *dev_priv, if (!driver) return; - if (driver->lvds_config == BDB_DRIVER_FEATURE_EDP) - dev_priv->vbt.edp.support = 1; + if (INTEL_GEN(dev_priv) >= 5 && + driver->lvds_config == BDB_DRIVER_FEATURE_EDP) + dev_priv->vbt.int_lvds_support = 0; DRM_DEBUG_KMS("DRRS State Enabled:%d\n", driver->drrs_enabled); /* @@ -542,11 +543,8 @@ parse_edp(struct drm_i915_private *dev_priv, const struct bdb_header *bdb) int panel_type = dev_priv->vbt.panel_type; edp = find_section(bdb, BDB_EDP); - if (!edp) { - if (dev_priv->vbt.edp.support) - DRM_DEBUG_KMS("No eDP BDB found but eDP panel supported.\n"); + if (!edp) return; - } switch ((edp->color_depth >> (panel_type * 2)) & 3) { case EDP_18BPP: @@ -1513,6 +1511,9 @@ init_vbt_defaults(struct drm_i915_private *dev_priv) dev_priv->vbt.int_tv_support = 1; dev_priv->vbt.int_crt_support = 1; + /* driver features */ + dev_priv->vbt.int_lvds_support = 1; + /* Default to using SSC */ dev_priv->vbt.lvds_use_ssc = 1; /* diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 17f297dca2965..bacad88ad7ae5 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -1003,6 +1003,11 @@ void intel_lvds_init(struct drm_i915_private *dev_priv) if (dmi_check_system(intel_no_lvds)) return; + if (!dev_priv->vbt.int_lvds_support) { + DRM_DEBUG_KMS("Internal LVDS support disabled by VBT\n"); + return; + } + if (HAS_PCH_SPLIT(dev_priv)) lvds_reg = PCH_LVDS; else @@ -1013,10 +1018,6 @@ void intel_lvds_init(struct drm_i915_private *dev_priv) if (HAS_PCH_SPLIT(dev_priv)) { if ((lvds & LVDS_DETECTED) == 0) return; - if (dev_priv->vbt.edp.support) { - DRM_DEBUG_KMS("disable LVDS for eDP support\n"); - return; - } } pin = GMBUS_PIN_PANEL; -- GitLab From 59462a00cc88bc45eaed069942362839ccb0b3de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Tue, 8 May 2018 15:41:36 +0300 Subject: [PATCH 0081/1506] drm/i915: Eliminate the unused dev_priv->vbt.lvds_vbt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dev_priv->vbt.lvds_vbt is set but never actually used. Kill it. Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180508124136.10969-3-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/i915_drv.h | 1 - drivers/gpu/drm/i915/intel_bios.c | 3 --- 2 files changed, 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 3302b3d4d974a..b86ed6401120e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1049,7 +1049,6 @@ struct intel_vbt_data { /* Feature bits */ unsigned int int_tv_support:1; unsigned int lvds_dither:1; - unsigned int lvds_vbt:1; unsigned int int_crt_support:1; unsigned int lvds_use_ssc:1; unsigned int int_lvds_support:1; diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 5c863e2714ec5..34c805970d7ce 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -267,8 +267,6 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, if (!lvds_lfp_data_ptrs) return; - dev_priv->vbt.lvds_vbt = 1; - panel_dvo_timing = get_lvds_dvo_timing(lvds_lfp_data, lvds_lfp_data_ptrs, panel_type); @@ -1502,7 +1500,6 @@ init_vbt_defaults(struct drm_i915_private *dev_priv) /* LFP panel data */ dev_priv->vbt.lvds_dither = 1; - dev_priv->vbt.lvds_vbt = 0; /* SDVO panel data */ dev_priv->vbt.sdvo_lvds_vbt_mode = NULL; -- GitLab From a33b1dc8a732144e11cb4bf067d24ba51e6b8ab0 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Tue, 22 May 2018 13:10:18 +0100 Subject: [PATCH 0082/1506] drm/i915/query: nospec expects no more than an unsigned long nospec quite reasonably asserts that it will never be used with an index larger than unsigned long (that being the largest possibly index into an C array). However, our ubi uses the convention of u64 for any large integer, running afoul of the assertion on 32b. Reduce our index to an unsigned long, checking for type overflow first. drivers/gpu/drm/i915/i915_query.c: In function 'i915_query_ioctl': include/linux/compiler.h:339:38: error: call to '__compiletime_assert_119' declared with attribute error: BUILD_BUG_ON failed: sizeof(_s) > sizeof(long) Reported-by: kbuild-all@01.org Fixes: 84b510e22da7 ("drm/i915/query: Protect tainted function pointer lookup") Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Lionel Landwerlin <lionel.g.landwerlin@intel.com> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180522121018.15199-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_query.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_query.c b/drivers/gpu/drm/i915/i915_query.c index 95f9d179afc43..3f502eef24316 100644 --- a/drivers/gpu/drm/i915/i915_query.c +++ b/drivers/gpu/drm/i915/i915_query.c @@ -102,7 +102,7 @@ int i915_query_ioctl(struct drm_device *dev, void *data, struct drm_file *file) for (i = 0; i < args->num_items; i++, user_item_ptr++) { struct drm_i915_query_item item; - u64 func_idx; + unsigned long func_idx; int ret; if (copy_from_user(&item, user_item_ptr, sizeof(item))) @@ -111,6 +111,9 @@ int i915_query_ioctl(struct drm_device *dev, void *data, struct drm_file *file) if (item.query_id == 0) return -EINVAL; + if (overflows_type(item.query_id - 1, unsigned long)) + return -EINVAL; + func_idx = item.query_id - 1; ret = -EINVAL; -- GitLab From 520ea9347505f5eb90a6162385cf821e80b6c233 Mon Sep 17 00:00:00 2001 From: Laura Abbott <labbott@redhat.com> Date: Mon, 9 Apr 2018 14:06:47 -0700 Subject: [PATCH 0083/1506] drm/gma500: Remove VLA There's an ongoing effort to remove VLAs[1] from the kernel to eventually turn on -Wvla. Switch to a reasonable upper bound for the VLAs in the gma500 driver. [1] https://lkml.org/lkml/2018/3/7/621 Signed-off-by: Laura Abbott <labbott@redhat.com> Reviewed-by: Kees Cook <keescook@chromium.org> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180409210647.3718-1-labbott@redhat.com --- drivers/gpu/drm/gma500/psb_intel_sdvo.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/gma500/psb_intel_sdvo.c b/drivers/gpu/drm/gma500/psb_intel_sdvo.c index f2ee6aa10afa1..1d40746ab6259 100644 --- a/drivers/gpu/drm/gma500/psb_intel_sdvo.c +++ b/drivers/gpu/drm/gma500/psb_intel_sdvo.c @@ -429,13 +429,20 @@ static const char *cmd_status_names[] = { "Scaling not supported" }; +#define MAX_ARG_LEN 32 + static bool psb_intel_sdvo_write_cmd(struct psb_intel_sdvo *psb_intel_sdvo, u8 cmd, const void *args, int args_len) { - u8 buf[args_len*2 + 2], status; - struct i2c_msg msgs[args_len + 3]; + u8 buf[MAX_ARG_LEN*2 + 2], status; + struct i2c_msg msgs[MAX_ARG_LEN + 3]; int i, ret; + if (args_len > MAX_ARG_LEN) { + DRM_ERROR("Need to increase arg length\n"); + return false; + } + psb_intel_sdvo_debug_write(psb_intel_sdvo, cmd, args, args_len); for (i = 0; i < args_len; i++) { -- GitLab From ca510ead96d78c5379db5d36ffbdf5382f36db6d Mon Sep 17 00:00:00 2001 From: Laura Abbott <labbott@redhat.com> Date: Tue, 10 Apr 2018 18:03:30 -0700 Subject: [PATCH 0084/1506] drm/i2c: tda998x: Remove VLA usage There's an ongoing effort to remove VLAs[1] from the kernel to eventually turn on -Wvla. The vla in reg_write_range is based on the length of data passed. The one use of a non-constant size for this range is bounded by the size buffer passed to hdmi_infoframe_pack which is a fixed size. Switch to this upper bound. [1] https://lkml.org/lkml/2018/3/7/621 Signed-off-by: Laura Abbott <labbott@redhat.com> Reviewed-by: Kees Cook <keescook@chromium.org> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180411010330.17866-1-labbott@redhat.com --- drivers/gpu/drm/i2c/tda998x_drv.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index 421c8a72369e3..0068d714d1bd6 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -466,13 +466,22 @@ reg_read_range(struct tda998x_priv *priv, u16 reg, char *buf, int cnt) return ret; } +#define MAX_WRITE_RANGE_BUF 32 + static void reg_write_range(struct tda998x_priv *priv, u16 reg, u8 *p, int cnt) { struct i2c_client *client = priv->hdmi; - u8 buf[cnt+1]; + /* This is the maximum size of the buffer passed in */ + u8 buf[MAX_WRITE_RANGE_BUF + 1]; int ret; + if (cnt > MAX_WRITE_RANGE_BUF) { + dev_err(&client->dev, "Fixed write buffer too small (%d)\n", + MAX_WRITE_RANGE_BUF); + return; + } + buf[0] = REG2ADDR(reg); memcpy(&buf[1], p, cnt); @@ -679,7 +688,7 @@ static void tda998x_write_if(struct tda998x_priv *priv, u8 bit, u16 addr, union hdmi_infoframe *frame) { - u8 buf[32]; + u8 buf[MAX_WRITE_RANGE_BUF]; ssize_t len; len = hdmi_infoframe_pack(frame, buf, sizeof(buf)); -- GitLab From 3c5f134ac9d0e405a15af652c3ce8cbaa9bf1bc7 Mon Sep 17 00:00:00 2001 From: Souptick Joarder <jrdr.linux@gmail.com> Date: Wed, 25 Apr 2018 10:29:22 +0530 Subject: [PATCH 0085/1506] gpu: drm: udl: Adding new typedef vm_fault_t Use new return type vm_fault_t for fault and huge_fault handler. For now, this is just documenting that the function returns a VM_FAULT value rather than an errno. Once all instances are converted, vm_fault_t will become a distinct type. Commit 1c8f422059ae ("mm: change return type to vm_fault_t") Previously vm_insert_page() returns err which driver mapped into VM_FAULT_* type. The new function vmf_ insert_page() will replace this inefficiency by returning VM_FAULT_* type. Signed-off-by: Souptick Joarder <jrdr.linux@gmail.com> Reviewed-by: Matthew Wilcox <mawilcox@microsoft.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180425045922.GA21590@jordon-HP-15-Notebook-PC --- drivers/gpu/drm/udl/udl_drv.h | 3 ++- drivers/gpu/drm/udl/udl_gem.c | 15 ++------------- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h index 55c0cc3091981..072582570a4fa 100644 --- a/drivers/gpu/drm/udl/udl_drv.h +++ b/drivers/gpu/drm/udl/udl_drv.h @@ -16,6 +16,7 @@ #include <linux/usb.h> #include <drm/drm_gem.h> +#include <linux/mm_types.h> #define DRIVER_NAME "udl" #define DRIVER_DESC "DisplayLink" @@ -136,7 +137,7 @@ void udl_gem_put_pages(struct udl_gem_object *obj); int udl_gem_vmap(struct udl_gem_object *obj); void udl_gem_vunmap(struct udl_gem_object *obj); int udl_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma); -int udl_gem_fault(struct vm_fault *vmf); +vm_fault_t udl_gem_fault(struct vm_fault *vmf); int udl_handle_damage(struct udl_framebuffer *fb, int x, int y, int width, int height); diff --git a/drivers/gpu/drm/udl/udl_gem.c b/drivers/gpu/drm/udl/udl_gem.c index 9a15cce22ccee..d5a23295dd80c 100644 --- a/drivers/gpu/drm/udl/udl_gem.c +++ b/drivers/gpu/drm/udl/udl_gem.c @@ -100,13 +100,12 @@ int udl_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) return ret; } -int udl_gem_fault(struct vm_fault *vmf) +vm_fault_t udl_gem_fault(struct vm_fault *vmf) { struct vm_area_struct *vma = vmf->vma; struct udl_gem_object *obj = to_udl_bo(vma->vm_private_data); struct page *page; unsigned int page_offset; - int ret = 0; page_offset = (vmf->address - vma->vm_start) >> PAGE_SHIFT; @@ -114,17 +113,7 @@ int udl_gem_fault(struct vm_fault *vmf) return VM_FAULT_SIGBUS; page = obj->pages[page_offset]; - ret = vm_insert_page(vma, vmf->address, page); - switch (ret) { - case -EAGAIN: - case 0: - case -ERESTARTSYS: - return VM_FAULT_NOPAGE; - case -ENOMEM: - return VM_FAULT_OOM; - default: - return VM_FAULT_SIGBUS; - } + return vmf_insert_page(vma, vmf->address, page); } int udl_gem_get_pages(struct udl_gem_object *obj) -- GitLab From f606bc6d9d416504596844d513474791cdbb3993 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Fri, 18 May 2018 18:29:25 +0300 Subject: [PATCH 0086/1506] drm/i915: Move intel_ddi_get_crtc_new_encoder() out from ddi code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ddi code no longer uses intel_ddi_get_crtc_new_encoder(). Move it elsewhere where we have some users left. Reviewed-by: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180518152931.13104-1-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/intel_ddi.c | 29 -------------------------- drivers/gpu/drm/i915/intel_display.c | 31 +++++++++++++++++++++++++++- drivers/gpu/drm/i915/intel_drv.h | 2 -- 3 files changed, 30 insertions(+), 32 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 1665bc588241c..3b8f12883ca79 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1243,35 +1243,6 @@ intel_ddi_get_crtc_encoder(struct intel_crtc *crtc) return ret; } -/* Finds the only possible encoder associated with the given CRTC. */ -struct intel_encoder * -intel_ddi_get_crtc_new_encoder(struct intel_crtc_state *crtc_state) -{ - struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); - struct intel_encoder *ret = NULL; - struct drm_atomic_state *state; - struct drm_connector *connector; - struct drm_connector_state *connector_state; - int num_encoders = 0; - int i; - - state = crtc_state->base.state; - - for_each_new_connector_in_state(state, connector, connector_state, i) { - if (connector_state->crtc != crtc_state->base.crtc) - continue; - - ret = to_intel_encoder(connector_state->best_encoder); - num_encoders++; - } - - WARN(num_encoders != 1, "%d encoders on crtc for pipe %c\n", num_encoders, - pipe_name(crtc->pipe)); - - BUG_ON(ret == NULL); - return ret; -} - #define LC_FREQ 2700 static int hsw_ddi_calc_wrpll_link(struct drm_i915_private *dev_priv, diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 12226a2c8d390..16f9a9b3364a7 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4590,6 +4590,35 @@ static void ivybridge_update_fdi_bc_bifurcation(struct intel_crtc *intel_crtc) } } +/* + * Finds the encoder associated with the given CRTC. This can only be + * used when we know that the CRTC isn't feeding multiple encoders! + */ +static struct intel_encoder * +intel_get_crtc_new_encoder(const struct intel_crtc_state *crtc_state) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); + const struct drm_atomic_state *state = crtc_state->base.state; + const struct drm_connector_state *connector_state; + const struct drm_connector *connector; + struct intel_encoder *encoder = NULL; + int num_encoders = 0; + int i; + + for_each_new_connector_in_state(state, connector, connector_state, i) { + if (connector_state->crtc != &crtc->base) + continue; + + encoder = to_intel_encoder(connector_state->best_encoder); + num_encoders++; + } + + WARN(num_encoders != 1, "%d encoders for pipe %c\n", + num_encoders, pipe_name(crtc->pipe)); + + return encoder; +} + /* Return which DP Port should be selected for Transcoder DP control */ static enum port intel_trans_dp_port_sel(struct intel_crtc *crtc) @@ -9103,7 +9132,7 @@ static int haswell_crtc_compute_clock(struct intel_crtc *crtc, { if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI)) { struct intel_encoder *encoder = - intel_ddi_get_crtc_new_encoder(crtc_state); + intel_get_crtc_new_encoder(crtc_state); if (!intel_get_shared_dpll(crtc, crtc_state, encoder)) { DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n", diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 2bf383bb4b8dd..e919e0099ad68 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1393,8 +1393,6 @@ void intel_ddi_disable_transcoder_func(struct drm_i915_private *dev_priv, enum transcoder cpu_transcoder); void intel_ddi_enable_pipe_clock(const struct intel_crtc_state *crtc_state); void intel_ddi_disable_pipe_clock(const struct intel_crtc_state *crtc_state); -struct intel_encoder * -intel_ddi_get_crtc_new_encoder(struct intel_crtc_state *crtc_state); void intel_ddi_set_pipe_settings(const struct intel_crtc_state *crtc_state); void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp); bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector); -- GitLab From f67dc6d8869fd29fb1635119e3210bf92ce983a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Fri, 18 May 2018 18:29:26 +0300 Subject: [PATCH 0087/1506] drm/i915: Parametrize TRANS_DP_PORT_SEL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Parametrize the TRANS_DP_PORT_SEL macros. v2: WARN for bogus ports (Jani) Order the defines mask,value (Jani) Reviewed-by: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180518152931.13104-2-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/i915_reg.h | 8 +++----- drivers/gpu/drm/i915/intel_display.c | 24 ++++++++---------------- 2 files changed, 11 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 196a0eb792725..5a103496423c7 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -7887,11 +7887,9 @@ enum { #define _TRANS_DP_CTL_C 0xe2300 #define TRANS_DP_CTL(pipe) _MMIO_PIPE(pipe, _TRANS_DP_CTL_A, _TRANS_DP_CTL_B) #define TRANS_DP_OUTPUT_ENABLE (1<<31) -#define TRANS_DP_PORT_SEL_B (0<<29) -#define TRANS_DP_PORT_SEL_C (1<<29) -#define TRANS_DP_PORT_SEL_D (2<<29) -#define TRANS_DP_PORT_SEL_NONE (3<<29) -#define TRANS_DP_PORT_SEL_MASK (3<<29) +#define TRANS_DP_PORT_SEL_MASK (3 << 29) +#define TRANS_DP_PORT_SEL_NONE (3 << 29) +#define TRANS_DP_PORT_SEL(port) (((port) - PORT_B) << 29) #define TRANS_DP_PIPE_TO_PORT(val) ((((val) & TRANS_DP_PORT_SEL_MASK) >> 29) + PORT_B) #define TRANS_DP_AUDIO_ONLY (1<<26) #define TRANS_DP_ENH_FRAMING (1<<18) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 16f9a9b3364a7..68d48b7445e90 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1360,9 +1360,9 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv, { enum pipe port_pipe; - assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_B, TRANS_DP_PORT_SEL_B); - assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_C, TRANS_DP_PORT_SEL_C); - assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_D, TRANS_DP_PORT_SEL_D); + assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_B, TRANS_DP_PORT_SEL(PORT_B)); + assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_C, TRANS_DP_PORT_SEL(PORT_C)); + assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_D, TRANS_DP_PORT_SEL(PORT_D)); I915_STATE_WARN(intel_crt_port_enabled(dev_priv, PCH_ADPA, &port_pipe) && port_pipe == pipe, @@ -4702,6 +4702,8 @@ static void ironlake_pch_enable(const struct intel_crtc_state *crtc_state) &crtc_state->base.adjusted_mode; u32 bpc = (I915_READ(PIPECONF(pipe)) & PIPECONF_BPC_MASK) >> 5; i915_reg_t reg = TRANS_DP_CTL(pipe); + enum port port; + temp = I915_READ(reg); temp &= ~(TRANS_DP_PORT_SEL_MASK | TRANS_DP_SYNC_MASK | @@ -4714,19 +4716,9 @@ static void ironlake_pch_enable(const struct intel_crtc_state *crtc_state) if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) temp |= TRANS_DP_VSYNC_ACTIVE_HIGH; - switch (intel_trans_dp_port_sel(crtc)) { - case PORT_B: - temp |= TRANS_DP_PORT_SEL_B; - break; - case PORT_C: - temp |= TRANS_DP_PORT_SEL_C; - break; - case PORT_D: - temp |= TRANS_DP_PORT_SEL_D; - break; - default: - BUG(); - } + port = intel_trans_dp_port_sel(crtc); + WARN_ON(port < PORT_B || port > PORT_D); + temp |= TRANS_DP_PORT_SEL(port); I915_WRITE(reg, temp); } -- GitLab From 5a0b385e1cb6a8289e01367710035e18d72794cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Fri, 18 May 2018 18:29:27 +0300 Subject: [PATCH 0088/1506] drm/i915: Nuke intel_trans_dp_port_sel() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit for_each_encoder_on_crtc() is legacy and shouldn't be used by atomic drivers. Let's throw out intel_trans_dp_port_sel() and replace it with intel_get_crtc_new_encoder() which looks the atomic state instead. Since we now have to call intel_get_crtc_new_encoder() during the commit phase we'll need to plumb in the top level atomic state. The crtc_state->state pointers are no longer valid at that point. Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180518152931.13104-3-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula <jani.nikula@intel.com> --- drivers/gpu/drm/i915/intel_display.c | 39 ++++++++++------------------ 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 68d48b7445e90..b60b28feb8649 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4595,17 +4595,17 @@ static void ivybridge_update_fdi_bc_bifurcation(struct intel_crtc *intel_crtc) * used when we know that the CRTC isn't feeding multiple encoders! */ static struct intel_encoder * -intel_get_crtc_new_encoder(const struct intel_crtc_state *crtc_state) +intel_get_crtc_new_encoder(const struct intel_atomic_state *state, + const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); - const struct drm_atomic_state *state = crtc_state->base.state; const struct drm_connector_state *connector_state; const struct drm_connector *connector; struct intel_encoder *encoder = NULL; int num_encoders = 0; int i; - for_each_new_connector_in_state(state, connector, connector_state, i) { + for_each_new_connector_in_state(&state->base, connector, connector_state, i) { if (connector_state->crtc != &crtc->base) continue; @@ -4619,22 +4619,6 @@ intel_get_crtc_new_encoder(const struct intel_crtc_state *crtc_state) return encoder; } -/* Return which DP Port should be selected for Transcoder DP control */ -static enum port -intel_trans_dp_port_sel(struct intel_crtc *crtc) -{ - struct drm_device *dev = crtc->base.dev; - struct intel_encoder *encoder; - - for_each_encoder_on_crtc(dev, &crtc->base, encoder) { - if (encoder->type == INTEL_OUTPUT_DP || - encoder->type == INTEL_OUTPUT_EDP) - return encoder->port; - } - - return -1; -} - /* * Enable PCH resources required for PCH ports: * - PCH PLLs @@ -4643,7 +4627,8 @@ intel_trans_dp_port_sel(struct intel_crtc *crtc) * - DP transcoding bits * - transcoder */ -static void ironlake_pch_enable(const struct intel_crtc_state *crtc_state) +static void ironlake_pch_enable(const struct intel_atomic_state *state, + const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); struct drm_device *dev = crtc->base.dev; @@ -4716,7 +4701,7 @@ static void ironlake_pch_enable(const struct intel_crtc_state *crtc_state) if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) temp |= TRANS_DP_VSYNC_ACTIVE_HIGH; - port = intel_trans_dp_port_sel(crtc); + port = intel_get_crtc_new_encoder(state, crtc_state)->port; WARN_ON(port < PORT_B || port > PORT_D); temp |= TRANS_DP_PORT_SEL(port); @@ -4726,7 +4711,8 @@ static void ironlake_pch_enable(const struct intel_crtc_state *crtc_state) ironlake_enable_pch_transcoder(dev_priv, pipe); } -static void lpt_pch_enable(const struct intel_crtc_state *crtc_state) +static void lpt_pch_enable(const struct intel_atomic_state *state, + const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); @@ -5529,7 +5515,7 @@ static void ironlake_crtc_enable(struct intel_crtc_state *pipe_config, intel_enable_pipe(pipe_config); if (intel_crtc->config->has_pch_encoder) - ironlake_pch_enable(pipe_config); + ironlake_pch_enable(old_intel_state, pipe_config); assert_vblank_disabled(crtc); drm_crtc_vblank_on(crtc); @@ -5668,7 +5654,7 @@ static void haswell_crtc_enable(struct intel_crtc_state *pipe_config, intel_enable_pipe(pipe_config); if (intel_crtc->config->has_pch_encoder) - lpt_pch_enable(pipe_config); + lpt_pch_enable(old_intel_state, pipe_config); if (intel_crtc_has_type(intel_crtc->config, INTEL_OUTPUT_DP_MST)) intel_ddi_set_vc_payload_alloc(pipe_config, true); @@ -9122,9 +9108,12 @@ void hsw_disable_pc8(struct drm_i915_private *dev_priv) static int haswell_crtc_compute_clock(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state) { + struct intel_atomic_state *state = + to_intel_atomic_state(crtc_state->base.state); + if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI)) { struct intel_encoder *encoder = - intel_get_crtc_new_encoder(crtc_state); + intel_get_crtc_new_encoder(state, crtc_state); if (!intel_get_shared_dpll(crtc, crtc_state, encoder)) { DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n", -- GitLab From 59b74c497ae4e9d703307bc9b7b20566588d1ccf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Fri, 18 May 2018 18:29:28 +0300 Subject: [PATCH 0089/1506] drm/i915: Clean up DP pipe select bits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clean up the DP pipe select bits. To make the whole situation a bit less ugly we'll start to share the same code between .get_hw_state(), the port state asserts, and the VLV power sequencer code. v2: Return PIPE_A for cpt/ppt when the port isn't selected by any transcoder. Returning INVALID_PIPE explodes *somewhere* on some machines (can't immediately see where though). This now matches the old behaviour. v3: Order the defines shift,mask,value (Jani) Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180518152931.13104-4-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula <jani.nikula@intel.com> --- drivers/gpu/drm/i915/i915_reg.h | 24 +++--- drivers/gpu/drm/i915/intel_display.c | 46 ++++------- drivers/gpu/drm/i915/intel_dp.c | 113 +++++++++++++++------------ drivers/gpu/drm/i915/intel_drv.h | 3 + 4 files changed, 91 insertions(+), 95 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 5a103496423c7..b888da96caf78 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -5182,10 +5182,15 @@ enum { #define CHV_DP_D _MMIO(VLV_DISPLAY_BASE + 0x64300) #define DP_PORT_EN (1 << 31) -#define DP_PIPEB_SELECT (1 << 30) -#define DP_PIPE_MASK (1 << 30) -#define DP_PIPE_SELECT_CHV(pipe) ((pipe) << 16) -#define DP_PIPE_MASK_CHV (3 << 16) +#define DP_PIPE_SEL_SHIFT 30 +#define DP_PIPE_SEL_MASK (1 << 30) +#define DP_PIPE_SEL(pipe) ((pipe) << 30) +#define DP_PIPE_SEL_SHIFT_IVB 29 +#define DP_PIPE_SEL_MASK_IVB (3 << 29) +#define DP_PIPE_SEL_IVB(pipe) ((pipe) << 29) +#define DP_PIPE_SEL_SHIFT_CHV 16 +#define DP_PIPE_SEL_MASK_CHV (3 << 16) +#define DP_PIPE_SEL_CHV(pipe) ((pipe) << 16) /* Link training mode - select a suitable mode for each stage */ #define DP_LINK_TRAIN_PAT_1 (0 << 28) @@ -7872,16 +7877,6 @@ enum { #define PCH_DP_AUX_CH_DATA(aux_ch, i) _MMIO(_PORT((aux_ch) - AUX_CH_B, _PCH_DPB_AUX_CH_DATA1, _PCH_DPC_AUX_CH_DATA1) + (i) * 4) /* 5 registers */ /* CPT */ -#define PORT_TRANS_A_SEL_CPT 0 -#define PORT_TRANS_B_SEL_CPT (1<<29) -#define PORT_TRANS_C_SEL_CPT (2<<29) -#define PORT_TRANS_SEL_MASK (3<<29) -#define PORT_TRANS_SEL_CPT(pipe) ((pipe) << 29) -#define PORT_TO_PIPE(val) (((val) & (1<<30)) >> 30) -#define PORT_TO_PIPE_CPT(val) (((val) & PORT_TRANS_SEL_MASK) >> 29) -#define SDVO_PORT_TO_PIPE_CHV(val) (((val) & (3<<24)) >> 24) -#define DP_PORT_TO_PIPE_CHV(val) (((val) & (3<<16)) >> 16) - #define _TRANS_DP_CTL_A 0xe0300 #define _TRANS_DP_CTL_B 0xe1300 #define _TRANS_DP_CTL_C 0xe2300 @@ -7890,7 +7885,6 @@ enum { #define TRANS_DP_PORT_SEL_MASK (3 << 29) #define TRANS_DP_PORT_SEL_NONE (3 << 29) #define TRANS_DP_PORT_SEL(port) (((port) - PORT_B) << 29) -#define TRANS_DP_PIPE_TO_PORT(val) ((((val) & TRANS_DP_PORT_SEL_MASK) >> 29) + PORT_B) #define TRANS_DP_AUDIO_ONLY (1<<26) #define TRANS_DP_ENH_FRAMING (1<<18) #define TRANS_DP_8BPC (0<<9) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b60b28feb8649..7126ddf224f6f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1303,38 +1303,22 @@ void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv, pipe_name(pipe)); } -static bool dp_pipe_enabled(struct drm_i915_private *dev_priv, - enum pipe pipe, u32 port_sel, u32 val) +static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv, + enum pipe pipe, enum port port, + i915_reg_t dp_reg) { - if ((val & DP_PORT_EN) == 0) - return false; + enum pipe port_pipe; + bool state; - if (HAS_PCH_CPT(dev_priv)) { - u32 trans_dp_ctl = I915_READ(TRANS_DP_CTL(pipe)); - if ((trans_dp_ctl & TRANS_DP_PORT_SEL_MASK) != port_sel) - return false; - } else if (IS_CHERRYVIEW(dev_priv)) { - if ((val & DP_PIPE_MASK_CHV) != DP_PIPE_SELECT_CHV(pipe)) - return false; - } else { - if ((val & DP_PIPE_MASK) != (pipe << 30)) - return false; - } - return true; -} + state = intel_dp_port_enabled(dev_priv, dp_reg, port, &port_pipe); -static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv, - enum pipe pipe, i915_reg_t reg, - u32 port_sel) -{ - u32 val = I915_READ(reg); - I915_STATE_WARN(dp_pipe_enabled(dev_priv, pipe, port_sel, val), - "PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n", - i915_mmio_reg_offset(reg), pipe_name(pipe)); + I915_STATE_WARN(state && port_pipe == pipe, + "PCH DP %c enabled on transcoder %c, should be disabled\n", + port_name(port), pipe_name(pipe)); - I915_STATE_WARN(HAS_PCH_IBX(dev_priv) && (val & DP_PORT_EN) == 0 - && (val & DP_PIPEB_SELECT), - "IBX PCH dp port still using transcoder B\n"); + I915_STATE_WARN(HAS_PCH_IBX(dev_priv) && !state && port_pipe == PIPE_B, + "IBX PCH DP %c still using transcoder B\n", + port_name(port)); } static void assert_pch_hdmi_disabled(struct drm_i915_private *dev_priv, @@ -1360,9 +1344,9 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv, { enum pipe port_pipe; - assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_B, TRANS_DP_PORT_SEL(PORT_B)); - assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_C, TRANS_DP_PORT_SEL(PORT_C)); - assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_D, TRANS_DP_PORT_SEL(PORT_D)); + assert_pch_dp_disabled(dev_priv, pipe, PORT_B, PCH_DP_B); + assert_pch_dp_disabled(dev_priv, pipe, PORT_C, PCH_DP_C); + assert_pch_dp_disabled(dev_priv, pipe, PORT_D, PCH_DP_D); I915_STATE_WARN(intel_crt_port_enabled(dev_priv, PCH_ADPA, &port_pipe) && port_pipe == pipe, diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index be99e56cf7d91..b7d3cf27d5e23 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -529,9 +529,9 @@ vlv_power_sequencer_kick(struct intel_dp *intel_dp) DP |= DP_LINK_TRAIN_PAT_1; if (IS_CHERRYVIEW(dev_priv)) - DP |= DP_PIPE_SELECT_CHV(pipe); - else if (pipe == PIPE_B) - DP |= DP_PIPEB_SELECT; + DP |= DP_PIPE_SEL_CHV(pipe); + else + DP |= DP_PIPE_SEL(pipe); pll_enabled = I915_READ(DPLL(pipe)) & DPLL_VCO_ENABLE; @@ -1974,7 +1974,7 @@ static void intel_dp_prepare(struct intel_encoder *encoder, if (drm_dp_enhanced_frame_cap(intel_dp->dpcd)) intel_dp->DP |= DP_ENHANCED_FRAMING; - intel_dp->DP |= crtc->pipe << 29; + intel_dp->DP |= DP_PIPE_SEL_IVB(crtc->pipe); } else if (HAS_PCH_CPT(dev_priv) && port != PORT_A) { u32 trans_dp; @@ -2000,9 +2000,9 @@ static void intel_dp_prepare(struct intel_encoder *encoder, intel_dp->DP |= DP_ENHANCED_FRAMING; if (IS_CHERRYVIEW(dev_priv)) - intel_dp->DP |= DP_PIPE_SELECT_CHV(crtc->pipe); - else if (crtc->pipe == PIPE_B) - intel_dp->DP |= DP_PIPEB_SELECT; + intel_dp->DP |= DP_PIPE_SEL_CHV(crtc->pipe); + else + intel_dp->DP |= DP_PIPE_SEL(crtc->pipe); } } @@ -2624,52 +2624,66 @@ void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode) mode == DRM_MODE_DPMS_ON ? "enable" : "disable"); } +static bool cpt_dp_port_selected(struct drm_i915_private *dev_priv, + enum port port, enum pipe *pipe) +{ + enum pipe p; + + for_each_pipe(dev_priv, p) { + u32 val = I915_READ(TRANS_DP_CTL(p)); + + if ((val & TRANS_DP_PORT_SEL_MASK) == TRANS_DP_PORT_SEL(port)) { + *pipe = p; + return true; + } + } + + DRM_DEBUG_KMS("No pipe for DP port %c found\n", port_name(port)); + + /* must initialize pipe to something for the asserts */ + *pipe = PIPE_A; + + return false; +} + +bool intel_dp_port_enabled(struct drm_i915_private *dev_priv, + i915_reg_t dp_reg, enum port port, + enum pipe *pipe) +{ + bool ret; + u32 val; + + val = I915_READ(dp_reg); + + ret = val & DP_PORT_EN; + + /* asserts want to know the pipe even if the port is disabled */ + if (IS_IVYBRIDGE(dev_priv) && port == PORT_A) + *pipe = (val & DP_PIPE_SEL_MASK_IVB) >> DP_PIPE_SEL_SHIFT_IVB; + else if (HAS_PCH_CPT(dev_priv) && port != PORT_A) + ret &= cpt_dp_port_selected(dev_priv, port, pipe); + else if (IS_CHERRYVIEW(dev_priv)) + *pipe = (val & DP_PIPE_SEL_MASK_CHV) >> DP_PIPE_SEL_SHIFT_CHV; + else + *pipe = (val & DP_PIPE_SEL_MASK) >> DP_PIPE_SEL_SHIFT; + + return ret; +} + static bool intel_dp_get_hw_state(struct intel_encoder *encoder, enum pipe *pipe) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); - enum port port = encoder->port; - u32 tmp; bool ret; if (!intel_display_power_get_if_enabled(dev_priv, encoder->power_domain)) return false; - ret = false; + ret = intel_dp_port_enabled(dev_priv, intel_dp->output_reg, + encoder->port, pipe); - tmp = I915_READ(intel_dp->output_reg); - - if (!(tmp & DP_PORT_EN)) - goto out; - - if (IS_IVYBRIDGE(dev_priv) && port == PORT_A) { - *pipe = PORT_TO_PIPE_CPT(tmp); - } else if (HAS_PCH_CPT(dev_priv) && port != PORT_A) { - enum pipe p; - - for_each_pipe(dev_priv, p) { - u32 trans_dp = I915_READ(TRANS_DP_CTL(p)); - if (TRANS_DP_PIPE_TO_PORT(trans_dp) == port) { - *pipe = p; - ret = true; - - goto out; - } - } - - DRM_DEBUG_KMS("No pipe for dp port 0x%x found\n", - i915_mmio_reg_offset(intel_dp->output_reg)); - } else if (IS_CHERRYVIEW(dev_priv)) { - *pipe = DP_PORT_TO_PIPE_CHV(tmp); - } else { - *pipe = PORT_TO_PIPE(tmp); - } - - ret = true; - -out: intel_display_power_put(dev_priv, encoder->power_domain); return ret; @@ -3659,8 +3673,9 @@ intel_dp_link_down(struct intel_encoder *encoder, intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, false); /* always enable with pattern 1 (as per spec) */ - DP &= ~(DP_PIPEB_SELECT | DP_LINK_TRAIN_MASK); - DP |= DP_PORT_EN | DP_LINK_TRAIN_PAT_1; + DP &= ~(DP_PIPE_SEL_MASK | DP_LINK_TRAIN_MASK); + DP |= DP_PORT_EN | DP_PIPE_SEL(PIPE_A) | + DP_LINK_TRAIN_PAT_1; I915_WRITE(intel_dp->output_reg, DP); POSTING_READ(intel_dp->output_reg); @@ -5295,14 +5310,14 @@ static void intel_edp_panel_vdd_sanitize(struct intel_dp *intel_dp) static enum pipe vlv_active_pipe(struct intel_dp *intel_dp) { struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; + enum pipe pipe; - if ((intel_dp->DP & DP_PORT_EN) == 0) - return INVALID_PIPE; + if (intel_dp_port_enabled(dev_priv, intel_dp->output_reg, + encoder->port, &pipe)) + return pipe; - if (IS_CHERRYVIEW(dev_priv)) - return DP_PORT_TO_PIPE_CHV(intel_dp->DP); - else - return PORT_TO_PIPE(intel_dp->DP); + return INVALID_PIPE; } void intel_dp_encoder_reset(struct drm_encoder *encoder) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index e919e0099ad68..2855363f5b6cc 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1645,6 +1645,9 @@ void intel_csr_ucode_suspend(struct drm_i915_private *); void intel_csr_ucode_resume(struct drm_i915_private *); /* intel_dp.c */ +bool intel_dp_port_enabled(struct drm_i915_private *dev_priv, + i915_reg_t dp_reg, enum port port, + enum pipe *pipe); bool intel_dp_init(struct drm_i915_private *dev_priv, i915_reg_t output_reg, enum port port); bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port, -- GitLab From 05bf51d3b5750f3b47c241e094b9c2230a9c1a93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Fri, 18 May 2018 18:29:29 +0300 Subject: [PATCH 0090/1506] drm/i915: Allow eDP on port C in theory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The power sequencer has bits to allow DP C to be used for eDP. Currently we assume this will never happen, but I guess it could theoretically be a thing. Make the code do the right thing in that case, and toss in a MISSING_CASE() for any other port. Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180518152931.13104-5-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula <jani.nikula@intel.com> --- drivers/gpu/drm/i915/intel_dp.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index b7d3cf27d5e23..ce07bd794aed5 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -5712,10 +5712,20 @@ intel_dp_init_panel_power_sequencer_registers(struct intel_dp *intel_dp, if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { port_sel = PANEL_PORT_SELECT_VLV(port); } else if (HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv)) { - if (port == PORT_A) + switch (port) { + case PORT_A: port_sel = PANEL_PORT_SELECT_DPA; - else + break; + case PORT_C: + port_sel = PANEL_PORT_SELECT_DPC; + break; + case PORT_D: port_sel = PANEL_PORT_SELECT_DPD; + break; + default: + MISSING_CASE(port); + break; + } } pp_on |= port_sel; -- GitLab From 4c23dea48b0d8d9da2ac0911f8cee105f4394281 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Fri, 18 May 2018 18:29:30 +0300 Subject: [PATCH 0091/1506] drm/i915: Implement the missing bits of assert_panel_unlocked() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the missing eDP port handling into assert_panel_unlocked(). We now have intel_dp_port_enabled() which makes this trivial. Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180518152931.13104-6-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula <jani.nikula@intel.com> --- drivers/gpu/drm/i915/intel_display.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 7126ddf224f6f..3a0709a6e4a0b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1214,9 +1214,23 @@ void assert_panel_unlocked(struct drm_i915_private *dev_priv, enum pipe pipe) pp_reg = PP_CONTROL(0); port_sel = I915_READ(PP_ON_DELAYS(0)) & PANEL_PORT_SELECT_MASK; - if (port_sel == PANEL_PORT_SELECT_LVDS) + switch (port_sel) { + case PANEL_PORT_SELECT_LVDS: intel_lvds_port_enabled(dev_priv, PCH_LVDS, &panel_pipe); - /* XXX: else fix for eDP */ + break; + case PANEL_PORT_SELECT_DPA: + intel_dp_port_enabled(dev_priv, DP_A, PORT_A, &panel_pipe); + break; + case PANEL_PORT_SELECT_DPC: + intel_dp_port_enabled(dev_priv, PCH_DP_C, PORT_C, &panel_pipe); + break; + case PANEL_PORT_SELECT_DPD: + intel_dp_port_enabled(dev_priv, PCH_DP_D, PORT_D, &panel_pipe); + break; + default: + MISSING_CASE(port_sel); + break; + } } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { /* presumably write lock depends on pipe, not port select */ pp_reg = PP_CONTROL(pipe); -- GitLab From f0d2b758e05e209f4572182afade180cda22c9c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Fri, 18 May 2018 18:29:31 +0300 Subject: [PATCH 0092/1506] drm/i915: WARN if power sequencer is not connected to the LVDS port on pre-ilk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don't support using the power sequencer with other ports besides LVDS on pre-ilk platforms. WARN if someone has mistakenly connected the power sequencer to the wrong port. Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180518152931.13104-7-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula <jani.nikula@intel.com> --- drivers/gpu/drm/i915/intel_display.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3a0709a6e4a0b..aab1c6c58edf6 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1236,7 +1236,12 @@ void assert_panel_unlocked(struct drm_i915_private *dev_priv, enum pipe pipe) pp_reg = PP_CONTROL(pipe); panel_pipe = pipe; } else { + u32 port_sel; + pp_reg = PP_CONTROL(0); + port_sel = I915_READ(PP_ON_DELAYS(0)) & PANEL_PORT_SELECT_MASK; + + WARN_ON(port_sel != PANEL_PORT_SELECT_LVDS); intel_lvds_port_enabled(dev_priv, LVDS, &panel_pipe); } -- GitLab From 4a774ee35c9f57feaf332b252ecb2d4275521c8a Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Wed, 23 May 2018 15:23:46 +0100 Subject: [PATCH 0093/1506] drm/i915/selftests: Pin the mock kernel context The driver assumes that the kernel context is pinned and always available for use from any process or atomic context. Make it so for selftesting as well! Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180523142346.27953-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/selftests/mock_engine.c | 7 +++++++ .../gpu/drm/i915/selftests/mock_gem_device.c | 17 +++++++---------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/selftests/mock_engine.c b/drivers/gpu/drm/i915/selftests/mock_engine.c index f1ac7453053e4..c2a0451336cf5 100644 --- a/drivers/gpu/drm/i915/selftests/mock_engine.c +++ b/drivers/gpu/drm/i915/selftests/mock_engine.c @@ -212,8 +212,13 @@ struct intel_engine_cs *mock_engine(struct drm_i915_private *i915, if (!engine->base.buffer) goto err_breadcrumbs; + if (IS_ERR(intel_context_pin(i915->kernel_context, &engine->base))) + goto err_ring; + return &engine->base; +err_ring: + mock_ring_free(engine->base.buffer); err_breadcrumbs: intel_engine_fini_breadcrumbs(&engine->base); i915_timeline_fini(&engine->base.timeline); @@ -254,6 +259,8 @@ void mock_engine_free(struct intel_engine_cs *engine) if (ce) intel_context_unpin(ce); + __intel_context_unpin(engine->i915->kernel_context, engine); + mock_ring_free(engine->buffer); intel_engine_fini_breadcrumbs(engine); diff --git a/drivers/gpu/drm/i915/selftests/mock_gem_device.c b/drivers/gpu/drm/i915/selftests/mock_gem_device.c index 94baedfa0f745..c97075c5ccafa 100644 --- a/drivers/gpu/drm/i915/selftests/mock_gem_device.c +++ b/drivers/gpu/drm/i915/selftests/mock_gem_device.c @@ -136,8 +136,6 @@ static struct dev_pm_domain pm_domain = { struct drm_i915_private *mock_gem_device(void) { struct drm_i915_private *i915; - struct intel_engine_cs *engine; - enum intel_engine_id id; struct pci_dev *pdev; int err; @@ -233,13 +231,13 @@ struct drm_i915_private *mock_gem_device(void) mock_init_ggtt(i915); mkwrite_device_info(i915)->ring_mask = BIT(0); - i915->engine[RCS] = mock_engine(i915, "mock", RCS); - if (!i915->engine[RCS]) - goto err_unlock; - i915->kernel_context = mock_context(i915, NULL); if (!i915->kernel_context) - goto err_engine; + goto err_unlock; + + i915->engine[RCS] = mock_engine(i915, "mock", RCS); + if (!i915->engine[RCS]) + goto err_context; mutex_unlock(&i915->drm.struct_mutex); @@ -247,9 +245,8 @@ struct drm_i915_private *mock_gem_device(void) return i915; -err_engine: - for_each_engine(engine, i915, id) - mock_engine_free(engine); +err_context: + i915_gem_contexts_fini(i915); err_unlock: mutex_unlock(&i915->drm.struct_mutex); kmem_cache_destroy(i915->priorities); -- GitLab From c894d63c6b36de20f0248d88801be5ace8e6bee8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= <jose.souza@intel.com> Date: Fri, 18 May 2018 13:15:47 -0700 Subject: [PATCH 0094/1506] drm/i915/icl: Disable pipe CSC and gamma in cursor plane MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 'Pipe CSC enable' bit is more than just deprecated in ICL+, it was disabled in commit 077ef1f09c25 ("drm/i915/icl: Don't set pipe CSC/Gamma in PLANE_COLOR_CTL") for primary and sprite planes as it was causing those planes to be rendered as always black but it was not disabled in cursor plane, also causing it to be rendered as black. As mentioned in the commit referenced above, this is a workaround too and the CSC and gamma per plane values needs to be setup before enable CSC and gamma again. BSpec: 4278 and 7635 Cc: James Ausmus <james.ausmus@intel.com> Cc: Paulo Zanoni <paulo.r.zanoni@intel.com> Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Signed-off-by: José Roberto de Souza <jose.souza@intel.com> Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180518201547.15793-1-jose.souza@intel.com --- drivers/gpu/drm/i915/intel_display.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index aab1c6c58edf6..8b385176ce3c3 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9687,12 +9687,14 @@ static u32 i9xx_cursor_ctl(const struct intel_crtc_state *crtc_state, struct drm_i915_private *dev_priv = to_i915(plane_state->base.plane->dev); struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); - u32 cntl; + u32 cntl = 0; - cntl = MCURSOR_GAMMA_ENABLE; + if (INTEL_GEN(dev_priv) <= 10) { + cntl |= MCURSOR_GAMMA_ENABLE; - if (HAS_DDI(dev_priv)) - cntl |= CURSOR_PIPE_CSC_ENABLE; + if (HAS_DDI(dev_priv)) + cntl |= CURSOR_PIPE_CSC_ENABLE; + } if (INTEL_GEN(dev_priv) < 5 && !IS_G4X(dev_priv)) cntl |= MCURSOR_PIPE_SELECT(crtc->pipe); -- GitLab From 1e40d4aea57bbbd277777dd1fe18599dd77c55ab Mon Sep 17 00:00:00 2001 From: Yunwei Zhang <yunwei.zhang@intel.com> Date: Fri, 18 May 2018 15:39:57 -0700 Subject: [PATCH 0095/1506] drm/i915/cnl: Implement WaProgramMgsrForCorrectSliceSpecificMmioReads WaProgramMgsrForCorrectSliceSpecificMmioReads dictate that before any MMIO read into Slice/Subslice specific registers, MCR packet control register(0xFDC) needs to be programmed to point to any enabled slice/subslice pair. Otherwise, incorrect value will be returned. However, that means each subsequent MMIO read will be forwarded to a specific slice/subslice combination as read is unicast. This is OK since slice/subslice specific register values are consistent in almost all cases across slice/subslice. There are rare occasions such as INSTDONE that this value will be dependent on slice/subslice combo, in such cases, we need to program 0xFDC and recover this after. This is already covered by read_subslice_reg. Also, 0xFDC will lose its information after TDR/engine reset/power state change. References: HSD#1405586840, BSID#0575 v2: - use fls() instead of find_last_bit() (Chris) - added INTEL_SSEU to extract sseu from device info. (Chris) v3: - rebase on latest tip v5: - Added references (Mika) - Change the ordered of passing arguments and etc. (Ursulin) v7: - Moved WA explanation Comments(Oscar) - Rebased. v8: - Renamed sanitize_mcr to calculate_s_ss_select. (Oscar) - calculate s/ss selector instead of whole mcr. (Oscar) v9: - Updated function name (Oscar) - Remove redundant variables (Oscar) v10: - Separate pre-GEN10 and GEN11 mask. (Oscar) Cc: Oscar Mateo <oscar.mateo@intel.com> Cc: Michel Thierry <michel.thierry@intel.com> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Chris Wilson <chris@chris-wilson.co.uk> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com> Signed-off-by: Yunwei Zhang <yunwei.zhang@intel.com> Reviewed-by: Oscar Mateo <oscar.mateo@intel.com> Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/1526683197-24656-1-git-send-email-yunwei.zhang@intel.com --- drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/intel_engine_cs.c | 30 ++++++++++++++++++++---- drivers/gpu/drm/i915/intel_workarounds.c | 27 +++++++++++++++++++++ 3 files changed, 54 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b86ed6401120e..1b8bd84f07995 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2743,6 +2743,8 @@ int vlv_force_gfx_clock(struct drm_i915_private *dev_priv, bool on); int intel_engines_init_mmio(struct drm_i915_private *dev_priv); int intel_engines_init(struct drm_i915_private *dev_priv); +u32 intel_calculate_mcr_s_ss_select(struct drm_i915_private *dev_priv); + /* intel_hotplug.c */ void intel_hpd_irq_handler(struct drm_i915_private *dev_priv, u32 pin_mask, u32 long_mask); diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index 0c1f084ee5936..ad28680390b8d 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -819,12 +819,29 @@ const char *i915_cache_level_str(struct drm_i915_private *i915, int type) } } +u32 intel_calculate_mcr_s_ss_select(struct drm_i915_private *dev_priv) +{ + const struct sseu_dev_info *sseu = &(INTEL_INFO(dev_priv)->sseu); + u32 mcr_s_ss_select; + u32 slice = fls(sseu->slice_mask); + u32 subslice = fls(sseu->subslice_mask[slice]); + + if (INTEL_GEN(dev_priv) == 10) + mcr_s_ss_select = GEN8_MCR_SLICE(slice) | + GEN8_MCR_SUBSLICE(subslice); + else + mcr_s_ss_select = 0; + + return mcr_s_ss_select; +} + static inline uint32_t read_subslice_reg(struct drm_i915_private *dev_priv, int slice, int subslice, i915_reg_t reg) { uint32_t mcr_slice_subslice_mask; uint32_t mcr_slice_subslice_select; + uint32_t default_mcr_s_ss_select; uint32_t mcr; uint32_t ret; enum forcewake_domains fw_domains; @@ -841,6 +858,8 @@ read_subslice_reg(struct drm_i915_private *dev_priv, int slice, GEN8_MCR_SUBSLICE(subslice); } + default_mcr_s_ss_select = intel_calculate_mcr_s_ss_select(dev_priv); + fw_domains = intel_uncore_forcewake_for_reg(dev_priv, reg, FW_REG_READ); fw_domains |= intel_uncore_forcewake_for_reg(dev_priv, @@ -851,11 +870,10 @@ read_subslice_reg(struct drm_i915_private *dev_priv, int slice, intel_uncore_forcewake_get__locked(dev_priv, fw_domains); mcr = I915_READ_FW(GEN8_MCR_SELECTOR); - /* - * The HW expects the slice and sublice selectors to be reset to 0 - * after reading out the registers. - */ - WARN_ON_ONCE(mcr & mcr_slice_subslice_mask); + + WARN_ON_ONCE((mcr & mcr_slice_subslice_mask) != + default_mcr_s_ss_select); + mcr &= ~mcr_slice_subslice_mask; mcr |= mcr_slice_subslice_select; I915_WRITE_FW(GEN8_MCR_SELECTOR, mcr); @@ -863,6 +881,8 @@ read_subslice_reg(struct drm_i915_private *dev_priv, int slice, ret = I915_READ_FW(reg); mcr &= ~mcr_slice_subslice_mask; + mcr |= default_mcr_s_ss_select; + I915_WRITE_FW(GEN8_MCR_SELECTOR, mcr); intel_uncore_forcewake_put__locked(dev_priv, fw_domains); diff --git a/drivers/gpu/drm/i915/intel_workarounds.c b/drivers/gpu/drm/i915/intel_workarounds.c index 2df3538ceba54..720d8635c2cf2 100644 --- a/drivers/gpu/drm/i915/intel_workarounds.c +++ b/drivers/gpu/drm/i915/intel_workarounds.c @@ -672,8 +672,35 @@ static void cfl_gt_workarounds_apply(struct drm_i915_private *dev_priv) GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS); } +static void wa_init_mcr(struct drm_i915_private *dev_priv) +{ + u32 mcr; + u32 mcr_slice_subslice_mask; + + mcr = I915_READ(GEN8_MCR_SELECTOR); + + mcr_slice_subslice_mask = GEN8_MCR_SLICE_MASK | + GEN8_MCR_SUBSLICE_MASK; + /* + * WaProgramMgsrForCorrectSliceSpecificMmioReads:cnl + * Before any MMIO read into slice/subslice specific registers, MCR + * packet control register needs to be programmed to point to any + * enabled s/ss pair. Otherwise, incorrect values will be returned. + * This means each subsequent MMIO read will be forwarded to an + * specific s/ss combination, but this is OK since these registers + * are consistent across s/ss in almost all cases. In the rare + * occasions, such as INSTDONE, where this value is dependent + * on s/ss combo, the read should be done with read_subslice_reg. + */ + mcr &= ~mcr_slice_subslice_mask; + mcr |= intel_calculate_mcr_s_ss_select(dev_priv); + I915_WRITE(GEN8_MCR_SELECTOR, mcr); +} + static void cnl_gt_workarounds_apply(struct drm_i915_private *dev_priv) { + wa_init_mcr(dev_priv); + /* WaDisableI2mCycleOnWRPort:cnl (pre-prod) */ if (IS_CNL_REVID(dev_priv, CNL_REVID_B0, CNL_REVID_B0)) I915_WRITE(GAMT_CHKN_BIT_REG, -- GitLab From d78fa508f08d7d91d8ce9e2cec1f04bd2d63f0a1 Mon Sep 17 00:00:00 2001 From: Yunwei Zhang <yunwei.zhang@intel.com> Date: Fri, 18 May 2018 15:40:32 -0700 Subject: [PATCH 0096/1506] drm/i915/icl: Enable WaProgramMgsrForCorrectSliceSpecificMmioReads WaProgramMgsrForCorrectSliceSpecificMmioReads applies for Icelake as well. References: HSD#1405586840, BSID#0575 v2: - GEN11 mask is different from its predecessors. (Oscar) - Better separate GEN10 and GEN11. (Oscar) Cc: Oscar Mateo <oscar.mateo@intel.com> Cc: Michel Thierry <michel.thierry@intel.com> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Chris Wilson <chris@chris-wilson.co.uk> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com> Signed-off-by: Yunwei Zhang <yunwei.zhang@intel.com> Reviewed-by: Oscar Mateo <oscar.mateo@intel.com> Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/1526683232-24753-1-git-send-email-yunwei.zhang@intel.com --- drivers/gpu/drm/i915/intel_engine_cs.c | 3 +++ drivers/gpu/drm/i915/intel_workarounds.c | 12 +++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index ad28680390b8d..13448ea76f57b 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -829,6 +829,9 @@ u32 intel_calculate_mcr_s_ss_select(struct drm_i915_private *dev_priv) if (INTEL_GEN(dev_priv) == 10) mcr_s_ss_select = GEN8_MCR_SLICE(slice) | GEN8_MCR_SUBSLICE(subslice); + else if (INTEL_GEN(dev_priv) >= 11) + mcr_s_ss_select = GEN11_MCR_SLICE(slice) | + GEN11_MCR_SUBSLICE(subslice); else mcr_s_ss_select = 0; diff --git a/drivers/gpu/drm/i915/intel_workarounds.c b/drivers/gpu/drm/i915/intel_workarounds.c index 720d8635c2cf2..2deec58e97dde 100644 --- a/drivers/gpu/drm/i915/intel_workarounds.c +++ b/drivers/gpu/drm/i915/intel_workarounds.c @@ -679,10 +679,14 @@ static void wa_init_mcr(struct drm_i915_private *dev_priv) mcr = I915_READ(GEN8_MCR_SELECTOR); - mcr_slice_subslice_mask = GEN8_MCR_SLICE_MASK | - GEN8_MCR_SUBSLICE_MASK; + if (INTEL_GEN(dev_priv) >= 11) + mcr_slice_subslice_mask = GEN11_MCR_SLICE_MASK | + GEN11_MCR_SUBSLICE_MASK; + else + mcr_slice_subslice_mask = GEN8_MCR_SLICE_MASK | + GEN8_MCR_SUBSLICE_MASK; /* - * WaProgramMgsrForCorrectSliceSpecificMmioReads:cnl + * WaProgramMgsrForCorrectSliceSpecificMmioReads:cnl,icl * Before any MMIO read into slice/subslice specific registers, MCR * packet control register needs to be programmed to point to any * enabled s/ss pair. Otherwise, incorrect values will be returned. @@ -719,6 +723,8 @@ static void cnl_gt_workarounds_apply(struct drm_i915_private *dev_priv) static void icl_gt_workarounds_apply(struct drm_i915_private *dev_priv) { + wa_init_mcr(dev_priv); + /* This is not an Wa. Enable for better image quality */ I915_WRITE(_3D_CHICKEN3, _MASKED_BIT_ENABLE(_3D_CHICKEN3_AA_LINE_QUALITY_FIX_ENABLE)); -- GitLab From fe864b76c2ab9503b4ff90d5d8785716a0b8d815 Mon Sep 17 00:00:00 2001 From: Yunwei Zhang <yunwei.zhang@intel.com> Date: Fri, 18 May 2018 15:41:25 -0700 Subject: [PATCH 0097/1506] drm/i915: Implement WaProgramMgsrForL3BankSpecificMmioReads L3Bank could be fused off in hardware for debug purpose, and it is possible that subslice is enabled while its corresponding L3Bank pairs are disabled. In such case, if MCR packet control register(0xFDC) is programed to point to a disabled bank pair, a MMIO read into L3Bank range will return 0 instead of correct values. However, this is not going to be the case in any production silicon. Therefore, we only check at initialization and issue a warning should this really happen. References: HSDES#1405586840 v2: - use fls instead of find_last_bit (Chris) - use is_power_of_2() instead of counting bit set (Chris) v3: - rebase on latest tip v5: - Added references (Mika) - Move local variable into scope where they are used (Ursulin) - use a new local variable to reduce long line of code (Ursulin) v6: - Some coding style and use more local variables for clearer logic (Ursulin) Cc: Oscar Mateo <oscar.mateo@intel.com> Cc: Michel Thierry <michel.thierry@intel.com> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Chris Wilson <chris@chris-wilson.co.uk> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com> Signed-off-by: Yunwei Zhang <yunwei.zhang@intel.com> Reviewed-by: Oscar Mateo <oscar.mateo@intel.com> Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/1526683285-24861-1-git-send-email-yunwei.zhang@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 4 +++ drivers/gpu/drm/i915/intel_workarounds.c | 35 ++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index b888da96caf78..d52a11c2c73cb 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2709,6 +2709,10 @@ enum i915_power_well_id { #define GEN10_F2_SS_DIS_SHIFT 18 #define GEN10_F2_SS_DIS_MASK (0xf << GEN10_F2_SS_DIS_SHIFT) +#define GEN10_MIRROR_FUSE3 _MMIO(0x9118) +#define GEN10_L3BANK_PAIR_COUNT 4 +#define GEN10_L3BANK_MASK 0x0F + #define GEN8_EU_DISABLE0 _MMIO(0x9134) #define GEN8_EU_DIS0_S0_MASK 0xffffff #define GEN8_EU_DIS0_S1_SHIFT 24 diff --git a/drivers/gpu/drm/i915/intel_workarounds.c b/drivers/gpu/drm/i915/intel_workarounds.c index 2deec58e97dde..cea57104de134 100644 --- a/drivers/gpu/drm/i915/intel_workarounds.c +++ b/drivers/gpu/drm/i915/intel_workarounds.c @@ -674,9 +674,44 @@ static void cfl_gt_workarounds_apply(struct drm_i915_private *dev_priv) static void wa_init_mcr(struct drm_i915_private *dev_priv) { + const struct sseu_dev_info *sseu = &(INTEL_INFO(dev_priv)->sseu); u32 mcr; u32 mcr_slice_subslice_mask; + /* + * WaProgramMgsrForL3BankSpecificMmioReads: cnl,icl + * L3Banks could be fused off in single slice scenario. If that is + * the case, we might need to program MCR select to a valid L3Bank + * by default, to make sure we correctly read certain registers + * later on (in the range 0xB100 - 0xB3FF). + * This might be incompatible with + * WaProgramMgsrForCorrectSliceSpecificMmioReads. + * Fortunately, this should not happen in production hardware, so + * we only assert that this is the case (instead of implementing + * something more complex that requires checking the range of every + * MMIO read). + */ + if (INTEL_GEN(dev_priv) >= 10 && + is_power_of_2(sseu->slice_mask)) { + /* + * read FUSE3 for enabled L3 Bank IDs, if L3 Bank matches + * enabled subslice, no need to redirect MCR packet + */ + u32 slice = fls(sseu->slice_mask); + u32 fuse3 = I915_READ(GEN10_MIRROR_FUSE3); + u8 ss_mask = sseu->subslice_mask[slice]; + + u8 enabled_mask = (ss_mask | ss_mask >> + GEN10_L3BANK_PAIR_COUNT) & GEN10_L3BANK_MASK; + u8 disabled_mask = fuse3 & GEN10_L3BANK_MASK; + + /* + * Production silicon should have matched L3Bank and + * subslice enabled + */ + WARN_ON((enabled_mask & disabled_mask) != enabled_mask); + } + mcr = I915_READ(GEN8_MCR_SELECTOR); if (INTEL_GEN(dev_priv) >= 11) -- GitLab From 1d1a4f6dd1645fba6533c7884582006d13664748 Mon Sep 17 00:00:00 2001 From: Souptick Joarder <jrdr.linux@gmail.com> Date: Mon, 16 Apr 2018 20:32:32 +0530 Subject: [PATCH 0098/1506] gpu: drm: vgem: Change return type to vm_fault_t Use new return type vm_fault_t for fault handler. Signed-off-by: Souptick Joarder <jrdr.linux@gmail.com> Reviewed-by: Matthew Wilcox <mawilcox@microsoft.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180416150232.GA26745@jordon-HP-15-Notebook-PC --- drivers/gpu/drm/vgem/vgem_drv.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/vgem/vgem_drv.c b/drivers/gpu/drm/vgem/vgem_drv.c index 2524ff116f00d..c64a85950c829 100644 --- a/drivers/gpu/drm/vgem/vgem_drv.c +++ b/drivers/gpu/drm/vgem/vgem_drv.c @@ -61,13 +61,13 @@ static void vgem_gem_free_object(struct drm_gem_object *obj) kfree(vgem_obj); } -static int vgem_gem_fault(struct vm_fault *vmf) +static vm_fault_t vgem_gem_fault(struct vm_fault *vmf) { struct vm_area_struct *vma = vmf->vma; struct drm_vgem_gem_object *obj = vma->vm_private_data; /* We don't use vmf->pgoff since that has the fake offset */ unsigned long vaddr = vmf->address; - int ret; + vm_fault_t ret = VM_FAULT_SIGBUS; loff_t num_pages; pgoff_t page_offset; page_offset = (vaddr - vma->vm_start) >> PAGE_SHIFT; @@ -77,7 +77,6 @@ static int vgem_gem_fault(struct vm_fault *vmf) if (page_offset > num_pages) return VM_FAULT_SIGBUS; - ret = -ENOENT; mutex_lock(&obj->pages_lock); if (obj->pages) { get_page(obj->pages[page_offset]); -- GitLab From 77312ae8f071fb389d9982ce743b72975990c4d9 Mon Sep 17 00:00:00 2001 From: Vathsala Nagaraju <vathsala.nagaraju@intel.com> Date: Tue, 22 May 2018 14:57:23 +0530 Subject: [PATCH 0099/1506] drm/i915/psr: vbt change for psr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For psr block #9, the vbt description has moved to options [0-3] for TP1,TP2,TP3 Wakeup time from decimal value without any change to vbt structure. Since spec does not mention from which VBT version this change was added to vbt.bsf file, we cannot depend on bdb->version check to change for all the platforms. There is RCR inplace for GOP team to provide the version number to make generic change. Since Kabylake with bdb version 209 is having this change, limiting this change to gen9_bc and version 209+ to unblock google. Tested on skl(bdb version 203,without options) and kabylake(bdb version 209,212) having new options. bspec 20131 v2: (Jani and Rodrigo) move the 165 version check to intel_bios.c v3: Jani Move the abstraction to intel_bios. v4: Jani Rename tp*_wakeup_time to have "us" suffix. For values outside range[0-3],default to max 2500us. Old decimal value was wake up time in multiples of 100us. v5: Jani and Rodrigo Handle option 2 in default condition. Print oustide range value. For negetive values default to 2500us. v6: Jani Handle default first and then fall through for case 2. v7: Rodrigo Apply this change for IS_GEN9_BC and vbt version > 209 v8: Puthik Add new function vbt_psr_to_us. v9: Jani Change to v7 version as it's more readable. DK add comment /*fall through*/ after case2. Cc: Rodrigo Vivi <rodrigo.vivi@intel.com> Cc: Puthikorn Voravootivat <puthik@chromium.org> Cc: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Cc: Jani Nikula <jani.nikula@intel.com> Cc: José Roberto de Souza <jose.souza@intel.com> Signed-off-by: Maulik V Vaghela <maulik.v.vaghela@intel.com> Signed-off-by: Vathsala Nagaraju <vathsala.nagaraju@intel.com> Reviewed-by: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/1526981243-2745-1-git-send-email-vathsala.nagaraju@intel.com --- drivers/gpu/drm/i915/i915_drv.h | 4 +-- drivers/gpu/drm/i915/i915_reg.h | 8 +++--- drivers/gpu/drm/i915/intel_bios.c | 48 +++++++++++++++++++++++++++++-- drivers/gpu/drm/i915/intel_psr.c | 39 +++++++++++++------------ 4 files changed, 72 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 1b8bd84f07995..a7a563ed0fd8b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1077,8 +1077,8 @@ struct intel_vbt_data { bool require_aux_wakeup; int idle_frames; enum psr_lines_to_wait lines_to_wait; - int tp1_wakeup_time; - int tp2_tp3_wakeup_time; + int tp1_wakeup_time_us; + int tp2_tp3_wakeup_time_us; } psr; struct { diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index d52a11c2c73cb..6953419881c48 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4092,10 +4092,10 @@ enum { #define EDP_Y_COORDINATE_ENABLE (1<<25) /* GLK and CNL+ */ #define EDP_MAX_SU_DISABLE_TIME(t) ((t)<<20) #define EDP_MAX_SU_DISABLE_TIME_MASK (0x1f<<20) -#define EDP_PSR2_TP2_TIME_500 (0<<8) -#define EDP_PSR2_TP2_TIME_100 (1<<8) -#define EDP_PSR2_TP2_TIME_2500 (2<<8) -#define EDP_PSR2_TP2_TIME_50 (3<<8) +#define EDP_PSR2_TP2_TIME_500us (0<<8) +#define EDP_PSR2_TP2_TIME_100us (1<<8) +#define EDP_PSR2_TP2_TIME_2500us (2<<8) +#define EDP_PSR2_TP2_TIME_50us (3<<8) #define EDP_PSR2_TP2_TIME_MASK (3<<8) #define EDP_PSR2_FRAME_BEFORE_SU_SHIFT 4 #define EDP_PSR2_FRAME_BEFORE_SU_MASK (0xf<<4) diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 34c805970d7ce..ea7ae8bc0ea0e 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -684,8 +684,52 @@ parse_psr(struct drm_i915_private *dev_priv, const struct bdb_header *bdb) break; } - dev_priv->vbt.psr.tp1_wakeup_time = psr_table->tp1_wakeup_time; - dev_priv->vbt.psr.tp2_tp3_wakeup_time = psr_table->tp2_tp3_wakeup_time; + /* + * New psr options 0=500us, 1=100us, 2=2500us, 3=0us + * Old decimal value is wake up time in multiples of 100 us. + */ + if (bdb->version >= 209 && IS_GEN9_BC(dev_priv)) { + switch (psr_table->tp1_wakeup_time) { + case 0: + dev_priv->vbt.psr.tp1_wakeup_time_us = 500; + break; + case 1: + dev_priv->vbt.psr.tp1_wakeup_time_us = 100; + break; + case 3: + dev_priv->vbt.psr.tp1_wakeup_time_us = 0; + break; + default: + DRM_DEBUG_KMS("VBT tp1 wakeup time value %d is outside range[0-3], defaulting to max value 2500us\n", + psr_table->tp1_wakeup_time); + /* fallthrough */ + case 2: + dev_priv->vbt.psr.tp1_wakeup_time_us = 2500; + break; + } + + switch (psr_table->tp2_tp3_wakeup_time) { + case 0: + dev_priv->vbt.psr.tp2_tp3_wakeup_time_us = 500; + break; + case 1: + dev_priv->vbt.psr.tp2_tp3_wakeup_time_us = 100; + break; + case 3: + dev_priv->vbt.psr.tp1_wakeup_time_us = 0; + break; + default: + DRM_DEBUG_KMS("VBT tp2_tp3 wakeup time value %d is outside range[0-3], defaulting to max value 2500us\n", + psr_table->tp2_tp3_wakeup_time); + /* fallthrough */ + case 2: + dev_priv->vbt.psr.tp2_tp3_wakeup_time_us = 2500; + break; + } + } else { + dev_priv->vbt.psr.tp1_wakeup_time_us = psr_table->tp1_wakeup_time * 100; + dev_priv->vbt.psr.tp2_tp3_wakeup_time_us = psr_table->tp2_tp3_wakeup_time * 100; + } } static void parse_dsi_backlight_ports(struct drm_i915_private *dev_priv, diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index db27f2faa1dec..d64f03949d9ad 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -461,23 +461,23 @@ static void hsw_activate_psr1(struct intel_dp *intel_dp) if (dev_priv->psr.link_standby) val |= EDP_PSR_LINK_STANDBY; - if (dev_priv->vbt.psr.tp1_wakeup_time > 5) - val |= EDP_PSR_TP1_TIME_2500us; - else if (dev_priv->vbt.psr.tp1_wakeup_time > 1) - val |= EDP_PSR_TP1_TIME_500us; - else if (dev_priv->vbt.psr.tp1_wakeup_time > 0) + if (dev_priv->vbt.psr.tp1_wakeup_time_us == 0) + val |= EDP_PSR_TP1_TIME_0us; + else if (dev_priv->vbt.psr.tp1_wakeup_time_us <= 100) val |= EDP_PSR_TP1_TIME_100us; + else if (dev_priv->vbt.psr.tp1_wakeup_time_us <= 500) + val |= EDP_PSR_TP1_TIME_500us; else - val |= EDP_PSR_TP1_TIME_0us; + val |= EDP_PSR_TP1_TIME_2500us; - if (dev_priv->vbt.psr.tp2_tp3_wakeup_time > 5) - val |= EDP_PSR_TP2_TP3_TIME_2500us; - else if (dev_priv->vbt.psr.tp2_tp3_wakeup_time > 1) - val |= EDP_PSR_TP2_TP3_TIME_500us; - else if (dev_priv->vbt.psr.tp2_tp3_wakeup_time > 0) + if (dev_priv->vbt.psr.tp2_tp3_wakeup_time_us == 0) + val |= EDP_PSR_TP2_TP3_TIME_0us; + else if (dev_priv->vbt.psr.tp2_tp3_wakeup_time_us <= 100) val |= EDP_PSR_TP2_TP3_TIME_100us; + else if (dev_priv->vbt.psr.tp2_tp3_wakeup_time_us <= 500) + val |= EDP_PSR_TP2_TP3_TIME_500us; else - val |= EDP_PSR_TP2_TP3_TIME_0us; + val |= EDP_PSR_TP2_TP3_TIME_2500us; if (intel_dp_source_supports_hbr2(intel_dp) && drm_dp_tps3_supported(intel_dp->dpcd)) @@ -513,14 +513,15 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp) val |= EDP_PSR2_FRAME_BEFORE_SU(dev_priv->psr.sink_sync_latency + 1); - if (dev_priv->vbt.psr.tp2_tp3_wakeup_time > 5) - val |= EDP_PSR2_TP2_TIME_2500; - else if (dev_priv->vbt.psr.tp2_tp3_wakeup_time > 1) - val |= EDP_PSR2_TP2_TIME_500; - else if (dev_priv->vbt.psr.tp2_tp3_wakeup_time > 0) - val |= EDP_PSR2_TP2_TIME_100; + if (dev_priv->vbt.psr.tp2_tp3_wakeup_time_us >= 0 && + dev_priv->vbt.psr.tp2_tp3_wakeup_time_us <= 50) + val |= EDP_PSR2_TP2_TIME_50us; + else if (dev_priv->vbt.psr.tp2_tp3_wakeup_time_us <= 100) + val |= EDP_PSR2_TP2_TIME_100us; + else if (dev_priv->vbt.psr.tp2_tp3_wakeup_time_us <= 500) + val |= EDP_PSR2_TP2_TIME_500us; else - val |= EDP_PSR2_TP2_TIME_50; + val |= EDP_PSR2_TP2_TIME_2500us; I915_WRITE(EDP_PSR2_CTL, val); } -- GitLab From ce3508fd2a778e9366ab638f4e1dbe6dab874c5b Mon Sep 17 00:00:00 2001 From: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Date: Fri, 11 May 2018 16:00:59 -0700 Subject: [PATCH 0100/1506] drm/i915/psr: Nuke PSR support for VLV and CHV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PSR hardware and hence the driver code for VLV and CHV deviates a lot from their DDI counterparts. While the feature has been disabled for a long time now, retaining support for these platforms is a maintenance burden. There have been multiple refactoring commits to just keep the existing code for these platforms in line with the rest. There are known issues that need to be fixed to enable PSR on these platforms, and there is no PSR capable platform in CI to ensure the code does not break again if we get around to fixing the existing issues. On account of all these reasons, let's nuke this code for now and bring it back if a need arises in the future. Cc: Jani Nikula <jani.nikula@intel.com> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Acked-by: Jani Nikula <jani.nikula@intel.com> Acked-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Reviewed-by: José Roberto de Souza <jose.souza@intel.com> Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180511230059.19387-1-dhinakaran.pandiyan@intel.com --- drivers/gpu/drm/i915/i915_debugfs.c | 42 +--- drivers/gpu/drm/i915/i915_drv.h | 1 - drivers/gpu/drm/i915/i915_pci.c | 2 - drivers/gpu/drm/i915/intel_drv.h | 2 - drivers/gpu/drm/i915/intel_frontbuffer.c | 2 - drivers/gpu/drm/i915/intel_psr.c | 248 ++--------------------- 6 files changed, 27 insertions(+), 270 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index e9b1b8df6ef5d..a8e7761cdc7d5 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2643,8 +2643,6 @@ static int i915_edp_psr_status(struct seq_file *m, void *data) { struct drm_i915_private *dev_priv = node_to_i915(m->private); u32 psrperf = 0; - u32 stat[3]; - enum pipe pipe; bool enabled = false; bool sink_support; @@ -2665,47 +2663,17 @@ static int i915_edp_psr_status(struct seq_file *m, void *data) seq_printf(m, "Re-enable work scheduled: %s\n", yesno(work_busy(&dev_priv->psr.work.work))); - if (HAS_DDI(dev_priv)) { - if (dev_priv->psr.psr2_enabled) - enabled = I915_READ(EDP_PSR2_CTL) & EDP_PSR2_ENABLE; - else - enabled = I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE; - } else { - for_each_pipe(dev_priv, pipe) { - enum transcoder cpu_transcoder = - intel_pipe_to_cpu_transcoder(dev_priv, pipe); - enum intel_display_power_domain power_domain; - - power_domain = POWER_DOMAIN_TRANSCODER(cpu_transcoder); - if (!intel_display_power_get_if_enabled(dev_priv, - power_domain)) - continue; - - stat[pipe] = I915_READ(VLV_PSRSTAT(pipe)) & - VLV_EDP_PSR_CURR_STATE_MASK; - if ((stat[pipe] == VLV_EDP_PSR_ACTIVE_NORFB_UP) || - (stat[pipe] == VLV_EDP_PSR_ACTIVE_SF_UPDATE)) - enabled = true; - - intel_display_power_put(dev_priv, power_domain); - } - } + if (dev_priv->psr.psr2_enabled) + enabled = I915_READ(EDP_PSR2_CTL) & EDP_PSR2_ENABLE; + else + enabled = I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE; seq_printf(m, "Main link in standby mode: %s\n", yesno(dev_priv->psr.link_standby)); - seq_printf(m, "HW Enabled & Active bit: %s", yesno(enabled)); - - if (!HAS_DDI(dev_priv)) - for_each_pipe(dev_priv, pipe) { - if ((stat[pipe] == VLV_EDP_PSR_ACTIVE_NORFB_UP) || - (stat[pipe] == VLV_EDP_PSR_ACTIVE_SF_UPDATE)) - seq_printf(m, " pipe %c", pipe_name(pipe)); - } - seq_puts(m, "\n"); + seq_printf(m, "HW Enabled & Active bit: %s\n", yesno(enabled)); /* - * VLV/CHV PSR has no kind of performance counter * SKL+ Perf counter is reset to 0 everytime DC state is entered */ if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) { diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index a7a563ed0fd8b..487922f88b76e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -607,7 +607,6 @@ struct i915_psr { bool link_standby; bool colorimetry_support; bool alpm; - bool has_hw_tracking; bool psr2_enabled; u8 sink_sync_latency; bool debug; diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c index 4364922e935d3..97a91e6af7e3c 100644 --- a/drivers/gpu/drm/i915/i915_pci.c +++ b/drivers/gpu/drm/i915/i915_pci.c @@ -340,7 +340,6 @@ static const struct intel_device_info intel_valleyview_info = { GEN(7), .is_lp = 1, .num_pipes = 2, - .has_psr = 1, .has_runtime_pm = 1, .has_rc6 = 1, .has_gmch_display = 1, @@ -433,7 +432,6 @@ static const struct intel_device_info intel_cherryview_info = { .is_lp = 1, .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING, .has_64bit_reloc = 1, - .has_psr = 1, .has_runtime_pm = 1, .has_resource_streamer = 1, .has_rc6 = 1, diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 2855363f5b6cc..fd6256632482c 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1917,8 +1917,6 @@ void intel_psr_flush(struct drm_i915_private *dev_priv, unsigned frontbuffer_bits, enum fb_op_origin origin); void intel_psr_init(struct drm_i915_private *dev_priv); -void intel_psr_single_frame_update(struct drm_i915_private *dev_priv, - unsigned frontbuffer_bits); void intel_psr_compute_config(struct intel_dp *intel_dp, struct intel_crtc_state *crtc_state); void intel_psr_irq_control(struct drm_i915_private *dev_priv, bool debug); diff --git a/drivers/gpu/drm/i915/intel_frontbuffer.c b/drivers/gpu/drm/i915/intel_frontbuffer.c index 7fff0a0eceb47..c3379bde266f1 100644 --- a/drivers/gpu/drm/i915/intel_frontbuffer.c +++ b/drivers/gpu/drm/i915/intel_frontbuffer.c @@ -153,8 +153,6 @@ void intel_frontbuffer_flip_prepare(struct drm_i915_private *dev_priv, /* Remove stale busy bits due to the old buffer. */ dev_priv->fb_tracking.busy_bits &= ~frontbuffer_bits; spin_unlock(&dev_priv->fb_tracking.lock); - - intel_psr_single_frame_update(dev_priv, frontbuffer_bits); } /** diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index d64f03949d9ad..c08e4b4c07e14 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -97,10 +97,6 @@ void intel_psr_irq_control(struct drm_i915_private *dev_priv, bool debug) { u32 debug_mask, mask; - /* No PSR interrupts on VLV/CHV */ - if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) - return; - mask = EDP_PSR_ERROR(TRANSCODER_EDP); debug_mask = EDP_PSR_POST_EXIT(TRANSCODER_EDP) | EDP_PSR_PRE_ENTRY(TRANSCODER_EDP); @@ -284,31 +280,6 @@ void intel_psr_init_dpcd(struct intel_dp *intel_dp) } } -static bool vlv_is_psr_active_on_pipe(struct drm_device *dev, int pipe) -{ - struct drm_i915_private *dev_priv = to_i915(dev); - uint32_t val; - - val = I915_READ(VLV_PSRSTAT(pipe)) & - VLV_EDP_PSR_CURR_STATE_MASK; - return (val == VLV_EDP_PSR_ACTIVE_NORFB_UP) || - (val == VLV_EDP_PSR_ACTIVE_SF_UPDATE); -} - -static void vlv_psr_setup_vsc(struct intel_dp *intel_dp, - const struct intel_crtc_state *crtc_state) -{ - struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - uint32_t val; - - /* VLV auto-generate VSC package as per EDP 1.3 spec, Table 3.10 */ - val = I915_READ(VLV_VSCSDP(crtc->pipe)); - val &= ~VLV_EDP_PSR_SDP_FREQ_MASK; - val |= VLV_EDP_PSR_SDP_FREQ_EVFRAME; - I915_WRITE(VLV_VSCSDP(crtc->pipe), val); -} - static void hsw_psr_setup_vsc(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state) { @@ -341,12 +312,6 @@ static void hsw_psr_setup_vsc(struct intel_dp *intel_dp, DP_SDP_VSC, &psr_vsc, sizeof(psr_vsc)); } -static void vlv_psr_enable_sink(struct intel_dp *intel_dp) -{ - drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, - DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE); -} - static void hsw_psr_setup_aux(struct intel_dp *intel_dp) { struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); @@ -403,38 +368,6 @@ static void hsw_psr_enable_sink(struct intel_dp *intel_dp) drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER, DP_SET_POWER_D0); } -static void vlv_psr_enable_source(struct intel_dp *intel_dp, - const struct intel_crtc_state *crtc_state) -{ - struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); - struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); - struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); - - /* Transition from PSR_state 0 (disabled) to PSR_state 1 (inactive) */ - I915_WRITE(VLV_PSRCTL(crtc->pipe), - VLV_EDP_PSR_MODE_SW_TIMER | - VLV_EDP_PSR_SRC_TRANSMITTER_STATE | - VLV_EDP_PSR_ENABLE); -} - -static void vlv_psr_activate(struct intel_dp *intel_dp) -{ - struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); - struct drm_device *dev = dig_port->base.base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); - struct drm_crtc *crtc = dig_port->base.base.crtc; - enum pipe pipe = to_intel_crtc(crtc)->pipe; - - /* - * Let's do the transition from PSR_state 1 (inactive) to - * PSR_state 2 (transition to active - static frame transmission). - * Then Hardware is responsible for the transition to - * PSR_state 3 (active - no Remote Frame Buffer (RFB) update). - */ - I915_WRITE(VLV_PSRCTL(pipe), I915_READ(VLV_PSRCTL(pipe)) | - VLV_EDP_PSR_ACTIVE_ENTRY); -} - static void hsw_activate_psr1(struct intel_dp *intel_dp) { struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); @@ -603,17 +536,11 @@ void intel_psr_compute_config(struct intel_dp *intel_dp, * ones. Since by Display design transcoder EDP is tied to port A * we can safely escape based on the port A. */ - if (HAS_DDI(dev_priv) && dig_port->base.port != PORT_A) { + if (dig_port->base.port != PORT_A) { DRM_DEBUG_KMS("PSR condition failed: Port not supported\n"); return; } - if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) && - !dev_priv->psr.link_standby) { - DRM_ERROR("PSR condition failed: Link off requested but not supported on this platform\n"); - return; - } - if (IS_HASWELL(dev_priv) && I915_READ(HSW_STEREO_3D_CTL(crtc_state->cpu_transcoder)) & S3D_ENABLE) { @@ -761,7 +688,6 @@ void intel_psr_enable(struct intel_dp *intel_dp, * enabled. * However on some platforms we face issues when first * activation follows a modeset so quickly. - * - On VLV/CHV we get bank screen on first activation * - On HSW/BDW we get a recoverable frozen screen until * next exit-activate sequence. */ @@ -773,36 +699,6 @@ void intel_psr_enable(struct intel_dp *intel_dp, mutex_unlock(&dev_priv->psr.lock); } -static void vlv_psr_disable(struct intel_dp *intel_dp, - const struct intel_crtc_state *old_crtc_state) -{ - struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); - struct drm_device *dev = intel_dig_port->base.base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); - struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc); - uint32_t val; - - if (dev_priv->psr.active) { - /* Put VLV PSR back to PSR_state 0 (disabled). */ - if (intel_wait_for_register(dev_priv, - VLV_PSRSTAT(crtc->pipe), - VLV_EDP_PSR_IN_TRANS, - 0, - 1)) - WARN(1, "PSR transition took longer than expected\n"); - - val = I915_READ(VLV_PSRCTL(crtc->pipe)); - val &= ~VLV_EDP_PSR_ACTIVE_ENTRY; - val &= ~VLV_EDP_PSR_ENABLE; - val &= ~VLV_EDP_PSR_MODE_MASK; - I915_WRITE(VLV_PSRCTL(crtc->pipe), val); - - dev_priv->psr.active = false; - } else { - WARN_ON(vlv_is_psr_active_on_pipe(dev, crtc->pipe)); - } -} - static void hsw_psr_disable(struct intel_dp *intel_dp, const struct intel_crtc_state *old_crtc_state) { @@ -895,21 +791,12 @@ static bool psr_wait_for_idle(struct drm_i915_private *dev_priv) if (!intel_dp) return false; - if (HAS_DDI(dev_priv)) { - if (dev_priv->psr.psr2_enabled) { - reg = EDP_PSR2_STATUS; - mask = EDP_PSR2_STATUS_STATE_MASK; - } else { - reg = EDP_PSR_STATUS; - mask = EDP_PSR_STATUS_STATE_MASK; - } + if (dev_priv->psr.psr2_enabled) { + reg = EDP_PSR2_STATUS; + mask = EDP_PSR2_STATUS_STATE_MASK; } else { - struct drm_crtc *crtc = - dp_to_dig_port(intel_dp)->base.base.crtc; - enum pipe pipe = to_intel_crtc(crtc)->pipe; - - reg = VLV_PSRSTAT(pipe); - mask = VLV_EDP_PSR_IN_TRANS; + reg = EDP_PSR_STATUS; + mask = EDP_PSR_STATUS_STATE_MASK; } mutex_unlock(&dev_priv->psr.lock); @@ -954,102 +841,23 @@ static void intel_psr_work(struct work_struct *work) static void intel_psr_exit(struct drm_i915_private *dev_priv) { - struct intel_dp *intel_dp = dev_priv->psr.enabled; - struct drm_crtc *crtc = dp_to_dig_port(intel_dp)->base.base.crtc; - enum pipe pipe = to_intel_crtc(crtc)->pipe; u32 val; if (!dev_priv->psr.active) return; - if (HAS_DDI(dev_priv)) { - if (dev_priv->psr.psr2_enabled) { - val = I915_READ(EDP_PSR2_CTL); - WARN_ON(!(val & EDP_PSR2_ENABLE)); - I915_WRITE(EDP_PSR2_CTL, val & ~EDP_PSR2_ENABLE); - } else { - val = I915_READ(EDP_PSR_CTL); - WARN_ON(!(val & EDP_PSR_ENABLE)); - I915_WRITE(EDP_PSR_CTL, val & ~EDP_PSR_ENABLE); - } + if (dev_priv->psr.psr2_enabled) { + val = I915_READ(EDP_PSR2_CTL); + WARN_ON(!(val & EDP_PSR2_ENABLE)); + I915_WRITE(EDP_PSR2_CTL, val & ~EDP_PSR2_ENABLE); } else { - val = I915_READ(VLV_PSRCTL(pipe)); - - /* - * Here we do the transition drirectly from - * PSR_state 3 (active - no Remote Frame Buffer (RFB) update) to - * PSR_state 5 (exit). - * PSR State 4 (active with single frame update) can be skipped. - * On PSR_state 5 (exit) Hardware is responsible to transition - * back to PSR_state 1 (inactive). - * Now we are at Same state after vlv_psr_enable_source. - */ - val &= ~VLV_EDP_PSR_ACTIVE_ENTRY; - I915_WRITE(VLV_PSRCTL(pipe), val); - - /* - * Send AUX wake up - Spec says after transitioning to PSR - * active we have to send AUX wake up by writing 01h in DPCD - * 600h of sink device. - * XXX: This might slow down the transition, but without this - * HW doesn't complete the transition to PSR_state 1 and we - * never get the screen updated. - */ - drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER, - DP_SET_POWER_D0); + val = I915_READ(EDP_PSR_CTL); + WARN_ON(!(val & EDP_PSR_ENABLE)); + I915_WRITE(EDP_PSR_CTL, val & ~EDP_PSR_ENABLE); } - dev_priv->psr.active = false; } -/** - * intel_psr_single_frame_update - Single Frame Update - * @dev_priv: i915 device - * @frontbuffer_bits: frontbuffer plane tracking bits - * - * Some platforms support a single frame update feature that is used to - * send and update only one frame on Remote Frame Buffer. - * So far it is only implemented for Valleyview and Cherryview because - * hardware requires this to be done before a page flip. - */ -void intel_psr_single_frame_update(struct drm_i915_private *dev_priv, - unsigned frontbuffer_bits) -{ - struct drm_crtc *crtc; - enum pipe pipe; - u32 val; - - if (!CAN_PSR(dev_priv)) - return; - - /* - * Single frame update is already supported on BDW+ but it requires - * many W/A and it isn't really needed. - */ - if (!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv)) - return; - - mutex_lock(&dev_priv->psr.lock); - if (!dev_priv->psr.enabled) { - mutex_unlock(&dev_priv->psr.lock); - return; - } - - crtc = dp_to_dig_port(dev_priv->psr.enabled)->base.base.crtc; - pipe = to_intel_crtc(crtc)->pipe; - - if (frontbuffer_bits & INTEL_FRONTBUFFER_ALL_MASK(pipe)) { - val = I915_READ(VLV_PSRCTL(pipe)); - - /* - * We need to set this bit before writing registers for a flip. - * This bit will be self-clear when it gets to the PSR active state. - */ - I915_WRITE(VLV_PSRCTL(pipe), val | VLV_EDP_PSR_SINGLE_FRAME_UPDATE); - } - mutex_unlock(&dev_priv->psr.lock); -} - /** * intel_psr_invalidate - Invalidade PSR * @dev_priv: i915 device @@ -1072,7 +880,7 @@ void intel_psr_invalidate(struct drm_i915_private *dev_priv, if (!CAN_PSR(dev_priv)) return; - if (dev_priv->psr.has_hw_tracking && origin == ORIGIN_FLIP) + if (origin == ORIGIN_FLIP) return; mutex_lock(&dev_priv->psr.lock); @@ -1115,7 +923,7 @@ void intel_psr_flush(struct drm_i915_private *dev_priv, if (!CAN_PSR(dev_priv)) return; - if (dev_priv->psr.has_hw_tracking && origin == ORIGIN_FLIP) + if (origin == ORIGIN_FLIP) return; mutex_lock(&dev_priv->psr.lock); @@ -1132,8 +940,7 @@ void intel_psr_flush(struct drm_i915_private *dev_priv, /* By definition flush = invalidate + flush */ if (frontbuffer_bits) { - if (dev_priv->psr.psr2_enabled || - IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { + if (dev_priv->psr.psr2_enabled) { intel_psr_exit(dev_priv); } else { /* @@ -1185,9 +992,6 @@ void intel_psr_init(struct drm_i915_private *dev_priv) if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) /* HSW and BDW require workarounds that we don't implement. */ dev_priv->psr.link_standby = false; - else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) - /* On VLV and CHV only standby mode is supported. */ - dev_priv->psr.link_standby = true; else /* For new platforms let's respect VBT back again */ dev_priv->psr.link_standby = dev_priv->vbt.psr.full_link; @@ -1205,18 +1009,10 @@ void intel_psr_init(struct drm_i915_private *dev_priv) INIT_DELAYED_WORK(&dev_priv->psr.work, intel_psr_work); mutex_init(&dev_priv->psr.lock); - if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { - dev_priv->psr.enable_source = vlv_psr_enable_source; - dev_priv->psr.disable_source = vlv_psr_disable; - dev_priv->psr.enable_sink = vlv_psr_enable_sink; - dev_priv->psr.activate = vlv_psr_activate; - dev_priv->psr.setup_vsc = vlv_psr_setup_vsc; - } else { - dev_priv->psr.has_hw_tracking = true; - dev_priv->psr.enable_source = hsw_psr_enable_source; - dev_priv->psr.disable_source = hsw_psr_disable; - dev_priv->psr.enable_sink = hsw_psr_enable_sink; - dev_priv->psr.activate = hsw_psr_activate; - dev_priv->psr.setup_vsc = hsw_psr_setup_vsc; - } + dev_priv->psr.enable_source = hsw_psr_enable_source; + dev_priv->psr.disable_source = hsw_psr_disable; + dev_priv->psr.enable_sink = hsw_psr_enable_sink; + dev_priv->psr.activate = hsw_psr_activate; + dev_priv->psr.setup_vsc = hsw_psr_setup_vsc; + } -- GitLab From 8cf6da7ef755c8e09094baae941134b771bd4344 Mon Sep 17 00:00:00 2001 From: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Date: Fri, 11 May 2018 12:51:40 -0700 Subject: [PATCH 0101/1506] drm/i915/psr: Avoid DPCD reads when panel does not support PSR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ville noticed that we are unncessarily reading DPCD's after knowing panel did not support PSR. Looks like this check that was present earlier got removed unintentionally, let's put it back. While we do this, add the PSR version number in the debug print. Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Tarun Vyas <tarun.vyas@intel.com> Reviewed-by: Vathsala Nagaraju <vathsala.nagaraju@intel.com> Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180511195145.3829-1-dhinakaran.pandiyan@intel.com --- drivers/gpu/drm/i915/intel_psr.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index c08e4b4c07e14..f0ff005bc86a3 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -246,10 +246,12 @@ void intel_psr_init_dpcd(struct intel_dp *intel_dp) drm_dp_dpcd_read(&intel_dp->aux, DP_PSR_SUPPORT, intel_dp->psr_dpcd, sizeof(intel_dp->psr_dpcd)); - if (intel_dp->psr_dpcd[0]) { - dev_priv->psr.sink_support = true; - DRM_DEBUG_KMS("Detected EDP PSR Panel.\n"); - } + if (!intel_dp->psr_dpcd[0]) + return; + + DRM_DEBUG_KMS("eDP panel supports PSR version %x\n", + intel_dp->psr_dpcd[0]); + dev_priv->psr.sink_support = true; if (INTEL_GEN(dev_priv) >= 9 && (intel_dp->psr_dpcd[0] == DP_PSR2_WITH_Y_COORD_IS_SUPPORTED)) { @@ -266,8 +268,8 @@ void intel_psr_init_dpcd(struct intel_dp *intel_dp) */ dev_priv->psr.sink_psr2_support = intel_dp_get_y_coord_required(intel_dp); - DRM_DEBUG_KMS("PSR2 %s on sink", dev_priv->psr.sink_psr2_support - ? "supported" : "not supported"); + DRM_DEBUG_KMS("PSR2 %ssupported\n", + dev_priv->psr.sink_psr2_support ? "" : "not "); if (dev_priv->psr.sink_psr2_support) { dev_priv->psr.colorimetry_support = -- GitLab From 84bb2916a6835636fe28e8db192c3293f2d4df21 Mon Sep 17 00:00:00 2001 From: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Date: Fri, 11 May 2018 12:51:41 -0700 Subject: [PATCH 0102/1506] drm/i915/psr: Check for SET_POWER_CAPABLE bit at PSR init time. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By moving the check from psr_compute_config() to psr_init_dpcd(), we get to set the dev_priv->psr.sink_support flag only when the panel is capable of changing power state. An additional benefit is that the check will be performed only at init time instead of every atomic_check. This should change the psr_basic IGT failures on HSW to skips. v2: Return early when SET_POWER_CAPABLE bit is 0 (Jose) Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=106217 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=106346 Cc: José Roberto de Souza <jose.souza@intel.com> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Reviewed-by: José Roberto de Souza <jose.souza@intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180511195145.3829-2-dhinakaran.pandiyan@intel.com --- drivers/gpu/drm/i915/intel_dp.c | 8 ++++++-- drivers/gpu/drm/i915/intel_psr.c | 11 +++++------ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index ce07bd794aed5..37b9f62aeb6e8 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -3730,8 +3730,6 @@ intel_edp_init_dpcd(struct intel_dp *intel_dp) dev_priv->no_aux_handshake = intel_dp->dpcd[DP_MAX_DOWNSPREAD] & DP_NO_AUX_HANDSHAKE_LINK_TRAINING; - intel_psr_init_dpcd(intel_dp); - /* * Read the eDP display control registers. * @@ -3747,6 +3745,12 @@ intel_edp_init_dpcd(struct intel_dp *intel_dp) DRM_DEBUG_KMS("eDP DPCD: %*ph\n", (int) sizeof(intel_dp->edp_dpcd), intel_dp->edp_dpcd); + /* + * This has to be called after intel_dp->edp_dpcd is filled, PSR checks + * for SET_POWER_CAPABLE bit in intel_dp->edp_dpcd[1] + */ + intel_psr_init_dpcd(intel_dp); + /* Read the eDP 1.4+ supported link rates. */ if (intel_dp->edp_dpcd[0] >= DP_EDP_14) { __le16 sink_rates[DP_MAX_SUPPORTED_RATES]; diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index f0ff005bc86a3..26dbb6097981c 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -248,9 +248,13 @@ void intel_psr_init_dpcd(struct intel_dp *intel_dp) if (!intel_dp->psr_dpcd[0]) return; - DRM_DEBUG_KMS("eDP panel supports PSR version %x\n", intel_dp->psr_dpcd[0]); + + if (!(intel_dp->edp_dpcd[1] & DP_EDP_SET_POWER_CAP)) { + DRM_DEBUG_KMS("Panel lacks power state control, PSR cannot be enabled\n"); + return; + } dev_priv->psr.sink_support = true; if (INTEL_GEN(dev_priv) >= 9 && @@ -570,11 +574,6 @@ void intel_psr_compute_config(struct intel_dp *intel_dp, return; } - if (!(intel_dp->edp_dpcd[1] & DP_EDP_SET_POWER_CAP)) { - DRM_DEBUG_KMS("PSR condition failed: panel lacks power state control\n"); - return; - } - crtc_state->has_psr = true; crtc_state->has_psr2 = intel_psr2_config_valid(intel_dp, crtc_state); DRM_DEBUG_KMS("Enabling PSR%s\n", crtc_state->has_psr2 ? "2" : ""); -- GitLab From 1e8b251ebcbbfc6bfa826bca4d91a8e1bcad2e5f Mon Sep 17 00:00:00 2001 From: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Date: Fri, 11 May 2018 12:51:43 -0700 Subject: [PATCH 0103/1506] drm/i915/psr: Avoid unnecessary DPCD read of DP_PSR_CAPS intel_dp->psr_dpcd already has the required values. Cc: Jose Roberto de Souza <jose.souza@intel.com> Reviewed-by: Tarun Vyas <tarun.vyas@intel.com> Reviewed-by: Vathsala Nagaraju <vathsala.nagaraju@intel.com> Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180511195145.3829-4-dhinakaran.pandiyan@intel.com --- drivers/gpu/drm/i915/intel_psr.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 26dbb6097981c..4f34abcacacf3 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -197,15 +197,6 @@ void intel_psr_irq_handler(struct drm_i915_private *dev_priv, u32 psr_iir) } } -static bool intel_dp_get_y_coord_required(struct intel_dp *intel_dp) -{ - uint8_t psr_caps = 0; - - if (drm_dp_dpcd_readb(&intel_dp->aux, DP_PSR_CAPS, &psr_caps) != 1) - return false; - return psr_caps & DP_PSR2_SU_Y_COORDINATE_REQUIRED; -} - static bool intel_dp_get_colorimetry_status(struct intel_dp *intel_dp) { uint8_t dprx = 0; @@ -271,7 +262,7 @@ void intel_psr_init_dpcd(struct intel_dp *intel_dp) * GTC first. */ dev_priv->psr.sink_psr2_support = - intel_dp_get_y_coord_required(intel_dp); + intel_dp->psr_dpcd[1] & DP_PSR2_SU_Y_COORDINATE_REQUIRED; DRM_DEBUG_KMS("PSR2 %ssupported\n", dev_priv->psr.sink_psr2_support ? "" : "not "); -- GitLab From 264ff016cf0672f99f98ea853dbc7e45c3527bc2 Mon Sep 17 00:00:00 2001 From: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Date: Fri, 11 May 2018 12:51:44 -0700 Subject: [PATCH 0104/1506] drm/i915/psr: Fall back to max. synchronization latency if DPCD read fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Noticed that we assume the best case of 0 latency when the DPCD read fails, reasonable pessimism is safer. eDP spec does say that if latency is greater than 8, the panel supplier needs to provide it. I didn't see anything specific in the VBT for this, so let's go with 8 frames as a fallback. Cc: Jose Roberto de Souza <jose.souza@intel.com> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: José Roberto de Souza <jose.souza@intel.com> Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180511195145.3829-5-dhinakaran.pandiyan@intel.com --- drivers/gpu/drm/i915/intel_psr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 4f34abcacacf3..09f5962a19aab 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -219,13 +219,13 @@ static bool intel_dp_get_alpm_status(struct intel_dp *intel_dp) static u8 intel_dp_get_sink_sync_latency(struct intel_dp *intel_dp) { - u8 val = 0; + u8 val = 8; /* assume the worst if we can't read the value */ if (drm_dp_dpcd_readb(&intel_dp->aux, DP_SYNCHRONIZATION_LATENCY_IN_SINK, &val) == 1) val &= DP_MAX_RESYNC_FRAME_COUNT_MASK; else - DRM_ERROR("Unable to get sink synchronization latency\n"); + DRM_DEBUG_KMS("Unable to get sink synchronization latency, assuming 8 frames\n"); return val; } -- GitLab From 97c9de66ca8075871b31f4af05593e027e880e67 Mon Sep 17 00:00:00 2001 From: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Date: Fri, 11 May 2018 12:51:45 -0700 Subject: [PATCH 0105/1506] drm/i915/psr: Fix ALPM cap check for PSR2 While touching the code around this, I noticed that absence of ALPM capability does not stop us from enabling PSR2. But, the spec unambiguously states that ALPM is required for PSR2 and so does this commit that introduced this code drm/i915/psr: enable ALPM for psr2 As per edp1.4 spec , alpm is required for psr2 operation as it's used for all psr2 main link power down management and alpm enable bit must be set for psr2 operation. Cc: Jose Roberto de Souza <jose.souza@intel.com> Cc: Vathsala Nagaraju <vathsala.nagaraju@intel.com> Reviewed-by: Vathsala Nagaraju <vathsala.nagaraju@intel.com> Reviewed-by: Tarun Vyas <tarun.vyas@intel.com> Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180511195145.3829-6-dhinakaran.pandiyan@intel.com --- drivers/gpu/drm/i915/intel_psr.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 09f5962a19aab..ebc483f06c6f3 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -250,6 +250,10 @@ void intel_psr_init_dpcd(struct intel_dp *intel_dp) if (INTEL_GEN(dev_priv) >= 9 && (intel_dp->psr_dpcd[0] == DP_PSR2_WITH_Y_COORD_IS_SUPPORTED)) { + bool y_req = intel_dp->psr_dpcd[1] & + DP_PSR2_SU_Y_COORDINATE_REQUIRED; + bool alpm = intel_dp_get_alpm_status(intel_dp); + /* * All panels that supports PSR version 03h (PSR2 + * Y-coordinate) can handle Y-coordinates in VSC but we are @@ -261,16 +265,13 @@ void intel_psr_init_dpcd(struct intel_dp *intel_dp) * Y-coordinate requirement panels we would need to enable * GTC first. */ - dev_priv->psr.sink_psr2_support = - intel_dp->psr_dpcd[1] & DP_PSR2_SU_Y_COORDINATE_REQUIRED; + dev_priv->psr.sink_psr2_support = y_req && alpm; DRM_DEBUG_KMS("PSR2 %ssupported\n", dev_priv->psr.sink_psr2_support ? "" : "not "); if (dev_priv->psr.sink_psr2_support) { dev_priv->psr.colorimetry_support = intel_dp_get_colorimetry_status(intel_dp); - dev_priv->psr.alpm = - intel_dp_get_alpm_status(intel_dp); dev_priv->psr.sink_sync_latency = intel_dp_get_sink_sync_latency(intel_dp); } @@ -351,13 +352,12 @@ static void hsw_psr_enable_sink(struct intel_dp *intel_dp) u8 dpcd_val = DP_PSR_ENABLE; /* Enable ALPM at sink for psr2 */ - if (dev_priv->psr.psr2_enabled && dev_priv->psr.alpm) - drm_dp_dpcd_writeb(&intel_dp->aux, - DP_RECEIVER_ALPM_CONFIG, - DP_ALPM_ENABLE); - - if (dev_priv->psr.psr2_enabled) + if (dev_priv->psr.psr2_enabled) { + drm_dp_dpcd_writeb(&intel_dp->aux, DP_RECEIVER_ALPM_CONFIG, + DP_ALPM_ENABLE); dpcd_val |= DP_PSR_ENABLE_PSR2; + } + if (dev_priv->psr.link_standby) dpcd_val |= DP_PSR_MAIN_LINK_ACTIVE; drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, dpcd_val); -- GitLab From 2f7e87692e0441abf27a9714991edd136e87363a Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Mon, 21 May 2018 09:21:28 +0100 Subject: [PATCH 0106/1506] drm/mm: Reject over-sized allocation requests early As we keep an rbtree of available holes sorted by their size, we can very easily determine if there is any hole large enough that might satisfy the allocation request. This helps when dealing with a highly fragmented address space and a request for a search by address. To cache the largest size, we convert into the cached rbtree variant which tracks the leftmost node for us. However, currently we sorted into ascending size order so the leftmost node is the smallest, and so to make it the largest hole we need to invert our sorting. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180521082131.13744-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/drm_mm.c | 82 ++++++++++++++++++++++++++++------------ include/drm/drm_mm.h | 2 +- 2 files changed, 58 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index 3166026a1874d..7b4ad05fe1c04 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -239,6 +239,32 @@ static void drm_mm_interval_tree_add_node(struct drm_mm_node *hole_node, #define HOLE_SIZE(NODE) ((NODE)->hole_size) #define HOLE_ADDR(NODE) (__drm_mm_hole_node_start(NODE)) +static u64 rb_to_hole_size(struct rb_node *rb) +{ + return rb_entry(rb, struct drm_mm_node, rb_hole_size)->hole_size; +} + +static void insert_hole_size(struct rb_root_cached *root, + struct drm_mm_node *node) +{ + struct rb_node **link = &root->rb_root.rb_node, *rb = NULL; + u64 x = node->hole_size; + bool first = true; + + while (*link) { + rb = *link; + if (x > rb_to_hole_size(rb)) { + link = &rb->rb_left; + } else { + link = &rb->rb_right; + first = false; + } + } + + rb_link_node(&node->rb_hole_size, rb, link); + rb_insert_color_cached(&node->rb_hole_size, root, first); +} + static void add_hole(struct drm_mm_node *node) { struct drm_mm *mm = node->mm; @@ -247,7 +273,7 @@ static void add_hole(struct drm_mm_node *node) __drm_mm_hole_node_end(node) - __drm_mm_hole_node_start(node); DRM_MM_BUG_ON(!drm_mm_hole_follows(node)); - RB_INSERT(mm->holes_size, rb_hole_size, HOLE_SIZE); + insert_hole_size(&mm->holes_size, node); RB_INSERT(mm->holes_addr, rb_hole_addr, HOLE_ADDR); list_add(&node->hole_stack, &mm->hole_stack); @@ -258,7 +284,7 @@ static void rm_hole(struct drm_mm_node *node) DRM_MM_BUG_ON(!drm_mm_hole_follows(node)); list_del(&node->hole_stack); - rb_erase(&node->rb_hole_size, &node->mm->holes_size); + rb_erase_cached(&node->rb_hole_size, &node->mm->holes_size); rb_erase(&node->rb_hole_addr, &node->mm->holes_addr); node->hole_size = 0; @@ -282,38 +308,39 @@ static inline u64 rb_hole_size(struct rb_node *rb) static struct drm_mm_node *best_hole(struct drm_mm *mm, u64 size) { - struct rb_node *best = NULL; - struct rb_node **link = &mm->holes_size.rb_node; + struct rb_node *rb = mm->holes_size.rb_root.rb_node; + struct drm_mm_node *best = NULL; - while (*link) { - struct rb_node *rb = *link; + do { + struct drm_mm_node *node = + rb_entry(rb, struct drm_mm_node, rb_hole_size); - if (size <= rb_hole_size(rb)) { - link = &rb->rb_left; - best = rb; + if (size <= node->hole_size) { + best = node; + rb = rb->rb_right; } else { - link = &rb->rb_right; + rb = rb->rb_left; } - } + } while (rb); - return rb_hole_size_to_node(best); + return best; } static struct drm_mm_node *find_hole(struct drm_mm *mm, u64 addr) { + struct rb_node *rb = mm->holes_addr.rb_node; struct drm_mm_node *node = NULL; - struct rb_node **link = &mm->holes_addr.rb_node; - while (*link) { + while (rb) { u64 hole_start; - node = rb_hole_addr_to_node(*link); + node = rb_hole_addr_to_node(rb); hole_start = __drm_mm_hole_node_start(node); if (addr < hole_start) - link = &node->rb_hole_addr.rb_left; + rb = node->rb_hole_addr.rb_left; else if (addr > hole_start + node->hole_size) - link = &node->rb_hole_addr.rb_right; + rb = node->rb_hole_addr.rb_right; else break; } @@ -326,9 +353,6 @@ first_hole(struct drm_mm *mm, u64 start, u64 end, u64 size, enum drm_mm_insert_mode mode) { - if (RB_EMPTY_ROOT(&mm->holes_size)) - return NULL; - switch (mode) { default: case DRM_MM_INSERT_BEST: @@ -355,7 +379,7 @@ next_hole(struct drm_mm *mm, switch (mode) { default: case DRM_MM_INSERT_BEST: - return rb_hole_size_to_node(rb_next(&node->rb_hole_size)); + return rb_hole_size_to_node(rb_prev(&node->rb_hole_size)); case DRM_MM_INSERT_LOW: return rb_hole_addr_to_node(rb_next(&node->rb_hole_addr)); @@ -426,6 +450,11 @@ int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node) } EXPORT_SYMBOL(drm_mm_reserve_node); +static u64 rb_to_hole_size_or_zero(struct rb_node *rb) +{ + return rb ? rb_to_hole_size(rb) : 0; +} + /** * drm_mm_insert_node_in_range - ranged search for space and insert @node * @mm: drm_mm to allocate from @@ -457,6 +486,9 @@ int drm_mm_insert_node_in_range(struct drm_mm * const mm, if (unlikely(size == 0 || range_end - range_start < size)) return -ENOSPC; + if (rb_to_hole_size_or_zero(rb_first_cached(&mm->holes_size)) < size) + return -ENOSPC; + if (alignment <= 1) alignment = 0; @@ -587,9 +619,9 @@ void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new) if (drm_mm_hole_follows(old)) { list_replace(&old->hole_stack, &new->hole_stack); - rb_replace_node(&old->rb_hole_size, - &new->rb_hole_size, - &mm->holes_size); + rb_replace_node_cached(&old->rb_hole_size, + &new->rb_hole_size, + &mm->holes_size); rb_replace_node(&old->rb_hole_addr, &new->rb_hole_addr, &mm->holes_addr); @@ -885,7 +917,7 @@ void drm_mm_init(struct drm_mm *mm, u64 start, u64 size) INIT_LIST_HEAD(&mm->hole_stack); mm->interval_tree = RB_ROOT_CACHED; - mm->holes_size = RB_ROOT; + mm->holes_size = RB_ROOT_CACHED; mm->holes_addr = RB_ROOT; /* Clever trick to avoid a special case in the free hole tracking. */ diff --git a/include/drm/drm_mm.h b/include/drm/drm_mm.h index 101f566ae43d0..e3aa3bfd4860b 100644 --- a/include/drm/drm_mm.h +++ b/include/drm/drm_mm.h @@ -173,7 +173,7 @@ struct drm_mm { struct drm_mm_node head_node; /* Keep an interval_tree for fast lookup of drm_mm_nodes by address. */ struct rb_root_cached interval_tree; - struct rb_root holes_size; + struct rb_root_cached holes_size; struct rb_root holes_addr; unsigned long scan_active; -- GitLab From 83bc4ec37210b17bd611a58968b2ce0e9cc7f251 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Mon, 21 May 2018 09:21:29 +0100 Subject: [PATCH 0107/1506] drm/mm: Add a search-by-address variant to only inspect a single hole Searching for an available hole by address is slow, as there no guarantee that a hole will be available and so we must walk over all nodes in the rbtree before we determine the search was futile. In many cases, the caller doesn't strictly care for the highest available hole and was just opportunistically laying out the address space in a preferred order. In such cases, the caller can accept any address and would rather do so then do a slow walk. To be able to mix search strategies, the caller wants to tell the drm_mm how long to spend on the search. Without a good guide for what should be the best split, start with a request to try once at most. That is return the top-most (or lowest) hole if it fulfils the alignment and size requirements. v2: Documentation, by why of example (selftests) and kerneldoc. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180521082131.13744-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/drm_mm.c | 9 ++- drivers/gpu/drm/selftests/drm_mm_selftests.h | 2 + drivers/gpu/drm/selftests/test-drm_mm.c | 71 ++++++++++++++++++++ include/drm/drm_mm.h | 32 +++++++++ 4 files changed, 112 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index 7b4ad05fe1c04..3cc5fbd78ee20 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -480,6 +480,7 @@ int drm_mm_insert_node_in_range(struct drm_mm * const mm, { struct drm_mm_node *hole; u64 remainder_mask; + bool once; DRM_MM_BUG_ON(range_start >= range_end); @@ -492,9 +493,13 @@ int drm_mm_insert_node_in_range(struct drm_mm * const mm, if (alignment <= 1) alignment = 0; + once = mode & DRM_MM_INSERT_ONCE; + mode &= ~DRM_MM_INSERT_ONCE; + remainder_mask = is_power_of_2(alignment) ? alignment - 1 : 0; - for (hole = first_hole(mm, range_start, range_end, size, mode); hole; - hole = next_hole(mm, hole, mode)) { + for (hole = first_hole(mm, range_start, range_end, size, mode); + hole; + hole = once ? NULL : next_hole(mm, hole, mode)) { u64 hole_start = __drm_mm_hole_node_start(hole); u64 hole_end = hole_start + hole->hole_size; u64 adj_start, adj_end; diff --git a/drivers/gpu/drm/selftests/drm_mm_selftests.h b/drivers/gpu/drm/selftests/drm_mm_selftests.h index 54acc117550cf..6b943ea1c57da 100644 --- a/drivers/gpu/drm/selftests/drm_mm_selftests.h +++ b/drivers/gpu/drm/selftests/drm_mm_selftests.h @@ -19,7 +19,9 @@ selftest(align64, igt_align64) selftest(evict, igt_evict) selftest(evict_range, igt_evict_range) selftest(bottomup, igt_bottomup) +selftest(lowest, igt_lowest) selftest(topdown, igt_topdown) +selftest(highest, igt_highest) selftest(color, igt_color) selftest(color_evict, igt_color_evict) selftest(color_evict_range, igt_color_evict_range) diff --git a/drivers/gpu/drm/selftests/test-drm_mm.c b/drivers/gpu/drm/selftests/test-drm_mm.c index 7cc935d7b7aaa..f69d8da222b02 100644 --- a/drivers/gpu/drm/selftests/test-drm_mm.c +++ b/drivers/gpu/drm/selftests/test-drm_mm.c @@ -1825,6 +1825,77 @@ static int igt_bottomup(void *ignored) return ret; } +static int __igt_once(unsigned int mode) +{ + struct drm_mm mm; + struct drm_mm_node rsvd_lo, rsvd_hi, node; + int err; + + drm_mm_init(&mm, 0, 7); + + memset(&rsvd_lo, 0, sizeof(rsvd_lo)); + rsvd_lo.start = 1; + rsvd_lo.size = 1; + err = drm_mm_reserve_node(&mm, &rsvd_lo); + if (err) { + pr_err("Could not reserve low node\n"); + goto err; + } + + memset(&rsvd_hi, 0, sizeof(rsvd_hi)); + rsvd_hi.start = 5; + rsvd_hi.size = 1; + err = drm_mm_reserve_node(&mm, &rsvd_hi); + if (err) { + pr_err("Could not reserve low node\n"); + goto err_lo; + } + + if (!drm_mm_hole_follows(&rsvd_lo) || !drm_mm_hole_follows(&rsvd_hi)) { + pr_err("Expected a hole after lo and high nodes!\n"); + err = -EINVAL; + goto err_hi; + } + + memset(&node, 0, sizeof(node)); + err = drm_mm_insert_node_generic(&mm, &node, + 2, 0, 0, + mode | DRM_MM_INSERT_ONCE); + if (!err) { + pr_err("Unexpectedly inserted the node into the wrong hole: node.start=%llx\n", + node.start); + err = -EINVAL; + goto err_node; + } + + err = drm_mm_insert_node_generic(&mm, &node, 2, 0, 0, mode); + if (err) { + pr_err("Could not insert the node into the available hole!\n"); + err = -EINVAL; + goto err_hi; + } + +err_node: + drm_mm_remove_node(&node); +err_hi: + drm_mm_remove_node(&rsvd_hi); +err_lo: + drm_mm_remove_node(&rsvd_lo); +err: + drm_mm_takedown(&mm); + return err; +} + +static int igt_lowest(void *ignored) +{ + return __igt_once(DRM_MM_INSERT_LOW); +} + +static int igt_highest(void *ignored) +{ + return __igt_once(DRM_MM_INSERT_HIGH); +} + static void separate_adjacent_colors(const struct drm_mm_node *node, unsigned long color, u64 *start, diff --git a/include/drm/drm_mm.h b/include/drm/drm_mm.h index e3aa3bfd4860b..2c3bbb43c7d1a 100644 --- a/include/drm/drm_mm.h +++ b/include/drm/drm_mm.h @@ -109,6 +109,38 @@ enum drm_mm_insert_mode { * Allocates the node from the bottom of the found hole. */ DRM_MM_INSERT_EVICT, + + /** + * @DRM_MM_INSERT_ONCE: + * + * Only check the first hole for suitablity and report -ENOSPC + * immediately otherwise, rather than check every hole until a + * suitable one is found. Can only be used in conjunction with another + * search method such as DRM_MM_INSERT_HIGH or DRM_MM_INSERT_LOW. + */ + DRM_MM_INSERT_ONCE = BIT(31), + + /** + * @DRM_MM_INSERT_HIGHEST: + * + * Only check the highest hole (the hole with the largest address) and + * insert the node at the top of the hole or report -ENOSPC if + * unsuitable. + * + * Does not search all holes. + */ + DRM_MM_INSERT_HIGHEST = DRM_MM_INSERT_HIGH | DRM_MM_INSERT_ONCE, + + /** + * @DRM_MM_INSERT_LOWEST: + * + * Only check the lowest hole (the hole with the smallest address) and + * insert the node at the bottom of the hole or report -ENOSPC if + * unsuitable. + * + * Does not search all holes. + */ + DRM_MM_INSERT_LOWEST = DRM_MM_INSERT_LOW | DRM_MM_INSERT_ONCE, }; /** -- GitLab From eb479f86397923cdb82dabae4ca33dc4fec18968 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Mon, 21 May 2018 09:21:30 +0100 Subject: [PATCH 0108/1506] drm/i915: Limit searching for PIN_HIGH To no surprise (since we've flip-flopped over the use of PIN_HIGH a few times), doing a search by address over a pathologically fragmented address space is exceeding slow. To protect ourselves from nearly unbounded latency (think searching a million holes while under struct_mutex), limit the search for the highest available hole and fallback to best-fit if it fails. In the pathologically fragmented case, such as igt/gem_ctx_thrash, the effect is dramatic, bringing the runtime down from hours to seconds (depending on how many other slow searches you hit, e.g. alloc_iova() and alloc_vmap_area() both degrade to a slow rbtree walk after their small cache is exhausted). For the real world, the number of search steps is unlikely to be significant as we should only need to search once per new context. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180521082131.13744-3-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_gtt.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 21d72f695adb7..c8eaeacd34710 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -3972,7 +3972,7 @@ int i915_gem_gtt_insert(struct i915_address_space *vm, mode = DRM_MM_INSERT_BEST; if (flags & PIN_HIGH) - mode = DRM_MM_INSERT_HIGH; + mode = DRM_MM_INSERT_HIGHEST; if (flags & PIN_MAPPABLE) mode = DRM_MM_INSERT_LOW; @@ -3992,6 +3992,15 @@ int i915_gem_gtt_insert(struct i915_address_space *vm, if (err != -ENOSPC) return err; + if (mode & DRM_MM_INSERT_ONCE) { + err = drm_mm_insert_node_in_range(&vm->mm, node, + size, alignment, color, + start, end, + DRM_MM_INSERT_BEST); + if (err != -ENOSPC) + return err; + } + if (flags & PIN_NOEVICT) return -ENOSPC; -- GitLab From 2edd4e698dc8a0c497a502c75561c87be0e8a9a6 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Mon, 21 May 2018 09:21:31 +0100 Subject: [PATCH 0109/1506] drm/i915: Pin the ring high If we can use an unmappable ring, try to pin it out of the mappable aperture. This simple layout preference is to try and keep the mappable aperture reserved and available to handle GGTT mmapping requests from userspace without causing evictions and GPU stalls. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180521082131.13744-4-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_ringbuffer.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 757bb0990c071..8948b30ea5d65 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1034,6 +1034,8 @@ int intel_ring_pin(struct intel_ring *ring, flags |= PIN_OFFSET_BIAS | offset_bias; if (vma->obj->stolen) flags |= PIN_MAPPABLE; + else + flags |= PIN_HIGH; if (!(vma->flags & I915_VMA_GLOBAL_BIND)) { if (flags & PIN_MAPPABLE || map == I915_MAP_WC) -- GitLab From 09a4c02e58c1b3d9748f78242962b7f63c68477e Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 24 May 2018 09:11:35 +0100 Subject: [PATCH 0110/1506] drm/i915: Look for an active kernel context before switching We were not very carefully checking to see if an older request on the engine was an earlier switch-to-kernel-context before deciding to emit a new switch. The end result would be that we could get into a permanent loop of trying to emit a new request to perform the switch simply to flush the existing switch. What we need is a means of tracking the completion of each timeline versus the kernel context, that is to detect if a more recent request has been submitted that would result in a switch away from the kernel context. To realise this, we need only to look in our syncmap on the kernel context and check that we have synchronized against all active rings. v2: Since all ringbuffer clients currently share the same timeline, we do have to use the gem_context to distinguish clients. As a bonus, include all the tracing used to debug the death inside suspend. v3: Test, test, test. Construct a selftest to exercise and assert the expected behaviour that multiple switch-to-contexts do not emit redundant requests. Reported-by: Mika Kuoppala <mika.kuoppala@intel.com> Fixes: a89d1f921c15 ("drm/i915: Split i915_gem_timeline into individual timelines") Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Mika Kuoppala <mika.kuoppala@intel.com> Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180524081135.15278-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 7 + drivers/gpu/drm/i915/i915_gem.h | 3 + drivers/gpu/drm/i915/i915_gem_context.c | 86 +++++++++-- drivers/gpu/drm/i915/i915_request.c | 5 +- .../gpu/drm/i915/selftests/i915_gem_context.c | 144 ++++++++++++++++++ .../drm/i915/selftests/i915_mock_selftests.h | 1 + 6 files changed, 231 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 03874b50ada92..05f44ca35a062 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3703,6 +3703,9 @@ static int wait_for_engines(struct drm_i915_private *i915) int i915_gem_wait_for_idle(struct drm_i915_private *i915, unsigned int flags) { + GEM_TRACE("flags=%x (%s)\n", + flags, flags & I915_WAIT_LOCKED ? "locked" : "unlocked"); + /* If the device is asleep, we have no requests outstanding */ if (!READ_ONCE(i915->gt.awake)) return 0; @@ -3719,6 +3722,7 @@ int i915_gem_wait_for_idle(struct drm_i915_private *i915, unsigned int flags) return err; } i915_retire_requests(i915); + GEM_BUG_ON(i915->gt.active_requests); return wait_for_engines(i915); } else { @@ -4901,6 +4905,7 @@ static void assert_kernel_context_is_current(struct drm_i915_private *i915) struct intel_engine_cs *engine; enum intel_engine_id id; + GEM_BUG_ON(i915->gt.active_requests); for_each_engine(engine, i915, id) { GEM_BUG_ON(__i915_gem_active_peek(&engine->timeline.last_request)); GEM_BUG_ON(engine->last_retired_context->gem_context != kctx); @@ -4932,6 +4937,8 @@ int i915_gem_suspend(struct drm_i915_private *dev_priv) struct drm_device *dev = &dev_priv->drm; int ret; + GEM_TRACE("\n"); + intel_runtime_pm_get(dev_priv); intel_suspend_gt_powersave(dev_priv); diff --git a/drivers/gpu/drm/i915/i915_gem.h b/drivers/gpu/drm/i915/i915_gem.h index 5bf24cfc218cc..62ee4e3853658 100644 --- a/drivers/gpu/drm/i915/i915_gem.h +++ b/drivers/gpu/drm/i915/i915_gem.h @@ -63,9 +63,12 @@ struct drm_i915_private; #if IS_ENABLED(CONFIG_DRM_I915_TRACE_GEM) #define GEM_TRACE(...) trace_printk(__VA_ARGS__) #define GEM_TRACE_DUMP() ftrace_dump(DUMP_ALL) +#define GEM_TRACE_DUMP_ON(expr) \ + do { if (expr) ftrace_dump(DUMP_ALL); } while (0) #else #define GEM_TRACE(...) do { } while (0) #define GEM_TRACE_DUMP() do { } while (0) +#define GEM_TRACE_DUMP_ON(expr) BUILD_BUG_ON_INVALID(expr) #endif #define I915_NUM_ENGINES 8 diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index b69b18ef81203..45393f6e0208b 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -576,30 +576,72 @@ last_request_on_engine(struct i915_timeline *timeline, { struct i915_request *rq; - if (timeline == &engine->timeline) - return NULL; + GEM_BUG_ON(timeline == &engine->timeline); rq = i915_gem_active_raw(&timeline->last_request, &engine->i915->drm.struct_mutex); - if (rq && rq->engine == engine) + if (rq && rq->engine == engine) { + GEM_TRACE("last request for %s on engine %s: %llx:%d\n", + timeline->name, engine->name, + rq->fence.context, rq->fence.seqno); + GEM_BUG_ON(rq->timeline != timeline); return rq; + } return NULL; } -static bool engine_has_idle_kernel_context(struct intel_engine_cs *engine) +static bool engine_has_kernel_context_barrier(struct intel_engine_cs *engine) { - struct list_head * const active_rings = &engine->i915->gt.active_rings; + struct drm_i915_private *i915 = engine->i915; + const struct intel_context * const ce = + to_intel_context(i915->kernel_context, engine); + struct i915_timeline *barrier = ce->ring->timeline; struct intel_ring *ring; + bool any_active = false; - lockdep_assert_held(&engine->i915->drm.struct_mutex); + lockdep_assert_held(&i915->drm.struct_mutex); + list_for_each_entry(ring, &i915->gt.active_rings, active_link) { + struct i915_request *rq; + + rq = last_request_on_engine(ring->timeline, engine); + if (!rq) + continue; - list_for_each_entry(ring, active_rings, active_link) { - if (last_request_on_engine(ring->timeline, engine)) + any_active = true; + + if (rq->gem_context == i915->kernel_context) + continue; + + /* + * Was this request submitted after the previous + * switch-to-kernel-context? + */ + if (!i915_timeline_sync_is_later(barrier, &rq->fence)) { + GEM_TRACE("%s needs barrier for %llx:%d\n", + ring->timeline->name, + rq->fence.context, + rq->fence.seqno); return false; + } + + GEM_TRACE("%s has barrier after %llx:%d\n", + ring->timeline->name, + rq->fence.context, + rq->fence.seqno); } - return intel_engine_has_kernel_context(engine); + /* + * If any other timeline was still active and behind the last barrier, + * then our last switch-to-kernel-context must still be queued and + * will run last (leaving the engine in the kernel context when it + * eventually idles). + */ + if (any_active) + return true; + + /* The engine is idle; check that it is idling in the kernel context. */ + return engine->last_retired_context == ce; } int i915_gem_switch_to_kernel_context(struct drm_i915_private *i915) @@ -607,7 +649,10 @@ int i915_gem_switch_to_kernel_context(struct drm_i915_private *i915) struct intel_engine_cs *engine; enum intel_engine_id id; + GEM_TRACE("\n"); + lockdep_assert_held(&i915->drm.struct_mutex); + GEM_BUG_ON(!i915->kernel_context); i915_retire_requests(i915); @@ -615,9 +660,12 @@ int i915_gem_switch_to_kernel_context(struct drm_i915_private *i915) struct intel_ring *ring; struct i915_request *rq; - if (engine_has_idle_kernel_context(engine)) + GEM_BUG_ON(!to_intel_context(i915->kernel_context, engine)); + if (engine_has_kernel_context_barrier(engine)) continue; + GEM_TRACE("emit barrier on %s\n", engine->name); + rq = i915_request_alloc(engine, i915->kernel_context); if (IS_ERR(rq)) return PTR_ERR(rq); @@ -627,10 +675,20 @@ int i915_gem_switch_to_kernel_context(struct drm_i915_private *i915) struct i915_request *prev; prev = last_request_on_engine(ring->timeline, engine); - if (prev) - i915_sw_fence_await_sw_fence_gfp(&rq->submit, - &prev->submit, - I915_FENCE_GFP); + if (!prev) + continue; + + if (prev->gem_context == i915->kernel_context) + continue; + + GEM_TRACE("add barrier on %s for %llx:%d\n", + engine->name, + prev->fence.context, + prev->fence.seqno); + i915_sw_fence_await_sw_fence_gfp(&rq->submit, + &prev->submit, + I915_FENCE_GFP); + i915_timeline_sync_set(rq->timeline, &prev->fence); } /* diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index fc499bcbd105f..f187250e60c6f 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -320,6 +320,7 @@ static void advance_ring(struct i915_request *request) * is just about to be. Either works, if we miss the last two * noops - they are safe to be replayed on a reset. */ + GEM_TRACE("marking %s as inactive\n", ring->timeline->name); tail = READ_ONCE(request->tail); list_del(&ring->active_link); } else { @@ -1095,8 +1096,10 @@ void __i915_request_add(struct i915_request *request, bool flush_caches) i915_gem_active_set(&timeline->last_request, request); list_add_tail(&request->ring_link, &ring->request_list); - if (list_is_first(&request->ring_link, &ring->request_list)) + if (list_is_first(&request->ring_link, &ring->request_list)) { + GEM_TRACE("marking %s as active\n", ring->timeline->name); list_add(&ring->active_link, &request->i915->gt.active_rings); + } request->emitted_jiffies = jiffies; /* diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_context.c b/drivers/gpu/drm/i915/selftests/i915_gem_context.c index ddb03f009232f..b39392a00a6fe 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_context.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_context.c @@ -26,6 +26,7 @@ #include "igt_flush_test.h" #include "mock_drm.h" +#include "mock_gem_device.h" #include "huge_gem_object.h" #define DW_PER_PAGE (PAGE_SIZE / sizeof(u32)) @@ -420,6 +421,130 @@ static int igt_ctx_exec(void *arg) return err; } +static __maybe_unused const char * +__engine_name(struct drm_i915_private *i915, unsigned int engines) +{ + struct intel_engine_cs *engine; + unsigned int tmp; + + if (engines == ALL_ENGINES) + return "all"; + + for_each_engine_masked(engine, i915, engines, tmp) + return engine->name; + + return "none"; +} + +static int __igt_switch_to_kernel_context(struct drm_i915_private *i915, + struct i915_gem_context *ctx, + unsigned int engines) +{ + struct intel_engine_cs *engine; + unsigned int tmp; + int err; + + GEM_TRACE("Testing %s\n", __engine_name(i915, engines)); + for_each_engine_masked(engine, i915, engines, tmp) { + struct i915_request *rq; + + rq = i915_request_alloc(engine, ctx); + if (IS_ERR(rq)) + return PTR_ERR(rq); + + i915_request_add(rq); + } + + err = i915_gem_switch_to_kernel_context(i915); + if (err) + return err; + + for_each_engine_masked(engine, i915, engines, tmp) { + if (!engine_has_kernel_context_barrier(engine)) { + pr_err("kernel context not last on engine %s!\n", + engine->name); + return -EINVAL; + } + } + + err = i915_gem_wait_for_idle(i915, I915_WAIT_LOCKED); + if (err) + return err; + + GEM_BUG_ON(i915->gt.active_requests); + for_each_engine_masked(engine, i915, engines, tmp) { + if (engine->last_retired_context->gem_context != i915->kernel_context) { + pr_err("engine %s not idling in kernel context!\n", + engine->name); + return -EINVAL; + } + } + + err = i915_gem_switch_to_kernel_context(i915); + if (err) + return err; + + if (i915->gt.active_requests) { + pr_err("switch-to-kernel-context emitted %d requests even though it should already be idling in the kernel context\n", + i915->gt.active_requests); + return -EINVAL; + } + + for_each_engine_masked(engine, i915, engines, tmp) { + if (!intel_engine_has_kernel_context(engine)) { + pr_err("kernel context not last on engine %s!\n", + engine->name); + return -EINVAL; + } + } + + return 0; +} + +static int igt_switch_to_kernel_context(void *arg) +{ + struct drm_i915_private *i915 = arg; + struct intel_engine_cs *engine; + struct i915_gem_context *ctx; + enum intel_engine_id id; + int err; + + /* + * A core premise of switching to the kernel context is that + * if an engine is already idling in the kernel context, we + * do not emit another request and wake it up. The other being + * that we do indeed end up idling in the kernel context. + */ + + mutex_lock(&i915->drm.struct_mutex); + ctx = kernel_context(i915); + if (IS_ERR(ctx)) { + err = PTR_ERR(ctx); + goto out_unlock; + } + + /* First check idling each individual engine */ + for_each_engine(engine, i915, id) { + err = __igt_switch_to_kernel_context(i915, ctx, BIT(id)); + if (err) + goto out_unlock; + } + + /* Now en masse */ + err = __igt_switch_to_kernel_context(i915, ctx, ALL_ENGINES); + if (err) + goto out_unlock; + +out_unlock: + GEM_TRACE_DUMP_ON(err); + if (igt_flush_test(i915, I915_WAIT_LOCKED)) + err = -EIO; + mutex_unlock(&i915->drm.struct_mutex); + + kernel_context_close(ctx); + return err; +} + static int fake_aliasing_ppgtt_enable(struct drm_i915_private *i915) { struct drm_i915_gem_object *obj; @@ -447,9 +572,28 @@ static void fake_aliasing_ppgtt_disable(struct drm_i915_private *i915) i915_gem_fini_aliasing_ppgtt(i915); } +int i915_gem_context_mock_selftests(void) +{ + static const struct i915_subtest tests[] = { + SUBTEST(igt_switch_to_kernel_context), + }; + struct drm_i915_private *i915; + int err; + + i915 = mock_gem_device(); + if (!i915) + return -ENOMEM; + + err = i915_subtests(tests, i915); + + drm_dev_unref(&i915->drm); + return err; +} + int i915_gem_context_live_selftests(struct drm_i915_private *dev_priv) { static const struct i915_subtest tests[] = { + SUBTEST(igt_switch_to_kernel_context), SUBTEST(igt_ctx_exec), }; bool fake_alias = false; diff --git a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h index d16d74178e9df..1b70208eeea7a 100644 --- a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h +++ b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h @@ -24,3 +24,4 @@ selftest(vma, i915_vma_mock_selftests) selftest(evict, i915_gem_evict_mock_selftests) selftest(gtt, i915_gem_gtt_mock_selftests) selftest(hugepages, i915_gem_huge_page_mock_selftests) +selftest(contexts, i915_gem_context_mock_selftests) -- GitLab From 9eece5d9c6e0316f17091e37ff3ec87331bdedf3 Mon Sep 17 00:00:00 2001 From: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com> Date: Wed, 23 May 2018 14:36:30 +0300 Subject: [PATCH 0111/1506] drm/xen-front: fix pointer casts Building for a 32-bit target results in warnings from casting between a 32-bit pointer and a 64-bit integer. Fix the warnings by casting those pointers to uintptr_t first. Signed-off-by: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com> Reviewed-by: Juergen Gross <jgross@suse.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180523113630.29811-1-andr2000@gmail.com --- drivers/gpu/drm/xen/xen_drm_front.h | 4 ++-- drivers/gpu/drm/xen/xen_drm_front_shbuf.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/xen/xen_drm_front.h b/drivers/gpu/drm/xen/xen_drm_front.h index 2c2479b571ae6..5693b4a4b02b1 100644 --- a/drivers/gpu/drm/xen/xen_drm_front.h +++ b/drivers/gpu/drm/xen/xen_drm_front.h @@ -126,12 +126,12 @@ struct xen_drm_front_drm_info { static inline u64 xen_drm_front_fb_to_cookie(struct drm_framebuffer *fb) { - return (u64)fb; + return (uintptr_t)fb; } static inline u64 xen_drm_front_dbuf_to_cookie(struct drm_gem_object *gem_obj) { - return (u64)gem_obj; + return (uintptr_t)gem_obj; } int xen_drm_front_mode_set(struct xen_drm_front_drm_pipeline *pipeline, diff --git a/drivers/gpu/drm/xen/xen_drm_front_shbuf.c b/drivers/gpu/drm/xen/xen_drm_front_shbuf.c index 8099cb343ae3b..d333b67cc1a06 100644 --- a/drivers/gpu/drm/xen/xen_drm_front_shbuf.c +++ b/drivers/gpu/drm/xen/xen_drm_front_shbuf.c @@ -122,7 +122,7 @@ static void guest_calc_num_grefs(struct xen_drm_front_shbuf *buf) } #define xen_page_to_vaddr(page) \ - ((phys_addr_t)pfn_to_kaddr(page_to_xen_pfn(page))) + ((uintptr_t)pfn_to_kaddr(page_to_xen_pfn(page))) static int backend_unmap(struct xen_drm_front_shbuf *buf) { -- GitLab From c5d1f5562ea7f83fe911d6f9fcb3a32a8e1139ae Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Date: Thu, 24 May 2018 16:06:20 +0100 Subject: [PATCH 0112/1506] drm/i915: Include i915_scheduler.h from i915_gem_context.h struct i915_gem_context embeds struct i915_sched_attr so needs to include the respective header. Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20180524150621.17332-1-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/i915_gem_context.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/i915_gem_context.h b/drivers/gpu/drm/i915/i915_gem_context.h index c3262b4dd2ee6..84fef3b1e6e4e 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.h +++ b/drivers/gpu/drm/i915/i915_gem_context.h @@ -30,6 +30,7 @@ #include <linux/radix-tree.h> #include "i915_gem.h" +#include "i915_scheduler.h" struct pid; -- GitLab From 8359768c5c325f841473343288fc4d55a256954f Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Date: Thu, 24 May 2018 16:06:21 +0100 Subject: [PATCH 0113/1506] drm/i915: Forward declare struct intel_context This is to avoid an error with structure declared in parameter list if the include ordering changes. Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20180524150621.17332-2-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/i915_gem_context.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem_context.h b/drivers/gpu/drm/i915/i915_gem_context.h index 84fef3b1e6e4e..b116e4942c10d 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.h +++ b/drivers/gpu/drm/i915/i915_gem_context.h @@ -46,6 +46,8 @@ struct intel_ring; #define DEFAULT_CONTEXT_HANDLE 0 +struct intel_context; + struct intel_context_ops { void (*unpin)(struct intel_context *ce); void (*destroy)(struct intel_context *ce); -- GitLab From 9a4dc80399b1630cea0f1ad8ef0417436cbb95d0 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 18 May 2018 11:09:33 +0100 Subject: [PATCH 0114/1506] drm/i915: Flush the ring stop bit after clearing RING_HEAD in reset Inside the live_hangcheck (reset) selftests, we occasionally see failures like <7>[ 239.094840] i915_gem_set_wedged rcs0 <7>[ 239.094843] i915_gem_set_wedged current seqno 19a98, last 19a9a, hangcheck 0 [5158 ms] <7>[ 239.094846] i915_gem_set_wedged Reset count: 6239 (global 1) <7>[ 239.094848] i915_gem_set_wedged Requests: <7>[ 239.095052] i915_gem_set_wedged first 19a99 [e8c:5f] prio=1024 @ 5159ms: (null) <7>[ 239.095056] i915_gem_set_wedged last 19a9a [e81:1a] prio=139 @ 5159ms: igt/rcs0[5977]/1 <7>[ 239.095059] i915_gem_set_wedged active 19a99 [e8c:5f] prio=1024 @ 5159ms: (null) <7>[ 239.095062] i915_gem_set_wedged [head 0220, postfix 0280, tail 02a8, batch 0xffffffff_ffffffff] <7>[ 239.100050] i915_gem_set_wedged ring->start: 0x00283000 <7>[ 239.100053] i915_gem_set_wedged ring->head: 0x000001f8 <7>[ 239.100055] i915_gem_set_wedged ring->tail: 0x000002a8 <7>[ 239.100057] i915_gem_set_wedged ring->emit: 0x000002a8 <7>[ 239.100059] i915_gem_set_wedged ring->space: 0x00000f10 <7>[ 239.100085] i915_gem_set_wedged RING_START: 0x00283000 <7>[ 239.100088] i915_gem_set_wedged RING_HEAD: 0x00000260 <7>[ 239.100091] i915_gem_set_wedged RING_TAIL: 0x000002a8 <7>[ 239.100094] i915_gem_set_wedged RING_CTL: 0x00000001 <7>[ 239.100097] i915_gem_set_wedged RING_MODE: 0x00000300 [idle] <7>[ 239.100100] i915_gem_set_wedged RING_IMR: fffffefe <7>[ 239.100104] i915_gem_set_wedged ACTHD: 0x00000000_0000609c <7>[ 239.100108] i915_gem_set_wedged BBADDR: 0x00000000_0000609d <7>[ 239.100111] i915_gem_set_wedged DMA_FADDR: 0x00000000_00283260 <7>[ 239.100114] i915_gem_set_wedged IPEIR: 0x00000000 <7>[ 239.100117] i915_gem_set_wedged IPEHR: 0x02800000 <7>[ 239.100120] i915_gem_set_wedged Execlist status: 0x00044052 00000002 <7>[ 239.100124] i915_gem_set_wedged Execlist CSB read 5 [5 cached], write 5 [5 from hws], interrupt posted? no, tasklet queued? no (enabled) <7>[ 239.100128] i915_gem_set_wedged ELSP[0] count=1, ring->start=00283000, rq: 19a99 [e8c:5f] prio=1024 @ 5164ms: (null) <7>[ 239.100132] i915_gem_set_wedged ELSP[1] count=1, ring->start=00257000, rq: 19a9a [e81:1a] prio=139 @ 5164ms: igt/rcs0[5977]/1 <7>[ 239.100135] i915_gem_set_wedged HW active? 0x5 <7>[ 239.100250] i915_gem_set_wedged E 19a99 [e8c:5f] prio=1024 @ 5164ms: (null) <7>[ 239.100338] i915_gem_set_wedged E 19a9a [e81:1a] prio=139 @ 5164ms: igt/rcs0[5977]/1 <7>[ 239.100340] i915_gem_set_wedged Queue priority: 139 <7>[ 239.100343] i915_gem_set_wedged Q 0 [e98:19] prio=132 @ 5164ms: igt/rcs0[5977]/8 <7>[ 239.100346] i915_gem_set_wedged Q 0 [e84:19] prio=121 @ 5165ms: igt/rcs0[5977]/2 <7>[ 239.100349] i915_gem_set_wedged Q 0 [e87:19] prio=82 @ 5165ms: igt/rcs0[5977]/3 <7>[ 239.100352] i915_gem_set_wedged Q 0 [e84:1a] prio=44 @ 5164ms: igt/rcs0[5977]/2 <7>[ 239.100356] i915_gem_set_wedged Q 0 [e8b:19] prio=20 @ 5165ms: igt/rcs0[5977]/4 <7>[ 239.100362] i915_gem_set_wedged drv_selftest [5894] waiting for 19a99 where the GPU saw an arbitration point and idles; AND HAS NOT BEEN RESET! The RING_MODE indicates that is idle and has the STOP_RING bit set, so try clearing it. v2: Only clear the bit on restarting the ring, as we want to be sure the STOP_RING bit is kept if reset fails on wedging. v3: Spot when the ring state doesn't make sense when re-initialising the engine and dump it to the logs so that we don't have to wait for an error later and try to guess what happened earlier. v4: Prepare to print all the unexpected state, not just the first. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180518100933.2239-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_lrc.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 46e7bf4a30a97..302af60415a37 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1782,6 +1782,9 @@ static void enable_execlists(struct intel_engine_cs *engine) I915_WRITE(RING_MODE_GEN7(engine), _MASKED_BIT_ENABLE(GFX_RUN_LIST_ENABLE)); + I915_WRITE(RING_MI_MODE(engine->mmio_base), + _MASKED_BIT_DISABLE(STOP_RING)); + I915_WRITE(RING_HWS_PGA(engine->mmio_base), engine->status_page.ggtt_offset); POSTING_READ(RING_HWS_PGA(engine->mmio_base)); @@ -1790,6 +1793,19 @@ static void enable_execlists(struct intel_engine_cs *engine) engine->execlists.csb_head = -1; } +static bool unexpected_starting_state(struct intel_engine_cs *engine) +{ + struct drm_i915_private *dev_priv = engine->i915; + bool unexpected = false; + + if (I915_READ(RING_MI_MODE(engine->mmio_base)) & STOP_RING) { + DRM_DEBUG_DRIVER("STOP_RING still set in RING_MI_MODE\n"); + unexpected = true; + } + + return unexpected; +} + static int gen8_init_common_ring(struct intel_engine_cs *engine) { struct intel_engine_execlists * const execlists = &engine->execlists; @@ -1802,6 +1818,12 @@ static int gen8_init_common_ring(struct intel_engine_cs *engine) intel_engine_reset_breadcrumbs(engine); intel_engine_init_hangcheck(engine); + if (GEM_SHOW_DEBUG() && unexpected_starting_state(engine)) { + struct drm_printer p = drm_debug_printer(__func__); + + intel_engine_dump(engine, &p, NULL); + } + enable_execlists(engine); /* After a GPU reset, we may have requests to replay */ -- GitLab From fe25f3048322f32131a151ebe213f52821322f9c Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Tue, 22 May 2018 11:19:37 +0100 Subject: [PATCH 0115/1506] drm/i915/execlists: Wait for ELSP submission on restart After a reset, we will ensure that there is at least one request submitted to HW to ensure that a context is loaded for powersaving. Let's wait for this submission via a tasklet to complete before we drop our forcewake, ensuring the system is ready for rc6 before we let it possibly sleep. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20180522101937.7738-1-chris@chris-wilson.co.uk Reviewed-by: Mika Kuoppala <mika.kuoppala@intel.com> --- drivers/gpu/drm/i915/i915_gem.h | 6 ++++++ drivers/gpu/drm/i915/intel_lrc.c | 11 ++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem.h b/drivers/gpu/drm/i915/i915_gem.h index 62ee4e3853658..261da577829a6 100644 --- a/drivers/gpu/drm/i915/i915_gem.h +++ b/drivers/gpu/drm/i915/i915_gem.h @@ -82,4 +82,10 @@ static inline void __tasklet_disable_sync_once(struct tasklet_struct *t) tasklet_unlock_wait(t); } +static inline void __tasklet_enable_sync_once(struct tasklet_struct *t) +{ + if (atomic_dec_return(&t->count) == 0) + tasklet_kill(t); +} + #endif /* __I915_GEM_H__ */ diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 302af60415a37..4bcd3206991da 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -2008,7 +2008,16 @@ static void execlists_reset(struct intel_engine_cs *engine, static void execlists_reset_finish(struct intel_engine_cs *engine) { - tasklet_enable(&engine->execlists.tasklet); + /* + * Flush the tasklet while we still have the forcewake to be sure + * that it is not allowed to sleep before we restart and reload a + * context. + * + * As before (with execlists_reset_prepare) we rely on the caller + * serialising multiple attempts to reset so that we know that we + * are the only one manipulating tasklet state. + */ + __tasklet_enable_sync_once(&engine->execlists.tasklet); GEM_TRACE("%s\n", engine->name); } -- GitLab From 73b66f8731573a5fa74799dfabb4cdfe513b9241 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 25 May 2018 10:26:29 +0100 Subject: [PATCH 0116/1506] drm/i915: Prepare GEM for suspend earlier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to prepare the GPU for sleeping, we may want to submit commands to it. This is a complicated process that may even require some swapping in from shmemfs, if the GPU was in the wrong state. As such, we need to do this preparation step synchronously before the rest of the system has started to turn off (e.g. swapin fails if scsi is suspended). Fortunately, we are provided with a such a hook, pm_ops.prepare(). v2: Compile cleanup v3: Fewer asserts, fewer problems? v4: Ville pointed out that in some circumstances (such as switching off the overlay) the display code may issue a GPU request. This is unexpected, and will result in us going to sleep with us believing the GPU is still awake (though all user work has been saved). Add a comment to remind our future selves of what trouble brews. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=106640 Testcase: igt/drv_suspend after igt/gem_tiled_swapping Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20180525092629.1456-1-chris@chris-wilson.co.uk Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Mika Kuoppala <mika.kuoppala@intel.com> --- drivers/gpu/drm/i915/i915_drv.c | 47 ++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 2a96d082addf2..fb39e40c08474 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1553,12 +1553,30 @@ static bool suspend_to_idle(struct drm_i915_private *dev_priv) return false; } +static int i915_drm_prepare(struct drm_device *dev) +{ + struct drm_i915_private *i915 = to_i915(dev); + int err; + + /* + * NB intel_display_suspend() may issue new requests after we've + * ostensibly marked the GPU as ready-to-sleep here. We need to + * split out that work and pull it forward so that after point, + * the GPU is not woken again. + */ + err = i915_gem_suspend(i915); + if (err) + dev_err(&i915->drm.pdev->dev, + "GEM idle failed, suspend/resume might fail\n"); + + return err; +} + static int i915_drm_suspend(struct drm_device *dev) { struct drm_i915_private *dev_priv = to_i915(dev); struct pci_dev *pdev = dev_priv->drm.pdev; pci_power_t opregion_target_state; - int error; /* ignore lid events during suspend */ mutex_lock(&dev_priv->modeset_restore_lock); @@ -1575,13 +1593,6 @@ static int i915_drm_suspend(struct drm_device *dev) pci_save_state(pdev); - error = i915_gem_suspend(dev_priv); - if (error) { - dev_err(&pdev->dev, - "GEM idle failed, resume might fail\n"); - goto out; - } - intel_display_suspend(dev); intel_dp_mst_suspend(dev); @@ -1609,10 +1620,9 @@ static int i915_drm_suspend(struct drm_device *dev) intel_csr_ucode_suspend(dev_priv); -out: enable_rpm_wakeref_asserts(dev_priv); - return error; + return 0; } static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation) @@ -2081,6 +2091,22 @@ int i915_reset_engine(struct intel_engine_cs *engine, const char *msg) return ret; } +static int i915_pm_prepare(struct device *kdev) +{ + struct pci_dev *pdev = to_pci_dev(kdev); + struct drm_device *dev = pci_get_drvdata(pdev); + + if (!dev) { + dev_err(kdev, "DRM not initialized, aborting suspend.\n"); + return -ENODEV; + } + + if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) + return 0; + + return i915_drm_prepare(dev); +} + static int i915_pm_suspend(struct device *kdev) { struct pci_dev *pdev = to_pci_dev(kdev); @@ -2731,6 +2757,7 @@ const struct dev_pm_ops i915_pm_ops = { * S0ix (via system suspend) and S3 event handlers [PMSG_SUSPEND, * PMSG_RESUME] */ + .prepare = i915_pm_prepare, .suspend = i915_pm_suspend, .suspend_late = i915_pm_suspend_late, .resume_early = i915_pm_resume_early, -- GitLab From 7869196000080ace29ddd1f05153d23fa1734d79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Thu, 24 May 2018 22:20:35 +0300 Subject: [PATCH 0117/1506] drm/edid: Fix up edid_cea_modes[] formatting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix up a bunch of bad indentation and insconsistent comments in edid_cea_modes[]. v2: Instead of stripping the aspect ratio comments let's add them to all modes Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180524192035.9776-1-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula <jani.nikula@intel.com> --- drivers/gpu/drm/drm_edid.c | 268 ++++++++++++++++++------------------- 1 file changed, 134 insertions(+), 134 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 82f1ab09169da..634a68a03b07e 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -687,562 +687,562 @@ static const struct minimode extra_modes[] = { static const struct drm_display_mode edid_cea_modes[] = { /* 0 - dummy, VICs start at 1 */ { }, - /* 1 - 640x480@60Hz */ + /* 1 - 640x480@60Hz 4:3 */ { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656, 752, 800, 0, 480, 490, 492, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, - /* 2 - 720x480@60Hz */ + /* 2 - 720x480@60Hz 4:3 */ { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, - /* 3 - 720x480@60Hz */ + /* 3 - 720x480@60Hz 16:9 */ { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 4 - 1280x720@60Hz */ + /* 4 - 1280x720@60Hz 16:9 */ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1390, 1430, 1650, 0, 720, 725, 730, 750, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 5 - 1920x1080i@60Hz */ + /* 5 - 1920x1080i@60Hz 16:9 */ { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1094, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | - DRM_MODE_FLAG_INTERLACE), + DRM_MODE_FLAG_INTERLACE), .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 6 - 720(1440)x480i@60Hz */ + /* 6 - 720(1440)x480i@60Hz 4:3 */ { DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 13500, 720, 739, 801, 858, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, - /* 7 - 720(1440)x480i@60Hz */ + /* 7 - 720(1440)x480i@60Hz 16:9 */ { DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 13500, 720, 739, 801, 858, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 8 - 720(1440)x240@60Hz */ + /* 8 - 720(1440)x240@60Hz 4:3 */ { DRM_MODE("720x240", DRM_MODE_TYPE_DRIVER, 13500, 720, 739, 801, 858, 0, 240, 244, 247, 262, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_DBLCLK), + DRM_MODE_FLAG_DBLCLK), .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, - /* 9 - 720(1440)x240@60Hz */ + /* 9 - 720(1440)x240@60Hz 16:9 */ { DRM_MODE("720x240", DRM_MODE_TYPE_DRIVER, 13500, 720, 739, 801, 858, 0, 240, 244, 247, 262, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_DBLCLK), + DRM_MODE_FLAG_DBLCLK), .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 10 - 2880x480i@60Hz */ + /* 10 - 2880x480i@60Hz 4:3 */ { DRM_MODE("2880x480i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956, 3204, 3432, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_INTERLACE), + DRM_MODE_FLAG_INTERLACE), .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, - /* 11 - 2880x480i@60Hz */ + /* 11 - 2880x480i@60Hz 16:9 */ { DRM_MODE("2880x480i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956, 3204, 3432, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_INTERLACE), + DRM_MODE_FLAG_INTERLACE), .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 12 - 2880x240@60Hz */ + /* 12 - 2880x240@60Hz 4:3 */ { DRM_MODE("2880x240", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956, 3204, 3432, 0, 240, 244, 247, 262, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, - /* 13 - 2880x240@60Hz */ + /* 13 - 2880x240@60Hz 16:9 */ { DRM_MODE("2880x240", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956, 3204, 3432, 0, 240, 244, 247, 262, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 14 - 1440x480@60Hz */ + /* 14 - 1440x480@60Hz 4:3 */ { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1472, 1596, 1716, 0, 480, 489, 495, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, - /* 15 - 1440x480@60Hz */ + /* 15 - 1440x480@60Hz 16:9 */ { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1472, 1596, 1716, 0, 480, 489, 495, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 16 - 1920x1080@60Hz */ + /* 16 - 1920x1080@60Hz 16:9 */ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 17 - 720x576@50Hz */ + /* 17 - 720x576@50Hz 4:3 */ { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, - /* 18 - 720x576@50Hz */ + /* 18 - 720x576@50Hz 16:9 */ { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 19 - 1280x720@50Hz */ + /* 19 - 1280x720@50Hz 16:9 */ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1720, 1760, 1980, 0, 720, 725, 730, 750, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 20 - 1920x1080i@50Hz */ + /* 20 - 1920x1080i@50Hz 16:9 */ { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | - DRM_MODE_FLAG_INTERLACE), + DRM_MODE_FLAG_INTERLACE), .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 21 - 720(1440)x576i@50Hz */ + /* 21 - 720(1440)x576i@50Hz 4:3 */ { DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 13500, 720, 732, 795, 864, 0, 576, 580, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, - /* 22 - 720(1440)x576i@50Hz */ + /* 22 - 720(1440)x576i@50Hz 16:9 */ { DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 13500, 720, 732, 795, 864, 0, 576, 580, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 23 - 720(1440)x288@50Hz */ + /* 23 - 720(1440)x288@50Hz 4:3 */ { DRM_MODE("720x288", DRM_MODE_TYPE_DRIVER, 13500, 720, 732, 795, 864, 0, 288, 290, 293, 312, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_DBLCLK), + DRM_MODE_FLAG_DBLCLK), .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, - /* 24 - 720(1440)x288@50Hz */ + /* 24 - 720(1440)x288@50Hz 16:9 */ { DRM_MODE("720x288", DRM_MODE_TYPE_DRIVER, 13500, 720, 732, 795, 864, 0, 288, 290, 293, 312, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_DBLCLK), + DRM_MODE_FLAG_DBLCLK), .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 25 - 2880x576i@50Hz */ + /* 25 - 2880x576i@50Hz 4:3 */ { DRM_MODE("2880x576i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928, 3180, 3456, 0, 576, 580, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_INTERLACE), + DRM_MODE_FLAG_INTERLACE), .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, - /* 26 - 2880x576i@50Hz */ + /* 26 - 2880x576i@50Hz 16:9 */ { DRM_MODE("2880x576i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928, 3180, 3456, 0, 576, 580, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_INTERLACE), + DRM_MODE_FLAG_INTERLACE), .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 27 - 2880x288@50Hz */ + /* 27 - 2880x288@50Hz 4:3 */ { DRM_MODE("2880x288", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928, 3180, 3456, 0, 288, 290, 293, 312, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, - /* 28 - 2880x288@50Hz */ + /* 28 - 2880x288@50Hz 16:9 */ { DRM_MODE("2880x288", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928, 3180, 3456, 0, 288, 290, 293, 312, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 29 - 1440x576@50Hz */ + /* 29 - 1440x576@50Hz 4:3 */ { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464, 1592, 1728, 0, 576, 581, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, - /* 30 - 1440x576@50Hz */ + /* 30 - 1440x576@50Hz 16:9 */ { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464, 1592, 1728, 0, 576, 581, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 31 - 1920x1080@50Hz */ + /* 31 - 1920x1080@50Hz 16:9 */ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 32 - 1920x1080@24Hz */ + /* 32 - 1920x1080@24Hz 16:9 */ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2558, 2602, 2750, 0, 1080, 1084, 1089, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 33 - 1920x1080@25Hz */ + /* 33 - 1920x1080@25Hz 16:9 */ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 34 - 1920x1080@30Hz */ + /* 34 - 1920x1080@30Hz 16:9 */ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 35 - 2880x480@60Hz */ + /* 35 - 2880x480@60Hz 4:3 */ { DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2944, 3192, 3432, 0, 480, 489, 495, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, - /* 36 - 2880x480@60Hz */ + /* 36 - 2880x480@60Hz 16:9 */ { DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2944, 3192, 3432, 0, 480, 489, 495, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 37 - 2880x576@50Hz */ + /* 37 - 2880x576@50Hz 4:3 */ { DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2928, 3184, 3456, 0, 576, 581, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, - /* 38 - 2880x576@50Hz */ + /* 38 - 2880x576@50Hz 16:9 */ { DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2928, 3184, 3456, 0, 576, 581, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 39 - 1920x1080i@50Hz */ + /* 39 - 1920x1080i@50Hz 16:9 */ { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 72000, 1920, 1952, 2120, 2304, 0, 1080, 1126, 1136, 1250, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_INTERLACE), + DRM_MODE_FLAG_INTERLACE), .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 40 - 1920x1080i@100Hz */ + /* 40 - 1920x1080i@100Hz 16:9 */ { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | - DRM_MODE_FLAG_INTERLACE), + DRM_MODE_FLAG_INTERLACE), .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 41 - 1280x720@100Hz */ + /* 41 - 1280x720@100Hz 16:9 */ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1720, 1760, 1980, 0, 720, 725, 730, 750, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 42 - 720x576@100Hz */ + /* 42 - 720x576@100Hz 4:3 */ { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 54000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, - /* 43 - 720x576@100Hz */ + /* 43 - 720x576@100Hz 16:9 */ { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 54000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 44 - 720(1440)x576i@100Hz */ + /* 44 - 720(1440)x576i@100Hz 4:3 */ { DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 27000, 720, 732, 795, 864, 0, 576, 580, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, - /* 45 - 720(1440)x576i@100Hz */ + /* 45 - 720(1440)x576i@100Hz 16:9 */ { DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 27000, 720, 732, 795, 864, 0, 576, 580, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 46 - 1920x1080i@120Hz */ + /* 46 - 1920x1080i@120Hz 16:9 */ { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1094, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | - DRM_MODE_FLAG_INTERLACE), + DRM_MODE_FLAG_INTERLACE), .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 47 - 1280x720@120Hz */ + /* 47 - 1280x720@120Hz 16:9 */ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1390, 1430, 1650, 0, 720, 725, 730, 750, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 48 - 720x480@120Hz */ + /* 48 - 720x480@120Hz 4:3 */ { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 54000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, - /* 49 - 720x480@120Hz */ + /* 49 - 720x480@120Hz 16:9 */ { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 54000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 50 - 720(1440)x480i@120Hz */ + /* 50 - 720(1440)x480i@120Hz 4:3 */ { DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 27000, 720, 739, 801, 858, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, - /* 51 - 720(1440)x480i@120Hz */ + /* 51 - 720(1440)x480i@120Hz 16:9 */ { DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 27000, 720, 739, 801, 858, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 52 - 720x576@200Hz */ + /* 52 - 720x576@200Hz 4:3 */ { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 108000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), .vrefresh = 200, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, - /* 53 - 720x576@200Hz */ + /* 53 - 720x576@200Hz 16:9 */ { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 108000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), .vrefresh = 200, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 54 - 720(1440)x576i@200Hz */ + /* 54 - 720(1440)x576i@200Hz 4:3 */ { DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 54000, 720, 732, 795, 864, 0, 576, 580, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), .vrefresh = 200, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, - /* 55 - 720(1440)x576i@200Hz */ + /* 55 - 720(1440)x576i@200Hz 16:9 */ { DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 54000, 720, 732, 795, 864, 0, 576, 580, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), .vrefresh = 200, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 56 - 720x480@240Hz */ + /* 56 - 720x480@240Hz 4:3 */ { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 108000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), .vrefresh = 240, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, - /* 57 - 720x480@240Hz */ + /* 57 - 720x480@240Hz 16:9 */ { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 108000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), .vrefresh = 240, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 58 - 720(1440)x480i@240Hz */ + /* 58 - 720(1440)x480i@240Hz 4:3 */ { DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 54000, 720, 739, 801, 858, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), .vrefresh = 240, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, - /* 59 - 720(1440)x480i@240Hz */ + /* 59 - 720(1440)x480i@240Hz 16:9 */ { DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 54000, 720, 739, 801, 858, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | - DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), .vrefresh = 240, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 60 - 1280x720@24Hz */ + /* 60 - 1280x720@24Hz 16:9 */ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 59400, 1280, 3040, 3080, 3300, 0, 720, 725, 730, 750, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 61 - 1280x720@25Hz */ + /* 61 - 1280x720@25Hz 16:9 */ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3700, 3740, 3960, 0, 720, 725, 730, 750, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 62 - 1280x720@30Hz */ + /* 62 - 1280x720@30Hz 16:9 */ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3040, 3080, 3300, 0, 720, 725, 730, 750, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 63 - 1920x1080@120Hz */ + /* 63 - 1920x1080@120Hz 16:9 */ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), - .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 64 - 1920x1080@100Hz */ + .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, + /* 64 - 1920x1080@100Hz 16:9 */ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), - .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 65 - 1280x720@24Hz */ + .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, + /* 65 - 1280x720@24Hz 64:27 */ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 59400, 1280, 3040, 3080, 3300, 0, 720, 725, 730, 750, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, - /* 66 - 1280x720@25Hz */ + /* 66 - 1280x720@25Hz 64:27 */ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3700, 3740, 3960, 0, 720, 725, 730, 750, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, - /* 67 - 1280x720@30Hz */ + /* 67 - 1280x720@30Hz 64:27 */ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3040, 3080, 3300, 0, 720, 725, 730, 750, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, - /* 68 - 1280x720@50Hz */ + /* 68 - 1280x720@50Hz 64:27 */ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1720, 1760, 1980, 0, 720, 725, 730, 750, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, - /* 69 - 1280x720@60Hz */ + /* 69 - 1280x720@60Hz 64:27 */ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1390, 1430, 1650, 0, 720, 725, 730, 750, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, - /* 70 - 1280x720@100Hz */ + /* 70 - 1280x720@100Hz 64:27 */ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1720, 1760, 1980, 0, 720, 725, 730, 750, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, - /* 71 - 1280x720@120Hz */ + /* 71 - 1280x720@120Hz 64:27 */ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1390, 1430, 1650, 0, 720, 725, 730, 750, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, - /* 72 - 1920x1080@24Hz */ + /* 72 - 1920x1080@24Hz 64:27 */ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2558, 2602, 2750, 0, 1080, 1084, 1089, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, - /* 73 - 1920x1080@25Hz */ + /* 73 - 1920x1080@25Hz 64:27 */ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, - /* 74 - 1920x1080@30Hz */ + /* 74 - 1920x1080@30Hz 64:27 */ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, - /* 75 - 1920x1080@50Hz */ + /* 75 - 1920x1080@50Hz 64:27 */ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, - /* 76 - 1920x1080@60Hz */ + /* 76 - 1920x1080@60Hz 64:27 */ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, - /* 77 - 1920x1080@100Hz */ + /* 77 - 1920x1080@100Hz 64:27 */ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, - /* 78 - 1920x1080@120Hz */ + /* 78 - 1920x1080@120Hz 64:27 */ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, - /* 79 - 1680x720@24Hz */ + /* 79 - 1680x720@24Hz 64:27 */ { DRM_MODE("1680x720", DRM_MODE_TYPE_DRIVER, 59400, 1680, 3040, 3080, 3300, 0, 720, 725, 730, 750, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, - /* 80 - 1680x720@25Hz */ + /* 80 - 1680x720@25Hz 64:27 */ { DRM_MODE("1680x720", DRM_MODE_TYPE_DRIVER, 59400, 1680, 2908, 2948, 3168, 0, 720, 725, 730, 750, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, - /* 81 - 1680x720@30Hz */ + /* 81 - 1680x720@30Hz 64:27 */ { DRM_MODE("1680x720", DRM_MODE_TYPE_DRIVER, 59400, 1680, 2380, 2420, 2640, 0, 720, 725, 730, 750, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, - /* 82 - 1680x720@50Hz */ + /* 82 - 1680x720@50Hz 64:27 */ { DRM_MODE("1680x720", DRM_MODE_TYPE_DRIVER, 82500, 1680, 1940, 1980, 2200, 0, 720, 725, 730, 750, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, - /* 83 - 1680x720@60Hz */ + /* 83 - 1680x720@60Hz 64:27 */ { DRM_MODE("1680x720", DRM_MODE_TYPE_DRIVER, 99000, 1680, 1940, 1980, 2200, 0, 720, 725, 730, 750, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, - /* 84 - 1680x720@100Hz */ + /* 84 - 1680x720@100Hz 64:27 */ { DRM_MODE("1680x720", DRM_MODE_TYPE_DRIVER, 165000, 1680, 1740, 1780, 2000, 0, 720, 725, 730, 825, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, - /* 85 - 1680x720@120Hz */ + /* 85 - 1680x720@120Hz 64:27 */ { DRM_MODE("1680x720", DRM_MODE_TYPE_DRIVER, 198000, 1680, 1740, 1780, 2000, 0, 720, 725, 730, 825, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, - /* 86 - 2560x1080@24Hz */ + /* 86 - 2560x1080@24Hz 64:27 */ { DRM_MODE("2560x1080", DRM_MODE_TYPE_DRIVER, 99000, 2560, 3558, 3602, 3750, 0, 1080, 1084, 1089, 1100, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, - /* 87 - 2560x1080@25Hz */ + /* 87 - 2560x1080@25Hz 64:27 */ { DRM_MODE("2560x1080", DRM_MODE_TYPE_DRIVER, 90000, 2560, 3008, 3052, 3200, 0, 1080, 1084, 1089, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, - /* 88 - 2560x1080@30Hz */ + /* 88 - 2560x1080@30Hz 64:27 */ { DRM_MODE("2560x1080", DRM_MODE_TYPE_DRIVER, 118800, 2560, 3328, 3372, 3520, 0, 1080, 1084, 1089, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, - /* 89 - 2560x1080@50Hz */ + /* 89 - 2560x1080@50Hz 64:27 */ { DRM_MODE("2560x1080", DRM_MODE_TYPE_DRIVER, 185625, 2560, 3108, 3152, 3300, 0, 1080, 1084, 1089, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, - /* 90 - 2560x1080@60Hz */ + /* 90 - 2560x1080@60Hz 64:27 */ { DRM_MODE("2560x1080", DRM_MODE_TYPE_DRIVER, 198000, 2560, 2808, 2852, 3000, 0, 1080, 1084, 1089, 1100, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, - /* 91 - 2560x1080@100Hz */ + /* 91 - 2560x1080@100Hz 64:27 */ { DRM_MODE("2560x1080", DRM_MODE_TYPE_DRIVER, 371250, 2560, 2778, 2822, 2970, 0, 1080, 1084, 1089, 1250, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, - /* 92 - 2560x1080@120Hz */ + /* 92 - 2560x1080@120Hz 64:27 */ { DRM_MODE("2560x1080", DRM_MODE_TYPE_DRIVER, 495000, 2560, 3108, 3152, 3300, 0, 1080, 1084, 1089, 1250, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, - /* 93 - 3840x2160p@24Hz 16:9 */ + /* 93 - 3840x2160@24Hz 16:9 */ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 5116, 5204, 5500, 0, 2160, 2168, 2178, 2250, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 94 - 3840x2160p@25Hz 16:9 */ + /* 94 - 3840x2160@25Hz 16:9 */ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 4896, 4984, 5280, 0, 2160, 2168, 2178, 2250, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 95 - 3840x2160p@30Hz 16:9 */ + /* 95 - 3840x2160@30Hz 16:9 */ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 4016, 4104, 4400, 0, 2160, 2168, 2178, 2250, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 96 - 3840x2160p@50Hz 16:9 */ + /* 96 - 3840x2160@50Hz 16:9 */ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4896, 4984, 5280, 0, 2160, 2168, 2178, 2250, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 97 - 3840x2160p@60Hz 16:9 */ + /* 97 - 3840x2160@60Hz 16:9 */ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4016, 4104, 4400, 0, 2160, 2168, 2178, 2250, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, - /* 98 - 4096x2160p@24Hz 256:135 */ + /* 98 - 4096x2160@24Hz 256:135 */ { DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 297000, 4096, 5116, 5204, 5500, 0, 2160, 2168, 2178, 2250, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135, }, - /* 99 - 4096x2160p@25Hz 256:135 */ + /* 99 - 4096x2160@25Hz 256:135 */ { DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 297000, 4096, 5064, 5152, 5280, 0, 2160, 2168, 2178, 2250, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135, }, - /* 100 - 4096x2160p@30Hz 256:135 */ + /* 100 - 4096x2160@30Hz 256:135 */ { DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 297000, 4096, 4184, 4272, 4400, 0, 2160, 2168, 2178, 2250, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135, }, - /* 101 - 4096x2160p@50Hz 256:135 */ + /* 101 - 4096x2160@50Hz 256:135 */ { DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 594000, 4096, 5064, 5152, 5280, 0, 2160, 2168, 2178, 2250, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135, }, - /* 102 - 4096x2160p@60Hz 256:135 */ + /* 102 - 4096x2160@60Hz 256:135 */ { DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 594000, 4096, 4184, 4272, 4400, 0, 2160, 2168, 2178, 2250, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135, }, - /* 103 - 3840x2160p@24Hz 64:27 */ + /* 103 - 3840x2160@24Hz 64:27 */ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 5116, 5204, 5500, 0, 2160, 2168, 2178, 2250, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, - /* 104 - 3840x2160p@25Hz 64:27 */ + /* 104 - 3840x2160@25Hz 64:27 */ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 4896, 4984, 5280, 0, 2160, 2168, 2178, 2250, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, - /* 105 - 3840x2160p@30Hz 64:27 */ + /* 105 - 3840x2160@30Hz 64:27 */ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 4016, 4104, 4400, 0, 2160, 2168, 2178, 2250, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, - /* 106 - 3840x2160p@50Hz 64:27 */ + /* 106 - 3840x2160@50Hz 64:27 */ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4896, 4984, 5280, 0, 2160, 2168, 2178, 2250, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, - /* 107 - 3840x2160p@60Hz 64:27 */ + /* 107 - 3840x2160@60Hz 64:27 */ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4016, 4104, 4400, 0, 2160, 2168, 2178, 2250, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), -- GitLab From 10ed55e4d94c39cf32058cc0a2a7935b67e4bc9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Wed, 23 May 2018 17:57:18 +0300 Subject: [PATCH 0118/1506] drm/i915: Initialize panel_pipe to INVALID_PIPE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can always figure out which pipe is affected by the panel power sequencer lockout mechanism. So no need for the pipe A fallback anymore. The only case we may have to worry about is an invalid port select in the power sequencer, but INVALID_PIPE is just fine in that case. We'll get the WARN about the bogus pps port select anyway. Cc: Jani Nikula <jani.nikula@intel.com> Suggested-by: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180523145718.22932-1-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula <jani.nikula@intel.com> --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8b385176ce3c3..b0e8e30616311 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1202,7 +1202,7 @@ void assert_panel_unlocked(struct drm_i915_private *dev_priv, enum pipe pipe) { i915_reg_t pp_reg; u32 val; - enum pipe panel_pipe = PIPE_A; + enum pipe panel_pipe = INVALID_PIPE; bool locked = true; if (WARN_ON(HAS_DDI(dev_priv))) -- GitLab From ea80a661fe56f27821a4fc40f8149be650ec913d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Thu, 24 May 2018 22:04:05 +0300 Subject: [PATCH 0119/1506] drm/i915: Try to suppress more spurious PCH underruns on ILK-IVB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit My ILK seems to generate a spurious PCH underrun with most interlaced HDMI modes. Add a second vblank wait to avoid it. We have seen some spurious PCH underruns still in CI as well, some of which seem to be progressive DP. The logs also point towards some spurious underrins with progressive HDMI on SNB. While I don't have a solid explanation for those let's try to kill all the birds with one stone and always do the double wait. Buzilla: https://bugs.freedesktop.org/show_bug.cgi?id=106387 Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180524190406.2973-1-ville.syrjala@linux.intel.com Acked-by: Chris Wilson <chris@chris-wilson.co.uk> --- drivers/gpu/drm/i915/intel_display.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b0e8e30616311..90a6ff00c79db 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5528,9 +5528,16 @@ static void ironlake_crtc_enable(struct intel_crtc_state *pipe_config, if (HAS_PCH_CPT(dev_priv)) cpt_verify_modeset(dev, intel_crtc->pipe); - /* Must wait for vblank to avoid spurious PCH FIFO underruns */ - if (intel_crtc->config->has_pch_encoder) + /* + * Must wait for vblank to avoid spurious PCH FIFO underruns. + * And a second vblank wait is needed at least on ILK with + * some interlaced HDMI modes. Let's do the double wait always + * in case there are more corner cases we don't know about. + */ + if (intel_crtc->config->has_pch_encoder) { + intel_wait_for_vblank(dev_priv, pipe); intel_wait_for_vblank(dev_priv, pipe); + } intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true); intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, true); } -- GitLab From ca3b3fa344476c640712aa9c49b5bc3b350f2584 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Fri, 18 May 2018 18:01:38 +0300 Subject: [PATCH 0120/1506] drm/i915: Consult VBT "LVDS config" bits to determine whether internal LVDS is present MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VBT seems to have some bits to tell us whether the internal LVDS port has something hooked up. In theory one might expect the VBT to not have a child device for the LVDS port if there's no panel hooked up, but in practice many VBTs still add the child device. The "LVDS config" bits seem more reliable though, so let's check those. So far we've used the "LVDS config" bits to check for eDP support on ILK+, and disable the internal LVDS when the value is 3. That value is actually documented as "Both internal LVDS and SDVO LVDS", but in practice it looks to mean "eDP" on all the ilk+ VBTs I've seen. So let's keep that interpretation, but for pre-ILK we will consider the value 3 to also indicate the presence of the internal LVDS. Currently we have 25 DMI matches for the "no internal LVDS" quirk. In an effort to reduce that let's toss in a WARN when the DMI match and VBT both tell us that the internal LVDS is not present. The hope is that people will report a bug, and then we can just nuke the corresponding entry from the DMI quirk list. Credits to Jani for this idea. v2: Split the basic int_lvds_support thing to a separate patch (Jani) v3: Rebase v4: Limit this to VBT version >= 134 Cc: Jani Nikula <jani.nikula@intel.com> Cc: Ondrej Zary <linux@rainbow-software.org> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180518150138.18361-1-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula <jani.nikula@intel.com> --- drivers/gpu/drm/i915/intel_bios.c | 28 ++++++++++++++++++++++++--- drivers/gpu/drm/i915/intel_lvds.c | 5 ++++- drivers/gpu/drm/i915/intel_vbt_defs.h | 2 +- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index ea7ae8bc0ea0e..1cf073b6ac8a7 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -516,9 +516,31 @@ parse_driver_features(struct drm_i915_private *dev_priv, if (!driver) return; - if (INTEL_GEN(dev_priv) >= 5 && - driver->lvds_config == BDB_DRIVER_FEATURE_EDP) - dev_priv->vbt.int_lvds_support = 0; + if (INTEL_GEN(dev_priv) >= 5) { + /* + * Note that we consider BDB_DRIVER_FEATURE_INT_SDVO_LVDS + * to mean "eDP". The VBT spec doesn't agree with that + * interpretation, but real world VBTs seem to. + */ + if (driver->lvds_config != BDB_DRIVER_FEATURE_INT_LVDS) + dev_priv->vbt.int_lvds_support = 0; + } else { + /* + * FIXME it's not clear which BDB version has the LVDS config + * bits defined. Revision history in the VBT spec says: + * "0.92 | Add two definitions for VBT value of LVDS Active + * Config (00b and 11b values defined) | 06/13/2005" + * but does not the specify the BDB version. + * + * So far version 134 (on i945gm) is the oldest VBT observed + * in the wild with the bits correctly populated. Version + * 108 (on i85x) does not have the bits correctly populated. + */ + if (bdb->version >= 134 && + driver->lvds_config != BDB_DRIVER_FEATURE_INT_LVDS && + driver->lvds_config != BDB_DRIVER_FEATURE_INT_SDVO_LVDS) + dev_priv->vbt.int_lvds_support = 0; + } DRM_DEBUG_KMS("DRRS State Enabled:%d\n", driver->drrs_enabled); /* diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index bacad88ad7ae5..e05c12e7629cc 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -1000,8 +1000,11 @@ void intel_lvds_init(struct drm_i915_private *dev_priv) return; /* Skip init on machines we know falsely report LVDS */ - if (dmi_check_system(intel_no_lvds)) + if (dmi_check_system(intel_no_lvds)) { + WARN(!dev_priv->vbt.int_lvds_support, + "Useless DMI match. Internal LVDS support disabled by VBT\n"); return; + } if (!dev_priv->vbt.int_lvds_support) { DRM_DEBUG_KMS("Internal LVDS support disabled by VBT\n"); diff --git a/drivers/gpu/drm/i915/intel_vbt_defs.h b/drivers/gpu/drm/i915/intel_vbt_defs.h index 458468237b5f9..39c8046241793 100644 --- a/drivers/gpu/drm/i915/intel_vbt_defs.h +++ b/drivers/gpu/drm/i915/intel_vbt_defs.h @@ -635,7 +635,7 @@ struct bdb_sdvo_lvds_options { #define BDB_DRIVER_FEATURE_NO_LVDS 0 #define BDB_DRIVER_FEATURE_INT_LVDS 1 #define BDB_DRIVER_FEATURE_SDVO_LVDS 2 -#define BDB_DRIVER_FEATURE_EDP 3 +#define BDB_DRIVER_FEATURE_INT_SDVO_LVDS 3 struct bdb_driver_features { u8 boot_dev_algorithm:1; -- GitLab From 1add20eb0068fb4526b946e8ae0a94676438a6fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Thu, 5 Apr 2018 22:50:29 +0300 Subject: [PATCH 0121/1506] drm/arc: Stop consulting plane->fb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to stop using plane->fb with atomic driver, so stop looking at it. I have no idea what this code is trying to achieve. There is no corresponding check in the enable path. Also since arc_pgu_set_pxl_fmt() will anyway oops if there is no fb I'm going to assuming that I can just remove the check entirely. There seems to be a general shortage of .atomic_check() in this driver... Cc: Alexey Brodkin <abrodkin@synopsys.com> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180405195035.24722-1-ville.syrjala@linux.intel.com Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Acked-by: Alexey Brodkin <abrodkin@synopys.com> --- drivers/gpu/drm/arc/arcpgu_crtc.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/arc/arcpgu_crtc.c b/drivers/gpu/drm/arc/arcpgu_crtc.c index 16903dc7fe0dc..c3349b8fb58bc 100644 --- a/drivers/gpu/drm/arc/arcpgu_crtc.c +++ b/drivers/gpu/drm/arc/arcpgu_crtc.c @@ -136,9 +136,6 @@ static void arc_pgu_crtc_atomic_disable(struct drm_crtc *crtc, { struct arcpgu_drm_private *arcpgu = crtc_to_arcpgu_priv(crtc); - if (!crtc->primary->fb) - return; - clk_disable_unprepare(arcpgu->clk); arc_pgu_write(arcpgu, ARCPGU_REG_CTRL, arc_pgu_read(arcpgu, ARCPGU_REG_CTRL) & -- GitLab From 42eb2f729e55a521e10dbb6dea6d736e0ad6df2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Thu, 5 Apr 2018 18:13:48 +0300 Subject: [PATCH 0122/1506] drm/msm: Stop consulting plane->fb/crtc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to get rid of plane->fb/crtc on atomic drivers. Stop looking at them. v2: Catch the plane->crtc case too Cc: Rob Clark <robdclark@gmail.com> Cc: linux-arm-msm@vger.kernel.org Cc: freedreno@lists.freedesktop.org Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> #v1 Link: https://patchwork.freedesktop.org/patch/msgid/20180405151400.11326-1-ville.syrjala@linux.intel.com Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> --- drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c | 2 +- drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c index b001699297c48..20f9e5de5f19f 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c @@ -201,7 +201,7 @@ static void blend_setup(struct drm_crtc *crtc) int idx = idxs[pipe_id]; if (idx > 0) { const struct mdp_format *format = - to_mdp_format(msm_framebuffer_format(plane->fb)); + to_mdp_format(msm_framebuffer_format(plane->state->fb)); alpha[idx-1] = format->alpha_enable; } } diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c index a9f31da7d45ad..f2361f79fdce2 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c @@ -526,7 +526,7 @@ static void mdp5_plane_atomic_async_update(struct drm_plane *plane, if (plane_enabled(new_state)) { struct mdp5_ctl *ctl; struct mdp5_pipeline *pipeline = - mdp5_crtc_get_pipeline(plane->crtc); + mdp5_crtc_get_pipeline(new_state->crtc); int ret; ret = mdp5_plane_mode_set(plane, new_state->crtc, new_state->fb, -- GitLab From df751849219b1be87c86b3224cf07fd0de4c5228 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Thu, 5 Apr 2018 18:13:49 +0300 Subject: [PATCH 0123/1506] drm/sti: Stop consulting plane->crtc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to get rid of plane->crtc on atomic drivers. Stop looking at it. Cc: Benjamin Gaignard <benjamin.gaignard@linaro.org> Cc: Vincent Abriou <vincent.abriou@st.com> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180405151400.11326-2-ville.syrjala@linux.intel.com Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> --- drivers/gpu/drm/sti/sti_gdp.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c index 9b2c47051b51e..49813d34bdf06 100644 --- a/drivers/gpu/drm/sti/sti_gdp.c +++ b/drivers/gpu/drm/sti/sti_gdp.c @@ -211,7 +211,11 @@ static int gdp_dbg_show(struct seq_file *s, void *data) struct drm_info_node *node = s->private; struct sti_gdp *gdp = (struct sti_gdp *)node->info_ent->data; struct drm_plane *drm_plane = &gdp->plane.drm_plane; - struct drm_crtc *crtc = drm_plane->crtc; + struct drm_crtc *crtc; + + drm_modeset_lock(&drm_plane->mutex, NULL); + crtc = drm_plane->state->crtc; + drm_modeset_unlock(&drm_plane->mutex); seq_printf(s, "%s: (vaddr = 0x%p)", sti_plane_to_str(&gdp->plane), gdp->regs); -- GitLab From 0010ac3ffc0e2638b08869bef2588673e04b257d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Thu, 5 Apr 2018 18:13:50 +0300 Subject: [PATCH 0124/1506] drm/atmel-hlcdc: Stop consulting plane->crtc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to get rid of plane->crtc on atomic drivers. Stop looking at it. Cc: Boris Brezillon <boris.brezillon@free-electrons.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180405151400.11326-3-ville.syrjala@linux.intel.com Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> --- drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c index 73c875db45f43..15c74527ba49f 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c @@ -412,9 +412,10 @@ static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane, ATMEL_HLCDC_LAYER_FORMAT_CFG, cfg); } -static void atmel_hlcdc_plane_update_clut(struct atmel_hlcdc_plane *plane) +static void atmel_hlcdc_plane_update_clut(struct atmel_hlcdc_plane *plane, + struct atmel_hlcdc_plane_state *state) { - struct drm_crtc *crtc = plane->base.crtc; + struct drm_crtc *crtc = state->base.crtc; struct drm_color_lut *lut; int idx; @@ -779,7 +780,7 @@ static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p, atmel_hlcdc_plane_update_pos_and_size(plane, state); atmel_hlcdc_plane_update_general_settings(plane, state); atmel_hlcdc_plane_update_format(plane, state); - atmel_hlcdc_plane_update_clut(plane); + atmel_hlcdc_plane_update_clut(plane, state); atmel_hlcdc_plane_update_buffers(plane, state); atmel_hlcdc_plane_update_disc_area(plane, state); -- GitLab From 3ed70ecd865943a2cbe9b1631f33c9370bc03578 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Thu, 5 Apr 2018 18:14:00 +0300 Subject: [PATCH 0125/1506] drm: Add local 'plane' variable for tmp->primary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clean up the ugly tmp->primary-> stuff in __drm_mode_set_config_internal() with a local plane variable. Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Suggested-by: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180405151400.11326-13-ville.syrjala@linux.intel.com Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> --- drivers/gpu/drm/drm_crtc.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 98a36e6c69ad1..237bd34212dbf 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -469,8 +469,11 @@ static int __drm_mode_set_config_internal(struct drm_mode_set *set, * connectors from it), hence we need to refcount the fbs across all * crtcs. Atomic modeset will have saner semantics ... */ - drm_for_each_crtc(tmp, crtc->dev) - tmp->primary->old_fb = tmp->primary->fb; + drm_for_each_crtc(tmp, crtc->dev) { + struct drm_plane *plane = tmp->primary; + + plane->old_fb = plane->fb; + } fb = set->fb; @@ -481,11 +484,13 @@ static int __drm_mode_set_config_internal(struct drm_mode_set *set, } drm_for_each_crtc(tmp, crtc->dev) { - if (tmp->primary->fb) - drm_framebuffer_get(tmp->primary->fb); - if (tmp->primary->old_fb) - drm_framebuffer_put(tmp->primary->old_fb); - tmp->primary->old_fb = NULL; + struct drm_plane *plane = tmp->primary; + + if (plane->fb) + drm_framebuffer_get(plane->fb); + if (plane->old_fb) + drm_framebuffer_put(plane->old_fb); + plane->old_fb = NULL; } return ret; -- GitLab From b79df2767cc6bcb5da169d147fc199512a527d4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Thu, 5 Apr 2018 18:13:58 +0300 Subject: [PATCH 0126/1506] drm/omapdrm: Nuke omap_framebuffer_get_next_connector() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit omap_framebuffer_get_next_connector() uses plane->fb which we want to deprecate for atomic drivers. As omap_framebuffer_get_next_connector() is unused just nuke the entire function. Cc: Tomi Valkeinen <tomi.valkeinen@ti.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180405151400.11326-11-ville.syrjala@linux.intel.com Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ti.com> --- drivers/gpu/drm/omapdrm/omap_fb.c | 27 --------------------------- drivers/gpu/drm/omapdrm/omap_fb.h | 2 -- 2 files changed, 29 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/omap_fb.c b/drivers/gpu/drm/omapdrm/omap_fb.c index 9d75eab0d1649..9f1e3d8f8488c 100644 --- a/drivers/gpu/drm/omapdrm/omap_fb.c +++ b/drivers/gpu/drm/omapdrm/omap_fb.c @@ -279,33 +279,6 @@ void omap_framebuffer_unpin(struct drm_framebuffer *fb) mutex_unlock(&omap_fb->lock); } -/* iterate thru all the connectors, returning ones that are attached - * to the same fb.. - */ -struct drm_connector *omap_framebuffer_get_next_connector( - struct drm_framebuffer *fb, struct drm_connector *from) -{ - struct drm_device *dev = fb->dev; - struct list_head *connector_list = &dev->mode_config.connector_list; - struct drm_connector *connector = from; - - if (!from) - return list_first_entry_or_null(connector_list, typeof(*from), - head); - - list_for_each_entry_from(connector, connector_list, head) { - if (connector != from) { - struct drm_encoder *encoder = connector->encoder; - struct drm_crtc *crtc = encoder ? encoder->crtc : NULL; - if (crtc && crtc->primary->fb == fb) - return connector; - - } - } - - return NULL; -} - #ifdef CONFIG_DEBUG_FS void omap_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m) { diff --git a/drivers/gpu/drm/omapdrm/omap_fb.h b/drivers/gpu/drm/omapdrm/omap_fb.h index 94ad5f9e44049..c20cb4bc714da 100644 --- a/drivers/gpu/drm/omapdrm/omap_fb.h +++ b/drivers/gpu/drm/omapdrm/omap_fb.h @@ -38,8 +38,6 @@ int omap_framebuffer_pin(struct drm_framebuffer *fb); void omap_framebuffer_unpin(struct drm_framebuffer *fb); void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, struct drm_plane_state *state, struct omap_overlay_info *info); -struct drm_connector *omap_framebuffer_get_next_connector( - struct drm_framebuffer *fb, struct drm_connector *from); bool omap_framebuffer_supports_rotation(struct drm_framebuffer *fb); void omap_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m); -- GitLab From 952a08a21ac537c2a0e5c481e8cf3a2426311f56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Thu, 5 Apr 2018 18:13:57 +0300 Subject: [PATCH 0127/1506] drm/atmel-hlcdc: Stop using plane->fb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to get rid of plane->fb on atomic drivers. Stop looking at it. Daniel pointed out that the drm_framebuffer_put() in the plane cleanup indicates that the driver doesn't shut things down cleanly. To do that we should be able to just call drm_atomic_helper_shutdown(). Not really sure the current cleanup sequence is actually sane, but whatever. v2: Replace the drm_framebuffer_put() with drm_atomic_helper_shutdown() (Daniel) Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Cc: Boris Brezillon <boris.brezillon@free-electrons.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180405151400.11326-10-ville.syrjala@linux.intel.com Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> --- drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c | 1 + drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | 12 +----------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c index c1ea5c36b0061..843cac222e60d 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c @@ -681,6 +681,7 @@ static void atmel_hlcdc_dc_unload(struct drm_device *dev) drm_fb_cma_fbdev_fini(dev); flush_workqueue(dc->wq); drm_kms_helper_poll_fini(dev); + drm_atomic_helper_shutdown(dev); drm_mode_config_cleanup(dev); pm_runtime_get_sync(dev->dev); diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c index 15c74527ba49f..1aecc74cc463d 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c @@ -817,16 +817,6 @@ static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p, atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR); } -static void atmel_hlcdc_plane_destroy(struct drm_plane *p) -{ - struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); - - if (plane->base.fb) - drm_framebuffer_put(plane->base.fb); - - drm_plane_cleanup(p); -} - static int atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane) { const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc; @@ -1003,7 +993,7 @@ static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *p, static const struct drm_plane_funcs layer_plane_funcs = { .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, - .destroy = atmel_hlcdc_plane_destroy, + .destroy = drm_plane_cleanup, .reset = atmel_hlcdc_plane_reset, .atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state, .atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state, -- GitLab From 2b5b63126ef4037a576bc8f9954629dc22274ad2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Thu, 24 May 2018 22:04:06 +0300 Subject: [PATCH 0128/1506] drm/i915: Simplify ilk-ivb underrun suppression MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's suppress the underruns around every modeset sequence instead of trying to avoid it. Planes are disabled at this point anyway so we don't really gain anything from keeping the underrun reporting enabled. Also for PCH ports we already suppress all underruns here anyway so trying avoid it for the CPU eDP doesn't seem all that important. Maybe this gets rid of some lingering spurious underruns? Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180524190406.2973-2-ville.syrjala@linux.intel.com Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> --- drivers/gpu/drm/i915/intel_display.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 90a6ff00c79db..8d4c9e249c44f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5470,10 +5470,8 @@ static void ironlake_crtc_enable(struct intel_crtc_state *pipe_config, * * Spurious PCH underruns also occur during PCH enabling. */ - if (intel_crtc->config->has_pch_encoder || IS_GEN5(dev_priv)) - intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false); - if (intel_crtc->config->has_pch_encoder) - intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, false); + intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false); + intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, false); if (intel_crtc->config->has_pch_encoder) intel_prepare_shared_dpll(intel_crtc); @@ -5717,10 +5715,8 @@ static void ironlake_crtc_disable(struct intel_crtc_state *old_crtc_state, * pipe is already disabled, but FDI RX/TX is still enabled. * Happens at least with VGA+HDMI cloning. Suppress them. */ - if (intel_crtc->config->has_pch_encoder) { - intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false); - intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, false); - } + intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false); + intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, false); intel_encoders_disable(crtc, old_crtc_state, old_state); -- GitLab From 8f1ad1ef1e7ac916a0b344e5e473f52b9159fc87 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko <michal.wajdeczko@intel.com> Date: Fri, 25 May 2018 12:18:58 +0000 Subject: [PATCH 0129/1506] drm/i915/uc: Trivial s/dev_priv/i915 in intel_uc.c Some functions already use i915 name instead of dev_priv. Let's rename this param in all remaining functions, except those that still use legacy macros. v2: don't forget about function descriptions (Sagar) v3: rebased v4: rebased v5: rebased, pulled out from the series Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com> Reviewed-by: Sagar Arun Kamble <sagar.a.kamble@intel.com> Cc: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20180525121858.53928-1-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/intel_uc.c | 129 ++++++++++++++++---------------- 1 file changed, 64 insertions(+), 65 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_uc.c b/drivers/gpu/drm/i915/intel_uc.c index 1cffaf7b5dbef..6a73e81f373b6 100644 --- a/drivers/gpu/drm/i915/intel_uc.c +++ b/drivers/gpu/drm/i915/intel_uc.c @@ -50,10 +50,10 @@ static int __intel_uc_reset_hw(struct drm_i915_private *dev_priv) return ret; } -static int __get_platform_enable_guc(struct drm_i915_private *dev_priv) +static int __get_platform_enable_guc(struct drm_i915_private *i915) { - struct intel_uc_fw *guc_fw = &dev_priv->guc.fw; - struct intel_uc_fw *huc_fw = &dev_priv->huc.fw; + struct intel_uc_fw *guc_fw = &i915->guc.fw; + struct intel_uc_fw *huc_fw = &i915->huc.fw; int enable_guc = 0; /* Default is to enable GuC/HuC if we know their firmwares */ @@ -67,11 +67,11 @@ static int __get_platform_enable_guc(struct drm_i915_private *dev_priv) return enable_guc; } -static int __get_default_guc_log_level(struct drm_i915_private *dev_priv) +static int __get_default_guc_log_level(struct drm_i915_private *i915) { int guc_log_level; - if (!HAS_GUC(dev_priv) || !intel_uc_is_using_guc()) + if (!HAS_GUC(i915) || !intel_uc_is_using_guc()) guc_log_level = GUC_LOG_LEVEL_DISABLED; else if (IS_ENABLED(CONFIG_DRM_I915_DEBUG) || IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)) @@ -86,7 +86,7 @@ static int __get_default_guc_log_level(struct drm_i915_private *dev_priv) /** * sanitize_options_early - sanitize uC related modparam options - * @dev_priv: device private + * @i915: device private * * In case of "enable_guc" option this function will attempt to modify * it only if it was initially set to "auto(-1)". Default value for this @@ -101,14 +101,14 @@ static int __get_default_guc_log_level(struct drm_i915_private *dev_priv) * unless GuC is enabled on given platform and the driver is compiled with * debug config when this modparam will default to "enable(1..4)". */ -static void sanitize_options_early(struct drm_i915_private *dev_priv) +static void sanitize_options_early(struct drm_i915_private *i915) { - struct intel_uc_fw *guc_fw = &dev_priv->guc.fw; - struct intel_uc_fw *huc_fw = &dev_priv->huc.fw; + struct intel_uc_fw *guc_fw = &i915->guc.fw; + struct intel_uc_fw *huc_fw = &i915->huc.fw; /* A negative value means "use platform default" */ if (i915_modparams.enable_guc < 0) - i915_modparams.enable_guc = __get_platform_enable_guc(dev_priv); + i915_modparams.enable_guc = __get_platform_enable_guc(i915); DRM_DEBUG_DRIVER("enable_guc=%d (submission:%s huc:%s)\n", i915_modparams.enable_guc, @@ -119,28 +119,28 @@ static void sanitize_options_early(struct drm_i915_private *dev_priv) if (intel_uc_is_using_guc() && !intel_uc_fw_is_selected(guc_fw)) { DRM_WARN("Incompatible option detected: %s=%d, %s!\n", "enable_guc", i915_modparams.enable_guc, - !HAS_GUC(dev_priv) ? "no GuC hardware" : - "no GuC firmware"); + !HAS_GUC(i915) ? "no GuC hardware" : + "no GuC firmware"); } /* Verify HuC firmware availability */ if (intel_uc_is_using_huc() && !intel_uc_fw_is_selected(huc_fw)) { DRM_WARN("Incompatible option detected: %s=%d, %s!\n", "enable_guc", i915_modparams.enable_guc, - !HAS_HUC(dev_priv) ? "no HuC hardware" : - "no HuC firmware"); + !HAS_HUC(i915) ? "no HuC hardware" : + "no HuC firmware"); } /* A negative value means "use platform/config default" */ if (i915_modparams.guc_log_level < 0) i915_modparams.guc_log_level = - __get_default_guc_log_level(dev_priv); + __get_default_guc_log_level(i915); if (i915_modparams.guc_log_level > 0 && !intel_uc_is_using_guc()) { DRM_WARN("Incompatible option detected: %s=%d, %s!\n", "guc_log_level", i915_modparams.guc_log_level, - !HAS_GUC(dev_priv) ? "no GuC hardware" : - "GuC not enabled"); + !HAS_GUC(i915) ? "no GuC hardware" : + "GuC not enabled"); i915_modparams.guc_log_level = 0; } @@ -195,15 +195,14 @@ void intel_uc_cleanup_early(struct drm_i915_private *i915) /** * intel_uc_init_mmio - setup uC MMIO access - * - * @dev_priv: device private + * @i915: device private * * Setup minimal state necessary for MMIO accesses later in the * initialization sequence. */ -void intel_uc_init_mmio(struct drm_i915_private *dev_priv) +void intel_uc_init_mmio(struct drm_i915_private *i915) { - intel_guc_init_send_regs(&dev_priv->guc); + intel_guc_init_send_regs(&i915->guc); } static void guc_capture_load_err_log(struct intel_guc *guc) @@ -225,11 +224,11 @@ static void guc_free_load_err_log(struct intel_guc *guc) static int guc_enable_communication(struct intel_guc *guc) { - struct drm_i915_private *dev_priv = guc_to_i915(guc); + struct drm_i915_private *i915 = guc_to_i915(guc); - gen9_enable_guc_interrupts(dev_priv); + gen9_enable_guc_interrupts(i915); - if (HAS_GUC_CT(dev_priv)) + if (HAS_GUC_CT(i915)) return intel_guc_ct_enable(&guc->ct); guc->send = intel_guc_send_mmio; @@ -239,23 +238,23 @@ static int guc_enable_communication(struct intel_guc *guc) static void guc_disable_communication(struct intel_guc *guc) { - struct drm_i915_private *dev_priv = guc_to_i915(guc); + struct drm_i915_private *i915 = guc_to_i915(guc); - if (HAS_GUC_CT(dev_priv)) + if (HAS_GUC_CT(i915)) intel_guc_ct_disable(&guc->ct); - gen9_disable_guc_interrupts(dev_priv); + gen9_disable_guc_interrupts(i915); guc->send = intel_guc_send_nop; guc->handler = intel_guc_to_host_event_handler_nop; } -int intel_uc_init_misc(struct drm_i915_private *dev_priv) +int intel_uc_init_misc(struct drm_i915_private *i915) { - struct intel_guc *guc = &dev_priv->guc; + struct intel_guc *guc = &i915->guc; int ret; - if (!USES_GUC(dev_priv)) + if (!USES_GUC(i915)) return 0; intel_guc_init_ggtt_pin_bias(guc); @@ -267,32 +266,32 @@ int intel_uc_init_misc(struct drm_i915_private *dev_priv) return 0; } -void intel_uc_fini_misc(struct drm_i915_private *dev_priv) +void intel_uc_fini_misc(struct drm_i915_private *i915) { - struct intel_guc *guc = &dev_priv->guc; + struct intel_guc *guc = &i915->guc; - if (!USES_GUC(dev_priv)) + if (!USES_GUC(i915)) return; intel_guc_fini_wq(guc); } -int intel_uc_init(struct drm_i915_private *dev_priv) +int intel_uc_init(struct drm_i915_private *i915) { - struct intel_guc *guc = &dev_priv->guc; + struct intel_guc *guc = &i915->guc; int ret; - if (!USES_GUC(dev_priv)) + if (!USES_GUC(i915)) return 0; - if (!HAS_GUC(dev_priv)) + if (!HAS_GUC(i915)) return -ENODEV; ret = intel_guc_init(guc); if (ret) return ret; - if (USES_GUC_SUBMISSION(dev_priv)) { + if (USES_GUC_SUBMISSION(i915)) { /* * This is stuff we need to have available at fw load time * if we are planning to enable submission later @@ -307,16 +306,16 @@ int intel_uc_init(struct drm_i915_private *dev_priv) return 0; } -void intel_uc_fini(struct drm_i915_private *dev_priv) +void intel_uc_fini(struct drm_i915_private *i915) { - struct intel_guc *guc = &dev_priv->guc; + struct intel_guc *guc = &i915->guc; - if (!USES_GUC(dev_priv)) + if (!USES_GUC(i915)) return; - GEM_BUG_ON(!HAS_GUC(dev_priv)); + GEM_BUG_ON(!HAS_GUC(i915)); - if (USES_GUC_SUBMISSION(dev_priv)) + if (USES_GUC_SUBMISSION(i915)) intel_guc_submission_fini(guc); intel_guc_fini(guc); @@ -340,22 +339,22 @@ void intel_uc_sanitize(struct drm_i915_private *i915) __intel_uc_reset_hw(i915); } -int intel_uc_init_hw(struct drm_i915_private *dev_priv) +int intel_uc_init_hw(struct drm_i915_private *i915) { - struct intel_guc *guc = &dev_priv->guc; - struct intel_huc *huc = &dev_priv->huc; + struct intel_guc *guc = &i915->guc; + struct intel_huc *huc = &i915->huc; int ret, attempts; - if (!USES_GUC(dev_priv)) + if (!USES_GUC(i915)) return 0; - GEM_BUG_ON(!HAS_GUC(dev_priv)); + GEM_BUG_ON(!HAS_GUC(i915)); - gen9_reset_guc_interrupts(dev_priv); + gen9_reset_guc_interrupts(i915); /* WaEnableuKernelHeaderValidFix:skl */ /* WaEnableGuCBootHashCheckNotSet:skl,bxt,kbl */ - if (IS_GEN9(dev_priv)) + if (IS_GEN9(i915)) attempts = 3; else attempts = 1; @@ -365,11 +364,11 @@ int intel_uc_init_hw(struct drm_i915_private *dev_priv) * Always reset the GuC just before (re)loading, so * that the state and timing are fairly predictable */ - ret = __intel_uc_reset_hw(dev_priv); + ret = __intel_uc_reset_hw(i915); if (ret) goto err_out; - if (USES_HUC(dev_priv)) { + if (USES_HUC(i915)) { ret = intel_huc_fw_upload(huc); if (ret) goto err_out; @@ -392,24 +391,24 @@ int intel_uc_init_hw(struct drm_i915_private *dev_priv) if (ret) goto err_log_capture; - if (USES_HUC(dev_priv)) { + if (USES_HUC(i915)) { ret = intel_huc_auth(huc); if (ret) goto err_communication; } - if (USES_GUC_SUBMISSION(dev_priv)) { + if (USES_GUC_SUBMISSION(i915)) { ret = intel_guc_submission_enable(guc); if (ret) goto err_communication; } - dev_info(dev_priv->drm.dev, "GuC firmware version %u.%u\n", + dev_info(i915->drm.dev, "GuC firmware version %u.%u\n", guc->fw.major_ver_found, guc->fw.minor_ver_found); - dev_info(dev_priv->drm.dev, "GuC submission %s\n", - enableddisabled(USES_GUC_SUBMISSION(dev_priv))); - dev_info(dev_priv->drm.dev, "HuC %s\n", - enableddisabled(USES_HUC(dev_priv))); + dev_info(i915->drm.dev, "GuC submission %s\n", + enableddisabled(USES_GUC_SUBMISSION(i915))); + dev_info(i915->drm.dev, "HuC %s\n", + enableddisabled(USES_HUC(i915))); return 0; @@ -428,20 +427,20 @@ int intel_uc_init_hw(struct drm_i915_private *dev_priv) if (GEM_WARN_ON(ret == -EIO)) ret = -EINVAL; - dev_err(dev_priv->drm.dev, "GuC initialization failed %d\n", ret); + dev_err(i915->drm.dev, "GuC initialization failed %d\n", ret); return ret; } -void intel_uc_fini_hw(struct drm_i915_private *dev_priv) +void intel_uc_fini_hw(struct drm_i915_private *i915) { - struct intel_guc *guc = &dev_priv->guc; + struct intel_guc *guc = &i915->guc; - if (!USES_GUC(dev_priv)) + if (!USES_GUC(i915)) return; - GEM_BUG_ON(!HAS_GUC(dev_priv)); + GEM_BUG_ON(!HAS_GUC(i915)); - if (USES_GUC_SUBMISSION(dev_priv)) + if (USES_GUC_SUBMISSION(i915)) intel_guc_submission_disable(guc); guc_disable_communication(guc); -- GitLab From 6b1c5eaf5cfd994bc364ce367ab4cd1f572cc476 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann <arnd@arndb.de> Date: Fri, 25 May 2018 17:50:08 +0200 Subject: [PATCH 0130/1506] drm/sun4i: mark PM functions as __maybe_unused Disabling CONFIG_PM produces a compile time warning when these functions are not referenced: drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c:1072:12: error: 'sun6i_dsi_runtime_suspend' defined but not used [-Werror=unused-function] static int sun6i_dsi_runtime_suspend(struct device *dev) ^~~~~~~~~~~~~~~~~~~~~~~~~ drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c:1043:12: error: 'sun6i_dsi_runtime_resume' defined but not used [-Werror=unused-function] static int sun6i_dsi_runtime_resume(struct device *dev) ^~~~~~~~~~~~~~~~~~~~~~~~ Fixes: 133add5b5ad4 ("drm/sun4i: Add Allwinner A31 MIPI-DSI controller support") Signed-off-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180525155030.3667352-1-arnd@arndb.de --- drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c index bfbf761f0c1dd..d4e7d16a2514e 100644 --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c @@ -1040,7 +1040,7 @@ static int sun6i_dsi_remove(struct platform_device *pdev) return 0; } -static int sun6i_dsi_runtime_resume(struct device *dev) +static int __maybe_unused sun6i_dsi_runtime_resume(struct device *dev) { struct sun6i_dsi *dsi = dev_get_drvdata(dev); @@ -1069,7 +1069,7 @@ static int sun6i_dsi_runtime_resume(struct device *dev) return 0; } -static int sun6i_dsi_runtime_suspend(struct device *dev) +static int __maybe_unused sun6i_dsi_runtime_suspend(struct device *dev) { struct sun6i_dsi *dsi = dev_get_drvdata(dev); -- GitLab From d104328ce352eec23e608dab875f2ad2fead60fb Mon Sep 17 00:00:00 2001 From: Daniel Vetter <daniel.vetter@ffwll.ch> Date: Thu, 24 May 2018 11:01:05 +0200 Subject: [PATCH 0131/1506] drm/fb-helper: Fix typo on kerneldoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Copypasta mistake. Fixes: 742547b73d27 ("drm/fb_helper: Create wrappers for blit, copyarea and fillrect funcs") Cc: Archit Taneja <architt@codeaurora.org> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Cc: Gustavo Padovan <gustavo@padovan.org> Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Cc: Sean Paul <seanpaul@chromium.org> Cc: David Airlie <airlied@linux.ie> Cc: dri-devel@lists.freedesktop.org Acked-by: Noralf Trønnes <noralf@tronnes.org> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180524090105.21196-1-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_fb_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 2ee1eaa661880..91f051e5e130f 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -1164,7 +1164,7 @@ EXPORT_SYMBOL(drm_fb_helper_sys_imageblit); * @info: fbdev registered by the helper * @rect: info about rectangle to fill * - * A wrapper around cfb_imageblit implemented by fbdev core + * A wrapper around cfb_fillrect implemented by fbdev core */ void drm_fb_helper_cfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) -- GitLab From 6c2590914cffa9212874da5c1eddfcfe6553bda6 Mon Sep 17 00:00:00 2001 From: Souptick Joarder <jrdr.linux@gmail.com> Date: Thu, 10 May 2018 19:12:04 +0530 Subject: [PATCH 0132/1506] gpu: drm: drm_vm: Adding new typedef vm_fault_t Use new return type vm_fault_t for fault handler. For now, this is just documenting that the function returns a VM_FAULT value rather than an errno. Once all instances are converted, vm_fault_t will become a distinct type. commit 1c8f422059ae ("mm: change return type to vm_fault_t") Signed-off-by: Souptick Joarder <jrdr.linux@gmail.com> Reviewed-by: Matthew Wilcox <mawilcox@microsoft.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180510134203.GA25166@jordon-HP-15-Notebook-PC --- drivers/gpu/drm/drm_vm.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/drm_vm.c b/drivers/gpu/drm/drm_vm.c index 2660543ad86a5..c3301046dfaa5 100644 --- a/drivers/gpu/drm/drm_vm.c +++ b/drivers/gpu/drm/drm_vm.c @@ -100,7 +100,7 @@ static pgprot_t drm_dma_prot(uint32_t map_type, struct vm_area_struct *vma) * map, get the page, increment the use count and return it. */ #if IS_ENABLED(CONFIG_AGP) -static int drm_vm_fault(struct vm_fault *vmf) +static vm_fault_t drm_vm_fault(struct vm_fault *vmf) { struct vm_area_struct *vma = vmf->vma; struct drm_file *priv = vma->vm_file->private_data; @@ -173,7 +173,7 @@ static int drm_vm_fault(struct vm_fault *vmf) return VM_FAULT_SIGBUS; /* Disallow mremap */ } #else -static int drm_vm_fault(struct vm_fault *vmf) +static vm_fault_t drm_vm_fault(struct vm_fault *vmf) { return VM_FAULT_SIGBUS; } @@ -189,7 +189,7 @@ static int drm_vm_fault(struct vm_fault *vmf) * Get the mapping, find the real physical page to map, get the page, and * return it. */ -static int drm_vm_shm_fault(struct vm_fault *vmf) +static vm_fault_t drm_vm_shm_fault(struct vm_fault *vmf) { struct vm_area_struct *vma = vmf->vma; struct drm_local_map *map = vma->vm_private_data; @@ -291,7 +291,7 @@ static void drm_vm_shm_close(struct vm_area_struct *vma) * * Determine the page number from the page offset and get it from drm_device_dma::pagelist. */ -static int drm_vm_dma_fault(struct vm_fault *vmf) +static vm_fault_t drm_vm_dma_fault(struct vm_fault *vmf) { struct vm_area_struct *vma = vmf->vma; struct drm_file *priv = vma->vm_file->private_data; @@ -326,7 +326,7 @@ static int drm_vm_dma_fault(struct vm_fault *vmf) * * Determine the map offset from the page offset and get it from drm_sg_mem::pagelist. */ -static int drm_vm_sg_fault(struct vm_fault *vmf) +static vm_fault_t drm_vm_sg_fault(struct vm_fault *vmf) { struct vm_area_struct *vma = vmf->vma; struct drm_local_map *map = vma->vm_private_data; -- GitLab From 3c7ab27896804ebda7499969befbdbfbc4edaa53 Mon Sep 17 00:00:00 2001 From: Oscar Mateo <oscar.mateo@intel.com> Date: Fri, 25 May 2018 15:05:29 -0700 Subject: [PATCH 0133/1506] drm/i915/icl: WaDisableImprovedTdlClkGating Revert to the legacy implementation. v2: GEN7_ROW_CHICKEN2 is masked v3: - Rebased - Renamed to Wa_2006611047 - A0 and B0 only v4: - Add spaces around '<<' (and fix the surrounding code as well) - Mark the WA as pre-prod v5: Rebased on top of the WA refactoring v6: Added References (Mika) v7: Fixed in B0 References: HSDES#2006611047 Signed-off-by: Oscar Mateo <oscar.mateo@intel.com> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/1527285939-20113-2-git-send-email-oscar.mateo@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 5 +++-- drivers/gpu/drm/i915/intel_workarounds.c | 7 +++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 6953419881c48..4eb159faf06db 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -8328,8 +8328,9 @@ enum { #define GEN7_ROW_CHICKEN2 _MMIO(0xe4f4) #define GEN7_ROW_CHICKEN2_GT2 _MMIO(0xf4f4) -#define DOP_CLOCK_GATING_DISABLE (1<<0) -#define PUSH_CONSTANT_DEREF_DISABLE (1<<8) +#define DOP_CLOCK_GATING_DISABLE (1 << 0) +#define PUSH_CONSTANT_DEREF_DISABLE (1 << 8) +#define GEN11_TDL_CLOCK_GATING_FIX_DISABLE (1 << 1) #define HSW_ROW_CHICKEN3 _MMIO(0xe49c) #define HSW_ROW_CHICKEN3_L3_GLOBAL_ATOMICS_DISABLE (1 << 6) diff --git a/drivers/gpu/drm/i915/intel_workarounds.c b/drivers/gpu/drm/i915/intel_workarounds.c index cea57104de134..04aa88506edc6 100644 --- a/drivers/gpu/drm/i915/intel_workarounds.c +++ b/drivers/gpu/drm/i915/intel_workarounds.c @@ -463,6 +463,13 @@ static int icl_ctx_workarounds_init(struct drm_i915_private *dev_priv) */ WA_SET_BIT_MASKED(ICL_HDC_MODE, HDC_FORCE_NON_COHERENT); + /* Wa_2006611047:icl (pre-prod) + * Formerly known as WaDisableImprovedTdlClkGating + */ + if (IS_ICL_REVID(dev_priv, ICL_REVID_A0, ICL_REVID_A0)) + WA_SET_BIT_MASKED(GEN7_ROW_CHICKEN2, + GEN11_TDL_CLOCK_GATING_FIX_DISABLE); + return 0; } -- GitLab From f63c7b4880aabaf7423b301be438bd47a6720ddc Mon Sep 17 00:00:00 2001 From: Oscar Mateo <oscar.mateo@intel.com> Date: Fri, 25 May 2018 15:05:30 -0700 Subject: [PATCH 0134/1506] drm/i915/icl: WaEnableStateCacheRedirectToCS Redirects the state cache to the CS Command buffer section for performance reasons. v2: Rebased v3: Rebased on top of the WA refactoring v3: Added References (Mika) References: HSDES#1604325460 Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Signed-off-by: Oscar Mateo <oscar.mateo@intel.com> Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/1527285939-20113-3-git-send-email-oscar.mateo@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_workarounds.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 4eb159faf06db..924b9a6b1cd0d 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -7227,6 +7227,7 @@ enum { #define DISABLE_PIXEL_MASK_CAMMING (1<<14) #define GEN9_SLICE_COMMON_ECO_CHICKEN1 _MMIO(0x731c) +#define GEN11_STATE_CACHE_REDIRECT_TO_CS (1 << 11) #define GEN7_L3SQCREG1 _MMIO(0xB010) #define VLV_B0_WA_L3SQCREG1_VALUE 0x00D30000 diff --git a/drivers/gpu/drm/i915/intel_workarounds.c b/drivers/gpu/drm/i915/intel_workarounds.c index 04aa88506edc6..1d298035b1d24 100644 --- a/drivers/gpu/drm/i915/intel_workarounds.c +++ b/drivers/gpu/drm/i915/intel_workarounds.c @@ -470,6 +470,10 @@ static int icl_ctx_workarounds_init(struct drm_i915_private *dev_priv) WA_SET_BIT_MASKED(GEN7_ROW_CHICKEN2, GEN11_TDL_CLOCK_GATING_FIX_DISABLE); + /* WaEnableStateCacheRedirectToCS:icl */ + WA_SET_BIT_MASKED(GEN9_SLICE_COMMON_ECO_CHICKEN1, + GEN11_STATE_CACHE_REDIRECT_TO_CS); + return 0; } -- GitLab From b1f88820f4d7ea5b98f331abb50588cdc77b248a Mon Sep 17 00:00:00 2001 From: Oscar Mateo <oscar.mateo@intel.com> Date: Fri, 25 May 2018 15:05:31 -0700 Subject: [PATCH 0135/1506] drm/i915/icl: Wa_2006665173 Disable blend embellishment in RCC. Also, some other registers style fixed in passing. v2: Rebased on top of the WA refactoring v3: Added References (Mika) v4: - Fixed in B0 - Mentioned style fixes in commit message References: HSDES#2006665173 Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Signed-off-by: Oscar Mateo <oscar.mateo@intel.com> Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/1527285939-20113-4-git-send-email-oscar.mateo@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 18 +++++++++++------- drivers/gpu/drm/i915/intel_workarounds.c | 5 +++++ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 924b9a6b1cd0d..6e88c6bf3911b 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -7211,13 +7211,17 @@ enum { /* GEN7 chicken */ #define GEN7_COMMON_SLICE_CHICKEN1 _MMIO(0x7010) -# define GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC ((1<<10) | (1<<26)) -# define GEN9_RHWO_OPTIMIZATION_DISABLE (1<<14) -#define COMMON_SLICE_CHICKEN2 _MMIO(0x7014) -# define GEN9_PBE_COMPRESSED_HASH_SELECTION (1<<13) -# define GEN9_DISABLE_GATHER_AT_SET_SHADER_COMMON_SLICE (1<<12) -# define GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION (1<<8) -# define GEN8_CSC2_SBE_VUE_CACHE_CONSERVATIVE (1<<0) + #define GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC ((1 << 10) | (1 << 26)) + #define GEN9_RHWO_OPTIMIZATION_DISABLE (1 << 14) + +#define COMMON_SLICE_CHICKEN2 _MMIO(0x7014) + #define GEN9_PBE_COMPRESSED_HASH_SELECTION (1 << 13) + #define GEN9_DISABLE_GATHER_AT_SET_SHADER_COMMON_SLICE (1 << 12) + #define GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION (1 << 8) + #define GEN8_CSC2_SBE_VUE_CACHE_CONSERVATIVE (1 << 0) + +#define GEN11_COMMON_SLICE_CHICKEN3 _MMIO(0x7304) + #define GEN11_BLEND_EMB_FIX_DISABLE_IN_RCC (1 << 11) #define HIZ_CHICKEN _MMIO(0x7018) # define CHV_HZ_8X8_MODE_IN_1X (1<<15) diff --git a/drivers/gpu/drm/i915/intel_workarounds.c b/drivers/gpu/drm/i915/intel_workarounds.c index 1d298035b1d24..33a1a0cd2a843 100644 --- a/drivers/gpu/drm/i915/intel_workarounds.c +++ b/drivers/gpu/drm/i915/intel_workarounds.c @@ -474,6 +474,11 @@ static int icl_ctx_workarounds_init(struct drm_i915_private *dev_priv) WA_SET_BIT_MASKED(GEN9_SLICE_COMMON_ECO_CHICKEN1, GEN11_STATE_CACHE_REDIRECT_TO_CS); + /* Wa_2006665173:icl (pre-prod) */ + if (IS_ICL_REVID(dev_priv, ICL_REVID_A0, ICL_REVID_A0)) + WA_SET_BIT_MASKED(GEN11_COMMON_SLICE_CHICKEN3, + GEN11_BLEND_EMB_FIX_DISABLE_IN_RCC); + return 0; } -- GitLab From 0bf059f3532bb39c52d917142206a8554fc2f1c5 Mon Sep 17 00:00:00 2001 From: Oscar Mateo <oscar.mateo@intel.com> Date: Fri, 25 May 2018 15:05:32 -0700 Subject: [PATCH 0136/1506] drm/i915/icl: WaEnableFloatBlendOptimization Enables blend optimization for floating point RTs v2: Rebased on top of the WA refactoring v3: Added References (Mika) References: HSDES#1406393558 Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Signed-off-by: Oscar Mateo <oscar.mateo@intel.com> Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/1527285939-20113-5-git-send-email-oscar.mateo@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 3 +++ drivers/gpu/drm/i915/intel_workarounds.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 6e88c6bf3911b..f123c3e821fc6 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2663,6 +2663,9 @@ enum i915_power_well_id { #define GEN8_4x4_STC_OPTIMIZATION_DISABLE (1<<6) #define GEN9_PARTIAL_RESOLVE_IN_VC_DISABLE (1<<1) +#define GEN10_CACHE_MODE_SS _MMIO(0xe420) +#define FLOAT_BLEND_OPTIMIZATION_ENABLE (1 << 4) + #define GEN6_BLITTER_ECOSKPD _MMIO(0x221d0) #define GEN6_BLITTER_LOCK_SHIFT 16 #define GEN6_BLITTER_FBC_NOTIFY (1<<3) diff --git a/drivers/gpu/drm/i915/intel_workarounds.c b/drivers/gpu/drm/i915/intel_workarounds.c index 33a1a0cd2a843..e9c00b004c099 100644 --- a/drivers/gpu/drm/i915/intel_workarounds.c +++ b/drivers/gpu/drm/i915/intel_workarounds.c @@ -479,6 +479,9 @@ static int icl_ctx_workarounds_init(struct drm_i915_private *dev_priv) WA_SET_BIT_MASKED(GEN11_COMMON_SLICE_CHICKEN3, GEN11_BLEND_EMB_FIX_DISABLE_IN_RCC); + /* WaEnableFloatBlendOptimization:icl */ + WA_SET_BIT_MASKED(GEN10_CACHE_MODE_SS, FLOAT_BLEND_OPTIMIZATION_ENABLE); + return 0; } -- GitLab From 4ece66b149a38c7b52ead463fb608f2aad39c20e Mon Sep 17 00:00:00 2001 From: Oscar Mateo <oscar.mateo@intel.com> Date: Fri, 25 May 2018 15:05:39 -0700 Subject: [PATCH 0137/1506] drm/i915/icl: Wa_1406463099 Prevents an error in the GAM unit. Also known as WaGamTlbPendError References: HSDES#1406463099 References: HSDES#1406465643 Signed-off-by: Oscar Mateo <oscar.mateo@intel.com> Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/1527285939-20113-12-git-send-email-oscar.mateo@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 5 +++-- drivers/gpu/drm/i915/intel_workarounds.c | 7 +++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index f123c3e821fc6..f238b7b33cd9f 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2306,8 +2306,9 @@ enum i915_power_well_id { #define GAMW_ECO_ENABLE_64K_IPS_FIELD 0xF #define GAMT_CHKN_BIT_REG _MMIO(0x4ab8) -#define GAMT_CHKN_DISABLE_DYNAMIC_CREDIT_SHARING (1<<28) -#define GAMT_CHKN_DISABLE_I2M_CYCLE_ON_WR_PORT (1<<24) +#define GAMT_CHKN_DISABLE_L3_COH_PIPE (1 << 31) +#define GAMT_CHKN_DISABLE_DYNAMIC_CREDIT_SHARING (1 << 28) +#define GAMT_CHKN_DISABLE_I2M_CYCLE_ON_WR_PORT (1 << 24) #if 0 #define PRB0_TAIL _MMIO(0x2030) diff --git a/drivers/gpu/drm/i915/intel_workarounds.c b/drivers/gpu/drm/i915/intel_workarounds.c index e9c00b004c099..b1ab56a1ec313 100644 --- a/drivers/gpu/drm/i915/intel_workarounds.c +++ b/drivers/gpu/drm/i915/intel_workarounds.c @@ -859,6 +859,13 @@ static void icl_gt_workarounds_apply(struct drm_i915_private *dev_priv) PMFLUSHDONE_LNICRSDROP | PMFLUSH_GAPL3UNBLOCK | PMFLUSHDONE_LNEBLK); + + /* Wa_1406463099:icl + * Formerly known as WaGamTlbPendError + */ + I915_WRITE(GAMT_CHKN_BIT_REG, + I915_READ(GAMT_CHKN_BIT_REG) | + GAMT_CHKN_DISABLE_L3_COH_PIPE); } void intel_gt_workarounds_apply(struct drm_i915_private *dev_priv) -- GitLab From bccfaffb76a8974ca275b99e9293a2594ae75f31 Mon Sep 17 00:00:00 2001 From: Lukasz Majewski <lukma@denx.de> Date: Mon, 14 May 2018 21:08:49 +0200 Subject: [PATCH 0138/1506] display: panel: Add AUO g070vvn01 display support (800x480) This commit adds support for AUO's 7.0" display. Signed-off-by: Lukasz Majewski <lukma@denx.de> Reviewed-by: Rob Herring <robh@kernel.org> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180514190849.18723-1-lukma@denx.de --- .../bindings/display/panel/auo,g070vvn01.txt | 29 +++++++++++++++++ drivers/gpu/drm/panel/panel-simple.c | 31 +++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/panel/auo,g070vvn01.txt diff --git a/Documentation/devicetree/bindings/display/panel/auo,g070vvn01.txt b/Documentation/devicetree/bindings/display/panel/auo,g070vvn01.txt new file mode 100644 index 0000000000000..49e4105378f65 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/auo,g070vvn01.txt @@ -0,0 +1,29 @@ +AU Optronics Corporation 7.0" FHD (800 x 480) TFT LCD panel + +Required properties: +- compatible: should be "auo,g070vvn01" +- backlight: phandle of the backlight device attached to the panel +- power-supply: single regulator to provide the supply voltage + +Required nodes: +- port: Parallel port mapping to connect this display + +This panel needs single power supply voltage. Its backlight is conntrolled +via PWM signal. + +Example: +-------- + +Example device-tree definition when connected to iMX6Q based board + + lcd_panel: lcd-panel { + compatible = "auo,g070vvn01"; + backlight = <&backlight_lcd>; + power-supply = <®_display>; + + port { + lcd_panel_in: endpoint { + remote-endpoint = <&lcd_display_out>; + }; + }; + }; diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 964c261cfb78a..ac6aaa174c0b8 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -580,6 +580,34 @@ static const struct panel_desc auo_b133htn01 = { }, }; +static const struct display_timing auo_g070vvn01_timings = { + .pixelclock = { 33300000, 34209000, 45000000 }, + .hactive = { 800, 800, 800 }, + .hfront_porch = { 20, 40, 200 }, + .hback_porch = { 87, 40, 1 }, + .hsync_len = { 1, 48, 87 }, + .vactive = { 480, 480, 480 }, + .vfront_porch = { 5, 13, 200 }, + .vback_porch = { 31, 31, 29 }, + .vsync_len = { 1, 1, 3 }, +}; + +static const struct panel_desc auo_g070vvn01 = { + .timings = &auo_g070vvn01_timings, + .num_timings = 1, + .bpc = 8, + .size = { + .width = 152, + .height = 91, + }, + .delay = { + .prepare = 200, + .enable = 50, + .disable = 50, + .unprepare = 1000, + }, +}; + static const struct drm_display_mode auo_g104sn02_mode = { .clock = 40000, .hdisplay = 800, @@ -2117,6 +2145,9 @@ static const struct of_device_id platform_of_match[] = { }, { .compatible = "auo,b133xtn01", .data = &auo_b133xtn01, + }, { + .compatible = "auo,g070vvn01", + .data = &auo_g070vvn01, }, { .compatible = "auo,g104sn02", .data = &auo_g104sn02, -- GitLab From a3db142829e68e2619207306a7b83e8ed47466a6 Mon Sep 17 00:00:00 2001 From: Dhinakaran Pandiyan <dhinakaran.pandiyan@gmail.com> Date: Thu, 24 May 2018 20:30:47 -0700 Subject: [PATCH 0139/1506] drm/i915/psr: Set idle frame count based on sink synchronization latency DPCD 2009h "Synchronization latency in sink" has bits that tell us the maximum number of frames sink can take to resynchronize to source timing when exiting PSR. More importantly, as per eDP 1.4b, this is the "Minimum number of frames following PSR exit that the Source device needs to wait for PSR entry." We currently use this value only to setup the number frames to wait before PSR2 selective update. But, based on the above description it makes more sense to use this to configure idle frames for both PSR1 and and PSR2. This will ensure we wait the required number of frames before activation whether it is PSR1 or PSR2. The minimum number of idle frames remains 6, while allowing sink synchronization latency and VBT to increase this value. This also solves the flip-flop between sink and source frames that I noticed on my Thinkpad X260 during PSR exit. This specific panel has a value of 8h, which according to the spec means the "Source device must wait for more than eight active frames after PSR exit before initiating PSR entry. (In this case, should be provided by the panel supplier.)" VBT however has a value of 0. Cc: Jani Nikula <jani.nikula@intel.com> Cc: Jose Roberto de Souza <jose.souza@intel.com> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com> Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180525033047.7596-1-dhinakaran.pandiyan@intel.com --- drivers/gpu/drm/i915/intel_psr.c | 40 ++++++++++++++++---------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index ebc483f06c6f3..71dfe541740f0 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -247,6 +247,8 @@ void intel_psr_init_dpcd(struct intel_dp *intel_dp) return; } dev_priv->psr.sink_support = true; + dev_priv->psr.sink_sync_latency = + intel_dp_get_sink_sync_latency(intel_dp); if (INTEL_GEN(dev_priv) >= 9 && (intel_dp->psr_dpcd[0] == DP_PSR2_WITH_Y_COORD_IS_SUPPORTED)) { @@ -272,8 +274,6 @@ void intel_psr_init_dpcd(struct intel_dp *intel_dp) if (dev_priv->psr.sink_psr2_support) { dev_priv->psr.colorimetry_support = intel_dp_get_colorimetry_status(intel_dp); - dev_priv->psr.sink_sync_latency = - intel_dp_get_sink_sync_latency(intel_dp); } } } @@ -370,21 +370,21 @@ static void hsw_activate_psr1(struct intel_dp *intel_dp) struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct drm_device *dev = dig_port->base.base.dev; struct drm_i915_private *dev_priv = to_i915(dev); + u32 max_sleep_time = 0x1f; + u32 val = EDP_PSR_ENABLE; - uint32_t max_sleep_time = 0x1f; - /* - * Let's respect VBT in case VBT asks a higher idle_frame value. - * Let's use 6 as the minimum to cover all known cases including - * the off-by-one issue that HW has in some cases. Also there are - * cases where sink should be able to train - * with the 5 or 6 idle patterns. + /* Let's use 6 as the minimum to cover all known cases including the + * off-by-one issue that HW has in some cases. */ - uint32_t idle_frames = max(6, dev_priv->vbt.psr.idle_frames); - uint32_t val = EDP_PSR_ENABLE; + int idle_frames = max(6, dev_priv->vbt.psr.idle_frames); - val |= max_sleep_time << EDP_PSR_MAX_SLEEP_TIME_SHIFT; + /* sink_sync_latency of 8 means source has to wait for more than 8 + * frames, we'll go with 9 frames for now + */ + idle_frames = max(idle_frames, dev_priv->psr.sink_sync_latency + 1); val |= idle_frames << EDP_PSR_IDLE_FRAME_SHIFT; + val |= max_sleep_time << EDP_PSR_MAX_SLEEP_TIME_SHIFT; if (IS_HASWELL(dev_priv)) val |= EDP_PSR_MIN_LINK_ENTRY_TIME_8_LINES; @@ -424,15 +424,15 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp) struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct drm_device *dev = dig_port->base.base.dev; struct drm_i915_private *dev_priv = to_i915(dev); - /* - * Let's respect VBT in case VBT asks a higher idle_frame value. - * Let's use 6 as the minimum to cover all known cases including - * the off-by-one issue that HW has in some cases. Also there are - * cases where sink should be able to train - * with the 5 or 6 idle patterns. + u32 val; + + /* Let's use 6 as the minimum to cover all known cases including the + * off-by-one issue that HW has in some cases. */ - uint32_t idle_frames = max(6, dev_priv->vbt.psr.idle_frames); - u32 val = idle_frames << EDP_PSR2_IDLE_FRAME_SHIFT; + int idle_frames = max(6, dev_priv->vbt.psr.idle_frames); + + idle_frames = max(idle_frames, dev_priv->psr.sink_sync_latency + 1); + val = idle_frames << EDP_PSR2_IDLE_FRAME_SHIFT; /* FIXME: selective update is probably totally broken because it doesn't * mesh at all with our frontbuffer tracking. And the hw alone isn't -- GitLab From cc7cc5343584d90e74b7c929ff2c9a2ec8b49cfe Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Tue, 29 May 2018 14:29:18 +0100 Subject: [PATCH 0140/1506] drm/i915: Remove stale asserts from i915_gem_find_active_request() Since we use i915_gem_find_active_request() from inside intel_engine_dump() and may call that at any time, we do not guarantee that the engine is paused nor that the signal kthreads and irq handler are suspended, so we cannot assert that the breadcrumb doesn't advance and that the irq hasn't happened on another CPU signaling the request we believe to be idle. The second assert removed (that request->engine == engine) remains valid, but is now more rigorously checked during retirement. Fixes: f636edb214a5 ("drm/i915: Make i915_engine_info pretty printer to standalone") Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Mika Kuoppala <mika.kuoppala@intel.com> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180529132922.6831-1-chris@chris-wilson.co.uk Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> --- drivers/gpu/drm/i915/i915_gem.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 05f44ca35a062..530d6d0109b4d 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2972,23 +2972,22 @@ i915_gem_find_active_request(struct intel_engine_cs *engine) struct i915_request *request, *active = NULL; unsigned long flags; - /* We are called by the error capture and reset at a random - * point in time. In particular, note that neither is crucially - * ordered with an interrupt. After a hang, the GPU is dead and we - * assume that no more writes can happen (we waited long enough for - * all writes that were in transaction to be flushed) - adding an + /* + * We are called by the error capture, reset and to dump engine + * state at random points in time. In particular, note that neither is + * crucially ordered with an interrupt. After a hang, the GPU is dead + * and we assume that no more writes can happen (we waited long enough + * for all writes that were in transaction to be flushed) - adding an * extra delay for a recent interrupt is pointless. Hence, we do * not need an engine->irq_seqno_barrier() before the seqno reads. + * At all other times, we must assume the GPU is still running, but + * we only care about the snapshot of this moment. */ spin_lock_irqsave(&engine->timeline.lock, flags); list_for_each_entry(request, &engine->timeline.requests, link) { if (__i915_request_completed(request, request->global_seqno)) continue; - GEM_BUG_ON(request->engine != engine); - GEM_BUG_ON(test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, - &request->fence.flags)); - active = request; break; } -- GitLab From a38189c5f79d486cb6193a3965dad98d1b0a17b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Fri, 18 May 2018 19:21:59 +0300 Subject: [PATCH 0141/1506] drm/i915: Promote .format_mod_supported() to the lead role MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Up to now we've used the plane's modifier list as the primary source of information for which modifiers are supported by a given plane. In order to allow auxiliary metadata to be embedded within the bits of the modifier we need to stop doing that. Thus we have to make .format_mod_supported() aware of the plane's capabilities and gracefully deal with any modifier being passed in directly from userspace. v2: Rebase after NV12 Simplify Cc: Eric Anholt <eric@anholt.net> References: https://lists.freedesktop.org/archives/dri-devel/2018-March/169782.html Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180518162159.30305-1-ville.syrjala@linux.intel.com Reviewed-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/i915/intel_display.c | 116 +++++++++++++++------- drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_sprite.c | 141 ++++++++++++++++++++------- 3 files changed, 186 insertions(+), 72 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 020900e08d42a..00b030b08a6a7 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13067,8 +13067,17 @@ void intel_plane_destroy(struct drm_plane *plane) kfree(to_intel_plane(plane)); } -static bool i8xx_mod_supported(uint32_t format, uint64_t modifier) +static bool i8xx_plane_format_mod_supported(struct drm_plane *_plane, + u32 format, u64 modifier) { + switch (modifier) { + case DRM_FORMAT_MOD_LINEAR: + case I915_FORMAT_MOD_X_TILED: + break; + default: + return false; + } + switch (format) { case DRM_FORMAT_C8: case DRM_FORMAT_RGB565: @@ -13081,8 +13090,17 @@ static bool i8xx_mod_supported(uint32_t format, uint64_t modifier) } } -static bool i965_mod_supported(uint32_t format, uint64_t modifier) +static bool i965_plane_format_mod_supported(struct drm_plane *_plane, + u32 format, u64 modifier) { + switch (modifier) { + case DRM_FORMAT_MOD_LINEAR: + case I915_FORMAT_MOD_X_TILED: + break; + default: + return false; + } + switch (format) { case DRM_FORMAT_C8: case DRM_FORMAT_RGB565: @@ -13097,8 +13115,26 @@ static bool i965_mod_supported(uint32_t format, uint64_t modifier) } } -static bool skl_mod_supported(uint32_t format, uint64_t modifier) +static bool skl_plane_format_mod_supported(struct drm_plane *_plane, + u32 format, u64 modifier) { + struct intel_plane *plane = to_intel_plane(_plane); + + switch (modifier) { + case DRM_FORMAT_MOD_LINEAR: + case I915_FORMAT_MOD_X_TILED: + case I915_FORMAT_MOD_Y_TILED: + case I915_FORMAT_MOD_Yf_TILED: + break; + case I915_FORMAT_MOD_Y_TILED_CCS: + case I915_FORMAT_MOD_Yf_TILED_CCS: + if (!plane->has_ccs) + return false; + break; + default: + return false; + } + switch (format) { case DRM_FORMAT_XRGB8888: case DRM_FORMAT_XBGR8888: @@ -13129,38 +13165,36 @@ static bool skl_mod_supported(uint32_t format, uint64_t modifier) } } -static bool intel_primary_plane_format_mod_supported(struct drm_plane *plane, - uint32_t format, - uint64_t modifier) +static bool intel_cursor_format_mod_supported(struct drm_plane *_plane, + u32 format, u64 modifier) { - struct drm_i915_private *dev_priv = to_i915(plane->dev); - - if (WARN_ON(modifier == DRM_FORMAT_MOD_INVALID)) - return false; - - if ((modifier >> 56) != DRM_FORMAT_MOD_VENDOR_INTEL && - modifier != DRM_FORMAT_MOD_LINEAR) - return false; - - if (INTEL_GEN(dev_priv) >= 9) - return skl_mod_supported(format, modifier); - else if (INTEL_GEN(dev_priv) >= 4) - return i965_mod_supported(format, modifier); - else - return i8xx_mod_supported(format, modifier); + return modifier == DRM_FORMAT_MOD_LINEAR && + format == DRM_FORMAT_ARGB8888; } -static bool intel_cursor_plane_format_mod_supported(struct drm_plane *plane, - uint32_t format, - uint64_t modifier) -{ - if (WARN_ON(modifier == DRM_FORMAT_MOD_INVALID)) - return false; +static struct drm_plane_funcs skl_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = intel_plane_destroy, + .atomic_get_property = intel_plane_atomic_get_property, + .atomic_set_property = intel_plane_atomic_set_property, + .atomic_duplicate_state = intel_plane_duplicate_state, + .atomic_destroy_state = intel_plane_destroy_state, + .format_mod_supported = skl_plane_format_mod_supported, +}; - return modifier == DRM_FORMAT_MOD_LINEAR && format == DRM_FORMAT_ARGB8888; -} +static struct drm_plane_funcs i965_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = intel_plane_destroy, + .atomic_get_property = intel_plane_atomic_get_property, + .atomic_set_property = intel_plane_atomic_set_property, + .atomic_duplicate_state = intel_plane_duplicate_state, + .atomic_destroy_state = intel_plane_destroy_state, + .format_mod_supported = i965_plane_format_mod_supported, +}; -static struct drm_plane_funcs intel_plane_funcs = { +static struct drm_plane_funcs i8xx_plane_funcs = { .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, .destroy = intel_plane_destroy, @@ -13168,7 +13202,7 @@ static struct drm_plane_funcs intel_plane_funcs = { .atomic_set_property = intel_plane_atomic_set_property, .atomic_duplicate_state = intel_plane_duplicate_state, .atomic_destroy_state = intel_plane_destroy_state, - .format_mod_supported = intel_primary_plane_format_mod_supported, + .format_mod_supported = i8xx_plane_format_mod_supported, }; static int @@ -13293,7 +13327,7 @@ static const struct drm_plane_funcs intel_cursor_plane_funcs = { .atomic_set_property = intel_plane_atomic_set_property, .atomic_duplicate_state = intel_plane_duplicate_state, .atomic_destroy_state = intel_plane_destroy_state, - .format_mod_supported = intel_cursor_plane_format_mod_supported, + .format_mod_supported = intel_cursor_format_mod_supported, }; static bool i9xx_plane_has_fbc(struct drm_i915_private *dev_priv, @@ -13327,6 +13361,7 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe) { struct intel_plane *primary = NULL; struct intel_plane_state *state = NULL; + const struct drm_plane_funcs *plane_funcs; const uint32_t *intel_primary_formats; unsigned int supported_rotations; unsigned int num_formats; @@ -13382,10 +13417,13 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe) primary->check_plane = intel_check_primary_plane; if (INTEL_GEN(dev_priv) >= 9) { + primary->has_ccs = skl_plane_has_ccs(dev_priv, pipe, + PLANE_PRIMARY); + intel_primary_formats = skl_primary_formats; num_formats = ARRAY_SIZE(skl_primary_formats); - if (skl_plane_has_ccs(dev_priv, pipe, PLANE_PRIMARY)) + if (primary->has_ccs) modifiers = skl_format_modifiers_ccs; else modifiers = skl_format_modifiers_noccs; @@ -13393,6 +13431,8 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe) primary->update_plane = skl_update_plane; primary->disable_plane = skl_disable_plane; primary->get_hw_state = skl_plane_get_hw_state; + + plane_funcs = &skl_plane_funcs; } else if (INTEL_GEN(dev_priv) >= 4) { intel_primary_formats = i965_primary_formats; num_formats = ARRAY_SIZE(i965_primary_formats); @@ -13401,6 +13441,8 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe) primary->update_plane = i9xx_update_plane; primary->disable_plane = i9xx_disable_plane; primary->get_hw_state = i9xx_plane_get_hw_state; + + plane_funcs = &i965_plane_funcs; } else { intel_primary_formats = i8xx_primary_formats; num_formats = ARRAY_SIZE(i8xx_primary_formats); @@ -13409,25 +13451,27 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe) primary->update_plane = i9xx_update_plane; primary->disable_plane = i9xx_disable_plane; primary->get_hw_state = i9xx_plane_get_hw_state; + + plane_funcs = &i8xx_plane_funcs; } if (INTEL_GEN(dev_priv) >= 9) ret = drm_universal_plane_init(&dev_priv->drm, &primary->base, - 0, &intel_plane_funcs, + 0, plane_funcs, intel_primary_formats, num_formats, modifiers, DRM_PLANE_TYPE_PRIMARY, "plane 1%c", pipe_name(pipe)); else if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv)) ret = drm_universal_plane_init(&dev_priv->drm, &primary->base, - 0, &intel_plane_funcs, + 0, plane_funcs, intel_primary_formats, num_formats, modifiers, DRM_PLANE_TYPE_PRIMARY, "primary %c", pipe_name(pipe)); else ret = drm_universal_plane_init(&dev_priv->drm, &primary->base, - 0, &intel_plane_funcs, + 0, plane_funcs, intel_primary_formats, num_formats, modifiers, DRM_PLANE_TYPE_PRIMARY, diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 6bd7bff0947a0..3c7921ecf6f43 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -945,6 +945,7 @@ struct intel_plane { enum pipe pipe; bool can_scale; bool has_fbc; + bool has_ccs; int max_downscale; uint32_t frontbuffer_bit; diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 970015dcc6f1b..04428cea8f3b6 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -1197,8 +1197,17 @@ static const uint64_t skl_plane_format_modifiers_ccs[] = { DRM_FORMAT_MOD_INVALID }; -static bool g4x_mod_supported(uint32_t format, uint64_t modifier) +static bool g4x_sprite_format_mod_supported(struct drm_plane *_plane, + u32 format, u64 modifier) { + switch (modifier) { + case DRM_FORMAT_MOD_LINEAR: + case I915_FORMAT_MOD_X_TILED: + break; + default: + return false; + } + switch (format) { case DRM_FORMAT_XRGB8888: case DRM_FORMAT_YUYV: @@ -1214,8 +1223,17 @@ static bool g4x_mod_supported(uint32_t format, uint64_t modifier) } } -static bool snb_mod_supported(uint32_t format, uint64_t modifier) +static bool snb_sprite_format_mod_supported(struct drm_plane *_plane, + u32 format, u64 modifier) { + switch (modifier) { + case DRM_FORMAT_MOD_LINEAR: + case I915_FORMAT_MOD_X_TILED: + break; + default: + return false; + } + switch (format) { case DRM_FORMAT_XRGB8888: case DRM_FORMAT_XBGR8888: @@ -1232,8 +1250,17 @@ static bool snb_mod_supported(uint32_t format, uint64_t modifier) } } -static bool vlv_mod_supported(uint32_t format, uint64_t modifier) +static bool vlv_sprite_format_mod_supported(struct drm_plane *_plane, + u32 format, u64 modifier) { + switch (modifier) { + case DRM_FORMAT_MOD_LINEAR: + case I915_FORMAT_MOD_X_TILED: + break; + default: + return false; + } + switch (format) { case DRM_FORMAT_RGB565: case DRM_FORMAT_ABGR8888: @@ -1255,8 +1282,26 @@ static bool vlv_mod_supported(uint32_t format, uint64_t modifier) } } -static bool skl_mod_supported(uint32_t format, uint64_t modifier) +static bool skl_plane_format_mod_supported(struct drm_plane *_plane, + u32 format, u64 modifier) { + struct intel_plane *plane = to_intel_plane(_plane); + + switch (modifier) { + case DRM_FORMAT_MOD_LINEAR: + case I915_FORMAT_MOD_X_TILED: + case I915_FORMAT_MOD_Y_TILED: + case I915_FORMAT_MOD_Yf_TILED: + break; + case I915_FORMAT_MOD_Y_TILED_CCS: + case I915_FORMAT_MOD_Yf_TILED_CCS: + if (!plane->has_ccs) + return false; + break; + default: + return false; + } + switch (format) { case DRM_FORMAT_XRGB8888: case DRM_FORMAT_XBGR8888: @@ -1287,38 +1332,48 @@ static bool skl_mod_supported(uint32_t format, uint64_t modifier) } } -static bool intel_sprite_plane_format_mod_supported(struct drm_plane *plane, - uint32_t format, - uint64_t modifier) -{ - struct drm_i915_private *dev_priv = to_i915(plane->dev); - - if (WARN_ON(modifier == DRM_FORMAT_MOD_INVALID)) - return false; +static const struct drm_plane_funcs g4x_sprite_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = intel_plane_destroy, + .atomic_get_property = intel_plane_atomic_get_property, + .atomic_set_property = intel_plane_atomic_set_property, + .atomic_duplicate_state = intel_plane_duplicate_state, + .atomic_destroy_state = intel_plane_destroy_state, + .format_mod_supported = g4x_sprite_format_mod_supported, +}; - if ((modifier >> 56) != DRM_FORMAT_MOD_VENDOR_INTEL && - modifier != DRM_FORMAT_MOD_LINEAR) - return false; +static const struct drm_plane_funcs snb_sprite_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = intel_plane_destroy, + .atomic_get_property = intel_plane_atomic_get_property, + .atomic_set_property = intel_plane_atomic_set_property, + .atomic_duplicate_state = intel_plane_duplicate_state, + .atomic_destroy_state = intel_plane_destroy_state, + .format_mod_supported = snb_sprite_format_mod_supported, +}; - if (INTEL_GEN(dev_priv) >= 9) - return skl_mod_supported(format, modifier); - else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) - return vlv_mod_supported(format, modifier); - else if (INTEL_GEN(dev_priv) >= 6) - return snb_mod_supported(format, modifier); - else - return g4x_mod_supported(format, modifier); -} +static const struct drm_plane_funcs vlv_sprite_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = intel_plane_destroy, + .atomic_get_property = intel_plane_atomic_get_property, + .atomic_set_property = intel_plane_atomic_set_property, + .atomic_duplicate_state = intel_plane_duplicate_state, + .atomic_destroy_state = intel_plane_destroy_state, + .format_mod_supported = vlv_sprite_format_mod_supported, +}; -static const struct drm_plane_funcs intel_sprite_plane_funcs = { - .update_plane = drm_atomic_helper_update_plane, - .disable_plane = drm_atomic_helper_disable_plane, - .destroy = intel_plane_destroy, - .atomic_get_property = intel_plane_atomic_get_property, - .atomic_set_property = intel_plane_atomic_set_property, - .atomic_duplicate_state = intel_plane_duplicate_state, - .atomic_destroy_state = intel_plane_destroy_state, - .format_mod_supported = intel_sprite_plane_format_mod_supported, +static const struct drm_plane_funcs skl_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = intel_plane_destroy, + .atomic_get_property = intel_plane_atomic_get_property, + .atomic_set_property = intel_plane_atomic_set_property, + .atomic_duplicate_state = intel_plane_duplicate_state, + .atomic_destroy_state = intel_plane_destroy_state, + .format_mod_supported = skl_plane_format_mod_supported, }; bool skl_plane_has_ccs(struct drm_i915_private *dev_priv, @@ -1344,6 +1399,7 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv, { struct intel_plane *intel_plane = NULL; struct intel_plane_state *state = NULL; + const struct drm_plane_funcs *plane_funcs; unsigned long possible_crtcs; const uint32_t *plane_formats; const uint64_t *modifiers; @@ -1368,6 +1424,9 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv, intel_plane->can_scale = true; state->scaler_id = -1; + intel_plane->has_ccs = skl_plane_has_ccs(dev_priv, pipe, + PLANE_SPRITE0 + plane); + intel_plane->update_plane = skl_update_plane; intel_plane->disable_plane = skl_disable_plane; intel_plane->get_hw_state = skl_plane_get_hw_state; @@ -1375,10 +1434,12 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv, plane_formats = skl_plane_formats; num_plane_formats = ARRAY_SIZE(skl_plane_formats); - if (skl_plane_has_ccs(dev_priv, pipe, PLANE_SPRITE0 + plane)) + if (intel_plane->has_ccs) modifiers = skl_plane_format_modifiers_ccs; else modifiers = skl_plane_format_modifiers_noccs; + + plane_funcs = &skl_plane_funcs; } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { intel_plane->can_scale = false; intel_plane->max_downscale = 1; @@ -1390,6 +1451,8 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv, plane_formats = vlv_plane_formats; num_plane_formats = ARRAY_SIZE(vlv_plane_formats); modifiers = i9xx_plane_format_modifiers; + + plane_funcs = &vlv_sprite_funcs; } else if (INTEL_GEN(dev_priv) >= 7) { if (IS_IVYBRIDGE(dev_priv)) { intel_plane->can_scale = true; @@ -1406,6 +1469,8 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv, plane_formats = snb_plane_formats; num_plane_formats = ARRAY_SIZE(snb_plane_formats); modifiers = i9xx_plane_format_modifiers; + + plane_funcs = &snb_sprite_funcs; } else { intel_plane->can_scale = true; intel_plane->max_downscale = 16; @@ -1418,9 +1483,13 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv, if (IS_GEN6(dev_priv)) { plane_formats = snb_plane_formats; num_plane_formats = ARRAY_SIZE(snb_plane_formats); + + plane_funcs = &snb_sprite_funcs; } else { plane_formats = g4x_plane_formats; num_plane_formats = ARRAY_SIZE(g4x_plane_formats); + + plane_funcs = &g4x_sprite_funcs; } } @@ -1447,14 +1516,14 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv, if (INTEL_GEN(dev_priv) >= 9) ret = drm_universal_plane_init(&dev_priv->drm, &intel_plane->base, - possible_crtcs, &intel_sprite_plane_funcs, + possible_crtcs, plane_funcs, plane_formats, num_plane_formats, modifiers, DRM_PLANE_TYPE_OVERLAY, "plane %d%c", plane + 2, pipe_name(pipe)); else ret = drm_universal_plane_init(&dev_priv->drm, &intel_plane->base, - possible_crtcs, &intel_sprite_plane_funcs, + possible_crtcs, plane_funcs, plane_formats, num_plane_formats, modifiers, DRM_PLANE_TYPE_OVERLAY, -- GitLab From 9d570dbfc095de08e401d6a627c9c212ab7aaa80 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi <rodrigo.vivi@intel.com> Date: Wed, 30 May 2018 15:00:51 -0700 Subject: [PATCH 0142/1506] drm/i915: Update DRIVER_DATE to 20180530 Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com> --- drivers/gpu/drm/i915/i915_drv.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 487922f88b76e..32a65de7222dc 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -85,8 +85,8 @@ #define DRIVER_NAME "i915" #define DRIVER_DESC "Intel Graphics" -#define DRIVER_DATE "20180514" -#define DRIVER_TIMESTAMP 1526300884 +#define DRIVER_DATE "20180530" +#define DRIVER_TIMESTAMP 1527717651 /* Use I915_STATE_WARN(x) and I915_STATE_WARN_ON() (rather than WARN() and * WARN_ON()) for hw state sanity checks to check for unexpected conditions -- GitLab From d6cae4aa30ce551dfa2872f793f64d39719da6b7 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Date: Wed, 16 May 2018 10:50:38 +0200 Subject: [PATCH 0143/1506] drm/i915: Call intel_opregion_notify_encoder in intel_sanitize_encoder, v2. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Normally this is called on a modeset, but the call is missing when we inherit the mode from the BIOS, so make sure it's called somewhere in hardware readout. Changes since v1: - Unconditionally call intel_opregion_notify_encoder. (Ville) Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180516085038.36785-1-maarten.lankhorst@linux.intel.com Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> --- drivers/gpu/drm/i915/intel_display.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8d4c9e249c44f..da251ff6aca93 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -15251,6 +15251,9 @@ static void intel_sanitize_encoder(struct intel_encoder *encoder) connector->base.dpms = DRM_MODE_DPMS_OFF; connector->base.encoder = NULL; } + + /* notify opregion of the sanitized encoder state */ + intel_opregion_notify_encoder(encoder, connector && has_active_crtc); } void i915_redisable_vga_power_on(struct drm_i915_private *dev_priv) -- GitLab From 8fb756dfa273bcb42bdaff65baae83548b6c326d Mon Sep 17 00:00:00 2001 From: Eric Anholt <eric@anholt.net> Date: Fri, 16 Mar 2018 15:04:33 -0700 Subject: [PATCH 0144/1506] drm: Trust format_mod_supported() when it OKs a plane modifier. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For parameterized modifiers (Broadcom's SAND and UIF), we need to allow the parameter fields to be filled in, while exposing only the variant of the modifier with the parameter unfilled in the internal arrays and the format blob. Signed-off-by: Eric Anholt <eric@anholt.net> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180316220435.31416-1-eric@anholt.net Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> --- drivers/gpu/drm/drm_plane.c | 23 ++++++++++++----------- include/drm/drm_plane.h | 5 ++++- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index 0350544553010..7ce88dff871d7 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -561,19 +561,20 @@ int drm_plane_check_pixel_format(struct drm_plane *plane, if (i == plane->format_count) return -EINVAL; - if (!plane->modifier_count) - return 0; + if (plane->funcs->format_mod_supported) { + if (!plane->funcs->format_mod_supported(plane, format, modifier)) + return -EINVAL; + } else { + if (!plane->modifier_count) + return 0; - for (i = 0; i < plane->modifier_count; i++) { - if (modifier == plane->modifiers[i]) - break; + for (i = 0; i < plane->modifier_count; i++) { + if (modifier == plane->modifiers[i]) + break; + } + if (i == plane->modifier_count) + return -EINVAL; } - if (i == plane->modifier_count) - return -EINVAL; - - if (plane->funcs->format_mod_supported && - !plane->funcs->format_mod_supported(plane, format, modifier)) - return -EINVAL; return 0; } diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index 26fa50c2a50e8..14b1607aba4bb 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -431,7 +431,10 @@ struct drm_plane_funcs { * This optional hook is used for the DRM to determine if the given * format/modifier combination is valid for the plane. This allows the * DRM to generate the correct format bitmask (which formats apply to - * which modifier). + * which modifier), and to valdiate modifiers at atomic_check time. + * + * If not present, then any modifier in the plane's modifier + * list is allowed with any of the plane's formats. * * Returns: * -- GitLab From 13295bd887d07a9d904401808f41a8d35946d8c2 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko <michal.wajdeczko@intel.com> Date: Mon, 28 May 2018 17:16:18 +0000 Subject: [PATCH 0145/1506] drm/i915/guc: Don't read SOFT_SCRATCH(15) on MMIO error SOFT_SCRATCH(15) is used by GuC for sending MMIO GuC events to host and those events are now handled by intel_guc_to_host_event_handler_mmio(). We should not try to read it on MMIO action error as 1) we may be using different set of registers for GuC MMIO communication, and 2) GuC may use CTB mechanism for sending events to host. While here, upgrade error message to DRM_ERROR. Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com> Cc: Michel Thierry <michel.thierry@intel.com> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20180528171618.10436-1-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/intel_guc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c index 116f4ccf1bbd6..e28a996b9604a 100644 --- a/drivers/gpu/drm/i915/intel_guc.c +++ b/drivers/gpu/drm/i915/intel_guc.c @@ -346,10 +346,8 @@ int intel_guc_send_mmio(struct intel_guc *guc, const u32 *action, u32 len, ret = -EIO; if (ret) { - DRM_DEBUG_DRIVER("INTEL_GUC_SEND: Action 0x%X failed;" - " ret=%d status=0x%08X response=0x%08X\n", - action[0], ret, status, - I915_READ(SOFT_SCRATCH(15))); + DRM_ERROR("MMIO: GuC action %#x failed with error %d %#x\n", + action[0], ret, status); goto out; } -- GitLab From 4dfacb0bcbee79fa2ef4b2e9e64a8f8a28598934 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 31 May 2018 09:22:43 +0100 Subject: [PATCH 0146/1506] drm/i915: Switch to kernel context before idling at runtime We can reduce our exposure to random neutrinos by resting on the kernel context having flushed out the user contexts to system memory and beyond. The corollary is that we then we require two passes through the idle handler to go to sleep, which on a truly idle system involves an extra pass through the slow and irregular retire work handler. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Mika Kuoppala <mika.kuoppala@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180531082246.9763-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_debugfs.c | 9 +++++-- drivers/gpu/drm/i915/i915_gem.c | 36 +++++++++++++++++++++---- drivers/gpu/drm/i915/i915_gem_context.c | 2 +- 3 files changed, 39 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index a8e7761cdc7d5..15e86d34a81ce 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -4226,8 +4226,13 @@ i915_drop_caches_set(void *data, u64 val) i915_gem_shrink_all(dev_priv); fs_reclaim_release(GFP_KERNEL); - if (val & DROP_IDLE) - drain_delayed_work(&dev_priv->gt.idle_work); + if (val & DROP_IDLE) { + do { + if (READ_ONCE(dev_priv->gt.active_requests)) + flush_delayed_work(&dev_priv->gt.retire_work); + drain_delayed_work(&dev_priv->gt.idle_work); + } while (READ_ONCE(dev_priv->gt.awake)); + } if (val & DROP_FREED) i915_gem_drain_freed_objects(dev_priv); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 530d6d0109b4d..173d1e4ad9632 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -139,6 +139,8 @@ int i915_mutex_lock_interruptible(struct drm_device *dev) static u32 __i915_gem_park(struct drm_i915_private *i915) { + GEM_TRACE("\n"); + lockdep_assert_held(&i915->drm.struct_mutex); GEM_BUG_ON(i915->gt.active_requests); GEM_BUG_ON(!list_empty(&i915->gt.active_rings)); @@ -181,6 +183,8 @@ static u32 __i915_gem_park(struct drm_i915_private *i915) void i915_gem_park(struct drm_i915_private *i915) { + GEM_TRACE("\n"); + lockdep_assert_held(&i915->drm.struct_mutex); GEM_BUG_ON(i915->gt.active_requests); @@ -193,6 +197,8 @@ void i915_gem_park(struct drm_i915_private *i915) void i915_gem_unpark(struct drm_i915_private *i915) { + GEM_TRACE("\n"); + lockdep_assert_held(&i915->drm.struct_mutex); GEM_BUG_ON(!i915->gt.active_requests); @@ -3503,6 +3509,24 @@ i915_gem_idle_work_handler(struct work_struct *work) if (!READ_ONCE(dev_priv->gt.awake)) return; + if (READ_ONCE(dev_priv->gt.active_requests)) + return; + + /* + * Flush out the last user context, leaving only the pinned + * kernel context resident. When we are idling on the kernel_context, + * no more new requests (with a context switch) are emitted and we + * can finally rest. A consequence is that the idle work handler is + * always called at least twice before idling (and if the system is + * idle that implies a round trip through the retire worker). + */ + mutex_lock(&dev_priv->drm.struct_mutex); + i915_gem_switch_to_kernel_context(dev_priv); + mutex_unlock(&dev_priv->drm.struct_mutex); + + GEM_TRACE("active_requests=%d (after switch-to-kernel-context)\n", + READ_ONCE(dev_priv->gt.active_requests)); + /* * Wait for last execlists context complete, but bail out in case a * new request is submitted. As we don't trust the hardware, we @@ -4913,11 +4937,9 @@ static void assert_kernel_context_is_current(struct drm_i915_private *i915) void i915_gem_sanitize(struct drm_i915_private *i915) { - if (i915_terminally_wedged(&i915->gpu_error)) { - mutex_lock(&i915->drm.struct_mutex); + mutex_lock(&i915->drm.struct_mutex); + if (i915_terminally_wedged(&i915->gpu_error)) i915_gem_unset_wedged(i915); - mutex_unlock(&i915->drm.struct_mutex); - } /* * If we inherit context state from the BIOS or earlier occupants @@ -4929,6 +4951,9 @@ void i915_gem_sanitize(struct drm_i915_private *i915) */ if (INTEL_GEN(i915) >= 5 && intel_has_gpu_reset(i915)) WARN_ON(intel_gpu_reset(i915, ALL_ENGINES)); + + i915_gem_contexts_lost(i915); + mutex_unlock(&i915->drm.struct_mutex); } int i915_gem_suspend(struct drm_i915_private *dev_priv) @@ -4964,7 +4989,6 @@ int i915_gem_suspend(struct drm_i915_private *dev_priv) assert_kernel_context_is_current(dev_priv); } - i915_gem_contexts_lost(dev_priv); mutex_unlock(&dev->struct_mutex); intel_uc_suspend(dev_priv); @@ -5017,6 +5041,8 @@ int i915_gem_suspend(struct drm_i915_private *dev_priv) void i915_gem_resume(struct drm_i915_private *i915) { + GEM_TRACE("\n"); + WARN_ON(i915->gt.awake); mutex_lock(&i915->drm.struct_mutex); diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 45393f6e0208b..81f086397d10b 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -649,7 +649,7 @@ int i915_gem_switch_to_kernel_context(struct drm_i915_private *i915) struct intel_engine_cs *engine; enum intel_engine_id id; - GEM_TRACE("\n"); + GEM_TRACE("awake?=%s\n", yesno(i915->gt.awake)); lockdep_assert_held(&i915->drm.struct_mutex); GEM_BUG_ON(!i915->kernel_context); -- GitLab From 0606035fcab6b2630b0d95a5b31e235ec9ad5642 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 31 May 2018 09:22:44 +0100 Subject: [PATCH 0147/1506] drm/i915: "Race-to-idle" after switching to the kernel context During suspend we want to flush out all active contexts and their rendering. To do so we queue a request from the kernel's context, once we know that request is done, we know the GPU is completely idle. To speed up that switch bump the GPU clocks. Switching to the kernel context prior to idling is also used to enforce a barrier before changing OA properties, and when evicting active rendering from the global GTT. All cases where we do want to race-to-idle. v2: Limit the boosting to only the switch before suspend. v3: Limit it to the wait-for-idle on suspend. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: David Weinehall <david.weinehall@linux.intel.com> Cc: Mika Kuoppala <mika.kuoppala@intel.com> Tested-by: David Weinehall <david.weinehall@linux.intel.com> #v1 Reviewed-by: Mika Kuoppala <mika.kuoppala@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180531082246.9763-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 27 +++++++++++++++++++++++++-- drivers/gpu/drm/i915/i915_request.h | 1 + 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 173d1e4ad9632..b312ac006d242 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3708,7 +3708,29 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file) static int wait_for_timeline(struct i915_timeline *tl, unsigned int flags) { - return i915_gem_active_wait(&tl->last_request, flags); + struct i915_request *rq; + long ret; + + rq = i915_gem_active_get_unlocked(&tl->last_request); + if (!rq) + return 0; + + /* + * "Race-to-idle". + * + * Switching to the kernel context is often used a synchronous + * step prior to idling, e.g. in suspend for flushing all + * current operations to memory before sleeping. These we + * want to complete as quickly as possible to avoid prolonged + * stalls, so allow the gpu to boost to maximum clocks. + */ + if (flags & I915_WAIT_FOR_IDLE_BOOST) + gen6_rps_boost(rq, NULL); + + ret = i915_request_wait(rq, flags, MAX_SCHEDULE_TIMEOUT); + i915_request_put(rq); + + return ret < 0 ? ret : 0; } static int wait_for_engines(struct drm_i915_private *i915) @@ -4983,7 +5005,8 @@ int i915_gem_suspend(struct drm_i915_private *dev_priv) ret = i915_gem_wait_for_idle(dev_priv, I915_WAIT_INTERRUPTIBLE | - I915_WAIT_LOCKED); + I915_WAIT_LOCKED | + I915_WAIT_FOR_IDLE_BOOST); if (ret && ret != -EIO) goto err_unlock; diff --git a/drivers/gpu/drm/i915/i915_request.h b/drivers/gpu/drm/i915/i915_request.h index 1bbbb7a9fa037..491ff81d0fea7 100644 --- a/drivers/gpu/drm/i915/i915_request.h +++ b/drivers/gpu/drm/i915/i915_request.h @@ -267,6 +267,7 @@ long i915_request_wait(struct i915_request *rq, #define I915_WAIT_INTERRUPTIBLE BIT(0) #define I915_WAIT_LOCKED BIT(1) /* struct_mutex held, handle GPU reset */ #define I915_WAIT_ALL BIT(2) /* used by i915_gem_object_wait() */ +#define I915_WAIT_FOR_IDLE_BOOST BIT(3) static inline u32 intel_engine_get_seqno(struct intel_engine_cs *engine); -- GitLab From c3160da9a6af0e2d8f4fb3410df9d027a178ca3d Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 31 May 2018 09:22:45 +0100 Subject: [PATCH 0148/1506] drm/i915: After reset on sanitization, reset the engine backends As we reset the GPU on suspend/resume, we also do need to reset the engine state tracking so call into the engine backends. This is especially important so that we can also sanitize the state tracking across resume. References: https://bugs.freedesktop.org/show_bug.cgi?id=106702 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Mika Kuoppala <mika.kuoppala@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180531082246.9763-3-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 24 ++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_lrc.c | 8 +++++--- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index b312ac006d242..9b8fa1866cc97 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4959,7 +4959,22 @@ static void assert_kernel_context_is_current(struct drm_i915_private *i915) void i915_gem_sanitize(struct drm_i915_private *i915) { + struct intel_engine_cs *engine; + enum intel_engine_id id; + + GEM_TRACE("\n"); + mutex_lock(&i915->drm.struct_mutex); + + intel_runtime_pm_get(i915); + intel_uncore_forcewake_get(i915, FORCEWAKE_ALL); + + /* + * As we have just resumed the machine and woken the device up from + * deep PCI sleep (presumably D3_cold), assume the HW has been reset + * back to defaults, recovering from whatever wedged state we left it + * in and so worth trying to use the device once more. + */ if (i915_terminally_wedged(&i915->gpu_error)) i915_gem_unset_wedged(i915); @@ -4974,6 +4989,15 @@ void i915_gem_sanitize(struct drm_i915_private *i915) if (INTEL_GEN(i915) >= 5 && intel_has_gpu_reset(i915)) WARN_ON(intel_gpu_reset(i915, ALL_ENGINES)); + /* Reset the submission backend after resume as well as the GPU reset */ + for_each_engine(engine, i915, id) { + if (engine->reset.reset) + engine->reset.reset(engine, NULL); + } + + intel_uncore_forcewake_put(i915, FORCEWAKE_ALL); + intel_runtime_pm_put(i915); + i915_gem_contexts_lost(i915); mutex_unlock(&i915->drm.struct_mutex); } diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 4bcd3206991da..38696d9cc02ec 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1788,9 +1788,6 @@ static void enable_execlists(struct intel_engine_cs *engine) I915_WRITE(RING_HWS_PGA(engine->mmio_base), engine->status_page.ggtt_offset); POSTING_READ(RING_HWS_PGA(engine->mmio_base)); - - /* Following the reset, we need to reload the CSB read/write pointers */ - engine->execlists.csb_head = -1; } static bool unexpected_starting_state(struct intel_engine_cs *engine) @@ -1962,6 +1959,9 @@ static void execlists_reset(struct intel_engine_cs *engine, __unwind_incomplete_requests(engine); spin_unlock(&engine->timeline.lock); + /* Following the reset, we need to reload the CSB read/write pointers */ + engine->execlists.csb_head = -1; + local_irq_restore(flags); /* @@ -2461,6 +2461,8 @@ static int logical_ring_init(struct intel_engine_cs *engine) upper_32_bits(ce->lrc_desc); } + engine->execlists.csb_head = -1; + return 0; error: -- GitLab From ec92ad00a393d07f7f6c1c9a0ff65141f2173050 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 31 May 2018 09:22:46 +0100 Subject: [PATCH 0149/1506] drm/i915: Only sanitize GEM from late suspend During testing we encounter a conflict between SUSPEND_TEST_DEVICES and disabling reset (gem_eio/suspend). This results in the device continuing on without being reset, but since it has gone through HW sanitization to account for the suspend/resume cycle, we have to assume the device has been reset to its defaults. A simple way around this is to skip the sanitize phase for SUSPEND_TEST_DEVICES by moving it to suspend-late. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180531082246.9763-4-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_drv.c | 6 +++++- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_gem.c | 22 +++++++++++++--------- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index fb39e40c08474..fe92665c8482b 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -636,6 +636,8 @@ static const struct vga_switcheroo_client_ops i915_switcheroo_ops = { static void i915_gem_fini(struct drm_i915_private *dev_priv) { + i915_gem_suspend_late(dev_priv); + /* Flush any outstanding unpin_work. */ i915_gem_drain_workqueue(dev_priv); @@ -1611,7 +1613,6 @@ static int i915_drm_suspend(struct drm_device *dev) opregion_target_state = suspend_to_idle(dev_priv) ? PCI_D1 : PCI_D3cold; intel_opregion_notify_adapter(dev_priv, opregion_target_state); - intel_uncore_suspend(dev_priv); intel_opregion_unregister(dev_priv); intel_fbdev_set_suspend(dev, FBINFO_STATE_SUSPENDED, true); @@ -1633,7 +1634,10 @@ static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation) disable_rpm_wakeref_asserts(dev_priv); + i915_gem_suspend_late(dev_priv); + intel_display_set_init_power(dev_priv, false); + intel_uncore_suspend(dev_priv); /* * In case of firmware assisted context save/restore don't manually diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 32a65de7222dc..38157df6ff5c6 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3169,6 +3169,7 @@ void i915_gem_cleanup_engines(struct drm_i915_private *dev_priv); int i915_gem_wait_for_idle(struct drm_i915_private *dev_priv, unsigned int flags); int __must_check i915_gem_suspend(struct drm_i915_private *dev_priv); +void i915_gem_suspend_late(struct drm_i915_private *dev_priv); void i915_gem_resume(struct drm_i915_private *dev_priv); int i915_gem_fault(struct vm_fault *vmf); int i915_gem_object_wait(struct drm_i915_gem_object *obj, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 9b8fa1866cc97..f5c4ef0520017 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5055,6 +5055,17 @@ int i915_gem_suspend(struct drm_i915_private *dev_priv) if (WARN_ON(!intel_engines_are_idle(dev_priv))) i915_gem_set_wedged(dev_priv); /* no hope, discard everything */ + intel_runtime_pm_put(dev_priv); + return 0; + +err_unlock: + mutex_unlock(&dev->struct_mutex); + intel_runtime_pm_put(dev_priv); + return ret; +} + +void i915_gem_suspend_late(struct drm_i915_private *i915) +{ /* * Neither the BIOS, ourselves or any other kernel * expects the system to be in execlists mode on startup, @@ -5074,16 +5085,9 @@ int i915_gem_suspend(struct drm_i915_private *dev_priv) * machines is a good idea, we don't - just in case it leaves the * machine in an unusable condition. */ - intel_uc_sanitize(dev_priv); - i915_gem_sanitize(dev_priv); - intel_runtime_pm_put(dev_priv); - return 0; - -err_unlock: - mutex_unlock(&dev->struct_mutex); - intel_runtime_pm_put(dev_priv); - return ret; + intel_uc_sanitize(i915); + i915_gem_sanitize(i915); } void i915_gem_resume(struct drm_i915_private *i915) -- GitLab From 1e871d65e375280757833d9fce91dda71980bdf5 Mon Sep 17 00:00:00 2001 From: Eric Anholt <eric@anholt.net> Date: Fri, 16 Mar 2018 15:04:34 -0700 Subject: [PATCH 0150/1506] drm/vc4: Add missing formats to vc4_format_mod_supported(). Daniel's format_mod_supported() patch predated Dave's for NV21/61, and I didn't catch that when rebasing. This is a problem since the formats are now getting validated before being passed to the driver's atomic hooks. Signed-off-by: Eric Anholt <eric@anholt.net> Acked-by: Daniel Stone <daniels@collabora.com> Cc: Dave Stevenson <dave.stevenson@raspberrypi.org> Fixes: 423ad7b3cbd1 ("drm/vc4: Advertise supported modifiers for planes") Link: https://patchwork.freedesktop.org/patch/msgid/20180316220435.31416-2-eric@anholt.net --- drivers/gpu/drm/vc4/vc4_plane.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 6e8984aee613f..6efd55bae8dbd 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -873,7 +873,9 @@ static bool vc4_format_mod_supported(struct drm_plane *plane, case DRM_FORMAT_YUV420: case DRM_FORMAT_YVU420: case DRM_FORMAT_NV12: + case DRM_FORMAT_NV21: case DRM_FORMAT_NV16: + case DRM_FORMAT_NV61: default: return (modifier == DRM_FORMAT_MOD_LINEAR); } -- GitLab From e065a8dd30af703b4794dc740c0825ee12b92efd Mon Sep 17 00:00:00 2001 From: Dave Stevenson <dave.stevenson@raspberrypi.org> Date: Fri, 16 Mar 2018 15:04:35 -0700 Subject: [PATCH 0151/1506] drm/vc4: Add support for SAND modifier. This is the format generated by VC4's H.264 engine, and preferred by the ISP as well. By displaying SAND buffers directly, we can avoid needing to use the ISP to rewrite the SAND H.264 output to linear before display. This is a joint effort by Dave Stevenson (who wrote the initial patch and DRM demo) and Eric Anholt (drm_fourcc.h generalization, safety checks, RGBA support). v2: Make the parameter macro give all of the middle 48 bits (suggested by Daniels). Fix fourcc_mod_broadcom_mod()'s bits/shift being swapped. Mark NV12/21 as supported, not YUV420. Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org> Signed-off-by: Eric Anholt <eric@anholt.net> Cc: Daniel Vetter <daniel@ffwll.ch> Acked-by: Daniel Stone <daniels@collabora.com> (v1) Cc: Boris Brezillon <boris.brezillon@bootlin.com> Cc: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180316220435.31416-3-eric@anholt.net --- drivers/gpu/drm/vc4/vc4_plane.c | 84 ++++++++++++++++++++++++++++++--- drivers/gpu/drm/vc4/vc4_regs.h | 6 +++ include/uapi/drm/drm_fourcc.h | 59 +++++++++++++++++++++++ 3 files changed, 142 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 6efd55bae8dbd..2575bd81a0105 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -467,12 +467,14 @@ static int vc4_plane_mode_set(struct drm_plane *plane, struct drm_framebuffer *fb = state->fb; u32 ctl0_offset = vc4_state->dlist_count; const struct hvs_format *format = vc4_get_hvs_format(fb->format->format); + u64 base_format_mod = fourcc_mod_broadcom_mod(fb->modifier); int num_planes = drm_format_num_planes(format->drm); bool mix_plane_alpha; bool covers_screen; u32 scl0, scl1, pitch0; u32 lbm_size, tiling; unsigned long irqflags; + u32 hvs_format = format->hvs; int ret, i; ret = vc4_plane_setup_clipping_and_scaling(state); @@ -512,7 +514,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane, scl1 = vc4_get_scl_field(state, 0); } - switch (fb->modifier) { + switch (base_format_mod) { case DRM_FORMAT_MOD_LINEAR: tiling = SCALER_CTL0_TILING_LINEAR; pitch0 = VC4_SET_FIELD(fb->pitches[0], SCALER_SRC_PITCH); @@ -535,6 +537,49 @@ static int vc4_plane_mode_set(struct drm_plane *plane, break; } + case DRM_FORMAT_MOD_BROADCOM_SAND64: + case DRM_FORMAT_MOD_BROADCOM_SAND128: + case DRM_FORMAT_MOD_BROADCOM_SAND256: { + uint32_t param = fourcc_mod_broadcom_param(fb->modifier); + + /* Column-based NV12 or RGBA. + */ + if (fb->format->num_planes > 1) { + if (hvs_format != HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE) { + DRM_DEBUG_KMS("SAND format only valid for NV12/21"); + return -EINVAL; + } + hvs_format = HVS_PIXEL_FORMAT_H264; + } else { + if (base_format_mod == DRM_FORMAT_MOD_BROADCOM_SAND256) { + DRM_DEBUG_KMS("SAND256 format only valid for H.264"); + return -EINVAL; + } + } + + switch (base_format_mod) { + case DRM_FORMAT_MOD_BROADCOM_SAND64: + tiling = SCALER_CTL0_TILING_64B; + break; + case DRM_FORMAT_MOD_BROADCOM_SAND128: + tiling = SCALER_CTL0_TILING_128B; + break; + case DRM_FORMAT_MOD_BROADCOM_SAND256: + tiling = SCALER_CTL0_TILING_256B_OR_T; + break; + default: + break; + } + + if (param > SCALER_TILE_HEIGHT_MASK) { + DRM_DEBUG_KMS("SAND height too large (%d)\n", param); + return -EINVAL; + } + + pitch0 = VC4_SET_FIELD(param, SCALER_TILE_HEIGHT); + break; + } + default: DRM_DEBUG_KMS("Unsupported FB tiling flag 0x%16llx", (long long)fb->modifier); @@ -546,7 +591,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane, SCALER_CTL0_VALID | VC4_SET_FIELD(SCALER_CTL0_RGBA_EXPAND_ROUND, SCALER_CTL0_RGBA_EXPAND) | (format->pixel_order << SCALER_CTL0_ORDER_SHIFT) | - (format->hvs << SCALER_CTL0_PIXEL_FORMAT_SHIFT) | + (hvs_format << SCALER_CTL0_PIXEL_FORMAT_SHIFT) | VC4_SET_FIELD(tiling, SCALER_CTL0_TILING) | (vc4_state->is_unity ? SCALER_CTL0_UNITY : 0) | VC4_SET_FIELD(scl0, SCALER_CTL0_SCL0) | @@ -608,8 +653,13 @@ static int vc4_plane_mode_set(struct drm_plane *plane, /* Pitch word 1/2 */ for (i = 1; i < num_planes; i++) { - vc4_dlist_write(vc4_state, - VC4_SET_FIELD(fb->pitches[i], SCALER_SRC_PITCH)); + if (hvs_format != HVS_PIXEL_FORMAT_H264) { + vc4_dlist_write(vc4_state, + VC4_SET_FIELD(fb->pitches[i], + SCALER_SRC_PITCH)); + } else { + vc4_dlist_write(vc4_state, pitch0); + } } /* Colorspace conversion words */ @@ -867,13 +917,30 @@ static bool vc4_format_mod_supported(struct drm_plane *plane, case DRM_FORMAT_BGR565: case DRM_FORMAT_ARGB1555: case DRM_FORMAT_XRGB1555: - return true; + switch (fourcc_mod_broadcom_mod(modifier)) { + case DRM_FORMAT_MOD_LINEAR: + case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: + case DRM_FORMAT_MOD_BROADCOM_SAND64: + case DRM_FORMAT_MOD_BROADCOM_SAND128: + return true; + default: + return false; + } + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV21: + switch (fourcc_mod_broadcom_mod(modifier)) { + case DRM_FORMAT_MOD_LINEAR: + case DRM_FORMAT_MOD_BROADCOM_SAND64: + case DRM_FORMAT_MOD_BROADCOM_SAND128: + case DRM_FORMAT_MOD_BROADCOM_SAND256: + return true; + default: + return false; + } case DRM_FORMAT_YUV422: case DRM_FORMAT_YVU422: case DRM_FORMAT_YUV420: case DRM_FORMAT_YVU420: - case DRM_FORMAT_NV12: - case DRM_FORMAT_NV21: case DRM_FORMAT_NV16: case DRM_FORMAT_NV61: default: @@ -903,6 +970,9 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev, unsigned i; static const uint64_t modifiers[] = { DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED, + DRM_FORMAT_MOD_BROADCOM_SAND128, + DRM_FORMAT_MOD_BROADCOM_SAND64, + DRM_FORMAT_MOD_BROADCOM_SAND256, DRM_FORMAT_MOD_LINEAR, DRM_FORMAT_MOD_INVALID }; diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h index d1fb6fec46eb2..d6864fa4bd141 100644 --- a/drivers/gpu/drm/vc4/vc4_regs.h +++ b/drivers/gpu/drm/vc4/vc4_regs.h @@ -1031,6 +1031,12 @@ enum hvs_pixel_format { #define SCALER_SRC_PITCH_MASK VC4_MASK(15, 0) #define SCALER_SRC_PITCH_SHIFT 0 +/* PITCH0/1/2 fields for tiled (SAND). */ +#define SCALER_TILE_SKIP_0_MASK VC4_MASK(18, 16) +#define SCALER_TILE_SKIP_0_SHIFT 16 +#define SCALER_TILE_HEIGHT_MASK VC4_MASK(15, 0) +#define SCALER_TILE_HEIGHT_SHIFT 0 + /* PITCH0 fields for T-tiled. */ #define SCALER_PITCH0_TILE_WIDTH_L_MASK VC4_MASK(22, 16) #define SCALER_PITCH0_TILE_WIDTH_L_SHIFT 16 diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h index e04613d30a134..64bf67abff7e3 100644 --- a/include/uapi/drm/drm_fourcc.h +++ b/include/uapi/drm/drm_fourcc.h @@ -384,6 +384,23 @@ extern "C" { #define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_THIRTYTWO_GOB \ fourcc_mod_code(NVIDIA, 0x15) +/* + * Some Broadcom modifiers take parameters, for example the number of + * vertical lines in the image. Reserve the lower 32 bits for modifier + * type, and the next 24 bits for parameters. Top 8 bits are the + * vendor code. + */ +#define __fourcc_mod_broadcom_param_shift 8 +#define __fourcc_mod_broadcom_param_bits 48 +#define fourcc_mod_broadcom_code(val, params) \ + fourcc_mod_code(BROADCOM, ((((__u64)params) << __fourcc_mod_broadcom_param_shift) | val)) +#define fourcc_mod_broadcom_param(m) \ + ((int)(((m) >> __fourcc_mod_broadcom_param_shift) & \ + ((1ULL << __fourcc_mod_broadcom_param_bits) - 1))) +#define fourcc_mod_broadcom_mod(m) \ + ((m) & ~(((1ULL << __fourcc_mod_broadcom_param_bits) - 1) << \ + __fourcc_mod_broadcom_param_shift)) + /* * Broadcom VC4 "T" format * @@ -405,6 +422,48 @@ extern "C" { */ #define DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED fourcc_mod_code(BROADCOM, 1) +/* + * Broadcom SAND format + * + * This is the native format that the H.264 codec block uses. For VC4 + * HVS, it is only valid for H.264 (NV12/21) and RGBA modes. + * + * The image can be considered to be split into columns, and the + * columns are placed consecutively into memory. The width of those + * columns can be either 32, 64, 128, or 256 pixels, but in practice + * only 128 pixel columns are used. + * + * The pitch between the start of each column is set to optimally + * switch between SDRAM banks. This is passed as the number of lines + * of column width in the modifier (we can't use the stride value due + * to various core checks that look at it , so you should set the + * stride to width*cpp). + * + * Note that the column height for this format modifier is the same + * for all of the planes, assuming that each column contains both Y + * and UV. Some SAND-using hardware stores UV in a separate tiled + * image from Y to reduce the column height, which is not supported + * with these modifiers. + */ + +#define DRM_FORMAT_MOD_BROADCOM_SAND32_COL_HEIGHT(v) \ + fourcc_mod_broadcom_code(2, v) +#define DRM_FORMAT_MOD_BROADCOM_SAND64_COL_HEIGHT(v) \ + fourcc_mod_broadcom_code(3, v) +#define DRM_FORMAT_MOD_BROADCOM_SAND128_COL_HEIGHT(v) \ + fourcc_mod_broadcom_code(4, v) +#define DRM_FORMAT_MOD_BROADCOM_SAND256_COL_HEIGHT(v) \ + fourcc_mod_broadcom_code(5, v) + +#define DRM_FORMAT_MOD_BROADCOM_SAND32 \ + DRM_FORMAT_MOD_BROADCOM_SAND32_COL_HEIGHT(0) +#define DRM_FORMAT_MOD_BROADCOM_SAND64 \ + DRM_FORMAT_MOD_BROADCOM_SAND64_COL_HEIGHT(0) +#define DRM_FORMAT_MOD_BROADCOM_SAND128 \ + DRM_FORMAT_MOD_BROADCOM_SAND128_COL_HEIGHT(0) +#define DRM_FORMAT_MOD_BROADCOM_SAND256 \ + DRM_FORMAT_MOD_BROADCOM_SAND256_COL_HEIGHT(0) + #if defined(__cplusplus) } #endif -- GitLab From 09ea0dfbf972c63dfea8cf46f2fb67f39e4d833b Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann <kraxel@redhat.com> Date: Tue, 29 May 2018 15:59:18 +0200 Subject: [PATCH 0152/1506] dma-buf: make map_atomic and map function pointers optional So drivers don't need dummy functions just returning NULL. Cc: Daniel Vetter <daniel@ffwll.ch> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Reviewed-by: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com> Link: http://patchwork.freedesktop.org/patch/msgid/20180529135918.19729-1-kraxel@redhat.com --- drivers/dma-buf/dma-buf.c | 4 ++++ include/linux/dma-buf.h | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index d78d5fc173dc3..4c45e31258f04 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -872,6 +872,8 @@ void *dma_buf_kmap_atomic(struct dma_buf *dmabuf, unsigned long page_num) { WARN_ON(!dmabuf); + if (!dmabuf->ops->map_atomic) + return NULL; return dmabuf->ops->map_atomic(dmabuf, page_num); } EXPORT_SYMBOL_GPL(dma_buf_kmap_atomic); @@ -907,6 +909,8 @@ void *dma_buf_kmap(struct dma_buf *dmabuf, unsigned long page_num) { WARN_ON(!dmabuf); + if (!dmabuf->ops->map) + return NULL; return dmabuf->ops->map(dmabuf, page_num); } EXPORT_SYMBOL_GPL(dma_buf_kmap); diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h index 085db2fee2d71..88917fa796e44 100644 --- a/include/linux/dma-buf.h +++ b/include/linux/dma-buf.h @@ -39,12 +39,12 @@ struct dma_buf_attachment; /** * struct dma_buf_ops - operations possible on struct dma_buf - * @map_atomic: maps a page from the buffer into kernel address + * @map_atomic: [optional] maps a page from the buffer into kernel address * space, users may not block until the subsequent unmap call. * This callback must not sleep. * @unmap_atomic: [optional] unmaps a atomically mapped page from the buffer. * This Callback must not sleep. - * @map: maps a page from the buffer into kernel address space. + * @map: [optional] maps a page from the buffer into kernel address space. * @unmap: [optional] unmaps a page from the buffer. * @vmap: [optional] creates a virtual mapping for the buffer into kernel * address space. Same restrictions as for vmap and friends apply. -- GitLab From 1934f5deaf8f53e0af0b55f87b7fc519b76515a0 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 31 May 2018 23:40:57 +0100 Subject: [PATCH 0153/1506] drm/i915: Assert we idle in the kernel context Now that we always switch to the kernel context upon idling, we can make that assertion. References: 4dfacb0bcbee ("drm/i915: Switch to kernel context before idling at runtime") Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180531224057.6036-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index f5c4ef0520017..c85951f2b15af 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3498,6 +3498,22 @@ new_requests_since_last_retire(const struct drm_i915_private *i915) work_pending(&i915->gt.idle_work.work)); } +static void assert_kernel_context_is_current(struct drm_i915_private *i915) +{ + struct intel_engine_cs *engine; + enum intel_engine_id id; + + if (i915_terminally_wedged(&i915->gpu_error)) + return; + + GEM_BUG_ON(i915->gt.active_requests); + for_each_engine(engine, i915, id) { + GEM_BUG_ON(__i915_gem_active_peek(&engine->timeline.last_request)); + GEM_BUG_ON(engine->last_retired_context != + to_intel_context(i915->kernel_context, engine)); + } +} + static void i915_gem_idle_work_handler(struct work_struct *work) { @@ -3560,6 +3576,8 @@ i915_gem_idle_work_handler(struct work_struct *work) epoch = __i915_gem_park(dev_priv); + assert_kernel_context_is_current(dev_priv); + rearm_hangcheck = false; out_unlock: mutex_unlock(&dev_priv->drm.struct_mutex); @@ -4944,19 +4962,6 @@ void __i915_gem_object_release_unless_active(struct drm_i915_gem_object *obj) i915_gem_object_put(obj); } -static void assert_kernel_context_is_current(struct drm_i915_private *i915) -{ - struct i915_gem_context *kctx = i915->kernel_context; - struct intel_engine_cs *engine; - enum intel_engine_id id; - - GEM_BUG_ON(i915->gt.active_requests); - for_each_engine(engine, i915, id) { - GEM_BUG_ON(__i915_gem_active_peek(&engine->timeline.last_request)); - GEM_BUG_ON(engine->last_retired_context->gem_context != kctx); - } -} - void i915_gem_sanitize(struct drm_i915_private *i915) { struct intel_engine_cs *engine; -- GitLab From e312b689a92d82d2b67f8b58b307fe5b79019d60 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 1 Jun 2018 10:40:02 +0100 Subject: [PATCH 0154/1506] drm/i915: Check intel_contexts to avoid one extra pointer chase As we store the intel_context on the request (rq->hw_context), we can simply compare that against the local intel_context for the i915->kernel_context rather than using the rq->gem_context. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180601094002.13329-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_context.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 81f086397d10b..94e4db1870aa3 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -610,7 +610,7 @@ static bool engine_has_kernel_context_barrier(struct intel_engine_cs *engine) any_active = true; - if (rq->gem_context == i915->kernel_context) + if (rq->hw_context == ce) continue; /* -- GitLab From 37800ca8037adeeb1ccd23dc15f6452b395e3101 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 1 Jun 2018 10:35:49 +0100 Subject: [PATCH 0155/1506] drm/i915/gtt: Avoid calling non-existent allocate_va_range On hsw and older, we do not need to allocate the ppgtt on the fly and so ppgtt->allocate_va_range() is NULL. Fixup ppgtt_bind_vma not to call it, in that case! v2: PIN_UPDATE still exists. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20180601093554.13083-1-chris@chris-wilson.co.uk Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180601093554.13083-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_gtt.c | 34 ++++++++++++++++++----------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index fc5c0f746f265..ec60be48919bd 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -190,19 +190,11 @@ int intel_sanitize_enable_ppgtt(struct drm_i915_private *dev_priv, return 1; } -static int ppgtt_bind_vma(struct i915_vma *vma, - enum i915_cache_level cache_level, - u32 unused) +static int gen6_ppgtt_bind_vma(struct i915_vma *vma, + enum i915_cache_level cache_level, + u32 unused) { u32 pte_flags; - int ret; - - if (!(vma->flags & I915_VMA_LOCAL_BIND)) { - ret = vma->vm->allocate_va_range(vma->vm, vma->node.start, - vma->size); - if (ret) - return ret; - } /* Currently applicable only to VLV */ pte_flags = 0; @@ -214,6 +206,22 @@ static int ppgtt_bind_vma(struct i915_vma *vma, return 0; } +static int gen8_ppgtt_bind_vma(struct i915_vma *vma, + enum i915_cache_level cache_level, + u32 unused) +{ + int ret; + + if (!(vma->flags & I915_VMA_LOCAL_BIND)) { + ret = vma->vm->allocate_va_range(vma->vm, + vma->node.start, vma->size); + if (ret) + return ret; + } + + return gen6_ppgtt_bind_vma(vma, cache_level, unused); +} + static void ppgtt_unbind_vma(struct i915_vma *vma) { vma->vm->clear_range(vma->vm, vma->node.start, vma->size); @@ -1657,8 +1665,8 @@ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt) gen8_ppgtt_notify_vgt(ppgtt, true); ppgtt->base.cleanup = gen8_ppgtt_cleanup; + ppgtt->base.bind_vma = gen8_ppgtt_bind_vma; ppgtt->base.unbind_vma = ppgtt_unbind_vma; - ppgtt->base.bind_vma = ppgtt_bind_vma; ppgtt->base.set_pages = ppgtt_set_pages; ppgtt->base.clear_pages = clear_pages; ppgtt->debug_dump = gen8_dump_ppgtt; @@ -2100,8 +2108,8 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) ppgtt->base.clear_range = gen6_ppgtt_clear_range; ppgtt->base.insert_entries = gen6_ppgtt_insert_entries; + ppgtt->base.bind_vma = gen6_ppgtt_bind_vma; ppgtt->base.unbind_vma = ppgtt_unbind_vma; - ppgtt->base.bind_vma = ppgtt_bind_vma; ppgtt->base.set_pages = ppgtt_set_pages; ppgtt->base.clear_pages = clear_pages; ppgtt->base.cleanup = gen6_ppgtt_cleanup; -- GitLab From 3df845e7528b4f337e5cf91f3fd75610a646b259 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 1 Jun 2018 10:35:50 +0100 Subject: [PATCH 0156/1506] drm/i915/gtt: Don't restore the non-existent PDE for GGTT On resume, we have to rewrite all the PDE entries for gen7 ppgtts. If we switch on full-ppgtt, there is then one address space with no PDE, the GGTT. Currently under aliasing-ppgtt, the GGTT address space does have an associated ppgtt and so the restore works just fine. We would have a similar problem if we tried disabling aliasing-ppgtt (i915.enable_ppgtt=0). So skip the empty ppgtt, as being non-existent it doesn't need restoring. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180601093554.13083-2-chris@chris-wilson.co.uk Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> --- drivers/gpu/drm/i915/i915_gem_gtt.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index ec60be48919bd..d032069819ccd 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -3665,6 +3665,8 @@ void i915_gem_restore_gtt_mappings(struct drm_i915_private *dev_priv) ppgtt = dev_priv->mm.aliasing_ppgtt; else ppgtt = i915_vm_to_ppgtt(vm); + if (!ppgtt) + continue; gen6_write_page_range(ppgtt, 0, ppgtt->base.total); } -- GitLab From eade6c894498c12c2940e7fbe598dc08a292994f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Tue, 30 Jan 2018 22:38:03 +0200 Subject: [PATCH 0157/1506] drm/i915: Have plane->get_hw_state() return the current pipe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Like we do for encoder let's make the plane->get_hw_state() return the pipe to which the plane is currently attached. We don't currently allow planes to move between the pipes, but perhaps one day we will. In either case this makes the code more uniform and perhaps makes intel_plane_mapping_ok() slightly more clear. Note that for i965 and g4x planes A and B still have pipe select bits but they're hardwired to pipe A and B respectively. This means we can safely interpret those bits just like on gen2/3. This allows the same readout code work for plane C (which can still be assigned to eiter pipe on i965) should we ever expose it. g4x no longer allows moving the cursor planes between the pipes, but the pipe select bits can still be set in the register. Thus we have to ignore those bits. OTOH i965 still allows the cursors to move between pipes thus we have to trust the bits there. Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180130203807.13721-3-ville.syrjala@linux.intel.com Reviewed-by: Mika Kahola <mika.kahola@intel.com> --- drivers/gpu/drm/i915/i915_reg.h | 2 + drivers/gpu/drm/i915/intel_display.c | 71 ++++++++++++++++++++-------- drivers/gpu/drm/i915/intel_drv.h | 4 +- drivers/gpu/drm/i915/intel_sprite.c | 40 +++++++++------- 4 files changed, 79 insertions(+), 38 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index f238b7b33cd9f..be8a194727559 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -5936,6 +5936,8 @@ enum { #define CURSOR_MODE_128_ARGB_AX ((1 << 5) | CURSOR_MODE_128_32B_AX) #define CURSOR_MODE_256_ARGB_AX ((1 << 5) | CURSOR_MODE_256_32B_AX) #define CURSOR_MODE_64_ARGB_AX ((1 << 5) | CURSOR_MODE_64_32B_AX) +#define MCURSOR_PIPE_SELECT_MASK (0x3 << 28) +#define MCURSOR_PIPE_SELECT_SHIFT 28 #define MCURSOR_PIPE_SELECT(pipe) ((pipe) << 28) #define MCURSOR_GAMMA_ENABLE (1 << 26) #define CURSOR_ROTATE_180 (1<<15) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index da251ff6aca93..136f129f71c40 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1284,7 +1284,10 @@ void assert_pipe(struct drm_i915_private *dev_priv, static void assert_plane(struct intel_plane *plane, bool state) { - bool cur_state = plane->get_hw_state(plane); + enum pipe pipe; + bool cur_state; + + cur_state = plane->get_hw_state(plane, &pipe); I915_STATE_WARN(cur_state != state, "%s assertion failure (expected %s, current %s)\n", @@ -3387,24 +3390,33 @@ static void i9xx_disable_plane(struct intel_plane *plane, spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } -static bool i9xx_plane_get_hw_state(struct intel_plane *plane) +static bool i9xx_plane_get_hw_state(struct intel_plane *plane, + enum pipe *pipe) { struct drm_i915_private *dev_priv = to_i915(plane->base.dev); enum intel_display_power_domain power_domain; enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; - enum pipe pipe = plane->pipe; bool ret; + u32 val; /* * Not 100% correct for planes that can move between pipes, * but that's only the case for gen2-4 which don't have any * display power wells. */ - power_domain = POWER_DOMAIN_PIPE(pipe); + power_domain = POWER_DOMAIN_PIPE(plane->pipe); if (!intel_display_power_get_if_enabled(dev_priv, power_domain)) return false; - ret = I915_READ(DSPCNTR(i9xx_plane)) & DISPLAY_PLANE_ENABLE; + val = I915_READ(DSPCNTR(i9xx_plane)); + + ret = val & DISPLAY_PLANE_ENABLE; + + if (INTEL_GEN(dev_priv) >= 5) + *pipe = plane->pipe; + else + *pipe = (val & DISPPLANE_SEL_PIPE_MASK) >> + DISPPLANE_SEL_PIPE_SHIFT; intel_display_power_put(dev_priv, power_domain); @@ -7647,16 +7659,18 @@ i9xx_get_initial_plane_config(struct intel_crtc *crtc, struct drm_i915_private *dev_priv = to_i915(dev); struct intel_plane *plane = to_intel_plane(crtc->base.primary); enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; - enum pipe pipe = crtc->pipe; + enum pipe pipe; u32 val, base, offset; int fourcc, pixel_format; unsigned int aligned_height; struct drm_framebuffer *fb; struct intel_framebuffer *intel_fb; - if (!plane->get_hw_state(plane)) + if (!plane->get_hw_state(plane, &pipe)) return; + WARN_ON(pipe != crtc->pipe); + intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL); if (!intel_fb) { DRM_DEBUG_KMS("failed to alloc fb\n"); @@ -8677,16 +8691,18 @@ skylake_get_initial_plane_config(struct intel_crtc *crtc, struct drm_i915_private *dev_priv = to_i915(dev); struct intel_plane *plane = to_intel_plane(crtc->base.primary); enum plane_id plane_id = plane->id; - enum pipe pipe = crtc->pipe; + enum pipe pipe; u32 val, base, offset, stride_mult, tiling, alpha; int fourcc, pixel_format; unsigned int aligned_height; struct drm_framebuffer *fb; struct intel_framebuffer *intel_fb; - if (!plane->get_hw_state(plane)) + if (!plane->get_hw_state(plane, &pipe)) return; + WARN_ON(pipe != crtc->pipe); + intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL); if (!intel_fb) { DRM_DEBUG_KMS("failed to alloc fb\n"); @@ -9667,7 +9683,8 @@ static void i845_disable_cursor(struct intel_plane *plane, i845_update_cursor(plane, NULL, NULL); } -static bool i845_cursor_get_hw_state(struct intel_plane *plane) +static bool i845_cursor_get_hw_state(struct intel_plane *plane, + enum pipe *pipe) { struct drm_i915_private *dev_priv = to_i915(plane->base.dev); enum intel_display_power_domain power_domain; @@ -9679,6 +9696,8 @@ static bool i845_cursor_get_hw_state(struct intel_plane *plane) ret = I915_READ(CURCNTR(PIPE_A)) & CURSOR_ENABLE; + *pipe = PIPE_A; + intel_display_power_put(dev_priv, power_domain); return ret; @@ -9880,23 +9899,32 @@ static void i9xx_disable_cursor(struct intel_plane *plane, i9xx_update_cursor(plane, NULL, NULL); } -static bool i9xx_cursor_get_hw_state(struct intel_plane *plane) +static bool i9xx_cursor_get_hw_state(struct intel_plane *plane, + enum pipe *pipe) { struct drm_i915_private *dev_priv = to_i915(plane->base.dev); enum intel_display_power_domain power_domain; - enum pipe pipe = plane->pipe; bool ret; + u32 val; /* * Not 100% correct for planes that can move between pipes, * but that's only the case for gen2-3 which don't have any * display power wells. */ - power_domain = POWER_DOMAIN_PIPE(pipe); + power_domain = POWER_DOMAIN_PIPE(plane->pipe); if (!intel_display_power_get_if_enabled(dev_priv, power_domain)) return false; - ret = I915_READ(CURCNTR(pipe)) & CURSOR_MODE; + val = I915_READ(CURCNTR(plane->pipe)); + + ret = val & CURSOR_MODE; + + if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv)) + *pipe = plane->pipe; + else + *pipe = (val & MCURSOR_PIPE_SELECT_MASK) >> + MCURSOR_PIPE_SELECT_SHIFT; intel_display_power_put(dev_priv, power_domain); @@ -15087,12 +15115,12 @@ void i830_disable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe) static bool intel_plane_mapping_ok(struct intel_crtc *crtc, struct intel_plane *plane) { - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; - u32 val = I915_READ(DSPCNTR(i9xx_plane)); + enum pipe pipe; - return (val & DISPLAY_PLANE_ENABLE) == 0 || - (val & DISPPLANE_SEL_PIPE_MASK) == DISPPLANE_SEL_PIPE(crtc->pipe); + if (!plane->get_hw_state(plane, &pipe)) + return true; + + return pipe == crtc->pipe; } static void @@ -15294,7 +15322,10 @@ static void readout_plane_state(struct intel_crtc *crtc) for_each_intel_plane_on_crtc(&dev_priv->drm, crtc, plane) { struct intel_plane_state *plane_state = to_intel_plane_state(plane->base.state); - bool visible = plane->get_hw_state(plane); + enum pipe pipe; + bool visible; + + visible = plane->get_hw_state(plane, &pipe); intel_set_plane_visible(crtc_state, plane_state, visible); } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index fd6256632482c..1a4659a2e000a 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -970,7 +970,7 @@ struct intel_plane { const struct intel_plane_state *plane_state); void (*disable_plane)(struct intel_plane *plane, struct intel_crtc *crtc); - bool (*get_hw_state)(struct intel_plane *plane); + bool (*get_hw_state)(struct intel_plane *plane, enum pipe *pipe); int (*check_plane)(struct intel_plane *plane, struct intel_crtc_state *crtc_state, struct intel_plane_state *state); @@ -2082,7 +2082,7 @@ void skl_update_plane(struct intel_plane *plane, const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state); void skl_disable_plane(struct intel_plane *plane, struct intel_crtc *crtc); -bool skl_plane_get_hw_state(struct intel_plane *plane); +bool skl_plane_get_hw_state(struct intel_plane *plane, enum pipe *pipe); bool skl_plane_has_ccs(struct drm_i915_private *dev_priv, enum pipe pipe, enum plane_id plane_id); bool intel_format_is_yuv(uint32_t format); diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 1597938d2451f..fe2b44844e8a2 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -327,19 +327,21 @@ skl_disable_plane(struct intel_plane *plane, struct intel_crtc *crtc) } bool -skl_plane_get_hw_state(struct intel_plane *plane) +skl_plane_get_hw_state(struct intel_plane *plane, + enum pipe *pipe) { struct drm_i915_private *dev_priv = to_i915(plane->base.dev); enum intel_display_power_domain power_domain; enum plane_id plane_id = plane->id; - enum pipe pipe = plane->pipe; bool ret; - power_domain = POWER_DOMAIN_PIPE(pipe); + power_domain = POWER_DOMAIN_PIPE(plane->pipe); if (!intel_display_power_get_if_enabled(dev_priv, power_domain)) return false; - ret = I915_READ(PLANE_CTL(pipe, plane_id)) & PLANE_CTL_ENABLE; + ret = I915_READ(PLANE_CTL(plane->pipe, plane_id)) & PLANE_CTL_ENABLE; + + *pipe = plane->pipe; intel_display_power_put(dev_priv, power_domain); @@ -588,19 +590,21 @@ vlv_disable_plane(struct intel_plane *plane, struct intel_crtc *crtc) } static bool -vlv_plane_get_hw_state(struct intel_plane *plane) +vlv_plane_get_hw_state(struct intel_plane *plane, + enum pipe *pipe) { struct drm_i915_private *dev_priv = to_i915(plane->base.dev); enum intel_display_power_domain power_domain; enum plane_id plane_id = plane->id; - enum pipe pipe = plane->pipe; bool ret; - power_domain = POWER_DOMAIN_PIPE(pipe); + power_domain = POWER_DOMAIN_PIPE(plane->pipe); if (!intel_display_power_get_if_enabled(dev_priv, power_domain)) return false; - ret = I915_READ(SPCNTR(pipe, plane_id)) & SP_ENABLE; + ret = I915_READ(SPCNTR(plane->pipe, plane_id)) & SP_ENABLE; + + *pipe = plane->pipe; intel_display_power_put(dev_priv, power_domain); @@ -754,18 +758,20 @@ ivb_disable_plane(struct intel_plane *plane, struct intel_crtc *crtc) } static bool -ivb_plane_get_hw_state(struct intel_plane *plane) +ivb_plane_get_hw_state(struct intel_plane *plane, + enum pipe *pipe) { struct drm_i915_private *dev_priv = to_i915(plane->base.dev); enum intel_display_power_domain power_domain; - enum pipe pipe = plane->pipe; bool ret; - power_domain = POWER_DOMAIN_PIPE(pipe); + power_domain = POWER_DOMAIN_PIPE(plane->pipe); if (!intel_display_power_get_if_enabled(dev_priv, power_domain)) return false; - ret = I915_READ(SPRCTL(pipe)) & SPRITE_ENABLE; + ret = I915_READ(SPRCTL(plane->pipe)) & SPRITE_ENABLE; + + *pipe = plane->pipe; intel_display_power_put(dev_priv, power_domain); @@ -910,18 +916,20 @@ g4x_disable_plane(struct intel_plane *plane, struct intel_crtc *crtc) } static bool -g4x_plane_get_hw_state(struct intel_plane *plane) +g4x_plane_get_hw_state(struct intel_plane *plane, + enum pipe *pipe) { struct drm_i915_private *dev_priv = to_i915(plane->base.dev); enum intel_display_power_domain power_domain; - enum pipe pipe = plane->pipe; bool ret; - power_domain = POWER_DOMAIN_PIPE(pipe); + power_domain = POWER_DOMAIN_PIPE(plane->pipe); if (!intel_display_power_get_if_enabled(dev_priv, power_domain)) return false; - ret = I915_READ(DVSCNTR(pipe)) & DVS_ENABLE; + ret = I915_READ(DVSCNTR(plane->pipe)) & DVS_ENABLE; + + *pipe = plane->pipe; intel_display_power_put(dev_priv, power_domain); -- GitLab From b99b9ec1d374fd0354691d94ddb87b593f700f3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Wed, 31 Jan 2018 16:37:09 +0200 Subject: [PATCH 0158/1506] drm/i915: Clean up cursor defines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use MCURSOR_ instead of CURSOR_ as the prefix for the non-845/865 cursor defines consistently, and move the pipe CSC enable bit next to the other non-845/865 cursor defines. v2: Take care of gvt uses as well v3: Another gvt use popped up Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180131143709.875-1-ville.syrjala@linux.intel.com Reviewed-by: Mika Kahola <mika.kahola@intel.com> #v2 --- drivers/gpu/drm/i915/gvt/display.c | 4 ++-- drivers/gpu/drm/i915/gvt/fb_decoder.c | 12 ++++++------ drivers/gpu/drm/i915/i915_reg.h | 22 +++++++++++----------- drivers/gpu/drm/i915/intel_display.c | 16 ++++++++-------- 4 files changed, 27 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/display.c b/drivers/gpu/drm/i915/gvt/display.c index 6d8180e8d1e21..120e24c3fc628 100644 --- a/drivers/gpu/drm/i915/gvt/display.c +++ b/drivers/gpu/drm/i915/gvt/display.c @@ -273,8 +273,8 @@ static void emulate_monitor_status_change(struct intel_vgpu *vgpu) for_each_pipe(dev_priv, pipe) { vgpu_vreg_t(vgpu, DSPCNTR(pipe)) &= ~DISPLAY_PLANE_ENABLE; vgpu_vreg_t(vgpu, SPRCTL(pipe)) &= ~SPRITE_ENABLE; - vgpu_vreg_t(vgpu, CURCNTR(pipe)) &= ~CURSOR_MODE; - vgpu_vreg_t(vgpu, CURCNTR(pipe)) |= CURSOR_MODE_DISABLE; + vgpu_vreg_t(vgpu, CURCNTR(pipe)) &= ~MCURSOR_MODE; + vgpu_vreg_t(vgpu, CURCNTR(pipe)) |= MCURSOR_MODE_DISABLE; } vgpu_vreg_t(vgpu, PIPECONF(PIPE_A)) |= PIPECONF_ENABLE; diff --git a/drivers/gpu/drm/i915/gvt/fb_decoder.c b/drivers/gpu/drm/i915/gvt/fb_decoder.c index 1c120683e9588..00b788cf8b13e 100644 --- a/drivers/gpu/drm/i915/gvt/fb_decoder.c +++ b/drivers/gpu/drm/i915/gvt/fb_decoder.c @@ -300,16 +300,16 @@ static int cursor_mode_to_drm(int mode) int cursor_pixel_formats_index = 4; switch (mode) { - case CURSOR_MODE_128_ARGB_AX: + case MCURSOR_MODE_128_ARGB_AX: cursor_pixel_formats_index = 0; break; - case CURSOR_MODE_256_ARGB_AX: + case MCURSOR_MODE_256_ARGB_AX: cursor_pixel_formats_index = 1; break; - case CURSOR_MODE_64_ARGB_AX: + case MCURSOR_MODE_64_ARGB_AX: cursor_pixel_formats_index = 2; break; - case CURSOR_MODE_64_32B_AX: + case MCURSOR_MODE_64_32B_AX: cursor_pixel_formats_index = 3; break; @@ -342,8 +342,8 @@ int intel_vgpu_decode_cursor_plane(struct intel_vgpu *vgpu, return -ENODEV; val = vgpu_vreg_t(vgpu, CURCNTR(pipe)); - mode = val & CURSOR_MODE; - plane->enabled = (mode != CURSOR_MODE_DISABLE); + mode = val & MCURSOR_MODE; + plane->enabled = (mode != MCURSOR_MODE_DISABLE); if (!plane->enabled) return -ENODEV; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index be8a194727559..749d238117490 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -5919,7 +5919,6 @@ enum { #define CURSOR_GAMMA_ENABLE 0x40000000 #define CURSOR_STRIDE_SHIFT 28 #define CURSOR_STRIDE(x) ((ffs(x)-9) << CURSOR_STRIDE_SHIFT) /* 256,512,1k,2k */ -#define CURSOR_PIPE_CSC_ENABLE (1<<24) #define CURSOR_FORMAT_SHIFT 24 #define CURSOR_FORMAT_MASK (0x07 << CURSOR_FORMAT_SHIFT) #define CURSOR_FORMAT_2C (0x00 << CURSOR_FORMAT_SHIFT) @@ -5928,20 +5927,21 @@ enum { #define CURSOR_FORMAT_ARGB (0x04 << CURSOR_FORMAT_SHIFT) #define CURSOR_FORMAT_XRGB (0x05 << CURSOR_FORMAT_SHIFT) /* New style CUR*CNTR flags */ -#define CURSOR_MODE 0x27 -#define CURSOR_MODE_DISABLE 0x00 -#define CURSOR_MODE_128_32B_AX 0x02 -#define CURSOR_MODE_256_32B_AX 0x03 -#define CURSOR_MODE_64_32B_AX 0x07 -#define CURSOR_MODE_128_ARGB_AX ((1 << 5) | CURSOR_MODE_128_32B_AX) -#define CURSOR_MODE_256_ARGB_AX ((1 << 5) | CURSOR_MODE_256_32B_AX) -#define CURSOR_MODE_64_ARGB_AX ((1 << 5) | CURSOR_MODE_64_32B_AX) +#define MCURSOR_MODE 0x27 +#define MCURSOR_MODE_DISABLE 0x00 +#define MCURSOR_MODE_128_32B_AX 0x02 +#define MCURSOR_MODE_256_32B_AX 0x03 +#define MCURSOR_MODE_64_32B_AX 0x07 +#define MCURSOR_MODE_128_ARGB_AX ((1 << 5) | MCURSOR_MODE_128_32B_AX) +#define MCURSOR_MODE_256_ARGB_AX ((1 << 5) | MCURSOR_MODE_256_32B_AX) +#define MCURSOR_MODE_64_ARGB_AX ((1 << 5) | MCURSOR_MODE_64_32B_AX) #define MCURSOR_PIPE_SELECT_MASK (0x3 << 28) #define MCURSOR_PIPE_SELECT_SHIFT 28 #define MCURSOR_PIPE_SELECT(pipe) ((pipe) << 28) #define MCURSOR_GAMMA_ENABLE (1 << 26) -#define CURSOR_ROTATE_180 (1<<15) -#define CURSOR_TRICKLE_FEED_DISABLE (1 << 14) +#define MCURSOR_PIPE_CSC_ENABLE (1<<24) +#define MCURSOR_ROTATE_180 (1<<15) +#define MCURSOR_TRICKLE_FEED_DISABLE (1 << 14) #define _CURABASE 0x70084 #define _CURAPOS 0x70088 #define CURSOR_POS_MASK 0x007FF diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 136f129f71c40..3f94fd3e8df28 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9715,7 +9715,7 @@ static u32 i9xx_cursor_ctl(const struct intel_crtc_state *crtc_state, cntl |= MCURSOR_GAMMA_ENABLE; if (HAS_DDI(dev_priv)) - cntl |= CURSOR_PIPE_CSC_ENABLE; + cntl |= MCURSOR_PIPE_CSC_ENABLE; } if (INTEL_GEN(dev_priv) < 5 && !IS_G4X(dev_priv)) @@ -9723,13 +9723,13 @@ static u32 i9xx_cursor_ctl(const struct intel_crtc_state *crtc_state, switch (plane_state->base.crtc_w) { case 64: - cntl |= CURSOR_MODE_64_ARGB_AX; + cntl |= MCURSOR_MODE_64_ARGB_AX; break; case 128: - cntl |= CURSOR_MODE_128_ARGB_AX; + cntl |= MCURSOR_MODE_128_ARGB_AX; break; case 256: - cntl |= CURSOR_MODE_256_ARGB_AX; + cntl |= MCURSOR_MODE_256_ARGB_AX; break; default: MISSING_CASE(plane_state->base.crtc_w); @@ -9737,7 +9737,7 @@ static u32 i9xx_cursor_ctl(const struct intel_crtc_state *crtc_state, } if (plane_state->base.rotation & DRM_MODE_ROTATE_180) - cntl |= CURSOR_ROTATE_180; + cntl |= MCURSOR_ROTATE_180; return cntl; } @@ -9918,7 +9918,7 @@ static bool i9xx_cursor_get_hw_state(struct intel_plane *plane, val = I915_READ(CURCNTR(plane->pipe)); - ret = val & CURSOR_MODE; + ret = val & MCURSOR_MODE; if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv)) *pipe = plane->pipe; @@ -15100,8 +15100,8 @@ void i830_disable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe) WARN_ON(I915_READ(DSPCNTR(PLANE_A)) & DISPLAY_PLANE_ENABLE); WARN_ON(I915_READ(DSPCNTR(PLANE_B)) & DISPLAY_PLANE_ENABLE); WARN_ON(I915_READ(DSPCNTR(PLANE_C)) & DISPLAY_PLANE_ENABLE); - WARN_ON(I915_READ(CURCNTR(PIPE_A)) & CURSOR_MODE); - WARN_ON(I915_READ(CURCNTR(PIPE_B)) & CURSOR_MODE); + WARN_ON(I915_READ(CURCNTR(PIPE_A)) & MCURSOR_MODE); + WARN_ON(I915_READ(CURCNTR(PIPE_B)) & MCURSOR_MODE); I915_WRITE(PIPECONF(pipe), 0); POSTING_READ(PIPECONF(pipe)); -- GitLab From e876b78c5fbf1ef1b5eded8bd4d7ae045ade589a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Tue, 30 Jan 2018 22:38:05 +0200 Subject: [PATCH 0159/1506] drm/i915: Disable trickle feed for SNB/IVB cursors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We disable trickle feed whenever possible, except for the cursors on SNB/IVB. Let's try disabling it there too if for no other reason than consistency. Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180130203807.13721-5-ville.syrjala@linux.intel.com Reviewed-by: Mika Kahola <mika.kahola@intel.com> --- drivers/gpu/drm/i915/intel_display.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3f94fd3e8df28..0fcad0f0f175b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9711,6 +9711,9 @@ static u32 i9xx_cursor_ctl(const struct intel_crtc_state *crtc_state, struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); u32 cntl = 0; + if (IS_GEN6(dev_priv) || IS_IVYBRIDGE(dev_priv)) + cntl |= MCURSOR_TRICKLE_FEED_DISABLE; + if (INTEL_GEN(dev_priv) <= 10) { cntl |= MCURSOR_GAMMA_ENABLE; -- GitLab From 6380db61c54f6e5d6b05598eeb9beaf54c3e21a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Tue, 30 Jan 2018 22:38:07 +0200 Subject: [PATCH 0160/1506] drm/i915: s/plane/i9xx_plane/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Call the enum i9xx_plane_id variable i9xx_plane like we do elsewhere. Cc: Hans de Goede <j.w.r.degoede@gmail.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180130203807.13721-7-ville.syrjala@linux.intel.com Reviewed-by: Mika Kahola <mika.kahola@intel.com> --- drivers/gpu/drm/i915/intel_dsi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index cf39ca90d8878..cf1231f9c33bb 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -1665,16 +1665,16 @@ static int intel_dsi_get_panel_orientation(struct intel_connector *connector) { struct drm_i915_private *dev_priv = to_i915(connector->base.dev); int orientation = DRM_MODE_PANEL_ORIENTATION_NORMAL; - enum i9xx_plane_id plane; + enum i9xx_plane_id i9xx_plane; u32 val; if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { if (connector->encoder->crtc_mask == BIT(PIPE_B)) - plane = PLANE_B; + i9xx_plane = PLANE_B; else - plane = PLANE_A; + i9xx_plane = PLANE_A; - val = I915_READ(DSPCNTR(plane)); + val = I915_READ(DSPCNTR(i9xx_plane)); if (val & DISPPLANE_ROTATE_180) orientation = DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP; } -- GitLab From b4686c481b9b60f9dea12a3001ddbaad6291dc79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Wed, 30 May 2018 19:59:22 +0300 Subject: [PATCH 0161/1506] drm/i915: Fix tabs vs. spaces in sprite code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sprite code has a bunch of spaces where tabs should be used. Fix it up. v2: Make the patch subject more specific (Jani) Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180530165933.11424-3-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula <jani.nikula@intel.com> --- drivers/gpu/drm/i915/intel_sprite.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index fe2b44844e8a2..350c61cfd1e71 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -1385,8 +1385,8 @@ static bool skl_mod_supported(uint32_t format, uint64_t modifier) } static bool intel_sprite_plane_format_mod_supported(struct drm_plane *plane, - uint32_t format, - uint64_t modifier) + uint32_t format, + uint64_t modifier) { struct drm_i915_private *dev_priv = to_i915(plane->dev); @@ -1408,14 +1408,14 @@ static bool intel_sprite_plane_format_mod_supported(struct drm_plane *plane, } static const struct drm_plane_funcs intel_sprite_plane_funcs = { - .update_plane = drm_atomic_helper_update_plane, - .disable_plane = drm_atomic_helper_disable_plane, - .destroy = intel_plane_destroy, - .atomic_get_property = intel_plane_atomic_get_property, - .atomic_set_property = intel_plane_atomic_set_property, - .atomic_duplicate_state = intel_plane_duplicate_state, - .atomic_destroy_state = intel_plane_destroy_state, - .format_mod_supported = intel_sprite_plane_format_mod_supported, + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = intel_plane_destroy, + .atomic_get_property = intel_plane_atomic_get_property, + .atomic_set_property = intel_plane_atomic_set_property, + .atomic_duplicate_state = intel_plane_duplicate_state, + .atomic_destroy_state = intel_plane_destroy_state, + .format_mod_supported = intel_sprite_plane_format_mod_supported, }; bool skl_plane_has_ccs(struct drm_i915_private *dev_priv, -- GitLab From 012d79e6a33f095c293fe2a02b2b3b26d8c6402c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Mon, 21 May 2018 21:56:12 +0300 Subject: [PATCH 0162/1506] drm/i915: Remove bogus NV12 PLANE_COLOR_CTL setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We already handle the color encoding mode properly. Remove the broken NV12 special case. Cc: Vidya Srinivas <vidya.srinivas@intel.com> Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Fixes: 8ed30ab6aced ("drm/i915: Enable YUV to RGB for Gen10 in Plane Ctrl Reg") Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180521185613.5097-1-ville.syrjala@linux.intel.com Reviewed-By: Vidya Srinivas <vidya.srinivas@intel.com> --- drivers/gpu/drm/i915/intel_display.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0fcad0f0f175b..b422312804185 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3659,11 +3659,6 @@ u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state, plane_color_ctl |= glk_plane_color_ctl_alpha(fb->format->format); if (intel_format_is_yuv(fb->format->format)) { - if (fb->format->format == DRM_FORMAT_NV12) { - plane_color_ctl |= - PLANE_COLOR_CSC_MODE_YUV709_TO_RGB709; - goto out; - } if (plane_state->base.color_encoding == DRM_COLOR_YCBCR_BT709) plane_color_ctl |= PLANE_COLOR_CSC_MODE_YUV709_TO_RGB709; else @@ -3672,7 +3667,7 @@ u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state, if (plane_state->base.color_range == DRM_COLOR_YCBCR_FULL_RANGE) plane_color_ctl |= PLANE_COLOR_YUV_RANGE_CORRECTION_DISABLE; } -out: + return plane_color_ctl; } -- GitLab From 0a59952b24e24e153b8d1cbd781c8d264257b1b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Mon, 21 May 2018 21:56:13 +0300 Subject: [PATCH 0163/1506] drm/i915: Configure SKL+ scaler initial phase correctly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Set up the SKL+ scaler initial phase registers correctly. Otherwise we start fetching the data from the center of the first pixel instead of the top-left corner, which obviously then leads to right/bottom edges replicating data excessively as the data runs out half a pixel too soon. Cc: Vidya Srinivas <vidya.srinivas@intel.com> Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180521185613.5097-2-ville.syrjala@linux.intel.com Reviewed-By: Vidya Srinivas <vidya.srinivas@intel.com> --- drivers/gpu/drm/i915/i915_reg.h | 4 +++ drivers/gpu/drm/i915/intel_display.c | 41 ++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_sprite.c | 26 ++++++++++++++++-- 4 files changed, 70 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 749d238117490..43397e50fec37 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6789,6 +6789,10 @@ enum { #define _PS_VPHASE_1B 0x68988 #define _PS_VPHASE_2B 0x68A88 #define _PS_VPHASE_1C 0x69188 +#define PS_Y_PHASE(x) ((x) << 16) +#define PS_UV_RGB_PHASE(x) ((x) << 0) +#define PS_PHASE_MASK (0x7fff << 1) /* u2.13 */ +#define PS_PHASE_TRIP (1 << 0) #define _PS_HPHASE_1A 0x68194 #define _PS_HPHASE_2A 0x68294 diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b422312804185..141ded5244820 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4752,6 +4752,39 @@ static void cpt_verify_modeset(struct drm_device *dev, int pipe) } } +/* + * The hardware phase 0.0 refers to the center of the pixel. + * We want to start from the top/left edge which is phase + * -0.5. That matches how the hardware calculates the scaling + * factors (from top-left of the first pixel to bottom-right + * of the last pixel, as opposed to the pixel centers). + * + * For 4:2:0 subsampled chroma planes we obviously have to + * adjust that so that the chroma sample position lands in + * the right spot. + * + * Note that for packed YCbCr 4:2:2 formats there is no way to + * control chroma siting. The hardware simply replicates the + * chroma samples for both of the luma samples, and thus we don't + * actually get the expected MPEG2 chroma siting convention :( + * The same behaviour is observed on pre-SKL platforms as well. + */ +u16 skl_scaler_calc_phase(int sub, bool chroma_cosited) +{ + int phase = -0x8000; + u16 trip = 0; + + if (chroma_cosited) + phase += (sub - 1) * 0x8000 / sub; + + if (phase < 0) + phase = 0x10000 + phase; + else + trip = PS_PHASE_TRIP; + + return ((phase >> 2) & PS_PHASE_MASK) | trip; +} + static int skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach, unsigned int scaler_user, int *scaler_id, @@ -4951,14 +4984,22 @@ static void skylake_pfit_enable(struct intel_crtc *crtc) &crtc->config->scaler_state; if (crtc->config->pch_pfit.enabled) { + u16 uv_rgb_hphase, uv_rgb_vphase; int id; if (WARN_ON(crtc->config->scaler_state.scaler_id < 0)) return; + uv_rgb_hphase = skl_scaler_calc_phase(1, false); + uv_rgb_vphase = skl_scaler_calc_phase(1, false); + id = scaler_state->scaler_id; I915_WRITE(SKL_PS_CTRL(pipe, id), PS_SCALER_EN | PS_FILTER_MEDIUM | scaler_state->scalers[id].mode); + I915_WRITE_FW(SKL_PS_VPHASE(pipe, id), + PS_Y_PHASE(0) | PS_UV_RGB_PHASE(uv_rgb_vphase)); + I915_WRITE_FW(SKL_PS_HPHASE(pipe, id), + PS_Y_PHASE(0) | PS_UV_RGB_PHASE(uv_rgb_hphase)); I915_WRITE(SKL_PS_WIN_POS(pipe, id), crtc->config->pch_pfit.pos); I915_WRITE(SKL_PS_WIN_SZ(pipe, id), crtc->config->pch_pfit.size); } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 1a4659a2e000a..b1bb1a9d61f82 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1616,6 +1616,7 @@ void intel_mode_from_pipe_config(struct drm_display_mode *mode, void intel_crtc_arm_fifo_underrun(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state); +u16 skl_scaler_calc_phase(int sub, bool chroma_center); int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state); int skl_max_scale(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state, uint32_t pixel_format); diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 350c61cfd1e71..24f86c4375cf9 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -284,13 +284,35 @@ skl_update_plane(struct intel_plane *plane, /* program plane scaler */ if (plane_state->scaler_id >= 0) { int scaler_id = plane_state->scaler_id; - const struct intel_scaler *scaler; + const struct intel_scaler *scaler = + &crtc_state->scaler_state.scalers[scaler_id]; + u16 y_hphase, uv_rgb_hphase; + u16 y_vphase, uv_rgb_vphase; + + /* TODO: handle sub-pixel coordinates */ + if (fb->format->format == DRM_FORMAT_NV12) { + y_hphase = skl_scaler_calc_phase(1, false); + y_vphase = skl_scaler_calc_phase(1, false); + + /* MPEG2 chroma siting convention */ + uv_rgb_hphase = skl_scaler_calc_phase(2, true); + uv_rgb_vphase = skl_scaler_calc_phase(2, false); + } else { + /* not used */ + y_hphase = 0; + y_vphase = 0; - scaler = &crtc_state->scaler_state.scalers[scaler_id]; + uv_rgb_hphase = skl_scaler_calc_phase(1, false); + uv_rgb_vphase = skl_scaler_calc_phase(1, false); + } I915_WRITE_FW(SKL_PS_CTRL(pipe, scaler_id), PS_SCALER_EN | PS_PLANE_SEL(plane_id) | scaler->mode); I915_WRITE_FW(SKL_PS_PWR_GATE(pipe, scaler_id), 0); + I915_WRITE_FW(SKL_PS_VPHASE(pipe, scaler_id), + PS_Y_PHASE(y_vphase) | PS_UV_RGB_PHASE(uv_rgb_vphase)); + I915_WRITE_FW(SKL_PS_HPHASE(pipe, scaler_id), + PS_Y_PHASE(y_hphase) | PS_UV_RGB_PHASE(uv_rgb_hphase)); I915_WRITE_FW(SKL_PS_WIN_POS(pipe, scaler_id), (crtc_x << 16) | crtc_y); I915_WRITE_FW(SKL_PS_WIN_SZ(pipe, scaler_id), ((crtc_w + 1) << 16)|(crtc_h + 1)); -- GitLab From 9776f47253c3d953db8f9e33b3d75105f293ca70 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 1 Jun 2018 15:41:24 +0100 Subject: [PATCH 0164/1506] drm/i915: Flush all writes before suspend As we have already suspended the device, this should be a no-op except for marking that all writes are indeed complete. The downside is that we then have to walk all the lists of objects for what should be a no-op (in some cases they will be mmio read to ensure the GGTT writes are indeed flushed, and clflushes to ensure that cpu writes are in memory). It seems prudent and the safer course for us to ensure all writes are flushed to memory before suspend. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Mika Kuoppala <mika.kuoppala@intel.com> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180601144125.18026-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index c85951f2b15af..f77cffcd87929 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5071,6 +5071,13 @@ int i915_gem_suspend(struct drm_i915_private *dev_priv) void i915_gem_suspend_late(struct drm_i915_private *i915) { + struct drm_i915_gem_object *obj; + struct list_head *phases[] = { + &i915->mm.unbound_list, + &i915->mm.bound_list, + NULL + }, **phase; + /* * Neither the BIOS, ourselves or any other kernel * expects the system to be in execlists mode on startup, @@ -5091,6 +5098,13 @@ void i915_gem_suspend_late(struct drm_i915_private *i915) * machine in an unusable condition. */ + mutex_lock(&i915->drm.struct_mutex); + for (phase = phases; *phase; phase++) { + list_for_each_entry(obj, *phase, mm.link) + WARN_ON(i915_gem_object_set_to_gtt_domain(obj, false)); + } + mutex_unlock(&i915->drm.struct_mutex); + intel_uc_sanitize(i915); i915_gem_sanitize(i915); } -- GitLab From 95c778daecb5cd5aafcc09ebf1353fdc759b6fd7 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 1 Jun 2018 15:41:25 +0100 Subject: [PATCH 0165/1506] drm/i915: Apply the full CPU domain markup before freezing Let's not take any chances by using a shortcut to mark the objects as in the CPU domain upon freezing (all pages will be written to disk and so on restore all objects will start from the CPU domain). Currently, we simply mark the objects as being in the CPU domain, bypassing the flushes. Let's call the full domain transfer function so that we have less special case code (and symmetry with the suspend path) even though it will be mostly redundant. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Mika Kuoppala <mika.kuoppala@intel.com> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180601144125.18026-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index f77cffcd87929..62974e8862d51 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5718,16 +5718,17 @@ int i915_gem_freeze(struct drm_i915_private *dev_priv) return 0; } -int i915_gem_freeze_late(struct drm_i915_private *dev_priv) +int i915_gem_freeze_late(struct drm_i915_private *i915) { struct drm_i915_gem_object *obj; struct list_head *phases[] = { - &dev_priv->mm.unbound_list, - &dev_priv->mm.bound_list, + &i915->mm.unbound_list, + &i915->mm.bound_list, NULL - }, **p; + }, **phase; - /* Called just before we write the hibernation image. + /* + * Called just before we write the hibernation image. * * We need to update the domain tracking to reflect that the CPU * will be accessing all the pages to create and restore from the @@ -5741,15 +5742,15 @@ int i915_gem_freeze_late(struct drm_i915_private *dev_priv) * the objects as well, see i915_gem_freeze() */ - i915_gem_shrink(dev_priv, -1UL, NULL, I915_SHRINK_UNBOUND); - i915_gem_drain_freed_objects(dev_priv); + i915_gem_shrink(i915, -1UL, NULL, I915_SHRINK_UNBOUND); + i915_gem_drain_freed_objects(i915); - spin_lock(&dev_priv->mm.obj_lock); - for (p = phases; *p; p++) { - list_for_each_entry(obj, *p, mm.link) - __start_cpu_write(obj); + mutex_lock(&i915->drm.struct_mutex); + for (phase = phases; *phase; phase++) { + list_for_each_entry(obj, *phase, mm.link) + WARN_ON(i915_gem_object_set_to_cpu_domain(obj, true)); } - spin_unlock(&dev_priv->mm.obj_lock); + mutex_unlock(&i915->drm.struct_mutex); return 0; } -- GitLab From c46ef57d2008e5195f086a538550488b49644db7 Mon Sep 17 00:00:00 2001 From: Mahesh Kumar <mahesh1.kumar@intel.com> Date: Fri, 25 May 2018 08:52:38 -0700 Subject: [PATCH 0166/1506] drm/i915/icl: fix icl_unmap/map_plls_to_ports All connectors may not have best_encoder attached, so don't dereference encoder pointer for each connector. Fixes: c27e917e2bda ("drm/i915/icl: add basic support for the ICL clocks") Reviewed-by: Lucas De Marchi <lucas.demarchi@intel.com> Signed-off-by: Mahesh Kumar <mahesh1.kumar@intel.com> Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180525155238.7054-1-lucas.demarchi@intel.com --- drivers/gpu/drm/i915/intel_ddi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 3b8f12883ca79..c33b19705e394 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -2444,12 +2444,13 @@ void icl_map_plls_to_ports(struct drm_crtc *crtc, for_each_new_connector_in_state(old_state, conn, conn_state, i) { struct intel_encoder *encoder = to_intel_encoder(conn_state->best_encoder); - enum port port = encoder->port; + enum port port; uint32_t val; if (conn_state->crtc != crtc) continue; + port = encoder->port; mutex_lock(&dev_priv->dpll_lock); val = I915_READ(DPCLKA_CFGCR0_ICL); @@ -2481,11 +2482,12 @@ void icl_unmap_plls_to_ports(struct drm_crtc *crtc, for_each_old_connector_in_state(old_state, conn, old_conn_state, i) { struct intel_encoder *encoder = to_intel_encoder(old_conn_state->best_encoder); - enum port port = encoder->port; + enum port port; if (old_conn_state->crtc != crtc) continue; + port = encoder->port; mutex_lock(&dev_priv->dpll_lock); I915_WRITE(DPCLKA_CFGCR0_ICL, I915_READ(DPCLKA_CFGCR0_ICL) | -- GitLab From 9bb635d9e7dbfd8e0bc352457c70e75d612c7edb Mon Sep 17 00:00:00 2001 From: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Date: Mon, 21 May 2018 17:25:35 -0700 Subject: [PATCH 0167/1506] drm/i915/icl: Extend AUX F interrupts to ICL ICL has AUX F. Cc: Paulo Zanoni <paulo.r.zanoni@intel.com> Cc: Anusha Srivatsa <anusha.srivatsa@intel.com> Reviewed-by: Anusha Srivatsa <anusha.srivatsa@intel.com> Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180522002558.29262-2-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/i915_irq.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index f9bc3aaa90d0f..2fd92a8867894 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2640,7 +2640,8 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl) GEN9_AUX_CHANNEL_C | GEN9_AUX_CHANNEL_D; - if (IS_CNL_WITH_PORT_F(dev_priv)) + if (IS_CNL_WITH_PORT_F(dev_priv) || + INTEL_GEN(dev_priv) >= 11) tmp_mask |= CNL_AUX_CHANNEL_F; if (iir & tmp_mask) { @@ -3920,7 +3921,7 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv) de_pipe_masked |= GEN8_DE_PIPE_IRQ_FAULT_ERRORS; } - if (IS_CNL_WITH_PORT_F(dev_priv)) + if (IS_CNL_WITH_PORT_F(dev_priv) || INTEL_GEN(dev_priv) >= 11) de_port_masked |= CNL_AUX_CHANNEL_F; de_pipe_enables = de_pipe_masked | GEN8_PIPE_VBLANK | -- GitLab From ac213c1b45f7dcedb71d955c2321cbb4a2b6558e Mon Sep 17 00:00:00 2001 From: Paulo Zanoni <paulo.r.zanoni@intel.com> Date: Mon, 21 May 2018 17:25:37 -0700 Subject: [PATCH 0168/1506] drm/i915/icl: introduce tc_port Add and enum for TC ports and auxiliary functions to handle them. Icelake brings a lot of registers and other things that only apply to the TC ports and are indexed starting from 0, so having an enum for tc_ports that starts at 0 really helps the indexing. This patch is based on previous patches written by Dhinakaran Pandiyan and Mahesh Kumar. Cc: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Cc: Mahesh Kumar <mahesh1.kumar@intel.com> Reviewed-by: Mahesh Kumar <mahesh1.kumar@intel.com> Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180522002558.29262-4-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/intel_display.c | 16 ++++++++++++++++ drivers/gpu/drm/i915/intel_display.h | 11 +++++++++++ drivers/gpu/drm/i915/intel_drv.h | 3 +++ 3 files changed, 30 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 141ded5244820..17c590b42fd76 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5869,6 +5869,22 @@ static void i9xx_pfit_enable(struct intel_crtc *crtc) I915_WRITE(BCLRPAT(crtc->pipe), 0); } +bool intel_port_is_tc(struct drm_i915_private *dev_priv, enum port port) +{ + if (IS_ICELAKE(dev_priv)) + return port >= PORT_C && port <= PORT_F; + + return false; +} + +enum tc_port intel_port_to_tc(struct drm_i915_private *dev_priv, enum port port) +{ + if (!intel_port_is_tc(dev_priv, port)) + return PORT_TC_NONE; + + return port - PORT_C; +} + enum intel_display_power_domain intel_port_to_power_domain(enum port port) { switch (port) { diff --git a/drivers/gpu/drm/i915/intel_display.h b/drivers/gpu/drm/i915/intel_display.h index 2ef31617614ab..c88185ed75944 100644 --- a/drivers/gpu/drm/i915/intel_display.h +++ b/drivers/gpu/drm/i915/intel_display.h @@ -126,6 +126,17 @@ enum port { #define port_name(p) ((p) + 'A') +enum tc_port { + PORT_TC_NONE = -1, + + PORT_TC1 = 0, + PORT_TC2, + PORT_TC3, + PORT_TC4, + + I915_MAX_TC_PORTS +}; + enum dpio_channel { DPIO_CH0, DPIO_CH1 diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index b1bb1a9d61f82..8641583842be6 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1489,6 +1489,9 @@ void intel_connector_attach_encoder(struct intel_connector *connector, struct intel_encoder *encoder); struct drm_display_mode * intel_encoder_current_mode(struct intel_encoder *encoder); +bool intel_port_is_tc(struct drm_i915_private *dev_priv, enum port port); +enum tc_port intel_port_to_tc(struct drm_i915_private *dev_priv, + enum port port); enum pipe intel_get_pipe_from_connector(struct intel_connector *connector); int intel_get_pipe_from_crtc_id_ioctl(struct drm_device *dev, void *data, -- GitLab From a2bc69a1a9d6820976dfa014a6e7dcc53c585793 Mon Sep 17 00:00:00 2001 From: Manasi Navare <manasi.d.navare@intel.com> Date: Fri, 25 May 2018 12:03:52 -0700 Subject: [PATCH 0169/1506] drm/i915/icl: Add register definition for DFLEXDPMLE DFLEXDPMLE register is required to tell the FIA hardware which main links of DP are enabled on TCC Connectors. FIA uses this information to program PHY to Controller signal mapping. This register is applicable in both TC connector's Alternate mode as well as DP connector mode. v2: * Remove _ICL prefix since the reg is first introduced in ICL (Paulo) * s/ICL/icl in commit message (Lucas) Cc: Jani Nikula <jani.nikula@linux.intel.com> Cc: Animesh Manna <animesh.manna@intel.com> Cc: Madhav Chauhan <madhav.chauhan@intel.com> Cc: Anusha Srivatsa <anusha.srivatsa@intel.com> Cc: Paulo Zanoni <paulo.r.zanoni@intel.com> Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Signed-off-by: Manasi Navare <manasi.d.navare@intel.com> Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/1527275032-4555-1-git-send-email-manasi.d.navare@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 43397e50fec37..5866b7d0ad818 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1990,6 +1990,11 @@ enum i915_power_well_id { _ICL_PORT_COMP_DW10_A, \ _ICL_PORT_COMP_DW10_B) +/* ICL PHY DFLEX registers */ +#define PORT_TX_DFLEXDPMLE1 _MMIO(0x1638C0) +#define DFLEXDPMLE1_DPMLETC_MASK(n) (0xf << (4 * (n))) +#define DFLEXDPMLE1_DPMLETC(n, x) ((x) << (4 * (n))) + /* BXT PHY Ref registers */ #define _PORT_REF_DW3_A 0x16218C #define _PORT_REF_DW3_BC 0x6C18C -- GitLab From 3937eb1a076f251ecc29330a0b6ca10dbe2e633b Mon Sep 17 00:00:00 2001 From: Radhakrishna Sripada <radhakrishna.sripada@intel.com> Date: Mon, 21 May 2018 17:25:42 -0700 Subject: [PATCH 0170/1506] drm/i915/icl: Map VBT DDC Pin to BSpec DDC Pin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On ICL we need to map VBT DDC Pin to BSpec DDC Pin. Adding ICL Pin Values. According to VBT Block 2 (General Bytes Definition) DDC Bus +----------+-----------+--------------------+ | DDI Type | VBT Value | BSpec Mapped Value | +----------+-----------+--------------------+ | DDI-A | 0x1 | 0x1 | | DDI-B | 0x2 | 0x2 | | PORT-1 | 0x4 | 0x9 | | PORT-2 | 0x5 | 0xA | | PORT-3 | 0x6 | 0xB | | PORT-4 | 0x7 | 0xC | +----------+-----------+--------------------+ Cc: James Ausmus <james.ausmus@intel.com> Cc: Jani Nikula <jani.nikula@intel.com> Cc: Anusha Srivatsa <anusha.srivatsa@intel.com> Cc: Clinton Taylor <clinton.a.taylor@intel.com> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com> Cc: Paulo Zanoni <paulo.r.zanoni@intel.com> Reviewed-by: James Ausmus <james.ausmus@intel.com> Signed-off-by: Radhakrishna Sripada <radhakrishna.sripada@intel.com> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com> [Paulo: checkpatch fixes.] Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180522002558.29262-9-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/intel_bios.c | 35 +++++++++++++++++++++------ drivers/gpu/drm/i915/intel_vbt_defs.h | 6 +++++ 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 1cf073b6ac8a7..465dff4780fea 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -1259,18 +1259,37 @@ static const u8 cnp_ddc_pin_map[] = { [DDC_BUS_DDI_F] = GMBUS_PIN_3_BXT, /* sic */ }; +static const u8 icp_ddc_pin_map[] = { + [ICL_DDC_BUS_DDI_A] = GMBUS_PIN_1_BXT, + [ICL_DDC_BUS_DDI_B] = GMBUS_PIN_2_BXT, + [ICL_DDC_BUS_PORT_1] = GMBUS_PIN_9_TC1_ICP, + [ICL_DDC_BUS_PORT_2] = GMBUS_PIN_10_TC2_ICP, + [ICL_DDC_BUS_PORT_3] = GMBUS_PIN_11_TC3_ICP, + [ICL_DDC_BUS_PORT_4] = GMBUS_PIN_12_TC4_ICP, +}; + static u8 map_ddc_pin(struct drm_i915_private *dev_priv, u8 vbt_pin) { - if (HAS_PCH_CNP(dev_priv)) { - if (vbt_pin < ARRAY_SIZE(cnp_ddc_pin_map)) { - return cnp_ddc_pin_map[vbt_pin]; - } else { - DRM_DEBUG_KMS("Ignoring alternate pin: VBT claims DDC pin %d, which is not valid for this platform\n", vbt_pin); - return 0; - } + const u8 *ddc_pin_map; + int n_entries; + + if (HAS_PCH_ICP(dev_priv)) { + ddc_pin_map = icp_ddc_pin_map; + n_entries = ARRAY_SIZE(icp_ddc_pin_map); + } else if (HAS_PCH_CNP(dev_priv)) { + ddc_pin_map = cnp_ddc_pin_map; + n_entries = ARRAY_SIZE(cnp_ddc_pin_map); + } else { + /* Assuming direct map */ + return vbt_pin; } - return vbt_pin; + if (vbt_pin < n_entries && ddc_pin_map[vbt_pin] != 0) + return ddc_pin_map[vbt_pin]; + + DRM_DEBUG_KMS("Ignoring alternate pin: VBT claims DDC pin %d, which is not valid for this platform\n", + vbt_pin); + return 0; } static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port, diff --git a/drivers/gpu/drm/i915/intel_vbt_defs.h b/drivers/gpu/drm/i915/intel_vbt_defs.h index 39c8046241793..c132d0c3a500c 100644 --- a/drivers/gpu/drm/i915/intel_vbt_defs.h +++ b/drivers/gpu/drm/i915/intel_vbt_defs.h @@ -318,6 +318,12 @@ enum vbt_gmbus_ddi { DDC_BUS_DDI_C, DDC_BUS_DDI_D, DDC_BUS_DDI_F, + ICL_DDC_BUS_DDI_A = 0x1, + ICL_DDC_BUS_DDI_B, + ICL_DDC_BUS_PORT_1 = 0x4, + ICL_DDC_BUS_PORT_2, + ICL_DDC_BUS_PORT_3, + ICL_DDC_BUS_PORT_4, }; #define VBT_DP_MAX_LINK_RATE_HBR3 0 -- GitLab From f17ca5010c34e99e4035f22437f8b83452584a26 Mon Sep 17 00:00:00 2001 From: Anusha Srivatsa <anusha.srivatsa@intel.com> Date: Mon, 21 May 2018 17:25:43 -0700 Subject: [PATCH 0171/1506] drm/i915/icl: Add Icelake PCH detection This patch adds the support to detect PCH_ICP. Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Suggested-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Signed-off-by: Anusha Srivatsa <anusha.srivatsa@intel.com> Signed-off-by: Michel Thierry <michel.thierry@intel.com> Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180522002558.29262-10-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/i915_drv.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index fe92665c8482b..915758a65c96f 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -233,6 +233,8 @@ intel_virt_detect_pch(const struct drm_i915_private *dev_priv) id = INTEL_PCH_SPT_DEVICE_ID_TYPE; else if (IS_COFFEELAKE(dev_priv) || IS_CANNONLAKE(dev_priv)) id = INTEL_PCH_CNP_DEVICE_ID_TYPE; + else if (IS_ICELAKE(dev_priv)) + id = INTEL_PCH_ICP_DEVICE_ID_TYPE; if (id) DRM_DEBUG_KMS("Assuming PCH ID %04x\n", id); -- GitLab From 51c83cfaf96382ab65717d694f80af86482ba795 Mon Sep 17 00:00:00 2001 From: Manasi Navare <manasi.d.navare@intel.com> Date: Wed, 23 May 2018 15:44:44 -0700 Subject: [PATCH 0172/1506] drm/i915/icl: Get DDI clock for ICL based on PLLs. PLLs are the source clocks for the DDIs so in order to determine the ddi clock we need to check the PLL configuration. This gets a little tricky for ICL since there is no register bit that maps directly to the link clock. So this patch creates a separate function in intel_dpll_mgr.c to obtain the write array PLL Params and compares the set pll_params with the table to get the corresponding link clock. v2: - Fix the encoder type check (DK). - Improve our error checking, return a sane value (Mika, Paulo). - Fix table entries (Paulo). Cc: Rodrigo Vivi <rodrigo.vivi@intel.com> Cc: Mika Kahola <mika.kahola@intel.com> Cc: Paulo Zanoni <paulo.r.zanoni@intel.com> Cc: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Reviewed-by: Mika Kahola <mika.kahola@intel.com> Signed-off-by: Manasi Navare <manasi.d.navare@intel.com> Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com> [Paulo: implement v2] Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180523224444.19017-1-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 3 ++ drivers/gpu/drm/i915/intel_ddi.c | 26 ++++++++++ drivers/gpu/drm/i915/intel_dpll_mgr.c | 70 +++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_dpll_mgr.h | 2 + 4 files changed, 101 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 5866b7d0ad818..f0317bde3aabc 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -9127,13 +9127,16 @@ enum skl_power_gate { #define DPLL_CFGCR1_QDIV_RATIO_MASK (0xff << 10) #define DPLL_CFGCR1_QDIV_RATIO_SHIFT (10) #define DPLL_CFGCR1_QDIV_RATIO(x) ((x) << 10) +#define DPLL_CFGCR1_QDIV_MODE_SHIFT (9) #define DPLL_CFGCR1_QDIV_MODE(x) ((x) << 9) #define DPLL_CFGCR1_KDIV_MASK (7 << 6) +#define DPLL_CFGCR1_KDIV_SHIFT (6) #define DPLL_CFGCR1_KDIV(x) ((x) << 6) #define DPLL_CFGCR1_KDIV_1 (1 << 6) #define DPLL_CFGCR1_KDIV_2 (2 << 6) #define DPLL_CFGCR1_KDIV_4 (4 << 6) #define DPLL_CFGCR1_PDIV_MASK (0xf << 2) +#define DPLL_CFGCR1_PDIV_SHIFT (2) #define DPLL_CFGCR1_PDIV(x) ((x) << 2) #define DPLL_CFGCR1_PDIV_2 (1 << 2) #define DPLL_CFGCR1_PDIV_3 (2 << 2) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index c33b19705e394..3f042c505430d 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1422,6 +1422,30 @@ static void ddi_dotclock_get(struct intel_crtc_state *pipe_config) pipe_config->base.adjusted_mode.crtc_clock = dotclock; } +static void icl_ddi_clock_get(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + enum port port = encoder->port; + int link_clock = 0; + uint32_t pll_id; + + pll_id = intel_get_shared_dpll_id(dev_priv, pipe_config->shared_dpll); + if (port == PORT_A || port == PORT_B) { + if (intel_crtc_has_type(pipe_config, INTEL_OUTPUT_HDMI)) + link_clock = cnl_calc_wrpll_link(dev_priv, pll_id); + else + link_clock = icl_calc_dp_combo_pll_link(dev_priv, + pll_id); + } else { + /* FIXME - Add for MG PLL */ + WARN(1, "MG PLL clock_get code not implemented yet\n"); + } + + pipe_config->port_clock = link_clock; + ddi_dotclock_get(pipe_config); +} + static void cnl_ddi_clock_get(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config) { @@ -1615,6 +1639,8 @@ static void intel_ddi_clock_get(struct intel_encoder *encoder, bxt_ddi_clock_get(encoder, pipe_config); else if (IS_CANNONLAKE(dev_priv)) cnl_ddi_clock_get(encoder, pipe_config); + else if (IS_ICELAKE(dev_priv)) + icl_ddi_clock_get(encoder, pipe_config); } void intel_ddi_set_pipe_settings(const struct intel_crtc_state *crtc_state) diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c index 383fbc15113da..07bdbf2582ba1 100644 --- a/drivers/gpu/drm/i915/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c @@ -2525,6 +2525,76 @@ static bool icl_calc_dpll_state(struct intel_crtc_state *crtc_state, return true; } +int icl_calc_dp_combo_pll_link(struct drm_i915_private *dev_priv, + uint32_t pll_id) +{ + uint32_t cfgcr0, cfgcr1; + uint32_t pdiv, kdiv, qdiv_mode, qdiv_ratio, dco_integer, dco_fraction; + const struct skl_wrpll_params *params; + int index, n_entries, link_clock; + + /* Read back values from DPLL CFGCR registers */ + cfgcr0 = I915_READ(ICL_DPLL_CFGCR0(pll_id)); + cfgcr1 = I915_READ(ICL_DPLL_CFGCR1(pll_id)); + + dco_integer = cfgcr0 & DPLL_CFGCR0_DCO_INTEGER_MASK; + dco_fraction = (cfgcr0 & DPLL_CFGCR0_DCO_FRACTION_MASK) >> + DPLL_CFGCR0_DCO_FRACTION_SHIFT; + pdiv = (cfgcr1 & DPLL_CFGCR1_PDIV_MASK) >> DPLL_CFGCR1_PDIV_SHIFT; + kdiv = (cfgcr1 & DPLL_CFGCR1_KDIV_MASK) >> DPLL_CFGCR1_KDIV_SHIFT; + qdiv_mode = (cfgcr1 & DPLL_CFGCR1_QDIV_MODE(1)) >> + DPLL_CFGCR1_QDIV_MODE_SHIFT; + qdiv_ratio = (cfgcr1 & DPLL_CFGCR1_QDIV_RATIO_MASK) >> + DPLL_CFGCR1_QDIV_RATIO_SHIFT; + + params = dev_priv->cdclk.hw.ref == 24000 ? + icl_dp_combo_pll_24MHz_values : + icl_dp_combo_pll_19_2MHz_values; + n_entries = ARRAY_SIZE(icl_dp_combo_pll_24MHz_values); + + for (index = 0; index < n_entries; index++) { + if (dco_integer == params[index].dco_integer && + dco_fraction == params[index].dco_fraction && + pdiv == params[index].pdiv && + kdiv == params[index].kdiv && + qdiv_mode == params[index].qdiv_mode && + qdiv_ratio == params[index].qdiv_ratio) + break; + } + + /* Map PLL Index to Link Clock */ + switch (index) { + default: + MISSING_CASE(index); + case 0: + link_clock = 540000; + break; + case 1: + link_clock = 270000; + break; + case 2: + link_clock = 162000; + break; + case 3: + link_clock = 324000; + break; + case 4: + link_clock = 216000; + break; + case 5: + link_clock = 432000; + break; + case 6: + link_clock = 648000; + break; + case 7: + link_clock = 810000; + break; + } + + return link_clock; +} + static enum port icl_mg_pll_id_to_port(enum intel_dpll_id id) { return id - DPLL_ID_ICL_MGPLL1 + PORT_C; diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.h b/drivers/gpu/drm/i915/intel_dpll_mgr.h index 7a0cd564a9ee1..78915057d2e65 100644 --- a/drivers/gpu/drm/i915/intel_dpll_mgr.h +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.h @@ -336,5 +336,7 @@ void intel_shared_dpll_init(struct drm_device *dev); void intel_dpll_dump_hw_state(struct drm_i915_private *dev_priv, struct intel_dpll_hw_state *hw_state); +int icl_calc_dp_combo_pll_link(struct drm_i915_private *dev_priv, + uint32_t pll_id); #endif /* _INTEL_DPLL_MGR_H_ */ -- GitLab From 5428bf5a9a9f28fae1ba2c57ba4ea8f8d358d10c Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler <arkadiusz.hiler@intel.com> Date: Mon, 21 May 2018 17:25:46 -0700 Subject: [PATCH 0173/1506] drm/i915/icl: Calculate link clock using the new registers Start using the new registers for ICL and on. Cc: Manasi Navare <manasi.d.navare@intel.com> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com> Cc: Paulo Zanoni <paulo.r.zanoni@intel.com> Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Signed-off-by: Arkadiusz Hiler <arkadiusz.hiler@intel.com> Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180522002558.29262-13-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/intel_ddi.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 3f042c505430d..b344e0fe08fd5 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1345,8 +1345,13 @@ static int cnl_calc_wrpll_link(struct drm_i915_private *dev_priv, uint32_t cfgcr0, cfgcr1; uint32_t p0, p1, p2, dco_freq, ref_clock; - cfgcr0 = I915_READ(CNL_DPLL_CFGCR0(pll_id)); - cfgcr1 = I915_READ(CNL_DPLL_CFGCR1(pll_id)); + if (INTEL_GEN(dev_priv) >= 11) { + cfgcr0 = I915_READ(ICL_DPLL_CFGCR0(pll_id)); + cfgcr1 = I915_READ(ICL_DPLL_CFGCR1(pll_id)); + } else { + cfgcr0 = I915_READ(CNL_DPLL_CFGCR0(pll_id)); + cfgcr1 = I915_READ(CNL_DPLL_CFGCR1(pll_id)); + } p0 = cfgcr1 & DPLL_CFGCR1_PDIV_MASK; p2 = cfgcr1 & DPLL_CFGCR1_KDIV_MASK; -- GitLab From 6931317c714885f2d792e8150ef6715d416ac681 Mon Sep 17 00:00:00 2001 From: Lubosz Sarnecki <lubosz.sarnecki@collabora.com> Date: Tue, 29 May 2018 13:52:15 +0200 Subject: [PATCH 0174/1506] drm/edid: Quirk Vive Pro VR headset non-desktop. This adds the Vive Pro's EDID information and sets EDID_QUIRK_NON_DESKTOP. Signed-off-by: Lubosz Sarnecki <lubosz.sarnecki@collabora.com> Signed-off-by: Daniel Stone <daniels@collabora.com> Reviewed-by: Daniel Stone <daniels@collabora.com> Cc: <stable@vger.kernel.org> # v4.15+ Link: https://patchwork.freedesktop.org/patch/msgid/20180529115215.4526-1-lubosz.sarnecki@collabora.com --- drivers/gpu/drm/drm_edid.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 634a68a03b07e..87654b8b279c3 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -163,8 +163,9 @@ static const struct edid_quirk { /* Rotel RSX-1058 forwards sink's EDID but only does HDMI 1.1*/ { "ETR", 13896, EDID_QUIRK_FORCE_8BPC }, - /* HTC Vive VR Headset */ + /* HTC Vive and Vive Pro VR Headsets */ { "HVR", 0xaa01, EDID_QUIRK_NON_DESKTOP }, + { "HVR", 0xaa02, EDID_QUIRK_NON_DESKTOP }, /* Oculus Rift DK1, DK2, and CV1 VR Headsets */ { "OVR", 0x0001, EDID_QUIRK_NON_DESKTOP }, -- GitLab From 8979187a8cfa1fd221a17a06a9ce76e72ae52a05 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko <michal.wajdeczko@intel.com> Date: Mon, 4 Jun 2018 09:00:32 +0000 Subject: [PATCH 0175/1506] drm/i915: Move i915_gem_fini to i915_gem.c We should keep i915_gem_init/fini functions together for easier tracking of their symmetry. v2: rebased, pulled out from the series Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com> Cc: Sagar Arun Kamble <sagar.a.kamble@intel.com> Cc: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Sagar Arun Kamble <sagar.a.kamble@intel.com> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20180604090032.20840-1-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/i915_drv.c | 22 ---------------------- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_gem.c | 22 ++++++++++++++++++++++ 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 915758a65c96f..83ce9c1ec170a 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -636,28 +636,6 @@ static const struct vga_switcheroo_client_ops i915_switcheroo_ops = { .can_switch = i915_switcheroo_can_switch, }; -static void i915_gem_fini(struct drm_i915_private *dev_priv) -{ - i915_gem_suspend_late(dev_priv); - - /* Flush any outstanding unpin_work. */ - i915_gem_drain_workqueue(dev_priv); - - mutex_lock(&dev_priv->drm.struct_mutex); - intel_uc_fini_hw(dev_priv); - intel_uc_fini(dev_priv); - i915_gem_cleanup_engines(dev_priv); - i915_gem_contexts_fini(dev_priv); - mutex_unlock(&dev_priv->drm.struct_mutex); - - intel_uc_fini_misc(dev_priv); - i915_gem_cleanup_userptr(dev_priv); - - i915_gem_drain_freed_objects(dev_priv); - - WARN_ON(!list_empty(&dev_priv->contexts.list)); -} - static int i915_load_modeset_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = to_i915(dev); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 38157df6ff5c6..ecc888a972796 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3165,6 +3165,7 @@ void i915_gem_init_mmio(struct drm_i915_private *i915); int __must_check i915_gem_init(struct drm_i915_private *dev_priv); int __must_check i915_gem_init_hw(struct drm_i915_private *dev_priv); void i915_gem_init_swizzling(struct drm_i915_private *dev_priv); +void i915_gem_fini(struct drm_i915_private *dev_priv); void i915_gem_cleanup_engines(struct drm_i915_private *dev_priv); int i915_gem_wait_for_idle(struct drm_i915_private *dev_priv, unsigned int flags); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 62974e8862d51..cb680ddafa0c5 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5554,6 +5554,28 @@ int i915_gem_init(struct drm_i915_private *dev_priv) return ret; } +void i915_gem_fini(struct drm_i915_private *dev_priv) +{ + i915_gem_suspend_late(dev_priv); + + /* Flush any outstanding unpin_work. */ + i915_gem_drain_workqueue(dev_priv); + + mutex_lock(&dev_priv->drm.struct_mutex); + intel_uc_fini_hw(dev_priv); + intel_uc_fini(dev_priv); + i915_gem_cleanup_engines(dev_priv); + i915_gem_contexts_fini(dev_priv); + mutex_unlock(&dev_priv->drm.struct_mutex); + + intel_uc_fini_misc(dev_priv); + i915_gem_cleanup_userptr(dev_priv); + + i915_gem_drain_freed_objects(dev_priv); + + WARN_ON(!list_empty(&dev_priv->contexts.list)); +} + void i915_gem_init_mmio(struct drm_i915_private *i915) { i915_gem_sanitize(i915); -- GitLab From 30aacd3fe7f16bc577c612b710de8f047c2c492a Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Mon, 4 Jun 2018 14:15:52 +0100 Subject: [PATCH 0176/1506] drm/i915/gtt: Remove obsolete switch_mm hooks for gen8+ As the ppgtt for execlists is tightly coupled to the executing context, and not switch separately, we no longer use the ppgtt->switch_mm hooks on gen8+. Remove them. References: 79e6770cb1f5 ("drm/i915: Remove obsolete ringbuffer emission for gen8+") Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: Matthew Auld <matthew.william.auld@gmail.com> Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180604131552.29370-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_gtt.c | 49 ----------------------------- 1 file changed, 49 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index d032069819ccd..96c48decbb73c 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -773,53 +773,6 @@ static void gen8_initialize_pml4(struct i915_address_space *vm, memset_p((void **)pml4->pdps, vm->scratch_pdp, GEN8_PML4ES_PER_PML4); } -/* Broadwell Page Directory Pointer Descriptors */ -static int gen8_write_pdp(struct i915_request *rq, - unsigned entry, - dma_addr_t addr) -{ - struct intel_engine_cs *engine = rq->engine; - u32 *cs; - - BUG_ON(entry >= 4); - - cs = intel_ring_begin(rq, 6); - if (IS_ERR(cs)) - return PTR_ERR(cs); - - *cs++ = MI_LOAD_REGISTER_IMM(1); - *cs++ = i915_mmio_reg_offset(GEN8_RING_PDP_UDW(engine, entry)); - *cs++ = upper_32_bits(addr); - *cs++ = MI_LOAD_REGISTER_IMM(1); - *cs++ = i915_mmio_reg_offset(GEN8_RING_PDP_LDW(engine, entry)); - *cs++ = lower_32_bits(addr); - intel_ring_advance(rq, cs); - - return 0; -} - -static int gen8_mm_switch_3lvl(struct i915_hw_ppgtt *ppgtt, - struct i915_request *rq) -{ - int i, ret; - - for (i = GEN8_3LVL_PDPES - 1; i >= 0; i--) { - const dma_addr_t pd_daddr = i915_page_dir_dma_addr(ppgtt, i); - - ret = gen8_write_pdp(rq, i, pd_daddr); - if (ret) - return ret; - } - - return 0; -} - -static int gen8_mm_switch_4lvl(struct i915_hw_ppgtt *ppgtt, - struct i915_request *rq) -{ - return gen8_write_pdp(rq, 0, px_dma(&ppgtt->pml4)); -} - /* PDE TLBs are a pain to invalidate on GEN8+. When we modify * the page table structures, we mark them dirty so that * context switching/execlist queuing code takes extra steps @@ -1638,7 +1591,6 @@ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt) gen8_initialize_pml4(&ppgtt->base, &ppgtt->pml4); - ppgtt->switch_mm = gen8_mm_switch_4lvl; ppgtt->base.allocate_va_range = gen8_ppgtt_alloc_4lvl; ppgtt->base.insert_entries = gen8_ppgtt_insert_4lvl; ppgtt->base.clear_range = gen8_ppgtt_clear_4lvl; @@ -1655,7 +1607,6 @@ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt) } } - ppgtt->switch_mm = gen8_mm_switch_3lvl; ppgtt->base.allocate_va_range = gen8_ppgtt_alloc_3lvl; ppgtt->base.insert_entries = gen8_ppgtt_insert_3lvl; ppgtt->base.clear_range = gen8_ppgtt_clear_3lvl; -- GitLab From 218b5000982b7c5e7433b86819be92f95984a1ae Mon Sep 17 00:00:00 2001 From: Lionel Landwerlin <lionel.g.landwerlin@intel.com> Date: Sat, 2 Jun 2018 12:29:45 +0100 Subject: [PATCH 0177/1506] drm/i915: drop one bit on the hw_id when using guc We currently using GuC as a proxy to the hardware. When Guc is used in such mode, it consumes the bit 20 of the hw_id to indicate that the workload was submitted by proxy. So far we probably haven't seen the issue because we need to allocate 1048576+ contexts to hit this issue. Still, we should avoid allocating the hw_id on that bit and restriction to bits [0:19] (i.e 20bits instead of 21). v2: Leave the max hw_id computation in i915_gem_context.c (Michel) v3: Be consistent on if/else usage (Chris) Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com> BSpec: 1237 Reviewed-by: Michel Thierry <michel.thierry@intel.com> Acked-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20180602112946.30803-2-lionel.g.landwerlin@intel.com --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_gem_context.c | 15 ++++++++++++--- drivers/gpu/drm/i915/intel_lrc.c | 2 +- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ecc888a972796..b5b09c8a327f7 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1841,6 +1841,7 @@ struct drm_i915_private { */ struct ida hw_ida; #define MAX_CONTEXT_HW_ID (1<<21) /* exclusive */ +#define MAX_GUC_CONTEXT_HW_ID (1 << 20) /* exclusive */ #define GEN11_MAX_CONTEXT_HW_ID (1<<11) /* exclusive */ } contexts; diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 94e4db1870aa3..38c6e9e4e91bf 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -208,10 +208,19 @@ static int assign_hw_id(struct drm_i915_private *dev_priv, unsigned *out) int ret; unsigned int max; - if (INTEL_GEN(dev_priv) >= 11) + if (INTEL_GEN(dev_priv) >= 11) { max = GEN11_MAX_CONTEXT_HW_ID; - else - max = MAX_CONTEXT_HW_ID; + } else { + /* + * When using GuC in proxy submission, GuC consumes the + * highest bit in the context id to indicate proxy submission. + */ + if (USES_GUC_SUBMISSION(dev_priv)) + max = MAX_GUC_CONTEXT_HW_ID; + else + max = MAX_CONTEXT_HW_ID; + } + ret = ida_simple_get(&dev_priv->contexts.hw_ida, 0, max, GFP_KERNEL); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 38696d9cc02ec..cbc2a8d4dc9cf 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -200,7 +200,7 @@ static inline bool need_preempt(const struct intel_engine_cs *engine, * * bits 0-11: flags, GEN8_CTX_* (cached in ctx->desc_template) * bits 12-31: LRCA, GTT address of (the HWSP of) this context - * bits 32-52: ctx ID, a globally unique tag + * bits 32-52: ctx ID, a globally unique tag (highest bit used by GuC) * bits 53-54: mbz, reserved for use by hardware * bits 55-63: group ID, currently unused and set to 0 * -- GitLab From 61d5676b5561d61e3fdd9e88fc2b549b9b4df08f Mon Sep 17 00:00:00 2001 From: Lionel Landwerlin <lionel.g.landwerlin@intel.com> Date: Sat, 2 Jun 2018 12:29:46 +0100 Subject: [PATCH 0178/1506] drm/i915/perf: fix ctx_id read with GuC & ICL One thing we didn't really understand about the OA report is that the ContextID field (dword 2) is copy of the context descriptor (dword 1). On Gen8->10 and without using GuC we didn't notice the issue because we only checked the 21bits of the ContextID field in the OA reports which matches exactly the hw_id stored into the context descriptor. When using GuC submission we have an issue of a non matching hw_id because GuC uses bit 20 of the hw_id to signal proxy submission. This change introduces a mask to compare only the relevant bits. On ICL the context descriptor format has changed and we failed to address this. On top of using a mask we also need to shift the bits properly. v2: Reuse lrc_desc rather than recomputing part of it (Chris/Michel) v3: Always pin the context we're filtering with (Chris) Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com> Fixes: 1de401c08fa805 ("drm/i915/perf: enable perf support on ICL") Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=104252 BSpec: 1237 Testcase: igt/perf/gen8-unprivileged-single-ctx-counters Acked-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Michel Thierry <michel.thierry@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180602112946.30803-3-lionel.g.landwerlin@intel.com Cc: Lionel Landwerlin <lionel.g.landwerlin@intel.com> Cc: Matthew Auld <matthew.auld@intel.com> Cc: Jani Nikula <jani.nikula@linux.intel.com> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com> Cc: intel-gfx@lists.freedesktop.org --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_perf.c | 123 +++++++++++++++++++++++-------- drivers/gpu/drm/i915/intel_lrc.c | 5 ++ 3 files changed, 97 insertions(+), 32 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b5b09c8a327f7..06ecac4c32534 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1951,6 +1951,7 @@ struct drm_i915_private { struct intel_context *pinned_ctx; u32 specific_ctx_id; + u32 specific_ctx_id_mask; struct hrtimer poll_check_timer; wait_queue_head_t poll_wq; diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index 4f0eb84b3c00d..a6c8d61add0cd 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -737,12 +737,7 @@ static int gen8_append_oa_reports(struct i915_perf_stream *stream, continue; } - /* - * XXX: Just keep the lower 21 bits for now since I'm not - * entirely sure if the HW touches any of the higher bits in - * this field - */ - ctx_id = report32[2] & 0x1fffff; + ctx_id = report32[2] & dev_priv->perf.oa.specific_ctx_id_mask; /* * Squash whatever is in the CTX_ID field if it's marked as @@ -1203,6 +1198,33 @@ static int i915_oa_read(struct i915_perf_stream *stream, return dev_priv->perf.oa.ops.read(stream, buf, count, offset); } +static struct intel_context *oa_pin_context(struct drm_i915_private *i915, + struct i915_gem_context *ctx) +{ + struct intel_engine_cs *engine = i915->engine[RCS]; + struct intel_context *ce; + int ret; + + ret = i915_mutex_lock_interruptible(&i915->drm); + if (ret) + return ERR_PTR(ret); + + /* + * As the ID is the gtt offset of the context's vma we + * pin the vma to ensure the ID remains fixed. + * + * NB: implied RCS engine... + */ + ce = intel_context_pin(ctx, engine); + mutex_unlock(&i915->drm.struct_mutex); + if (IS_ERR(ce)) + return ce; + + i915->perf.oa.pinned_ctx = ce; + + return ce; +} + /** * oa_get_render_ctx_id - determine and hold ctx hw id * @stream: An i915-perf stream opened for OA metrics @@ -1215,40 +1237,76 @@ static int i915_oa_read(struct i915_perf_stream *stream, */ static int oa_get_render_ctx_id(struct i915_perf_stream *stream) { - struct drm_i915_private *dev_priv = stream->dev_priv; - - if (HAS_LOGICAL_RING_CONTEXTS(dev_priv)) { - dev_priv->perf.oa.specific_ctx_id = stream->ctx->hw_id; - } else { - struct intel_engine_cs *engine = dev_priv->engine[RCS]; - struct intel_context *ce; - int ret; + struct drm_i915_private *i915 = stream->dev_priv; + struct intel_context *ce; - ret = i915_mutex_lock_interruptible(&dev_priv->drm); - if (ret) - return ret; + ce = oa_pin_context(i915, stream->ctx); + if (IS_ERR(ce)) + return PTR_ERR(ce); + switch (INTEL_GEN(i915)) { + case 7: { /* - * As the ID is the gtt offset of the context's vma we - * pin the vma to ensure the ID remains fixed. - * - * NB: implied RCS engine... + * On Haswell we don't do any post processing of the reports + * and don't need to use the mask. */ - ce = intel_context_pin(stream->ctx, engine); - mutex_unlock(&dev_priv->drm.struct_mutex); - if (IS_ERR(ce)) - return PTR_ERR(ce); + i915->perf.oa.specific_ctx_id = i915_ggtt_offset(ce->state); + i915->perf.oa.specific_ctx_id_mask = 0; + break; + } - dev_priv->perf.oa.pinned_ctx = ce; + case 8: + case 9: + case 10: + if (USES_GUC_SUBMISSION(i915)) { + /* + * When using GuC, the context descriptor we write in + * i915 is read by GuC and rewritten before it's + * actually written into the hardware. The LRCA is + * what is put into the context id field of the + * context descriptor by GuC. Because it's aligned to + * a page, the lower 12bits are always at 0 and + * dropped by GuC. They won't be part of the context + * ID in the OA reports, so squash those lower bits. + */ + i915->perf.oa.specific_ctx_id = + lower_32_bits(ce->lrc_desc) >> 12; - /* - * Explicitly track the ID (instead of calling - * i915_ggtt_offset() on the fly) considering the difference - * with gen8+ and execlists - */ - dev_priv->perf.oa.specific_ctx_id = i915_ggtt_offset(ce->state); + /* + * GuC uses the top bit to signal proxy submission, so + * ignore that bit. + */ + i915->perf.oa.specific_ctx_id_mask = + (1U << (GEN8_CTX_ID_WIDTH - 1)) - 1; + } else { + i915->perf.oa.specific_ctx_id = stream->ctx->hw_id; + i915->perf.oa.specific_ctx_id_mask = + (1U << GEN8_CTX_ID_WIDTH) - 1; + } + break; + + case 11: { + struct intel_engine_cs *engine = i915->engine[RCS]; + + i915->perf.oa.specific_ctx_id = + stream->ctx->hw_id << (GEN11_SW_CTX_ID_SHIFT - 32) | + engine->instance << (GEN11_ENGINE_INSTANCE_SHIFT - 32) | + engine->class << (GEN11_ENGINE_INSTANCE_SHIFT - 32); + i915->perf.oa.specific_ctx_id_mask = + ((1U << GEN11_SW_CTX_ID_WIDTH) - 1) << (GEN11_SW_CTX_ID_SHIFT - 32) | + ((1U << GEN11_ENGINE_INSTANCE_WIDTH) - 1) << (GEN11_ENGINE_INSTANCE_SHIFT - 32) | + ((1 << GEN11_ENGINE_CLASS_WIDTH) - 1) << (GEN11_ENGINE_CLASS_SHIFT - 32); + break; + } + + default: + MISSING_CASE(INTEL_GEN(i915)); } + DRM_DEBUG_DRIVER("filtering on ctx_id=0x%x ctx_id_mask=0x%x\n", + i915->perf.oa.specific_ctx_id, + i915->perf.oa.specific_ctx_id_mask); + return 0; } @@ -1265,6 +1323,7 @@ static void oa_put_render_ctx_id(struct i915_perf_stream *stream) struct intel_context *ce; dev_priv->perf.oa.specific_ctx_id = INVALID_CTX_ID; + dev_priv->perf.oa.specific_ctx_id_mask = 0; ce = fetch_and_zero(&dev_priv->perf.oa.pinned_ctx); if (ce) { diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index cbc2a8d4dc9cf..f6f09f808f74a 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -233,6 +233,11 @@ intel_lr_context_descriptor_update(struct i915_gem_context *ctx, /* bits 12-31 */ GEM_BUG_ON(desc & GENMASK_ULL(63, 32)); + /* + * The following 32bits are copied into the OA reports (dword 2). + * Consider updating oa_get_render_ctx_id in i915_perf.c when changing + * anything below. + */ if (INTEL_GEN(ctx->i915) >= 11) { GEM_BUG_ON(ctx->hw_id >= BIT(GEN11_SW_CTX_ID_WIDTH)); desc |= (u64)ctx->hw_id << GEN11_SW_CTX_ID_SHIFT; -- GitLab From 6ceb7277173597eeed8d635e08db51e35235ab21 Mon Sep 17 00:00:00 2001 From: Mahesh Kumar <mahesh1.kumar@intel.com> Date: Thu, 17 May 2018 18:56:26 +0530 Subject: [PATCH 0179/1506] drm/i915/icl: Don't update enabled dbuf slices struct until updated in hw Do not update number of enabled dbuf slices in dev_priv struct until we actually enable/disable dbuf slice in hw. This is leading to never updating dbuf slices and resulting in DBuf slice mismatch warning. Fixes: aa9664ffe863 ("drm/i915/icl: Enable 2nd DBuf slice only when needed") Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Signed-off-by: Mahesh Kumar <mahesh1.kumar@intel.com> Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180517132626.5885-1-mahesh1.kumar@intel.com --- drivers/gpu/drm/i915/intel_pm.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index b85229e153c42..53aaaa3e6886d 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5150,7 +5150,6 @@ skl_copy_ddb_for_pipe(struct skl_ddb_values *dst, sizeof(dst->ddb.uv_plane[pipe])); memcpy(dst->ddb.plane[pipe], src->ddb.plane[pipe], sizeof(dst->ddb.plane[pipe])); - dst->ddb.enabled_slices = src->ddb.enabled_slices; } static void -- GitLab From 52b2416ceb72e8f757eb56de5a98ade04d9b062d Mon Sep 17 00:00:00 2001 From: Changbin Du <changbin.du@intel.com> Date: Tue, 8 May 2018 17:07:05 +0800 Subject: [PATCH 0180/1506] drm/i915: Add new vGPU cap info bit VGT_CAPS_HUGE_GTT This adds a new vGPU cap info bit VGT_CAPS_HUGE_GTT, which is to detect whether the host supports shadowing of huge gtt pages. If host does support it, remove the page sizes restriction for vGPU. Signed-off-by: Changbin Du <changbin.du@intel.com> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Signed-off-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/1525770425-5373-1-git-send-email-changbin.du@intel.com --- drivers/gpu/drm/i915/i915_gem.c | 8 ++------ drivers/gpu/drm/i915/i915_pvinfo.h | 1 + drivers/gpu/drm/i915/i915_vgpu.h | 6 ++++++ 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index cb680ddafa0c5..2a51a2b6d22cf 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5409,12 +5409,8 @@ int i915_gem_init(struct drm_i915_private *dev_priv) { int ret; - /* - * We need to fallback to 4K pages since gvt gtt handling doesn't - * support huge page entries - we will need to check either hypervisor - * mm can support huge guest page or just do emulation in gvt. - */ - if (intel_vgpu_active(dev_priv)) + /* We need to fallback to 4K pages if host doesn't support huge gtt. */ + if (intel_vgpu_active(dev_priv) && !intel_vgpu_has_huge_gtt(dev_priv)) mkwrite_device_info(dev_priv)->page_sizes = I915_GTT_PAGE_SIZE_4K; diff --git a/drivers/gpu/drm/i915/i915_pvinfo.h b/drivers/gpu/drm/i915/i915_pvinfo.h index 195203f298dfc..55bde4a022896 100644 --- a/drivers/gpu/drm/i915/i915_pvinfo.h +++ b/drivers/gpu/drm/i915/i915_pvinfo.h @@ -54,6 +54,7 @@ enum vgt_g2v_type { */ #define VGT_CAPS_FULL_48BIT_PPGTT BIT(2) #define VGT_CAPS_HWSP_EMULATION BIT(3) +#define VGT_CAPS_HUGE_GTT BIT(4) struct vgt_if { u64 magic; /* VGT_MAGIC */ diff --git a/drivers/gpu/drm/i915/i915_vgpu.h b/drivers/gpu/drm/i915/i915_vgpu.h index bb8338450dc11..551acc3900464 100644 --- a/drivers/gpu/drm/i915/i915_vgpu.h +++ b/drivers/gpu/drm/i915/i915_vgpu.h @@ -36,6 +36,12 @@ intel_vgpu_has_hwsp_emulation(struct drm_i915_private *dev_priv) return dev_priv->vgpu.caps & VGT_CAPS_HWSP_EMULATION; } +static inline bool +intel_vgpu_has_huge_gtt(struct drm_i915_private *dev_priv) +{ + return dev_priv->vgpu.caps & VGT_CAPS_HUGE_GTT; +} + int intel_vgt_balloon(struct drm_i915_private *dev_priv); void intel_vgt_deballoon(struct drm_i915_private *dev_priv); -- GitLab From d901e8e6733544e772713a23ab345eb79153de8c Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Tue, 5 Jun 2018 09:53:48 +0100 Subject: [PATCH 0181/1506] drm/i915/ringbuffer: Make context pin/unpin symmetric Currently, we have a special routine for pinning the context state at the start of activity tracking, but lack the complementary unpin routine. Create it to to ease later patches that want to do partial teardown on error, and, not least, to improve the readability of the code. Suggested-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: Matthew Auld <matthew.william.auld@gmail.com> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180605085348.3018-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_ringbuffer.c | 67 ++++++++++++++++--------- 1 file changed, 43 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 001cf6bcb3497..3f0eb538df098 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1193,20 +1193,14 @@ static void intel_ring_context_destroy(struct intel_context *ce) __i915_gem_object_release_unless_active(ce->state->obj); } -static void intel_ring_context_unpin(struct intel_context *ce) -{ - if (ce->state) { - ce->state->obj->pin_global--; - i915_vma_unpin(ce->state); - } - - i915_gem_context_put(ce->gem_context); -} - static int __context_pin(struct intel_context *ce) { - struct i915_vma *vma = ce->state; - int ret; + struct i915_vma *vma; + int err; + + vma = ce->state; + if (!vma) + return 0; /* * Clear this page out of any CPU caches for coherent swap-in/out. @@ -1214,13 +1208,42 @@ static int __context_pin(struct intel_context *ce) * on an active context (which by nature is already on the GPU). */ if (!(vma->flags & I915_VMA_GLOBAL_BIND)) { - ret = i915_gem_object_set_to_gtt_domain(vma->obj, true); - if (ret) - return ret; + err = i915_gem_object_set_to_gtt_domain(vma->obj, true); + if (err) + return err; } - return i915_vma_pin(vma, 0, I915_GTT_MIN_ALIGNMENT, - PIN_GLOBAL | PIN_HIGH); + err = i915_vma_pin(vma, 0, I915_GTT_MIN_ALIGNMENT, + PIN_GLOBAL | PIN_HIGH); + if (err) + return err; + + /* + * And mark is as a globally pinned object to let the shrinker know + * it cannot reclaim the object until we release it. + */ + vma->obj->pin_global++; + + return 0; +} + +static void __context_unpin(struct intel_context *ce) +{ + struct i915_vma *vma; + + vma = ce->state; + if (!vma) + return; + + vma->obj->pin_global--; + i915_vma_unpin(vma); +} + +static void intel_ring_context_unpin(struct intel_context *ce) +{ + __context_unpin(ce); + + i915_gem_context_put(ce->gem_context); } static struct i915_vma * @@ -1311,13 +1334,9 @@ __ring_context_pin(struct intel_engine_cs *engine, ce->state = vma; } - if (ce->state) { - err = __context_pin(ce); - if (err) - goto err; - - ce->state->obj->pin_global++; - } + err = __context_pin(ce); + if (err) + goto err; i915_gem_context_get(ctx); -- GitLab From 744799850ef1cb053457a8a7652165e895ea26a0 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Tue, 5 Jun 2018 09:28:56 +0100 Subject: [PATCH 0182/1506] drm/i915/gtt: Teach restore-gtt to walk the ggtt vma list not the object list In preparation, for having non-vma objects stored inside the ggtt, to handle restoration of the GGTT following resume, we need to walk over the ggtt address space rebinding vma, as opposed to walking over bound objects looking for ggtt entries. v2: Skip objects only bound for the aliasing_ppgtt Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: Matthew Auld <matthew.william.auld@gmail.com> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> #v1 Link: https://patchwork.freedesktop.org/patch/msgid/20180605082856.19221-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_gtt.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 96c48decbb73c..9302ee6e717d6 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -3569,7 +3569,7 @@ void i915_ggtt_disable_guc(struct drm_i915_private *i915) void i915_gem_restore_gtt_mappings(struct drm_i915_private *dev_priv) { struct i915_ggtt *ggtt = &dev_priv->ggtt; - struct drm_i915_gem_object *obj, *on; + struct i915_vma *vma, *vn; i915_check_and_clear_faults(dev_priv); @@ -3579,21 +3579,18 @@ void i915_gem_restore_gtt_mappings(struct drm_i915_private *dev_priv) ggtt->base.closed = true; /* skip rewriting PTE on VMA unbind */ /* clflush objects bound into the GGTT and rebind them. */ - list_for_each_entry_safe(obj, on, &dev_priv->mm.bound_list, mm.link) { - bool ggtt_bound = false; - struct i915_vma *vma; + GEM_BUG_ON(!list_empty(&ggtt->base.active_list)); + list_for_each_entry_safe(vma, vn, &ggtt->base.inactive_list, vm_link) { + struct drm_i915_gem_object *obj = vma->obj; - for_each_ggtt_vma(vma, obj) { - if (!i915_vma_unbind(vma)) - continue; + if (!(vma->flags & I915_VMA_GLOBAL_BIND)) + continue; - WARN_ON(i915_vma_bind(vma, obj->cache_level, - PIN_UPDATE)); - ggtt_bound = true; - } + if (!i915_vma_unbind(vma)) + continue; - if (ggtt_bound) - WARN_ON(i915_gem_object_set_to_gtt_domain(obj, false)); + WARN_ON(i915_vma_bind(vma, obj->cache_level, PIN_UPDATE)); + WARN_ON(i915_gem_object_set_to_gtt_domain(obj, false)); } ggtt->base.closed = false; -- GitLab From 83d317adfb4b27ec589b59548cf52e3b63a39fc9 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Tue, 5 Jun 2018 10:41:07 +0100 Subject: [PATCH 0183/1506] drm/i915/vma: Move the bind_count vs pin_count assertion to a helper To spare ourselves a long line later, refactor the repeated check of bind_count vs pin_count to a helper. v2: Fix up the commentary! Suggested-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: Matthew Auld <matthew.william.auld@gmail.com> Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180605094107.31367-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_vma.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c index 9324d476e0a7c..10bf654cd0235 100644 --- a/drivers/gpu/drm/i915/i915_vma.c +++ b/drivers/gpu/drm/i915/i915_vma.c @@ -459,6 +459,18 @@ bool i915_gem_valid_gtt_space(struct i915_vma *vma, unsigned long cache_level) return true; } +static void assert_bind_count(const struct drm_i915_gem_object *obj) +{ + /* + * Combine the assertion that the object is bound and that we have + * pinned its pages. But we should never have bound the object + * more than we have pinned its pages. (For complete accuracy, we + * assume that no else is pinning the pages, but as a rough assertion + * that we will not run into problems later, this will do!) + */ + GEM_BUG_ON(atomic_read(&obj->mm.pages_pin_count) < obj->bind_count); +} + /** * i915_vma_insert - finds a slot for the vma in its address space * @vma: the vma @@ -595,7 +607,7 @@ i915_vma_insert(struct i915_vma *vma, u64 size, u64 alignment, u64 flags) obj->bind_count++; spin_unlock(&dev_priv->mm.obj_lock); - GEM_BUG_ON(atomic_read(&obj->mm.pages_pin_count) < obj->bind_count); + assert_bind_count(obj); return 0; @@ -633,7 +645,7 @@ i915_vma_remove(struct i915_vma *vma) * reaped by the shrinker. */ i915_gem_object_unpin_pages(obj); - GEM_BUG_ON(atomic_read(&obj->mm.pages_pin_count) < obj->bind_count); + assert_bind_count(obj); } int __i915_vma_do_pin(struct i915_vma *vma, -- GitLab From b96f6ebfd02444b290ff5048c1ae61f5d3d52319 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko <michal.wajdeczko@intel.com> Date: Tue, 5 Jun 2018 12:24:43 +0000 Subject: [PATCH 0184/1506] drm/i915: Correctly handle error path in i915_gem_init_hw In function gem_init_hw() we are calling uc_init_hw() but in case of error later in function, we missed to call matching uc_fini_hw() v2: pulled out from the series Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com> Cc: Sagar Arun Kamble <sagar.a.kamble@intel.com> Cc: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Sagar Arun Kamble <sagar.a.kamble@intel.com> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20180605122443.23776-1-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/i915_gem.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 2a51a2b6d22cf..c419975951836 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5286,9 +5286,15 @@ int i915_gem_init_hw(struct drm_i915_private *dev_priv) /* Only when the HW is re-initialised, can we replay the requests */ ret = __i915_gem_restart_engines(dev_priv); + if (ret) + goto cleanup_uc; out: intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL); return ret; + +cleanup_uc: + intel_uc_fini_hw(dev_priv); + goto out; } static int __intel_engines_record_defaults(struct drm_i915_private *i915) -- GitLab From 420980ca79bcac50cab5bfd20c3d7e5425b1f3d6 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Tue, 5 Jun 2018 14:57:46 +0100 Subject: [PATCH 0185/1506] drm/i915: Swap magics and use SZ_1M Since the kernel provides SZ_1M, use it in preference of 1 << 20. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Michal Wajdeczko <michal.wajdeczko@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180605135746.8020-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index c419975951836..23374f3dd79d3 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1999,7 +1999,7 @@ compute_partial_view(struct drm_i915_gem_object *obj, */ int i915_gem_fault(struct vm_fault *vmf) { -#define MIN_CHUNK_PAGES ((1 << 20) >> PAGE_SHIFT) /* 1 MiB */ +#define MIN_CHUNK_PAGES (SZ_1M >> PAGE_SHIFT) struct vm_area_struct *area = vmf->vma; struct drm_i915_gem_object *obj = to_intel_bo(area->vm_private_data); struct drm_device *dev = obj->base.dev; -- GitLab From 2956e970f0b5f760a7c595730bac81d2f5e6250c Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Date: Fri, 25 May 2018 09:26:40 +0100 Subject: [PATCH 0186/1506] drm/i915/trace: Describe engines as class:instance pairs Instead of using the engine->id, use uabi_class:instance pairs in trace- points including engine info. This will be more readable, more future proof and more stable for userspace consumption. v2: * Use u16 for class and instance. (Chris Wilson) Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Cc: Chris Wilson <chris@chris-wilson.co.uk> Cc: svetlana.kukanova@intel.com Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180525082642.18246-1-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/i915_trace.h | 107 ++++++++++++++++++------------ 1 file changed, 65 insertions(+), 42 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h index 5d4f78765083e..7acea4052798c 100644 --- a/drivers/gpu/drm/i915/i915_trace.h +++ b/drivers/gpu/drm/i915/i915_trace.h @@ -591,21 +591,26 @@ TRACE_EVENT(i915_gem_ring_sync_to, TP_STRUCT__entry( __field(u32, dev) - __field(u32, sync_from) - __field(u32, sync_to) + __field(u32, from_class) + __field(u32, from_instance) + __field(u32, to_class) + __field(u32, to_instance) __field(u32, seqno) ), TP_fast_assign( __entry->dev = from->i915->drm.primary->index; - __entry->sync_from = from->engine->id; - __entry->sync_to = to->engine->id; + __entry->from_class = from->engine->uabi_class; + __entry->from_instance = from->engine->instance; + __entry->to_class = to->engine->uabi_class; + __entry->to_instance = to->engine->instance; __entry->seqno = from->global_seqno; ), - TP_printk("dev=%u, sync-from=%u, sync-to=%u, seqno=%u", + TP_printk("dev=%u, sync-from=%u:%u, sync-to=%u:%u, seqno=%u", __entry->dev, - __entry->sync_from, __entry->sync_to, + __entry->from_class, __entry->from_instance, + __entry->to_class, __entry->to_instance, __entry->seqno) ); @@ -616,7 +621,8 @@ TRACE_EVENT(i915_request_queue, TP_STRUCT__entry( __field(u32, dev) __field(u32, hw_id) - __field(u32, ring) + __field(u16, class) + __field(u16, instance) __field(u32, ctx) __field(u32, seqno) __field(u32, flags) @@ -625,15 +631,17 @@ TRACE_EVENT(i915_request_queue, TP_fast_assign( __entry->dev = rq->i915->drm.primary->index; __entry->hw_id = rq->gem_context->hw_id; - __entry->ring = rq->engine->id; + __entry->class = rq->engine->uabi_class; + __entry->instance = rq->engine->instance; __entry->ctx = rq->fence.context; __entry->seqno = rq->fence.seqno; __entry->flags = flags; ), - TP_printk("dev=%u, hw_id=%u, ring=%u, ctx=%u, seqno=%u, flags=0x%x", - __entry->dev, __entry->hw_id, __entry->ring, __entry->ctx, - __entry->seqno, __entry->flags) + TP_printk("dev=%u, hw_id=%u, engine=%u:%u, ctx=%u, seqno=%u, flags=0x%x", + __entry->dev, __entry->hw_id, __entry->class, + __entry->instance, __entry->ctx, __entry->seqno, + __entry->flags) ); DECLARE_EVENT_CLASS(i915_request, @@ -643,7 +651,8 @@ DECLARE_EVENT_CLASS(i915_request, TP_STRUCT__entry( __field(u32, dev) __field(u32, hw_id) - __field(u32, ring) + __field(u16, class) + __field(u16, instance) __field(u32, ctx) __field(u32, seqno) __field(u32, global) @@ -652,15 +661,17 @@ DECLARE_EVENT_CLASS(i915_request, TP_fast_assign( __entry->dev = rq->i915->drm.primary->index; __entry->hw_id = rq->gem_context->hw_id; - __entry->ring = rq->engine->id; + __entry->class = rq->engine->uabi_class; + __entry->instance = rq->engine->instance; __entry->ctx = rq->fence.context; __entry->seqno = rq->fence.seqno; __entry->global = rq->global_seqno; ), - TP_printk("dev=%u, hw_id=%u, ring=%u, ctx=%u, seqno=%u, global=%u", - __entry->dev, __entry->hw_id, __entry->ring, __entry->ctx, - __entry->seqno, __entry->global) + TP_printk("dev=%u, hw_id=%u, engine=%u:%u, ctx=%u, seqno=%u, global=%u", + __entry->dev, __entry->hw_id, __entry->class, + __entry->instance, __entry->ctx, __entry->seqno, + __entry->global) ); DEFINE_EVENT(i915_request, i915_request_add, @@ -686,7 +697,8 @@ TRACE_EVENT(i915_request_in, TP_STRUCT__entry( __field(u32, dev) __field(u32, hw_id) - __field(u32, ring) + __field(u16, class) + __field(u16, instance) __field(u32, ctx) __field(u32, seqno) __field(u32, global_seqno) @@ -697,7 +709,8 @@ TRACE_EVENT(i915_request_in, TP_fast_assign( __entry->dev = rq->i915->drm.primary->index; __entry->hw_id = rq->gem_context->hw_id; - __entry->ring = rq->engine->id; + __entry->class = rq->engine->uabi_class; + __entry->instance = rq->engine->instance; __entry->ctx = rq->fence.context; __entry->seqno = rq->fence.seqno; __entry->global_seqno = rq->global_seqno; @@ -705,10 +718,10 @@ TRACE_EVENT(i915_request_in, __entry->port = port; ), - TP_printk("dev=%u, hw_id=%u, ring=%u, ctx=%u, seqno=%u, prio=%u, global=%u, port=%u", - __entry->dev, __entry->hw_id, __entry->ring, __entry->ctx, - __entry->seqno, __entry->prio, __entry->global_seqno, - __entry->port) + TP_printk("dev=%u, hw_id=%u, engine=%u:%u, ctx=%u, seqno=%u, prio=%u, global=%u, port=%u", + __entry->dev, __entry->hw_id, __entry->class, + __entry->instance, __entry->ctx, __entry->seqno, + __entry->prio, __entry->global_seqno, __entry->port) ); TRACE_EVENT(i915_request_out, @@ -718,7 +731,8 @@ TRACE_EVENT(i915_request_out, TP_STRUCT__entry( __field(u32, dev) __field(u32, hw_id) - __field(u32, ring) + __field(u16, class) + __field(u16, instance) __field(u32, ctx) __field(u32, seqno) __field(u32, global_seqno) @@ -728,16 +742,17 @@ TRACE_EVENT(i915_request_out, TP_fast_assign( __entry->dev = rq->i915->drm.primary->index; __entry->hw_id = rq->gem_context->hw_id; - __entry->ring = rq->engine->id; + __entry->class = rq->engine->uabi_class; + __entry->instance = rq->engine->instance; __entry->ctx = rq->fence.context; __entry->seqno = rq->fence.seqno; __entry->global_seqno = rq->global_seqno; __entry->completed = i915_request_completed(rq); ), - TP_printk("dev=%u, hw_id=%u, ring=%u, ctx=%u, seqno=%u, global=%u, completed?=%u", - __entry->dev, __entry->hw_id, __entry->ring, - __entry->ctx, __entry->seqno, + TP_printk("dev=%u, hw_id=%u, engine=%u:%u, ctx=%u, seqno=%u, global=%u, completed?=%u", + __entry->dev, __entry->hw_id, __entry->class, + __entry->instance, __entry->ctx, __entry->seqno, __entry->global_seqno, __entry->completed) ); @@ -771,21 +786,23 @@ TRACE_EVENT(intel_engine_notify, TP_STRUCT__entry( __field(u32, dev) - __field(u32, ring) + __field(u16, class) + __field(u16, instance) __field(u32, seqno) __field(bool, waiters) ), TP_fast_assign( __entry->dev = engine->i915->drm.primary->index; - __entry->ring = engine->id; + __entry->class = engine->uabi_class; + __entry->instance = engine->instance; __entry->seqno = intel_engine_get_seqno(engine); __entry->waiters = waiters; ), - TP_printk("dev=%u, ring=%u, seqno=%u, waiters=%u", - __entry->dev, __entry->ring, __entry->seqno, - __entry->waiters) + TP_printk("dev=%u, engine=%u:%u, seqno=%u, waiters=%u", + __entry->dev, __entry->class, __entry->instance, + __entry->seqno, __entry->waiters) ); DEFINE_EVENT(i915_request, i915_request_retire, @@ -800,7 +817,8 @@ TRACE_EVENT(i915_request_wait_begin, TP_STRUCT__entry( __field(u32, dev) __field(u32, hw_id) - __field(u32, ring) + __field(u16, class) + __field(u16, instance) __field(u32, ctx) __field(u32, seqno) __field(u32, global) @@ -816,17 +834,19 @@ TRACE_EVENT(i915_request_wait_begin, TP_fast_assign( __entry->dev = rq->i915->drm.primary->index; __entry->hw_id = rq->gem_context->hw_id; - __entry->ring = rq->engine->id; + __entry->class = rq->engine->uabi_class; + __entry->instance = rq->engine->instance; __entry->ctx = rq->fence.context; __entry->seqno = rq->fence.seqno; __entry->global = rq->global_seqno; __entry->flags = flags; ), - TP_printk("dev=%u, hw_id=%u, ring=%u, ctx=%u, seqno=%u, global=%u, blocking=%u, flags=0x%x", - __entry->dev, __entry->hw_id, __entry->ring, __entry->ctx, - __entry->seqno, __entry->global, - !!(__entry->flags & I915_WAIT_LOCKED), __entry->flags) + TP_printk("dev=%u, hw_id=%u, engine=%u:%u, ctx=%u, seqno=%u, global=%u, blocking=%u, flags=0x%x", + __entry->dev, __entry->hw_id, __entry->class, + __entry->instance, __entry->ctx, __entry->seqno, + __entry->global, !!(__entry->flags & I915_WAIT_LOCKED), + __entry->flags) ); DEFINE_EVENT(i915_request, i915_request_wait_end, @@ -966,21 +986,24 @@ TRACE_EVENT(switch_mm, TP_ARGS(engine, to), TP_STRUCT__entry( - __field(u32, ring) + __field(u16, class) + __field(u16, instance) __field(struct i915_gem_context *, to) __field(struct i915_address_space *, vm) __field(u32, dev) ), TP_fast_assign( - __entry->ring = engine->id; + __entry->class = engine->uabi_class; + __entry->instance = engine->instance; __entry->to = to; __entry->vm = to->ppgtt? &to->ppgtt->base : NULL; __entry->dev = engine->i915->drm.primary->index; ), - TP_printk("dev=%u, ring=%u, ctx=%p, ctx_vm=%p", - __entry->dev, __entry->ring, __entry->to, __entry->vm) + TP_printk("dev=%u, engine=%u:%u, ctx=%p, ctx_vm=%p", + __entry->dev, __entry->class, __entry->instance, __entry->to, + __entry->vm) ); #endif /* _I915_TRACE_H_ */ -- GitLab From f24e74a7b73953b0b0a7afcddfa26c298b20c7c8 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Date: Fri, 25 May 2018 09:26:41 +0100 Subject: [PATCH 0187/1506] drm/i915/trace: Remove engine out of the context sandwich In the string tracepoint representation we ended up with the engine sandwiched between context hardware id and context fence id. Move the two pieces of context data together for redability. Binary records are left as is, that is both fields remaing under the existing name and ordering. v2: * Do not consolidate the printk format, just reorder. (Lionel) Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Cc: Lionel Landwerlin <lionel.g.landwerlin@intel.com> Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180525082642.18246-2-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/i915_trace.h | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h index 7acea4052798c..bac582ed3a0b5 100644 --- a/drivers/gpu/drm/i915/i915_trace.h +++ b/drivers/gpu/drm/i915/i915_trace.h @@ -638,9 +638,9 @@ TRACE_EVENT(i915_request_queue, __entry->flags = flags; ), - TP_printk("dev=%u, hw_id=%u, engine=%u:%u, ctx=%u, seqno=%u, flags=0x%x", - __entry->dev, __entry->hw_id, __entry->class, - __entry->instance, __entry->ctx, __entry->seqno, + TP_printk("dev=%u, engine=%u:%u, hw_id=%u, ctx=%u, seqno=%u, flags=0x%x", + __entry->dev, __entry->class, __entry->instance, + __entry->hw_id, __entry->ctx, __entry->seqno, __entry->flags) ); @@ -668,9 +668,9 @@ DECLARE_EVENT_CLASS(i915_request, __entry->global = rq->global_seqno; ), - TP_printk("dev=%u, hw_id=%u, engine=%u:%u, ctx=%u, seqno=%u, global=%u", - __entry->dev, __entry->hw_id, __entry->class, - __entry->instance, __entry->ctx, __entry->seqno, + TP_printk("dev=%u, engine=%u:%u, hw_id=%u, ctx=%u, seqno=%u, global=%u", + __entry->dev, __entry->class, __entry->instance, + __entry->hw_id, __entry->ctx, __entry->seqno, __entry->global) ); @@ -718,9 +718,9 @@ TRACE_EVENT(i915_request_in, __entry->port = port; ), - TP_printk("dev=%u, hw_id=%u, engine=%u:%u, ctx=%u, seqno=%u, prio=%u, global=%u, port=%u", - __entry->dev, __entry->hw_id, __entry->class, - __entry->instance, __entry->ctx, __entry->seqno, + TP_printk("dev=%u, engine=%u:%u, hw_id=%u, ctx=%u, seqno=%u, prio=%u, global=%u, port=%u", + __entry->dev, __entry->class, __entry->instance, + __entry->hw_id, __entry->ctx, __entry->seqno, __entry->prio, __entry->global_seqno, __entry->port) ); @@ -750,9 +750,9 @@ TRACE_EVENT(i915_request_out, __entry->completed = i915_request_completed(rq); ), - TP_printk("dev=%u, hw_id=%u, engine=%u:%u, ctx=%u, seqno=%u, global=%u, completed?=%u", - __entry->dev, __entry->hw_id, __entry->class, - __entry->instance, __entry->ctx, __entry->seqno, + TP_printk("dev=%u, engine=%u:%u, hw_id=%u, ctx=%u, seqno=%u, global=%u, completed?=%u", + __entry->dev, __entry->class, __entry->instance, + __entry->hw_id, __entry->ctx, __entry->seqno, __entry->global_seqno, __entry->completed) ); @@ -842,9 +842,9 @@ TRACE_EVENT(i915_request_wait_begin, __entry->flags = flags; ), - TP_printk("dev=%u, hw_id=%u, engine=%u:%u, ctx=%u, seqno=%u, global=%u, blocking=%u, flags=0x%x", - __entry->dev, __entry->hw_id, __entry->class, - __entry->instance, __entry->ctx, __entry->seqno, + TP_printk("dev=%u, engine=%u:%u, hw_id=%u, ctx=%u, seqno=%u, global=%u, blocking=%u, flags=0x%x", + __entry->dev, __entry->class, __entry->instance, + __entry->hw_id, __entry->ctx, __entry->seqno, __entry->global, !!(__entry->flags & I915_WAIT_LOCKED), __entry->flags) ); -- GitLab From 57d7116c472cd32ab167f208e1dec100596ce949 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Date: Tue, 5 Jun 2018 14:41:24 +0100 Subject: [PATCH 0188/1506] drm/i915/trace: Context field needs to be 64-bit wide Underlaying field is u64 so the tracepoint needs to be as well. v2: * Re-order binary packet for 64-bit alignment. (Chris Wilson) Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Suggested-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20180605134124.25672-1-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/i915_trace.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h index bac582ed3a0b5..3d5716d86e279 100644 --- a/drivers/gpu/drm/i915/i915_trace.h +++ b/drivers/gpu/drm/i915/i915_trace.h @@ -621,9 +621,9 @@ TRACE_EVENT(i915_request_queue, TP_STRUCT__entry( __field(u32, dev) __field(u32, hw_id) + __field(u64, ctx) __field(u16, class) __field(u16, instance) - __field(u32, ctx) __field(u32, seqno) __field(u32, flags) ), @@ -638,7 +638,7 @@ TRACE_EVENT(i915_request_queue, __entry->flags = flags; ), - TP_printk("dev=%u, engine=%u:%u, hw_id=%u, ctx=%u, seqno=%u, flags=0x%x", + TP_printk("dev=%u, engine=%u:%u, hw_id=%u, ctx=%llu, seqno=%u, flags=0x%x", __entry->dev, __entry->class, __entry->instance, __entry->hw_id, __entry->ctx, __entry->seqno, __entry->flags) @@ -651,9 +651,9 @@ DECLARE_EVENT_CLASS(i915_request, TP_STRUCT__entry( __field(u32, dev) __field(u32, hw_id) + __field(u64, ctx) __field(u16, class) __field(u16, instance) - __field(u32, ctx) __field(u32, seqno) __field(u32, global) ), @@ -668,7 +668,7 @@ DECLARE_EVENT_CLASS(i915_request, __entry->global = rq->global_seqno; ), - TP_printk("dev=%u, engine=%u:%u, hw_id=%u, ctx=%u, seqno=%u, global=%u", + TP_printk("dev=%u, engine=%u:%u, hw_id=%u, ctx=%llu, seqno=%u, global=%u", __entry->dev, __entry->class, __entry->instance, __entry->hw_id, __entry->ctx, __entry->seqno, __entry->global) @@ -697,9 +697,9 @@ TRACE_EVENT(i915_request_in, TP_STRUCT__entry( __field(u32, dev) __field(u32, hw_id) + __field(u64, ctx) __field(u16, class) __field(u16, instance) - __field(u32, ctx) __field(u32, seqno) __field(u32, global_seqno) __field(u32, port) @@ -718,7 +718,7 @@ TRACE_EVENT(i915_request_in, __entry->port = port; ), - TP_printk("dev=%u, engine=%u:%u, hw_id=%u, ctx=%u, seqno=%u, prio=%u, global=%u, port=%u", + TP_printk("dev=%u, engine=%u:%u, hw_id=%u, ctx=%llu, seqno=%u, prio=%u, global=%u, port=%u", __entry->dev, __entry->class, __entry->instance, __entry->hw_id, __entry->ctx, __entry->seqno, __entry->prio, __entry->global_seqno, __entry->port) @@ -731,9 +731,9 @@ TRACE_EVENT(i915_request_out, TP_STRUCT__entry( __field(u32, dev) __field(u32, hw_id) + __field(u64, ctx) __field(u16, class) __field(u16, instance) - __field(u32, ctx) __field(u32, seqno) __field(u32, global_seqno) __field(u32, completed) @@ -750,7 +750,7 @@ TRACE_EVENT(i915_request_out, __entry->completed = i915_request_completed(rq); ), - TP_printk("dev=%u, engine=%u:%u, hw_id=%u, ctx=%u, seqno=%u, global=%u, completed?=%u", + TP_printk("dev=%u, engine=%u:%u, hw_id=%u, ctx=%llu, seqno=%u, global=%u, completed?=%u", __entry->dev, __entry->class, __entry->instance, __entry->hw_id, __entry->ctx, __entry->seqno, __entry->global_seqno, __entry->completed) @@ -817,9 +817,9 @@ TRACE_EVENT(i915_request_wait_begin, TP_STRUCT__entry( __field(u32, dev) __field(u32, hw_id) + __field(u64, ctx) __field(u16, class) __field(u16, instance) - __field(u32, ctx) __field(u32, seqno) __field(u32, global) __field(unsigned int, flags) @@ -842,7 +842,7 @@ TRACE_EVENT(i915_request_wait_begin, __entry->flags = flags; ), - TP_printk("dev=%u, engine=%u:%u, hw_id=%u, ctx=%u, seqno=%u, global=%u, blocking=%u, flags=0x%x", + TP_printk("dev=%u, engine=%u:%u, hw_id=%u, ctx=%llu, seqno=%u, global=%u, blocking=%u, flags=0x%x", __entry->dev, __entry->class, __entry->instance, __entry->hw_id, __entry->ctx, __entry->seqno, __entry->global, !!(__entry->flags & I915_WAIT_LOCKED), -- GitLab From 9f473ecfe7a8520de359ed20bf95a1628e85e650 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Date: Tue, 5 Jun 2018 15:02:53 +0100 Subject: [PATCH 0189/1506] drm/i915/pmu: Do not assume fixed hrtimer period As Chris has discovered on his Ivybridge, and later automated test runs have confirmed, on most of our platforms hrtimer faced with heavy GPU load can occasionally become sufficiently imprecise to affect PMU sampling calculations. This means we cannot assume sampling frequency is what we asked for, but we need to measure the interval ourselves. This patch is similar to Chris' original proposal for per-engine counters, but instead of introducing a new set to work around the problem with frequency sampling, it swaps around the way internal frequency accounting is done. Instead of accumulating current frequency and dividing by sampling frequency on readout, it accumulates frequency scaled by each period. v2: * Typo in commit message, comment on period calculation and USEC_PER_SEC. (Chris Wilson) Testcase: igt/perf_pmu/*busy* # snb, ivb, hsw Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Suggested-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20180605140253.3541-1-tvrtko.ursulin@linux.intel.com --- drivers/gpu/drm/i915/i915_pmu.c | 67 +++++++++++++++++++++++---------- drivers/gpu/drm/i915/i915_pmu.h | 8 ++++ 2 files changed, 55 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c index dc87797db5005..c39541ed22194 100644 --- a/drivers/gpu/drm/i915/i915_pmu.c +++ b/drivers/gpu/drm/i915/i915_pmu.c @@ -127,6 +127,7 @@ static void __i915_pmu_maybe_start_timer(struct drm_i915_private *i915) { if (!i915->pmu.timer_enabled && pmu_needs_timer(i915, true)) { i915->pmu.timer_enabled = true; + i915->pmu.timer_last = ktime_get(); hrtimer_start_range_ns(&i915->pmu.timer, ns_to_ktime(PERIOD), 0, HRTIMER_MODE_REL_PINNED); @@ -155,12 +156,13 @@ static bool grab_forcewake(struct drm_i915_private *i915, bool fw) } static void -update_sample(struct i915_pmu_sample *sample, u32 unit, u32 val) +add_sample(struct i915_pmu_sample *sample, u32 val) { - sample->cur += mul_u32_u32(val, unit); + sample->cur += val; } -static void engines_sample(struct drm_i915_private *dev_priv) +static void +engines_sample(struct drm_i915_private *dev_priv, unsigned int period_ns) { struct intel_engine_cs *engine; enum intel_engine_id id; @@ -182,8 +184,9 @@ static void engines_sample(struct drm_i915_private *dev_priv) val = !i915_seqno_passed(current_seqno, last_seqno); - update_sample(&engine->pmu.sample[I915_SAMPLE_BUSY], - PERIOD, val); + if (val) + add_sample(&engine->pmu.sample[I915_SAMPLE_BUSY], + period_ns); if (val && (engine->pmu.enable & (BIT(I915_SAMPLE_WAIT) | BIT(I915_SAMPLE_SEMA)))) { @@ -194,11 +197,13 @@ static void engines_sample(struct drm_i915_private *dev_priv) val = 0; } - update_sample(&engine->pmu.sample[I915_SAMPLE_WAIT], - PERIOD, !!(val & RING_WAIT)); + if (val & RING_WAIT) + add_sample(&engine->pmu.sample[I915_SAMPLE_WAIT], + period_ns); - update_sample(&engine->pmu.sample[I915_SAMPLE_SEMA], - PERIOD, !!(val & RING_WAIT_SEMAPHORE)); + if (val & RING_WAIT_SEMAPHORE) + add_sample(&engine->pmu.sample[I915_SAMPLE_SEMA], + period_ns); } if (fw) @@ -207,7 +212,14 @@ static void engines_sample(struct drm_i915_private *dev_priv) intel_runtime_pm_put(dev_priv); } -static void frequency_sample(struct drm_i915_private *dev_priv) +static void +add_sample_mult(struct i915_pmu_sample *sample, u32 val, u32 mul) +{ + sample->cur += mul_u32_u32(val, mul); +} + +static void +frequency_sample(struct drm_i915_private *dev_priv, unsigned int period_ns) { if (dev_priv->pmu.enable & config_enabled_mask(I915_PMU_ACTUAL_FREQUENCY)) { @@ -221,15 +233,17 @@ static void frequency_sample(struct drm_i915_private *dev_priv) intel_runtime_pm_put(dev_priv); } - update_sample(&dev_priv->pmu.sample[__I915_SAMPLE_FREQ_ACT], - 1, intel_gpu_freq(dev_priv, val)); + add_sample_mult(&dev_priv->pmu.sample[__I915_SAMPLE_FREQ_ACT], + intel_gpu_freq(dev_priv, val), + period_ns / 1000); } if (dev_priv->pmu.enable & config_enabled_mask(I915_PMU_REQUESTED_FREQUENCY)) { - update_sample(&dev_priv->pmu.sample[__I915_SAMPLE_FREQ_REQ], 1, - intel_gpu_freq(dev_priv, - dev_priv->gt_pm.rps.cur_freq)); + add_sample_mult(&dev_priv->pmu.sample[__I915_SAMPLE_FREQ_REQ], + intel_gpu_freq(dev_priv, + dev_priv->gt_pm.rps.cur_freq), + period_ns / 1000); } } @@ -237,14 +251,27 @@ static enum hrtimer_restart i915_sample(struct hrtimer *hrtimer) { struct drm_i915_private *i915 = container_of(hrtimer, struct drm_i915_private, pmu.timer); + unsigned int period_ns; + ktime_t now; if (!READ_ONCE(i915->pmu.timer_enabled)) return HRTIMER_NORESTART; - engines_sample(i915); - frequency_sample(i915); + now = ktime_get(); + period_ns = ktime_to_ns(ktime_sub(now, i915->pmu.timer_last)); + i915->pmu.timer_last = now; + + /* + * Strictly speaking the passed in period may not be 100% accurate for + * all internal calculation, since some amount of time can be spent on + * grabbing the forcewake. However the potential error from timer call- + * back delay greatly dominates this so we keep it simple. + */ + engines_sample(i915, period_ns); + frequency_sample(i915, period_ns); + + hrtimer_forward(hrtimer, now, ns_to_ktime(PERIOD)); - hrtimer_forward_now(hrtimer, ns_to_ktime(PERIOD)); return HRTIMER_RESTART; } @@ -519,12 +546,12 @@ static u64 __i915_pmu_event_read(struct perf_event *event) case I915_PMU_ACTUAL_FREQUENCY: val = div_u64(i915->pmu.sample[__I915_SAMPLE_FREQ_ACT].cur, - FREQUENCY); + USEC_PER_SEC /* to MHz */); break; case I915_PMU_REQUESTED_FREQUENCY: val = div_u64(i915->pmu.sample[__I915_SAMPLE_FREQ_REQ].cur, - FREQUENCY); + USEC_PER_SEC /* to MHz */); break; case I915_PMU_INTERRUPTS: val = count_interrupts(i915); diff --git a/drivers/gpu/drm/i915/i915_pmu.h b/drivers/gpu/drm/i915/i915_pmu.h index 2ba735299f7c5..7f164ca3db129 100644 --- a/drivers/gpu/drm/i915/i915_pmu.h +++ b/drivers/gpu/drm/i915/i915_pmu.h @@ -65,6 +65,14 @@ struct i915_pmu { * event types. */ u64 enable; + + /** + * @timer_last: + * + * Timestmap of the previous timer invocation. + */ + ktime_t timer_last; + /** * @enable_count: Reference counts for the enabled events. * -- GitLab From 70be8b3dab43497718a2260f1daf47d378815d90 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko <michal.wajdeczko@intel.com> Date: Tue, 5 Jun 2018 12:05:47 +0000 Subject: [PATCH 0190/1506] drm/i915/guc: Don't leak stage descriptor pool on init failure In case of failure during GuC clients creation, we forget to cleanup earlier pool allocation. Use proper teardown to fix that. Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com> Cc: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com> Cc: Chris Wilson <chris@chris-wilson.co.uk> Cc: Michal Winiarski <michal.winiarski@intel.com> Reviewed-by: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20180605120547.16468-1-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/intel_guc_submission.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_guc_submission.c b/drivers/gpu/drm/i915/intel_guc_submission.c index 133367a178633..23e9f2023bc56 100644 --- a/drivers/gpu/drm/i915/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/intel_guc_submission.c @@ -1157,7 +1157,7 @@ int intel_guc_submission_init(struct intel_guc *guc) WARN_ON(!guc_verify_doorbells(guc)); ret = guc_clients_create(guc); if (ret) - return ret; + goto err_pool; for_each_engine(engine, dev_priv, id) { guc->preempt_work[id].engine = engine; @@ -1166,6 +1166,9 @@ int intel_guc_submission_init(struct intel_guc *guc) return 0; +err_pool: + guc_stage_desc_pool_destroy(guc); + return ret; } void intel_guc_submission_fini(struct intel_guc *guc) -- GitLab From cd68e04cf56a38029940a33cbc834b4ab15b2bdb Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Tue, 5 Jun 2018 17:06:23 +0100 Subject: [PATCH 0191/1506] drm/i915/error: Fixup inactive/active counting The inactive counter was over the active list, and vice versa. Fortuitously this should not cause a problem in practice as they shared the same array and clamped the number of entries they would write. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: Matthew Auld <matthew.william.auld@gmail.com> Reviewed-by: Matthew Auld <matthew.william.auld@gmail.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180605160623.30163-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gpu_error.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 47721437a4c58..6702776303bfd 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -1570,11 +1570,11 @@ static void capture_pinned_buffers(struct i915_gpu_state *error) int count_inactive, count_active; count_inactive = 0; - list_for_each_entry(vma, &vm->active_list, vm_link) + list_for_each_entry(vma, &vm->inactive_list, vm_link) count_inactive++; count_active = 0; - list_for_each_entry(vma, &vm->inactive_list, vm_link) + list_for_each_entry(vma, &vm->active_list, vm_link) count_active++; bo = NULL; -- GitLab From 82ad6443a55ea274ab2f0e24ada71f0529f3238b Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Tue, 5 Jun 2018 16:37:58 +0100 Subject: [PATCH 0192/1506] drm/i915/gtt: Rename i915_hw_ppgtt base member In the near future, I want to subclass gen6_hw_ppgtt as it contains a few specialised members and I wish to add more. To avoid the ugliness of using ppgtt->base.base, rename the i915_hw_ppgtt base member (i915_address_space) as vm, which is our common shorthand for an i915_address_space local. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: Matthew Auld <matthew.william.auld@gmail.com> Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180605153758.18422-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/gvt/aperture_gm.c | 2 +- drivers/gpu/drm/i915/gvt/gvt.h | 4 +- drivers/gpu/drm/i915/i915_debugfs.c | 4 +- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_gem.c | 30 +- drivers/gpu/drm/i915/i915_gem_context.c | 10 +- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 16 +- drivers/gpu/drm/i915/i915_gem_gtt.c | 333 +++++++++--------- drivers/gpu/drm/i915/i915_gem_gtt.h | 8 +- drivers/gpu/drm/i915/i915_gem_render_state.c | 2 +- drivers/gpu/drm/i915/i915_gem_shrinker.c | 2 +- drivers/gpu/drm/i915/i915_gem_stolen.c | 6 +- drivers/gpu/drm/i915/i915_gpu_error.c | 9 +- drivers/gpu/drm/i915/i915_trace.h | 4 +- drivers/gpu/drm/i915/i915_vgpu.c | 8 +- drivers/gpu/drm/i915/i915_vma.c | 2 +- drivers/gpu/drm/i915/intel_engine_cs.c | 4 +- drivers/gpu/drm/i915/intel_guc.c | 2 +- drivers/gpu/drm/i915/intel_guc_submission.c | 2 +- drivers/gpu/drm/i915/intel_lrc.c | 10 +- drivers/gpu/drm/i915/intel_ringbuffer.c | 4 +- drivers/gpu/drm/i915/selftests/huge_pages.c | 50 +-- .../gpu/drm/i915/selftests/i915_gem_context.c | 6 +- .../gpu/drm/i915/selftests/i915_gem_evict.c | 34 +- drivers/gpu/drm/i915/selftests/i915_gem_gtt.c | 110 +++--- .../gpu/drm/i915/selftests/i915_gem_object.c | 6 +- drivers/gpu/drm/i915/selftests/i915_request.c | 5 +- drivers/gpu/drm/i915/selftests/i915_vma.c | 31 +- .../gpu/drm/i915/selftests/intel_hangcheck.c | 4 +- drivers/gpu/drm/i915/selftests/intel_lrc.c | 2 +- .../drm/i915/selftests/intel_workarounds.c | 2 +- drivers/gpu/drm/i915/selftests/mock_gtt.c | 66 ++-- 32 files changed, 390 insertions(+), 390 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/aperture_gm.c b/drivers/gpu/drm/i915/gvt/aperture_gm.c index 7c9ec4f4f36c7..380eeb2a0e83c 100644 --- a/drivers/gpu/drm/i915/gvt/aperture_gm.c +++ b/drivers/gpu/drm/i915/gvt/aperture_gm.c @@ -61,7 +61,7 @@ static int alloc_gm(struct intel_vgpu *vgpu, bool high_gm) } mutex_lock(&dev_priv->drm.struct_mutex); - ret = i915_gem_gtt_insert(&dev_priv->ggtt.base, node, + ret = i915_gem_gtt_insert(&dev_priv->ggtt.vm, node, size, I915_GTT_PAGE_SIZE, I915_COLOR_UNEVICTABLE, start, end, flags); diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h index 05d15a095310d..2ff0d40281a9a 100644 --- a/drivers/gpu/drm/i915/gvt/gvt.h +++ b/drivers/gpu/drm/i915/gvt/gvt.h @@ -361,9 +361,9 @@ int intel_gvt_load_firmware(struct intel_gvt *gvt); #define gvt_aperture_sz(gvt) (gvt->dev_priv->ggtt.mappable_end) #define gvt_aperture_pa_base(gvt) (gvt->dev_priv->ggtt.gmadr.start) -#define gvt_ggtt_gm_sz(gvt) (gvt->dev_priv->ggtt.base.total) +#define gvt_ggtt_gm_sz(gvt) (gvt->dev_priv->ggtt.vm.total) #define gvt_ggtt_sz(gvt) \ - ((gvt->dev_priv->ggtt.base.total >> PAGE_SHIFT) << 3) + ((gvt->dev_priv->ggtt.vm.total >> PAGE_SHIFT) << 3) #define gvt_hidden_sz(gvt) (gvt_ggtt_gm_sz(gvt) - gvt_aperture_sz(gvt)) #define gvt_aperture_gmadr_base(gvt) (0) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 15e86d34a81ce..698af45e229ce 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -328,7 +328,7 @@ static int per_file_stats(int id, void *ptr, void *data) } else { struct i915_hw_ppgtt *ppgtt = i915_vm_to_ppgtt(vma->vm); - if (ppgtt->base.file != stats->file_priv) + if (ppgtt->vm.file != stats->file_priv) continue; } @@ -508,7 +508,7 @@ static int i915_gem_object_info(struct seq_file *m, void *data) dpy_count, dpy_size); seq_printf(m, "%llu [%pa] gtt total\n", - ggtt->base.total, &ggtt->mappable_end); + ggtt->vm.total, &ggtt->mappable_end); seq_printf(m, "Supported page sizes: %s\n", stringify_page_sizes(INTEL_INFO(dev_priv)->page_sizes, buf, sizeof(buf))); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 06ecac4c32534..a4bb30c32a527 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3213,7 +3213,7 @@ struct dma_buf *i915_gem_prime_export(struct drm_device *dev, static inline struct i915_hw_ppgtt * i915_vm_to_ppgtt(struct i915_address_space *vm) { - return container_of(vm, struct i915_hw_ppgtt, base); + return container_of(vm, struct i915_hw_ppgtt, vm); } /* i915_gem_fence_reg.c */ diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 23374f3dd79d3..86f1f9aaa1198 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -65,7 +65,7 @@ insert_mappable_node(struct i915_ggtt *ggtt, struct drm_mm_node *node, u32 size) { memset(node, 0, sizeof(*node)); - return drm_mm_insert_node_in_range(&ggtt->base.mm, node, + return drm_mm_insert_node_in_range(&ggtt->vm.mm, node, size, 0, I915_COLOR_UNEVICTABLE, 0, ggtt->mappable_end, DRM_MM_INSERT_LOW); @@ -249,17 +249,17 @@ i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data, struct i915_vma *vma; u64 pinned; - pinned = ggtt->base.reserved; + pinned = ggtt->vm.reserved; mutex_lock(&dev->struct_mutex); - list_for_each_entry(vma, &ggtt->base.active_list, vm_link) + list_for_each_entry(vma, &ggtt->vm.active_list, vm_link) if (i915_vma_is_pinned(vma)) pinned += vma->node.size; - list_for_each_entry(vma, &ggtt->base.inactive_list, vm_link) + list_for_each_entry(vma, &ggtt->vm.inactive_list, vm_link) if (i915_vma_is_pinned(vma)) pinned += vma->node.size; mutex_unlock(&dev->struct_mutex); - args->aper_size = ggtt->base.total; + args->aper_size = ggtt->vm.total; args->aper_available_size = args->aper_size - pinned; return 0; @@ -1223,9 +1223,9 @@ i915_gem_gtt_pread(struct drm_i915_gem_object *obj, page_length = remain < page_length ? remain : page_length; if (node.allocated) { wmb(); - ggtt->base.insert_page(&ggtt->base, - i915_gem_object_get_dma_address(obj, offset >> PAGE_SHIFT), - node.start, I915_CACHE_NONE, 0); + ggtt->vm.insert_page(&ggtt->vm, + i915_gem_object_get_dma_address(obj, offset >> PAGE_SHIFT), + node.start, I915_CACHE_NONE, 0); wmb(); } else { page_base += offset & PAGE_MASK; @@ -1246,8 +1246,7 @@ i915_gem_gtt_pread(struct drm_i915_gem_object *obj, out_unpin: if (node.allocated) { wmb(); - ggtt->base.clear_range(&ggtt->base, - node.start, node.size); + ggtt->vm.clear_range(&ggtt->vm, node.start, node.size); remove_mappable_node(&node); } else { i915_vma_unpin(vma); @@ -1426,9 +1425,9 @@ i915_gem_gtt_pwrite_fast(struct drm_i915_gem_object *obj, page_length = remain < page_length ? remain : page_length; if (node.allocated) { wmb(); /* flush the write before we modify the GGTT */ - ggtt->base.insert_page(&ggtt->base, - i915_gem_object_get_dma_address(obj, offset >> PAGE_SHIFT), - node.start, I915_CACHE_NONE, 0); + ggtt->vm.insert_page(&ggtt->vm, + i915_gem_object_get_dma_address(obj, offset >> PAGE_SHIFT), + node.start, I915_CACHE_NONE, 0); wmb(); /* flush modifications to the GGTT (insert_page) */ } else { page_base += offset & PAGE_MASK; @@ -1455,8 +1454,7 @@ i915_gem_gtt_pwrite_fast(struct drm_i915_gem_object *obj, out_unpin: if (node.allocated) { wmb(); - ggtt->base.clear_range(&ggtt->base, - node.start, node.size); + ggtt->vm.clear_range(&ggtt->vm, node.start, node.size); remove_mappable_node(&node); } else { i915_vma_unpin(vma); @@ -4374,7 +4372,7 @@ i915_gem_object_ggtt_pin(struct drm_i915_gem_object *obj, u64 flags) { struct drm_i915_private *dev_priv = to_i915(obj->base.dev); - struct i915_address_space *vm = &dev_priv->ggtt.base; + struct i915_address_space *vm = &dev_priv->ggtt.vm; struct i915_vma *vma; int ret; diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 38c6e9e4e91bf..b2c7ac1b074d4 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -197,7 +197,7 @@ static void context_close(struct i915_gem_context *ctx) */ lut_close(ctx); if (ctx->ppgtt) - i915_ppgtt_close(&ctx->ppgtt->base); + i915_ppgtt_close(&ctx->ppgtt->vm); ctx->file_priv = ERR_PTR(-EBADF); i915_gem_context_put(ctx); @@ -249,7 +249,7 @@ static u32 default_desc_template(const struct drm_i915_private *i915, desc = GEN8_CTX_VALID | GEN8_CTX_PRIVILEGE; address_mode = INTEL_LEGACY_32B_CONTEXT; - if (ppgtt && i915_vm_is_48bit(&ppgtt->base)) + if (ppgtt && i915_vm_is_48bit(&ppgtt->vm)) address_mode = INTEL_LEGACY_64B_CONTEXT; desc |= address_mode << GEN8_CTX_ADDRESSING_MODE_SHIFT; @@ -810,11 +810,11 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data, break; case I915_CONTEXT_PARAM_GTT_SIZE: if (ctx->ppgtt) - args->value = ctx->ppgtt->base.total; + args->value = ctx->ppgtt->vm.total; else if (to_i915(dev)->mm.aliasing_ppgtt) - args->value = to_i915(dev)->mm.aliasing_ppgtt->base.total; + args->value = to_i915(dev)->mm.aliasing_ppgtt->vm.total; else - args->value = to_i915(dev)->ggtt.base.total; + args->value = to_i915(dev)->ggtt.vm.total; break; case I915_CONTEXT_PARAM_NO_ERROR_CAPTURE: args->value = i915_gem_context_no_error_capture(ctx); diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index f627a8c47c58a..eefd449502e27 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -703,7 +703,7 @@ static int eb_select_context(struct i915_execbuffer *eb) return -ENOENT; eb->ctx = ctx; - eb->vm = ctx->ppgtt ? &ctx->ppgtt->base : &eb->i915->ggtt.base; + eb->vm = ctx->ppgtt ? &ctx->ppgtt->vm : &eb->i915->ggtt.vm; eb->context_flags = 0; if (ctx->flags & CONTEXT_NO_ZEROMAP) @@ -943,9 +943,9 @@ static void reloc_cache_reset(struct reloc_cache *cache) if (cache->node.allocated) { struct i915_ggtt *ggtt = cache_to_ggtt(cache); - ggtt->base.clear_range(&ggtt->base, - cache->node.start, - cache->node.size); + ggtt->vm.clear_range(&ggtt->vm, + cache->node.start, + cache->node.size); drm_mm_remove_node(&cache->node); } else { i915_vma_unpin((struct i915_vma *)cache->node.mm); @@ -1016,7 +1016,7 @@ static void *reloc_iomap(struct drm_i915_gem_object *obj, if (IS_ERR(vma)) { memset(&cache->node, 0, sizeof(cache->node)); err = drm_mm_insert_node_in_range - (&ggtt->base.mm, &cache->node, + (&ggtt->vm.mm, &cache->node, PAGE_SIZE, 0, I915_COLOR_UNEVICTABLE, 0, ggtt->mappable_end, DRM_MM_INSERT_LOW); @@ -1037,9 +1037,9 @@ static void *reloc_iomap(struct drm_i915_gem_object *obj, offset = cache->node.start; if (cache->node.allocated) { wmb(); - ggtt->base.insert_page(&ggtt->base, - i915_gem_object_get_dma_address(obj, page), - offset, I915_CACHE_NONE, 0); + ggtt->vm.insert_page(&ggtt->vm, + i915_gem_object_get_dma_address(obj, page), + offset, I915_CACHE_NONE, 0); } else { offset += page << PAGE_SHIFT; } diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 9302ee6e717d6..029a5f4fbd92b 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -780,7 +780,7 @@ static void gen8_initialize_pml4(struct i915_address_space *vm, */ static void mark_tlbs_dirty(struct i915_hw_ppgtt *ppgtt) { - ppgtt->pd_dirty_rings = INTEL_INFO(ppgtt->base.i915)->ring_mask; + ppgtt->pd_dirty_rings = INTEL_INFO(ppgtt->vm.i915)->ring_mask; } /* Removes entries from a single page table, releasing it if it's empty. @@ -973,7 +973,7 @@ gen8_ppgtt_insert_pte_entries(struct i915_hw_ppgtt *ppgtt, gen8_pte_t *vaddr; bool ret; - GEM_BUG_ON(idx->pdpe >= i915_pdpes_per_pdp(&ppgtt->base)); + GEM_BUG_ON(idx->pdpe >= i915_pdpes_per_pdp(&ppgtt->vm)); pd = pdp->page_directory[idx->pdpe]; vaddr = kmap_atomic_px(pd->page_table[idx->pde]); do { @@ -1004,7 +1004,7 @@ gen8_ppgtt_insert_pte_entries(struct i915_hw_ppgtt *ppgtt, break; } - GEM_BUG_ON(idx->pdpe >= i915_pdpes_per_pdp(&ppgtt->base)); + GEM_BUG_ON(idx->pdpe >= i915_pdpes_per_pdp(&ppgtt->vm)); pd = pdp->page_directory[idx->pdpe]; } @@ -1233,7 +1233,7 @@ static int gen8_init_scratch(struct i915_address_space *vm) static int gen8_ppgtt_notify_vgt(struct i915_hw_ppgtt *ppgtt, bool create) { - struct i915_address_space *vm = &ppgtt->base; + struct i915_address_space *vm = &ppgtt->vm; struct drm_i915_private *dev_priv = vm->i915; enum vgt_g2v_type msg; int i; @@ -1294,13 +1294,13 @@ static void gen8_ppgtt_cleanup_4lvl(struct i915_hw_ppgtt *ppgtt) int i; for (i = 0; i < GEN8_PML4ES_PER_PML4; i++) { - if (ppgtt->pml4.pdps[i] == ppgtt->base.scratch_pdp) + if (ppgtt->pml4.pdps[i] == ppgtt->vm.scratch_pdp) continue; - gen8_ppgtt_cleanup_3lvl(&ppgtt->base, ppgtt->pml4.pdps[i]); + gen8_ppgtt_cleanup_3lvl(&ppgtt->vm, ppgtt->pml4.pdps[i]); } - cleanup_px(&ppgtt->base, &ppgtt->pml4); + cleanup_px(&ppgtt->vm, &ppgtt->pml4); } static void gen8_ppgtt_cleanup(struct i915_address_space *vm) @@ -1314,7 +1314,7 @@ static void gen8_ppgtt_cleanup(struct i915_address_space *vm) if (use_4lvl(vm)) gen8_ppgtt_cleanup_4lvl(ppgtt); else - gen8_ppgtt_cleanup_3lvl(&ppgtt->base, &ppgtt->pdp); + gen8_ppgtt_cleanup_3lvl(&ppgtt->vm, &ppgtt->pdp); gen8_free_scratch(vm); } @@ -1450,7 +1450,7 @@ static void gen8_dump_pdp(struct i915_hw_ppgtt *ppgtt, gen8_pte_t scratch_pte, struct seq_file *m) { - struct i915_address_space *vm = &ppgtt->base; + struct i915_address_space *vm = &ppgtt->vm; struct i915_page_directory *pd; u32 pdpe; @@ -1460,7 +1460,7 @@ static void gen8_dump_pdp(struct i915_hw_ppgtt *ppgtt, u64 pd_start = start; u32 pde; - if (pdp->page_directory[pdpe] == ppgtt->base.scratch_pd) + if (pdp->page_directory[pdpe] == ppgtt->vm.scratch_pd) continue; seq_printf(m, "\tPDPE #%d\n", pdpe); @@ -1468,7 +1468,7 @@ static void gen8_dump_pdp(struct i915_hw_ppgtt *ppgtt, u32 pte; gen8_pte_t *pt_vaddr; - if (pd->page_table[pde] == ppgtt->base.scratch_pt) + if (pd->page_table[pde] == ppgtt->vm.scratch_pt) continue; pt_vaddr = kmap_atomic_px(pt); @@ -1501,10 +1501,10 @@ static void gen8_dump_pdp(struct i915_hw_ppgtt *ppgtt, static void gen8_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m) { - struct i915_address_space *vm = &ppgtt->base; + struct i915_address_space *vm = &ppgtt->vm; const gen8_pte_t scratch_pte = gen8_pte_encode(vm->scratch_page.daddr, I915_CACHE_LLC); - u64 start = 0, length = ppgtt->base.total; + u64 start = 0, length = ppgtt->vm.total; if (use_4lvl(vm)) { u64 pml4e; @@ -1512,7 +1512,7 @@ static void gen8_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m) struct i915_page_directory_pointer *pdp; gen8_for_each_pml4e(pdp, pml4, start, length, pml4e) { - if (pml4->pdps[pml4e] == ppgtt->base.scratch_pdp) + if (pml4->pdps[pml4e] == ppgtt->vm.scratch_pdp) continue; seq_printf(m, " PML4E #%llu\n", pml4e); @@ -1525,10 +1525,10 @@ static void gen8_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m) static int gen8_preallocate_top_level_pdp(struct i915_hw_ppgtt *ppgtt) { - struct i915_address_space *vm = &ppgtt->base; + struct i915_address_space *vm = &ppgtt->vm; struct i915_page_directory_pointer *pdp = &ppgtt->pdp; struct i915_page_directory *pd; - u64 start = 0, length = ppgtt->base.total; + u64 start = 0, length = ppgtt->vm.total; u64 from = start; unsigned int pdpe; @@ -1564,11 +1564,11 @@ static int gen8_preallocate_top_level_pdp(struct i915_hw_ppgtt *ppgtt) */ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt) { - struct i915_address_space *vm = &ppgtt->base; + struct i915_address_space *vm = &ppgtt->vm; struct drm_i915_private *dev_priv = vm->i915; int ret; - ppgtt->base.total = USES_FULL_48BIT_PPGTT(dev_priv) ? + ppgtt->vm.total = USES_FULL_48BIT_PPGTT(dev_priv) ? 1ULL << 48 : 1ULL << 32; @@ -1576,26 +1576,26 @@ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt) * And we are not sure about the latter so play safe for now. */ if (IS_CHERRYVIEW(dev_priv) || IS_BROXTON(dev_priv)) - ppgtt->base.pt_kmap_wc = true; + ppgtt->vm.pt_kmap_wc = true; - ret = gen8_init_scratch(&ppgtt->base); + ret = gen8_init_scratch(&ppgtt->vm); if (ret) { - ppgtt->base.total = 0; + ppgtt->vm.total = 0; return ret; } if (use_4lvl(vm)) { - ret = setup_px(&ppgtt->base, &ppgtt->pml4); + ret = setup_px(&ppgtt->vm, &ppgtt->pml4); if (ret) goto free_scratch; - gen8_initialize_pml4(&ppgtt->base, &ppgtt->pml4); + gen8_initialize_pml4(&ppgtt->vm, &ppgtt->pml4); - ppgtt->base.allocate_va_range = gen8_ppgtt_alloc_4lvl; - ppgtt->base.insert_entries = gen8_ppgtt_insert_4lvl; - ppgtt->base.clear_range = gen8_ppgtt_clear_4lvl; + ppgtt->vm.allocate_va_range = gen8_ppgtt_alloc_4lvl; + ppgtt->vm.insert_entries = gen8_ppgtt_insert_4lvl; + ppgtt->vm.clear_range = gen8_ppgtt_clear_4lvl; } else { - ret = __pdp_init(&ppgtt->base, &ppgtt->pdp); + ret = __pdp_init(&ppgtt->vm, &ppgtt->pdp); if (ret) goto free_scratch; @@ -1607,35 +1607,35 @@ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt) } } - ppgtt->base.allocate_va_range = gen8_ppgtt_alloc_3lvl; - ppgtt->base.insert_entries = gen8_ppgtt_insert_3lvl; - ppgtt->base.clear_range = gen8_ppgtt_clear_3lvl; + ppgtt->vm.allocate_va_range = gen8_ppgtt_alloc_3lvl; + ppgtt->vm.insert_entries = gen8_ppgtt_insert_3lvl; + ppgtt->vm.clear_range = gen8_ppgtt_clear_3lvl; } if (intel_vgpu_active(dev_priv)) gen8_ppgtt_notify_vgt(ppgtt, true); - ppgtt->base.cleanup = gen8_ppgtt_cleanup; - ppgtt->base.bind_vma = gen8_ppgtt_bind_vma; - ppgtt->base.unbind_vma = ppgtt_unbind_vma; - ppgtt->base.set_pages = ppgtt_set_pages; - ppgtt->base.clear_pages = clear_pages; + ppgtt->vm.cleanup = gen8_ppgtt_cleanup; + ppgtt->vm.bind_vma = gen8_ppgtt_bind_vma; + ppgtt->vm.unbind_vma = ppgtt_unbind_vma; + ppgtt->vm.set_pages = ppgtt_set_pages; + ppgtt->vm.clear_pages = clear_pages; ppgtt->debug_dump = gen8_dump_ppgtt; return 0; free_scratch: - gen8_free_scratch(&ppgtt->base); + gen8_free_scratch(&ppgtt->vm); return ret; } static void gen6_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m) { - struct i915_address_space *vm = &ppgtt->base; + struct i915_address_space *vm = &ppgtt->vm; struct i915_page_table *unused; gen6_pte_t scratch_pte; u32 pd_entry, pte, pde; - u32 start = 0, length = ppgtt->base.total; + u32 start = 0, length = ppgtt->vm.total; scratch_pte = vm->pte_encode(vm->scratch_page.daddr, I915_CACHE_LLC, 0); @@ -1972,8 +1972,8 @@ static void gen6_ppgtt_cleanup(struct i915_address_space *vm) static int gen6_ppgtt_allocate_page_directories(struct i915_hw_ppgtt *ppgtt) { - struct i915_address_space *vm = &ppgtt->base; - struct drm_i915_private *dev_priv = ppgtt->base.i915; + struct i915_address_space *vm = &ppgtt->vm; + struct drm_i915_private *dev_priv = ppgtt->vm.i915; struct i915_ggtt *ggtt = &dev_priv->ggtt; int ret; @@ -1981,16 +1981,16 @@ static int gen6_ppgtt_allocate_page_directories(struct i915_hw_ppgtt *ppgtt) * allocator works in address space sizes, so it's multiplied by page * size. We allocate at the top of the GTT to avoid fragmentation. */ - BUG_ON(!drm_mm_initialized(&ggtt->base.mm)); + BUG_ON(!drm_mm_initialized(&ggtt->vm.mm)); ret = gen6_init_scratch(vm); if (ret) return ret; - ret = i915_gem_gtt_insert(&ggtt->base, &ppgtt->node, + ret = i915_gem_gtt_insert(&ggtt->vm, &ppgtt->node, GEN6_PD_SIZE, GEN6_PD_ALIGN, I915_COLOR_UNEVICTABLE, - 0, ggtt->base.total, + 0, ggtt->vm.total, PIN_HIGH); if (ret) goto err_out; @@ -2023,16 +2023,16 @@ static void gen6_scratch_va_range(struct i915_hw_ppgtt *ppgtt, u32 pde; gen6_for_each_pde(unused, &ppgtt->pd, start, length, pde) - ppgtt->pd.page_table[pde] = ppgtt->base.scratch_pt; + ppgtt->pd.page_table[pde] = ppgtt->vm.scratch_pt; } static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) { - struct drm_i915_private *dev_priv = ppgtt->base.i915; + struct drm_i915_private *dev_priv = ppgtt->vm.i915; struct i915_ggtt *ggtt = &dev_priv->ggtt; int ret; - ppgtt->base.pte_encode = ggtt->base.pte_encode; + ppgtt->vm.pte_encode = ggtt->vm.pte_encode; if (intel_vgpu_active(dev_priv) || IS_GEN6(dev_priv)) ppgtt->switch_mm = gen6_mm_switch; else if (IS_HASWELL(dev_priv)) @@ -2046,24 +2046,24 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) if (ret) return ret; - ppgtt->base.total = I915_PDES * GEN6_PTES * PAGE_SIZE; + ppgtt->vm.total = I915_PDES * GEN6_PTES * PAGE_SIZE; - gen6_scratch_va_range(ppgtt, 0, ppgtt->base.total); - gen6_write_page_range(ppgtt, 0, ppgtt->base.total); + gen6_scratch_va_range(ppgtt, 0, ppgtt->vm.total); + gen6_write_page_range(ppgtt, 0, ppgtt->vm.total); - ret = gen6_alloc_va_range(&ppgtt->base, 0, ppgtt->base.total); + ret = gen6_alloc_va_range(&ppgtt->vm, 0, ppgtt->vm.total); if (ret) { - gen6_ppgtt_cleanup(&ppgtt->base); + gen6_ppgtt_cleanup(&ppgtt->vm); return ret; } - ppgtt->base.clear_range = gen6_ppgtt_clear_range; - ppgtt->base.insert_entries = gen6_ppgtt_insert_entries; - ppgtt->base.bind_vma = gen6_ppgtt_bind_vma; - ppgtt->base.unbind_vma = ppgtt_unbind_vma; - ppgtt->base.set_pages = ppgtt_set_pages; - ppgtt->base.clear_pages = clear_pages; - ppgtt->base.cleanup = gen6_ppgtt_cleanup; + ppgtt->vm.clear_range = gen6_ppgtt_clear_range; + ppgtt->vm.insert_entries = gen6_ppgtt_insert_entries; + ppgtt->vm.bind_vma = gen6_ppgtt_bind_vma; + ppgtt->vm.unbind_vma = ppgtt_unbind_vma; + ppgtt->vm.set_pages = ppgtt_set_pages; + ppgtt->vm.clear_pages = clear_pages; + ppgtt->vm.cleanup = gen6_ppgtt_cleanup; ppgtt->debug_dump = gen6_dump_ppgtt; DRM_DEBUG_DRIVER("Allocated pde space (%lldM) at GTT entry: %llx\n", @@ -2079,8 +2079,8 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) static int __hw_ppgtt_init(struct i915_hw_ppgtt *ppgtt, struct drm_i915_private *dev_priv) { - ppgtt->base.i915 = dev_priv; - ppgtt->base.dma = &dev_priv->drm.pdev->dev; + ppgtt->vm.i915 = dev_priv; + ppgtt->vm.dma = &dev_priv->drm.pdev->dev; if (INTEL_GEN(dev_priv) < 8) return gen6_ppgtt_init(ppgtt); @@ -2190,10 +2190,10 @@ i915_ppgtt_create(struct drm_i915_private *dev_priv, } kref_init(&ppgtt->ref); - i915_address_space_init(&ppgtt->base, dev_priv, name); - ppgtt->base.file = fpriv; + i915_address_space_init(&ppgtt->vm, dev_priv, name); + ppgtt->vm.file = fpriv; - trace_i915_ppgtt_create(&ppgtt->base); + trace_i915_ppgtt_create(&ppgtt->vm); return ppgtt; } @@ -2227,16 +2227,16 @@ void i915_ppgtt_release(struct kref *kref) struct i915_hw_ppgtt *ppgtt = container_of(kref, struct i915_hw_ppgtt, ref); - trace_i915_ppgtt_release(&ppgtt->base); + trace_i915_ppgtt_release(&ppgtt->vm); - ppgtt_destroy_vma(&ppgtt->base); + ppgtt_destroy_vma(&ppgtt->vm); - GEM_BUG_ON(!list_empty(&ppgtt->base.active_list)); - GEM_BUG_ON(!list_empty(&ppgtt->base.inactive_list)); - GEM_BUG_ON(!list_empty(&ppgtt->base.unbound_list)); + GEM_BUG_ON(!list_empty(&ppgtt->vm.active_list)); + GEM_BUG_ON(!list_empty(&ppgtt->vm.inactive_list)); + GEM_BUG_ON(!list_empty(&ppgtt->vm.unbound_list)); - ppgtt->base.cleanup(&ppgtt->base); - i915_address_space_fini(&ppgtt->base); + ppgtt->vm.cleanup(&ppgtt->vm); + i915_address_space_fini(&ppgtt->vm); kfree(ppgtt); } @@ -2332,7 +2332,7 @@ void i915_gem_suspend_gtt_mappings(struct drm_i915_private *dev_priv) i915_check_and_clear_faults(dev_priv); - ggtt->base.clear_range(&ggtt->base, 0, ggtt->base.total); + ggtt->vm.clear_range(&ggtt->vm, 0, ggtt->vm.total); i915_ggtt_invalidate(dev_priv); } @@ -2675,16 +2675,16 @@ static int aliasing_gtt_bind_vma(struct i915_vma *vma, struct i915_hw_ppgtt *appgtt = i915->mm.aliasing_ppgtt; if (!(vma->flags & I915_VMA_LOCAL_BIND) && - appgtt->base.allocate_va_range) { - ret = appgtt->base.allocate_va_range(&appgtt->base, - vma->node.start, - vma->size); + appgtt->vm.allocate_va_range) { + ret = appgtt->vm.allocate_va_range(&appgtt->vm, + vma->node.start, + vma->size); if (ret) return ret; } - appgtt->base.insert_entries(&appgtt->base, vma, cache_level, - pte_flags); + appgtt->vm.insert_entries(&appgtt->vm, vma, cache_level, + pte_flags); } if (flags & I915_VMA_GLOBAL_BIND) { @@ -2707,7 +2707,7 @@ static void aliasing_gtt_unbind_vma(struct i915_vma *vma) } if (vma->flags & I915_VMA_LOCAL_BIND) { - struct i915_address_space *vm = &i915->mm.aliasing_ppgtt->base; + struct i915_address_space *vm = &i915->mm.aliasing_ppgtt->vm; vm->clear_range(vm, vma->node.start, vma->size); } @@ -2774,30 +2774,30 @@ int i915_gem_init_aliasing_ppgtt(struct drm_i915_private *i915) if (IS_ERR(ppgtt)) return PTR_ERR(ppgtt); - if (WARN_ON(ppgtt->base.total < ggtt->base.total)) { + if (WARN_ON(ppgtt->vm.total < ggtt->vm.total)) { err = -ENODEV; goto err_ppgtt; } - if (ppgtt->base.allocate_va_range) { + if (ppgtt->vm.allocate_va_range) { /* Note we only pre-allocate as far as the end of the global * GTT. On 48b / 4-level page-tables, the difference is very, * very significant! We have to preallocate as GVT/vgpu does * not like the page directory disappearing. */ - err = ppgtt->base.allocate_va_range(&ppgtt->base, - 0, ggtt->base.total); + err = ppgtt->vm.allocate_va_range(&ppgtt->vm, + 0, ggtt->vm.total); if (err) goto err_ppgtt; } i915->mm.aliasing_ppgtt = ppgtt; - GEM_BUG_ON(ggtt->base.bind_vma != ggtt_bind_vma); - ggtt->base.bind_vma = aliasing_gtt_bind_vma; + GEM_BUG_ON(ggtt->vm.bind_vma != ggtt_bind_vma); + ggtt->vm.bind_vma = aliasing_gtt_bind_vma; - GEM_BUG_ON(ggtt->base.unbind_vma != ggtt_unbind_vma); - ggtt->base.unbind_vma = aliasing_gtt_unbind_vma; + GEM_BUG_ON(ggtt->vm.unbind_vma != ggtt_unbind_vma); + ggtt->vm.unbind_vma = aliasing_gtt_unbind_vma; return 0; @@ -2817,8 +2817,8 @@ void i915_gem_fini_aliasing_ppgtt(struct drm_i915_private *i915) i915_ppgtt_put(ppgtt); - ggtt->base.bind_vma = ggtt_bind_vma; - ggtt->base.unbind_vma = ggtt_unbind_vma; + ggtt->vm.bind_vma = ggtt_bind_vma; + ggtt->vm.unbind_vma = ggtt_unbind_vma; } int i915_gem_init_ggtt(struct drm_i915_private *dev_priv) @@ -2842,7 +2842,7 @@ int i915_gem_init_ggtt(struct drm_i915_private *dev_priv) return ret; /* Reserve a mappable slot for our lockless error capture */ - ret = drm_mm_insert_node_in_range(&ggtt->base.mm, &ggtt->error_capture, + ret = drm_mm_insert_node_in_range(&ggtt->vm.mm, &ggtt->error_capture, PAGE_SIZE, 0, I915_COLOR_UNEVICTABLE, 0, ggtt->mappable_end, DRM_MM_INSERT_LOW); @@ -2850,16 +2850,15 @@ int i915_gem_init_ggtt(struct drm_i915_private *dev_priv) return ret; /* Clear any non-preallocated blocks */ - drm_mm_for_each_hole(entry, &ggtt->base.mm, hole_start, hole_end) { + drm_mm_for_each_hole(entry, &ggtt->vm.mm, hole_start, hole_end) { DRM_DEBUG_KMS("clearing unused GTT space: [%lx, %lx]\n", hole_start, hole_end); - ggtt->base.clear_range(&ggtt->base, hole_start, - hole_end - hole_start); + ggtt->vm.clear_range(&ggtt->vm, hole_start, + hole_end - hole_start); } /* And finally clear the reserved guard page */ - ggtt->base.clear_range(&ggtt->base, - ggtt->base.total - PAGE_SIZE, PAGE_SIZE); + ggtt->vm.clear_range(&ggtt->vm, ggtt->vm.total - PAGE_SIZE, PAGE_SIZE); if (USES_PPGTT(dev_priv) && !USES_FULL_PPGTT(dev_priv)) { ret = i915_gem_init_aliasing_ppgtt(dev_priv); @@ -2884,11 +2883,11 @@ void i915_ggtt_cleanup_hw(struct drm_i915_private *dev_priv) struct i915_vma *vma, *vn; struct pagevec *pvec; - ggtt->base.closed = true; + ggtt->vm.closed = true; mutex_lock(&dev_priv->drm.struct_mutex); - GEM_BUG_ON(!list_empty(&ggtt->base.active_list)); - list_for_each_entry_safe(vma, vn, &ggtt->base.inactive_list, vm_link) + GEM_BUG_ON(!list_empty(&ggtt->vm.active_list)); + list_for_each_entry_safe(vma, vn, &ggtt->vm.inactive_list, vm_link) WARN_ON(i915_vma_unbind(vma)); mutex_unlock(&dev_priv->drm.struct_mutex); @@ -2900,12 +2899,12 @@ void i915_ggtt_cleanup_hw(struct drm_i915_private *dev_priv) if (drm_mm_node_allocated(&ggtt->error_capture)) drm_mm_remove_node(&ggtt->error_capture); - if (drm_mm_initialized(&ggtt->base.mm)) { + if (drm_mm_initialized(&ggtt->vm.mm)) { intel_vgt_deballoon(dev_priv); - i915_address_space_fini(&ggtt->base); + i915_address_space_fini(&ggtt->vm); } - ggtt->base.cleanup(&ggtt->base); + ggtt->vm.cleanup(&ggtt->vm); pvec = &dev_priv->mm.wc_stash; if (pvec->nr) { @@ -2955,7 +2954,7 @@ static unsigned int chv_get_total_gtt_size(u16 gmch_ctrl) static int ggtt_probe_common(struct i915_ggtt *ggtt, u64 size) { - struct drm_i915_private *dev_priv = ggtt->base.i915; + struct drm_i915_private *dev_priv = ggtt->vm.i915; struct pci_dev *pdev = dev_priv->drm.pdev; phys_addr_t phys_addr; int ret; @@ -2979,7 +2978,7 @@ static int ggtt_probe_common(struct i915_ggtt *ggtt, u64 size) return -ENOMEM; } - ret = setup_scratch_page(&ggtt->base, GFP_DMA32); + ret = setup_scratch_page(&ggtt->vm, GFP_DMA32); if (ret) { DRM_ERROR("Scratch setup failed\n"); /* iounmap will also get called at remove, but meh */ @@ -3285,7 +3284,7 @@ static void setup_private_pat(struct drm_i915_private *dev_priv) static int gen8_gmch_probe(struct i915_ggtt *ggtt) { - struct drm_i915_private *dev_priv = ggtt->base.i915; + struct drm_i915_private *dev_priv = ggtt->vm.i915; struct pci_dev *pdev = dev_priv->drm.pdev; unsigned int size; u16 snb_gmch_ctl; @@ -3309,25 +3308,25 @@ static int gen8_gmch_probe(struct i915_ggtt *ggtt) else size = gen8_get_total_gtt_size(snb_gmch_ctl); - ggtt->base.total = (size / sizeof(gen8_pte_t)) << PAGE_SHIFT; - ggtt->base.cleanup = gen6_gmch_remove; - ggtt->base.bind_vma = ggtt_bind_vma; - ggtt->base.unbind_vma = ggtt_unbind_vma; - ggtt->base.set_pages = ggtt_set_pages; - ggtt->base.clear_pages = clear_pages; - ggtt->base.insert_page = gen8_ggtt_insert_page; - ggtt->base.clear_range = nop_clear_range; + ggtt->vm.total = (size / sizeof(gen8_pte_t)) << PAGE_SHIFT; + ggtt->vm.cleanup = gen6_gmch_remove; + ggtt->vm.bind_vma = ggtt_bind_vma; + ggtt->vm.unbind_vma = ggtt_unbind_vma; + ggtt->vm.set_pages = ggtt_set_pages; + ggtt->vm.clear_pages = clear_pages; + ggtt->vm.insert_page = gen8_ggtt_insert_page; + ggtt->vm.clear_range = nop_clear_range; if (!USES_FULL_PPGTT(dev_priv) || intel_scanout_needs_vtd_wa(dev_priv)) - ggtt->base.clear_range = gen8_ggtt_clear_range; + ggtt->vm.clear_range = gen8_ggtt_clear_range; - ggtt->base.insert_entries = gen8_ggtt_insert_entries; + ggtt->vm.insert_entries = gen8_ggtt_insert_entries; /* Serialize GTT updates with aperture access on BXT if VT-d is on. */ if (intel_ggtt_update_needs_vtd_wa(dev_priv)) { - ggtt->base.insert_entries = bxt_vtd_ggtt_insert_entries__BKL; - ggtt->base.insert_page = bxt_vtd_ggtt_insert_page__BKL; - if (ggtt->base.clear_range != nop_clear_range) - ggtt->base.clear_range = bxt_vtd_ggtt_clear_range__BKL; + ggtt->vm.insert_entries = bxt_vtd_ggtt_insert_entries__BKL; + 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; } ggtt->invalidate = gen6_ggtt_invalidate; @@ -3339,7 +3338,7 @@ static int gen8_gmch_probe(struct i915_ggtt *ggtt) static int gen6_gmch_probe(struct i915_ggtt *ggtt) { - struct drm_i915_private *dev_priv = ggtt->base.i915; + struct drm_i915_private *dev_priv = ggtt->vm.i915; struct pci_dev *pdev = dev_priv->drm.pdev; unsigned int size; u16 snb_gmch_ctl; @@ -3366,29 +3365,29 @@ static int gen6_gmch_probe(struct i915_ggtt *ggtt) pci_read_config_word(pdev, SNB_GMCH_CTRL, &snb_gmch_ctl); size = gen6_get_total_gtt_size(snb_gmch_ctl); - ggtt->base.total = (size / sizeof(gen6_pte_t)) << PAGE_SHIFT; + ggtt->vm.total = (size / sizeof(gen6_pte_t)) << PAGE_SHIFT; - ggtt->base.clear_range = gen6_ggtt_clear_range; - ggtt->base.insert_page = gen6_ggtt_insert_page; - ggtt->base.insert_entries = gen6_ggtt_insert_entries; - ggtt->base.bind_vma = ggtt_bind_vma; - ggtt->base.unbind_vma = ggtt_unbind_vma; - ggtt->base.set_pages = ggtt_set_pages; - ggtt->base.clear_pages = clear_pages; - ggtt->base.cleanup = gen6_gmch_remove; + ggtt->vm.clear_range = gen6_ggtt_clear_range; + ggtt->vm.insert_page = gen6_ggtt_insert_page; + ggtt->vm.insert_entries = gen6_ggtt_insert_entries; + ggtt->vm.bind_vma = ggtt_bind_vma; + ggtt->vm.unbind_vma = ggtt_unbind_vma; + ggtt->vm.set_pages = ggtt_set_pages; + ggtt->vm.clear_pages = clear_pages; + ggtt->vm.cleanup = gen6_gmch_remove; ggtt->invalidate = gen6_ggtt_invalidate; if (HAS_EDRAM(dev_priv)) - ggtt->base.pte_encode = iris_pte_encode; + ggtt->vm.pte_encode = iris_pte_encode; else if (IS_HASWELL(dev_priv)) - ggtt->base.pte_encode = hsw_pte_encode; + ggtt->vm.pte_encode = hsw_pte_encode; else if (IS_VALLEYVIEW(dev_priv)) - ggtt->base.pte_encode = byt_pte_encode; + ggtt->vm.pte_encode = byt_pte_encode; else if (INTEL_GEN(dev_priv) >= 7) - ggtt->base.pte_encode = ivb_pte_encode; + ggtt->vm.pte_encode = ivb_pte_encode; else - ggtt->base.pte_encode = snb_pte_encode; + ggtt->vm.pte_encode = snb_pte_encode; return ggtt_probe_common(ggtt, size); } @@ -3400,7 +3399,7 @@ static void i915_gmch_remove(struct i915_address_space *vm) static int i915_gmch_probe(struct i915_ggtt *ggtt) { - struct drm_i915_private *dev_priv = ggtt->base.i915; + struct drm_i915_private *dev_priv = ggtt->vm.i915; phys_addr_t gmadr_base; int ret; @@ -3410,23 +3409,21 @@ static int i915_gmch_probe(struct i915_ggtt *ggtt) return -EIO; } - intel_gtt_get(&ggtt->base.total, - &gmadr_base, - &ggtt->mappable_end); + intel_gtt_get(&ggtt->vm.total, &gmadr_base, &ggtt->mappable_end); ggtt->gmadr = (struct resource) DEFINE_RES_MEM(gmadr_base, ggtt->mappable_end); ggtt->do_idle_maps = needs_idle_maps(dev_priv); - ggtt->base.insert_page = i915_ggtt_insert_page; - ggtt->base.insert_entries = i915_ggtt_insert_entries; - ggtt->base.clear_range = i915_ggtt_clear_range; - ggtt->base.bind_vma = ggtt_bind_vma; - ggtt->base.unbind_vma = ggtt_unbind_vma; - ggtt->base.set_pages = ggtt_set_pages; - ggtt->base.clear_pages = clear_pages; - ggtt->base.cleanup = i915_gmch_remove; + ggtt->vm.insert_page = i915_ggtt_insert_page; + ggtt->vm.insert_entries = i915_ggtt_insert_entries; + ggtt->vm.clear_range = i915_ggtt_clear_range; + ggtt->vm.bind_vma = ggtt_bind_vma; + ggtt->vm.unbind_vma = ggtt_unbind_vma; + ggtt->vm.set_pages = ggtt_set_pages; + ggtt->vm.clear_pages = clear_pages; + ggtt->vm.cleanup = i915_gmch_remove; ggtt->invalidate = gmch_ggtt_invalidate; @@ -3445,8 +3442,8 @@ int i915_ggtt_probe_hw(struct drm_i915_private *dev_priv) struct i915_ggtt *ggtt = &dev_priv->ggtt; int ret; - ggtt->base.i915 = dev_priv; - ggtt->base.dma = &dev_priv->drm.pdev->dev; + ggtt->vm.i915 = dev_priv; + ggtt->vm.dma = &dev_priv->drm.pdev->dev; if (INTEL_GEN(dev_priv) <= 5) ret = i915_gmch_probe(ggtt); @@ -3463,27 +3460,29 @@ int i915_ggtt_probe_hw(struct drm_i915_private *dev_priv) * restriction! */ if (USES_GUC(dev_priv)) { - ggtt->base.total = min_t(u64, ggtt->base.total, GUC_GGTT_TOP); - ggtt->mappable_end = min_t(u64, ggtt->mappable_end, ggtt->base.total); + ggtt->vm.total = min_t(u64, ggtt->vm.total, GUC_GGTT_TOP); + ggtt->mappable_end = + min_t(u64, ggtt->mappable_end, ggtt->vm.total); } - if ((ggtt->base.total - 1) >> 32) { + if ((ggtt->vm.total - 1) >> 32) { DRM_ERROR("We never expected a Global GTT with more than 32bits" " of address space! Found %lldM!\n", - ggtt->base.total >> 20); - ggtt->base.total = 1ULL << 32; - ggtt->mappable_end = min_t(u64, ggtt->mappable_end, ggtt->base.total); + ggtt->vm.total >> 20); + ggtt->vm.total = 1ULL << 32; + ggtt->mappable_end = + min_t(u64, ggtt->mappable_end, ggtt->vm.total); } - if (ggtt->mappable_end > ggtt->base.total) { + if (ggtt->mappable_end > ggtt->vm.total) { DRM_ERROR("mappable aperture extends past end of GGTT," " aperture=%pa, total=%llx\n", - &ggtt->mappable_end, ggtt->base.total); - ggtt->mappable_end = ggtt->base.total; + &ggtt->mappable_end, ggtt->vm.total); + ggtt->mappable_end = ggtt->vm.total; } /* GMADR is the PCI mmio aperture into the global GTT. */ - DRM_DEBUG_DRIVER("GGTT size = %lluM\n", ggtt->base.total >> 20); + DRM_DEBUG_DRIVER("GGTT size = %lluM\n", ggtt->vm.total >> 20); DRM_DEBUG_DRIVER("GMADR size = %lluM\n", (u64)ggtt->mappable_end >> 20); DRM_DEBUG_DRIVER("DSM size = %lluM\n", (u64)resource_size(&intel_graphics_stolen_res) >> 20); @@ -3510,9 +3509,9 @@ int i915_ggtt_init_hw(struct drm_i915_private *dev_priv) * and beyond the end of the GTT if we do not provide a guard. */ mutex_lock(&dev_priv->drm.struct_mutex); - i915_address_space_init(&ggtt->base, dev_priv, "[global]"); + i915_address_space_init(&ggtt->vm, dev_priv, "[global]"); if (!HAS_LLC(dev_priv) && !USES_PPGTT(dev_priv)) - ggtt->base.mm.color_adjust = i915_gtt_color_adjust; + ggtt->vm.mm.color_adjust = i915_gtt_color_adjust; mutex_unlock(&dev_priv->drm.struct_mutex); if (!io_mapping_init_wc(&dev_priv->ggtt.iomap, @@ -3535,7 +3534,7 @@ int i915_ggtt_init_hw(struct drm_i915_private *dev_priv) return 0; out_gtt_cleanup: - ggtt->base.cleanup(&ggtt->base); + ggtt->vm.cleanup(&ggtt->vm); return ret; } @@ -3574,13 +3573,13 @@ void i915_gem_restore_gtt_mappings(struct drm_i915_private *dev_priv) i915_check_and_clear_faults(dev_priv); /* First fill our portion of the GTT with scratch pages */ - ggtt->base.clear_range(&ggtt->base, 0, ggtt->base.total); + ggtt->vm.clear_range(&ggtt->vm, 0, ggtt->vm.total); - ggtt->base.closed = true; /* skip rewriting PTE on VMA unbind */ + ggtt->vm.closed = true; /* skip rewriting PTE on VMA unbind */ /* clflush objects bound into the GGTT and rebind them. */ - GEM_BUG_ON(!list_empty(&ggtt->base.active_list)); - list_for_each_entry_safe(vma, vn, &ggtt->base.inactive_list, vm_link) { + GEM_BUG_ON(!list_empty(&ggtt->vm.active_list)); + list_for_each_entry_safe(vma, vn, &ggtt->vm.inactive_list, vm_link) { struct drm_i915_gem_object *obj = vma->obj; if (!(vma->flags & I915_VMA_GLOBAL_BIND)) @@ -3593,7 +3592,7 @@ void i915_gem_restore_gtt_mappings(struct drm_i915_private *dev_priv) WARN_ON(i915_gem_object_set_to_gtt_domain(obj, false)); } - ggtt->base.closed = false; + ggtt->vm.closed = false; if (INTEL_GEN(dev_priv) >= 8) { struct intel_ppat *ppat = &dev_priv->ppat; @@ -3616,7 +3615,7 @@ void i915_gem_restore_gtt_mappings(struct drm_i915_private *dev_priv) if (!ppgtt) continue; - gen6_write_page_range(ppgtt, 0, ppgtt->base.total); + gen6_write_page_range(ppgtt, 0, ppgtt->vm.total); } } @@ -3838,7 +3837,7 @@ int i915_gem_gtt_reserve(struct i915_address_space *vm, GEM_BUG_ON(!IS_ALIGNED(size, I915_GTT_PAGE_SIZE)); GEM_BUG_ON(!IS_ALIGNED(offset, I915_GTT_MIN_ALIGNMENT)); GEM_BUG_ON(range_overflows(offset, size, vm->total)); - GEM_BUG_ON(vm == &vm->i915->mm.aliasing_ppgtt->base); + GEM_BUG_ON(vm == &vm->i915->mm.aliasing_ppgtt->vm); GEM_BUG_ON(drm_mm_node_allocated(node)); node->size = size; @@ -3935,7 +3934,7 @@ int i915_gem_gtt_insert(struct i915_address_space *vm, GEM_BUG_ON(start >= end); GEM_BUG_ON(start > 0 && !IS_ALIGNED(start, I915_GTT_PAGE_SIZE)); GEM_BUG_ON(end < U64_MAX && !IS_ALIGNED(end, I915_GTT_PAGE_SIZE)); - GEM_BUG_ON(vm == &vm->i915->mm.aliasing_ppgtt->base); + GEM_BUG_ON(vm == &vm->i915->mm.aliasing_ppgtt->vm); GEM_BUG_ON(drm_mm_node_allocated(node)); if (unlikely(range_overflows(start, size, end))) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index aec4f73574f4d..197c2c06ecb73 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -65,7 +65,7 @@ typedef u64 gen8_pde_t; typedef u64 gen8_ppgtt_pdpe_t; typedef u64 gen8_ppgtt_pml4e_t; -#define ggtt_total_entries(ggtt) ((ggtt)->base.total >> PAGE_SHIFT) +#define ggtt_total_entries(ggtt) ((ggtt)->vm.total >> PAGE_SHIFT) /* gen6-hsw has bit 11-4 for physical addr bit 39-32 */ #define GEN6_GTT_ADDR_ENCODE(addr) ((addr) | (((addr) >> 28) & 0xff0)) @@ -367,7 +367,7 @@ i915_vm_has_scratch_64K(struct i915_address_space *vm) * the spec. */ struct i915_ggtt { - struct i915_address_space base; + struct i915_address_space vm; struct io_mapping iomap; /* Mapping to our CPU mappable region */ struct resource gmadr; /* GMADR resource */ @@ -385,7 +385,7 @@ struct i915_ggtt { }; struct i915_hw_ppgtt { - struct i915_address_space base; + struct i915_address_space vm; struct kref ref; struct drm_mm_node node; unsigned long pd_dirty_rings; @@ -543,7 +543,7 @@ static inline struct i915_ggtt * i915_vm_to_ggtt(struct i915_address_space *vm) { GEM_BUG_ON(!i915_is_ggtt(vm)); - return container_of(vm, struct i915_ggtt, base); + return container_of(vm, struct i915_ggtt, vm); } #define INTEL_MAX_PPAT_ENTRIES 8 diff --git a/drivers/gpu/drm/i915/i915_gem_render_state.c b/drivers/gpu/drm/i915/i915_gem_render_state.c index 1036e86869165..3210cedfa46c3 100644 --- a/drivers/gpu/drm/i915/i915_gem_render_state.c +++ b/drivers/gpu/drm/i915/i915_gem_render_state.c @@ -194,7 +194,7 @@ int i915_gem_render_state_emit(struct i915_request *rq) if (IS_ERR(so.obj)) return PTR_ERR(so.obj); - so.vma = i915_vma_instance(so.obj, &engine->i915->ggtt.base, NULL); + so.vma = i915_vma_instance(so.obj, &engine->i915->ggtt.vm, NULL); if (IS_ERR(so.vma)) { err = PTR_ERR(so.vma); goto err_obj; diff --git a/drivers/gpu/drm/i915/i915_gem_shrinker.c b/drivers/gpu/drm/i915/i915_gem_shrinker.c index 5757fb7c4b5af..55e84e71f526d 100644 --- a/drivers/gpu/drm/i915/i915_gem_shrinker.c +++ b/drivers/gpu/drm/i915/i915_gem_shrinker.c @@ -480,7 +480,7 @@ i915_gem_shrinker_vmap(struct notifier_block *nb, unsigned long event, void *ptr /* We also want to clear any cached iomaps as they wrap vmap */ list_for_each_entry_safe(vma, next, - &i915->ggtt.base.inactive_list, vm_link) { + &i915->ggtt.vm.inactive_list, vm_link) { unsigned long count = vma->node.size >> PAGE_SHIFT; if (vma->iomap && i915_vma_unbind(vma) == 0) freed_pages += count; diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index ad949cc309281..79a347295e006 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -642,7 +642,7 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_i915_private *dev_priv if (ret) goto err; - vma = i915_vma_instance(obj, &ggtt->base, NULL); + vma = i915_vma_instance(obj, &ggtt->vm, NULL); if (IS_ERR(vma)) { ret = PTR_ERR(vma); goto err_pages; @@ -653,7 +653,7 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_i915_private *dev_priv * setting up the GTT space. The actual reservation will occur * later. */ - ret = i915_gem_gtt_reserve(&ggtt->base, &vma->node, + ret = i915_gem_gtt_reserve(&ggtt->vm, &vma->node, size, gtt_offset, obj->cache_level, 0); if (ret) { @@ -666,7 +666,7 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_i915_private *dev_priv vma->pages = obj->mm.pages; vma->flags |= I915_VMA_GLOBAL_BIND; __i915_vma_set_map_and_fenceable(vma); - list_move_tail(&vma->vm_link, &ggtt->base.inactive_list); + list_move_tail(&vma->vm_link, &ggtt->vm.inactive_list); spin_lock(&dev_priv->mm.obj_lock); list_move_tail(&obj->mm.link, &dev_priv->mm.bound_list); diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 6702776303bfd..758234d20f4ea 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -973,8 +973,7 @@ i915_error_object_create(struct drm_i915_private *i915, void __iomem *s; int ret; - ggtt->base.insert_page(&ggtt->base, dma, slot, - I915_CACHE_NONE, 0); + ggtt->vm.insert_page(&ggtt->vm, dma, slot, I915_CACHE_NONE, 0); s = io_mapping_map_atomic_wc(&ggtt->iomap, slot); ret = compress_page(&compress, (void __force *)s, dst); @@ -993,7 +992,7 @@ i915_error_object_create(struct drm_i915_private *i915, out: compress_fini(&compress, dst); - ggtt->base.clear_range(&ggtt->base, slot, PAGE_SIZE); + ggtt->vm.clear_range(&ggtt->vm, slot, PAGE_SIZE); return dst; } @@ -1466,7 +1465,7 @@ static void gem_record_rings(struct i915_gpu_state *error) struct i915_gem_context *ctx = request->gem_context; struct intel_ring *ring; - ee->vm = ctx->ppgtt ? &ctx->ppgtt->base : &ggtt->base; + ee->vm = ctx->ppgtt ? &ctx->ppgtt->vm : &ggtt->vm; record_context(&ee->context, ctx); @@ -1564,7 +1563,7 @@ static void capture_active_buffers(struct i915_gpu_state *error) static void capture_pinned_buffers(struct i915_gpu_state *error) { - struct i915_address_space *vm = &error->i915->ggtt.base; + struct i915_address_space *vm = &error->i915->ggtt.vm; struct drm_i915_error_buffer *bo; struct i915_vma *vma; int count_inactive, count_active; diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h index 3d5716d86e279..1472f48ab2e80 100644 --- a/drivers/gpu/drm/i915/i915_trace.h +++ b/drivers/gpu/drm/i915/i915_trace.h @@ -956,7 +956,7 @@ DECLARE_EVENT_CLASS(i915_context, __entry->dev = ctx->i915->drm.primary->index; __entry->ctx = ctx; __entry->hw_id = ctx->hw_id; - __entry->vm = ctx->ppgtt ? &ctx->ppgtt->base : NULL; + __entry->vm = ctx->ppgtt ? &ctx->ppgtt->vm : NULL; ), TP_printk("dev=%u, ctx=%p, ctx_vm=%p, hw_id=%u", @@ -997,7 +997,7 @@ TRACE_EVENT(switch_mm, __entry->class = engine->uabi_class; __entry->instance = engine->instance; __entry->to = to; - __entry->vm = to->ppgtt? &to->ppgtt->base : NULL; + __entry->vm = to->ppgtt ? &to->ppgtt->vm : NULL; __entry->dev = engine->i915->drm.primary->index; ), diff --git a/drivers/gpu/drm/i915/i915_vgpu.c b/drivers/gpu/drm/i915/i915_vgpu.c index 5fe9f3f394672..869cf4a3b6de7 100644 --- a/drivers/gpu/drm/i915/i915_vgpu.c +++ b/drivers/gpu/drm/i915/i915_vgpu.c @@ -105,7 +105,7 @@ static void vgt_deballoon_space(struct i915_ggtt *ggtt, node->start + node->size, node->size / 1024); - ggtt->base.reserved -= node->size; + ggtt->vm.reserved -= node->size; drm_mm_remove_node(node); } @@ -141,11 +141,11 @@ static int vgt_balloon_space(struct i915_ggtt *ggtt, DRM_INFO("balloon space: range [ 0x%lx - 0x%lx ] %lu KiB.\n", start, end, size / 1024); - ret = i915_gem_gtt_reserve(&ggtt->base, node, + ret = i915_gem_gtt_reserve(&ggtt->vm, node, size, start, I915_COLOR_UNEVICTABLE, 0); if (!ret) - ggtt->base.reserved += size; + ggtt->vm.reserved += size; return ret; } @@ -197,7 +197,7 @@ static int vgt_balloon_space(struct i915_ggtt *ggtt, int intel_vgt_balloon(struct drm_i915_private *dev_priv) { struct i915_ggtt *ggtt = &dev_priv->ggtt; - unsigned long ggtt_end = ggtt->base.total; + unsigned long ggtt_end = ggtt->vm.total; unsigned long mappable_base, mappable_size, mappable_end; unsigned long unmappable_base, unmappable_size, unmappable_end; diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c index 10bf654cd0235..912f16ffe7eea 100644 --- a/drivers/gpu/drm/i915/i915_vma.c +++ b/drivers/gpu/drm/i915/i915_vma.c @@ -85,7 +85,7 @@ vma_create(struct drm_i915_gem_object *obj, int i; /* The aliasing_ppgtt should never be used directly! */ - GEM_BUG_ON(vm == &vm->i915->mm.aliasing_ppgtt->base); + GEM_BUG_ON(vm == &vm->i915->mm.aliasing_ppgtt->vm); vma = kmem_cache_zalloc(vm->i915->vmas, GFP_KERNEL); if (vma == NULL) diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index 13448ea76f57b..2ec2e60dc6707 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -515,7 +515,7 @@ int intel_engine_create_scratch(struct intel_engine_cs *engine, int size) return PTR_ERR(obj); } - vma = i915_vma_instance(obj, &engine->i915->ggtt.base, NULL); + vma = i915_vma_instance(obj, &engine->i915->ggtt.vm, NULL); if (IS_ERR(vma)) { ret = PTR_ERR(vma); goto err_unref; @@ -585,7 +585,7 @@ static int init_status_page(struct intel_engine_cs *engine) if (ret) goto err; - vma = i915_vma_instance(obj, &engine->i915->ggtt.base, NULL); + vma = i915_vma_instance(obj, &engine->i915->ggtt.vm, NULL); if (IS_ERR(vma)) { ret = PTR_ERR(vma); goto err; diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c index e28a996b9604a..29fd95c1306bd 100644 --- a/drivers/gpu/drm/i915/intel_guc.c +++ b/drivers/gpu/drm/i915/intel_guc.c @@ -570,7 +570,7 @@ struct i915_vma *intel_guc_allocate_vma(struct intel_guc *guc, u32 size) if (IS_ERR(obj)) return ERR_CAST(obj); - vma = i915_vma_instance(obj, &dev_priv->ggtt.base, NULL); + vma = i915_vma_instance(obj, &dev_priv->ggtt.vm, NULL); if (IS_ERR(vma)) goto err; diff --git a/drivers/gpu/drm/i915/intel_guc_submission.c b/drivers/gpu/drm/i915/intel_guc_submission.c index 23e9f2023bc56..f3945258fe1b5 100644 --- a/drivers/gpu/drm/i915/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/intel_guc_submission.c @@ -536,7 +536,7 @@ static void guc_add_request(struct intel_guc *guc, struct i915_request *rq) */ static void flush_ggtt_writes(struct i915_vma *vma) { - struct drm_i915_private *dev_priv = to_i915(vma->obj->base.dev); + struct drm_i915_private *dev_priv = vma->vm->i915; if (i915_vma_is_map_and_fenceable(vma)) POSTING_READ_FW(GUC_STATUS); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index f6f09f808f74a..0935a19aca96f 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -431,7 +431,7 @@ static u64 execlists_update_context(struct i915_request *rq) * PML4 is allocated during ppgtt init, so this is not needed * in 48-bit mode. */ - if (ppgtt && !i915_vm_is_48bit(&ppgtt->base)) + if (ppgtt && !i915_vm_is_48bit(&ppgtt->vm)) execlists_update_context_pdps(ppgtt, reg_state); return ce->lrc_desc; @@ -1672,7 +1672,7 @@ static int lrc_setup_wa_ctx(struct intel_engine_cs *engine) if (IS_ERR(obj)) return PTR_ERR(obj); - vma = i915_vma_instance(obj, &engine->i915->ggtt.base, NULL); + vma = i915_vma_instance(obj, &engine->i915->ggtt.vm, NULL); if (IS_ERR(vma)) { err = PTR_ERR(vma); goto err; @@ -2070,7 +2070,7 @@ static int gen8_emit_bb_start(struct i915_request *rq, * not needed in 48-bit.*/ if (rq->gem_context->ppgtt && (intel_engine_flag(rq->engine) & rq->gem_context->ppgtt->pd_dirty_rings) && - !i915_vm_is_48bit(&rq->gem_context->ppgtt->base) && + !i915_vm_is_48bit(&rq->gem_context->ppgtt->vm) && !intel_vgpu_active(rq->i915)) { ret = intel_logical_ring_emit_pdps(rq); if (ret) @@ -2668,7 +2668,7 @@ static void execlists_init_reg_state(u32 *regs, CTX_REG(regs, CTX_PDP0_UDW, GEN8_RING_PDP_UDW(engine, 0), 0); CTX_REG(regs, CTX_PDP0_LDW, GEN8_RING_PDP_LDW(engine, 0), 0); - if (ppgtt && i915_vm_is_48bit(&ppgtt->base)) { + if (ppgtt && i915_vm_is_48bit(&ppgtt->vm)) { /* 64b PPGTT (48bit canonical) * PDP0_DESCRIPTOR contains the base address to PML4 and * other PDP Descriptors are ignored. @@ -2774,7 +2774,7 @@ static int execlists_context_deferred_alloc(struct i915_gem_context *ctx, goto error_deref_obj; } - vma = i915_vma_instance(ctx_obj, &ctx->i915->ggtt.base, NULL); + vma = i915_vma_instance(ctx_obj, &ctx->i915->ggtt.vm, NULL); if (IS_ERR(vma)) { ret = PTR_ERR(vma); goto error_deref_obj; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 3f0eb538df098..6496c1d00dbba 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1121,7 +1121,7 @@ intel_ring_create_vma(struct drm_i915_private *dev_priv, int size) /* mark ring buffers as read-only from GPU side by default */ obj->gt_ro = 1; - vma = i915_vma_instance(obj, &dev_priv->ggtt.base, NULL); + vma = i915_vma_instance(obj, &dev_priv->ggtt.vm, NULL); if (IS_ERR(vma)) goto err; @@ -1300,7 +1300,7 @@ alloc_context_vma(struct intel_engine_cs *engine) i915_gem_object_set_cache_level(obj, I915_CACHE_L3_LLC); } - vma = i915_vma_instance(obj, &i915->ggtt.base, NULL); + vma = i915_vma_instance(obj, &i915->ggtt.vm, NULL); if (IS_ERR(vma)) { err = PTR_ERR(vma); goto err_obj; diff --git a/drivers/gpu/drm/i915/selftests/huge_pages.c b/drivers/gpu/drm/i915/selftests/huge_pages.c index 91c72911be3cb..7846ea4a99bc6 100644 --- a/drivers/gpu/drm/i915/selftests/huge_pages.c +++ b/drivers/gpu/drm/i915/selftests/huge_pages.c @@ -338,7 +338,7 @@ fake_huge_pages_object(struct drm_i915_private *i915, u64 size, bool single) static int igt_check_page_sizes(struct i915_vma *vma) { - struct drm_i915_private *i915 = to_i915(vma->obj->base.dev); + struct drm_i915_private *i915 = vma->vm->i915; unsigned int supported = INTEL_INFO(i915)->page_sizes; struct drm_i915_gem_object *obj = vma->obj; int err = 0; @@ -379,7 +379,7 @@ static int igt_check_page_sizes(struct i915_vma *vma) static int igt_mock_exhaust_device_supported_pages(void *arg) { struct i915_hw_ppgtt *ppgtt = arg; - struct drm_i915_private *i915 = ppgtt->base.i915; + struct drm_i915_private *i915 = ppgtt->vm.i915; unsigned int saved_mask = INTEL_INFO(i915)->page_sizes; struct drm_i915_gem_object *obj; struct i915_vma *vma; @@ -415,7 +415,7 @@ static int igt_mock_exhaust_device_supported_pages(void *arg) goto out_put; } - vma = i915_vma_instance(obj, &ppgtt->base, NULL); + vma = i915_vma_instance(obj, &ppgtt->vm, NULL); if (IS_ERR(vma)) { err = PTR_ERR(vma); goto out_put; @@ -458,7 +458,7 @@ static int igt_mock_exhaust_device_supported_pages(void *arg) static int igt_mock_ppgtt_misaligned_dma(void *arg) { struct i915_hw_ppgtt *ppgtt = arg; - struct drm_i915_private *i915 = ppgtt->base.i915; + struct drm_i915_private *i915 = ppgtt->vm.i915; unsigned long supported = INTEL_INFO(i915)->page_sizes; struct drm_i915_gem_object *obj; int bit; @@ -500,7 +500,7 @@ static int igt_mock_ppgtt_misaligned_dma(void *arg) /* Force the page size for this object */ obj->mm.page_sizes.sg = page_size; - vma = i915_vma_instance(obj, &ppgtt->base, NULL); + vma = i915_vma_instance(obj, &ppgtt->vm, NULL); if (IS_ERR(vma)) { err = PTR_ERR(vma); goto out_unpin; @@ -591,7 +591,7 @@ static void close_object_list(struct list_head *objects, list_for_each_entry_safe(obj, on, objects, st_link) { struct i915_vma *vma; - vma = i915_vma_instance(obj, &ppgtt->base, NULL); + vma = i915_vma_instance(obj, &ppgtt->vm, NULL); if (!IS_ERR(vma)) i915_vma_close(vma); @@ -604,8 +604,8 @@ static void close_object_list(struct list_head *objects, static int igt_mock_ppgtt_huge_fill(void *arg) { struct i915_hw_ppgtt *ppgtt = arg; - struct drm_i915_private *i915 = ppgtt->base.i915; - unsigned long max_pages = ppgtt->base.total >> PAGE_SHIFT; + struct drm_i915_private *i915 = ppgtt->vm.i915; + unsigned long max_pages = ppgtt->vm.total >> PAGE_SHIFT; unsigned long page_num; bool single = false; LIST_HEAD(objects); @@ -641,7 +641,7 @@ static int igt_mock_ppgtt_huge_fill(void *arg) list_add(&obj->st_link, &objects); - vma = i915_vma_instance(obj, &ppgtt->base, NULL); + vma = i915_vma_instance(obj, &ppgtt->vm, NULL); if (IS_ERR(vma)) { err = PTR_ERR(vma); break; @@ -725,7 +725,7 @@ static int igt_mock_ppgtt_huge_fill(void *arg) static int igt_mock_ppgtt_64K(void *arg) { struct i915_hw_ppgtt *ppgtt = arg; - struct drm_i915_private *i915 = ppgtt->base.i915; + struct drm_i915_private *i915 = ppgtt->vm.i915; struct drm_i915_gem_object *obj; const struct object_info { unsigned int size; @@ -819,7 +819,7 @@ static int igt_mock_ppgtt_64K(void *arg) */ obj->mm.page_sizes.sg &= ~I915_GTT_PAGE_SIZE_2M; - vma = i915_vma_instance(obj, &ppgtt->base, NULL); + vma = i915_vma_instance(obj, &ppgtt->vm, NULL); if (IS_ERR(vma)) { err = PTR_ERR(vma); goto out_object_unpin; @@ -887,8 +887,8 @@ static int igt_mock_ppgtt_64K(void *arg) static struct i915_vma * gpu_write_dw(struct i915_vma *vma, u64 offset, u32 val) { - struct drm_i915_private *i915 = to_i915(vma->obj->base.dev); - const int gen = INTEL_GEN(vma->vm->i915); + struct drm_i915_private *i915 = vma->vm->i915; + const int gen = INTEL_GEN(i915); unsigned int count = vma->size >> PAGE_SHIFT; struct drm_i915_gem_object *obj; struct i915_vma *batch; @@ -1047,7 +1047,8 @@ static int __igt_write_huge(struct i915_gem_context *ctx, u32 dword, u32 val) { struct drm_i915_private *i915 = to_i915(obj->base.dev); - struct i915_address_space *vm = ctx->ppgtt ? &ctx->ppgtt->base : &i915->ggtt.base; + struct i915_address_space *vm = + ctx->ppgtt ? &ctx->ppgtt->vm : &i915->ggtt.vm; unsigned int flags = PIN_USER | PIN_OFFSET_FIXED; struct i915_vma *vma; int err; @@ -1100,7 +1101,8 @@ static int igt_write_huge(struct i915_gem_context *ctx, struct drm_i915_gem_object *obj) { struct drm_i915_private *i915 = to_i915(obj->base.dev); - struct i915_address_space *vm = ctx->ppgtt ? &ctx->ppgtt->base : &i915->ggtt.base; + struct i915_address_space *vm = + ctx->ppgtt ? &ctx->ppgtt->vm : &i915->ggtt.vm; static struct intel_engine_cs *engines[I915_NUM_ENGINES]; struct intel_engine_cs *engine; I915_RND_STATE(prng); @@ -1439,7 +1441,7 @@ static int igt_ppgtt_pin_update(void *arg) if (IS_ERR(obj)) return PTR_ERR(obj); - vma = i915_vma_instance(obj, &ppgtt->base, NULL); + vma = i915_vma_instance(obj, &ppgtt->vm, NULL); if (IS_ERR(vma)) { err = PTR_ERR(vma); goto out_put; @@ -1493,7 +1495,7 @@ static int igt_ppgtt_pin_update(void *arg) if (IS_ERR(obj)) return PTR_ERR(obj); - vma = i915_vma_instance(obj, &ppgtt->base, NULL); + vma = i915_vma_instance(obj, &ppgtt->vm, NULL); if (IS_ERR(vma)) { err = PTR_ERR(vma); goto out_put; @@ -1531,7 +1533,8 @@ static int igt_tmpfs_fallback(void *arg) struct i915_gem_context *ctx = arg; struct drm_i915_private *i915 = ctx->i915; struct vfsmount *gemfs = i915->mm.gemfs; - struct i915_address_space *vm = ctx->ppgtt ? &ctx->ppgtt->base : &i915->ggtt.base; + struct i915_address_space *vm = + ctx->ppgtt ? &ctx->ppgtt->vm : &i915->ggtt.vm; struct drm_i915_gem_object *obj; struct i915_vma *vma; u32 *vaddr; @@ -1587,7 +1590,8 @@ static int igt_shrink_thp(void *arg) { struct i915_gem_context *ctx = arg; struct drm_i915_private *i915 = ctx->i915; - struct i915_address_space *vm = ctx->ppgtt ? &ctx->ppgtt->base : &i915->ggtt.base; + struct i915_address_space *vm = + ctx->ppgtt ? &ctx->ppgtt->vm : &i915->ggtt.vm; struct drm_i915_gem_object *obj; struct i915_vma *vma; unsigned int flags = PIN_USER; @@ -1696,14 +1700,14 @@ int i915_gem_huge_page_mock_selftests(void) goto out_unlock; } - if (!i915_vm_is_48bit(&ppgtt->base)) { + if (!i915_vm_is_48bit(&ppgtt->vm)) { pr_err("failed to create 48b PPGTT\n"); err = -EINVAL; goto out_close; } /* If we were ever hit this then it's time to mock the 64K scratch */ - if (!i915_vm_has_scratch_64K(&ppgtt->base)) { + if (!i915_vm_has_scratch_64K(&ppgtt->vm)) { pr_err("PPGTT missing 64K scratch page\n"); err = -EINVAL; goto out_close; @@ -1712,7 +1716,7 @@ int i915_gem_huge_page_mock_selftests(void) err = i915_subtests(tests, ppgtt); out_close: - i915_ppgtt_close(&ppgtt->base); + i915_ppgtt_close(&ppgtt->vm); i915_ppgtt_put(ppgtt); out_unlock: @@ -1758,7 +1762,7 @@ int i915_gem_huge_page_live_selftests(struct drm_i915_private *dev_priv) } if (ctx->ppgtt) - ctx->ppgtt->base.scrub_64K = true; + ctx->ppgtt->vm.scrub_64K = true; err = i915_subtests(tests, ctx); diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_context.c b/drivers/gpu/drm/i915/selftests/i915_gem_context.c index b39392a00a6fe..708e8d7214488 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_context.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_context.c @@ -115,7 +115,7 @@ static int gpu_fill(struct drm_i915_gem_object *obj, { struct drm_i915_private *i915 = to_i915(obj->base.dev); struct i915_address_space *vm = - ctx->ppgtt ? &ctx->ppgtt->base : &i915->ggtt.base; + ctx->ppgtt ? &ctx->ppgtt->vm : &i915->ggtt.vm; struct i915_request *rq; struct i915_vma *vma; struct i915_vma *batch; @@ -290,7 +290,7 @@ create_test_object(struct i915_gem_context *ctx, { struct drm_i915_gem_object *obj; struct i915_address_space *vm = - ctx->ppgtt ? &ctx->ppgtt->base : &ctx->i915->ggtt.base; + ctx->ppgtt ? &ctx->ppgtt->vm : &ctx->i915->ggtt.vm; u64 size; int err; @@ -557,7 +557,7 @@ static int fake_aliasing_ppgtt_enable(struct drm_i915_private *i915) list_for_each_entry(obj, &i915->mm.bound_list, mm.link) { struct i915_vma *vma; - vma = i915_vma_instance(obj, &i915->ggtt.base, NULL); + vma = i915_vma_instance(obj, &i915->ggtt.vm, NULL); if (IS_ERR(vma)) continue; diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_evict.c b/drivers/gpu/drm/i915/selftests/i915_gem_evict.c index ab9d7bee0aae1..2dc72a984d450 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_evict.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_evict.c @@ -35,7 +35,7 @@ static int populate_ggtt(struct drm_i915_private *i915) u64 size; for (size = 0; - size + I915_GTT_PAGE_SIZE <= i915->ggtt.base.total; + size + I915_GTT_PAGE_SIZE <= i915->ggtt.vm.total; size += I915_GTT_PAGE_SIZE) { struct i915_vma *vma; @@ -57,7 +57,7 @@ static int populate_ggtt(struct drm_i915_private *i915) return -EINVAL; } - if (list_empty(&i915->ggtt.base.inactive_list)) { + if (list_empty(&i915->ggtt.vm.inactive_list)) { pr_err("No objects on the GGTT inactive list!\n"); return -EINVAL; } @@ -69,7 +69,7 @@ static void unpin_ggtt(struct drm_i915_private *i915) { struct i915_vma *vma; - list_for_each_entry(vma, &i915->ggtt.base.inactive_list, vm_link) + list_for_each_entry(vma, &i915->ggtt.vm.inactive_list, vm_link) i915_vma_unpin(vma); } @@ -103,7 +103,7 @@ static int igt_evict_something(void *arg) goto cleanup; /* Everything is pinned, nothing should happen */ - err = i915_gem_evict_something(&ggtt->base, + err = i915_gem_evict_something(&ggtt->vm, I915_GTT_PAGE_SIZE, 0, 0, 0, U64_MAX, 0); @@ -116,7 +116,7 @@ static int igt_evict_something(void *arg) unpin_ggtt(i915); /* Everything is unpinned, we should be able to evict something */ - err = i915_gem_evict_something(&ggtt->base, + err = i915_gem_evict_something(&ggtt->vm, I915_GTT_PAGE_SIZE, 0, 0, 0, U64_MAX, 0); @@ -181,7 +181,7 @@ static int igt_evict_for_vma(void *arg) goto cleanup; /* Everything is pinned, nothing should happen */ - err = i915_gem_evict_for_node(&ggtt->base, &target, 0); + err = i915_gem_evict_for_node(&ggtt->vm, &target, 0); if (err != -ENOSPC) { pr_err("i915_gem_evict_for_node on a full GGTT returned err=%d\n", err); @@ -191,7 +191,7 @@ static int igt_evict_for_vma(void *arg) unpin_ggtt(i915); /* Everything is unpinned, we should be able to evict the node */ - err = i915_gem_evict_for_node(&ggtt->base, &target, 0); + err = i915_gem_evict_for_node(&ggtt->vm, &target, 0); if (err) { pr_err("i915_gem_evict_for_node returned err=%d\n", err); @@ -229,7 +229,7 @@ static int igt_evict_for_cache_color(void *arg) * i915_gtt_color_adjust throughout our driver, so using a mock color * adjust will work just fine for our purposes. */ - ggtt->base.mm.color_adjust = mock_color_adjust; + ggtt->vm.mm.color_adjust = mock_color_adjust; obj = i915_gem_object_create_internal(i915, I915_GTT_PAGE_SIZE); if (IS_ERR(obj)) { @@ -265,7 +265,7 @@ static int igt_evict_for_cache_color(void *arg) i915_vma_unpin(vma); /* Remove just the second vma */ - err = i915_gem_evict_for_node(&ggtt->base, &target, 0); + err = i915_gem_evict_for_node(&ggtt->vm, &target, 0); if (err) { pr_err("[0]i915_gem_evict_for_node returned err=%d\n", err); goto cleanup; @@ -276,7 +276,7 @@ static int igt_evict_for_cache_color(void *arg) */ target.color = I915_CACHE_L3_LLC; - err = i915_gem_evict_for_node(&ggtt->base, &target, 0); + err = i915_gem_evict_for_node(&ggtt->vm, &target, 0); if (!err) { pr_err("[1]i915_gem_evict_for_node returned err=%d\n", err); err = -EINVAL; @@ -288,7 +288,7 @@ static int igt_evict_for_cache_color(void *arg) cleanup: unpin_ggtt(i915); cleanup_objects(i915); - ggtt->base.mm.color_adjust = NULL; + ggtt->vm.mm.color_adjust = NULL; return err; } @@ -305,7 +305,7 @@ static int igt_evict_vm(void *arg) goto cleanup; /* Everything is pinned, nothing should happen */ - err = i915_gem_evict_vm(&ggtt->base); + err = i915_gem_evict_vm(&ggtt->vm); if (err) { pr_err("i915_gem_evict_vm on a full GGTT returned err=%d]\n", err); @@ -314,7 +314,7 @@ static int igt_evict_vm(void *arg) unpin_ggtt(i915); - err = i915_gem_evict_vm(&ggtt->base); + err = i915_gem_evict_vm(&ggtt->vm); if (err) { pr_err("i915_gem_evict_vm on a full GGTT returned err=%d]\n", err); @@ -359,9 +359,9 @@ static int igt_evict_contexts(void *arg) /* Reserve a block so that we know we have enough to fit a few rq */ memset(&hole, 0, sizeof(hole)); - err = i915_gem_gtt_insert(&i915->ggtt.base, &hole, + err = i915_gem_gtt_insert(&i915->ggtt.vm, &hole, PRETEND_GGTT_SIZE, 0, I915_COLOR_UNEVICTABLE, - 0, i915->ggtt.base.total, + 0, i915->ggtt.vm.total, PIN_NOEVICT); if (err) goto out_locked; @@ -377,9 +377,9 @@ static int igt_evict_contexts(void *arg) goto out_locked; } - if (i915_gem_gtt_insert(&i915->ggtt.base, &r->node, + if (i915_gem_gtt_insert(&i915->ggtt.vm, &r->node, 1ul << 20, 0, I915_COLOR_UNEVICTABLE, - 0, i915->ggtt.base.total, + 0, i915->ggtt.vm.total, PIN_NOEVICT)) { kfree(r); break; diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c index f7dc926f4ef1f..58ab5e84ceb7c 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c @@ -151,14 +151,14 @@ static int igt_ppgtt_alloc(void *arg) if (err) goto err_ppgtt; - if (!ppgtt->base.allocate_va_range) + if (!ppgtt->vm.allocate_va_range) goto err_ppgtt_cleanup; /* Check we can allocate the entire range */ for (size = 4096; - size <= ppgtt->base.total; + size <= ppgtt->vm.total; size <<= 2) { - err = ppgtt->base.allocate_va_range(&ppgtt->base, 0, size); + err = ppgtt->vm.allocate_va_range(&ppgtt->vm, 0, size); if (err) { if (err == -ENOMEM) { pr_info("[1] Ran out of memory for va_range [0 + %llx] [bit %d]\n", @@ -168,15 +168,15 @@ static int igt_ppgtt_alloc(void *arg) goto err_ppgtt_cleanup; } - ppgtt->base.clear_range(&ppgtt->base, 0, size); + ppgtt->vm.clear_range(&ppgtt->vm, 0, size); } /* Check we can incrementally allocate the entire range */ for (last = 0, size = 4096; - size <= ppgtt->base.total; + size <= ppgtt->vm.total; last = size, size <<= 2) { - err = ppgtt->base.allocate_va_range(&ppgtt->base, - last, size - last); + err = ppgtt->vm.allocate_va_range(&ppgtt->vm, + last, size - last); if (err) { if (err == -ENOMEM) { pr_info("[2] Ran out of memory for va_range [%llx + %llx] [bit %d]\n", @@ -188,7 +188,7 @@ static int igt_ppgtt_alloc(void *arg) } err_ppgtt_cleanup: - ppgtt->base.cleanup(&ppgtt->base); + ppgtt->vm.cleanup(&ppgtt->vm); err_ppgtt: mutex_unlock(&dev_priv->drm.struct_mutex); kfree(ppgtt); @@ -987,12 +987,12 @@ static int exercise_ppgtt(struct drm_i915_private *dev_priv, err = PTR_ERR(ppgtt); goto out_unlock; } - GEM_BUG_ON(offset_in_page(ppgtt->base.total)); - GEM_BUG_ON(ppgtt->base.closed); + GEM_BUG_ON(offset_in_page(ppgtt->vm.total)); + GEM_BUG_ON(ppgtt->vm.closed); - err = func(dev_priv, &ppgtt->base, 0, ppgtt->base.total, end_time); + err = func(dev_priv, &ppgtt->vm, 0, ppgtt->vm.total, end_time); - i915_ppgtt_close(&ppgtt->base); + i915_ppgtt_close(&ppgtt->vm); i915_ppgtt_put(ppgtt); out_unlock: mutex_unlock(&dev_priv->drm.struct_mutex); @@ -1061,18 +1061,18 @@ static int exercise_ggtt(struct drm_i915_private *i915, mutex_lock(&i915->drm.struct_mutex); restart: - list_sort(NULL, &ggtt->base.mm.hole_stack, sort_holes); - drm_mm_for_each_hole(node, &ggtt->base.mm, hole_start, hole_end) { + list_sort(NULL, &ggtt->vm.mm.hole_stack, sort_holes); + drm_mm_for_each_hole(node, &ggtt->vm.mm, hole_start, hole_end) { if (hole_start < last) continue; - if (ggtt->base.mm.color_adjust) - ggtt->base.mm.color_adjust(node, 0, - &hole_start, &hole_end); + if (ggtt->vm.mm.color_adjust) + ggtt->vm.mm.color_adjust(node, 0, + &hole_start, &hole_end); if (hole_start >= hole_end) continue; - err = func(i915, &ggtt->base, hole_start, hole_end, end_time); + err = func(i915, &ggtt->vm, hole_start, hole_end, end_time); if (err) break; @@ -1134,7 +1134,7 @@ static int igt_ggtt_page(void *arg) goto out_free; memset(&tmp, 0, sizeof(tmp)); - err = drm_mm_insert_node_in_range(&ggtt->base.mm, &tmp, + err = drm_mm_insert_node_in_range(&ggtt->vm.mm, &tmp, count * PAGE_SIZE, 0, I915_COLOR_UNEVICTABLE, 0, ggtt->mappable_end, @@ -1147,9 +1147,9 @@ static int igt_ggtt_page(void *arg) for (n = 0; n < count; n++) { u64 offset = tmp.start + n * PAGE_SIZE; - ggtt->base.insert_page(&ggtt->base, - i915_gem_object_get_dma_address(obj, 0), - offset, I915_CACHE_NONE, 0); + ggtt->vm.insert_page(&ggtt->vm, + i915_gem_object_get_dma_address(obj, 0), + offset, I915_CACHE_NONE, 0); } order = i915_random_order(count, &prng); @@ -1188,7 +1188,7 @@ static int igt_ggtt_page(void *arg) kfree(order); out_remove: - ggtt->base.clear_range(&ggtt->base, tmp.start, tmp.size); + ggtt->vm.clear_range(&ggtt->vm, tmp.start, tmp.size); intel_runtime_pm_put(i915); drm_mm_remove_node(&tmp); out_unpin: @@ -1229,7 +1229,7 @@ static int exercise_mock(struct drm_i915_private *i915, ppgtt = ctx->ppgtt; GEM_BUG_ON(!ppgtt); - err = func(i915, &ppgtt->base, 0, ppgtt->base.total, end_time); + err = func(i915, &ppgtt->vm, 0, ppgtt->vm.total, end_time); mock_context_close(ctx); return err; @@ -1270,7 +1270,7 @@ static int igt_gtt_reserve(void *arg) /* Start by filling the GGTT */ for (total = 0; - total + 2*I915_GTT_PAGE_SIZE <= i915->ggtt.base.total; + total + 2*I915_GTT_PAGE_SIZE <= i915->ggtt.vm.total; total += 2*I915_GTT_PAGE_SIZE) { struct i915_vma *vma; @@ -1288,20 +1288,20 @@ static int igt_gtt_reserve(void *arg) list_add(&obj->st_link, &objects); - vma = i915_vma_instance(obj, &i915->ggtt.base, NULL); + vma = i915_vma_instance(obj, &i915->ggtt.vm, NULL); if (IS_ERR(vma)) { err = PTR_ERR(vma); goto out; } - err = i915_gem_gtt_reserve(&i915->ggtt.base, &vma->node, + err = i915_gem_gtt_reserve(&i915->ggtt.vm, &vma->node, obj->base.size, total, obj->cache_level, 0); if (err) { pr_err("i915_gem_gtt_reserve (pass 1) failed at %llu/%llu with err=%d\n", - total, i915->ggtt.base.total, err); + total, i915->ggtt.vm.total, err); goto out; } track_vma_bind(vma); @@ -1319,7 +1319,7 @@ static int igt_gtt_reserve(void *arg) /* Now we start forcing evictions */ for (total = I915_GTT_PAGE_SIZE; - total + 2*I915_GTT_PAGE_SIZE <= i915->ggtt.base.total; + total + 2*I915_GTT_PAGE_SIZE <= i915->ggtt.vm.total; total += 2*I915_GTT_PAGE_SIZE) { struct i915_vma *vma; @@ -1337,20 +1337,20 @@ static int igt_gtt_reserve(void *arg) list_add(&obj->st_link, &objects); - vma = i915_vma_instance(obj, &i915->ggtt.base, NULL); + vma = i915_vma_instance(obj, &i915->ggtt.vm, NULL); if (IS_ERR(vma)) { err = PTR_ERR(vma); goto out; } - err = i915_gem_gtt_reserve(&i915->ggtt.base, &vma->node, + err = i915_gem_gtt_reserve(&i915->ggtt.vm, &vma->node, obj->base.size, total, obj->cache_level, 0); if (err) { pr_err("i915_gem_gtt_reserve (pass 2) failed at %llu/%llu with err=%d\n", - total, i915->ggtt.base.total, err); + total, i915->ggtt.vm.total, err); goto out; } track_vma_bind(vma); @@ -1371,7 +1371,7 @@ static int igt_gtt_reserve(void *arg) struct i915_vma *vma; u64 offset; - vma = i915_vma_instance(obj, &i915->ggtt.base, NULL); + vma = i915_vma_instance(obj, &i915->ggtt.vm, NULL); if (IS_ERR(vma)) { err = PTR_ERR(vma); goto out; @@ -1383,18 +1383,18 @@ static int igt_gtt_reserve(void *arg) goto out; } - offset = random_offset(0, i915->ggtt.base.total, + offset = random_offset(0, i915->ggtt.vm.total, 2*I915_GTT_PAGE_SIZE, I915_GTT_MIN_ALIGNMENT); - err = i915_gem_gtt_reserve(&i915->ggtt.base, &vma->node, + err = i915_gem_gtt_reserve(&i915->ggtt.vm, &vma->node, obj->base.size, offset, obj->cache_level, 0); if (err) { pr_err("i915_gem_gtt_reserve (pass 3) failed at %llu/%llu with err=%d\n", - total, i915->ggtt.base.total, err); + total, i915->ggtt.vm.total, err); goto out; } track_vma_bind(vma); @@ -1429,8 +1429,8 @@ static int igt_gtt_insert(void *arg) u64 start, end; } invalid_insert[] = { { - i915->ggtt.base.total + I915_GTT_PAGE_SIZE, 0, - 0, i915->ggtt.base.total, + i915->ggtt.vm.total + I915_GTT_PAGE_SIZE, 0, + 0, i915->ggtt.vm.total, }, { 2*I915_GTT_PAGE_SIZE, 0, @@ -1460,7 +1460,7 @@ static int igt_gtt_insert(void *arg) /* Check a couple of obviously invalid requests */ for (ii = invalid_insert; ii->size; ii++) { - err = i915_gem_gtt_insert(&i915->ggtt.base, &tmp, + err = i915_gem_gtt_insert(&i915->ggtt.vm, &tmp, ii->size, ii->alignment, I915_COLOR_UNEVICTABLE, ii->start, ii->end, @@ -1475,7 +1475,7 @@ static int igt_gtt_insert(void *arg) /* Start by filling the GGTT */ for (total = 0; - total + I915_GTT_PAGE_SIZE <= i915->ggtt.base.total; + total + I915_GTT_PAGE_SIZE <= i915->ggtt.vm.total; total += I915_GTT_PAGE_SIZE) { struct i915_vma *vma; @@ -1493,15 +1493,15 @@ static int igt_gtt_insert(void *arg) list_add(&obj->st_link, &objects); - vma = i915_vma_instance(obj, &i915->ggtt.base, NULL); + vma = i915_vma_instance(obj, &i915->ggtt.vm, NULL); if (IS_ERR(vma)) { err = PTR_ERR(vma); goto out; } - err = i915_gem_gtt_insert(&i915->ggtt.base, &vma->node, + err = i915_gem_gtt_insert(&i915->ggtt.vm, &vma->node, obj->base.size, 0, obj->cache_level, - 0, i915->ggtt.base.total, + 0, i915->ggtt.vm.total, 0); if (err == -ENOSPC) { /* maxed out the GGTT space */ @@ -1510,7 +1510,7 @@ static int igt_gtt_insert(void *arg) } if (err) { pr_err("i915_gem_gtt_insert (pass 1) failed at %llu/%llu with err=%d\n", - total, i915->ggtt.base.total, err); + total, i915->ggtt.vm.total, err); goto out; } track_vma_bind(vma); @@ -1522,7 +1522,7 @@ static int igt_gtt_insert(void *arg) list_for_each_entry(obj, &objects, st_link) { struct i915_vma *vma; - vma = i915_vma_instance(obj, &i915->ggtt.base, NULL); + vma = i915_vma_instance(obj, &i915->ggtt.vm, NULL); if (IS_ERR(vma)) { err = PTR_ERR(vma); goto out; @@ -1542,7 +1542,7 @@ static int igt_gtt_insert(void *arg) struct i915_vma *vma; u64 offset; - vma = i915_vma_instance(obj, &i915->ggtt.base, NULL); + vma = i915_vma_instance(obj, &i915->ggtt.vm, NULL); if (IS_ERR(vma)) { err = PTR_ERR(vma); goto out; @@ -1557,13 +1557,13 @@ static int igt_gtt_insert(void *arg) goto out; } - err = i915_gem_gtt_insert(&i915->ggtt.base, &vma->node, + err = i915_gem_gtt_insert(&i915->ggtt.vm, &vma->node, obj->base.size, 0, obj->cache_level, - 0, i915->ggtt.base.total, + 0, i915->ggtt.vm.total, 0); if (err) { pr_err("i915_gem_gtt_insert (pass 2) failed at %llu/%llu with err=%d\n", - total, i915->ggtt.base.total, err); + total, i915->ggtt.vm.total, err); goto out; } track_vma_bind(vma); @@ -1579,7 +1579,7 @@ static int igt_gtt_insert(void *arg) /* And then force evictions */ for (total = 0; - total + 2*I915_GTT_PAGE_SIZE <= i915->ggtt.base.total; + total + 2*I915_GTT_PAGE_SIZE <= i915->ggtt.vm.total; total += 2*I915_GTT_PAGE_SIZE) { struct i915_vma *vma; @@ -1597,19 +1597,19 @@ static int igt_gtt_insert(void *arg) list_add(&obj->st_link, &objects); - vma = i915_vma_instance(obj, &i915->ggtt.base, NULL); + vma = i915_vma_instance(obj, &i915->ggtt.vm, NULL); if (IS_ERR(vma)) { err = PTR_ERR(vma); goto out; } - err = i915_gem_gtt_insert(&i915->ggtt.base, &vma->node, + err = i915_gem_gtt_insert(&i915->ggtt.vm, &vma->node, obj->base.size, 0, obj->cache_level, - 0, i915->ggtt.base.total, + 0, i915->ggtt.vm.total, 0); if (err) { pr_err("i915_gem_gtt_insert (pass 3) failed at %llu/%llu with err=%d\n", - total, i915->ggtt.base.total, err); + total, i915->ggtt.vm.total, err); goto out; } track_vma_bind(vma); @@ -1669,7 +1669,7 @@ int i915_gem_gtt_live_selftests(struct drm_i915_private *i915) SUBTEST(igt_ggtt_page), }; - GEM_BUG_ON(offset_in_page(i915->ggtt.base.total)); + GEM_BUG_ON(offset_in_page(i915->ggtt.vm.total)); return i915_subtests(tests, i915); } diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_object.c b/drivers/gpu/drm/i915/selftests/i915_gem_object.c index fbdb2419d418c..2b2dde94526f7 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_object.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_object.c @@ -113,7 +113,7 @@ static int igt_gem_huge(void *arg) obj = huge_gem_object(i915, nreal * PAGE_SIZE, - i915->ggtt.base.total + PAGE_SIZE); + i915->ggtt.vm.total + PAGE_SIZE); if (IS_ERR(obj)) return PTR_ERR(obj); @@ -311,7 +311,7 @@ static int igt_partial_tiling(void *arg) obj = huge_gem_object(i915, nreal << PAGE_SHIFT, - (1 + next_prime_number(i915->ggtt.base.total >> PAGE_SHIFT)) << PAGE_SHIFT); + (1 + next_prime_number(i915->ggtt.vm.total >> PAGE_SHIFT)) << PAGE_SHIFT); if (IS_ERR(obj)) return PTR_ERR(obj); @@ -440,7 +440,7 @@ static int make_obj_busy(struct drm_i915_gem_object *obj) struct i915_vma *vma; int err; - vma = i915_vma_instance(obj, &i915->ggtt.base, NULL); + vma = i915_vma_instance(obj, &i915->ggtt.vm, NULL); if (IS_ERR(vma)) return PTR_ERR(vma); diff --git a/drivers/gpu/drm/i915/selftests/i915_request.c b/drivers/gpu/drm/i915/selftests/i915_request.c index 94bc2e1898a4d..a3a89aadeccb0 100644 --- a/drivers/gpu/drm/i915/selftests/i915_request.c +++ b/drivers/gpu/drm/i915/selftests/i915_request.c @@ -430,7 +430,7 @@ static struct i915_vma *empty_batch(struct drm_i915_private *i915) if (err) goto err; - vma = i915_vma_instance(obj, &i915->ggtt.base, NULL); + vma = i915_vma_instance(obj, &i915->ggtt.vm, NULL); if (IS_ERR(vma)) { err = PTR_ERR(vma); goto err; @@ -555,7 +555,8 @@ static int live_empty_request(void *arg) static struct i915_vma *recursive_batch(struct drm_i915_private *i915) { struct i915_gem_context *ctx = i915->kernel_context; - struct i915_address_space *vm = ctx->ppgtt ? &ctx->ppgtt->base : &i915->ggtt.base; + struct i915_address_space *vm = + ctx->ppgtt ? &ctx->ppgtt->vm : &i915->ggtt.vm; struct drm_i915_gem_object *obj; const int gen = INTEL_GEN(i915); struct i915_vma *vma; diff --git a/drivers/gpu/drm/i915/selftests/i915_vma.c b/drivers/gpu/drm/i915/selftests/i915_vma.c index e90f97236e505..8400a8cc5cf20 100644 --- a/drivers/gpu/drm/i915/selftests/i915_vma.c +++ b/drivers/gpu/drm/i915/selftests/i915_vma.c @@ -35,7 +35,7 @@ static bool assert_vma(struct i915_vma *vma, { bool ok = true; - if (vma->vm != &ctx->ppgtt->base) { + if (vma->vm != &ctx->ppgtt->vm) { pr_err("VMA created with wrong VM\n"); ok = false; } @@ -110,8 +110,7 @@ static int create_vmas(struct drm_i915_private *i915, list_for_each_entry(obj, objects, st_link) { for (pinned = 0; pinned <= 1; pinned++) { list_for_each_entry(ctx, contexts, link) { - struct i915_address_space *vm = - &ctx->ppgtt->base; + struct i915_address_space *vm = &ctx->ppgtt->vm; struct i915_vma *vma; int err; @@ -259,12 +258,12 @@ static int igt_vma_pin1(void *arg) VALID(0, PIN_GLOBAL | PIN_OFFSET_BIAS | 8192), VALID(0, PIN_GLOBAL | PIN_OFFSET_BIAS | (i915->ggtt.mappable_end - 4096)), VALID(0, PIN_GLOBAL | PIN_MAPPABLE | PIN_OFFSET_BIAS | (i915->ggtt.mappable_end - 4096)), - VALID(0, PIN_GLOBAL | PIN_OFFSET_BIAS | (i915->ggtt.base.total - 4096)), + VALID(0, PIN_GLOBAL | PIN_OFFSET_BIAS | (i915->ggtt.vm.total - 4096)), VALID(0, PIN_GLOBAL | PIN_MAPPABLE | PIN_OFFSET_FIXED | (i915->ggtt.mappable_end - 4096)), INVALID(0, PIN_GLOBAL | PIN_MAPPABLE | PIN_OFFSET_FIXED | i915->ggtt.mappable_end), - VALID(0, PIN_GLOBAL | PIN_OFFSET_FIXED | (i915->ggtt.base.total - 4096)), - INVALID(0, PIN_GLOBAL | PIN_OFFSET_FIXED | i915->ggtt.base.total), + VALID(0, PIN_GLOBAL | PIN_OFFSET_FIXED | (i915->ggtt.vm.total - 4096)), + INVALID(0, PIN_GLOBAL | PIN_OFFSET_FIXED | i915->ggtt.vm.total), INVALID(0, PIN_GLOBAL | PIN_OFFSET_FIXED | round_down(U64_MAX, PAGE_SIZE)), VALID(4096, PIN_GLOBAL), @@ -272,12 +271,12 @@ static int igt_vma_pin1(void *arg) VALID(i915->ggtt.mappable_end - 4096, PIN_GLOBAL | PIN_MAPPABLE), VALID(i915->ggtt.mappable_end, PIN_GLOBAL | PIN_MAPPABLE), NOSPACE(i915->ggtt.mappable_end + 4096, PIN_GLOBAL | PIN_MAPPABLE), - VALID(i915->ggtt.base.total - 4096, PIN_GLOBAL), - VALID(i915->ggtt.base.total, PIN_GLOBAL), - NOSPACE(i915->ggtt.base.total + 4096, PIN_GLOBAL), + VALID(i915->ggtt.vm.total - 4096, PIN_GLOBAL), + VALID(i915->ggtt.vm.total, PIN_GLOBAL), + NOSPACE(i915->ggtt.vm.total + 4096, PIN_GLOBAL), NOSPACE(round_down(U64_MAX, PAGE_SIZE), PIN_GLOBAL), INVALID(8192, PIN_GLOBAL | PIN_MAPPABLE | PIN_OFFSET_FIXED | (i915->ggtt.mappable_end - 4096)), - INVALID(8192, PIN_GLOBAL | PIN_OFFSET_FIXED | (i915->ggtt.base.total - 4096)), + INVALID(8192, PIN_GLOBAL | PIN_OFFSET_FIXED | (i915->ggtt.vm.total - 4096)), INVALID(8192, PIN_GLOBAL | PIN_OFFSET_FIXED | (round_down(U64_MAX, PAGE_SIZE) - 4096)), VALID(8192, PIN_GLOBAL | PIN_OFFSET_BIAS | (i915->ggtt.mappable_end - 4096)), @@ -289,9 +288,9 @@ static int igt_vma_pin1(void *arg) * variable start, end and size. */ NOSPACE(0, PIN_GLOBAL | PIN_MAPPABLE | PIN_OFFSET_BIAS | i915->ggtt.mappable_end), - NOSPACE(0, PIN_GLOBAL | PIN_OFFSET_BIAS | i915->ggtt.base.total), + NOSPACE(0, PIN_GLOBAL | PIN_OFFSET_BIAS | i915->ggtt.vm.total), NOSPACE(8192, PIN_GLOBAL | PIN_MAPPABLE | PIN_OFFSET_BIAS | (i915->ggtt.mappable_end - 4096)), - NOSPACE(8192, PIN_GLOBAL | PIN_OFFSET_BIAS | (i915->ggtt.base.total - 4096)), + NOSPACE(8192, PIN_GLOBAL | PIN_OFFSET_BIAS | (i915->ggtt.vm.total - 4096)), #endif { }, #undef NOSPACE @@ -307,13 +306,13 @@ static int igt_vma_pin1(void *arg) * focusing on error handling of boundary conditions. */ - GEM_BUG_ON(!drm_mm_clean(&i915->ggtt.base.mm)); + GEM_BUG_ON(!drm_mm_clean(&i915->ggtt.vm.mm)); obj = i915_gem_object_create_internal(i915, PAGE_SIZE); if (IS_ERR(obj)) return PTR_ERR(obj); - vma = checked_vma_instance(obj, &i915->ggtt.base, NULL); + vma = checked_vma_instance(obj, &i915->ggtt.vm, NULL); if (IS_ERR(vma)) goto out; @@ -405,7 +404,7 @@ static unsigned int rotated_size(const struct intel_rotation_plane_info *a, static int igt_vma_rotate(void *arg) { struct drm_i915_private *i915 = arg; - struct i915_address_space *vm = &i915->ggtt.base; + struct i915_address_space *vm = &i915->ggtt.vm; struct drm_i915_gem_object *obj; const struct intel_rotation_plane_info planes[] = { { .width = 1, .height = 1, .stride = 1 }, @@ -604,7 +603,7 @@ static bool assert_pin(struct i915_vma *vma, static int igt_vma_partial(void *arg) { struct drm_i915_private *i915 = arg; - struct i915_address_space *vm = &i915->ggtt.base; + struct i915_address_space *vm = &i915->ggtt.vm; const unsigned int npages = 1021; /* prime! */ struct drm_i915_gem_object *obj; const struct phase { diff --git a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c index 2091e3a6a5be8..390a157b37c3f 100644 --- a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c +++ b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c @@ -107,8 +107,8 @@ static int emit_recurse_batch(struct hang *h, struct drm_i915_private *i915 = h->i915; struct i915_address_space *vm = rq->gem_context->ppgtt ? - &rq->gem_context->ppgtt->base : - &i915->ggtt.base; + &rq->gem_context->ppgtt->vm : + &i915->ggtt.vm; struct i915_vma *hws, *vma; unsigned int flags; u32 *batch; diff --git a/drivers/gpu/drm/i915/selftests/intel_lrc.c b/drivers/gpu/drm/i915/selftests/intel_lrc.c index 68cb9126b3e14..0b6da08c8caec 100644 --- a/drivers/gpu/drm/i915/selftests/intel_lrc.c +++ b/drivers/gpu/drm/i915/selftests/intel_lrc.c @@ -83,7 +83,7 @@ static int emit_recurse_batch(struct spinner *spin, struct i915_request *rq, u32 arbitration_command) { - struct i915_address_space *vm = &rq->gem_context->ppgtt->base; + struct i915_address_space *vm = &rq->gem_context->ppgtt->vm; struct i915_vma *hws, *vma; u32 *batch; int err; diff --git a/drivers/gpu/drm/i915/selftests/intel_workarounds.c b/drivers/gpu/drm/i915/selftests/intel_workarounds.c index 17444a3abbb93..f1cfb0fb6bea4 100644 --- a/drivers/gpu/drm/i915/selftests/intel_workarounds.c +++ b/drivers/gpu/drm/i915/selftests/intel_workarounds.c @@ -33,7 +33,7 @@ read_nonprivs(struct i915_gem_context *ctx, struct intel_engine_cs *engine) memset(cs, 0xc5, PAGE_SIZE); i915_gem_object_unpin_map(result); - vma = i915_vma_instance(result, &engine->i915->ggtt.base, NULL); + vma = i915_vma_instance(result, &engine->i915->ggtt.vm, NULL); if (IS_ERR(vma)) { err = PTR_ERR(vma); goto err_obj; diff --git a/drivers/gpu/drm/i915/selftests/mock_gtt.c b/drivers/gpu/drm/i915/selftests/mock_gtt.c index 36c1120889405..556c546f2715b 100644 --- a/drivers/gpu/drm/i915/selftests/mock_gtt.c +++ b/drivers/gpu/drm/i915/selftests/mock_gtt.c @@ -66,25 +66,25 @@ mock_ppgtt(struct drm_i915_private *i915, return NULL; kref_init(&ppgtt->ref); - ppgtt->base.i915 = i915; - ppgtt->base.total = round_down(U64_MAX, PAGE_SIZE); - ppgtt->base.file = ERR_PTR(-ENODEV); - - INIT_LIST_HEAD(&ppgtt->base.active_list); - INIT_LIST_HEAD(&ppgtt->base.inactive_list); - INIT_LIST_HEAD(&ppgtt->base.unbound_list); - - INIT_LIST_HEAD(&ppgtt->base.global_link); - drm_mm_init(&ppgtt->base.mm, 0, ppgtt->base.total); - - ppgtt->base.clear_range = nop_clear_range; - ppgtt->base.insert_page = mock_insert_page; - ppgtt->base.insert_entries = mock_insert_entries; - ppgtt->base.bind_vma = mock_bind_ppgtt; - ppgtt->base.unbind_vma = mock_unbind_ppgtt; - ppgtt->base.set_pages = ppgtt_set_pages; - ppgtt->base.clear_pages = clear_pages; - ppgtt->base.cleanup = mock_cleanup; + ppgtt->vm.i915 = i915; + ppgtt->vm.total = round_down(U64_MAX, PAGE_SIZE); + ppgtt->vm.file = ERR_PTR(-ENODEV); + + INIT_LIST_HEAD(&ppgtt->vm.active_list); + INIT_LIST_HEAD(&ppgtt->vm.inactive_list); + INIT_LIST_HEAD(&ppgtt->vm.unbound_list); + + INIT_LIST_HEAD(&ppgtt->vm.global_link); + drm_mm_init(&ppgtt->vm.mm, 0, ppgtt->vm.total); + + ppgtt->vm.clear_range = nop_clear_range; + ppgtt->vm.insert_page = mock_insert_page; + ppgtt->vm.insert_entries = mock_insert_entries; + ppgtt->vm.bind_vma = mock_bind_ppgtt; + ppgtt->vm.unbind_vma = mock_unbind_ppgtt; + ppgtt->vm.set_pages = ppgtt_set_pages; + ppgtt->vm.clear_pages = clear_pages; + ppgtt->vm.cleanup = mock_cleanup; return ppgtt; } @@ -107,27 +107,27 @@ void mock_init_ggtt(struct drm_i915_private *i915) INIT_LIST_HEAD(&i915->vm_list); - ggtt->base.i915 = i915; + ggtt->vm.i915 = i915; ggtt->gmadr = (struct resource) DEFINE_RES_MEM(0, 2048 * PAGE_SIZE); ggtt->mappable_end = resource_size(&ggtt->gmadr); - ggtt->base.total = 4096 * PAGE_SIZE; - - ggtt->base.clear_range = nop_clear_range; - ggtt->base.insert_page = mock_insert_page; - ggtt->base.insert_entries = mock_insert_entries; - ggtt->base.bind_vma = mock_bind_ggtt; - ggtt->base.unbind_vma = mock_unbind_ggtt; - ggtt->base.set_pages = ggtt_set_pages; - ggtt->base.clear_pages = clear_pages; - ggtt->base.cleanup = mock_cleanup; - - i915_address_space_init(&ggtt->base, i915, "global"); + ggtt->vm.total = 4096 * PAGE_SIZE; + + ggtt->vm.clear_range = nop_clear_range; + ggtt->vm.insert_page = mock_insert_page; + ggtt->vm.insert_entries = mock_insert_entries; + ggtt->vm.bind_vma = mock_bind_ggtt; + ggtt->vm.unbind_vma = mock_unbind_ggtt; + ggtt->vm.set_pages = ggtt_set_pages; + ggtt->vm.clear_pages = clear_pages; + ggtt->vm.cleanup = mock_cleanup; + + i915_address_space_init(&ggtt->vm, i915, "global"); } void mock_fini_ggtt(struct drm_i915_private *i915) { struct i915_ggtt *ggtt = &i915->ggtt; - i915_address_space_fini(&ggtt->base); + i915_address_space_fini(&ggtt->vm); } -- GitLab From cf68f0c3a07b092bca92e7b4f1b3893ab454bd38 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Wed, 6 Jun 2018 15:41:53 +0100 Subject: [PATCH 0193/1506] drm/i915: Mark i915.inject_load_failure as being hit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we reach the magic value and do inject a fault into our module load, mark the module option as being hit. Since we fail from inside pci probe, the module load isn't actually aborted and the module (and parameters) are left lingering. igt can then inspect the parameter on its synchronous completion of modprobe to see if the fault injection was successful, and will keeping on injecting new faults until the module succeeds in loading having surpassed the number of fault points. v2: Reset to 0 after being hit; Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: MichaÅ‚ Winiarski <michal.winiarski@intel.com> Cc: Imre Deak <imre.deak@intel.com> Reviewed-by: MichaÅ‚ Winiarski <michal.winiarski@intel.com> Reviewed-by: Michal Wajdeczko <michal.wajdeczko@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180606144153.4244-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_drv.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 83ce9c1ec170a..0a1b09bb658fe 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -67,6 +67,7 @@ bool __i915_inject_load_failure(const char *func, int line) if (++i915_load_fail_count == i915_modparams.inject_load_failure) { DRM_INFO("Injecting failure at checkpoint %u [%s:%d]\n", i915_modparams.inject_load_failure, func, line); + i915_modparams.inject_load_failure = 0; return true; } @@ -117,16 +118,15 @@ __i915_printk(struct drm_i915_private *dev_priv, const char *level, static bool i915_error_injected(struct drm_i915_private *dev_priv) { #if IS_ENABLED(CONFIG_DRM_I915_DEBUG) - return i915_modparams.inject_load_failure && - i915_load_fail_count == i915_modparams.inject_load_failure; + return i915_load_fail_count && !i915_modparams.inject_load_failure; #else return false; #endif } -#define i915_load_error(dev_priv, fmt, ...) \ - __i915_printk(dev_priv, \ - i915_error_injected(dev_priv) ? KERN_DEBUG : KERN_ERR, \ +#define i915_load_error(i915, fmt, ...) \ + __i915_printk(i915, \ + i915_error_injected(i915) ? KERN_DEBUG : KERN_ERR, \ fmt, ##__VA_ARGS__) /* Map PCH device id to PCH type, or PCH_NONE if unknown. */ -- GitLab From 64b3c93649a652c2e4a25569f167378333338347 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Wed, 6 Jun 2018 21:51:28 +0100 Subject: [PATCH 0194/1506] drm/i915/gtt: Fix typo in fill_px() macro The macro declared the ppgtt parameter but implicitly used the local vm instead. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: Matthew Auld <matthew.william.auld@gmail.com> Reviewed-by: Matthew Auld <matthew.william.auld@gmail.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180606205128.25952-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_gtt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 029a5f4fbd92b..2b4a40a32b765 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -528,8 +528,8 @@ static void cleanup_page_dma(struct i915_address_space *vm, #define setup_px(vm, px) setup_page_dma((vm), px_base(px)) #define cleanup_px(vm, px) cleanup_page_dma((vm), px_base(px)) -#define fill_px(ppgtt, px, v) fill_page_dma((vm), px_base(px), (v)) -#define fill32_px(ppgtt, px, v) fill_page_dma_32((vm), px_base(px), (v)) +#define fill_px(vm, px, v) fill_page_dma((vm), px_base(px), (v)) +#define fill32_px(vm, px, v) fill_page_dma_32((vm), px_base(px), (v)) static void fill_page_dma(struct i915_address_space *vm, struct i915_page_dma *p, -- GitLab From 14c3f8425080a1ff97df7b81f7c339bf42c427a3 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi <rodrigo.vivi@intel.com> Date: Wed, 6 Jun 2018 15:10:47 -0700 Subject: [PATCH 0195/1506] drm/i915: Update DRIVER_DATE to 20180606 Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com> --- drivers/gpu/drm/i915/i915_drv.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index a4bb30c32a527..79209ee25c217 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -85,8 +85,8 @@ #define DRIVER_NAME "i915" #define DRIVER_DESC "Intel Graphics" -#define DRIVER_DATE "20180530" -#define DRIVER_TIMESTAMP 1527717651 +#define DRIVER_DATE "20180606" +#define DRIVER_TIMESTAMP 1528323047 /* Use I915_STATE_WARN(x) and I915_STATE_WARN_ON() (rather than WARN() and * WARN_ON()) for hw state sanity checks to check for unexpected conditions -- GitLab From 8571a05a9dd0986a788f03e4de1a42fc9235959f Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Wed, 6 Jun 2018 15:54:41 +0100 Subject: [PATCH 0196/1506] drm/i915: Use GEM suspend when aborting initialisation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As part of our GEM initialisation now, we send a request to the hardware in order to record the initial GPU state. This coupled with deferred idle workers, makes aborting on error tricky. We already have the mechanism in place to wait on the GPU and cancel all the deferred workers for suspend, so let's reuse it during the error teardown. It is already used in places for later init error handling, but doing so at this point is slightly ugly due to the mutex dance (it's ok, the module load is still single threaded). Testcase: igt/drv_module_reload/basic-reload-inject Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: MichaÅ‚ Winiarski <michal.winiarski@intel.com> Reviewed-by: MichaÅ‚ Winiarski <michal.winiarski@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180606145441.4460-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 86f1f9aaa1198..1074f47e6cdaf 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5514,8 +5514,12 @@ int i915_gem_init(struct drm_i915_private *dev_priv) * driver doesn't explode during runtime. */ err_init_hw: - i915_gem_wait_for_idle(dev_priv, I915_WAIT_LOCKED); - i915_gem_contexts_lost(dev_priv); + mutex_unlock(&dev_priv->drm.struct_mutex); + + WARN_ON(i915_gem_suspend(dev_priv)); + i915_gem_suspend_late(dev_priv); + + mutex_lock(&dev_priv->drm.struct_mutex); intel_uc_fini_hw(dev_priv); err_uc_init: intel_uc_fini(dev_priv); -- GitLab From 521370106d0d614fca76c7001bf5a82e1250fa27 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Wed, 6 Jun 2018 22:45:20 +0100 Subject: [PATCH 0197/1506] drm/i915: Change i915_gem_fault() to return vm_fault_t In preparation for vm_fault_t becoming a distinct type, convert the fault handler (i915_gem_fault()) over to the new interface. Based on a patch by Souptick Joarder References: 1c8f422059ae ("mm: change return type to vm_fault_t") Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Souptick Joarder <jrdr.linux@gmail.com> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Matthew Auld <matthew.william.auld@gmail.com> Reviewed-by: Matthew Auld <matthew.william.auld@gmail.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180606214520.20220-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_drv.h | 3 ++- drivers/gpu/drm/i915/i915_gem.c | 21 +++++++-------------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 79209ee25c217..c4073666f1ca9 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -40,6 +40,7 @@ #include <linux/hash.h> #include <linux/intel-iommu.h> #include <linux/kref.h> +#include <linux/mm_types.h> #include <linux/perf_event.h> #include <linux/pm_qos.h> #include <linux/reservation.h> @@ -3174,7 +3175,7 @@ int i915_gem_wait_for_idle(struct drm_i915_private *dev_priv, int __must_check i915_gem_suspend(struct drm_i915_private *dev_priv); void i915_gem_suspend_late(struct drm_i915_private *dev_priv); void i915_gem_resume(struct drm_i915_private *dev_priv); -int i915_gem_fault(struct vm_fault *vmf); +vm_fault_t i915_gem_fault(struct vm_fault *vmf); int i915_gem_object_wait(struct drm_i915_gem_object *obj, unsigned int flags, long timeout, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 1074f47e6cdaf..fd882eb389d22 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1995,7 +1995,7 @@ compute_partial_view(struct drm_i915_gem_object *obj, * The current feature set supported by i915_gem_fault() and thus GTT mmaps * is exposed via I915_PARAM_MMAP_GTT_VERSION (see i915_gem_mmap_gtt_version). */ -int i915_gem_fault(struct vm_fault *vmf) +vm_fault_t i915_gem_fault(struct vm_fault *vmf) { #define MIN_CHUNK_PAGES (SZ_1M >> PAGE_SHIFT) struct vm_area_struct *area = vmf->vma; @@ -2112,10 +2112,8 @@ int i915_gem_fault(struct vm_fault *vmf) * fail). But any other -EIO isn't ours (e.g. swap in failure) * and so needs to be reported. */ - if (!i915_terminally_wedged(&dev_priv->gpu_error)) { - ret = VM_FAULT_SIGBUS; - break; - } + if (!i915_terminally_wedged(&dev_priv->gpu_error)) + return VM_FAULT_SIGBUS; case -EAGAIN: /* * EAGAIN means the gpu is hung and we'll wait for the error @@ -2130,21 +2128,16 @@ int i915_gem_fault(struct vm_fault *vmf) * EBUSY is ok: this just means that another thread * already did the job. */ - ret = VM_FAULT_NOPAGE; - break; + return VM_FAULT_NOPAGE; case -ENOMEM: - ret = VM_FAULT_OOM; - break; + return VM_FAULT_OOM; case -ENOSPC: case -EFAULT: - ret = VM_FAULT_SIGBUS; - break; + return VM_FAULT_SIGBUS; default: WARN_ONCE(ret, "unhandled error in i915_gem_fault: %i\n", ret); - ret = VM_FAULT_SIGBUS; - break; + return VM_FAULT_SIGBUS; } - return ret; } static void __i915_gem_object_release_mmap(struct drm_i915_gem_object *obj) -- GitLab From 520ea7c581bf3ba4761c1fb61c53b11767665b62 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 7 Jun 2018 16:40:45 +0100 Subject: [PATCH 0198/1506] drm/i915: Prepare for non-object vma In order to allow ourselves to use VMA to wrap other entities other than GEM objects, we need to allow for the vma->obj backpointer to be NULL. In most cases, we know we are operating on a GEM object and its vma, but we need the core code (such as i915_vma_pin/insert/bind/unbind) to work regardless of the innards. The remaining eyesore here is vma->obj->cache_level and related (but less of an issue) vma->obj->gt_ro. With a bit of care we should mirror those on the vma itself. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: Matthew Auld <matthew.william.auld@gmail.com> Reviewed-by: Matthew Auld <matthew.william.auld@gmail.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180607154047.9171-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_gtt.c | 7 +- drivers/gpu/drm/i915/i915_gpu_error.c | 3 + drivers/gpu/drm/i915/i915_vma.c | 96 ++++++++++++++++----------- drivers/gpu/drm/i915/i915_vma.h | 2 +- 4 files changed, 65 insertions(+), 43 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 2b4a40a32b765..7c45a516aa6b2 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -3588,8 +3588,11 @@ void i915_gem_restore_gtt_mappings(struct drm_i915_private *dev_priv) if (!i915_vma_unbind(vma)) continue; - WARN_ON(i915_vma_bind(vma, obj->cache_level, PIN_UPDATE)); - WARN_ON(i915_gem_object_set_to_gtt_domain(obj, false)); + WARN_ON(i915_vma_bind(vma, + obj ? obj->cache_level : 0, + PIN_UPDATE)); + if (obj) + WARN_ON(i915_gem_object_set_to_gtt_domain(obj, false)); } ggtt->vm.closed = false; diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 758234d20f4ea..df524c9cad408 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -1050,6 +1050,9 @@ static u32 capture_error_bo(struct drm_i915_error_buffer *err, int i = 0; list_for_each_entry(vma, head, vm_link) { + if (!vma->obj) + continue; + if (pinned_only && !i915_vma_is_pinned(vma)) continue; diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c index 912f16ffe7eea..b71265066cd16 100644 --- a/drivers/gpu/drm/i915/i915_vma.c +++ b/drivers/gpu/drm/i915/i915_vma.c @@ -345,7 +345,7 @@ void i915_vma_flush_writes(struct i915_vma *vma) void i915_vma_unpin_iomap(struct i915_vma *vma) { - lockdep_assert_held(&vma->obj->base.dev->struct_mutex); + lockdep_assert_held(&vma->vm->i915->drm.struct_mutex); GEM_BUG_ON(vma->iomap == NULL); @@ -365,6 +365,7 @@ void i915_vma_unpin_and_release(struct i915_vma **p_vma) return; obj = vma->obj; + GEM_BUG_ON(!obj); i915_vma_unpin(vma); i915_vma_close(vma); @@ -489,7 +490,7 @@ static int i915_vma_insert(struct i915_vma *vma, u64 size, u64 alignment, u64 flags) { struct drm_i915_private *dev_priv = vma->vm->i915; - struct drm_i915_gem_object *obj = vma->obj; + unsigned int cache_level; u64 start, end; int ret; @@ -524,16 +525,21 @@ i915_vma_insert(struct i915_vma *vma, u64 size, u64 alignment, u64 flags) * attempt to find space. */ if (size > end) { - DRM_DEBUG("Attempting to bind an object larger than the aperture: request=%llu [object=%zd] > %s aperture=%llu\n", - size, obj->base.size, - flags & PIN_MAPPABLE ? "mappable" : "total", + DRM_DEBUG("Attempting to bind an object larger than the aperture: request=%llu > %s aperture=%llu\n", + size, flags & PIN_MAPPABLE ? "mappable" : "total", end); return -ENOSPC; } - ret = i915_gem_object_pin_pages(obj); - if (ret) - return ret; + if (vma->obj) { + ret = i915_gem_object_pin_pages(vma->obj); + if (ret) + return ret; + + cache_level = vma->obj->cache_level; + } else { + cache_level = 0; + } GEM_BUG_ON(vma->pages); @@ -550,7 +556,7 @@ i915_vma_insert(struct i915_vma *vma, u64 size, u64 alignment, u64 flags) } ret = i915_gem_gtt_reserve(vma->vm, &vma->node, - size, offset, obj->cache_level, + size, offset, cache_level, flags); if (ret) goto err_clear; @@ -589,7 +595,7 @@ i915_vma_insert(struct i915_vma *vma, u64 size, u64 alignment, u64 flags) } ret = i915_gem_gtt_insert(vma->vm, &vma->node, - size, alignment, obj->cache_level, + size, alignment, cache_level, start, end, flags); if (ret) goto err_clear; @@ -598,23 +604,28 @@ i915_vma_insert(struct i915_vma *vma, u64 size, u64 alignment, u64 flags) GEM_BUG_ON(vma->node.start + vma->node.size > end); } GEM_BUG_ON(!drm_mm_node_allocated(&vma->node)); - GEM_BUG_ON(!i915_gem_valid_gtt_space(vma, obj->cache_level)); + GEM_BUG_ON(!i915_gem_valid_gtt_space(vma, cache_level)); list_move_tail(&vma->vm_link, &vma->vm->inactive_list); - spin_lock(&dev_priv->mm.obj_lock); - list_move_tail(&obj->mm.link, &dev_priv->mm.bound_list); - obj->bind_count++; - spin_unlock(&dev_priv->mm.obj_lock); + if (vma->obj) { + struct drm_i915_gem_object *obj = vma->obj; + + spin_lock(&dev_priv->mm.obj_lock); + list_move_tail(&obj->mm.link, &dev_priv->mm.bound_list); + obj->bind_count++; + spin_unlock(&dev_priv->mm.obj_lock); - assert_bind_count(obj); + assert_bind_count(obj); + } return 0; err_clear: vma->vm->clear_pages(vma); err_unpin: - i915_gem_object_unpin_pages(obj); + if (vma->obj) + i915_gem_object_unpin_pages(vma->obj); return ret; } @@ -622,7 +633,6 @@ static void i915_vma_remove(struct i915_vma *vma) { struct drm_i915_private *i915 = vma->vm->i915; - struct drm_i915_gem_object *obj = vma->obj; GEM_BUG_ON(!drm_mm_node_allocated(&vma->node)); GEM_BUG_ON(vma->flags & (I915_VMA_GLOBAL_BIND | I915_VMA_LOCAL_BIND)); @@ -632,20 +642,26 @@ i915_vma_remove(struct i915_vma *vma) drm_mm_remove_node(&vma->node); list_move_tail(&vma->vm_link, &vma->vm->unbound_list); - /* Since the unbound list is global, only move to that list if + /* + * Since the unbound list is global, only move to that list if * no more VMAs exist. */ - spin_lock(&i915->mm.obj_lock); - if (--obj->bind_count == 0) - list_move_tail(&obj->mm.link, &i915->mm.unbound_list); - spin_unlock(&i915->mm.obj_lock); - - /* And finally now the object is completely decoupled from this vma, - * we can drop its hold on the backing storage and allow it to be - * reaped by the shrinker. - */ - i915_gem_object_unpin_pages(obj); - assert_bind_count(obj); + if (vma->obj) { + struct drm_i915_gem_object *obj = vma->obj; + + spin_lock(&i915->mm.obj_lock); + if (--obj->bind_count == 0) + list_move_tail(&obj->mm.link, &i915->mm.unbound_list); + spin_unlock(&i915->mm.obj_lock); + + /* + * And finally now the object is completely decoupled from this + * vma, we can drop its hold on the backing storage and allow + * it to be reaped by the shrinker. + */ + i915_gem_object_unpin_pages(obj); + assert_bind_count(obj); + } } int __i915_vma_do_pin(struct i915_vma *vma, @@ -670,7 +686,7 @@ int __i915_vma_do_pin(struct i915_vma *vma, } GEM_BUG_ON(!drm_mm_node_allocated(&vma->node)); - ret = i915_vma_bind(vma, vma->obj->cache_level, flags); + ret = i915_vma_bind(vma, vma->obj ? vma->obj->cache_level : 0, flags); if (ret) goto err_remove; @@ -727,6 +743,7 @@ void i915_vma_reopen(struct i915_vma *vma) static void __i915_vma_destroy(struct i915_vma *vma) { + struct drm_i915_private *i915 = vma->vm->i915; int i; GEM_BUG_ON(vma->node.allocated); @@ -738,12 +755,13 @@ static void __i915_vma_destroy(struct i915_vma *vma) list_del(&vma->obj_link); list_del(&vma->vm_link); - rb_erase(&vma->obj_node, &vma->obj->vma_tree); + if (vma->obj) + rb_erase(&vma->obj_node, &vma->obj->vma_tree); if (!i915_vma_is_ggtt(vma)) i915_ppgtt_put(i915_vm_to_ppgtt(vma->vm)); - kmem_cache_free(to_i915(vma->obj->base.dev)->vmas, vma); + kmem_cache_free(i915->vmas, vma); } void i915_vma_destroy(struct i915_vma *vma) @@ -809,13 +827,13 @@ void i915_vma_revoke_mmap(struct i915_vma *vma) int i915_vma_unbind(struct i915_vma *vma) { - struct drm_i915_gem_object *obj = vma->obj; unsigned long active; int ret; - lockdep_assert_held(&obj->base.dev->struct_mutex); + lockdep_assert_held(&vma->vm->i915->drm.struct_mutex); - /* First wait upon any activity as retiring the request may + /* + * First wait upon any activity as retiring the request may * have side-effects such as unpinning or even unbinding this vma. */ might_sleep(); @@ -823,7 +841,8 @@ int i915_vma_unbind(struct i915_vma *vma) if (active) { int idx; - /* When a closed VMA is retired, it is unbound - eek. + /* + * When a closed VMA is retired, it is unbound - eek. * In order to prevent it from being recursively closed, * take a pin on the vma so that the second unbind is * aborted. @@ -861,9 +880,6 @@ int i915_vma_unbind(struct i915_vma *vma) if (!drm_mm_node_allocated(&vma->node)) return 0; - GEM_BUG_ON(obj->bind_count == 0); - GEM_BUG_ON(!i915_gem_object_has_pinned_pages(obj)); - if (i915_vma_is_map_and_fenceable(vma)) { /* * Check that we have flushed all writes through the GGTT diff --git a/drivers/gpu/drm/i915/i915_vma.h b/drivers/gpu/drm/i915/i915_vma.h index fc4294cfaa913..f0532f1a4953d 100644 --- a/drivers/gpu/drm/i915/i915_vma.h +++ b/drivers/gpu/drm/i915/i915_vma.h @@ -407,7 +407,7 @@ static inline void __i915_vma_unpin_fence(struct i915_vma *vma) static inline void i915_vma_unpin_fence(struct i915_vma *vma) { - lockdep_assert_held(&vma->obj->base.dev->struct_mutex); + /* lockdep_assert_held(&vma->vm->i915->drm.struct_mutex); */ if (vma->fence) __i915_vma_unpin_fence(vma); } -- GitLab From 93f2cde2a4f7947f6330ecfb9b27d13e2f4d43af Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 7 Jun 2018 16:40:46 +0100 Subject: [PATCH 0199/1506] drm/i915: Decouple vma vfuncs from vm To allow for future non-object backed vma, we need to be able to specialise the callbacks for binding, et al, the vma. For example, instead of calling vma->vm->bind_vma(), we now call vma->ops->bind_vma(). This gives us the opportunity to later override the operation for a custom vma. v2: flip order of unbind/bind Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: Matthew Auld <matthew.william.auld@gmail.com> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180607154047.9171-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_gtt.c | 57 ++++++++++++----------- drivers/gpu/drm/i915/i915_gem_gtt.h | 27 +++++++---- drivers/gpu/drm/i915/i915_vma.c | 11 +++-- drivers/gpu/drm/i915/i915_vma.h | 1 + drivers/gpu/drm/i915/selftests/mock_gtt.c | 18 +++---- 5 files changed, 66 insertions(+), 48 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 7c45a516aa6b2..d841bf296d191 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1616,12 +1616,13 @@ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt) gen8_ppgtt_notify_vgt(ppgtt, true); ppgtt->vm.cleanup = gen8_ppgtt_cleanup; - ppgtt->vm.bind_vma = gen8_ppgtt_bind_vma; - ppgtt->vm.unbind_vma = ppgtt_unbind_vma; - ppgtt->vm.set_pages = ppgtt_set_pages; - ppgtt->vm.clear_pages = clear_pages; ppgtt->debug_dump = gen8_dump_ppgtt; + ppgtt->vm.vma_ops.bind_vma = gen8_ppgtt_bind_vma; + ppgtt->vm.vma_ops.unbind_vma = ppgtt_unbind_vma; + ppgtt->vm.vma_ops.set_pages = ppgtt_set_pages; + ppgtt->vm.vma_ops.clear_pages = clear_pages; + return 0; free_scratch: @@ -2059,13 +2060,14 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) ppgtt->vm.clear_range = gen6_ppgtt_clear_range; ppgtt->vm.insert_entries = gen6_ppgtt_insert_entries; - ppgtt->vm.bind_vma = gen6_ppgtt_bind_vma; - ppgtt->vm.unbind_vma = ppgtt_unbind_vma; - ppgtt->vm.set_pages = ppgtt_set_pages; - ppgtt->vm.clear_pages = clear_pages; ppgtt->vm.cleanup = gen6_ppgtt_cleanup; ppgtt->debug_dump = gen6_dump_ppgtt; + ppgtt->vm.vma_ops.bind_vma = gen6_ppgtt_bind_vma; + ppgtt->vm.vma_ops.unbind_vma = ppgtt_unbind_vma; + ppgtt->vm.vma_ops.set_pages = ppgtt_set_pages; + ppgtt->vm.vma_ops.clear_pages = clear_pages; + DRM_DEBUG_DRIVER("Allocated pde space (%lldM) at GTT entry: %llx\n", ppgtt->node.size >> 20, ppgtt->node.start / PAGE_SIZE); @@ -2793,11 +2795,11 @@ int i915_gem_init_aliasing_ppgtt(struct drm_i915_private *i915) i915->mm.aliasing_ppgtt = ppgtt; - GEM_BUG_ON(ggtt->vm.bind_vma != ggtt_bind_vma); - ggtt->vm.bind_vma = aliasing_gtt_bind_vma; + GEM_BUG_ON(ggtt->vm.vma_ops.bind_vma != ggtt_bind_vma); + ggtt->vm.vma_ops.bind_vma = aliasing_gtt_bind_vma; - GEM_BUG_ON(ggtt->vm.unbind_vma != ggtt_unbind_vma); - ggtt->vm.unbind_vma = aliasing_gtt_unbind_vma; + GEM_BUG_ON(ggtt->vm.vma_ops.unbind_vma != ggtt_unbind_vma); + ggtt->vm.vma_ops.unbind_vma = aliasing_gtt_unbind_vma; return 0; @@ -2817,8 +2819,8 @@ void i915_gem_fini_aliasing_ppgtt(struct drm_i915_private *i915) i915_ppgtt_put(ppgtt); - ggtt->vm.bind_vma = ggtt_bind_vma; - ggtt->vm.unbind_vma = ggtt_unbind_vma; + ggtt->vm.vma_ops.bind_vma = ggtt_bind_vma; + ggtt->vm.vma_ops.unbind_vma = ggtt_unbind_vma; } int i915_gem_init_ggtt(struct drm_i915_private *dev_priv) @@ -3310,10 +3312,6 @@ static int gen8_gmch_probe(struct i915_ggtt *ggtt) ggtt->vm.total = (size / sizeof(gen8_pte_t)) << PAGE_SHIFT; ggtt->vm.cleanup = gen6_gmch_remove; - ggtt->vm.bind_vma = ggtt_bind_vma; - ggtt->vm.unbind_vma = ggtt_unbind_vma; - ggtt->vm.set_pages = ggtt_set_pages; - ggtt->vm.clear_pages = clear_pages; ggtt->vm.insert_page = gen8_ggtt_insert_page; ggtt->vm.clear_range = nop_clear_range; if (!USES_FULL_PPGTT(dev_priv) || intel_scanout_needs_vtd_wa(dev_priv)) @@ -3331,6 +3329,11 @@ static int gen8_gmch_probe(struct i915_ggtt *ggtt) ggtt->invalidate = gen6_ggtt_invalidate; + ggtt->vm.vma_ops.bind_vma = ggtt_bind_vma; + ggtt->vm.vma_ops.unbind_vma = ggtt_unbind_vma; + ggtt->vm.vma_ops.set_pages = ggtt_set_pages; + ggtt->vm.vma_ops.clear_pages = clear_pages; + setup_private_pat(dev_priv); return ggtt_probe_common(ggtt, size); @@ -3370,10 +3373,6 @@ static int gen6_gmch_probe(struct i915_ggtt *ggtt) ggtt->vm.clear_range = gen6_ggtt_clear_range; ggtt->vm.insert_page = gen6_ggtt_insert_page; ggtt->vm.insert_entries = gen6_ggtt_insert_entries; - ggtt->vm.bind_vma = ggtt_bind_vma; - ggtt->vm.unbind_vma = ggtt_unbind_vma; - ggtt->vm.set_pages = ggtt_set_pages; - ggtt->vm.clear_pages = clear_pages; ggtt->vm.cleanup = gen6_gmch_remove; ggtt->invalidate = gen6_ggtt_invalidate; @@ -3389,6 +3388,11 @@ static int gen6_gmch_probe(struct i915_ggtt *ggtt) else ggtt->vm.pte_encode = snb_pte_encode; + ggtt->vm.vma_ops.bind_vma = ggtt_bind_vma; + ggtt->vm.vma_ops.unbind_vma = ggtt_unbind_vma; + ggtt->vm.vma_ops.set_pages = ggtt_set_pages; + ggtt->vm.vma_ops.clear_pages = clear_pages; + return ggtt_probe_common(ggtt, size); } @@ -3419,14 +3423,15 @@ static int i915_gmch_probe(struct i915_ggtt *ggtt) ggtt->vm.insert_page = i915_ggtt_insert_page; ggtt->vm.insert_entries = i915_ggtt_insert_entries; ggtt->vm.clear_range = i915_ggtt_clear_range; - ggtt->vm.bind_vma = ggtt_bind_vma; - ggtt->vm.unbind_vma = ggtt_unbind_vma; - ggtt->vm.set_pages = ggtt_set_pages; - ggtt->vm.clear_pages = clear_pages; ggtt->vm.cleanup = i915_gmch_remove; ggtt->invalidate = gmch_ggtt_invalidate; + ggtt->vm.vma_ops.bind_vma = ggtt_bind_vma; + ggtt->vm.vma_ops.unbind_vma = ggtt_unbind_vma; + ggtt->vm.vma_ops.set_pages = ggtt_set_pages; + ggtt->vm.vma_ops.clear_pages = clear_pages; + if (unlikely(ggtt->do_idle_maps)) DRM_INFO("applying Ironlake quirks for intel_iommu\n"); diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index 197c2c06ecb73..16307ba7e3035 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -58,6 +58,7 @@ struct drm_i915_file_private; struct drm_i915_fence_reg; +struct i915_vma; typedef u32 gen6_pte_t; typedef u64 gen8_pte_t; @@ -254,6 +255,21 @@ struct i915_pml4 { struct i915_page_directory_pointer *pdps[GEN8_PML4ES_PER_PML4]; }; +struct i915_vma_ops { + /* Map an object into an address space with the given cache flags. */ + int (*bind_vma)(struct i915_vma *vma, + enum i915_cache_level cache_level, + u32 flags); + /* + * Unmap an object from an address space. This usually consists of + * setting the valid PTE entries to a reserved scratch page. + */ + void (*unbind_vma)(struct i915_vma *vma); + + int (*set_pages)(struct i915_vma *vma); + void (*clear_pages)(struct i915_vma *vma); +}; + struct i915_address_space { struct drm_mm mm; struct drm_i915_private *i915; @@ -331,15 +347,8 @@ struct i915_address_space { enum i915_cache_level cache_level, u32 flags); void (*cleanup)(struct i915_address_space *vm); - /** Unmap an object from an address space. This usually consists of - * setting the valid PTE entries to a reserved scratch page. */ - void (*unbind_vma)(struct i915_vma *vma); - /* Map an object into an address space with the given cache flags. */ - int (*bind_vma)(struct i915_vma *vma, - enum i915_cache_level cache_level, - u32 flags); - int (*set_pages)(struct i915_vma *vma); - void (*clear_pages)(struct i915_vma *vma); + + struct i915_vma_ops vma_ops; I915_SELFTEST_DECLARE(struct fault_attr fault_attr); I915_SELFTEST_DECLARE(bool scrub_64K); diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c index b71265066cd16..e82aa804cdba3 100644 --- a/drivers/gpu/drm/i915/i915_vma.c +++ b/drivers/gpu/drm/i915/i915_vma.c @@ -95,6 +95,7 @@ vma_create(struct drm_i915_gem_object *obj, init_request_active(&vma->last_read[i], i915_vma_retire); init_request_active(&vma->last_fence, NULL); vma->vm = vm; + vma->ops = &vm->vma_ops; vma->obj = obj; vma->resv = obj->resv; vma->size = obj->base.size; @@ -280,7 +281,7 @@ int i915_vma_bind(struct i915_vma *vma, enum i915_cache_level cache_level, GEM_BUG_ON(!vma->pages); trace_i915_vma_bind(vma, bind_flags); - ret = vma->vm->bind_vma(vma, cache_level, bind_flags); + ret = vma->ops->bind_vma(vma, cache_level, bind_flags); if (ret) return ret; @@ -543,7 +544,7 @@ i915_vma_insert(struct i915_vma *vma, u64 size, u64 alignment, u64 flags) GEM_BUG_ON(vma->pages); - ret = vma->vm->set_pages(vma); + ret = vma->ops->set_pages(vma); if (ret) goto err_unpin; @@ -622,7 +623,7 @@ i915_vma_insert(struct i915_vma *vma, u64 size, u64 alignment, u64 flags) return 0; err_clear: - vma->vm->clear_pages(vma); + vma->ops->clear_pages(vma); err_unpin: if (vma->obj) i915_gem_object_unpin_pages(vma->obj); @@ -637,7 +638,7 @@ i915_vma_remove(struct i915_vma *vma) GEM_BUG_ON(!drm_mm_node_allocated(&vma->node)); GEM_BUG_ON(vma->flags & (I915_VMA_GLOBAL_BIND | I915_VMA_LOCAL_BIND)); - vma->vm->clear_pages(vma); + vma->ops->clear_pages(vma); drm_mm_remove_node(&vma->node); list_move_tail(&vma->vm_link, &vma->vm->unbound_list); @@ -906,7 +907,7 @@ int i915_vma_unbind(struct i915_vma *vma) if (likely(!vma->vm->closed)) { trace_i915_vma_unbind(vma); - vma->vm->unbind_vma(vma); + vma->ops->unbind_vma(vma); } vma->flags &= ~(I915_VMA_GLOBAL_BIND | I915_VMA_LOCAL_BIND); diff --git a/drivers/gpu/drm/i915/i915_vma.h b/drivers/gpu/drm/i915/i915_vma.h index f0532f1a4953d..4321476a6a329 100644 --- a/drivers/gpu/drm/i915/i915_vma.h +++ b/drivers/gpu/drm/i915/i915_vma.h @@ -49,6 +49,7 @@ struct i915_vma { struct drm_mm_node node; struct drm_i915_gem_object *obj; struct i915_address_space *vm; + const struct i915_vma_ops *ops; struct drm_i915_fence_reg *fence; struct reservation_object *resv; /** Alias of obj->resv */ struct sg_table *pages; diff --git a/drivers/gpu/drm/i915/selftests/mock_gtt.c b/drivers/gpu/drm/i915/selftests/mock_gtt.c index 556c546f2715b..6a7f4da7b523e 100644 --- a/drivers/gpu/drm/i915/selftests/mock_gtt.c +++ b/drivers/gpu/drm/i915/selftests/mock_gtt.c @@ -80,12 +80,13 @@ mock_ppgtt(struct drm_i915_private *i915, ppgtt->vm.clear_range = nop_clear_range; ppgtt->vm.insert_page = mock_insert_page; ppgtt->vm.insert_entries = mock_insert_entries; - ppgtt->vm.bind_vma = mock_bind_ppgtt; - ppgtt->vm.unbind_vma = mock_unbind_ppgtt; - ppgtt->vm.set_pages = ppgtt_set_pages; - ppgtt->vm.clear_pages = clear_pages; ppgtt->vm.cleanup = mock_cleanup; + ppgtt->vm.vma_ops.bind_vma = mock_bind_ppgtt; + ppgtt->vm.vma_ops.unbind_vma = mock_unbind_ppgtt; + ppgtt->vm.vma_ops.set_pages = ppgtt_set_pages; + ppgtt->vm.vma_ops.clear_pages = clear_pages; + return ppgtt; } @@ -116,12 +117,13 @@ void mock_init_ggtt(struct drm_i915_private *i915) ggtt->vm.clear_range = nop_clear_range; ggtt->vm.insert_page = mock_insert_page; ggtt->vm.insert_entries = mock_insert_entries; - ggtt->vm.bind_vma = mock_bind_ggtt; - ggtt->vm.unbind_vma = mock_unbind_ggtt; - ggtt->vm.set_pages = ggtt_set_pages; - ggtt->vm.clear_pages = clear_pages; ggtt->vm.cleanup = mock_cleanup; + ggtt->vm.vma_ops.bind_vma = mock_bind_ggtt; + ggtt->vm.vma_ops.unbind_vma = mock_unbind_ggtt; + ggtt->vm.vma_ops.set_pages = ggtt_set_pages; + ggtt->vm.vma_ops.clear_pages = clear_pages; + i915_address_space_init(&ggtt->vm, i915, "global"); } -- GitLab From 17f297b427a32ef5524a494de331c68366e8226d Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 7 Jun 2018 17:30:40 +0100 Subject: [PATCH 0200/1506] drm/i915/gtt: Push allocation to hw ppgtt constructor In the next patch, we will subclass the gen6 hw_ppgtt. In order, for the two different generations of hw ppgtt stucts to be of different size, push the allocation down to the constructor. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: Matthew Auld <matthew.william.auld@gmail.com> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180607163040.9781-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_gtt.c | 140 +++++++++--------- drivers/gpu/drm/i915/selftests/i915_gem_gtt.c | 16 +- 2 files changed, 83 insertions(+), 73 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index d841bf296d191..912d6c4ba336a 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1562,32 +1562,36 @@ static int gen8_preallocate_top_level_pdp(struct i915_hw_ppgtt *ppgtt) * space. * */ -static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt) +static struct i915_hw_ppgtt *gen8_ppgtt_create(struct drm_i915_private *i915) { - struct i915_address_space *vm = &ppgtt->vm; - struct drm_i915_private *dev_priv = vm->i915; - int ret; + struct i915_hw_ppgtt *ppgtt; + int err; + + ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL); + if (!ppgtt) + return ERR_PTR(-ENOMEM); - ppgtt->vm.total = USES_FULL_48BIT_PPGTT(dev_priv) ? + ppgtt->vm.i915 = i915; + ppgtt->vm.dma = &i915->drm.pdev->dev; + + ppgtt->vm.total = USES_FULL_48BIT_PPGTT(i915) ? 1ULL << 48 : 1ULL << 32; /* There are only few exceptions for gen >=6. chv and bxt. * And we are not sure about the latter so play safe for now. */ - if (IS_CHERRYVIEW(dev_priv) || IS_BROXTON(dev_priv)) + if (IS_CHERRYVIEW(i915) || IS_BROXTON(i915)) ppgtt->vm.pt_kmap_wc = true; - ret = gen8_init_scratch(&ppgtt->vm); - if (ret) { - ppgtt->vm.total = 0; - return ret; - } + err = gen8_init_scratch(&ppgtt->vm); + if (err) + goto err_free; - if (use_4lvl(vm)) { - ret = setup_px(&ppgtt->vm, &ppgtt->pml4); - if (ret) - goto free_scratch; + if (use_4lvl(&ppgtt->vm)) { + err = setup_px(&ppgtt->vm, &ppgtt->pml4); + if (err) + goto err_scratch; gen8_initialize_pml4(&ppgtt->vm, &ppgtt->pml4); @@ -1595,15 +1599,15 @@ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt) ppgtt->vm.insert_entries = gen8_ppgtt_insert_4lvl; ppgtt->vm.clear_range = gen8_ppgtt_clear_4lvl; } else { - ret = __pdp_init(&ppgtt->vm, &ppgtt->pdp); - if (ret) - goto free_scratch; + err = __pdp_init(&ppgtt->vm, &ppgtt->pdp); + if (err) + goto err_scratch; - if (intel_vgpu_active(dev_priv)) { - ret = gen8_preallocate_top_level_pdp(ppgtt); - if (ret) { + if (intel_vgpu_active(i915)) { + err = gen8_preallocate_top_level_pdp(ppgtt); + if (err) { __pdp_fini(&ppgtt->pdp); - goto free_scratch; + goto err_scratch; } } @@ -1612,7 +1616,7 @@ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt) ppgtt->vm.clear_range = gen8_ppgtt_clear_3lvl; } - if (intel_vgpu_active(dev_priv)) + if (intel_vgpu_active(i915)) gen8_ppgtt_notify_vgt(ppgtt, true); ppgtt->vm.cleanup = gen8_ppgtt_cleanup; @@ -1623,11 +1627,13 @@ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt) ppgtt->vm.vma_ops.set_pages = ppgtt_set_pages; ppgtt->vm.vma_ops.clear_pages = clear_pages; - return 0; + return ppgtt; -free_scratch: +err_scratch: gen8_free_scratch(&ppgtt->vm); - return ret; +err_free: + kfree(ppgtt); + return ERR_PTR(err); } static void gen6_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m) @@ -1638,8 +1644,7 @@ static void gen6_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m) u32 pd_entry, pte, pde; u32 start = 0, length = ppgtt->vm.total; - scratch_pte = vm->pte_encode(vm->scratch_page.daddr, - I915_CACHE_LLC, 0); + scratch_pte = vm->pte_encode(vm->scratch_page.daddr, I915_CACHE_LLC, 0); gen6_for_each_pde(unused, &ppgtt->pd, start, length, pde) { u32 expected; @@ -2027,36 +2032,41 @@ static void gen6_scratch_va_range(struct i915_hw_ppgtt *ppgtt, ppgtt->pd.page_table[pde] = ppgtt->vm.scratch_pt; } -static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) +static struct i915_hw_ppgtt *gen6_ppgtt_create(struct drm_i915_private *i915) { - struct drm_i915_private *dev_priv = ppgtt->vm.i915; - struct i915_ggtt *ggtt = &dev_priv->ggtt; - int ret; + struct i915_ggtt * const ggtt = &i915->ggtt; + struct i915_hw_ppgtt *ppgtt; + int err; + + ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL); + if (!ppgtt) + return ERR_PTR(-ENOMEM); + + ppgtt->vm.i915 = i915; + ppgtt->vm.dma = &i915->drm.pdev->dev; ppgtt->vm.pte_encode = ggtt->vm.pte_encode; - if (intel_vgpu_active(dev_priv) || IS_GEN6(dev_priv)) + if (intel_vgpu_active(i915) || IS_GEN6(i915)) ppgtt->switch_mm = gen6_mm_switch; - else if (IS_HASWELL(dev_priv)) + else if (IS_HASWELL(i915)) ppgtt->switch_mm = hsw_mm_switch; - else if (IS_GEN7(dev_priv)) + else if (IS_GEN7(i915)) ppgtt->switch_mm = gen7_mm_switch; else BUG(); - ret = gen6_ppgtt_alloc(ppgtt); - if (ret) - return ret; + err = gen6_ppgtt_alloc(ppgtt); + if (err) + goto err_free; ppgtt->vm.total = I915_PDES * GEN6_PTES * PAGE_SIZE; gen6_scratch_va_range(ppgtt, 0, ppgtt->vm.total); gen6_write_page_range(ppgtt, 0, ppgtt->vm.total); - ret = gen6_alloc_va_range(&ppgtt->vm, 0, ppgtt->vm.total); - if (ret) { - gen6_ppgtt_cleanup(&ppgtt->vm); - return ret; - } + err = gen6_alloc_va_range(&ppgtt->vm, 0, ppgtt->vm.total); + if (err) + goto err_cleanup; ppgtt->vm.clear_range = gen6_ppgtt_clear_range; ppgtt->vm.insert_entries = gen6_ppgtt_insert_entries; @@ -2075,19 +2085,13 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) DRM_DEBUG_DRIVER("Adding PPGTT at offset %x\n", ppgtt->pd.base.ggtt_offset << 10); - return 0; -} - -static int __hw_ppgtt_init(struct i915_hw_ppgtt *ppgtt, - struct drm_i915_private *dev_priv) -{ - ppgtt->vm.i915 = dev_priv; - ppgtt->vm.dma = &dev_priv->drm.pdev->dev; + return ppgtt; - if (INTEL_GEN(dev_priv) < 8) - return gen6_ppgtt_init(ppgtt); - else - return gen8_ppgtt_init(ppgtt); +err_cleanup: + gen6_ppgtt_cleanup(&ppgtt->vm); +err_free: + kfree(ppgtt); + return ERR_PTR(err); } static void i915_address_space_init(struct i915_address_space *vm, @@ -2173,26 +2177,28 @@ int i915_ppgtt_init_hw(struct drm_i915_private *dev_priv) return 0; } +static struct i915_hw_ppgtt * +__hw_ppgtt_create(struct drm_i915_private *i915) +{ + if (INTEL_GEN(i915) < 8) + return gen6_ppgtt_create(i915); + else + return gen8_ppgtt_create(i915); +} + struct i915_hw_ppgtt * -i915_ppgtt_create(struct drm_i915_private *dev_priv, +i915_ppgtt_create(struct drm_i915_private *i915, struct drm_i915_file_private *fpriv, const char *name) { struct i915_hw_ppgtt *ppgtt; - int ret; - ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL); - if (!ppgtt) - return ERR_PTR(-ENOMEM); - - ret = __hw_ppgtt_init(ppgtt, dev_priv); - if (ret) { - kfree(ppgtt); - return ERR_PTR(ret); - } + ppgtt = __hw_ppgtt_create(i915); + if (IS_ERR(ppgtt)) + return ppgtt; kref_init(&ppgtt->ref); - i915_address_space_init(&ppgtt->vm, dev_priv, name); + i915_address_space_init(&ppgtt->vm, i915, name); ppgtt->vm.file = fpriv; trace_i915_ppgtt_create(&ppgtt->vm); diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c index 58ab5e84ceb7c..f80cf7ce3fa96 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c @@ -147,12 +147,16 @@ static int igt_ppgtt_alloc(void *arg) return -ENOMEM; mutex_lock(&dev_priv->drm.struct_mutex); - err = __hw_ppgtt_init(ppgtt, dev_priv); - if (err) - goto err_ppgtt; + ppgtt = __hw_ppgtt_create(dev_priv); + if (IS_ERR(ppgtt)) { + err = PTR_ERR(ppgtt); + goto err_unlock; + } - if (!ppgtt->vm.allocate_va_range) + if (!ppgtt->vm.allocate_va_range) { + err = 0; goto err_ppgtt_cleanup; + } /* Check we can allocate the entire range */ for (size = 4096; @@ -189,9 +193,9 @@ static int igt_ppgtt_alloc(void *arg) err_ppgtt_cleanup: ppgtt->vm.cleanup(&ppgtt->vm); -err_ppgtt: - mutex_unlock(&dev_priv->drm.struct_mutex); kfree(ppgtt); +err_unlock: + mutex_unlock(&dev_priv->drm.struct_mutex); return err; } -- GitLab From c30acb04e7c401d5b412ec925ff4b862bc77b0b8 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala <mika.kuoppala@linux.intel.com> Date: Tue, 5 Jun 2018 19:03:56 +0300 Subject: [PATCH 0201/1506] drm/i915: Cancel reset preparations on failed resets Our reset handling has a retry layer further up in the chain. As we have told the engine to prepare for reset, and failed it, make sure to remove that preparation so that the next attempted reset has a clean slate by triggering another full prepare cycle for the engines. v2: ret as int, simplified cleanup (Chris) Cc: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20180605160357.32591-1-mika.kuoppala@linux.intel.com --- drivers/gpu/drm/i915/intel_uncore.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index b36a3b5736a0e..bb03f6d8b3d16 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -2093,21 +2093,25 @@ static int gen8_reset_engines(struct drm_i915_private *dev_priv, { struct intel_engine_cs *engine; unsigned int tmp; + int ret; - for_each_engine_masked(engine, dev_priv, engine_mask, tmp) - if (gen8_reset_engine_start(engine)) + for_each_engine_masked(engine, dev_priv, engine_mask, tmp) { + if (gen8_reset_engine_start(engine)) { + ret = -EIO; goto not_ready; + } + } if (INTEL_GEN(dev_priv) >= 11) - return gen11_reset_engines(dev_priv, engine_mask); + ret = gen11_reset_engines(dev_priv, engine_mask); else - return gen6_reset_engines(dev_priv, engine_mask); + ret = gen6_reset_engines(dev_priv, engine_mask); not_ready: for_each_engine_masked(engine, dev_priv, engine_mask, tmp) gen8_reset_engine_cancel(engine); - return -EIO; + return ret; } typedef int (*reset_func)(struct drm_i915_private *, unsigned engine_mask); -- GitLab From 39e78234b0be7ae543db8c8ea3cd2e433b8a7bec Mon Sep 17 00:00:00 2001 From: Mika Kuoppala <mika.kuoppala@linux.intel.com> Date: Thu, 7 Jun 2018 20:24:44 +0300 Subject: [PATCH 0202/1506] drm/i915: Add WaKBLVECSSemaphoreWaitPoll There is a problem with kbl up to rev E0 where a heavy memory/fabric traffic from adjacent engine(s) can cause an engine reset to fail. This traffic can be from normal memory accesses or it can be from heavy polling on a semaphore wait. For engine hogging causing a fail, we already fallback to full reset. Which effectively stops all engines and thus we only add a workaround documentation. For the semaphore wait loop poll case, we add one microsecond poll interval to semaphore wait to guarantee bandwidth for the reset preration. The side effect is that we make semaphore completion latencies also 1us longer. v2: Let full reset handle the adjacent engine idling (Chris) v3: Skip render engine (Joonas), please checkpatch on define (Mika) References: https://bugs.freedesktop.org/show_bug.cgi?id=106684 References: VTHSD#2227190, HSDES#1604216706, BSID#0917 Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Acked-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180607172444.17080-1-mika.kuoppala@linux.intel.com --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_uncore.c | 2 ++ drivers/gpu/drm/i915/intel_workarounds.c | 13 +++++++++++++ 3 files changed, 16 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index f0317bde3aabc..987def26ce829 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2242,6 +2242,7 @@ enum i915_power_well_id { #define RING_RESET_CTL(base) _MMIO((base)+0xd0) #define RESET_CTL_REQUEST_RESET (1 << 0) #define RESET_CTL_READY_TO_RESET (1 << 1) +#define RING_SEMA_WAIT_POLL(base) _MMIO((base) + 0x24c) #define HSW_GTT_CACHE_EN _MMIO(0x4024) #define GTT_CACHE_EN_ALL 0xF0007FFF diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index bb03f6d8b3d16..b892ca8396e87 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -2174,6 +2174,8 @@ int intel_gpu_reset(struct drm_i915_private *dev_priv, unsigned engine_mask) * Thus assume it is best to stop engines on all gens * where we have a gpu reset. * + * WaKBLVECSSemaphoreWaitPoll:kbl (on ALL_ENGINES) + * * WaMediaResetMainRingCleanup:ctg,elk (presumably) * * FIXME: Wa for more modern gens needs to be validated diff --git a/drivers/gpu/drm/i915/intel_workarounds.c b/drivers/gpu/drm/i915/intel_workarounds.c index b1ab56a1ec313..24b929ce3341b 100644 --- a/drivers/gpu/drm/i915/intel_workarounds.c +++ b/drivers/gpu/drm/i915/intel_workarounds.c @@ -666,6 +666,19 @@ static void kbl_gt_workarounds_apply(struct drm_i915_private *dev_priv) I915_WRITE(GEN9_GAMT_ECO_REG_RW_IA, I915_READ(GEN9_GAMT_ECO_REG_RW_IA) | GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS); + + /* WaKBLVECSSemaphoreWaitPoll:kbl */ + if (IS_KBL_REVID(dev_priv, KBL_REVID_A0, KBL_REVID_E0)) { + struct intel_engine_cs *engine; + unsigned int tmp; + + for_each_engine(engine, dev_priv, tmp) { + if (engine->id == RCS) + continue; + + I915_WRITE(RING_SEMA_WAIT_POLL(engine->mmio_base), 1); + } + } } static void glk_gt_workarounds_apply(struct drm_i915_private *dev_priv) -- GitLab From 51e645b6652c997a68cbadf70e62a7b0c49e63a2 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 7 Jun 2018 14:45:58 +0100 Subject: [PATCH 0203/1506] drm/i915: Mark the GPU as wedged without error on fault injection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we have been instructed (by CI) to inject a fault to load the module with a wedged GPU, do so quietly less we upset CI. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: MichaÅ‚ Winiarski <michal.winiarski@intel.com> Cc: Michal Wajdeczko <michal.wajdeczko@intel.com> Reviewed-by: MichaÅ‚ Winiarski <michal.winiarski@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180607134558.31150-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index fd882eb389d22..4187e0688e508 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5491,6 +5491,8 @@ int i915_gem_init(struct drm_i915_private *dev_priv) } if (i915_inject_load_failure()) { + DRM_DEBUG_DRIVER("Marking the driver as wedged\n"); + i915_gem_set_wedged(dev_priv); /* Fail silently! */ ret = -EIO; goto err_init_hw; } -- GitLab From 672b3c4bc3d157078c00146c2d20bdd3aeec38e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Tue, 29 May 2018 21:28:00 +0300 Subject: [PATCH 0204/1506] drm/i915: Fix sprite destination colorkeying on SKL+ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On SKL+ the dst colorkey must be configured on the lower plane that contains the colorkey. This is in contrast to most earlier platforms where the dst colorkey is configured on the plane above. The hardware will peform dst keying only between two immediately adjacent (in zorder) planes. Plane 2 will be keyed against plane 1, plane 3 againts plane 2, and so on. There is no way to key arbitrary planes against plane 1. Thus offering dst color keying on plane 3+ is pointless. In fact it can be harmful since enabling dst keying on more than one plane on the same pipe leads to only the top-most of the planes performing the keying. For any plane lower in zorder the dst key enable is simply ignored. v2: s/plane 0/plane 1/ etc. since the hw plane names start from 1 Don't break dst colorkey on pre-SKL sprites (hunk ended in the wrong patch) Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180529182804.8571-1-ville.syrjala@linux.intel.com Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> #v1 --- drivers/gpu/drm/i915/intel_sprite.c | 64 +++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 24f86c4375cf9..d9e7f4fb5096c 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -1175,6 +1175,37 @@ intel_check_sprite_plane(struct intel_plane *plane, return 0; } +static bool has_dst_key_in_primary_plane(struct drm_i915_private *dev_priv) +{ + return INTEL_GEN(dev_priv) >= 9; +} + +static void intel_plane_set_ckey(struct intel_plane_state *plane_state, + const struct drm_intel_sprite_colorkey *set) +{ + struct intel_plane *plane = to_intel_plane(plane_state->base.plane); + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + struct drm_intel_sprite_colorkey *key = &plane_state->ckey; + + *key = *set; + + /* + * We want src key enabled on the + * sprite and not on the primary. + */ + if (plane->id == PLANE_PRIMARY && + set->flags & I915_SET_COLORKEY_SOURCE) + key->flags = 0; + + /* + * On SKL+ we want dst key enabled on + * the primary and not on the sprite. + */ + if (INTEL_GEN(dev_priv) >= 9 && plane->id != PLANE_PRIMARY && + set->flags & I915_SET_COLORKEY_DESTINATION) + key->flags = 0; +} + int intel_sprite_set_colorkey_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -1204,6 +1235,16 @@ int intel_sprite_set_colorkey_ioctl(struct drm_device *dev, void *data, if (!plane || plane->type != DRM_PLANE_TYPE_OVERLAY) return -ENOENT; + /* + * SKL+ only plane 2 can do destination keying against plane 1. + * Also multiple planes can't do destination keying on the same + * pipe simultaneously. + */ + if (INTEL_GEN(dev_priv) >= 9 && + to_intel_plane(plane)->id >= PLANE_SPRITE1 && + set->flags & I915_SET_COLORKEY_DESTINATION) + return -EINVAL; + drm_modeset_acquire_init(&ctx, 0); state = drm_atomic_state_alloc(plane->dev); @@ -1216,11 +1257,28 @@ int intel_sprite_set_colorkey_ioctl(struct drm_device *dev, void *data, while (1) { plane_state = drm_atomic_get_plane_state(state, plane); ret = PTR_ERR_OR_ZERO(plane_state); - if (!ret) { - to_intel_plane_state(plane_state)->ckey = *set; - ret = drm_atomic_commit(state); + if (!ret) + intel_plane_set_ckey(to_intel_plane_state(plane_state), set); + + /* + * On some platforms we have to configure + * the dst colorkey on the primary plane. + */ + if (!ret && has_dst_key_in_primary_plane(dev_priv)) { + struct intel_crtc *crtc = + intel_get_crtc_for_pipe(dev_priv, + to_intel_plane(plane)->pipe); + + plane_state = drm_atomic_get_plane_state(state, + crtc->base.primary); + ret = PTR_ERR_OR_ZERO(plane_state); + if (!ret) + intel_plane_set_ckey(to_intel_plane_state(plane_state), set); } + if (!ret) + ret = drm_atomic_commit(state); + if (ret != -EDEADLK) break; -- GitLab From b4e2727df2713a5aea9de6364f7a943147ceef92 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 8 Jun 2018 18:32:21 +0100 Subject: [PATCH 0205/1506] drm/i915/gtt: Fix unwind length passed to gen6_ppgtt_clear_range When we want to unwind an error when allocating the PD for gen6, we call gen6_ppgtt_clear_range() telling to clear upto the PD we've previously allocated. However, we passed it an incorrect length, passing it the endpoint instead. Fortunately, as the start was always 0, this has no impact today, but tomorrow we want to start using non-zero origins. Reported-by: Matthew Auld <matthew.william.auld@gmail.com> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: Matthew Auld <matthew.william.auld@gmail.com> Reviewed-by: Matthew Auld <matthew.william.auld@gmail.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180608173221.10455-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_gtt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 912d6c4ba336a..ae3b24095d046 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1931,7 +1931,7 @@ static int gen6_alloc_va_range(struct i915_address_space *vm, return 0; unwind_out: - gen6_ppgtt_clear_range(vm, from, start); + gen6_ppgtt_clear_range(vm, from, start - from); return -ENOMEM; } -- GitLab From f6b1e35f3e47f40d18fe50a52c09a618ec703c1b Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 8 Jun 2018 16:04:34 +0100 Subject: [PATCH 0206/1506] drm/i915/gtt: Remove redundant hsw_mm_switch() hsw_mm_switch() and gen7_mm_switch() are identical, so let's remove the redundant specialism. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: Matthew Auld <matthew.william.auld@gmail.com> Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180608150435.15010-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_gtt.c | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index ae3b24095d046..df0ea66ba68c2 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1718,28 +1718,6 @@ static inline u32 get_pd_offset(struct i915_hw_ppgtt *ppgtt) return ppgtt->pd.base.ggtt_offset << 10; } -static int hsw_mm_switch(struct i915_hw_ppgtt *ppgtt, - struct i915_request *rq) -{ - struct intel_engine_cs *engine = rq->engine; - u32 *cs; - - /* NB: TLBs must be flushed and invalidated before a switch */ - cs = intel_ring_begin(rq, 6); - if (IS_ERR(cs)) - return PTR_ERR(cs); - - *cs++ = MI_LOAD_REGISTER_IMM(2); - *cs++ = i915_mmio_reg_offset(RING_PP_DIR_DCLV(engine)); - *cs++ = PP_DIR_DCLV_2G; - *cs++ = i915_mmio_reg_offset(RING_PP_DIR_BASE(engine)); - *cs++ = get_pd_offset(ppgtt); - *cs++ = MI_NOOP; - intel_ring_advance(rq, cs); - - return 0; -} - static int gen7_mm_switch(struct i915_hw_ppgtt *ppgtt, struct i915_request *rq) { @@ -2048,8 +2026,6 @@ static struct i915_hw_ppgtt *gen6_ppgtt_create(struct drm_i915_private *i915) ppgtt->vm.pte_encode = ggtt->vm.pte_encode; if (intel_vgpu_active(i915) || IS_GEN6(i915)) ppgtt->switch_mm = gen6_mm_switch; - else if (IS_HASWELL(i915)) - ppgtt->switch_mm = hsw_mm_switch; else if (IS_GEN7(i915)) ppgtt->switch_mm = gen7_mm_switch; else -- GitLab From e1f8789883a1bfdb4bfa8b638eeb24eb089c5836 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 8 Jun 2018 16:04:35 +0100 Subject: [PATCH 0207/1506] drm/i915/gtt: Remove vgpu check for gen6 Since vgpu is not supported on Haswell or any other gen6/7, we do not need to check and act upon it's enablement. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: Matthew Auld <matthew.william.auld@gmail.com> Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180608150435.15010-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_gtt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index df0ea66ba68c2..a8cfe3c413c11 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -2024,7 +2024,7 @@ static struct i915_hw_ppgtt *gen6_ppgtt_create(struct drm_i915_private *i915) ppgtt->vm.dma = &i915->drm.pdev->dev; ppgtt->vm.pte_encode = ggtt->vm.pte_encode; - if (intel_vgpu_active(i915) || IS_GEN6(i915)) + if (IS_GEN6(i915)) ppgtt->switch_mm = gen6_mm_switch; else if (IS_GEN7(i915)) ppgtt->switch_mm = gen7_mm_switch; -- GitLab From eed2890374446ff67fe5b14517d0b2b08a1a11d2 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Sat, 9 Jun 2018 10:01:51 +0100 Subject: [PATCH 0208/1506] drm/i915/gtt: Reorder aliasing_ppgtt fini To allow ourselves to use a first class vma for the aliasing_ppgtt page directory, we have to reorder the shutdown on module unload to remove and unpin the aliasing_ppgtt before complaining about any objects left in the GGTT. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: Matthew Auld <matthew.william.auld@gmail.com> Reviewed-by: Matthew Auld <matthew.william.auld@gmail.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180609090151.22007-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_gtt.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index a8cfe3c413c11..7ccfdbc8f9b43 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -2870,15 +2870,11 @@ void i915_ggtt_cleanup_hw(struct drm_i915_private *dev_priv) ggtt->vm.closed = true; mutex_lock(&dev_priv->drm.struct_mutex); + i915_gem_fini_aliasing_ppgtt(dev_priv); + GEM_BUG_ON(!list_empty(&ggtt->vm.active_list)); list_for_each_entry_safe(vma, vn, &ggtt->vm.inactive_list, vm_link) WARN_ON(i915_vma_unbind(vma)); - mutex_unlock(&dev_priv->drm.struct_mutex); - - i915_gem_cleanup_stolen(&dev_priv->drm); - - mutex_lock(&dev_priv->drm.struct_mutex); - i915_gem_fini_aliasing_ppgtt(dev_priv); if (drm_mm_node_allocated(&ggtt->error_capture)) drm_mm_remove_node(&ggtt->error_capture); @@ -2900,6 +2896,8 @@ void i915_ggtt_cleanup_hw(struct drm_i915_private *dev_priv) arch_phys_wc_del(ggtt->mtrr); io_mapping_fini(&ggtt->iomap); + + i915_gem_cleanup_stolen(&dev_priv->drm); } static unsigned int gen6_get_total_gtt_size(u16 snb_gmch_ctl) -- GitLab From 1f1c60d5b577377d07863f3e0891e63a0a56a3ad Mon Sep 17 00:00:00 2001 From: Xinyun Liu <xinyun.liu@intel.com> Date: Thu, 7 Jun 2018 22:48:40 +0800 Subject: [PATCH 0209/1506] drm/i915/gvt: Avoid dereference a potential null pointer Add sanity check for up_irq_info. Signed-off-by: Xinyun Liu <xinyun.liu@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> --- drivers/gpu/drm/i915/gvt/interrupt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gvt/interrupt.c b/drivers/gpu/drm/i915/gvt/interrupt.c index 7a041b368f688..1d79596da510e 100644 --- a/drivers/gpu/drm/i915/gvt/interrupt.c +++ b/drivers/gpu/drm/i915/gvt/interrupt.c @@ -350,7 +350,8 @@ static void update_upstream_irq(struct intel_vgpu *vgpu, clear_bits |= (1 << bit); } - WARN_ON(!up_irq_info); + if (WARN_ON(!up_irq_info)) + return; if (up_irq_info->group == INTEL_GVT_IRQ_INFO_MASTER) { u32 isr = i915_mmio_reg_offset(up_irq_info->reg_base); -- GitLab From 659571953d315b36204acac508ef8d477044d260 Mon Sep 17 00:00:00 2001 From: Xinyun Liu <xinyun.liu@intel.com> Date: Thu, 7 Jun 2018 22:48:41 +0800 Subject: [PATCH 0210/1506] drm/i915/gvt: removed unnecessary boundary check type is already checked in the function entry. So it is unnecessary to check it again. Signed-off-by: Xinyun Liu <xinyun.liu@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> --- drivers/gpu/drm/i915/gvt/gtt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gvt/gtt.c b/drivers/gpu/drm/i915/gvt/gtt.c index 78e55aafc8bca..49400ab129ffa 100644 --- a/drivers/gpu/drm/i915/gvt/gtt.c +++ b/drivers/gpu/drm/i915/gvt/gtt.c @@ -1972,7 +1972,7 @@ static int alloc_scratch_pages(struct intel_vgpu *vgpu, * GTT_TYPE_PPGTT_PDE_PT level pt, that means this scratch_pt it self * is GTT_TYPE_PPGTT_PTE_PT, and full filled by scratch page mfn. */ - if (type > GTT_TYPE_PPGTT_PTE_PT && type < GTT_TYPE_MAX) { + if (type > GTT_TYPE_PPGTT_PTE_PT) { struct intel_gvt_gtt_entry se; memset(&se, 0, sizeof(struct intel_gvt_gtt_entry)); -- GitLab From 1417fad75cb4eddc8d50604be88ca9a8a8de4c71 Mon Sep 17 00:00:00 2001 From: Xinyun Liu <xinyun.liu@intel.com> Date: Thu, 7 Jun 2018 22:48:42 +0800 Subject: [PATCH 0211/1506] drm/i915/gvt: use array to avoid potential buffer overflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Array 'pdp_pair' of size 1 may use index value(s) 1..7. Changed to pdps[8] to avoid confusion. Signed-off-by: Xinyun Liu <xinyun.liu@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> --- drivers/gpu/drm/i915/gvt/execlist.h | 13 +++++-------- drivers/gpu/drm/i915/gvt/scheduler.c | 5 ++--- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/execlist.h b/drivers/gpu/drm/i915/gvt/execlist.h index 427e40e64d41e..714d709829a2a 100644 --- a/drivers/gpu/drm/i915/gvt/execlist.h +++ b/drivers/gpu/drm/i915/gvt/execlist.h @@ -146,14 +146,11 @@ struct execlist_ring_context { u32 nop4; u32 lri_cmd_2; struct execlist_mmio_pair ctx_timestamp; - struct execlist_mmio_pair pdp3_UDW; - struct execlist_mmio_pair pdp3_LDW; - struct execlist_mmio_pair pdp2_UDW; - struct execlist_mmio_pair pdp2_LDW; - struct execlist_mmio_pair pdp1_UDW; - struct execlist_mmio_pair pdp1_LDW; - struct execlist_mmio_pair pdp0_UDW; - struct execlist_mmio_pair pdp0_LDW; + /* + * pdps[8]={ pdp3_UDW, pdp3_LDW, pdp2_UDW, pdp2_LDW, + * pdp1_UDW, pdp1_LDW, pdp0_UDW, pdp0_LDW} + */ + struct execlist_mmio_pair pdps[8]; }; struct intel_vgpu_elsp_dwords { diff --git a/drivers/gpu/drm/i915/gvt/scheduler.c b/drivers/gpu/drm/i915/gvt/scheduler.c index cf5a22cb6e06e..462cf560492e3 100644 --- a/drivers/gpu/drm/i915/gvt/scheduler.c +++ b/drivers/gpu/drm/i915/gvt/scheduler.c @@ -45,11 +45,10 @@ static void set_context_pdp_root_pointer( struct execlist_ring_context *ring_context, u32 pdp[8]) { - struct execlist_mmio_pair *pdp_pair = &ring_context->pdp3_UDW; int i; for (i = 0; i < 8; i++) - pdp_pair[i].val = pdp[7 - i]; + ring_context->pdps[i].val = pdp[7 - i]; } static void update_shadow_pdps(struct intel_vgpu_workload *workload) @@ -1230,7 +1229,7 @@ static void read_guest_pdps(struct intel_vgpu *vgpu, u64 gpa; int i; - gpa = ring_context_gpa + RING_CTX_OFF(pdp3_UDW.val); + gpa = ring_context_gpa + RING_CTX_OFF(pdps[0].val); for (i = 0; i < 8; i++) intel_gvt_hypervisor_read_gpa(vgpu, -- GitLab From 78ef3faff9ea557e54b053234b6c9461d3ea183f Mon Sep 17 00:00:00 2001 From: Jani Nikula <jani.nikula@intel.com> Date: Fri, 8 Jun 2018 15:33:26 +0300 Subject: [PATCH 0212/1506] drm/i915: fix guest virtual PCH detection on non-PCH systems MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Virtualized non-PCH systems such as Broxton or Geminilake should use PCH_NONE to indicate no PCH rather than PCH_NOP. The latter is a specific case to indicate a PCH system without south display. Reported-by: Colin Xu <Colin.Xu@intel.com> Cc: Colin Xu <Colin.Xu@intel.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Tested-by: Colin Xu <Colin.Xu@intel.com> Reviewed-by: Colin Xu <Colin.Xu@intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180608123330.31003-2-jani.nikula@intel.com --- drivers/gpu/drm/i915/i915_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 0a1b09bb658fe..8f22ae8925fc6 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -289,7 +289,7 @@ static void intel_detect_pch(struct drm_i915_private *dev_priv) if (WARN_ON(pch_type == PCH_NONE)) pch_type = PCH_NOP; } else { - pch_type = PCH_NOP; + pch_type = PCH_NONE; } dev_priv->pch_type = pch_type; dev_priv->pch_id = id; -- GitLab From b8bf31d82d22ee06e7bb4802c2ce93ccb4b8ee5b Mon Sep 17 00:00:00 2001 From: Lucas De Marchi <lucas.de.marchi@gmail.com> Date: Fri, 8 Jun 2018 15:33:27 +0300 Subject: [PATCH 0213/1506] drm/i915: document PCH_NOP There's a difference between PCH_NONE and PCH_NOP: the former means we don't have a PCH while in the latter we do, but it doesn't have the south display. Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180608123330.31003-3-jani.nikula@intel.com --- drivers/gpu/drm/i915/i915_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c4073666f1ca9..71651ca7a8b1b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -632,7 +632,7 @@ enum intel_pch { PCH_KBP, /* Kaby Lake PCH */ PCH_CNP, /* Cannon Lake PCH */ PCH_ICP, /* Ice Lake PCH */ - PCH_NOP, + PCH_NOP, /* PCH without south display */ }; enum intel_sbi_destination { -- GitLab From 85b17e6e4d3f288cc757ff5407b2ca6604673d74 Mon Sep 17 00:00:00 2001 From: Jani Nikula <jani.nikula@intel.com> Date: Fri, 8 Jun 2018 15:33:28 +0300 Subject: [PATCH 0214/1506] drm/i915: clean up virtual PCH special case handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use intel_pch_type() also for mapping the no PCH case (PCH id 0) to PCH_NONE to simplify code. Also make sure that intel_pch_type() knows all the PCH ids returned by intel_virt_detect_pch(). Loudly fail if this isn't the case; this shouldn't happen anyway. Cc: Colin Xu <Colin.Xu@intel.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Tested-by: Colin Xu <Colin.Xu@intel.com> Reviewed-by: Colin Xu <Colin.Xu@intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180608123330.31003-4-jani.nikula@intel.com --- drivers/gpu/drm/i915/i915_drv.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 8f22ae8925fc6..9aba419e5d8bb 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -284,13 +284,12 @@ static void intel_detect_pch(struct drm_i915_private *dev_priv) } else if (intel_is_virt_pch(id, pch->subsystem_vendor, pch->subsystem_device)) { id = intel_virt_detect_pch(dev_priv); - if (id) { - pch_type = intel_pch_type(dev_priv, id); - if (WARN_ON(pch_type == PCH_NONE)) - pch_type = PCH_NOP; - } else { - pch_type = PCH_NONE; - } + pch_type = intel_pch_type(dev_priv, id); + + /* Sanity check virtual PCH id */ + if (WARN_ON(id && pch_type == PCH_NONE)) + id = 0; + dev_priv->pch_type = pch_type; dev_priv->pch_id = id; break; -- GitLab From 13d0464b3240429234c34b39b819fe6f088fc3c8 Mon Sep 17 00:00:00 2001 From: Jani Nikula <jani.nikula@intel.com> Date: Fri, 8 Jun 2018 15:33:29 +0300 Subject: [PATCH 0215/1506] drm/i915: be more strict about HAS_PCH_NOP() usage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit HAS_PCH_NOP() implies a PCH platform without south display, not generic disabled display. Prefer num_pipes == 0 for PCH independent checks. Cc: Ville Syrjala <ville.syrjala@linux.intel.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180608123330.31003-5-jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_bios.c | 2 +- drivers/gpu/drm/i915/intel_i2c.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 465dff4780fea..18b9e04441169 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -1719,7 +1719,7 @@ void intel_bios_init(struct drm_i915_private *dev_priv) const struct bdb_header *bdb; u8 __iomem *bios = NULL; - if (HAS_PCH_NOP(dev_priv)) { + if (INTEL_INFO(dev_priv)->num_pipes == 0) { DRM_DEBUG_KMS("Skipping VBT init due to disabled display.\n"); return; } diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index e6875509bcd9c..61729bf84e087 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -771,7 +771,7 @@ int intel_setup_gmbus(struct drm_i915_private *dev_priv) unsigned int pin; int ret; - if (HAS_PCH_NOP(dev_priv)) + if (INTEL_INFO(dev_priv)->num_pipes == 0) return 0; if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) -- GitLab From 07ba0a82536e4955682b3b9077957ae1421d94bf Mon Sep 17 00:00:00 2001 From: Jani Nikula <jani.nikula@intel.com> Date: Fri, 8 Jun 2018 15:33:30 +0300 Subject: [PATCH 0216/1506] drm/i915: fix PCH_NOP setting for non-PCH platforms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Setting PCH type to PCH_NOP before checking whether we actually have a PCH ends up returning true for HAS_PCH_SPLIT() on all non-PCH split platforms. Fix this by using PCH_NOP only for platforms that actually have a PCH. Cc: Ville Syrjala <ville.syrjala@linux.intel.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180608123330.31003-6-jani.nikula@intel.com --- drivers/gpu/drm/i915/i915_drv.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 9aba419e5d8bb..d258388605d60 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -248,14 +248,6 @@ static void intel_detect_pch(struct drm_i915_private *dev_priv) { struct pci_dev *pch = NULL; - /* In all current cases, num_pipes is equivalent to the PCH_NOP setting - * (which really amounts to a PCH but no South Display). - */ - if (INTEL_INFO(dev_priv)->num_pipes == 0) { - dev_priv->pch_type = PCH_NOP; - return; - } - /* * The reason to probe ISA bridge instead of Dev31:Fun0 is to * make graphics device passthrough work easy for VMM, that only @@ -295,6 +287,17 @@ static void intel_detect_pch(struct drm_i915_private *dev_priv) break; } } + + /* + * Use PCH_NOP (PCH but no South Display) for PCH platforms without + * display. + */ + if (pch && INTEL_INFO(dev_priv)->num_pipes == 0) { + DRM_DEBUG_KMS("Display disabled, reverting to NOP PCH\n"); + dev_priv->pch_type = PCH_NOP; + dev_priv->pch_id = 0; + } + if (!pch) DRM_DEBUG_KMS("No PCH found.\n"); -- GitLab From 51c18bf7fdbe3c0546e86cb0fa5866fee07c5261 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Sat, 9 Jun 2018 12:10:58 +0100 Subject: [PATCH 0217/1506] drm/i915: Squash GEM load failure message (again) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Due to a silent conflict (silent because we are trying to fix the CI test that is meant to exercising these failures!) between commit 51e645b6652c ("drm/i915: Mark the GPU as wedged without error on fault injection") and commit 8571a05a9dd0 ("drm/i915: Use GEM suspend when aborting initialisation"), we failed to actually squash the error message after injecting the load failure. Rearrange the code to export i915_load_failure() for better logging of real errors (and quiet logging of injected errors). Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: MichaÅ‚ Winiarski <michal.winiarski@intel.com> Reviewed-by: MichaÅ‚ Winiarski <michal.winiarski@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180609111058.2660-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_drv.c | 20 ++++++-------------- drivers/gpu/drm/i915/i915_drv.h | 11 +++++++++++ drivers/gpu/drm/i915/i915_gem.c | 5 ++--- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index d258388605d60..4cdd70de5ed02 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -73,6 +73,12 @@ bool __i915_inject_load_failure(const char *func, int line) return false; } + +bool i915_error_injected(void) +{ + return i915_load_fail_count && !i915_modparams.inject_load_failure; +} + #endif #define FDO_BUG_URL "https://bugs.freedesktop.org/enter_bug.cgi?product=DRI" @@ -115,20 +121,6 @@ __i915_printk(struct drm_i915_private *dev_priv, const char *level, va_end(args); } -static bool i915_error_injected(struct drm_i915_private *dev_priv) -{ -#if IS_ENABLED(CONFIG_DRM_I915_DEBUG) - return i915_load_fail_count && !i915_modparams.inject_load_failure; -#else - return false; -#endif -} - -#define i915_load_error(i915, fmt, ...) \ - __i915_printk(i915, \ - i915_error_injected(i915) ? KERN_DEBUG : KERN_ERR, \ - fmt, ##__VA_ARGS__) - /* Map PCH device id to PCH type, or PCH_NONE if unknown. */ static enum intel_pch intel_pch_type(const struct drm_i915_private *dev_priv, unsigned short id) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 71651ca7a8b1b..6104d71150546 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -108,13 +108,24 @@ I915_STATE_WARN((x), "%s", "WARN_ON(" __stringify(x) ")") #if IS_ENABLED(CONFIG_DRM_I915_DEBUG) + bool __i915_inject_load_failure(const char *func, int line); #define i915_inject_load_failure() \ __i915_inject_load_failure(__func__, __LINE__) + +bool i915_error_injected(void); + #else + #define i915_inject_load_failure() false +#define i915_error_injected() false + #endif +#define i915_load_error(i915, fmt, ...) \ + __i915_printk(i915, i915_error_injected() ? KERN_DEBUG : KERN_ERR, \ + fmt, ##__VA_ARGS__) + typedef struct { uint32_t val; } uint_fixed_16_16_t; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 4187e0688e508..0f28b5ddfd156 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5491,8 +5491,6 @@ int i915_gem_init(struct drm_i915_private *dev_priv) } if (i915_inject_load_failure()) { - DRM_DEBUG_DRIVER("Marking the driver as wedged\n"); - i915_gem_set_wedged(dev_priv); /* Fail silently! */ ret = -EIO; goto err_init_hw; } @@ -5543,7 +5541,8 @@ int i915_gem_init(struct drm_i915_private *dev_priv) * for all other failure, such as an allocation failure, bail. */ if (!i915_terminally_wedged(&dev_priv->gpu_error)) { - DRM_ERROR("Failed to initialize GPU, declaring it wedged\n"); + i915_load_error(dev_priv, + "Failed to initialize GPU, declaring it wedged!\n"); i915_gem_set_wedged(dev_priv); } ret = 0; -- GitLab From acd1c1e621fcd90bf94e31b0c871cd241c9153ef Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Mon, 11 Jun 2018 08:55:32 +0100 Subject: [PATCH 0218/1506] drm/i915: Refactor unsettting obj->mm.pages As i915_gem_object_phys_attach() wants to play dirty and mess around with obj->mm.pages itself (replacing the shmemfs with a DMA allocation), refactor the gubbins so into i915_gem_object_unset_pages() that we don't have to duplicate all the secrets. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Reviewed-by: Matthew Auld <matthew.auld@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180611075532.26534-1-chris@chris-wilson.co.uk Link: https://patchwork.freedesktop.org/patch/msgid/152871104647.1718.8796913290418060204@jlahtine-desk.ger.corp.intel.com --- drivers/gpu/drm/i915/i915_gem.c | 68 ++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 0f28b5ddfd156..93efd92362dbc 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2401,29 +2401,15 @@ static void __i915_gem_object_reset_page_iter(struct drm_i915_gem_object *obj) rcu_read_unlock(); } -void __i915_gem_object_put_pages(struct drm_i915_gem_object *obj, - enum i915_mm_subclass subclass) +static struct sg_table * +__i915_gem_object_unset_pages(struct drm_i915_gem_object *obj) { struct drm_i915_private *i915 = to_i915(obj->base.dev); struct sg_table *pages; - if (i915_gem_object_has_pinned_pages(obj)) - return; - - GEM_BUG_ON(obj->bind_count); - if (!i915_gem_object_has_pages(obj)) - return; - - /* May be called by shrinker from within get_pages() (on another bo) */ - mutex_lock_nested(&obj->mm.lock, subclass); - if (unlikely(atomic_read(&obj->mm.pages_pin_count))) - goto unlock; - - /* ->put_pages might need to allocate memory for the bit17 swizzle - * array, hence protect them from being reaped by removing them from gtt - * lists early. */ pages = fetch_and_zero(&obj->mm.pages); - GEM_BUG_ON(!pages); + if (!pages) + return NULL; spin_lock(&i915->mm.obj_lock); list_del(&obj->mm.link); @@ -2442,12 +2428,37 @@ void __i915_gem_object_put_pages(struct drm_i915_gem_object *obj, } __i915_gem_object_reset_page_iter(obj); + obj->mm.page_sizes.phys = obj->mm.page_sizes.sg = 0; + + return pages; +} +void __i915_gem_object_put_pages(struct drm_i915_gem_object *obj, + enum i915_mm_subclass subclass) +{ + struct sg_table *pages; + + if (i915_gem_object_has_pinned_pages(obj)) + return; + + GEM_BUG_ON(obj->bind_count); + if (!i915_gem_object_has_pages(obj)) + return; + + /* May be called by shrinker from within get_pages() (on another bo) */ + mutex_lock_nested(&obj->mm.lock, subclass); + if (unlikely(atomic_read(&obj->mm.pages_pin_count))) + goto unlock; + + /* + * ->put_pages might need to allocate memory for the bit17 swizzle + * array, hence protect them from being reaped by removing them from gtt + * lists early. + */ + pages = __i915_gem_object_unset_pages(obj); if (!IS_ERR(pages)) obj->ops->put_pages(obj, pages); - obj->mm.page_sizes.phys = obj->mm.page_sizes.sg = 0; - unlock: mutex_unlock(&obj->mm.lock); } @@ -6089,16 +6100,7 @@ int i915_gem_object_attach_phys(struct drm_i915_gem_object *obj, int align) goto err_unlock; } - pages = fetch_and_zero(&obj->mm.pages); - if (pages) { - struct drm_i915_private *i915 = to_i915(obj->base.dev); - - __i915_gem_object_reset_page_iter(obj); - - spin_lock(&i915->mm.obj_lock); - list_del(&obj->mm.link); - spin_unlock(&i915->mm.obj_lock); - } + pages = __i915_gem_object_unset_pages(obj); obj->ops = &i915_gem_phys_ops; @@ -6116,7 +6118,11 @@ int i915_gem_object_attach_phys(struct drm_i915_gem_object *obj, int align) err_xfer: obj->ops = &i915_gem_object_ops; - obj->mm.pages = pages; + if (!IS_ERR_OR_NULL(pages)) { + unsigned int sg_page_sizes = i915_sg_page_sizes(pages->sgl); + + __i915_gem_object_set_pages(obj, pages, sg_page_sizes); + } err_unlock: mutex_unlock(&obj->mm.lock); return err; -- GitLab From 746c8f143afad7aaa66c484485fc39888d437a3f Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Sun, 10 Jun 2018 20:43:09 +0100 Subject: [PATCH 0219/1506] drm/i915: Apply batch location restrictions before pinning We special case the position of the batch within the GTT to prevent negative self-relocation deltas from underflowing. However, that restriction is being applied after a trial pin of the batch in its current position. Thus we are not rejecting an invalid location if the batch has been used before, leading to an assertion if we happen to need to rearrange the entire payload. In the worst case, this may cause a GPU hang on gen7 or perhaps missing state. References: https://bugs.freedesktop.org/show_bug.cgi?id=105720 Fixes: 2889caa92321 ("drm/i915: Eliminate lots of iterations over the execobjects array") Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Martin Peres <martin.peres@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180610194325.13467-2-chris@chris-wilson.co.uk Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 49 ++++++++++++---------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index eefd449502e27..2d2eb3075960c 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -489,7 +489,9 @@ eb_validate_vma(struct i915_execbuffer *eb, } static int -eb_add_vma(struct i915_execbuffer *eb, unsigned int i, struct i915_vma *vma) +eb_add_vma(struct i915_execbuffer *eb, + unsigned int i, unsigned batch_idx, + struct i915_vma *vma) { struct drm_i915_gem_exec_object2 *entry = &eb->exec[i]; int err; @@ -522,6 +524,24 @@ eb_add_vma(struct i915_execbuffer *eb, unsigned int i, struct i915_vma *vma) eb->flags[i] = entry->flags; vma->exec_flags = &eb->flags[i]; + /* + * SNA is doing fancy tricks with compressing batch buffers, which leads + * to negative relocation deltas. Usually that works out ok since the + * relocate address is still positive, except when the batch is placed + * very low in the GTT. Ensure this doesn't happen. + * + * Note that actual hangs have only been observed on gen7, but for + * paranoia do it everywhere. + */ + if (i == batch_idx) { + if (!(eb->flags[i] & EXEC_OBJECT_PINNED)) + eb->flags[i] |= __EXEC_OBJECT_NEEDS_BIAS; + if (eb->reloc_cache.has_fence) + eb->flags[i] |= EXEC_OBJECT_NEEDS_FENCE; + + eb->batch = vma; + } + err = 0; if (eb_pin_vma(eb, entry, vma)) { if (entry->offset != vma->node.start) { @@ -716,7 +736,7 @@ static int eb_lookup_vmas(struct i915_execbuffer *eb) { struct radix_tree_root *handles_vma = &eb->ctx->handles_vma; struct drm_i915_gem_object *obj; - unsigned int i; + unsigned int i, batch; int err; if (unlikely(i915_gem_context_is_closed(eb->ctx))) @@ -728,6 +748,8 @@ static int eb_lookup_vmas(struct i915_execbuffer *eb) INIT_LIST_HEAD(&eb->relocs); INIT_LIST_HEAD(&eb->unbound); + batch = eb_batch_index(eb); + for (i = 0; i < eb->buffer_count; i++) { u32 handle = eb->exec[i].handle; struct i915_lut_handle *lut; @@ -770,33 +792,16 @@ static int eb_lookup_vmas(struct i915_execbuffer *eb) lut->handle = handle; add_vma: - err = eb_add_vma(eb, i, vma); + err = eb_add_vma(eb, i, batch, vma); if (unlikely(err)) goto err_vma; GEM_BUG_ON(vma != eb->vma[i]); GEM_BUG_ON(vma->exec_flags != &eb->flags[i]); + GEM_BUG_ON(drm_mm_node_allocated(&vma->node) && + eb_vma_misplaced(&eb->exec[i], vma, eb->flags[i])); } - /* take note of the batch buffer before we might reorder the lists */ - i = eb_batch_index(eb); - eb->batch = eb->vma[i]; - GEM_BUG_ON(eb->batch->exec_flags != &eb->flags[i]); - - /* - * SNA is doing fancy tricks with compressing batch buffers, which leads - * to negative relocation deltas. Usually that works out ok since the - * relocate address is still positive, except when the batch is placed - * very low in the GTT. Ensure this doesn't happen. - * - * Note that actual hangs have only been observed on gen7, but for - * paranoia do it everywhere. - */ - if (!(eb->flags[i] & EXEC_OBJECT_PINNED)) - eb->flags[i] |= __EXEC_OBJECT_NEEDS_BIAS; - if (eb->reloc_cache.has_fence) - eb->flags[i] |= EXEC_OBJECT_NEEDS_FENCE; - eb->args->flags |= __EXEC_VALIDATED; return eb_reserve(eb); -- GitLab From 9904b1560e4a2e7c956004f9843939e23d84cd7b Mon Sep 17 00:00:00 2001 From: Michel Thierry <michel.thierry@intel.com> Date: Mon, 4 Jun 2018 16:32:49 -0700 Subject: [PATCH 0220/1506] drm/i915/perf: use the lrc_desc to get the ctx hw id in gen8-10 The upper 32 bits of the lrc_desc (bits 52-32 to be precise) are the context hw id in GEN8-10, so use them and have one less thing to maintain in the unlikely case we change the descriptor sw fields. v2: If we use the lrc_desc, we must apply the ctx_id_mask too (Lionel) Signed-off-by: Michel Thierry <michel.thierry@intel.com> Cc: Lionel Landwerlin <lionel.g.landwerlin@intel.com> Cc: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com> Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180604233250.609-1-michel.thierry@intel.com --- drivers/gpu/drm/i915/i915_perf.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index a6c8d61add0cd..6aba30cb40eac 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -1279,9 +1279,12 @@ static int oa_get_render_ctx_id(struct i915_perf_stream *stream) i915->perf.oa.specific_ctx_id_mask = (1U << (GEN8_CTX_ID_WIDTH - 1)) - 1; } else { - i915->perf.oa.specific_ctx_id = stream->ctx->hw_id; i915->perf.oa.specific_ctx_id_mask = (1U << GEN8_CTX_ID_WIDTH) - 1; + i915->perf.oa.specific_ctx_id = + upper_32_bits(ce->lrc_desc); + i915->perf.oa.specific_ctx_id &= + i915->perf.oa.specific_ctx_id_mask; } break; -- GitLab From 2b9a820318ebdf81f666be4daf7414d98123fefb Mon Sep 17 00:00:00 2001 From: Michel Thierry <michel.thierry@intel.com> Date: Mon, 4 Jun 2018 16:32:50 -0700 Subject: [PATCH 0221/1506] drm/i915/perf: fix gen11 engine class shift Use the correct engine class shift value while storing the ctx hw id. Fixes the copy+paste error from commit 61d5676b5561 ("drm/i915/perf: fix ctx_id read with GuC & ICL"). Apologies for not spotting this in the original review, the specific_ctx_id_mask is correct, only the specific_ctx_id had this problem. v2: Just use the upper 32 bits of lrc_desc (Chris) v3: If we use the lrc_desc, we must apply the ctx_id_mask too (Lionel) Fixes: 61d5676b5561 ("drm/i915/perf: fix ctx_id read with GuC & ICL") Signed-off-by: Michel Thierry <michel.thierry@intel.com> Cc: Lionel Landwerlin <lionel.g.landwerlin@intel.com> Cc: Chris Wilson <chris@chris-wilson.co.uk> Cc: Michel Thierry <michel.thierry@intel.com> Cc: Matthew Auld <matthew.auld@intel.com> Cc: Jani Nikula <jani.nikula@linux.intel.com> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com> Cc: intel-gfx@lists.freedesktop.org Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com> Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180604233250.609-2-michel.thierry@intel.com --- drivers/gpu/drm/i915/i915_perf.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index 6aba30cb40eac..881a992305ecd 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -1289,16 +1289,13 @@ static int oa_get_render_ctx_id(struct i915_perf_stream *stream) break; case 11: { - struct intel_engine_cs *engine = i915->engine[RCS]; - - i915->perf.oa.specific_ctx_id = - stream->ctx->hw_id << (GEN11_SW_CTX_ID_SHIFT - 32) | - engine->instance << (GEN11_ENGINE_INSTANCE_SHIFT - 32) | - engine->class << (GEN11_ENGINE_INSTANCE_SHIFT - 32); i915->perf.oa.specific_ctx_id_mask = ((1U << GEN11_SW_CTX_ID_WIDTH) - 1) << (GEN11_SW_CTX_ID_SHIFT - 32) | ((1U << GEN11_ENGINE_INSTANCE_WIDTH) - 1) << (GEN11_ENGINE_INSTANCE_SHIFT - 32) | ((1 << GEN11_ENGINE_CLASS_WIDTH) - 1) << (GEN11_ENGINE_CLASS_SHIFT - 32); + i915->perf.oa.specific_ctx_id = upper_32_bits(ce->lrc_desc); + i915->perf.oa.specific_ctx_id &= + i915->perf.oa.specific_ctx_id_mask; break; } -- GitLab From 602a9de513d5a43ecaf7d0443eca41656165d3c4 Mon Sep 17 00:00:00 2001 From: Imre Deak <imre.deak@intel.com> Date: Fri, 8 Jun 2018 17:41:37 +0300 Subject: [PATCH 0222/1506] drm/i915/skl: Add warn about unsupported CDCLK rates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While checking workarounds related to the CDCLK PLL, I noticed that the DMC firmware bits for WA#1183 are missing for SKL. After that I clarified with HW people that it's not needed on SKL, since it doesn't support eDP1.4 which would be the only thing requiring the problematic CDCLK clock rates. So in theory we shouldn't ever choose these frequencies, but add an assert in any case for catching such cases and for documentation. v2: - Move the check to skl_set_cdclk and warn whenever using the corresponding VCO freq. (Ville) v3: - Actually check for the platform. (Ville) Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Imre Deak <imre.deak@intel.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180608144137.7943-1-imre.deak@intel.com --- drivers/gpu/drm/i915/intel_cdclk.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_cdclk.c b/drivers/gpu/drm/i915/intel_cdclk.c index 704ddb4d3ca7e..8ed7bd052e462 100644 --- a/drivers/gpu/drm/i915/intel_cdclk.c +++ b/drivers/gpu/drm/i915/intel_cdclk.c @@ -991,6 +991,16 @@ static void skl_set_cdclk(struct drm_i915_private *dev_priv, u32 freq_select, cdclk_ctl; int ret; + /* + * Based on WA#1183 CDCLK rates 308 and 617MHz CDCLK rates are + * unsupported on SKL. In theory this should never happen since only + * the eDP1.4 2.16 and 4.32Gbps rates require it, but eDP1.4 is not + * supported on SKL either, see the above WA. WARN whenever trying to + * use the corresponding VCO freq as that always leads to using the + * minimum 308MHz CDCLK. + */ + WARN_ON_ONCE(IS_SKYLAKE(dev_priv) && vco == 8640000); + mutex_lock(&dev_priv->pcu_lock); ret = skl_pcode_request(dev_priv, SKL_PCODE_CDCLK_CONTROL, SKL_CDCLK_PREPARE_FOR_CHANGE, -- GitLab From 1fc719d13ac07b082ff9daa8f40254680cade111 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Mon, 11 Jun 2018 11:48:08 +0100 Subject: [PATCH 0223/1506] drm/i915/ringbuffer: Brute force context restore An issue encountered with switching mm on gen7 is that the GPU likes to hang (with the VS unit busy) when told to force restore the current context. We can simply workaround this by substituting the MI_FORCE_RESTORE flag with a round-trip through the kernel_context, forcing the context to be saved and restored; thereby reloading the PP_DIR registers and updating the modified page directory! v2: Undo attempted optimisation in caller (Tvrtko) Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: Matthew Auld <matthew.william.auld@gmail.com> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180611104808.24295-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_ringbuffer.c | 27 +++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 6496c1d00dbba..5bc53a5f4504e 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1456,6 +1456,7 @@ static inline int mi_set_context(struct i915_request *rq, u32 flags) (HAS_LEGACY_SEMAPHORES(i915) && IS_GEN7(i915)) ? INTEL_INFO(i915)->num_rings - 1 : 0; + bool force_restore = false; int len; u32 *cs; @@ -1469,6 +1470,12 @@ static inline int mi_set_context(struct i915_request *rq, u32 flags) len = 4; if (IS_GEN7(i915)) len += 2 + (num_rings ? 4*num_rings + 6 : 0); + if (flags & MI_FORCE_RESTORE) { + GEM_BUG_ON(flags & MI_RESTORE_INHIBIT); + flags &= ~MI_FORCE_RESTORE; + force_restore = true; + len += 2; + } cs = intel_ring_begin(rq, len); if (IS_ERR(cs)) @@ -1493,6 +1500,26 @@ static inline int mi_set_context(struct i915_request *rq, u32 flags) } } + if (force_restore) { + /* + * The HW doesn't handle being told to restore the current + * context very well. Quite often it likes goes to go off and + * sulk, especially when it is meant to be reloading PP_DIR. + * A very simple fix to force the reload is to simply switch + * away from the current context and back again. + * + * Note that the kernel_context will contain random state + * following the INHIBIT_RESTORE. We accept this since we + * never use the kernel_context state; it is merely a + * placeholder we use to flush other contexts. + */ + *cs++ = MI_SET_CONTEXT; + *cs++ = i915_ggtt_offset(to_intel_context(i915->kernel_context, + engine)->state) | + MI_MM_SPACE_GTT | + MI_RESTORE_INHIBIT; + } + *cs++ = MI_NOOP; *cs++ = MI_SET_CONTEXT; *cs++ = i915_ggtt_offset(rq->hw_context->state) | flags; -- GitLab From b3ee09a4de33259a89d30aca6b2ebb0bc26640af Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Mon, 11 Jun 2018 12:08:44 +0100 Subject: [PATCH 0224/1506] drm/i915/ringbuffer: Fix context restore upon reset The discovery with trying to enable full-ppgtt was that we were completely failing to the load both the mm and context following the reset. Although we were performing mmio to set the PP_DIR (per-process GTT) and CCID (context), these were taking no effect (the assumption was that this would trigger reload of the context and restore the page tables). It was not until we performed the LRI + MI_SET_CONTEXT in a following context switch would anything occur. Since we are then required to reset the context image and PP_DIR using CS commands, we place those commands into every batch. The hardware should recognise the no-ops and eliminate the expensive context loads, but we still have to pay the cost of using cross-powerwell register writes. In practice, this has no effect on actual context switch times, and only adds a few hundred nanoseconds to no-op switches. We can improve the latter by eliminating the w/a around known no-op switches, but there is an ulterior motive to keeping them. Always emitting the context switch at the beginning of the request (and relying on HW to skip unneeded switches) does have one key advantage. Should we implement request reordering on Haswell, we will not know in advance what the previous executing context was on the GPU and so we would not be able to elide the MI_SET_CONTEXT commands ourselves and always have to emit them. Having our hand forced now actually prepares us for later. Now since that context and mm follow the request, we no longer (and not for a long time since requests took over!) require a trace point to tell when we write the switch into the ring, since it is always. (This is even more important when you remember that simply writing into the ring bears no relation to the current mm.) v2: Sandybridge has to agree to use LRI as well. Testcase: igt/drv_selftests/live_hangcheck Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: Matthew Auld <matthew.william.auld@gmail.com> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180611110845.31890-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_gtt.c | 45 --------- drivers/gpu/drm/i915/i915_gem_gtt.h | 2 - drivers/gpu/drm/i915/i915_request.c | 2 + drivers/gpu/drm/i915/i915_request.h | 3 + drivers/gpu/drm/i915/i915_trace.h | 33 ------- drivers/gpu/drm/i915/intel_engine_cs.c | 3 - drivers/gpu/drm/i915/intel_ringbuffer.c | 125 ++++++++++++------------ drivers/gpu/drm/i915/intel_ringbuffer.h | 9 -- 8 files changed, 66 insertions(+), 156 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 7ccfdbc8f9b43..ac75e0c5735c6 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1712,45 +1712,6 @@ static void gen6_write_page_range(struct i915_hw_ppgtt *ppgtt, wmb(); } -static inline u32 get_pd_offset(struct i915_hw_ppgtt *ppgtt) -{ - GEM_BUG_ON(ppgtt->pd.base.ggtt_offset & 0x3f); - return ppgtt->pd.base.ggtt_offset << 10; -} - -static int gen7_mm_switch(struct i915_hw_ppgtt *ppgtt, - struct i915_request *rq) -{ - struct intel_engine_cs *engine = rq->engine; - u32 *cs; - - /* NB: TLBs must be flushed and invalidated before a switch */ - cs = intel_ring_begin(rq, 6); - if (IS_ERR(cs)) - return PTR_ERR(cs); - - *cs++ = MI_LOAD_REGISTER_IMM(2); - *cs++ = i915_mmio_reg_offset(RING_PP_DIR_DCLV(engine)); - *cs++ = PP_DIR_DCLV_2G; - *cs++ = i915_mmio_reg_offset(RING_PP_DIR_BASE(engine)); - *cs++ = get_pd_offset(ppgtt); - *cs++ = MI_NOOP; - intel_ring_advance(rq, cs); - - return 0; -} - -static int gen6_mm_switch(struct i915_hw_ppgtt *ppgtt, - struct i915_request *rq) -{ - struct intel_engine_cs *engine = rq->engine; - struct drm_i915_private *dev_priv = rq->i915; - - I915_WRITE(RING_PP_DIR_DCLV(engine), PP_DIR_DCLV_2G); - I915_WRITE(RING_PP_DIR_BASE(engine), get_pd_offset(ppgtt)); - return 0; -} - static void gen8_ppgtt_enable(struct drm_i915_private *dev_priv) { struct intel_engine_cs *engine; @@ -2024,12 +1985,6 @@ static struct i915_hw_ppgtt *gen6_ppgtt_create(struct drm_i915_private *i915) ppgtt->vm.dma = &i915->drm.pdev->dev; ppgtt->vm.pte_encode = ggtt->vm.pte_encode; - if (IS_GEN6(i915)) - ppgtt->switch_mm = gen6_mm_switch; - else if (IS_GEN7(i915)) - ppgtt->switch_mm = gen7_mm_switch; - else - BUG(); err = gen6_ppgtt_alloc(ppgtt); if (err) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index 16307ba7e3035..e70f6abcd0f28 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -406,8 +406,6 @@ struct i915_hw_ppgtt { gen6_pte_t __iomem *pd_addr; - int (*switch_mm)(struct i915_hw_ppgtt *ppgtt, - struct i915_request *rq); void (*debug_dump)(struct i915_hw_ppgtt *ppgtt, struct seq_file *m); }; diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index f187250e60c6f..9092f5464c24d 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -817,6 +817,8 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx) /* Keep a second pin for the dual retirement along engine and ring */ __intel_context_pin(ce); + rq->infix = rq->ring->emit; /* end of header; start of user payload */ + /* Check that we didn't interrupt ourselves with a new request */ GEM_BUG_ON(rq->timeline->seqno != rq->fence.seqno); return rq; diff --git a/drivers/gpu/drm/i915/i915_request.h b/drivers/gpu/drm/i915/i915_request.h index 491ff81d0fea7..0e9aba53d0e42 100644 --- a/drivers/gpu/drm/i915/i915_request.h +++ b/drivers/gpu/drm/i915/i915_request.h @@ -134,6 +134,9 @@ struct i915_request { /** Position in the ring of the start of the request */ u32 head; + /** Position in the ring of the start of the user packets */ + u32 infix; + /** * Position in the ring of the start of the postfix. * This is required to calculate the maximum available ring space diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h index 1472f48ab2e80..b50c6b829715e 100644 --- a/drivers/gpu/drm/i915/i915_trace.h +++ b/drivers/gpu/drm/i915/i915_trace.h @@ -973,39 +973,6 @@ DEFINE_EVENT(i915_context, i915_context_free, TP_ARGS(ctx) ); -/** - * DOC: switch_mm tracepoint - * - * This tracepoint allows tracking of the mm switch, which is an important point - * in the lifetime of the vm in the legacy submission path. This tracepoint is - * called only if full ppgtt is enabled. - */ -TRACE_EVENT(switch_mm, - TP_PROTO(struct intel_engine_cs *engine, struct i915_gem_context *to), - - TP_ARGS(engine, to), - - TP_STRUCT__entry( - __field(u16, class) - __field(u16, instance) - __field(struct i915_gem_context *, to) - __field(struct i915_address_space *, vm) - __field(u32, dev) - ), - - TP_fast_assign( - __entry->class = engine->uabi_class; - __entry->instance = engine->instance; - __entry->to = to; - __entry->vm = to->ppgtt ? &to->ppgtt->vm : NULL; - __entry->dev = engine->i915->drm.primary->index; - ), - - TP_printk("dev=%u, engine=%u:%u, ctx=%p, ctx_vm=%p", - __entry->dev, __entry->class, __entry->instance, __entry->to, - __entry->vm) -); - #endif /* _I915_TRACE_H_ */ /* This part must be outside protection */ diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index 2ec2e60dc6707..d1cf8b4926abe 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -1168,9 +1168,6 @@ void intel_engine_lost_context(struct intel_engine_cs *engine) lockdep_assert_held(&engine->i915->drm.struct_mutex); - engine->legacy_active_context = NULL; - engine->legacy_active_ppgtt = NULL; - ce = fetch_and_zero(&engine->last_retired_context); if (ce) intel_context_unpin(ce); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 5bc53a5f4504e..d72a6a5ff3acb 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -541,11 +541,23 @@ static struct i915_request *reset_prepare(struct intel_engine_cs *engine) return i915_gem_find_active_request(engine); } -static void reset_ring(struct intel_engine_cs *engine, - struct i915_request *request) +static void skip_request(struct i915_request *rq) { - GEM_TRACE("%s seqno=%x\n", - engine->name, request ? request->global_seqno : 0); + void *vaddr = rq->ring->vaddr; + u32 head; + + head = rq->infix; + if (rq->postfix < head) { + memset32(vaddr + head, MI_NOOP, + (rq->ring->size - head) / sizeof(u32)); + head = 0; + } + memset32(vaddr + head, MI_NOOP, (rq->postfix - head) / sizeof(u32)); +} + +static void reset_ring(struct intel_engine_cs *engine, struct i915_request *rq) +{ + GEM_TRACE("%s seqno=%x\n", engine->name, rq ? rq->global_seqno : 0); /* * RC6 must be prevented until the reset is complete and the engine @@ -569,43 +581,11 @@ static void reset_ring(struct intel_engine_cs *engine, * If the request was innocent, we try to replay the request with * the restored context. */ - if (request) { - struct drm_i915_private *dev_priv = request->i915; - struct intel_context *ce = request->hw_context; - struct i915_hw_ppgtt *ppgtt; - - if (ce->state) { - I915_WRITE(CCID, - i915_ggtt_offset(ce->state) | - BIT(8) /* must be set! */ | - CCID_EXTENDED_STATE_SAVE | - CCID_EXTENDED_STATE_RESTORE | - CCID_EN); - } - - ppgtt = request->gem_context->ppgtt ?: engine->i915->mm.aliasing_ppgtt; - if (ppgtt) { - u32 pd_offset = ppgtt->pd.base.ggtt_offset << 10; - - I915_WRITE(RING_PP_DIR_DCLV(engine), PP_DIR_DCLV_2G); - I915_WRITE(RING_PP_DIR_BASE(engine), pd_offset); - - /* Wait for the PD reload to complete */ - if (intel_wait_for_register(dev_priv, - RING_PP_DIR_BASE(engine), - BIT(0), 0, - 10)) - DRM_ERROR("Wait for reload of ppgtt page-directory timed out\n"); - - ppgtt->pd_dirty_rings &= ~intel_engine_flag(engine); - } - + if (rq) { /* If the rq hung, jump to its breadcrumb and skip the batch */ - if (request->fence.error == -EIO) - request->ring->head = request->postfix; - } else { - engine->legacy_active_context = NULL; - engine->legacy_active_ppgtt = NULL; + rq->ring->head = intel_ring_wrap(rq->ring, rq->head); + if (rq->fence.error == -EIO) + skip_request(rq); } } @@ -1446,6 +1426,29 @@ void intel_legacy_submission_resume(struct drm_i915_private *dev_priv) intel_ring_reset(engine->buffer, 0); } +static int load_pd_dir(struct i915_request *rq, + const struct i915_hw_ppgtt *ppgtt) +{ + const struct intel_engine_cs * const engine = rq->engine; + u32 *cs; + + cs = intel_ring_begin(rq, 6); + if (IS_ERR(cs)) + return PTR_ERR(cs); + + *cs++ = MI_LOAD_REGISTER_IMM(1); + *cs++ = i915_mmio_reg_offset(RING_PP_DIR_DCLV(engine)); + *cs++ = PP_DIR_DCLV_2G; + + *cs++ = MI_LOAD_REGISTER_IMM(1); + *cs++ = i915_mmio_reg_offset(RING_PP_DIR_BASE(engine)); + *cs++ = ppgtt->pd.base.ggtt_offset << 10; + + intel_ring_advance(rq, cs); + + return 0; +} + static inline int mi_set_context(struct i915_request *rq, u32 flags) { struct drm_i915_private *i915 = rq->i915; @@ -1590,31 +1593,28 @@ static int remap_l3(struct i915_request *rq, int slice) static int switch_context(struct i915_request *rq) { struct intel_engine_cs *engine = rq->engine; - struct i915_gem_context *to_ctx = rq->gem_context; - struct i915_hw_ppgtt *to_mm = - to_ctx->ppgtt ?: rq->i915->mm.aliasing_ppgtt; - struct i915_gem_context *from_ctx = engine->legacy_active_context; - struct i915_hw_ppgtt *from_mm = engine->legacy_active_ppgtt; + struct i915_gem_context *ctx = rq->gem_context; + struct i915_hw_ppgtt *ppgtt = ctx->ppgtt ?: rq->i915->mm.aliasing_ppgtt; + unsigned int unwind_mm = 0; u32 hw_flags = 0; int ret, i; lockdep_assert_held(&rq->i915->drm.struct_mutex); GEM_BUG_ON(HAS_EXECLISTS(rq->i915)); - if (to_mm != from_mm || - (to_mm && intel_engine_flag(engine) & to_mm->pd_dirty_rings)) { - trace_switch_mm(engine, to_ctx); - ret = to_mm->switch_mm(to_mm, rq); + if (ppgtt) { + ret = load_pd_dir(rq, ppgtt); if (ret) goto err; - to_mm->pd_dirty_rings &= ~intel_engine_flag(engine); - engine->legacy_active_ppgtt = to_mm; - hw_flags = MI_FORCE_RESTORE; + if (intel_engine_flag(engine) & ppgtt->pd_dirty_rings) { + unwind_mm = intel_engine_flag(engine); + ppgtt->pd_dirty_rings &= ~unwind_mm; + hw_flags = MI_FORCE_RESTORE; + } } - if (rq->hw_context->state && - (to_ctx != from_ctx || hw_flags & MI_FORCE_RESTORE)) { + if (rq->hw_context->state) { GEM_BUG_ON(engine->id != RCS); /* @@ -1624,35 +1624,32 @@ static int switch_context(struct i915_request *rq) * as nothing actually executes using the kernel context; it * is purely used for flushing user contexts. */ - if (i915_gem_context_is_kernel(to_ctx)) + if (i915_gem_context_is_kernel(ctx)) hw_flags = MI_RESTORE_INHIBIT; ret = mi_set_context(rq, hw_flags); if (ret) goto err_mm; - - engine->legacy_active_context = to_ctx; } - if (to_ctx->remap_slice) { + if (ctx->remap_slice) { for (i = 0; i < MAX_L3_SLICES; i++) { - if (!(to_ctx->remap_slice & BIT(i))) + if (!(ctx->remap_slice & BIT(i))) continue; ret = remap_l3(rq, i); if (ret) - goto err_ctx; + goto err_mm; } - to_ctx->remap_slice = 0; + ctx->remap_slice = 0; } return 0; -err_ctx: - engine->legacy_active_context = from_ctx; err_mm: - engine->legacy_active_ppgtt = from_mm; + if (unwind_mm) + ppgtt->pd_dirty_rings |= unwind_mm; err: return ret; } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index acef385c4c80d..b44c678497494 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -557,15 +557,6 @@ struct intel_engine_cs { */ struct intel_context *last_retired_context; - /* We track the current MI_SET_CONTEXT in order to eliminate - * redudant context switches. This presumes that requests are not - * reordered! Or when they are the tracking is updated along with - * the emission of individual requests into the legacy command - * stream (ring). - */ - struct i915_gem_context *legacy_active_context; - struct i915_hw_ppgtt *legacy_active_ppgtt; - /* status_notifier: list of callbacks for context-switch changes */ struct atomic_notifier_head context_status_notifier; -- GitLab From 41d37680ca0b157ad1ed29409bcdc2b0bc21d11f Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Mon, 11 Jun 2018 12:08:45 +0100 Subject: [PATCH 0225/1506] drm/i915: Wrap around the tail offset before setting ring->tail The HW only accepts offsets within ring->size, and fails peculiarly if the RING_HEAD or RING_TAIL is set to ring->size. Therefore whenever we set ring->head/ring->tail we want to make sure it is within value (using intel_ring_wrap()). v2: Double check execlists as well v3: Remove redundancy with assert_ring_tail_valid() v4: Just assert in intel_ring_reset() rather than be over-defensive. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: Matthew Auld <matthew.william.auld@gmail.com> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> #v2 Link: https://patchwork.freedesktop.org/patch/msgid/20180611110845.31890-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_lrc.c | 6 ++++-- drivers/gpu/drm/i915/intel_ringbuffer.c | 6 ++++++ drivers/gpu/drm/i915/intel_ringbuffer.h | 20 ++++++++++++++------ 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 0935a19aca96f..3401889e51217 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1414,6 +1414,7 @@ __execlists_context_pin(struct intel_engine_cs *engine, ce->lrc_reg_state = vaddr + LRC_STATE_PN * PAGE_SIZE; ce->lrc_reg_state[CTX_RING_BUFFER_START+1] = i915_ggtt_offset(ce->ring->vma); + GEM_BUG_ON(!intel_ring_offset_valid(ce->ring, ce->ring->head)); ce->lrc_reg_state[CTX_RING_HEAD+1] = ce->ring->head; ce->state->obj->pin_global++; @@ -2002,9 +2003,10 @@ static void execlists_reset(struct intel_engine_cs *engine, /* Move the RING_HEAD onto the breadcrumb, past the hanging batch */ regs[CTX_RING_BUFFER_START + 1] = i915_ggtt_offset(request->ring->vma); - regs[CTX_RING_HEAD + 1] = request->postfix; - request->ring->head = request->postfix; + request->ring->head = intel_ring_wrap(request->ring, request->postfix); + regs[CTX_RING_HEAD + 1] = request->ring->head; + intel_ring_update_space(request->ring); /* Reset WaIdleLiteRestore:bdw,skl as well */ diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index d72a6a5ff3acb..bb4af8f84a22c 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -496,6 +496,10 @@ static int init_ring_common(struct intel_engine_cs *engine) DRM_DEBUG_DRIVER("%s initialization failed [head=%08x], fudging\n", engine->name, I915_READ_HEAD(engine)); + /* Check that the ring offsets point within the ring! */ + GEM_BUG_ON(!intel_ring_offset_valid(ring, ring->head)); + GEM_BUG_ON(!intel_ring_offset_valid(ring, ring->tail)); + intel_ring_update_space(ring); I915_WRITE_HEAD(engine, ring->head); I915_WRITE_TAIL(engine, ring->tail); @@ -1062,6 +1066,8 @@ int intel_ring_pin(struct intel_ring *ring, void intel_ring_reset(struct intel_ring *ring, u32 tail) { + GEM_BUG_ON(!intel_ring_offset_valid(ring, tail)); + ring->tail = tail; ring->head = tail; ring->emit = tail; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index b44c678497494..e9494557aaa12 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -805,6 +805,19 @@ static inline u32 intel_ring_wrap(const struct intel_ring *ring, u32 pos) return pos & (ring->size - 1); } +static inline bool +intel_ring_offset_valid(const struct intel_ring *ring, + unsigned int pos) +{ + if (pos & -ring->size) /* must be strictly within the ring */ + return false; + + if (!IS_ALIGNED(pos, 8)) /* must be qword aligned */ + return false; + + return true; +} + static inline u32 intel_ring_offset(const struct i915_request *rq, void *addr) { /* Don't write ring->size (equivalent to 0) as that hangs some GPUs. */ @@ -816,12 +829,7 @@ static inline u32 intel_ring_offset(const struct i915_request *rq, void *addr) static inline void assert_ring_tail_valid(const struct intel_ring *ring, unsigned int tail) { - /* We could combine these into a single tail operation, but keeping - * them as seperate tests will help identify the cause should one - * ever fire. - */ - GEM_BUG_ON(!IS_ALIGNED(tail, 8)); - GEM_BUG_ON(tail >= ring->size); + GEM_BUG_ON(!intel_ring_offset_valid(ring, tail)); /* * "Ring Buffer Use" -- GitLab From 467d35789e5a4f47428b65ef711b30fdabbb0fd4 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Mon, 11 Jun 2018 16:33:32 +0100 Subject: [PATCH 0226/1506] drm/i915/execlists: Avoid putting the error pointer On allocation error, do not jump to the unwind handler that tries to free the error pointer. Reported-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com> Fixes: a89d1f921c15 ("drm/i915: Split i915_gem_timeline into individual timelines") Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Lionel Landwerlin <lionel.g.landwerlin@intel.com> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180611153332.14824-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_lrc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 3401889e51217..44e4c9e075712 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -2771,10 +2771,8 @@ static int execlists_context_deferred_alloc(struct i915_gem_context *ctx, context_size += LRC_HEADER_PAGES * PAGE_SIZE; ctx_obj = i915_gem_object_create(ctx->i915, context_size); - if (IS_ERR(ctx_obj)) { - ret = PTR_ERR(ctx_obj); - goto error_deref_obj; - } + if (IS_ERR(ctx_obj)) + return PTR_ERR(ctx_obj); vma = i915_vma_instance(ctx_obj, &ctx->i915->ggtt.vm, NULL); if (IS_ERR(vma)) { -- GitLab From 06168448733a82da165981115d61b5d2faa82761 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Fri, 25 May 2018 21:50:33 +0300 Subject: [PATCH 0227/1506] drm/vmwgfx: Stop using plane->fb in vmw_kms_atomic_check_modeset() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of looking at plane->fb let's look at the proper new plane state. Not that the code makes a ton of sense. It's only going through the crtcs in the atomic state, so assuming not all of them are included we're not even calculating the total bandwidth here. Also we're not considering whether each crtc is actually enabled or not. Cc: Deepak Rawat <drawat@vmware.com> Cc: Thomas Hellstrom <thellstrom@vmware.com> Cc: Sinclair Yeh <syeh@vmware.com> Cc: VMware Graphics <linux-graphics-maintainer@vmware.com> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180525185045.29689-2-ville.syrjala@linux.intel.com Reviewed-by: Sinclair Yeh <syeh@vmware.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 6728c6247b4b6..a2a796b4cc238 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -1536,9 +1536,13 @@ vmw_kms_atomic_check_modeset(struct drm_device *dev, unsigned long requested_bb_mem = 0; if (dev_priv->active_display_unit == vmw_du_screen_target) { - if (crtc->primary->fb) { - int cpp = crtc->primary->fb->pitches[0] / - crtc->primary->fb->width; + struct drm_plane *plane = crtc->primary; + struct drm_plane_state *plane_state; + + plane_state = drm_atomic_get_new_plane_state(state, plane); + + if (plane_state && plane_state->fb) { + int cpp = plane_state->fb->format->cpp[0]; requested_bb_mem += crtc->mode.hdisplay * cpp * crtc->mode.vdisplay; -- GitLab From 464ce098e69cf886ce99a08cb3ebf5f8c53820b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Fri, 25 May 2018 21:50:34 +0300 Subject: [PATCH 0228/1506] drm/vmwgfx: Stop using plane->fb in vmw_kms_helper_dirty() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of plane->fb (which we're going to deprecate for atomic drivers) we need to look at plane->state->fb. The maze of code leading to vmw_kms_helper_dirty() wasn't particularly clear, but my analysis concluded that the calls originating from vmw_*_primary_plane_atomic_update() all pass in the crtc which means we'll never end up in this branch of the function. All other callers use drm_modeset_lock_all() somewhere higher up, which means accessing plane->state is safe. v2: Drop the comment and make the code do what it did before (Thomas) v3: Drop the bogus lockdep assert Cc: Deepak Rawat <drawat@vmware.com> Cc: Thomas Hellstrom <thellstrom@vmware.com> Cc: Sinclair Yeh <syeh@vmware.com> Cc: VMware Graphics <linux-graphics-maintainer@vmware.com> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180525185045.29689-3-ville.syrjala@linux.intel.com Reviewed-by: Sinclair Yeh <syeh@vmware.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index a2a796b4cc238..146ea18d765ec 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -2326,9 +2326,10 @@ int vmw_kms_helper_dirty(struct vmw_private *dev_priv, } else { list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) { - if (crtc->primary->fb != &framebuffer->base) - continue; - units[num_units++] = vmw_crtc_to_du(crtc); + struct drm_plane *plane = crtc->primary; + + if (plane->state->fb == &framebuffer->base) + units[num_units++] = vmw_crtc_to_du(crtc); } } -- GitLab From ec8a31a7d0eb9f2bc675bf4ad6bdcc9cc84e6221 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Fri, 25 May 2018 21:50:35 +0300 Subject: [PATCH 0229/1506] drm/vmwgfx: Stop using plane->fb in vmw_kms_update_implicit_fb() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The only caller of vmw_kms_update_implicit_fb() is the page_flip hook which itself gets called with the plane mutex already held. Hence we can look at plane->state safely. v2: Drop the bogus lockdep assert Cc: Deepak Rawat <drawat@vmware.com> Cc: Thomas Hellstrom <thellstrom@vmware.com> Cc: Sinclair Yeh <syeh@vmware.com> Cc: VMware Graphics <linux-graphics-maintainer@vmware.com> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Deepak Rawat <drawat@vmware.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180525185045.29689-4-ville.syrjala@linux.intel.com Reviewed-by: Sinclair Yeh <syeh@vmware.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 146ea18d765ec..e6889682205f4 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -2803,6 +2803,7 @@ void vmw_kms_update_implicit_fb(struct vmw_private *dev_priv, struct drm_crtc *crtc) { struct vmw_display_unit *du = vmw_crtc_to_du(crtc); + struct drm_plane *plane = crtc->primary; struct vmw_framebuffer *vfb; mutex_lock(&dev_priv->global_kms_state_mutex); @@ -2810,7 +2811,7 @@ void vmw_kms_update_implicit_fb(struct vmw_private *dev_priv, if (!du->is_implicit) goto out_unlock; - vfb = vmw_framebuffer_to_vfb(crtc->primary->fb); + vfb = vmw_framebuffer_to_vfb(plane->state->fb); WARN_ON_ONCE(dev_priv->num_implicit != 1 && dev_priv->implicit_fb != vfb); -- GitLab From e1cd4f8e45937ce7bbf2613de2c9503d3cda6c12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Fri, 25 May 2018 21:50:36 +0300 Subject: [PATCH 0230/1506] drm/vmwgfx: Stop updating plane->fb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to get rid of plane->fb on atomic drivers. Stop setting it. Cc: Deepak Rawat <drawat@vmware.com> Cc: Thomas Hellstrom <thellstrom@vmware.com> Cc: Sinclair Yeh <syeh@vmware.com> Cc: VMware Graphics <linux-graphics-maintainer@vmware.com> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Deepak Rawat <drawat@vmware.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180525185045.29689-5-ville.syrjala@linux.intel.com Reviewed-by: Sinclair Yeh <syeh@vmware.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 2 -- drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 2 -- 2 files changed, 4 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index 648f8127f65ae..bbd3f19b1a0bf 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -525,8 +525,6 @@ vmw_sou_primary_plane_atomic_update(struct drm_plane *plane, */ if (ret != 0) DRM_ERROR("Failed to update screen.\n"); - - crtc->primary->fb = plane->state->fb; } else { /* * When disabling a plane, CRTC and FB should always be NULL diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index 67331f01ef32e..90445bc590cba 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -1285,8 +1285,6 @@ vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane, 1, 1, NULL, crtc); if (ret) DRM_ERROR("Failed to update STDU.\n"); - - crtc->primary->fb = plane->state->fb; } else { crtc = old_state->crtc; stdu = vmw_crtc_to_stdu(crtc); -- GitLab From 0d45d79de22feb4f32de08249e93d878fa6fdab8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Fri, 25 May 2018 21:50:37 +0300 Subject: [PATCH 0231/1506] drm/vmwgfx: Stop using plane->fb in atomic_enable() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of looking at the (soon to be deprecated) plane->fb we'll examing plane->state->fb instead. We can do this because vmw_du_crtc_atomic_check() prevents us from enabling a crtc without the primary plane also being enabled. Due to that same reason, I'm actually not sure what the checks here are for NULL fb. If we can't enable the crtc without an enabled plane we should always have an fb. But I'll leave that for someone else to figure out. Cc: Deepak Rawat <drawat@vmware.com> Cc: Thomas Hellstrom <thellstrom@vmware.com> Cc: Sinclair Yeh <syeh@vmware.com> Cc: VMware Graphics <linux-graphics-maintainer@vmware.com> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Deepak Rawat <drawat@vmware.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180525185045.29689-6-ville.syrjala@linux.intel.com Reviewed-by: Sinclair Yeh <syeh@vmware.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index 90445bc590cba..152e96cb1c01a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -414,6 +414,7 @@ static void vmw_stdu_crtc_helper_prepare(struct drm_crtc *crtc) static void vmw_stdu_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) { + struct drm_plane_state *plane_state = crtc->primary->state; struct vmw_private *dev_priv; struct vmw_screen_target_display_unit *stdu; struct vmw_framebuffer *vfb; @@ -422,7 +423,7 @@ static void vmw_stdu_crtc_atomic_enable(struct drm_crtc *crtc, stdu = vmw_crtc_to_stdu(crtc); dev_priv = vmw_priv(crtc->dev); - fb = crtc->primary->fb; + fb = plane_state->fb; vfb = (fb) ? vmw_framebuffer_to_vfb(fb) : NULL; -- GitLab From 93b21226bbff59e00b1b08caa4bf64325a3991b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Fri, 25 May 2018 21:50:38 +0300 Subject: [PATCH 0232/1506] drm/vmwgfx: Stop messing about with plane->fb/old_fb/crtc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit plane->fb/old_fb/crtc should no longer be used by atomic drivers. Stop messing about with them. Cc: Deepak Rawat <drawat@vmware.com> Cc: Thomas Hellstrom <thellstrom@vmware.com> Cc: Sinclair Yeh <syeh@vmware.com> Cc: VMware Graphics <linux-graphics-maintainer@vmware.com> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180525185045.29689-7-ville.syrjala@linux.intel.com Reviewed-by: Sinclair Yeh <syeh@vmware.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index 2582ffd36bb57..3c5935f3d49e9 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -439,8 +439,6 @@ static int vmw_fb_compute_depth(struct fb_var_screeninfo *var, static int vmwgfx_set_config_internal(struct drm_mode_set *set) { struct drm_crtc *crtc = set->crtc; - struct drm_framebuffer *fb; - struct drm_crtc *tmp; struct drm_modeset_acquire_ctx *ctx; struct drm_device *dev = set->crtc->dev; int ret; @@ -448,29 +446,7 @@ static int vmwgfx_set_config_internal(struct drm_mode_set *set) ctx = dev->mode_config.acquire_ctx; restart: - /* - * NOTE: ->set_config can also disable other crtcs (if we steal all - * connectors from it), hence we need to refcount the fbs across all - * crtcs. Atomic modeset will have saner semantics ... - */ - drm_for_each_crtc(tmp, dev) - tmp->primary->old_fb = tmp->primary->fb; - - fb = set->fb; - ret = crtc->funcs->set_config(set, ctx); - if (ret == 0) { - crtc->primary->crtc = crtc; - crtc->primary->fb = fb; - } - - drm_for_each_crtc(tmp, dev) { - if (tmp->primary->fb) - drm_framebuffer_get(tmp->primary->fb); - if (tmp->primary->old_fb) - drm_framebuffer_put(tmp->primary->old_fb); - tmp->primary->old_fb = NULL; - } if (ret == -EDEADLK) { dev->mode_config.acquire_ctx = NULL; -- GitLab From 9e5c947cb7c11211bb5ca55bf209730c684fe43b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Fri, 25 May 2018 21:50:39 +0300 Subject: [PATCH 0233/1506] drm/amdgpu/dc: Stop updating plane->fb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to get rid of plane->fb on atomic drivers. Stop setting it. Cc: Alex Deucher <alexander.deucher@amd.com> Cc: "Christian König" <christian.koenig@amd.com> Cc: "David (ChunMing) Zhou" <David1.Zhou@amd.com> Cc: Harry Wentland <harry.wentland@amd.com> Cc: amd-gfx@lists.freedesktop.org Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Reviewed-by: Harry Wentland <harry.wentland@amd.com> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180525185045.29689-8-ville.syrjala@linux.intel.com Reviewed-by: Sinclair Yeh <syeh@vmware.com> --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 -- 1 file changed, 2 deletions(-) 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 1dd1142246c25..3263031db44bf 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -3951,8 +3951,6 @@ static void amdgpu_dm_do_flip(struct drm_crtc *crtc, /* Flip */ spin_lock_irqsave(&crtc->dev->event_lock, flags); - /* update crtc fb */ - crtc->primary->fb = fb; WARN_ON(acrtc->pflip_status != AMDGPU_FLIP_NONE); WARN_ON(!acrtc_state->stream); -- GitLab From cd30fbca9713d225bc61ff9a2d5f1fbaff9df2f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Fri, 25 May 2018 21:50:40 +0300 Subject: [PATCH 0234/1506] drm/i915: Stop updating plane->fb/crtc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to get rid of plane->fb/crtc on atomic drivers. Stop setting them. v2: Fix up the comment in intel_crtc_active() and nuke the rest of the stale comments (Daniel) Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> #v1 Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180525185045.29689-9-ville.syrjala@linux.intel.com Reviewed-by: Sinclair Yeh <syeh@vmware.com> --- drivers/gpu/drm/i915/intel_atomic_plane.c | 12 ------------ drivers/gpu/drm/i915/intel_display.c | 7 +++---- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c index 7481ce85746b4..eb0579fb5e547 100644 --- a/drivers/gpu/drm/i915/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c @@ -120,12 +120,6 @@ int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_ &crtc_state->base.adjusted_mode; int ret; - /* - * Both crtc and plane->crtc could be NULL if we're updating a - * property while the plane is disabled. We don't actually have - * anything driver-specific we need to test in that case, so - * just return success. - */ if (!intel_state->base.crtc && !old_plane_state->base.crtc) return 0; @@ -204,12 +198,6 @@ static int intel_plane_atomic_check(struct drm_plane *plane, const struct drm_crtc_state *old_crtc_state; struct drm_crtc_state *new_crtc_state; - /* - * Both crtc and plane->crtc could be NULL if we're updating a - * property while the plane is disabled. We don't actually have - * anything driver-specific we need to test in that case, so - * just return success. - */ if (!crtc) return 0; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 00b030b08a6a7..91eb47a1c9225 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -994,7 +994,7 @@ bool intel_crtc_active(struct intel_crtc *crtc) * We can ditch the adjusted_mode.crtc_clock check as soon * as Haswell has gained clock readout/fastboot support. * - * We can ditch the crtc->primary->fb check as soon as we can + * We can ditch the crtc->primary->state->fb check as soon as we can * properly reconstruct framebuffers. * * FIXME: The intel_crtc->active here should be switched to @@ -2894,9 +2894,8 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc, if (i915_gem_object_is_tiled(obj)) dev_priv->preserve_bios_swizzle = true; - drm_framebuffer_get(fb); - primary->fb = primary->state->fb = fb; - primary->crtc = primary->state->crtc = &intel_crtc->base; + plane_state->fb = fb; + plane_state->crtc = &intel_crtc->base; intel_set_plane_visible(to_intel_crtc_state(crtc_state), to_intel_plane_state(plane_state), -- GitLab From 67ba0c56a807912b4254da043b9b47c90a391eb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Fri, 25 May 2018 21:50:41 +0300 Subject: [PATCH 0235/1506] drm/exynos: Stop updating plane->crtc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to get rid of plane->crtc on atomic drivers. Stop setting it. Cc: Inki Dae <inki.dae@samsung.com> Cc: Joonyoung Shim <jy0922.shim@samsung.com> Cc: Seung-Woo Kim <sw0312.kim@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Acked-by: Inki Dae <inki.dae@samsung.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180525185045.29689-10-ville.syrjala@linux.intel.com Reviewed-by: Sinclair Yeh <syeh@vmware.com> --- drivers/gpu/drm/exynos/exynos_drm_plane.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index d2a90dae5c710..1b1af359c3037 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c @@ -263,8 +263,6 @@ static void exynos_plane_atomic_update(struct drm_plane *plane, if (!state->crtc) return; - plane->crtc = state->crtc; - if (exynos_crtc->ops->update_plane) exynos_crtc->ops->update_plane(exynos_crtc, exynos_plane); } -- GitLab From d0766b0047c2161ae2261865297992f570e63cfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Fri, 25 May 2018 21:50:42 +0300 Subject: [PATCH 0236/1506] drm/msm: Stop updating plane->fb/crtc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to get rid of plane->fb/crtc on atomic drivers. Stop setting them. v2: Catch a few more cases Cc: Rob Clark <robdclark@gmail.com> Cc: linux-arm-msm@vger.kernel.org Cc: freedreno@lists.freedesktop.org Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> #v1 Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180525185045.29689-11-ville.syrjala@linux.intel.com Reviewed-by: Sinclair Yeh <syeh@vmware.com> --- drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c | 1 - drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c | 2 -- drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c | 1 - drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c | 2 -- 4 files changed, 6 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c index 20f9e5de5f19f..457c29dba4a1a 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c @@ -665,7 +665,6 @@ struct drm_crtc *mdp4_crtc_init(struct drm_device *dev, drm_crtc_init_with_planes(dev, crtc, plane, NULL, &mdp4_crtc_funcs, NULL); drm_crtc_helper_add(crtc, &mdp4_crtc_helper_funcs); - plane->crtc = crtc; return crtc; } diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c index 7a1ad3af08e33..782b1e27f040c 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c @@ -182,8 +182,6 @@ static void mdp4_plane_set_scanout(struct drm_plane *plane, msm_framebuffer_iova(fb, kms->aspace, 2)); mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRCP3_BASE(pipe), msm_framebuffer_iova(fb, kms->aspace, 3)); - - plane->fb = fb; } static void mdp4_write_csc_config(struct mdp4_kms *mdp4_kms, diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c index 76b96081916f0..efedcac6e641a 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c @@ -1198,7 +1198,6 @@ struct drm_crtc *mdp5_crtc_init(struct drm_device *dev, "unref cursor", unref_cursor_worker); drm_crtc_helper_add(crtc, &mdp5_crtc_helper_funcs); - plane->crtc = crtc; return crtc; } diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c index f2361f79fdce2..6826aa10f3ac9 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c @@ -1043,8 +1043,6 @@ static int mdp5_plane_mode_set(struct drm_plane *plane, src_img_w, src_img_h, src_x + src_w, src_y, src_w, src_h); - plane->fb = fb; - return ret; } -- GitLab From 50dcd554181e57c2352b387a0d0fb8cf4a1aa555 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Fri, 25 May 2018 21:50:43 +0300 Subject: [PATCH 0237/1506] drm/virtio: Stop updating plane->crtc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to get rid of plane->crtc on atomic drivers. Stop setting it. v2: s/fb/crtc/ in the commit message (Gerd) Cc: David Airlie <airlied@linux.ie> Cc: Gerd Hoffmann <kraxel@redhat.com> Cc: virtualization@lists.linux-foundation.org Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180525185045.29689-12-ville.syrjala@linux.intel.com Reviewed-by: Sinclair Yeh <syeh@vmware.com> --- drivers/gpu/drm/virtio/virtgpu_display.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/virtio/virtgpu_display.c b/drivers/gpu/drm/virtio/virtgpu_display.c index d6dd769a7ad3f..ff9933e794169 100644 --- a/drivers/gpu/drm/virtio/virtgpu_display.c +++ b/drivers/gpu/drm/virtio/virtgpu_display.c @@ -282,8 +282,6 @@ static int vgdev_output_init(struct virtio_gpu_device *vgdev, int index) drm_crtc_init_with_planes(dev, crtc, primary, cursor, &virtio_gpu_crtc_funcs, NULL); drm_crtc_helper_add(crtc, &virtio_gpu_crtc_helper_funcs); - primary->crtc = crtc; - cursor->crtc = crtc; drm_connector_init(dev, connector, &virtio_gpu_connector_funcs, DRM_MODE_CONNECTOR_VIRTUAL); -- GitLab From 2f958af7fc2483e09a048308fe55399343d8f20c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Fri, 25 May 2018 21:50:44 +0300 Subject: [PATCH 0238/1506] drm/vc4: Stop updating plane->fb/crtc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to get rid of plane->fb/crtc on atomic drivers. Stop setting them. Cc: Eric Anholt <eric@anholt.net> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180525185045.29689-13-ville.syrjala@linux.intel.com Reviewed-by: Eric Anholt <eric@anholt.net> Reviewed-by: Sinclair Yeh <syeh@vmware.com> --- drivers/gpu/drm/vc4/vc4_crtc.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index 83d3b7912fc2b..868f39a9ae8a4 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -818,7 +818,6 @@ static int vc4_async_page_flip(struct drm_crtc *crtc, * is released. */ drm_atomic_set_fb_for_plane(plane->state, fb); - plane->fb = fb; vc4_queue_seqno_cb(dev, &flip_state->cb, bo->seqno, vc4_async_page_flip_complete); @@ -1013,7 +1012,6 @@ static int vc4_crtc_bind(struct device *dev, struct device *master, void *data) drm_crtc_init_with_planes(drm, crtc, primary_plane, NULL, &vc4_crtc_funcs, NULL); drm_crtc_helper_add(crtc, &vc4_crtc_helper_funcs); - primary_plane->crtc = crtc; vc4_crtc->channel = vc4_crtc->data->hvs_channel; drm_mode_crtc_set_gamma_size(crtc, ARRAY_SIZE(vc4_crtc->lut_r)); drm_crtc_enable_color_mgmt(crtc, 0, false, crtc->gamma_size); @@ -1049,7 +1047,6 @@ static int vc4_crtc_bind(struct device *dev, struct device *master, void *data) cursor_plane = vc4_plane_init(drm, DRM_PLANE_TYPE_CURSOR); if (!IS_ERR(cursor_plane)) { cursor_plane->possible_crtcs = 1 << drm_crtc_index(crtc); - cursor_plane->crtc = crtc; crtc->cursor = cursor_plane; } -- GitLab From e00fb8564ee98c5c3a72c74b1a27e441abff6cca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Fri, 25 May 2018 21:50:45 +0300 Subject: [PATCH 0239/1506] drm: Stop updating plane->crtc/fb/old_fb on atomic drivers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stop playing around with plane->crtc/fb/old_fb with atomic drivers. Make life a lot simpler when we don't have to do the magic old_fb vs. fb dance around plane updates. That way we can't risk plane->fb getting out of sync with plane->state->fb and we're less likely to leak any refcounts as well. Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180525185045.29689-14-ville.syrjala@linux.intel.com Reviewed-by: Sinclair Yeh <syeh@vmware.com> --- drivers/gpu/drm/drm_atomic.c | 55 +++-------------------------- drivers/gpu/drm/drm_atomic_helper.c | 15 +------- drivers/gpu/drm/drm_crtc.c | 8 +++-- drivers/gpu/drm/drm_fb_helper.c | 7 ---- drivers/gpu/drm/drm_framebuffer.c | 5 --- drivers/gpu/drm/drm_plane.c | 14 +++++--- drivers/gpu/drm/drm_plane_helper.c | 4 ++- include/drm/drm_atomic.h | 3 -- 8 files changed, 24 insertions(+), 87 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 07fef42869aa2..11059d556dbd0 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -692,6 +692,11 @@ drm_atomic_get_plane_state(struct drm_atomic_state *state, WARN_ON(!state->acquire_ctx); + /* the legacy pointers should never be set */ + WARN_ON(plane->fb); + WARN_ON(plane->old_fb); + WARN_ON(plane->crtc); + plane_state = drm_atomic_get_existing_plane_state(state, plane); if (plane_state) return plane_state; @@ -2039,45 +2044,6 @@ int drm_atomic_set_property(struct drm_atomic_state *state, return ret; } -/** - * drm_atomic_clean_old_fb -- Unset old_fb pointers and set plane->fb pointers. - * - * @dev: drm device to check. - * @plane_mask: plane mask for planes that were updated. - * @ret: return value, can be -EDEADLK for a retry. - * - * Before doing an update &drm_plane.old_fb is set to &drm_plane.fb, but before - * dropping the locks old_fb needs to be set to NULL and plane->fb updated. This - * is a common operation for each atomic update, so this call is split off as a - * helper. - */ -void drm_atomic_clean_old_fb(struct drm_device *dev, - unsigned plane_mask, - int ret) -{ - struct drm_plane *plane; - - /* if succeeded, fixup legacy plane crtc/fb ptrs before dropping - * locks (ie. while it is still safe to deref plane->state). We - * need to do this here because the driver entry points cannot - * distinguish between legacy and atomic ioctls. - */ - drm_for_each_plane_mask(plane, dev, plane_mask) { - if (ret == 0) { - struct drm_framebuffer *new_fb = plane->state->fb; - if (new_fb) - drm_framebuffer_get(new_fb); - plane->fb = new_fb; - plane->crtc = plane->state->crtc; - - if (plane->old_fb) - drm_framebuffer_put(plane->old_fb); - } - plane->old_fb = NULL; - } -} -EXPORT_SYMBOL(drm_atomic_clean_old_fb); - /** * DOC: explicit fencing properties * @@ -2298,9 +2264,7 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, unsigned int copied_objs, copied_props; struct drm_atomic_state *state; struct drm_modeset_acquire_ctx ctx; - struct drm_plane *plane; struct drm_out_fence_state *fence_state; - unsigned plane_mask; int ret = 0; unsigned int i, j, num_fences; @@ -2340,7 +2304,6 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, state->allow_modeset = !!(arg->flags & DRM_MODE_ATOMIC_ALLOW_MODESET); retry: - plane_mask = 0; copied_objs = 0; copied_props = 0; fence_state = NULL; @@ -2411,12 +2374,6 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, copied_props++; } - if (obj->type == DRM_MODE_OBJECT_PLANE && count_props && - !(arg->flags & DRM_MODE_ATOMIC_TEST_ONLY)) { - plane = obj_to_plane(obj); - plane_mask |= (1 << drm_plane_index(plane)); - plane->old_fb = plane->fb; - } drm_mode_object_put(obj); } @@ -2437,8 +2394,6 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, } out: - drm_atomic_clean_old_fb(dev, plane_mask, ret); - complete_crtc_signaling(dev, state, fence_state, num_fences, !ret); if (ret == -EDEADLK) { diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 130da5195f3b6..232fa11a5e311 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -2914,7 +2914,6 @@ static int __drm_atomic_helper_disable_all(struct drm_device *dev, struct drm_plane *plane; struct drm_crtc_state *crtc_state; struct drm_crtc *crtc; - unsigned plane_mask = 0; int ret, i; state = drm_atomic_state_alloc(dev); @@ -2957,17 +2956,10 @@ static int __drm_atomic_helper_disable_all(struct drm_device *dev, goto free; drm_atomic_set_fb_for_plane(plane_state, NULL); - - if (clean_old_fbs) { - plane->old_fb = plane->fb; - plane_mask |= BIT(drm_plane_index(plane)); - } } ret = drm_atomic_commit(state); free: - if (plane_mask) - drm_atomic_clean_old_fb(dev, plane_mask, ret); drm_atomic_state_put(state); return ret; } @@ -3129,13 +3121,8 @@ int drm_atomic_helper_commit_duplicated_state(struct drm_atomic_state *state, state->acquire_ctx = ctx; - for_each_new_plane_in_state(state, plane, new_plane_state, i) { - WARN_ON(plane->crtc != new_plane_state->crtc); - WARN_ON(plane->fb != new_plane_state->fb); - WARN_ON(plane->old_fb); - + for_each_new_plane_in_state(state, plane, new_plane_state, i) state->planes[i].old_state = plane->state; - } for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) state->crtcs[i].old_state = crtc->state; diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 237bd34212dbf..53828fc8d9115 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -479,8 +479,12 @@ static int __drm_mode_set_config_internal(struct drm_mode_set *set, ret = crtc->funcs->set_config(set, ctx); if (ret == 0) { - crtc->primary->crtc = fb ? crtc : NULL; - crtc->primary->fb = fb; + struct drm_plane *plane = crtc->primary; + + if (!plane->state) { + plane->crtc = fb ? crtc : NULL; + plane->fb = fb; + } } drm_for_each_crtc(tmp, crtc->dev) { diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 91f051e5e130f..cab14f2533840 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -368,7 +368,6 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool activ struct drm_plane *plane; struct drm_atomic_state *state; int i, ret; - unsigned int plane_mask; struct drm_modeset_acquire_ctx ctx; drm_modeset_acquire_init(&ctx, 0); @@ -381,7 +380,6 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool activ state->acquire_ctx = &ctx; retry: - plane_mask = 0; drm_for_each_plane(plane, dev) { plane_state = drm_atomic_get_plane_state(state, plane); if (IS_ERR(plane_state)) { @@ -391,9 +389,6 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool activ plane_state->rotation = DRM_MODE_ROTATE_0; - plane->old_fb = plane->fb; - plane_mask |= 1 << drm_plane_index(plane); - /* disable non-primary: */ if (plane->type == DRM_PLANE_TYPE_PRIMARY) continue; @@ -430,8 +425,6 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool activ ret = drm_atomic_commit(state); out_state: - drm_atomic_clean_old_fb(dev, plane_mask, ret); - if (ret == -EDEADLK) goto backoff; diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index bfedceff87bba..46b11e46edbd6 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -836,8 +836,6 @@ static int atomic_remove_fb(struct drm_framebuffer *fb) goto unlock; plane_mask |= BIT(drm_plane_index(plane)); - - plane->old_fb = plane->fb; } /* This list is only filled when disable_crtcs is set. */ @@ -852,9 +850,6 @@ static int atomic_remove_fb(struct drm_framebuffer *fb) ret = drm_atomic_commit(state); unlock: - if (plane_mask) - drm_atomic_clean_old_fb(dev, plane_mask, ret); - if (ret == -EDEADLK) { drm_atomic_state_clear(state); drm_modeset_backoff(&ctx); diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index 7ce88dff871d7..534b579335765 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -651,9 +651,11 @@ static int __setplane_internal(struct drm_plane *plane, crtc_x, crtc_y, crtc_w, crtc_h, src_x, src_y, src_w, src_h, ctx); if (!ret) { - plane->crtc = crtc; - plane->fb = fb; - drm_framebuffer_get(plane->fb); + if (!plane->state) { + plane->crtc = crtc; + plane->fb = fb; + drm_framebuffer_get(plane->fb); + } } else { plane->old_fb = NULL; } @@ -1093,8 +1095,10 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, /* Keep the old fb, don't unref it. */ plane->old_fb = NULL; } else { - plane->fb = fb; - drm_framebuffer_get(fb); + if (!plane->state) { + plane->fb = fb; + drm_framebuffer_get(fb); + } } out: diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index f88f681615193..2010794943bcc 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -502,6 +502,7 @@ EXPORT_SYMBOL(drm_plane_helper_update); int drm_plane_helper_disable(struct drm_plane *plane) { struct drm_plane_state *plane_state; + struct drm_framebuffer *old_fb; /* crtc helpers love to call disable functions for already disabled hw * functions. So cope with that. */ @@ -521,8 +522,9 @@ int drm_plane_helper_disable(struct drm_plane *plane) plane_state->plane = plane; plane_state->crtc = NULL; + old_fb = plane_state->fb; drm_atomic_set_fb_for_plane(plane_state, NULL); - return drm_plane_helper_commit(plane, plane_state, plane->fb); + return drm_plane_helper_commit(plane, plane_state, old_fb); } EXPORT_SYMBOL(drm_plane_helper_disable); diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index a57a8aa90ffb7..ca461b6cf71f3 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -601,9 +601,6 @@ int __must_check drm_atomic_add_affected_planes(struct drm_atomic_state *state, struct drm_crtc *crtc); -void -drm_atomic_clean_old_fb(struct drm_device *dev, unsigned plane_mask, int ret); - int __must_check drm_atomic_check_only(struct drm_atomic_state *state); int __must_check drm_atomic_commit(struct drm_atomic_state *state); int __must_check drm_atomic_nonblocking_commit(struct drm_atomic_state *state); -- GitLab From 68a8570375df647cf8b6626d63917b564dd9390e Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Mon, 11 Jun 2018 18:18:24 +0100 Subject: [PATCH 0240/1506] drm/i915/gtt: Invalidate GGTT caches after writing the gen6 page directories When we update the gen6 ppgtt page directories, we do so by writing the new address into a reserved slot in the GGTT. It appears that when the GPU reads that entry from the gsm, it uses its small cache and that we need to invalidate that cache after writing. We don't see an issue currently as we prefill the ppgtt page directories on creation; and only create the single aliasing_ppgtt long before we start using the GGTT (and so before the cache may have a conflicting entry). Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: Matthew Auld <matthew.william.auld@gmail.com> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180611171825.13678-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_gtt.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index ac75e0c5735c6..905a58b6ddf80 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1693,8 +1693,8 @@ static inline void gen6_write_pde(const struct i915_hw_ppgtt *ppgtt, const struct i915_page_table *pt) { /* Caller needs to make sure the write completes if necessary */ - writel_relaxed(GEN6_PDE_ADDR_ENCODE(px_dma(pt)) | GEN6_PDE_VALID, - ppgtt->pd_addr + pde); + iowrite32(GEN6_PDE_ADDR_ENCODE(px_dma(pt)) | GEN6_PDE_VALID, + ppgtt->pd_addr + pde); } /* Write all the page tables found in the ppgtt structure to incrementing page @@ -1709,7 +1709,7 @@ static void gen6_write_page_range(struct i915_hw_ppgtt *ppgtt, gen6_write_pde(ppgtt, pde, pt); mark_tlbs_dirty(ppgtt); - wmb(); + gen6_ggtt_invalidate(ppgtt->vm.i915); } static void gen8_ppgtt_enable(struct drm_i915_private *dev_priv) @@ -1864,7 +1864,7 @@ static int gen6_alloc_va_range(struct i915_address_space *vm, if (flush) { mark_tlbs_dirty(ppgtt); - wmb(); + gen6_ggtt_invalidate(ppgtt->vm.i915); } return 0; -- GitLab From d9d117e40d4ffc03438177eeac83d96dfeee76be Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Mon, 11 Jun 2018 18:18:25 +0100 Subject: [PATCH 0241/1506] drm/i915/ringbuffer: Serialize load of PD_DIR After triggering the mm switch with a load of PD_DIR, which may be deferred unto the MI_SET_CONTEXT on rcs, serialise the next commands with that load by posting a read of PD_DIR (or else those subsequent commands may access the stale page tables). Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: Matthew Auld <matthew.william.auld@gmail.com> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180611171825.13678-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_engine_cs.c | 5 ++- drivers/gpu/drm/i915/intel_ringbuffer.c | 49 +++++++++++++++++++------ drivers/gpu/drm/i915/intel_ringbuffer.h | 5 ++- 3 files changed, 44 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index d1cf8b4926abe..d278fed8cb31d 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -499,7 +499,8 @@ void intel_engine_setup_common(struct intel_engine_cs *engine) intel_engine_init_cmd_parser(engine); } -int intel_engine_create_scratch(struct intel_engine_cs *engine, int size) +int intel_engine_create_scratch(struct intel_engine_cs *engine, + unsigned int size) { struct drm_i915_gem_object *obj; struct i915_vma *vma; @@ -533,7 +534,7 @@ int intel_engine_create_scratch(struct intel_engine_cs *engine, int size) return ret; } -static void intel_engine_cleanup_scratch(struct intel_engine_cs *engine) +void intel_engine_cleanup_scratch(struct intel_engine_cs *engine) { i915_vma_unpin_and_release(&engine->scratch); } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index bb4af8f84a22c..735622dc73ec2 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1361,8 +1361,9 @@ intel_ring_context_pin(struct intel_engine_cs *engine, static int intel_init_ring_buffer(struct intel_engine_cs *engine) { - struct intel_ring *ring; struct i915_timeline *timeline; + struct intel_ring *ring; + unsigned int size; int err; intel_engine_setup_common(engine); @@ -1388,12 +1389,21 @@ static int intel_init_ring_buffer(struct intel_engine_cs *engine) GEM_BUG_ON(engine->buffer); engine->buffer = ring; - err = intel_engine_init_common(engine); + size = PAGE_SIZE; + if (HAS_BROKEN_CS_TLB(engine->i915)) + size = I830_WA_SIZE; + err = intel_engine_create_scratch(engine, size); if (err) goto err_unpin; + err = intel_engine_init_common(engine); + if (err) + goto err_scratch; + return 0; +err_scratch: + intel_engine_cleanup_scratch(engine); err_unpin: intel_ring_unpin(ring); err_ring: @@ -1455,6 +1465,25 @@ static int load_pd_dir(struct i915_request *rq, return 0; } +static int flush_pd_dir(struct i915_request *rq) +{ + const struct intel_engine_cs * const engine = rq->engine; + u32 *cs; + + cs = intel_ring_begin(rq, 4); + if (IS_ERR(cs)) + return PTR_ERR(cs); + + /* Stall until the page table load is complete */ + *cs++ = MI_STORE_REGISTER_MEM | MI_SRM_LRM_GLOBAL_GTT; + *cs++ = i915_mmio_reg_offset(RING_PP_DIR_BASE(engine)); + *cs++ = i915_ggtt_offset(engine->scratch); + *cs++ = MI_NOOP; + + intel_ring_advance(rq, cs); + return 0; +} + static inline int mi_set_context(struct i915_request *rq, u32 flags) { struct drm_i915_private *i915 = rq->i915; @@ -1638,6 +1667,12 @@ static int switch_context(struct i915_request *rq) goto err_mm; } + if (ppgtt) { + ret = flush_pd_dir(rq); + if (ret) + goto err_mm; + } + if (ctx->remap_slice) { for (i = 0; i < MAX_L3_SLICES; i++) { if (!(ctx->remap_slice & BIT(i))) @@ -2158,16 +2193,6 @@ int intel_init_render_ring_buffer(struct intel_engine_cs *engine) if (ret) return ret; - if (INTEL_GEN(dev_priv) >= 6) { - ret = intel_engine_create_scratch(engine, PAGE_SIZE); - if (ret) - return ret; - } else if (HAS_BROKEN_CS_TLB(dev_priv)) { - ret = intel_engine_create_scratch(engine, I830_WA_SIZE); - if (ret) - return ret; - } - return 0; } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index e9494557aaa12..2c35dd3525a6e 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -869,9 +869,12 @@ void intel_engine_init_global_seqno(struct intel_engine_cs *engine, u32 seqno); void intel_engine_setup_common(struct intel_engine_cs *engine); int intel_engine_init_common(struct intel_engine_cs *engine); -int intel_engine_create_scratch(struct intel_engine_cs *engine, int size); void intel_engine_cleanup_common(struct intel_engine_cs *engine); +int intel_engine_create_scratch(struct intel_engine_cs *engine, + unsigned int size); +void intel_engine_cleanup_scratch(struct intel_engine_cs *engine); + int intel_init_render_ring_buffer(struct intel_engine_cs *engine); int intel_init_bsd_ring_buffer(struct intel_engine_cs *engine); int intel_init_blt_ring_buffer(struct intel_engine_cs *engine); -- GitLab From 35ac40d8b65ab5bd09b683720bca96a1f5a0625b Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Tue, 12 Jun 2018 09:18:14 +0100 Subject: [PATCH 0242/1506] drm/i915/gtt: Subclass gen6_hw_ppgtt The legacy gen6 ppgtt needs a little more hand holding than gen8+, and so requires a larger structure. As I intend to make this slightly more complicated in the future, separate the gen6 from the core gen8 hw struct by subclassing. This patch moves the gen6 only features out to gen6_hw_ppgtt and pipes the new type everywhere that needs it. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: Matthew Auld <matthew.william.auld@gmail.com> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180612081815.3585-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_gtt.c | 94 +++++++++---------- drivers/gpu/drm/i915/i915_gem_gtt.h | 19 +++- drivers/gpu/drm/i915/selftests/i915_gem_gtt.c | 10 +- 3 files changed, 65 insertions(+), 58 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 905a58b6ddf80..62991e6cf1d54 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1636,20 +1636,20 @@ static struct i915_hw_ppgtt *gen8_ppgtt_create(struct drm_i915_private *i915) return ERR_PTR(err); } -static void gen6_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m) +static void gen6_dump_ppgtt(struct i915_hw_ppgtt *base, struct seq_file *m) { - struct i915_address_space *vm = &ppgtt->vm; + struct gen6_hw_ppgtt *ppgtt = to_gen6_ppgtt(base); + struct i915_address_space *vm = &base->vm; struct i915_page_table *unused; gen6_pte_t scratch_pte; u32 pd_entry, pte, pde; - u32 start = 0, length = ppgtt->vm.total; scratch_pte = vm->pte_encode(vm->scratch_page.daddr, I915_CACHE_LLC, 0); - gen6_for_each_pde(unused, &ppgtt->pd, start, length, pde) { + gen6_for_all_pdes(unused, &base->pd, pde) { u32 expected; gen6_pte_t *pt_vaddr; - const dma_addr_t pt_addr = px_dma(ppgtt->pd.page_table[pde]); + const dma_addr_t pt_addr = px_dma(base->pd.page_table[pde]); pd_entry = readl(ppgtt->pd_addr + pde); expected = (GEN6_PDE_ADDR_ENCODE(pt_addr) | GEN6_PDE_VALID); @@ -1660,7 +1660,7 @@ static void gen6_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m) expected); seq_printf(m, "\tPDE: %x\n", pd_entry); - pt_vaddr = kmap_atomic_px(ppgtt->pd.page_table[pde]); + pt_vaddr = kmap_atomic_px(base->pd.page_table[pde]); for (pte = 0; pte < GEN6_PTES; pte+=4) { unsigned long va = @@ -1688,7 +1688,7 @@ static void gen6_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m) } /* Write pde (index) from the page directory @pd to the page table @pt */ -static inline void gen6_write_pde(const struct i915_hw_ppgtt *ppgtt, +static inline void gen6_write_pde(const struct gen6_hw_ppgtt *ppgtt, const unsigned int pde, const struct i915_page_table *pt) { @@ -1699,17 +1699,18 @@ static inline void gen6_write_pde(const struct i915_hw_ppgtt *ppgtt, /* Write all the page tables found in the ppgtt structure to incrementing page * directories. */ -static void gen6_write_page_range(struct i915_hw_ppgtt *ppgtt, +static void gen6_write_page_range(struct i915_hw_ppgtt *base, u32 start, u32 length) { + struct gen6_hw_ppgtt *ppgtt = to_gen6_ppgtt(base); struct i915_page_table *pt; unsigned int pde; - gen6_for_each_pde(pt, &ppgtt->pd, start, length, pde) + gen6_for_each_pde(pt, &base->pd, start, length, pde) gen6_write_pde(ppgtt, pde, pt); - mark_tlbs_dirty(ppgtt); - gen6_ggtt_invalidate(ppgtt->vm.i915); + mark_tlbs_dirty(base); + gen6_ggtt_invalidate(base->vm.i915); } static void gen8_ppgtt_enable(struct drm_i915_private *dev_priv) @@ -1843,28 +1844,28 @@ static void gen6_ppgtt_insert_entries(struct i915_address_space *vm, static int gen6_alloc_va_range(struct i915_address_space *vm, u64 start, u64 length) { - struct i915_hw_ppgtt *ppgtt = i915_vm_to_ppgtt(vm); + struct gen6_hw_ppgtt *ppgtt = to_gen6_ppgtt(i915_vm_to_ppgtt(vm)); struct i915_page_table *pt; u64 from = start; unsigned int pde; bool flush = false; - gen6_for_each_pde(pt, &ppgtt->pd, start, length, pde) { + gen6_for_each_pde(pt, &ppgtt->base.pd, start, length, pde) { if (pt == vm->scratch_pt) { pt = alloc_pt(vm); if (IS_ERR(pt)) goto unwind_out; gen6_initialize_pt(vm, pt); - ppgtt->pd.page_table[pde] = pt; + ppgtt->base.pd.page_table[pde] = pt; gen6_write_pde(ppgtt, pde, pt); flush = true; } } if (flush) { - mark_tlbs_dirty(ppgtt); - gen6_ggtt_invalidate(ppgtt->vm.i915); + mark_tlbs_dirty(&ppgtt->base); + gen6_ggtt_invalidate(ppgtt->base.vm.i915); } return 0; @@ -1901,24 +1902,23 @@ static void gen6_free_scratch(struct i915_address_space *vm) static void gen6_ppgtt_cleanup(struct i915_address_space *vm) { - struct i915_hw_ppgtt *ppgtt = i915_vm_to_ppgtt(vm); - struct i915_page_directory *pd = &ppgtt->pd; + struct gen6_hw_ppgtt *ppgtt = to_gen6_ppgtt(i915_vm_to_ppgtt(vm)); struct i915_page_table *pt; u32 pde; drm_mm_remove_node(&ppgtt->node); - gen6_for_all_pdes(pt, pd, pde) + gen6_for_all_pdes(pt, &ppgtt->base.pd, pde) if (pt != vm->scratch_pt) free_pt(vm, pt); gen6_free_scratch(vm); } -static int gen6_ppgtt_allocate_page_directories(struct i915_hw_ppgtt *ppgtt) +static int gen6_ppgtt_allocate_page_directories(struct gen6_hw_ppgtt *ppgtt) { - struct i915_address_space *vm = &ppgtt->vm; - struct drm_i915_private *dev_priv = ppgtt->vm.i915; + struct i915_address_space *vm = &ppgtt->base.vm; + struct drm_i915_private *dev_priv = ppgtt->base.vm.i915; struct i915_ggtt *ggtt = &dev_priv->ggtt; int ret; @@ -1943,11 +1943,11 @@ static int gen6_ppgtt_allocate_page_directories(struct i915_hw_ppgtt *ppgtt) if (ppgtt->node.start < ggtt->mappable_end) DRM_DEBUG("Forced to use aperture for PDEs\n"); - ppgtt->pd.base.ggtt_offset = + ppgtt->base.pd.base.ggtt_offset = ppgtt->node.start / PAGE_SIZE * sizeof(gen6_pte_t); ppgtt->pd_addr = (gen6_pte_t __iomem *)ggtt->gsm + - ppgtt->pd.base.ggtt_offset / sizeof(gen6_pte_t); + ppgtt->base.pd.base.ggtt_offset / sizeof(gen6_pte_t); return 0; @@ -1956,70 +1956,70 @@ static int gen6_ppgtt_allocate_page_directories(struct i915_hw_ppgtt *ppgtt) return ret; } -static int gen6_ppgtt_alloc(struct i915_hw_ppgtt *ppgtt) +static int gen6_ppgtt_alloc(struct gen6_hw_ppgtt *ppgtt) { return gen6_ppgtt_allocate_page_directories(ppgtt); } -static void gen6_scratch_va_range(struct i915_hw_ppgtt *ppgtt, +static void gen6_scratch_va_range(struct gen6_hw_ppgtt *ppgtt, u64 start, u64 length) { struct i915_page_table *unused; u32 pde; - gen6_for_each_pde(unused, &ppgtt->pd, start, length, pde) - ppgtt->pd.page_table[pde] = ppgtt->vm.scratch_pt; + gen6_for_each_pde(unused, &ppgtt->base.pd, start, length, pde) + ppgtt->base.pd.page_table[pde] = ppgtt->base.vm.scratch_pt; } static struct i915_hw_ppgtt *gen6_ppgtt_create(struct drm_i915_private *i915) { struct i915_ggtt * const ggtt = &i915->ggtt; - struct i915_hw_ppgtt *ppgtt; + struct gen6_hw_ppgtt *ppgtt; int err; ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL); if (!ppgtt) return ERR_PTR(-ENOMEM); - ppgtt->vm.i915 = i915; - ppgtt->vm.dma = &i915->drm.pdev->dev; + ppgtt->base.vm.i915 = i915; + ppgtt->base.vm.dma = &i915->drm.pdev->dev; - ppgtt->vm.pte_encode = ggtt->vm.pte_encode; + ppgtt->base.vm.pte_encode = ggtt->vm.pte_encode; err = gen6_ppgtt_alloc(ppgtt); if (err) goto err_free; - ppgtt->vm.total = I915_PDES * GEN6_PTES * PAGE_SIZE; + ppgtt->base.vm.total = I915_PDES * GEN6_PTES * PAGE_SIZE; - gen6_scratch_va_range(ppgtt, 0, ppgtt->vm.total); - gen6_write_page_range(ppgtt, 0, ppgtt->vm.total); + gen6_scratch_va_range(ppgtt, 0, ppgtt->base.vm.total); + gen6_write_page_range(&ppgtt->base, 0, ppgtt->base.vm.total); - err = gen6_alloc_va_range(&ppgtt->vm, 0, ppgtt->vm.total); + err = gen6_alloc_va_range(&ppgtt->base.vm, 0, ppgtt->base.vm.total); if (err) goto err_cleanup; - ppgtt->vm.clear_range = gen6_ppgtt_clear_range; - ppgtt->vm.insert_entries = gen6_ppgtt_insert_entries; - ppgtt->vm.cleanup = gen6_ppgtt_cleanup; - ppgtt->debug_dump = gen6_dump_ppgtt; + ppgtt->base.vm.clear_range = gen6_ppgtt_clear_range; + ppgtt->base.vm.insert_entries = gen6_ppgtt_insert_entries; + ppgtt->base.vm.cleanup = gen6_ppgtt_cleanup; + ppgtt->base.debug_dump = gen6_dump_ppgtt; - ppgtt->vm.vma_ops.bind_vma = gen6_ppgtt_bind_vma; - ppgtt->vm.vma_ops.unbind_vma = ppgtt_unbind_vma; - ppgtt->vm.vma_ops.set_pages = ppgtt_set_pages; - ppgtt->vm.vma_ops.clear_pages = clear_pages; + ppgtt->base.vm.vma_ops.bind_vma = gen6_ppgtt_bind_vma; + ppgtt->base.vm.vma_ops.unbind_vma = ppgtt_unbind_vma; + ppgtt->base.vm.vma_ops.set_pages = ppgtt_set_pages; + ppgtt->base.vm.vma_ops.clear_pages = clear_pages; DRM_DEBUG_DRIVER("Allocated pde space (%lldM) at GTT entry: %llx\n", ppgtt->node.size >> 20, ppgtt->node.start / PAGE_SIZE); DRM_DEBUG_DRIVER("Adding PPGTT at offset %x\n", - ppgtt->pd.base.ggtt_offset << 10); + ppgtt->base.pd.base.ggtt_offset << 10); - return ppgtt; + return &ppgtt->base; err_cleanup: - gen6_ppgtt_cleanup(&ppgtt->vm); + gen6_ppgtt_cleanup(&ppgtt->base.vm); err_free: kfree(ppgtt); return ERR_PTR(err); diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index e70f6abcd0f28..7d65d813eff0b 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -396,7 +396,7 @@ struct i915_ggtt { struct i915_hw_ppgtt { struct i915_address_space vm; struct kref ref; - struct drm_mm_node node; + unsigned long pd_dirty_rings; union { struct i915_pml4 pml4; /* GEN8+ & 48b PPGTT */ @@ -404,11 +404,24 @@ struct i915_hw_ppgtt { struct i915_page_directory pd; /* GEN6-7 */ }; - gen6_pte_t __iomem *pd_addr; - void (*debug_dump)(struct i915_hw_ppgtt *ppgtt, struct seq_file *m); }; +struct gen6_hw_ppgtt { + struct i915_hw_ppgtt base; + + struct drm_mm_node node; + gen6_pte_t __iomem *pd_addr; +}; + +#define __to_gen6_ppgtt(base) container_of(base, struct gen6_hw_ppgtt, base) + +static inline struct gen6_hw_ppgtt *to_gen6_ppgtt(struct i915_hw_ppgtt *base) +{ + BUILD_BUG_ON(offsetof(struct gen6_hw_ppgtt, base)); + return __to_gen6_ppgtt(base); +} + /* * gen6_for_each_pde() iterates over every pde from start until start+length. * If start and start+length are not perfectly divisible, the macro will round diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c index f80cf7ce3fa96..a4060238bef03 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c @@ -135,17 +135,13 @@ static int igt_ppgtt_alloc(void *arg) struct drm_i915_private *dev_priv = arg; struct i915_hw_ppgtt *ppgtt; u64 size, last; - int err; + int err = 0; /* Allocate a ppggt and try to fill the entire range */ if (!USES_PPGTT(dev_priv)) return 0; - ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL); - if (!ppgtt) - return -ENOMEM; - mutex_lock(&dev_priv->drm.struct_mutex); ppgtt = __hw_ppgtt_create(dev_priv); if (IS_ERR(ppgtt)) { @@ -153,10 +149,8 @@ static int igt_ppgtt_alloc(void *arg) goto err_unlock; } - if (!ppgtt->vm.allocate_va_range) { - err = 0; + if (!ppgtt->vm.allocate_va_range) goto err_ppgtt_cleanup; - } /* Check we can allocate the entire range */ for (size = 4096; -- GitLab From a9ded78535a109389cd2ca38a22c8d5c0099f71e Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Tue, 12 Jun 2018 09:18:15 +0100 Subject: [PATCH 0243/1506] drm/i915/gtt: Onionify error handling for gen6_ppgtt_create Pull the empty stubs together into the top level gen6_ppgtt_create, and tear each one down on error in proper onion order (rather than use Joonas' pet hate of calling the cleanup function in indeterminable state). Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: Matthew Auld <matthew.william.auld@gmail.com> Reviewed-by: Matthew Auld <matthew.william.auld@gmail.com> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180612081815.3585-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_gtt.c | 81 ++++++++++++++--------------- 1 file changed, 39 insertions(+), 42 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 62991e6cf1d54..40a839119d23f 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1875,7 +1875,7 @@ static int gen6_alloc_va_range(struct i915_address_space *vm, return -ENOMEM; } -static int gen6_init_scratch(struct i915_address_space *vm) +static int gen6_ppgtt_init_scratch(struct i915_address_space *vm) { int ret; @@ -1894,33 +1894,37 @@ static int gen6_init_scratch(struct i915_address_space *vm) return 0; } -static void gen6_free_scratch(struct i915_address_space *vm) +static void gen6_ppgtt_free_scratch(struct i915_address_space *vm) { free_pt(vm, vm->scratch_pt); cleanup_scratch_page(vm); } -static void gen6_ppgtt_cleanup(struct i915_address_space *vm) +static void gen6_ppgtt_free_pd(struct gen6_hw_ppgtt *ppgtt) { - struct gen6_hw_ppgtt *ppgtt = to_gen6_ppgtt(i915_vm_to_ppgtt(vm)); struct i915_page_table *pt; u32 pde; - drm_mm_remove_node(&ppgtt->node); - gen6_for_all_pdes(pt, &ppgtt->base.pd, pde) - if (pt != vm->scratch_pt) - free_pt(vm, pt); + if (pt != ppgtt->base.vm.scratch_pt) + free_pt(&ppgtt->base.vm, pt); +} - gen6_free_scratch(vm); +static void gen6_ppgtt_cleanup(struct i915_address_space *vm) +{ + struct gen6_hw_ppgtt *ppgtt = to_gen6_ppgtt(i915_vm_to_ppgtt(vm)); + + drm_mm_remove_node(&ppgtt->node); + + gen6_ppgtt_free_pd(ppgtt); + gen6_ppgtt_free_scratch(vm); } static int gen6_ppgtt_allocate_page_directories(struct gen6_hw_ppgtt *ppgtt) { - struct i915_address_space *vm = &ppgtt->base.vm; struct drm_i915_private *dev_priv = ppgtt->base.vm.i915; struct i915_ggtt *ggtt = &dev_priv->ggtt; - int ret; + int err; /* PPGTT PDEs reside in the GGTT and consists of 512 entries. The * allocator works in address space sizes, so it's multiplied by page @@ -1928,17 +1932,13 @@ static int gen6_ppgtt_allocate_page_directories(struct gen6_hw_ppgtt *ppgtt) */ BUG_ON(!drm_mm_initialized(&ggtt->vm.mm)); - ret = gen6_init_scratch(vm); - if (ret) - return ret; - - ret = i915_gem_gtt_insert(&ggtt->vm, &ppgtt->node, + err = i915_gem_gtt_insert(&ggtt->vm, &ppgtt->node, GEN6_PD_SIZE, GEN6_PD_ALIGN, I915_COLOR_UNEVICTABLE, 0, ggtt->vm.total, PIN_HIGH); - if (ret) - goto err_out; + if (err) + return err; if (ppgtt->node.start < ggtt->mappable_end) DRM_DEBUG("Forced to use aperture for PDEs\n"); @@ -1950,15 +1950,6 @@ static int gen6_ppgtt_allocate_page_directories(struct gen6_hw_ppgtt *ppgtt) ppgtt->base.pd.base.ggtt_offset / sizeof(gen6_pte_t); return 0; - -err_out: - gen6_free_scratch(vm); - return ret; -} - -static int gen6_ppgtt_alloc(struct gen6_hw_ppgtt *ppgtt) -{ - return gen6_ppgtt_allocate_page_directories(ppgtt); } static void gen6_scratch_va_range(struct gen6_hw_ppgtt *ppgtt, @@ -1984,21 +1975,8 @@ static struct i915_hw_ppgtt *gen6_ppgtt_create(struct drm_i915_private *i915) ppgtt->base.vm.i915 = i915; ppgtt->base.vm.dma = &i915->drm.pdev->dev; - ppgtt->base.vm.pte_encode = ggtt->vm.pte_encode; - - err = gen6_ppgtt_alloc(ppgtt); - if (err) - goto err_free; - ppgtt->base.vm.total = I915_PDES * GEN6_PTES * PAGE_SIZE; - gen6_scratch_va_range(ppgtt, 0, ppgtt->base.vm.total); - gen6_write_page_range(&ppgtt->base, 0, ppgtt->base.vm.total); - - err = gen6_alloc_va_range(&ppgtt->base.vm, 0, ppgtt->base.vm.total); - if (err) - goto err_cleanup; - ppgtt->base.vm.clear_range = gen6_ppgtt_clear_range; ppgtt->base.vm.insert_entries = gen6_ppgtt_insert_entries; ppgtt->base.vm.cleanup = gen6_ppgtt_cleanup; @@ -2009,6 +1987,23 @@ static struct i915_hw_ppgtt *gen6_ppgtt_create(struct drm_i915_private *i915) ppgtt->base.vm.vma_ops.set_pages = ppgtt_set_pages; ppgtt->base.vm.vma_ops.clear_pages = clear_pages; + ppgtt->base.vm.pte_encode = ggtt->vm.pte_encode; + + err = gen6_ppgtt_init_scratch(&ppgtt->base.vm); + if (err) + goto err_free; + + err = gen6_ppgtt_allocate_page_directories(ppgtt); + if (err) + goto err_scratch; + + gen6_scratch_va_range(ppgtt, 0, ppgtt->base.vm.total); + gen6_write_page_range(&ppgtt->base, 0, ppgtt->base.vm.total); + + err = gen6_alloc_va_range(&ppgtt->base.vm, 0, ppgtt->base.vm.total); + if (err) + goto err_pd; + DRM_DEBUG_DRIVER("Allocated pde space (%lldM) at GTT entry: %llx\n", ppgtt->node.size >> 20, ppgtt->node.start / PAGE_SIZE); @@ -2018,8 +2013,10 @@ static struct i915_hw_ppgtt *gen6_ppgtt_create(struct drm_i915_private *i915) return &ppgtt->base; -err_cleanup: - gen6_ppgtt_cleanup(&ppgtt->base.vm); +err_pd: + gen6_ppgtt_free_pd(ppgtt); +err_scratch: + gen6_ppgtt_free_scratch(&ppgtt->base.vm); err_free: kfree(ppgtt); return ERR_PTR(err); -- GitLab From 50935ac767cab5494b4e15f3a95aa9e10513d82d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Pi=C3=B3rkowski?= <piotr.piorkowski@intel.com> Date: Mon, 4 Jun 2018 16:19:41 +0200 Subject: [PATCH 0244/1506] drm/i915/guc: Don't store runtime GuC log level in modparam MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we are using modparam as placeholder for GuC log level. Stop doing this and keep runtime GuC level in intel_guc_log struct. v2: - rename functions intel_guc_log_level_[get|set] to intel_guc_log_[get|set]_level (MichaÅ‚ Wajdeczko) - remove GEM_BUG_ON from intel_guc_log_get_level() (MichaÅ‚ Wajdeczko) Signed-off-by: Piotr Piórkowski <piotr.piorkowski@intel.com> Cc: Michal Wajdeczko <michal.wajdeczko@intel.com> Cc: MichaÅ‚ Winiarski <michal.winiarski@intel.com> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Michal Wajdeczko <michal.wajdeczko@intel.com> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20180604141947.8299-1-piotr.piorkowski@intel.com --- drivers/gpu/drm/i915/i915_debugfs.c | 4 ++-- drivers/gpu/drm/i915/intel_guc.c | 8 +++----- drivers/gpu/drm/i915/intel_guc_log.c | 28 ++++++++++------------------ drivers/gpu/drm/i915/intel_guc_log.h | 10 ++++++++-- drivers/gpu/drm/i915/intel_uc.c | 2 +- 5 files changed, 24 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 698af45e229ce..769ab97458342 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2536,7 +2536,7 @@ static int i915_guc_log_level_get(void *data, u64 *val) if (!USES_GUC(dev_priv)) return -ENODEV; - *val = intel_guc_log_level_get(&dev_priv->guc.log); + *val = intel_guc_log_get_level(&dev_priv->guc.log); return 0; } @@ -2548,7 +2548,7 @@ static int i915_guc_log_level_set(void *data, u64 val) if (!USES_GUC(dev_priv)) return -ENODEV; - return intel_guc_log_level_set(&dev_priv->guc.log, val); + return intel_guc_log_set_level(&dev_priv->guc.log, val); } DEFINE_SIMPLE_ATTRIBUTE(i915_guc_log_level_fops, diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c index 29fd95c1306bd..98b7c121162ab 100644 --- a/drivers/gpu/drm/i915/intel_guc.c +++ b/drivers/gpu/drm/i915/intel_guc.c @@ -203,13 +203,11 @@ void intel_guc_fini(struct intel_guc *guc) guc_shared_data_destroy(guc); } -static u32 get_log_control_flags(void) +static u32 guc_ctl_debug_flags(struct intel_guc *guc) { - u32 level = i915_modparams.guc_log_level; + u32 level = intel_guc_log_get_level(&guc->log); u32 flags = 0; - GEM_BUG_ON(level < 0); - if (!GUC_LOG_LEVEL_IS_ENABLED(level)) flags |= GUC_LOG_DEFAULT_DISABLED; @@ -250,7 +248,7 @@ void intel_guc_init_params(struct intel_guc *guc) params[GUC_CTL_LOG_PARAMS] = guc->log.flags; - params[GUC_CTL_DEBUG] = get_log_control_flags(); + params[GUC_CTL_DEBUG] = guc_ctl_debug_flags(guc); /* If GuC submission is enabled, set up additional parameters here */ if (USES_GUC_SUBMISSION(dev_priv)) { diff --git a/drivers/gpu/drm/i915/intel_guc_log.c b/drivers/gpu/drm/i915/intel_guc_log.c index 401e1704d61ed..d35d883d48e19 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.c +++ b/drivers/gpu/drm/i915/intel_guc_log.c @@ -475,11 +475,12 @@ int intel_guc_log_create(struct intel_guc_log *log) offset = intel_guc_ggtt_offset(guc, vma) >> PAGE_SHIFT; log->flags = (offset << GUC_LOG_BUF_ADDR_SHIFT) | flags; + log->level = i915_modparams.guc_log_level; + return 0; err: - /* logging will be off */ - i915_modparams.guc_log_level = 0; + DRM_ERROR("Failed to allocate GuC log buffer. %d\n", ret); return ret; } @@ -488,15 +489,7 @@ void intel_guc_log_destroy(struct intel_guc_log *log) i915_vma_unpin_and_release(&log->vma); } -int intel_guc_log_level_get(struct intel_guc_log *log) -{ - GEM_BUG_ON(!log->vma); - GEM_BUG_ON(i915_modparams.guc_log_level < 0); - - return i915_modparams.guc_log_level; -} - -int intel_guc_log_level_set(struct intel_guc_log *log, u64 val) +int intel_guc_log_set_level(struct intel_guc_log *log, u32 level) { struct intel_guc *guc = log_to_guc(log); struct drm_i915_private *dev_priv = guc_to_i915(guc); @@ -504,33 +497,32 @@ int intel_guc_log_level_set(struct intel_guc_log *log, u64 val) BUILD_BUG_ON(GUC_LOG_VERBOSITY_MIN != 0); GEM_BUG_ON(!log->vma); - GEM_BUG_ON(i915_modparams.guc_log_level < 0); /* * GuC is recognizing log levels starting from 0 to max, we're using 0 * as indication that logging should be disabled. */ - if (val < GUC_LOG_LEVEL_DISABLED || val > GUC_LOG_LEVEL_MAX) + if (level < GUC_LOG_LEVEL_DISABLED || level > GUC_LOG_LEVEL_MAX) return -EINVAL; mutex_lock(&dev_priv->drm.struct_mutex); - if (i915_modparams.guc_log_level == val) { + if (log->level == level) { ret = 0; goto out_unlock; } intel_runtime_pm_get(dev_priv); - ret = guc_action_control_log(guc, GUC_LOG_LEVEL_IS_VERBOSE(val), - GUC_LOG_LEVEL_IS_ENABLED(val), - GUC_LOG_LEVEL_TO_VERBOSITY(val)); + ret = guc_action_control_log(guc, GUC_LOG_LEVEL_IS_VERBOSE(level), + GUC_LOG_LEVEL_IS_ENABLED(level), + GUC_LOG_LEVEL_TO_VERBOSITY(level)); intel_runtime_pm_put(dev_priv); if (ret) { DRM_DEBUG_DRIVER("guc_log_control action failed %d\n", ret); goto out_unlock; } - i915_modparams.guc_log_level = val; + log->level = level; out_unlock: mutex_unlock(&dev_priv->drm.struct_mutex); diff --git a/drivers/gpu/drm/i915/intel_guc_log.h b/drivers/gpu/drm/i915/intel_guc_log.h index fa80535a6f9d8..f38c48950ed4b 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.h +++ b/drivers/gpu/drm/i915/intel_guc_log.h @@ -30,6 +30,7 @@ #include <linux/workqueue.h> #include "intel_guc_fwif.h" +#include "i915_gem.h" struct intel_guc; @@ -58,6 +59,7 @@ struct intel_guc; #define GUC_LOG_LEVEL_MAX GUC_VERBOSITY_TO_LOG_LEVEL(GUC_LOG_VERBOSITY_MAX) struct intel_guc_log { + u32 level; u32 flags; struct i915_vma *vma; struct { @@ -80,8 +82,7 @@ void intel_guc_log_init_early(struct intel_guc_log *log); int intel_guc_log_create(struct intel_guc_log *log); void intel_guc_log_destroy(struct intel_guc_log *log); -int intel_guc_log_level_get(struct intel_guc_log *log); -int intel_guc_log_level_set(struct intel_guc_log *log, u64 control_val); +int intel_guc_log_set_level(struct intel_guc_log *log, u32 level); bool intel_guc_log_relay_enabled(const struct intel_guc_log *log); int intel_guc_log_relay_open(struct intel_guc_log *log); void intel_guc_log_relay_flush(struct intel_guc_log *log); @@ -89,4 +90,9 @@ void intel_guc_log_relay_close(struct intel_guc_log *log); void intel_guc_log_handle_flush_event(struct intel_guc_log *log); +static inline u32 intel_guc_log_get_level(struct intel_guc_log *log) +{ + return log->level; +} + #endif diff --git a/drivers/gpu/drm/i915/intel_uc.c b/drivers/gpu/drm/i915/intel_uc.c index 6a73e81f373b6..94e8863bd97c6 100644 --- a/drivers/gpu/drm/i915/intel_uc.c +++ b/drivers/gpu/drm/i915/intel_uc.c @@ -207,7 +207,7 @@ void intel_uc_init_mmio(struct drm_i915_private *i915) static void guc_capture_load_err_log(struct intel_guc *guc) { - if (!guc->log.vma || !i915_modparams.guc_log_level) + if (!guc->log.vma || !intel_guc_log_get_level(&guc->log)) return; if (!guc->load_err_log) -- GitLab From 24d891d81312ab3921ce735952d8d2ad34dd90fb Mon Sep 17 00:00:00 2001 From: Piotr Piorkowski <piotr.piorkowski@intel.com> Date: Mon, 4 Jun 2018 16:19:42 +0200 Subject: [PATCH 0245/1506] drm/i915/guc: Refactoring preparation of the GUC_CTL_DEBUG parameter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At the moment, the preparation of GUC_CTL_DEBUG is disordered. Lets move all GUC_CTL_DEBUG related operations to one place. v2: - move 'ads' declaration to USES_GUC_SUBMISSION case (MichaÅ‚ Wajdeczko) Signed-off-by: Piotr Piórkowski <piotr.piorkowski@intel.com> Cc: Michal Wajdeczko <michal.wajdeczko@intel.com> Cc: MichaÅ‚ Winiarski <michal.winiarski@intel.com> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Michal Wajdeczko <michal.wajdeczko@intel.com> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20180604141947.8299-2-piotr.piorkowski@intel.com --- drivers/gpu/drm/i915/intel_guc.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c index 98b7c121162ab..843dfe6b58e2b 100644 --- a/drivers/gpu/drm/i915/intel_guc.c +++ b/drivers/gpu/drm/i915/intel_guc.c @@ -217,6 +217,13 @@ static u32 guc_ctl_debug_flags(struct intel_guc *guc) flags |= GUC_LOG_LEVEL_TO_VERBOSITY(level) << GUC_LOG_VERBOSITY_SHIFT; + if (USES_GUC_SUBMISSION(guc_to_i915(guc))) { + u32 ads = intel_guc_ggtt_offset(guc, guc->ads_vma) + >> PAGE_SHIFT; + + flags |= ads << GUC_ADS_ADDR_SHIFT | GUC_ADS_ENABLED; + } + return flags; } @@ -252,14 +259,9 @@ void intel_guc_init_params(struct intel_guc *guc) /* If GuC submission is enabled, set up additional parameters here */ if (USES_GUC_SUBMISSION(dev_priv)) { - u32 ads = intel_guc_ggtt_offset(guc, - guc->ads_vma) >> PAGE_SHIFT; u32 pgs = intel_guc_ggtt_offset(guc, guc->stage_desc_pool); u32 ctx_in_16 = GUC_MAX_STAGE_DESCRIPTORS / 16; - params[GUC_CTL_DEBUG] |= ads << GUC_ADS_ADDR_SHIFT; - params[GUC_CTL_DEBUG] |= GUC_ADS_ENABLED; - pgs >>= PAGE_SHIFT; params[GUC_CTL_CTXINFO] = (pgs << GUC_CTL_BASE_ADDR_SHIFT) | (ctx_in_16 << GUC_CTL_CTXNUM_IN16_SHIFT); -- GitLab From dc755faef2640ea3d9ef3714c4ac5ece28bfe5a3 Mon Sep 17 00:00:00 2001 From: Piotr Piorkowski <piotr.piorkowski@intel.com> Date: Mon, 4 Jun 2018 16:19:43 +0200 Subject: [PATCH 0246/1506] drm/i915/guc: Refactoring preparation of the GUC_CTL_FEATURE parameter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At the moment, the preparation of GUC_CTL_FEATURE is disordered. Lets move all GUC_CTL_FEATURE related operations to one place. Signed-off-by: Piotr Piórkowski <piotr.piorkowski@intel.com> Cc: Michal Wajdeczko <michal.wajdeczko@intel.com> Cc: MichaÅ‚ Winiarski <michal.winiarski@intel.com> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Michal Wajdeczko <michal.wajdeczko@intel.com> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20180604141947.8299-3-piotr.piorkowski@intel.com --- drivers/gpu/drm/i915/intel_guc.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c index 843dfe6b58e2b..dfc5ef8be9f0a 100644 --- a/drivers/gpu/drm/i915/intel_guc.c +++ b/drivers/gpu/drm/i915/intel_guc.c @@ -227,6 +227,19 @@ static u32 guc_ctl_debug_flags(struct intel_guc *guc) return flags; } +static u32 guc_ctl_feature_flags(struct intel_guc *guc) +{ + u32 flags = 0; + + flags |= GUC_CTL_VCS2_ENABLED; + + if (USES_GUC_SUBMISSION(guc_to_i915(guc))) + flags |= GUC_CTL_KERNEL_SUBMISSIONS; + else + flags |= GUC_CTL_DISABLE_SCHEDULER; + + return flags; +} /* * Initialise the GuC parameter block before starting the firmware * transfer. These parameters are read by the firmware on startup @@ -250,9 +263,7 @@ void intel_guc_init_params(struct intel_guc *guc) params[GUC_CTL_WA] |= GUC_CTL_WA_UK_BY_DRIVER; - params[GUC_CTL_FEATURE] |= GUC_CTL_DISABLE_SCHEDULER | - GUC_CTL_VCS2_ENABLED; - + params[GUC_CTL_FEATURE] = guc_ctl_feature_flags(guc); params[GUC_CTL_LOG_PARAMS] = guc->log.flags; params[GUC_CTL_DEBUG] = guc_ctl_debug_flags(guc); @@ -265,11 +276,6 @@ void intel_guc_init_params(struct intel_guc *guc) pgs >>= PAGE_SHIFT; params[GUC_CTL_CTXINFO] = (pgs << GUC_CTL_BASE_ADDR_SHIFT) | (ctx_in_16 << GUC_CTL_CTXNUM_IN16_SHIFT); - - params[GUC_CTL_FEATURE] |= GUC_CTL_KERNEL_SUBMISSIONS; - - /* Unmask this bit to enable the GuC's internal scheduler */ - params[GUC_CTL_FEATURE] &= ~GUC_CTL_DISABLE_SCHEDULER; } /* -- GitLab From 532717b90bd0159f221a6f5f1d0b35514e88192b Mon Sep 17 00:00:00 2001 From: Piotr Piorkowski <piotr.piorkowski@intel.com> Date: Mon, 4 Jun 2018 16:19:44 +0200 Subject: [PATCH 0247/1506] drm/i915/guc: Refactoring preparation of the GUC_CTL_LOG_PARAMS parameter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At the moment, the preparation of GUC_CTL_LOG_PARAMS is disordered. Additionally, in struct intel_guc_log we have an unnecessary field 'flags' which we use only to assign value to GuC parameter. Lets move all GUC_CTL_LOG_PARAMS related operations to one place, and lets remove field 'flags' from struct intel_guc_log. Signed-off-by: Piotr Piórkowski <piotr.piorkowski@intel.com> Cc: Michal Wajdeczko <michal.wajdeczko@intel.com> Cc: MichaÅ‚ Winiarski <michal.winiarski@intel.com> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Michal Wajdeczko <michal.wajdeczko@intel.com> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20180604141947.8299-4-piotr.piorkowski@intel.com --- drivers/gpu/drm/i915/intel_guc.c | 19 +++++++++++++++++-- drivers/gpu/drm/i915/intel_guc_log.c | 11 ----------- drivers/gpu/drm/i915/intel_guc_log.h | 1 - 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c index dfc5ef8be9f0a..d2d2cc1d6d46a 100644 --- a/drivers/gpu/drm/i915/intel_guc.c +++ b/drivers/gpu/drm/i915/intel_guc.c @@ -240,6 +240,22 @@ static u32 guc_ctl_feature_flags(struct intel_guc *guc) return flags; } + +static u32 guc_ctl_log_params_flags(struct intel_guc *guc) +{ + u32 offset = intel_guc_ggtt_offset(guc, guc->log.vma) >> PAGE_SHIFT; + u32 flags; + + /* each allocated unit is a page */ + flags = GUC_LOG_VALID | GUC_LOG_NOTIFY_ON_HALF_FULL | + (GUC_LOG_CRASH_PAGES << GUC_LOG_CRASH_SHIFT) | + (GUC_LOG_DPC_PAGES << GUC_LOG_DPC_SHIFT) | + (GUC_LOG_ISR_PAGES << GUC_LOG_ISR_SHIFT) | + (offset << GUC_LOG_BUF_ADDR_SHIFT); + + return flags; +} + /* * Initialise the GuC parameter block before starting the firmware * transfer. These parameters are read by the firmware on startup @@ -264,8 +280,7 @@ void intel_guc_init_params(struct intel_guc *guc) params[GUC_CTL_WA] |= GUC_CTL_WA_UK_BY_DRIVER; params[GUC_CTL_FEATURE] = guc_ctl_feature_flags(guc); - params[GUC_CTL_LOG_PARAMS] = guc->log.flags; - + params[GUC_CTL_LOG_PARAMS] = guc_ctl_log_params_flags(guc); params[GUC_CTL_DEBUG] = guc_ctl_debug_flags(guc); /* If GuC submission is enabled, set up additional parameters here */ diff --git a/drivers/gpu/drm/i915/intel_guc_log.c b/drivers/gpu/drm/i915/intel_guc_log.c index d35d883d48e19..b921c948c7f5c 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.c +++ b/drivers/gpu/drm/i915/intel_guc_log.c @@ -452,8 +452,6 @@ int intel_guc_log_create(struct intel_guc_log *log) { struct intel_guc *guc = log_to_guc(log); struct i915_vma *vma; - unsigned long offset; - u32 flags; int ret; GEM_BUG_ON(log->vma); @@ -466,15 +464,6 @@ int intel_guc_log_create(struct intel_guc_log *log) log->vma = vma; - /* each allocated unit is a page */ - flags = GUC_LOG_VALID | GUC_LOG_NOTIFY_ON_HALF_FULL | - (GUC_LOG_DPC_PAGES << GUC_LOG_DPC_SHIFT) | - (GUC_LOG_ISR_PAGES << GUC_LOG_ISR_SHIFT) | - (GUC_LOG_CRASH_PAGES << GUC_LOG_CRASH_SHIFT); - - offset = intel_guc_ggtt_offset(guc, vma) >> PAGE_SHIFT; - log->flags = (offset << GUC_LOG_BUF_ADDR_SHIFT) | flags; - log->level = i915_modparams.guc_log_level; return 0; diff --git a/drivers/gpu/drm/i915/intel_guc_log.h b/drivers/gpu/drm/i915/intel_guc_log.h index f38c48950ed4b..196e2199a3e29 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.h +++ b/drivers/gpu/drm/i915/intel_guc_log.h @@ -60,7 +60,6 @@ struct intel_guc; struct intel_guc_log { u32 level; - u32 flags; struct i915_vma *vma; struct { void *buf_addr; -- GitLab From 741cebee0aa59cdaafb798c66171c2a863c3fa32 Mon Sep 17 00:00:00 2001 From: Piotr Piorkowski <piotr.piorkowski@intel.com> Date: Mon, 4 Jun 2018 16:19:45 +0200 Subject: [PATCH 0248/1506] drm/i915/guc: Refactoring preparation of the GUC_CTL_CTXINFO parameter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At the moment, the preparation of GUC_CTL_CTXINFO is disordered. Lets move all GUC_CTL_CTXINFO related operations to one place. v2: - move 'ctxnum' and 'base' declarations to USES_GUC_SUBMISSION case (MichaÅ‚ Wajdeczko) Signed-off-by: Piotr Piórkowski <piotr.piorkowski@intel.com> Cc: Michal Wajdeczko <michal.wajdeczko@intel.com> Cc: MichaÅ‚ Winiarski <michal.winiarski@intel.com> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Michal Wajdeczko <michal.wajdeczko@intel.com> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20180604141947.8299-5-piotr.piorkowski@intel.com --- drivers/gpu/drm/i915/intel_guc.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c index d2d2cc1d6d46a..dce475eaa39b6 100644 --- a/drivers/gpu/drm/i915/intel_guc.c +++ b/drivers/gpu/drm/i915/intel_guc.c @@ -241,6 +241,23 @@ static u32 guc_ctl_feature_flags(struct intel_guc *guc) return flags; } +static u32 guc_ctl_ctxinfo_flags(struct intel_guc *guc) +{ + u32 flags = 0; + + if (USES_GUC_SUBMISSION(guc_to_i915(guc))) { + u32 ctxnum, base; + + base = intel_guc_ggtt_offset(guc, guc->stage_desc_pool); + ctxnum = GUC_MAX_STAGE_DESCRIPTORS / 16; + + base >>= PAGE_SHIFT; + flags |= (base << GUC_CTL_BASE_ADDR_SHIFT) | + (ctxnum << GUC_CTL_CTXNUM_IN16_SHIFT); + } + return flags; +} + static u32 guc_ctl_log_params_flags(struct intel_guc *guc) { u32 offset = intel_guc_ggtt_offset(guc, guc->log.vma) >> PAGE_SHIFT; @@ -282,16 +299,7 @@ void intel_guc_init_params(struct intel_guc *guc) params[GUC_CTL_FEATURE] = guc_ctl_feature_flags(guc); params[GUC_CTL_LOG_PARAMS] = guc_ctl_log_params_flags(guc); params[GUC_CTL_DEBUG] = guc_ctl_debug_flags(guc); - - /* If GuC submission is enabled, set up additional parameters here */ - if (USES_GUC_SUBMISSION(dev_priv)) { - u32 pgs = intel_guc_ggtt_offset(guc, guc->stage_desc_pool); - u32 ctx_in_16 = GUC_MAX_STAGE_DESCRIPTORS / 16; - - pgs >>= PAGE_SHIFT; - params[GUC_CTL_CTXINFO] = (pgs << GUC_CTL_BASE_ADDR_SHIFT) | - (ctx_in_16 << GUC_CTL_CTXNUM_IN16_SHIFT); - } + params[GUC_CTL_CTXINFO] = guc_ctl_ctxinfo_flags(guc); /* * All SOFT_SCRATCH registers are in FORCEWAKE_BLITTER domain and -- GitLab From 5288c7182dd389bb03b0a1aa38550b344fe5bf97 Mon Sep 17 00:00:00 2001 From: Piotr Piorkowski <piotr.piorkowski@intel.com> Date: Tue, 5 Jun 2018 17:13:29 +0200 Subject: [PATCH 0249/1506] drm/i915/guc: Move defines with size of GuC logs to intel_guc_log.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At this moment, we have defined GuC logs sizes in intel_guc_fwif.h, but as these values are related directly to the GuC logs, and not to API of GuC parameters, we should move these defines to intel_guc_log.h. v2: - change buffers size to more friendly (MichaÅ‚ Wajdeczko) - remove GUC_LOG_SIZE define (MichaÅ‚ Wajdeczko) v3: - use SZ_* macros to define buffers sizes (MichaÅ‚ Wajdeczko) Signed-off-by: Piotr Piórkowski <piotr.piorkowski@intel.com> Cc: Michal Wajdeczko <michal.wajdeczko@intel.com> Cc: MichaÅ‚ Winiarski <michal.winiarski@intel.com> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Michal Wajdeczko <michal.wajdeczko@intel.com> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20180605151330.9954-1-piotr.piorkowski@intel.com --- drivers/gpu/drm/i915/intel_guc.c | 28 +++++++++++++++++++---- drivers/gpu/drm/i915/intel_guc_fwif.h | 20 +++------------- drivers/gpu/drm/i915/intel_guc_log.c | 33 +++++++++++++++++++++++---- drivers/gpu/drm/i915/intel_guc_log.h | 9 +++----- 4 files changed, 57 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c index dce475eaa39b6..4101264cf5660 100644 --- a/drivers/gpu/drm/i915/intel_guc.c +++ b/drivers/gpu/drm/i915/intel_guc.c @@ -263,13 +263,31 @@ static u32 guc_ctl_log_params_flags(struct intel_guc *guc) u32 offset = intel_guc_ggtt_offset(guc, guc->log.vma) >> PAGE_SHIFT; u32 flags; - /* each allocated unit is a page */ - flags = GUC_LOG_VALID | GUC_LOG_NOTIFY_ON_HALF_FULL | - (GUC_LOG_CRASH_PAGES << GUC_LOG_CRASH_SHIFT) | - (GUC_LOG_DPC_PAGES << GUC_LOG_DPC_SHIFT) | - (GUC_LOG_ISR_PAGES << GUC_LOG_ISR_SHIFT) | + #define UNIT SZ_4K + + BUILD_BUG_ON(!CRASH_BUFFER_SIZE); + BUILD_BUG_ON(!IS_ALIGNED(CRASH_BUFFER_SIZE, UNIT)); + BUILD_BUG_ON(!DPC_BUFFER_SIZE); + BUILD_BUG_ON(!IS_ALIGNED(DPC_BUFFER_SIZE, UNIT)); + BUILD_BUG_ON(!ISR_BUFFER_SIZE); + BUILD_BUG_ON(!IS_ALIGNED(ISR_BUFFER_SIZE, UNIT)); + + BUILD_BUG_ON((CRASH_BUFFER_SIZE / UNIT - 1) > + (GUC_LOG_CRASH_MASK >> GUC_LOG_CRASH_SHIFT)); + BUILD_BUG_ON((DPC_BUFFER_SIZE / UNIT - 1) > + (GUC_LOG_DPC_MASK >> GUC_LOG_DPC_SHIFT)); + BUILD_BUG_ON((ISR_BUFFER_SIZE / UNIT - 1) > + (GUC_LOG_ISR_MASK >> GUC_LOG_ISR_SHIFT)); + + flags = GUC_LOG_VALID | + GUC_LOG_NOTIFY_ON_HALF_FULL | + ((CRASH_BUFFER_SIZE / UNIT - 1) << GUC_LOG_CRASH_SHIFT) | + ((DPC_BUFFER_SIZE / UNIT - 1) << GUC_LOG_DPC_SHIFT) | + ((ISR_BUFFER_SIZE / UNIT - 1) << GUC_LOG_ISR_SHIFT) | (offset << GUC_LOG_BUF_ADDR_SHIFT); + #undef UNIT + return flags; } diff --git a/drivers/gpu/drm/i915/intel_guc_fwif.h b/drivers/gpu/drm/i915/intel_guc_fwif.h index 0867ba76d4453..1a0f2a39cef9b 100644 --- a/drivers/gpu/drm/i915/intel_guc_fwif.h +++ b/drivers/gpu/drm/i915/intel_guc_fwif.h @@ -84,12 +84,12 @@ #define GUC_LOG_VALID (1 << 0) #define GUC_LOG_NOTIFY_ON_HALF_FULL (1 << 1) #define GUC_LOG_ALLOC_IN_MEGABYTE (1 << 3) -#define GUC_LOG_CRASH_PAGES 1 #define GUC_LOG_CRASH_SHIFT 4 -#define GUC_LOG_DPC_PAGES 7 +#define GUC_LOG_CRASH_MASK (0x1 << GUC_LOG_CRASH_SHIFT) #define GUC_LOG_DPC_SHIFT 6 -#define GUC_LOG_ISR_PAGES 7 +#define GUC_LOG_DPC_MASK (0x7 << GUC_LOG_DPC_SHIFT) #define GUC_LOG_ISR_SHIFT 9 +#define GUC_LOG_ISR_MASK (0x7 << GUC_LOG_ISR_SHIFT) #define GUC_LOG_BUF_ADDR_SHIFT 12 #define GUC_CTL_PAGE_FAULT_CONTROL 5 @@ -532,20 +532,6 @@ enum guc_log_buffer_type { }; /** - * DOC: GuC Log buffer Layout - * - * Page0 +-------------------------------+ - * | ISR state header (32 bytes) | - * | DPC state header | - * | Crash dump state header | - * Page1 +-------------------------------+ - * | ISR logs | - * Page9 +-------------------------------+ - * | DPC logs | - * Page17 +-------------------------------+ - * | Crash Dump logs | - * +-------------------------------+ - * * Below state structure is used for coordination of retrieval of GuC firmware * logs. Separate state is maintained for each log buffer type. * read_ptr points to the location where i915 read last in log buffer and diff --git a/drivers/gpu/drm/i915/intel_guc_log.c b/drivers/gpu/drm/i915/intel_guc_log.c index b921c948c7f5c..6da61a71d28f6 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.c +++ b/drivers/gpu/drm/i915/intel_guc_log.c @@ -215,11 +215,11 @@ static unsigned int guc_get_log_buffer_size(enum guc_log_buffer_type type) { switch (type) { case GUC_ISR_LOG_BUFFER: - return (GUC_LOG_ISR_PAGES + 1) * PAGE_SIZE; + return ISR_BUFFER_SIZE; case GUC_DPC_LOG_BUFFER: - return (GUC_LOG_DPC_PAGES + 1) * PAGE_SIZE; + return DPC_BUFFER_SIZE; case GUC_CRASH_DUMP_LOG_BUFFER: - return (GUC_LOG_CRASH_PAGES + 1) * PAGE_SIZE; + return CRASH_BUFFER_SIZE; default: MISSING_CASE(type); } @@ -397,7 +397,7 @@ static int guc_log_relay_create(struct intel_guc_log *log) lockdep_assert_held(&log->relay.lock); /* Keep the size of sub buffers same as shared log buffer */ - subbuf_size = GUC_LOG_SIZE; + subbuf_size = log->vma->size; /* * Store up to 8 snapshots, which is large enough to buffer sufficient @@ -452,11 +452,34 @@ int intel_guc_log_create(struct intel_guc_log *log) { struct intel_guc *guc = log_to_guc(log); struct i915_vma *vma; + u32 guc_log_size; int ret; GEM_BUG_ON(log->vma); - vma = intel_guc_allocate_vma(guc, GUC_LOG_SIZE); + /* + * GuC Log buffer Layout + * + * +===============================+ 00B + * | Crash dump state header | + * +-------------------------------+ 32B + * | DPC state header | + * +-------------------------------+ 64B + * | ISR state header | + * +-------------------------------+ 96B + * | | + * +===============================+ PAGE_SIZE (4KB) + * | Crash Dump logs | + * +===============================+ + CRASH_SIZE + * | DPC logs | + * +===============================+ + DPC_SIZE + * | ISR logs | + * +===============================+ + ISR_SIZE + */ + guc_log_size = PAGE_SIZE + CRASH_BUFFER_SIZE + DPC_BUFFER_SIZE + + ISR_BUFFER_SIZE; + + vma = intel_guc_allocate_vma(guc, guc_log_size); if (IS_ERR(vma)) { ret = PTR_ERR(vma); goto err; diff --git a/drivers/gpu/drm/i915/intel_guc_log.h b/drivers/gpu/drm/i915/intel_guc_log.h index 196e2199a3e29..dfc07210a1075 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.h +++ b/drivers/gpu/drm/i915/intel_guc_log.h @@ -34,12 +34,9 @@ struct intel_guc; -/* - * The first page is to save log buffer state. Allocate one - * extra page for others in case for overlap - */ -#define GUC_LOG_SIZE ((1 + GUC_LOG_DPC_PAGES + 1 + GUC_LOG_ISR_PAGES + \ - 1 + GUC_LOG_CRASH_PAGES + 1) << PAGE_SHIFT) +#define CRASH_BUFFER_SIZE SZ_8K +#define DPC_BUFFER_SIZE SZ_32K +#define ISR_BUFFER_SIZE SZ_32K /* * While we're using plain log level in i915, GuC controls are much more... -- GitLab From 3d6d62eae7d75a902f4eacdbb2d775c7c27f3987 Mon Sep 17 00:00:00 2001 From: Piotr Piorkowski <piotr.piorkowski@intel.com> Date: Tue, 5 Jun 2018 17:13:30 +0200 Subject: [PATCH 0250/1506] drm/i915/guc: Add support for define guc_log_size in megabytes. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At this moment we can define GuC logs sizes only using pages. But GuC also allows use for this values expressed in megabytes. Lets add support for define guc_log_size in megabytes when we debug of GuC. v2: - change buffers size to more friendly (MichaÅ‚ Wajdeczko) - merge statements in guc_ctl_log_params_flags() (MichaÅ‚ Wajdeczko) v3: - fix ifdef (rename DRM_I915_DEBUG_GUC to CONFIG_DRM_I915_DEBUG_GUC) (MichaÅ‚ Wajdeczko) - use SZ_* macros to define buffers sizes (MichaÅ‚ Wajdeczko) Signed-off-by: Piotr Piórkowski <piotr.piorkowski@intel.com> Cc: Michal Wajdeczko <michal.wajdeczko@intel.com> Cc: MichaÅ‚ Winiarski <michal.winiarski@intel.com> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Michal Wajdeczko <michal.wajdeczko@intel.com> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20180605151330.9954-2-piotr.piorkowski@intel.com --- drivers/gpu/drm/i915/intel_guc.c | 8 ++++++++ drivers/gpu/drm/i915/intel_guc_log.h | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c index 4101264cf5660..1aff30b0870c2 100644 --- a/drivers/gpu/drm/i915/intel_guc.c +++ b/drivers/gpu/drm/i915/intel_guc.c @@ -263,7 +263,13 @@ static u32 guc_ctl_log_params_flags(struct intel_guc *guc) u32 offset = intel_guc_ggtt_offset(guc, guc->log.vma) >> PAGE_SHIFT; u32 flags; + #if (((CRASH_BUFFER_SIZE) % SZ_1M) == 0) + #define UNIT SZ_1M + #define FLAG GUC_LOG_ALLOC_IN_MEGABYTE + #else #define UNIT SZ_4K + #define FLAG 0 + #endif BUILD_BUG_ON(!CRASH_BUFFER_SIZE); BUILD_BUG_ON(!IS_ALIGNED(CRASH_BUFFER_SIZE, UNIT)); @@ -281,12 +287,14 @@ static u32 guc_ctl_log_params_flags(struct intel_guc *guc) flags = GUC_LOG_VALID | GUC_LOG_NOTIFY_ON_HALF_FULL | + FLAG | ((CRASH_BUFFER_SIZE / UNIT - 1) << GUC_LOG_CRASH_SHIFT) | ((DPC_BUFFER_SIZE / UNIT - 1) << GUC_LOG_DPC_SHIFT) | ((ISR_BUFFER_SIZE / UNIT - 1) << GUC_LOG_ISR_SHIFT) | (offset << GUC_LOG_BUF_ADDR_SHIFT); #undef UNIT + #undef FLAG return flags; } diff --git a/drivers/gpu/drm/i915/intel_guc_log.h b/drivers/gpu/drm/i915/intel_guc_log.h index dfc07210a1075..7bc763f10c03e 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.h +++ b/drivers/gpu/drm/i915/intel_guc_log.h @@ -34,9 +34,15 @@ struct intel_guc; +#ifdef CONFIG_DRM_I915_DEBUG_GUC +#define CRASH_BUFFER_SIZE SZ_2M +#define DPC_BUFFER_SIZE SZ_8M +#define ISR_BUFFER_SIZE SZ_8M +#else #define CRASH_BUFFER_SIZE SZ_8K #define DPC_BUFFER_SIZE SZ_32K #define ISR_BUFFER_SIZE SZ_32K +#endif /* * While we're using plain log level in i915, GuC controls are much more... -- GitLab From e9e7dc4144cd6d4ba873fd506fe38bccb9dbbd85 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Tue, 12 Jun 2018 13:04:46 +0100 Subject: [PATCH 0251/1506] drm/i915/gtt: Make gen6 page directories evictable Currently all page directories are bound at creation using an unevictable node in the GGTT. This severely limits us as we cannot remove any inactive ppgtt for new contexts, or under aperture pressure. To fix this we need to make the page directory into a first class and unbindable vma. Hence, the creation of a custom vma to wrap the page directory as opposed to a GEM object. In this patch, we leave the page directories pinned upon creation. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: Matthew Auld <matthew.william.auld@gmail.com> Reviewed-by: Matthew Auld <matthew.william.auld@gmail.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180612120446.13901-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_gtt.c | 257 ++++++++++++++++------------ drivers/gpu/drm/i915/i915_gem_gtt.h | 2 +- drivers/gpu/drm/i915/i915_vma.h | 7 + 3 files changed, 155 insertions(+), 111 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 40a839119d23f..267f1f97b9f09 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1640,50 +1640,55 @@ static void gen6_dump_ppgtt(struct i915_hw_ppgtt *base, struct seq_file *m) { struct gen6_hw_ppgtt *ppgtt = to_gen6_ppgtt(base); struct i915_address_space *vm = &base->vm; - struct i915_page_table *unused; - gen6_pte_t scratch_pte; - u32 pd_entry, pte, pde; - - scratch_pte = vm->pte_encode(vm->scratch_page.daddr, I915_CACHE_LLC, 0); - - gen6_for_all_pdes(unused, &base->pd, pde) { - u32 expected; - gen6_pte_t *pt_vaddr; - const dma_addr_t pt_addr = px_dma(base->pd.page_table[pde]); - pd_entry = readl(ppgtt->pd_addr + pde); - expected = (GEN6_PDE_ADDR_ENCODE(pt_addr) | GEN6_PDE_VALID); - - if (pd_entry != expected) - seq_printf(m, "\tPDE #%d mismatch: Actual PDE: %x Expected PDE: %x\n", - pde, - pd_entry, - expected); - seq_printf(m, "\tPDE: %x\n", pd_entry); - - pt_vaddr = kmap_atomic_px(base->pd.page_table[pde]); - - for (pte = 0; pte < GEN6_PTES; pte+=4) { - unsigned long va = - (pde * PAGE_SIZE * GEN6_PTES) + - (pte * PAGE_SIZE); + const gen6_pte_t scratch_pte = + vm->pte_encode(vm->scratch_page.daddr, I915_CACHE_LLC, 0); + struct i915_page_table *pt; + u32 pte, pde; + + gen6_for_all_pdes(pt, &base->pd, pde) { + gen6_pte_t *vaddr; + + if (pt == base->vm.scratch_pt) + continue; + + if (i915_vma_is_bound(ppgtt->vma, I915_VMA_GLOBAL_BIND)) { + u32 expected = + GEN6_PDE_ADDR_ENCODE(px_dma(pt)) | + GEN6_PDE_VALID; + u32 pd_entry = readl(ppgtt->pd_addr + pde); + + if (pd_entry != expected) + seq_printf(m, + "\tPDE #%d mismatch: Actual PDE: %x Expected PDE: %x\n", + pde, + pd_entry, + expected); + + seq_printf(m, "\tPDE: %x\n", pd_entry); + } + + vaddr = kmap_atomic_px(base->pd.page_table[pde]); + for (pte = 0; pte < GEN6_PTES; pte += 4) { int i; - bool found = false; + for (i = 0; i < 4; i++) - if (pt_vaddr[pte + i] != scratch_pte) - found = true; - if (!found) + if (vaddr[pte + i] != scratch_pte) + break; + if (i == 4) continue; - seq_printf(m, "\t\t0x%lx [%03d,%04d]: =", va, pde, pte); + seq_printf(m, "\t\t(%03d, %04d) %08lx: ", + pde, pte, + (pde * GEN6_PTES + pte) * PAGE_SIZE); for (i = 0; i < 4; i++) { - if (pt_vaddr[pte + i] != scratch_pte) - seq_printf(m, " %08x", pt_vaddr[pte + i]); + if (vaddr[pte + i] != scratch_pte) + seq_printf(m, " %08x", vaddr[pte + i]); else - seq_puts(m, " SCRATCH "); + seq_puts(m, " SCRATCH"); } seq_puts(m, "\n"); } - kunmap_atomic(pt_vaddr); + kunmap_atomic(vaddr); } } @@ -1697,22 +1702,6 @@ static inline void gen6_write_pde(const struct gen6_hw_ppgtt *ppgtt, ppgtt->pd_addr + pde); } -/* Write all the page tables found in the ppgtt structure to incrementing page - * directories. */ -static void gen6_write_page_range(struct i915_hw_ppgtt *base, - u32 start, u32 length) -{ - struct gen6_hw_ppgtt *ppgtt = to_gen6_ppgtt(base); - struct i915_page_table *pt; - unsigned int pde; - - gen6_for_each_pde(pt, &base->pd, start, length, pde) - gen6_write_pde(ppgtt, pde, pt); - - mark_tlbs_dirty(base); - gen6_ggtt_invalidate(base->vm.i915); -} - static void gen8_ppgtt_enable(struct drm_i915_private *dev_priv) { struct intel_engine_cs *engine; @@ -1858,8 +1847,12 @@ static int gen6_alloc_va_range(struct i915_address_space *vm, gen6_initialize_pt(vm, pt); ppgtt->base.pd.page_table[pde] = pt; - gen6_write_pde(ppgtt, pde, pt); - flush = true; + + if (i915_vma_is_bound(ppgtt->vma, + I915_VMA_GLOBAL_BIND)) { + gen6_write_pde(ppgtt, pde, pt); + flush = true; + } } } @@ -1875,8 +1868,11 @@ static int gen6_alloc_va_range(struct i915_address_space *vm, return -ENOMEM; } -static int gen6_ppgtt_init_scratch(struct i915_address_space *vm) +static int gen6_ppgtt_init_scratch(struct gen6_hw_ppgtt *ppgtt) { + struct i915_address_space * const vm = &ppgtt->base.vm; + struct i915_page_table *unused; + u32 pde; int ret; ret = setup_scratch_page(vm, __GFP_HIGHMEM); @@ -1890,6 +1886,8 @@ static int gen6_ppgtt_init_scratch(struct i915_address_space *vm) } gen6_initialize_pt(vm, vm->scratch_pt); + gen6_for_all_pdes(unused, &ppgtt->base.pd, pde) + ppgtt->base.pd.page_table[pde] = vm->scratch_pt; return 0; } @@ -1914,52 +1912,104 @@ static void gen6_ppgtt_cleanup(struct i915_address_space *vm) { struct gen6_hw_ppgtt *ppgtt = to_gen6_ppgtt(i915_vm_to_ppgtt(vm)); - drm_mm_remove_node(&ppgtt->node); + i915_vma_unpin(ppgtt->vma); + i915_vma_destroy(ppgtt->vma); gen6_ppgtt_free_pd(ppgtt); gen6_ppgtt_free_scratch(vm); } -static int gen6_ppgtt_allocate_page_directories(struct gen6_hw_ppgtt *ppgtt) +static int pd_vma_set_pages(struct i915_vma *vma) { - struct drm_i915_private *dev_priv = ppgtt->base.vm.i915; - struct i915_ggtt *ggtt = &dev_priv->ggtt; - int err; + vma->pages = ERR_PTR(-ENODEV); + return 0; +} - /* PPGTT PDEs reside in the GGTT and consists of 512 entries. The - * allocator works in address space sizes, so it's multiplied by page - * size. We allocate at the top of the GTT to avoid fragmentation. - */ - BUG_ON(!drm_mm_initialized(&ggtt->vm.mm)); +static void pd_vma_clear_pages(struct i915_vma *vma) +{ + GEM_BUG_ON(!vma->pages); - err = i915_gem_gtt_insert(&ggtt->vm, &ppgtt->node, - GEN6_PD_SIZE, GEN6_PD_ALIGN, - I915_COLOR_UNEVICTABLE, - 0, ggtt->vm.total, - PIN_HIGH); - if (err) - return err; + vma->pages = NULL; +} + +static int pd_vma_bind(struct i915_vma *vma, + enum i915_cache_level cache_level, + u32 unused) +{ + struct i915_ggtt *ggtt = i915_vm_to_ggtt(vma->vm); + struct gen6_hw_ppgtt *ppgtt = vma->private; + u32 ggtt_offset = i915_ggtt_offset(vma) / PAGE_SIZE; + struct i915_page_table *pt; + unsigned int pde; - if (ppgtt->node.start < ggtt->mappable_end) - DRM_DEBUG("Forced to use aperture for PDEs\n"); + ppgtt->base.pd.base.ggtt_offset = ggtt_offset * sizeof(gen6_pte_t); + ppgtt->pd_addr = (gen6_pte_t __iomem *)ggtt->gsm + ggtt_offset; - ppgtt->base.pd.base.ggtt_offset = - ppgtt->node.start / PAGE_SIZE * sizeof(gen6_pte_t); + gen6_for_all_pdes(pt, &ppgtt->base.pd, pde) + gen6_write_pde(ppgtt, pde, pt); - ppgtt->pd_addr = (gen6_pte_t __iomem *)ggtt->gsm + - ppgtt->base.pd.base.ggtt_offset / sizeof(gen6_pte_t); + mark_tlbs_dirty(&ppgtt->base); + gen6_ggtt_invalidate(ppgtt->base.vm.i915); return 0; } -static void gen6_scratch_va_range(struct gen6_hw_ppgtt *ppgtt, - u64 start, u64 length) +static void pd_vma_unbind(struct i915_vma *vma) { - struct i915_page_table *unused; - u32 pde; +} - gen6_for_each_pde(unused, &ppgtt->base.pd, start, length, pde) - ppgtt->base.pd.page_table[pde] = ppgtt->base.vm.scratch_pt; +static const struct i915_vma_ops pd_vma_ops = { + .set_pages = pd_vma_set_pages, + .clear_pages = pd_vma_clear_pages, + .bind_vma = pd_vma_bind, + .unbind_vma = pd_vma_unbind, +}; + +static struct i915_vma *pd_vma_create(struct gen6_hw_ppgtt *ppgtt, int size) +{ + struct drm_i915_private *i915 = ppgtt->base.vm.i915; + struct i915_ggtt *ggtt = &i915->ggtt; + struct i915_vma *vma; + int i; + + GEM_BUG_ON(!IS_ALIGNED(size, I915_GTT_PAGE_SIZE)); + GEM_BUG_ON(size > ggtt->vm.total); + + vma = kmem_cache_zalloc(i915->vmas, GFP_KERNEL); + if (!vma) + return ERR_PTR(-ENOMEM); + + for (i = 0; i < ARRAY_SIZE(vma->last_read); i++) + init_request_active(&vma->last_read[i], NULL); + init_request_active(&vma->last_fence, NULL); + + vma->vm = &ggtt->vm; + vma->ops = &pd_vma_ops; + vma->private = ppgtt; + + vma->size = size; + vma->fence_size = size; + vma->flags = I915_VMA_GGTT; + vma->ggtt_view.type = I915_GGTT_VIEW_ROTATED; /* prevent fencing */ + + INIT_LIST_HEAD(&vma->obj_link); + list_add(&vma->vm_link, &vma->vm->unbound_list); + + return vma; +} + +static int gen6_ppgtt_pin(struct i915_hw_ppgtt *base) +{ + struct gen6_hw_ppgtt *ppgtt = to_gen6_ppgtt(base); + + /* + * PPGTT PDEs reside in the GGTT and consists of 512 entries. The + * allocator works in address space sizes, so it's multiplied by page + * size. We allocate at the top of the GTT to avoid fragmentation. + */ + return i915_vma_pin(ppgtt->vma, + 0, GEN6_PD_ALIGN, + PIN_GLOBAL | PIN_HIGH); } static struct i915_hw_ppgtt *gen6_ppgtt_create(struct drm_i915_private *i915) @@ -1989,24 +2039,27 @@ static struct i915_hw_ppgtt *gen6_ppgtt_create(struct drm_i915_private *i915) ppgtt->base.vm.pte_encode = ggtt->vm.pte_encode; - err = gen6_ppgtt_init_scratch(&ppgtt->base.vm); + err = gen6_ppgtt_init_scratch(ppgtt); if (err) goto err_free; - err = gen6_ppgtt_allocate_page_directories(ppgtt); - if (err) + ppgtt->vma = pd_vma_create(ppgtt, GEN6_PD_SIZE); + if (IS_ERR(ppgtt->vma)) { + err = PTR_ERR(ppgtt->vma); goto err_scratch; - - gen6_scratch_va_range(ppgtt, 0, ppgtt->base.vm.total); - gen6_write_page_range(&ppgtt->base, 0, ppgtt->base.vm.total); + } err = gen6_alloc_va_range(&ppgtt->base.vm, 0, ppgtt->base.vm.total); + if (err) + goto err_vma; + + err = gen6_ppgtt_pin(&ppgtt->base); if (err) goto err_pd; DRM_DEBUG_DRIVER("Allocated pde space (%lldM) at GTT entry: %llx\n", - ppgtt->node.size >> 20, - ppgtt->node.start / PAGE_SIZE); + ppgtt->vma->node.size >> 20, + ppgtt->vma->node.start / PAGE_SIZE); DRM_DEBUG_DRIVER("Adding PPGTT at offset %x\n", ppgtt->base.pd.base.ggtt_offset << 10); @@ -2015,6 +2068,8 @@ static struct i915_hw_ppgtt *gen6_ppgtt_create(struct drm_i915_private *i915) err_pd: gen6_ppgtt_free_pd(ppgtt); +err_vma: + i915_vma_destroy(ppgtt->vma); err_scratch: gen6_ppgtt_free_scratch(&ppgtt->base.vm); err_free: @@ -3533,6 +3588,7 @@ void i915_gem_restore_gtt_mappings(struct drm_i915_private *dev_priv) } ggtt->vm.closed = false; + i915_ggtt_invalidate(dev_priv); if (INTEL_GEN(dev_priv) >= 8) { struct intel_ppat *ppat = &dev_priv->ppat; @@ -3541,25 +3597,6 @@ void i915_gem_restore_gtt_mappings(struct drm_i915_private *dev_priv) dev_priv->ppat.update_hw(dev_priv); return; } - - if (USES_PPGTT(dev_priv)) { - struct i915_address_space *vm; - - list_for_each_entry(vm, &dev_priv->vm_list, global_link) { - struct i915_hw_ppgtt *ppgtt; - - if (i915_is_ggtt(vm)) - ppgtt = dev_priv->mm.aliasing_ppgtt; - else - ppgtt = i915_vm_to_ppgtt(vm); - if (!ppgtt) - continue; - - gen6_write_page_range(ppgtt, 0, ppgtt->vm.total); - } - } - - i915_ggtt_invalidate(dev_priv); } static struct scatterlist * diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index 7d65d813eff0b..6e9acd99ecc61 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -410,7 +410,7 @@ struct i915_hw_ppgtt { struct gen6_hw_ppgtt { struct i915_hw_ppgtt base; - struct drm_mm_node node; + struct i915_vma *vma; gen6_pte_t __iomem *pd_addr; }; diff --git a/drivers/gpu/drm/i915/i915_vma.h b/drivers/gpu/drm/i915/i915_vma.h index 4321476a6a329..66a228931517f 100644 --- a/drivers/gpu/drm/i915/i915_vma.h +++ b/drivers/gpu/drm/i915/i915_vma.h @@ -54,6 +54,7 @@ struct i915_vma { struct reservation_object *resv; /** Alias of obj->resv */ struct sg_table *pages; void __iomem *iomap; + void *private; /* owned by creator */ u64 size; u64 display_alignment; struct i915_page_sizes page_sizes; @@ -340,6 +341,12 @@ static inline void i915_vma_unpin(struct i915_vma *vma) __i915_vma_unpin(vma); } +static inline bool i915_vma_is_bound(const struct i915_vma *vma, + unsigned int where) +{ + return vma->flags & where; +} + /** * i915_vma_pin_iomap - calls ioremap_wc to map the GGTT VMA via the aperture * @vma: VMA to iomap -- GitLab From dccc7228b5de7658f79ad0074a57a8798462c533 Mon Sep 17 00:00:00 2001 From: Manasi Navare <manasi.d.navare@intel.com> Date: Mon, 21 May 2018 17:25:41 -0700 Subject: [PATCH 0252/1506] drm/i915/icl: Add DDI HDMI level selection for ICL This patch adds a proper HDMI DDI entry level for vswing programming sequences on ICL. Spec doesn't specify any default for HDMI tables, so let's pick the last entry as the default for now to stay consistent with older platform like CNL. Cc: Rakshmi Bhatia <rakshmi.bhatia@intel.com> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com> Reviewed-by: Lucas De Marchi <lucas.demarchi@intel.com> Signed-off-by: Manasi Navare <manasi.d.navare@intel.com> Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180522002558.29262-8-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/intel_ddi.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index b344e0fe08fd5..ca73387bd5964 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -915,7 +915,14 @@ static int intel_ddi_hdmi_level(struct drm_i915_private *dev_priv, enum port por level = dev_priv->vbt.ddi_port_info[port].hdmi_level_shift; - if (IS_CANNONLAKE(dev_priv)) { + if (IS_ICELAKE(dev_priv)) { + if (port == PORT_A || port == PORT_B) + icl_get_combo_buf_trans(dev_priv, port, + INTEL_OUTPUT_HDMI, &n_entries); + else + n_entries = ARRAY_SIZE(icl_mg_phy_ddi_translations); + default_entry = n_entries - 1; + } else if (IS_CANNONLAKE(dev_priv)) { cnl_get_buf_trans_hdmi(dev_priv, &n_entries); default_entry = n_entries - 1; } else if (IS_GEN9_LP(dev_priv)) { -- GitLab From af1f1b81130e82a1ee62fe48aa09e6bdab6e68f4 Mon Sep 17 00:00:00 2001 From: Mahesh Kumar <mahesh1.kumar@intel.com> Date: Mon, 11 Jun 2018 17:25:11 -0700 Subject: [PATCH 0253/1506] drm/i915/icl: fix gmbus gpio pin mapping ICP has GPIO pin 1/2 mapped to combo-phy ports & GPIO pins 9/10/11/12 mapped to tc ports[1-4]. This patch defines GPIOCTL registers for GPIO pins 9-12 & uses them in GPIO pin mapping table. Cc: Anusha Srivatsa <anusha.srivatsa@intel.com> Cc: Madhav Chauhan <madhav.chauhan@intel.com> Cc: Lucas De Marchi <lucas.demarchi@intel.com> Reviewed-by: Lucas De Marchi <lucas.demarchi@intel.com> Signed-off-by: Mahesh Kumar <mahesh1.kumar@intel.com> Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180612002512.29783-1-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 4 ++++ drivers/gpu/drm/i915/intel_hdmi.c | 2 +- drivers/gpu/drm/i915/intel_i2c.c | 12 ++++++------ 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 987def26ce829..c96a3aec086cc 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2988,6 +2988,10 @@ enum i915_power_well_id { #define GPIOF _MMIO(0x5024) #define GPIOG _MMIO(0x5028) #define GPIOH _MMIO(0x502c) +#define GPIOJ _MMIO(0x5034) +#define GPIOK _MMIO(0x5038) +#define GPIOL _MMIO(0x503C) +#define GPIOM _MMIO(0x5040) # define GPIO_CLOCK_DIR_MASK (1 << 0) # define GPIO_CLOCK_DIR_IN (0 << 1) # define GPIO_CLOCK_DIR_OUT (1 << 1) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index ba5ea61fb7b96..ef4de5a02cb53 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -2234,7 +2234,7 @@ static u8 intel_hdmi_ddc_pin(struct drm_i915_private *dev_priv, ddc_pin = bxt_port_to_ddc_pin(dev_priv, port); else if (HAS_PCH_CNP(dev_priv)) ddc_pin = cnp_port_to_ddc_pin(dev_priv, port); - else if (IS_ICELAKE(dev_priv)) + else if (HAS_PCH_ICP(dev_priv)) ddc_pin = icl_port_to_ddc_pin(dev_priv, port); else ddc_pin = g4x_port_to_ddc_pin(dev_priv, port); diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 61729bf84e087..97606c1be70da 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -77,12 +77,12 @@ static const struct gmbus_pin gmbus_pins_cnp[] = { }; static const struct gmbus_pin gmbus_pins_icp[] = { - [GMBUS_PIN_1_BXT] = { "dpa", GPIOA }, - [GMBUS_PIN_2_BXT] = { "dpb", GPIOB }, - [GMBUS_PIN_9_TC1_ICP] = { "tc1", GPIOC }, - [GMBUS_PIN_10_TC2_ICP] = { "tc2", GPIOD }, - [GMBUS_PIN_11_TC3_ICP] = { "tc3", GPIOE }, - [GMBUS_PIN_12_TC4_ICP] = { "tc4", GPIOF }, + [GMBUS_PIN_1_BXT] = { "dpa", GPIOB }, + [GMBUS_PIN_2_BXT] = { "dpb", GPIOC }, + [GMBUS_PIN_9_TC1_ICP] = { "tc1", GPIOJ }, + [GMBUS_PIN_10_TC2_ICP] = { "tc2", GPIOK }, + [GMBUS_PIN_11_TC3_ICP] = { "tc3", GPIOL }, + [GMBUS_PIN_12_TC4_ICP] = { "tc4", GPIOM }, }; /* pin is expected to be valid */ -- GitLab From bb187e93e48d3a3f1e3c9bcae76c5b13d3529391 Mon Sep 17 00:00:00 2001 From: James Ausmus <james.ausmus@intel.com> Date: Mon, 11 Jun 2018 17:25:12 -0700 Subject: [PATCH 0254/1506] drm/i915/icl: DP_AUX_E is valid on ICL+ Add support for DP_AUX_E. Here we also introduce the bits for the AUX power well E, however ICL power well support is still not enabled yet, so the power well is not used. Cc: Rodrigo Vivi <rodrigo.vivi@intel.com> Cc: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Signed-off-by: James Ausmus <james.ausmus@intel.com> Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180612002512.29783-2-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_irq.c | 6 ++++++ drivers/gpu/drm/i915/i915_reg.h | 8 ++++++++ drivers/gpu/drm/i915/intel_display.h | 3 ++- drivers/gpu/drm/i915/intel_dp.c | 7 +++++++ drivers/gpu/drm/i915/intel_runtime_pm.c | 2 ++ 6 files changed, 26 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6104d71150546..be8c2f0823c46 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1016,6 +1016,7 @@ enum modeset_restore { #define DP_AUX_B 0x10 #define DP_AUX_C 0x20 #define DP_AUX_D 0x30 +#define DP_AUX_E 0x50 #define DP_AUX_F 0x60 #define DDC_PIN_B 0x05 diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 2fd92a8867894..c52060a353176 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2640,6 +2640,9 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl) GEN9_AUX_CHANNEL_C | GEN9_AUX_CHANNEL_D; + if (INTEL_GEN(dev_priv) >= 11) + tmp_mask |= ICL_AUX_CHANNEL_E; + if (IS_CNL_WITH_PORT_F(dev_priv) || INTEL_GEN(dev_priv) >= 11) tmp_mask |= CNL_AUX_CHANNEL_F; @@ -3921,6 +3924,9 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv) de_pipe_masked |= GEN8_DE_PIPE_IRQ_FAULT_ERRORS; } + if (INTEL_GEN(dev_priv) >= 11) + de_port_masked |= ICL_AUX_CHANNEL_E; + if (IS_CNL_WITH_PORT_F(dev_priv) || INTEL_GEN(dev_priv) >= 11) de_port_masked |= CNL_AUX_CHANNEL_F; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index c96a3aec086cc..140f6a27d6962 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -5315,6 +5315,13 @@ enum { #define _DPD_AUX_CH_DATA4 (dev_priv->info.display_mmio_offset + 0x64320) #define _DPD_AUX_CH_DATA5 (dev_priv->info.display_mmio_offset + 0x64324) +#define _DPE_AUX_CH_CTL (dev_priv->info.display_mmio_offset + 0x64410) +#define _DPE_AUX_CH_DATA1 (dev_priv->info.display_mmio_offset + 0x64414) +#define _DPE_AUX_CH_DATA2 (dev_priv->info.display_mmio_offset + 0x64418) +#define _DPE_AUX_CH_DATA3 (dev_priv->info.display_mmio_offset + 0x6441c) +#define _DPE_AUX_CH_DATA4 (dev_priv->info.display_mmio_offset + 0x64420) +#define _DPE_AUX_CH_DATA5 (dev_priv->info.display_mmio_offset + 0x64424) + #define _DPF_AUX_CH_CTL (dev_priv->info.display_mmio_offset + 0x64510) #define _DPF_AUX_CH_DATA1 (dev_priv->info.display_mmio_offset + 0x64514) #define _DPF_AUX_CH_DATA2 (dev_priv->info.display_mmio_offset + 0x64518) @@ -7019,6 +7026,7 @@ enum { #define GEN8_DE_PORT_IMR _MMIO(0x44444) #define GEN8_DE_PORT_IIR _MMIO(0x44448) #define GEN8_DE_PORT_IER _MMIO(0x4444c) +#define ICL_AUX_CHANNEL_E (1 << 29) #define CNL_AUX_CHANNEL_F (1 << 28) #define GEN9_AUX_CHANNEL_D (1 << 27) #define GEN9_AUX_CHANNEL_C (1 << 26) diff --git a/drivers/gpu/drm/i915/intel_display.h b/drivers/gpu/drm/i915/intel_display.h index c88185ed75944..dfb02da73ac86 100644 --- a/drivers/gpu/drm/i915/intel_display.h +++ b/drivers/gpu/drm/i915/intel_display.h @@ -155,7 +155,7 @@ enum aux_ch { AUX_CH_B, AUX_CH_C, AUX_CH_D, - _AUX_CH_E, /* does not exist */ + AUX_CH_E, /* ICL+ */ AUX_CH_F, }; @@ -196,6 +196,7 @@ enum intel_display_power_domain { POWER_DOMAIN_AUX_B, POWER_DOMAIN_AUX_C, POWER_DOMAIN_AUX_D, + POWER_DOMAIN_AUX_E, POWER_DOMAIN_AUX_F, POWER_DOMAIN_AUX_IO_A, POWER_DOMAIN_GMBUS, diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 37b9f62aeb6e8..40ffd91631755 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1347,6 +1347,9 @@ static enum aux_ch intel_aux_ch(struct intel_dp *intel_dp) case DP_AUX_D: aux_ch = AUX_CH_D; break; + case DP_AUX_E: + aux_ch = AUX_CH_E; + break; case DP_AUX_F: aux_ch = AUX_CH_F; break; @@ -1374,6 +1377,8 @@ intel_aux_power_domain(struct intel_dp *intel_dp) return POWER_DOMAIN_AUX_C; case AUX_CH_D: return POWER_DOMAIN_AUX_D; + case AUX_CH_E: + return POWER_DOMAIN_AUX_E; case AUX_CH_F: return POWER_DOMAIN_AUX_F; default: @@ -1460,6 +1465,7 @@ static i915_reg_t skl_aux_ctl_reg(struct intel_dp *intel_dp) case AUX_CH_B: case AUX_CH_C: case AUX_CH_D: + case AUX_CH_E: case AUX_CH_F: return DP_AUX_CH_CTL(aux_ch); default: @@ -1478,6 +1484,7 @@ static i915_reg_t skl_aux_data_reg(struct intel_dp *intel_dp, int index) case AUX_CH_B: case AUX_CH_C: case AUX_CH_D: + case AUX_CH_E: case AUX_CH_F: return DP_AUX_CH_DATA(aux_ch, index); default: diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 53a6eaa9671ab..de3a81034f779 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -128,6 +128,8 @@ intel_display_power_domain_str(enum intel_display_power_domain domain) return "AUX_C"; case POWER_DOMAIN_AUX_D: return "AUX_D"; + case POWER_DOMAIN_AUX_E: + return "AUX_E"; case POWER_DOMAIN_AUX_F: return "AUX_F"; case POWER_DOMAIN_AUX_IO_A: -- GitLab From 2939db9e2879a1f80bcf863ccbd4919b3eef0d91 Mon Sep 17 00:00:00 2001 From: Colin Xu <colin.xu@intel.com> Date: Mon, 11 Jun 2018 15:39:29 +0800 Subject: [PATCH 0255/1506] drm/i915/gvt: Add D_BXT device type define for BXT. Broxton belongs to GEN9 family so add to SKL and GEN9 plus. Signed-off-by: Colin Xu <colin.xu@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> --- drivers/gpu/drm/i915/gvt/handlers.c | 2 ++ drivers/gpu/drm/i915/gvt/mmio.h | 11 ++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c index d60c2bee00fb2..4dfe8ba558490 100644 --- a/drivers/gpu/drm/i915/gvt/handlers.c +++ b/drivers/gpu/drm/i915/gvt/handlers.c @@ -55,6 +55,8 @@ unsigned long intel_gvt_get_device_type(struct intel_gvt *gvt) return D_SKL; else if (IS_KABYLAKE(gvt->dev_priv)) return D_KBL; + else if (IS_BROXTON(gvt->dev_priv)) + return D_BXT; return 0; } diff --git a/drivers/gpu/drm/i915/gvt/mmio.h b/drivers/gpu/drm/i915/gvt/mmio.h index 71b6208759439..e474188b46d25 100644 --- a/drivers/gpu/drm/i915/gvt/mmio.h +++ b/drivers/gpu/drm/i915/gvt/mmio.h @@ -42,15 +42,16 @@ struct intel_vgpu; #define D_BDW (1 << 0) #define D_SKL (1 << 1) #define D_KBL (1 << 2) +#define D_BXT (1 << 3) -#define D_GEN9PLUS (D_SKL | D_KBL) -#define D_GEN8PLUS (D_BDW | D_SKL | D_KBL) +#define D_GEN9PLUS (D_SKL | D_KBL | D_BXT) +#define D_GEN8PLUS (D_BDW | D_SKL | D_KBL | D_BXT) -#define D_SKL_PLUS (D_SKL | D_KBL) -#define D_BDW_PLUS (D_BDW | D_SKL | D_KBL) +#define D_SKL_PLUS (D_SKL | D_KBL | D_BXT) +#define D_BDW_PLUS (D_BDW | D_SKL | D_KBL | D_BXT) #define D_PRE_SKL (D_BDW) -#define D_ALL (D_BDW | D_SKL | D_KBL) +#define D_ALL (D_BDW | D_SKL | D_KBL | D_BXT) typedef int (*gvt_mmio_func)(struct intel_vgpu *, unsigned int, void *, unsigned int); -- GitLab From 02b966c12b49ba6dae627c2135b7c1a258e32303 Mon Sep 17 00:00:00 2001 From: Colin Xu <colin.xu@intel.com> Date: Mon, 11 Jun 2018 15:39:30 +0800 Subject: [PATCH 0256/1506] drm/i915/gvt: Add MEDIA_POOL_STATE for BXT. As referred in PRM for Broxton Graphics on 01.org Signed-off-by: Colin Xu <colin.xu@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> --- drivers/gpu/drm/i915/gvt/cmd_parser.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/gvt/cmd_parser.c b/drivers/gpu/drm/i915/gvt/cmd_parser.c index 718ca08f95751..2b8e6e15e9360 100644 --- a/drivers/gpu/drm/i915/gvt/cmd_parser.c +++ b/drivers/gpu/drm/i915/gvt/cmd_parser.c @@ -172,6 +172,7 @@ struct decode_info { #define OP_MEDIA_INTERFACE_DESCRIPTOR_LOAD OP_3D_MEDIA(0x2, 0x0, 0x2) #define OP_MEDIA_GATEWAY_STATE OP_3D_MEDIA(0x2, 0x0, 0x3) #define OP_MEDIA_STATE_FLUSH OP_3D_MEDIA(0x2, 0x0, 0x4) +#define OP_MEDIA_POOL_STATE OP_3D_MEDIA(0x2, 0x0, 0x5) #define OP_MEDIA_OBJECT OP_3D_MEDIA(0x2, 0x1, 0x0) #define OP_MEDIA_OBJECT_PRT OP_3D_MEDIA(0x2, 0x1, 0x2) @@ -2349,6 +2350,9 @@ static struct cmd_info cmd_info[] = { {"MEDIA_STATE_FLUSH", OP_MEDIA_STATE_FLUSH, F_LEN_VAR, R_RCS, D_ALL, 0, 16, NULL}, + {"MEDIA_POOL_STATE", OP_MEDIA_POOL_STATE, F_LEN_VAR, R_RCS, D_ALL, + 0, 16, NULL}, + {"MEDIA_OBJECT", OP_MEDIA_OBJECT, F_LEN_VAR, R_RCS, D_ALL, 0, 16, NULL}, {"MEDIA_CURBE_LOAD", OP_MEDIA_CURBE_LOAD, F_LEN_VAR, R_RCS, D_ALL, -- GitLab From 6fa6616b8f7adaf8380d72e53733bc2472b0d157 Mon Sep 17 00:00:00 2001 From: Colin Xu <colin.xu@intel.com> Date: Mon, 11 Jun 2018 15:39:31 +0800 Subject: [PATCH 0257/1506] drm/i915/gvt: Enable device info initialization for BXT. Initialize BXT device info as SKL/KBL. v2: All supported platforms share the same device configuration. Remove the platform check by now and let is_supported_device() be the gate keeper. Signed-off-by: Colin Xu <colin.xu@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> --- drivers/gpu/drm/i915/gvt/gvt.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/gvt.c b/drivers/gpu/drm/i915/gvt/gvt.c index 22a3ddff38a3d..4e65266e7b95b 100644 --- a/drivers/gpu/drm/i915/gvt/gvt.c +++ b/drivers/gpu/drm/i915/gvt/gvt.c @@ -238,18 +238,15 @@ static void init_device_info(struct intel_gvt *gvt) struct intel_gvt_device_info *info = &gvt->device_info; struct pci_dev *pdev = gvt->dev_priv->drm.pdev; - if (IS_BROADWELL(gvt->dev_priv) || IS_SKYLAKE(gvt->dev_priv) - || IS_KABYLAKE(gvt->dev_priv)) { - info->max_support_vgpus = 8; - info->cfg_space_size = PCI_CFG_SPACE_EXP_SIZE; - info->mmio_size = 2 * 1024 * 1024; - info->mmio_bar = 0; - info->gtt_start_offset = 8 * 1024 * 1024; - info->gtt_entry_size = 8; - info->gtt_entry_size_shift = 3; - info->gmadr_bytes_in_cmd = 8; - info->max_surface_size = 36 * 1024 * 1024; - } + info->max_support_vgpus = 8; + info->cfg_space_size = PCI_CFG_SPACE_EXP_SIZE; + info->mmio_size = 2 * 1024 * 1024; + info->mmio_bar = 0; + info->gtt_start_offset = 8 * 1024 * 1024; + info->gtt_entry_size = 8; + info->gtt_entry_size_shift = 3; + info->gmadr_bytes_in_cmd = 8; + info->max_surface_size = 36 * 1024 * 1024; info->msi_cap_offset = pdev->msi_cap; } -- GitLab From 665004b8f50612d1e354eb9abd6d97e6eb85a619 Mon Sep 17 00:00:00 2001 From: Colin Xu <colin.xu@intel.com> Date: Mon, 11 Jun 2018 15:39:32 +0800 Subject: [PATCH 0258/1506] drm/i915/gvt: Enable gtt initialization for BXT. Initialize BXT gtt as SKL/KBL. v2: All supported platforms share the same gtt ops. Remove the platform check by now and let is_supported_device() be the gate keeper. Signed-off-by: Colin Xu <colin.xu@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> --- drivers/gpu/drm/i915/gvt/gtt.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/gtt.c b/drivers/gpu/drm/i915/gvt/gtt.c index 49400ab129ffa..6a8a9868bcfb9 100644 --- a/drivers/gpu/drm/i915/gvt/gtt.c +++ b/drivers/gpu/drm/i915/gvt/gtt.c @@ -2256,13 +2256,8 @@ int intel_gvt_init_gtt(struct intel_gvt *gvt) gvt_dbg_core("init gtt\n"); - if (IS_BROADWELL(gvt->dev_priv) || IS_SKYLAKE(gvt->dev_priv) - || IS_KABYLAKE(gvt->dev_priv)) { - gvt->gtt.pte_ops = &gen8_gtt_pte_ops; - gvt->gtt.gma_ops = &gen8_gtt_gma_ops; - } else { - return -ENODEV; - } + gvt->gtt.pte_ops = &gen8_gtt_pte_ops; + gvt->gtt.gma_ops = &gen8_gtt_gma_ops; page = (void *)get_zeroed_page(GFP_KERNEL); if (!page) { -- GitLab From d0f827bb18fe2ceb39707718334b636b89be4af0 Mon Sep 17 00:00:00 2001 From: Colin Xu <colin.xu@intel.com> Date: Mon, 11 Jun 2018 15:39:33 +0800 Subject: [PATCH 0259/1506] drm/i915/gvt: Enable irq initialization for BXT. Initialize BXT irq handler as SKL/KBL. v2: All supported platforms share the same irq ops and map. Remove the platform check by now and let is_supported_device() be the gate keeper. Signed-off-by: Colin Xu <colin.xu@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> --- drivers/gpu/drm/i915/gvt/interrupt.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/interrupt.c b/drivers/gpu/drm/i915/gvt/interrupt.c index 1d79596da510e..5daa23ae566b0 100644 --- a/drivers/gpu/drm/i915/gvt/interrupt.c +++ b/drivers/gpu/drm/i915/gvt/interrupt.c @@ -581,7 +581,9 @@ static void gen8_init_irq( SET_BIT_INFO(irq, 4, PRIMARY_C_FLIP_DONE, INTEL_GVT_IRQ_INFO_DE_PIPE_C); SET_BIT_INFO(irq, 5, SPRITE_C_FLIP_DONE, INTEL_GVT_IRQ_INFO_DE_PIPE_C); - } else if (IS_SKYLAKE(gvt->dev_priv) || IS_KABYLAKE(gvt->dev_priv)) { + } else if (IS_SKYLAKE(gvt->dev_priv) + || IS_KABYLAKE(gvt->dev_priv) + || IS_BROXTON(gvt->dev_priv)) { SET_BIT_INFO(irq, 25, AUX_CHANNEL_B, INTEL_GVT_IRQ_INFO_DE_PORT); SET_BIT_INFO(irq, 26, AUX_CHANNEL_C, INTEL_GVT_IRQ_INFO_DE_PORT); SET_BIT_INFO(irq, 27, AUX_CHANNEL_D, INTEL_GVT_IRQ_INFO_DE_PORT); @@ -691,14 +693,8 @@ int intel_gvt_init_irq(struct intel_gvt *gvt) gvt_dbg_core("init irq framework\n"); - if (IS_BROADWELL(gvt->dev_priv) || IS_SKYLAKE(gvt->dev_priv) - || IS_KABYLAKE(gvt->dev_priv)) { - irq->ops = &gen8_irq_ops; - irq->irq_map = gen8_irq_map; - } else { - WARN_ON(1); - return -ENODEV; - } + irq->ops = &gen8_irq_ops; + irq->irq_map = gen8_irq_map; /* common event initialization */ init_events(irq); -- GitLab From a94cf2e0ef7fef5cb42ed96f73c18c3ad4f0d170 Mon Sep 17 00:00:00 2001 From: Colin Xu <colin.xu@intel.com> Date: Mon, 11 Jun 2018 15:39:34 +0800 Subject: [PATCH 0260/1506] drm/i915/gvt: Enable mmio context init and switch for BXT. Handle pending tlb flush, mocs/mmio switch and context as KBL. Signed-off-by: Colin Xu <colin.xu@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> --- drivers/gpu/drm/i915/gvt/mmio_context.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/mmio_context.c b/drivers/gpu/drm/i915/gvt/mmio_context.c index 708170e61625a..20be9a92600f0 100644 --- a/drivers/gpu/drm/i915/gvt/mmio_context.c +++ b/drivers/gpu/drm/i915/gvt/mmio_context.c @@ -364,7 +364,8 @@ static void handle_tlb_pending_event(struct intel_vgpu *vgpu, int ring_id) */ fw = intel_uncore_forcewake_for_reg(dev_priv, reg, FW_REG_READ | FW_REG_WRITE); - if (ring_id == RCS && (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))) + if (ring_id == RCS && (IS_SKYLAKE(dev_priv) || + IS_KABYLAKE(dev_priv) || IS_BROXTON(dev_priv))) fw |= FORCEWAKE_RENDER; intel_uncore_forcewake_get(dev_priv, fw); @@ -401,7 +402,7 @@ static void switch_mocs(struct intel_vgpu *pre, struct intel_vgpu *next, if (WARN_ON(ring_id >= ARRAY_SIZE(regs))) return; - if (IS_KABYLAKE(dev_priv) && ring_id == RCS) + if ((IS_KABYLAKE(dev_priv) || IS_BROXTON(dev_priv)) && ring_id == RCS) return; if (!pre && !gen9_render_mocs.initialized) @@ -467,7 +468,9 @@ static void switch_mmio(struct intel_vgpu *pre, u32 old_v, new_v; dev_priv = pre ? pre->gvt->dev_priv : next->gvt->dev_priv; - if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) + if (IS_SKYLAKE(dev_priv) + || IS_KABYLAKE(dev_priv) + || IS_BROXTON(dev_priv)) switch_mocs(pre, next, ring_id); for (mmio = dev_priv->gvt->engine_mmio_list.mmio; @@ -479,7 +482,8 @@ static void switch_mmio(struct intel_vgpu *pre, * state image on kabylake, it's initialized by lri command and * save or restore with context together. */ - if (IS_KABYLAKE(dev_priv) && mmio->in_context) + if ((IS_KABYLAKE(dev_priv) || IS_BROXTON(dev_priv)) + && mmio->in_context) continue; // save @@ -574,7 +578,9 @@ void intel_gvt_init_engine_mmio_context(struct intel_gvt *gvt) { struct engine_mmio *mmio; - if (IS_SKYLAKE(gvt->dev_priv) || IS_KABYLAKE(gvt->dev_priv)) + if (IS_SKYLAKE(gvt->dev_priv) || + IS_KABYLAKE(gvt->dev_priv) || + IS_BROXTON(gvt->dev_priv)) gvt->engine_mmio_list.mmio = gen9_engine_mmio_list; else gvt->engine_mmio_list.mmio = gen8_engine_mmio_list; -- GitLab From f093f182ace9ce3c618c110e316cc1e22d0c9d3b Mon Sep 17 00:00:00 2001 From: Colin Xu <colin.xu@intel.com> Date: Mon, 11 Jun 2018 15:39:35 +0800 Subject: [PATCH 0261/1506] drm/i915/gvt: Enable cmd_parser support for BXT. Handle BXT cmd_parser as SKL/KBL. v2: All supported platforms share the same routines. Remove the platform check by now and let is_supported_device() be the gate keeper. Signed-off-by: Colin Xu <colin.xu@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> --- drivers/gpu/drm/i915/gvt/cmd_parser.c | 39 ++++++++++----------------- 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/cmd_parser.c b/drivers/gpu/drm/i915/gvt/cmd_parser.c index 2b8e6e15e9360..0dd88fe2e39a3 100644 --- a/drivers/gpu/drm/i915/gvt/cmd_parser.c +++ b/drivers/gpu/drm/i915/gvt/cmd_parser.c @@ -1257,7 +1257,9 @@ static int gen8_check_mi_display_flip(struct parser_exec_state *s, if (!info->async_flip) return 0; - if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) { + if (IS_SKYLAKE(dev_priv) + || IS_KABYLAKE(dev_priv) + || IS_BROXTON(dev_priv)) { stride = vgpu_vreg_t(s->vgpu, info->stride_reg) & GENMASK(9, 0); tile = (vgpu_vreg_t(s->vgpu, info->ctrl_reg) & GENMASK(12, 10)) >> 10; @@ -1285,7 +1287,9 @@ static int gen8_update_plane_mmio_from_mi_display_flip( set_mask_bits(&vgpu_vreg_t(vgpu, info->surf_reg), GENMASK(31, 12), info->surf_val << 12); - if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) { + if (IS_SKYLAKE(dev_priv) + || IS_KABYLAKE(dev_priv) + || IS_BROXTON(dev_priv)) { set_mask_bits(&vgpu_vreg_t(vgpu, info->stride_reg), GENMASK(9, 0), info->stride_val); set_mask_bits(&vgpu_vreg_t(vgpu, info->ctrl_reg), GENMASK(12, 10), @@ -1309,7 +1313,9 @@ static int decode_mi_display_flip(struct parser_exec_state *s, if (IS_BROADWELL(dev_priv)) return gen8_decode_mi_display_flip(s, info); - if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) + if (IS_SKYLAKE(dev_priv) + || IS_KABYLAKE(dev_priv) + || IS_BROXTON(dev_priv)) return skl_decode_mi_display_flip(s, info); return -ENODEV; @@ -1318,26 +1324,14 @@ static int decode_mi_display_flip(struct parser_exec_state *s, static int check_mi_display_flip(struct parser_exec_state *s, struct mi_display_flip_command_info *info) { - struct drm_i915_private *dev_priv = s->vgpu->gvt->dev_priv; - - if (IS_BROADWELL(dev_priv) - || IS_SKYLAKE(dev_priv) - || IS_KABYLAKE(dev_priv)) - return gen8_check_mi_display_flip(s, info); - return -ENODEV; + return gen8_check_mi_display_flip(s, info); } static int update_plane_mmio_from_mi_display_flip( struct parser_exec_state *s, struct mi_display_flip_command_info *info) { - struct drm_i915_private *dev_priv = s->vgpu->gvt->dev_priv; - - if (IS_BROADWELL(dev_priv) - || IS_SKYLAKE(dev_priv) - || IS_KABYLAKE(dev_priv)) - return gen8_update_plane_mmio_from_mi_display_flip(s, info); - return -ENODEV; + return gen8_update_plane_mmio_from_mi_display_flip(s, info); } static int cmd_handler_mi_display_flip(struct parser_exec_state *s) @@ -1616,15 +1610,10 @@ static int copy_gma_to_hva(struct intel_vgpu *vgpu, struct intel_vgpu_mm *mm, */ static int batch_buffer_needs_scan(struct parser_exec_state *s) { - struct intel_gvt *gvt = s->vgpu->gvt; - - if (IS_BROADWELL(gvt->dev_priv) || IS_SKYLAKE(gvt->dev_priv) - || IS_KABYLAKE(gvt->dev_priv)) { - /* BDW decides privilege based on address space */ - if (cmd_val(s, 0) & (1 << 8) && + /* Decide privilege based on address space */ + if (cmd_val(s, 0) & (1 << 8) && !(s->vgpu->scan_nonprivbb & (1 << s->ring_id))) - return 0; - } + return 0; return 1; } -- GitLab From 47d9d3be5925688dfcc7407b0ae70013ba2dce2e Mon Sep 17 00:00:00 2001 From: Colin Xu <colin.xu@intel.com> Date: Mon, 11 Jun 2018 15:39:36 +0800 Subject: [PATCH 0262/1506] drm/i915/gvt: Enable force wake support for BXT. BXT forcewake is handled in the same way as SKL/KBL. v2: Add missing inhibit_context restore for BXT. Signed-off-by: Colin Xu <colin.xu@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> --- drivers/gpu/drm/i915/gvt/scheduler.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/scheduler.c b/drivers/gpu/drm/i915/gvt/scheduler.c index 462cf560492e3..928818f218f7f 100644 --- a/drivers/gpu/drm/i915/gvt/scheduler.c +++ b/drivers/gpu/drm/i915/gvt/scheduler.c @@ -297,7 +297,8 @@ static int copy_workload_to_ring_buffer(struct intel_vgpu_workload *workload) void *shadow_ring_buffer_va; u32 *cs; - if (IS_KABYLAKE(req->i915) && is_inhibit_context(req->hw_context)) + if ((IS_KABYLAKE(req->i915) || IS_BROXTON(req->i915)) + && is_inhibit_context(req->hw_context)) intel_vgpu_restore_inhibit_context(vgpu, req); /* allocate shadow ring buffer */ @@ -904,7 +905,8 @@ static int workload_thread(void *priv) struct intel_vgpu *vgpu = NULL; int ret; bool need_force_wake = IS_SKYLAKE(gvt->dev_priv) - || IS_KABYLAKE(gvt->dev_priv); + || IS_KABYLAKE(gvt->dev_priv) + || IS_BROXTON(gvt->dev_priv); DEFINE_WAIT_FUNC(wait, woken_wake_function); kfree(p); -- GitLab From 72bad9972876933b3c428fcee122bb1dcbf8cf5a Mon Sep 17 00:00:00 2001 From: Colin Xu <colin.xu@intel.com> Date: Mon, 11 Jun 2018 15:39:37 +0800 Subject: [PATCH 0263/1506] drm/i915/gvt: Enable virtual display support for BXT. Virtual monitor on BXT start from port B. Unlike SKL/KBL, digital display port connectivity is detected via GEN8_DE_PORT_ISR so emulate monitor state change by setting it. Signed-off-by: Colin Xu <colin.xu@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> --- drivers/gpu/drm/i915/gvt/display.c | 23 +++++++++++++++++++++++ drivers/gpu/drm/i915/gvt/edid.c | 20 +++++++++++++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gvt/display.c b/drivers/gpu/drm/i915/gvt/display.c index 38521fa81bf9d..6ee50cb328f8e 100644 --- a/drivers/gpu/drm/i915/gvt/display.c +++ b/drivers/gpu/drm/i915/gvt/display.c @@ -171,6 +171,29 @@ static void emulate_monitor_status_change(struct intel_vgpu *vgpu) struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv; int pipe; + if (IS_BROXTON(dev_priv)) { + vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) &= ~(BXT_DE_PORT_HP_DDIA | + BXT_DE_PORT_HP_DDIB | + BXT_DE_PORT_HP_DDIC); + + if (intel_vgpu_has_monitor_on_port(vgpu, PORT_A)) { + vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) |= + BXT_DE_PORT_HP_DDIA; + } + + if (intel_vgpu_has_monitor_on_port(vgpu, PORT_B)) { + vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) |= + BXT_DE_PORT_HP_DDIB; + } + + if (intel_vgpu_has_monitor_on_port(vgpu, PORT_C)) { + vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) |= + BXT_DE_PORT_HP_DDIC; + } + + return; + } + vgpu_vreg_t(vgpu, SDEISR) &= ~(SDE_PORTB_HOTPLUG_CPT | SDE_PORTC_HOTPLUG_CPT | SDE_PORTD_HOTPLUG_CPT); diff --git a/drivers/gpu/drm/i915/gvt/edid.c b/drivers/gpu/drm/i915/gvt/edid.c index f61337632969d..4b98539025c5b 100644 --- a/drivers/gpu/drm/i915/gvt/edid.c +++ b/drivers/gpu/drm/i915/gvt/edid.c @@ -77,6 +77,20 @@ static unsigned char edid_get_byte(struct intel_vgpu *vgpu) return chr; } +static inline int bxt_get_port_from_gmbus0(u32 gmbus0) +{ + int port_select = gmbus0 & _GMBUS_PIN_SEL_MASK; + int port = -EINVAL; + + if (port_select == 1) + port = PORT_B; + else if (port_select == 2) + port = PORT_C; + else if (port_select == 3) + port = PORT_D; + return port; +} + static inline int get_port_from_gmbus0(u32 gmbus0) { int port_select = gmbus0 & _GMBUS_PIN_SEL_MASK; @@ -105,6 +119,7 @@ static void reset_gmbus_controller(struct intel_vgpu *vgpu) static int gmbus0_mmio_write(struct intel_vgpu *vgpu, unsigned int offset, void *p_data, unsigned int bytes) { + struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv; int port, pin_select; memcpy(&vgpu_vreg(vgpu, offset), p_data, bytes); @@ -116,7 +131,10 @@ static int gmbus0_mmio_write(struct intel_vgpu *vgpu, if (pin_select == 0) return 0; - port = get_port_from_gmbus0(pin_select); + if (IS_BROXTON(dev_priv)) + port = bxt_get_port_from_gmbus0(pin_select); + else + port = get_port_from_gmbus0(pin_select); if (WARN_ON(port < 0)) return 0; -- GitLab From 84eb04f6d77a824b33da11a08118ed2766038f13 Mon Sep 17 00:00:00 2001 From: Colin Xu <colin.xu@intel.com> Date: Mon, 11 Jun 2018 15:39:38 +0800 Subject: [PATCH 0264/1506] drm/i915/gvt: Enable dma_buf support for BXT. Handle dma_buf on BXT as SKL and KBL. Signed-off-by: Colin Xu <colin.xu@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> --- drivers/gpu/drm/i915/gvt/dmabuf.c | 4 +++- drivers/gpu/drm/i915/gvt/fb_decoder.c | 12 +++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/dmabuf.c b/drivers/gpu/drm/i915/gvt/dmabuf.c index d2eb2f7754b9f..6e3f56684f4ec 100644 --- a/drivers/gpu/drm/i915/gvt/dmabuf.c +++ b/drivers/gpu/drm/i915/gvt/dmabuf.c @@ -164,7 +164,9 @@ static struct drm_i915_gem_object *vgpu_create_gem(struct drm_device *dev, obj->read_domains = I915_GEM_DOMAIN_GTT; obj->write_domain = 0; - if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) { + if (IS_SKYLAKE(dev_priv) + || IS_KABYLAKE(dev_priv) + || IS_BROXTON(dev_priv)) { unsigned int tiling_mode = 0; unsigned int stride = 0; diff --git a/drivers/gpu/drm/i915/gvt/fb_decoder.c b/drivers/gpu/drm/i915/gvt/fb_decoder.c index 20b502c44eae1..face664be3e8e 100644 --- a/drivers/gpu/drm/i915/gvt/fb_decoder.c +++ b/drivers/gpu/drm/i915/gvt/fb_decoder.c @@ -151,7 +151,9 @@ static u32 intel_vgpu_get_stride(struct intel_vgpu *vgpu, int pipe, u32 stride_reg = vgpu_vreg_t(vgpu, DSPSTRIDE(pipe)) & stride_mask; u32 stride = stride_reg; - if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) { + if (IS_SKYLAKE(dev_priv) + || IS_KABYLAKE(dev_priv) + || IS_BROXTON(dev_priv)) { switch (tiled) { case PLANE_CTL_TILED_LINEAR: stride = stride_reg * 64; @@ -215,7 +217,9 @@ int intel_vgpu_decode_primary_plane(struct intel_vgpu *vgpu, if (!plane->enabled) return -ENODEV; - if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) { + if (IS_SKYLAKE(dev_priv) + || IS_KABYLAKE(dev_priv) + || IS_BROXTON(dev_priv)) { plane->tiled = (val & PLANE_CTL_TILED_MASK) >> _PLANE_CTL_TILED_SHIFT; fmt = skl_format_to_drm( @@ -257,7 +261,9 @@ int intel_vgpu_decode_primary_plane(struct intel_vgpu *vgpu, } plane->stride = intel_vgpu_get_stride(vgpu, pipe, (plane->tiled << 10), - (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) ? + (IS_SKYLAKE(dev_priv) + || IS_KABYLAKE(dev_priv) + || IS_BROXTON(dev_priv)) ? (_PRI_PLANE_STRIDE_MASK >> 6) : _PRI_PLANE_STRIDE_MASK, plane->bpp); -- GitLab From d71cb7129e7cf038ed1444781a50766e486bb2bd Mon Sep 17 00:00:00 2001 From: Colin Xu <colin.xu@intel.com> Date: Mon, 11 Jun 2018 15:39:39 +0800 Subject: [PATCH 0265/1506] drm/i915/gvt: Add mmio handler for for BXT. Leverage most SKL/KBL mmio init info and add different mmio to BXT specific function init_bxt_mmio_info(). Signed-off-by: Colin Xu <colin.xu@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> --- drivers/gpu/drm/i915/gvt/handlers.c | 389 ++++++++++++++++++++++++---- 1 file changed, 344 insertions(+), 45 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c index 4dfe8ba558490..0bc0c5418adb8 100644 --- a/drivers/gpu/drm/i915/gvt/handlers.c +++ b/drivers/gpu/drm/i915/gvt/handlers.c @@ -257,7 +257,8 @@ static int mul_force_wake_write(struct intel_vgpu *vgpu, new = CALC_MODE_MASK_REG(old, *(u32 *)p_data); if (IS_SKYLAKE(vgpu->gvt->dev_priv) - || IS_KABYLAKE(vgpu->gvt->dev_priv)) { + || IS_KABYLAKE(vgpu->gvt->dev_priv) + || IS_BROXTON(vgpu->gvt->dev_priv)) { switch (offset) { case FORCEWAKE_RENDER_GEN9_REG: ack_reg_offset = FORCEWAKE_ACK_RENDER_GEN9_REG; @@ -863,7 +864,8 @@ static int dp_aux_ch_ctl_mmio_write(struct intel_vgpu *vgpu, data = vgpu_vreg(vgpu, offset); if ((IS_SKYLAKE(vgpu->gvt->dev_priv) - || IS_KABYLAKE(vgpu->gvt->dev_priv)) + || IS_KABYLAKE(vgpu->gvt->dev_priv) + || IS_BROXTON(vgpu->gvt->dev_priv)) && offset != _REG_SKL_DP_AUX_CH_CTL(port_index)) { /* SKL DPB/C/D aux ctl register changed */ return 0; @@ -1370,6 +1372,16 @@ static int mailbox_write(struct intel_vgpu *vgpu, unsigned int offset, *data0 = 0x1e1a1100; else *data0 = 0x61514b3d; + } else if (IS_BROXTON(vgpu->gvt->dev_priv)) { + /** + * "Read memory latency" command on gen9. + * Below memory latency values are read + * from Broxton MRB. + */ + if (!*data0) + *data0 = 0x16080707; + else + *data0 = 0x16161616; } break; case SKL_PCODE_CDCLK_CONTROL: @@ -1427,8 +1439,11 @@ static int skl_power_well_ctl_write(struct intel_vgpu *vgpu, { u32 v = *(u32 *)p_data; - v &= (1 << 31) | (1 << 29) | (1 << 9) | - (1 << 7) | (1 << 5) | (1 << 3) | (1 << 1); + if (IS_BROXTON(vgpu->gvt->dev_priv)) + v &= (1 << 31) | (1 << 29); + else + v &= (1 << 31) | (1 << 29) | (1 << 9) | + (1 << 7) | (1 << 5) | (1 << 3) | (1 << 1); v |= (v >> 1); return intel_vgpu_default_mmio_write(vgpu, offset, &v, bytes); @@ -1448,6 +1463,102 @@ static int skl_lcpll_write(struct intel_vgpu *vgpu, unsigned int offset, return 0; } +static int bxt_de_pll_enable_write(struct intel_vgpu *vgpu, + unsigned int offset, void *p_data, unsigned int bytes) +{ + u32 v = *(u32 *)p_data; + + if (v & BXT_DE_PLL_PLL_ENABLE) + v |= BXT_DE_PLL_LOCK; + + vgpu_vreg(vgpu, offset) = v; + + return 0; +} + +static int bxt_port_pll_enable_write(struct intel_vgpu *vgpu, + unsigned int offset, void *p_data, unsigned int bytes) +{ + u32 v = *(u32 *)p_data; + + if (v & PORT_PLL_ENABLE) + v |= PORT_PLL_LOCK; + + vgpu_vreg(vgpu, offset) = v; + + return 0; +} + +static int bxt_phy_ctl_family_write(struct intel_vgpu *vgpu, + unsigned int offset, void *p_data, unsigned int bytes) +{ + u32 v = *(u32 *)p_data; + u32 data = v & COMMON_RESET_DIS ? BXT_PHY_LANE_ENABLED : 0; + + vgpu_vreg(vgpu, _BXT_PHY_CTL_DDI_A) = data; + vgpu_vreg(vgpu, _BXT_PHY_CTL_DDI_B) = data; + vgpu_vreg(vgpu, _BXT_PHY_CTL_DDI_C) = data; + + vgpu_vreg(vgpu, offset) = v; + + return 0; +} + +static int bxt_port_tx_dw3_read(struct intel_vgpu *vgpu, + unsigned int offset, void *p_data, unsigned int bytes) +{ + u32 v = vgpu_vreg(vgpu, offset); + + v &= ~UNIQUE_TRANGE_EN_METHOD; + + vgpu_vreg(vgpu, offset) = v; + + return intel_vgpu_default_mmio_read(vgpu, offset, p_data, bytes); +} + +static int bxt_pcs_dw12_grp_write(struct intel_vgpu *vgpu, + unsigned int offset, void *p_data, unsigned int bytes) +{ + u32 v = *(u32 *)p_data; + + if (offset == _PORT_PCS_DW12_GRP_A || offset == _PORT_PCS_DW12_GRP_B) { + vgpu_vreg(vgpu, offset - 0x600) = v; + vgpu_vreg(vgpu, offset - 0x800) = v; + } else { + vgpu_vreg(vgpu, offset - 0x400) = v; + vgpu_vreg(vgpu, offset - 0x600) = v; + } + + vgpu_vreg(vgpu, offset) = v; + + return 0; +} + +static int bxt_gt_disp_pwron_write(struct intel_vgpu *vgpu, + unsigned int offset, void *p_data, unsigned int bytes) +{ + u32 v = *(u32 *)p_data; + + if (v & BIT(0)) { + vgpu_vreg_t(vgpu, BXT_PORT_CL1CM_DW0(DPIO_PHY0)) &= + ~PHY_RESERVED; + vgpu_vreg_t(vgpu, BXT_PORT_CL1CM_DW0(DPIO_PHY0)) |= + PHY_POWER_GOOD; + } + + if (v & BIT(1)) { + vgpu_vreg_t(vgpu, BXT_PORT_CL1CM_DW0(DPIO_PHY1)) &= + ~PHY_RESERVED; + vgpu_vreg_t(vgpu, BXT_PORT_CL1CM_DW0(DPIO_PHY1)) |= + PHY_POWER_GOOD; + } + + + vgpu_vreg(vgpu, offset) = v; + + return 0; +} + static int mmio_read_from_hw(struct intel_vgpu *vgpu, unsigned int offset, void *p_data, unsigned int bytes) { @@ -2671,17 +2782,17 @@ static int init_skl_mmio_info(struct intel_gvt *gvt) MMIO_D(_MMIO(0x45504), D_SKL_PLUS); MMIO_D(_MMIO(0x45520), D_SKL_PLUS); MMIO_D(_MMIO(0x46000), D_SKL_PLUS); - MMIO_DH(_MMIO(0x46010), D_SKL | D_KBL, NULL, skl_lcpll_write); - MMIO_DH(_MMIO(0x46014), D_SKL | D_KBL, NULL, skl_lcpll_write); - MMIO_D(_MMIO(0x6C040), D_SKL | D_KBL); - MMIO_D(_MMIO(0x6C048), D_SKL | D_KBL); - MMIO_D(_MMIO(0x6C050), D_SKL | D_KBL); - MMIO_D(_MMIO(0x6C044), D_SKL | D_KBL); - MMIO_D(_MMIO(0x6C04C), D_SKL | D_KBL); - MMIO_D(_MMIO(0x6C054), D_SKL | D_KBL); - MMIO_D(_MMIO(0x6c058), D_SKL | D_KBL); - MMIO_D(_MMIO(0x6c05c), D_SKL | D_KBL); - MMIO_DH(_MMIO(0x6c060), D_SKL | D_KBL, dpll_status_read, NULL); + MMIO_DH(_MMIO(0x46010), D_SKL_PLUS, NULL, skl_lcpll_write); + MMIO_DH(_MMIO(0x46014), D_SKL_PLUS, NULL, skl_lcpll_write); + MMIO_D(_MMIO(0x6C040), D_SKL_PLUS); + MMIO_D(_MMIO(0x6C048), D_SKL_PLUS); + MMIO_D(_MMIO(0x6C050), D_SKL_PLUS); + MMIO_D(_MMIO(0x6C044), D_SKL_PLUS); + MMIO_D(_MMIO(0x6C04C), D_SKL_PLUS); + MMIO_D(_MMIO(0x6C054), D_SKL_PLUS); + MMIO_D(_MMIO(0x6c058), D_SKL_PLUS); + MMIO_D(_MMIO(0x6c05c), D_SKL_PLUS); + MMIO_DH(_MMIO(0x6c060), D_SKL_PLUS, dpll_status_read, NULL); MMIO_DH(SKL_PS_WIN_POS(PIPE_A, 0), D_SKL_PLUS, NULL, pf_write); MMIO_DH(SKL_PS_WIN_POS(PIPE_A, 1), D_SKL_PLUS, NULL, pf_write); @@ -2806,53 +2917,57 @@ static int init_skl_mmio_info(struct intel_gvt *gvt) MMIO_D(_MMIO(0x7239c), D_SKL_PLUS); MMIO_D(_MMIO(0x7039c), D_SKL_PLUS); - MMIO_D(_MMIO(0x8f074), D_SKL | D_KBL); - MMIO_D(_MMIO(0x8f004), D_SKL | D_KBL); - MMIO_D(_MMIO(0x8f034), D_SKL | D_KBL); + MMIO_D(_MMIO(0x8f074), D_SKL_PLUS); + MMIO_D(_MMIO(0x8f004), D_SKL_PLUS); + MMIO_D(_MMIO(0x8f034), D_SKL_PLUS); - MMIO_D(_MMIO(0xb11c), D_SKL | D_KBL); + MMIO_D(_MMIO(0xb11c), D_SKL_PLUS); - MMIO_D(_MMIO(0x51000), D_SKL | D_KBL); + MMIO_D(_MMIO(0x51000), D_SKL_PLUS); MMIO_D(_MMIO(0x6c00c), D_SKL_PLUS); - MMIO_F(_MMIO(0xc800), 0x7f8, F_CMD_ACCESS, 0, 0, D_SKL | D_KBL, NULL, NULL); - MMIO_F(_MMIO(0xb020), 0x80, F_CMD_ACCESS, 0, 0, D_SKL | D_KBL, NULL, NULL); + MMIO_F(_MMIO(0xc800), 0x7f8, F_CMD_ACCESS, 0, 0, D_SKL_PLUS, + NULL, NULL); + MMIO_F(_MMIO(0xb020), 0x80, F_CMD_ACCESS, 0, 0, D_SKL_PLUS, + NULL, NULL); MMIO_D(RPM_CONFIG0, D_SKL_PLUS); MMIO_D(_MMIO(0xd08), D_SKL_PLUS); MMIO_D(RC6_LOCATION, D_SKL_PLUS); MMIO_DFH(_MMIO(0x20e0), D_SKL_PLUS, F_MODE_MASK, NULL, NULL); - MMIO_DFH(_MMIO(0x20ec), D_SKL_PLUS, F_MODE_MASK | F_CMD_ACCESS, NULL, NULL); + MMIO_DFH(_MMIO(0x20ec), D_SKL_PLUS, F_MODE_MASK | F_CMD_ACCESS, + NULL, NULL); /* TRTT */ - MMIO_DFH(_MMIO(0x4de0), D_SKL | D_KBL, F_CMD_ACCESS, NULL, NULL); - MMIO_DFH(_MMIO(0x4de4), D_SKL | D_KBL, F_CMD_ACCESS, NULL, NULL); - MMIO_DFH(_MMIO(0x4de8), D_SKL | D_KBL, F_CMD_ACCESS, NULL, NULL); - MMIO_DFH(_MMIO(0x4dec), D_SKL | D_KBL, F_CMD_ACCESS, NULL, NULL); - MMIO_DFH(_MMIO(0x4df0), D_SKL | D_KBL, F_CMD_ACCESS, NULL, NULL); - MMIO_DFH(_MMIO(0x4df4), D_SKL | D_KBL, F_CMD_ACCESS, NULL, gen9_trtte_write); - MMIO_DH(_MMIO(0x4dfc), D_SKL | D_KBL, NULL, gen9_trtt_chicken_write); + MMIO_DFH(_MMIO(0x4de0), D_SKL_PLUS, F_CMD_ACCESS, NULL, NULL); + MMIO_DFH(_MMIO(0x4de4), D_SKL_PLUS, F_CMD_ACCESS, NULL, NULL); + MMIO_DFH(_MMIO(0x4de8), D_SKL_PLUS, F_CMD_ACCESS, NULL, NULL); + MMIO_DFH(_MMIO(0x4dec), D_SKL_PLUS, F_CMD_ACCESS, NULL, NULL); + MMIO_DFH(_MMIO(0x4df0), D_SKL_PLUS, F_CMD_ACCESS, NULL, NULL); + MMIO_DFH(_MMIO(0x4df4), D_SKL_PLUS, F_CMD_ACCESS, + NULL, gen9_trtte_write); + MMIO_DH(_MMIO(0x4dfc), D_SKL_PLUS, NULL, gen9_trtt_chicken_write); - MMIO_D(_MMIO(0x45008), D_SKL | D_KBL); + MMIO_D(_MMIO(0x45008), D_SKL_PLUS); - MMIO_D(_MMIO(0x46430), D_SKL | D_KBL); + MMIO_D(_MMIO(0x46430), D_SKL_PLUS); - MMIO_D(_MMIO(0x46520), D_SKL | D_KBL); + MMIO_D(_MMIO(0x46520), D_SKL_PLUS); - MMIO_D(_MMIO(0xc403c), D_SKL | D_KBL); + MMIO_D(_MMIO(0xc403c), D_SKL_PLUS); MMIO_D(_MMIO(0xb004), D_SKL_PLUS); MMIO_DH(DMA_CTRL, D_SKL_PLUS, NULL, dma_ctrl_write); MMIO_D(_MMIO(0x65900), D_SKL_PLUS); - MMIO_D(_MMIO(0x1082c0), D_SKL | D_KBL); - MMIO_D(_MMIO(0x4068), D_SKL | D_KBL); - MMIO_D(_MMIO(0x67054), D_SKL | D_KBL); - MMIO_D(_MMIO(0x6e560), D_SKL | D_KBL); - MMIO_D(_MMIO(0x6e554), D_SKL | D_KBL); - MMIO_D(_MMIO(0x2b20), D_SKL | D_KBL); - MMIO_D(_MMIO(0x65f00), D_SKL | D_KBL); - MMIO_D(_MMIO(0x65f08), D_SKL | D_KBL); - MMIO_D(_MMIO(0x320f0), D_SKL | D_KBL); + MMIO_D(_MMIO(0x1082c0), D_SKL_PLUS); + MMIO_D(_MMIO(0x4068), D_SKL_PLUS); + MMIO_D(_MMIO(0x67054), D_SKL_PLUS); + MMIO_D(_MMIO(0x6e560), D_SKL_PLUS); + MMIO_D(_MMIO(0x6e554), D_SKL_PLUS); + MMIO_D(_MMIO(0x2b20), D_SKL_PLUS); + MMIO_D(_MMIO(0x65f00), D_SKL_PLUS); + MMIO_D(_MMIO(0x65f08), D_SKL_PLUS); + MMIO_D(_MMIO(0x320f0), D_SKL_PLUS); MMIO_D(_MMIO(0x70034), D_SKL_PLUS); MMIO_D(_MMIO(0x71034), D_SKL_PLUS); @@ -2870,11 +2985,185 @@ static int init_skl_mmio_info(struct intel_gvt *gvt) MMIO_D(_MMIO(0x44500), D_SKL_PLUS); MMIO_DFH(GEN9_CSFE_CHICKEN1_RCS, D_SKL_PLUS, F_CMD_ACCESS, NULL, NULL); - MMIO_DFH(GEN8_HDC_CHICKEN1, D_SKL | D_KBL, F_MODE_MASK | F_CMD_ACCESS, + MMIO_DFH(GEN8_HDC_CHICKEN1, D_SKL_PLUS, F_MODE_MASK | F_CMD_ACCESS, NULL, NULL); MMIO_D(_MMIO(0x4ab8), D_KBL); - MMIO_D(_MMIO(0x2248), D_SKL_PLUS | D_KBL); + MMIO_D(_MMIO(0x2248), D_KBL | D_SKL); + + return 0; +} + +static int init_bxt_mmio_info(struct intel_gvt *gvt) +{ + struct drm_i915_private *dev_priv = gvt->dev_priv; + int ret; + + MMIO_F(_MMIO(0x80000), 0x3000, 0, 0, 0, D_BXT, NULL, NULL); + + MMIO_D(GEN7_SAMPLER_INSTDONE, D_BXT); + MMIO_D(GEN7_ROW_INSTDONE, D_BXT); + MMIO_D(GEN8_FAULT_TLB_DATA0, D_BXT); + MMIO_D(GEN8_FAULT_TLB_DATA1, D_BXT); + MMIO_D(ERROR_GEN6, D_BXT); + MMIO_D(DONE_REG, D_BXT); + MMIO_D(EIR, D_BXT); + MMIO_D(PGTBL_ER, D_BXT); + MMIO_D(_MMIO(0x4194), D_BXT); + MMIO_D(_MMIO(0x4294), D_BXT); + MMIO_D(_MMIO(0x4494), D_BXT); + + MMIO_RING_D(RING_PSMI_CTL, D_BXT); + MMIO_RING_D(RING_DMA_FADD, D_BXT); + MMIO_RING_D(RING_DMA_FADD_UDW, D_BXT); + MMIO_RING_D(RING_IPEHR, D_BXT); + MMIO_RING_D(RING_INSTPS, D_BXT); + MMIO_RING_D(RING_BBADDR_UDW, D_BXT); + MMIO_RING_D(RING_BBSTATE, D_BXT); + MMIO_RING_D(RING_IPEIR, D_BXT); + + MMIO_F(SOFT_SCRATCH(0), 16 * 4, 0, 0, 0, D_BXT, NULL, NULL); + + MMIO_DH(BXT_P_CR_GT_DISP_PWRON, D_BXT, NULL, bxt_gt_disp_pwron_write); + MMIO_D(BXT_RP_STATE_CAP, D_BXT); + MMIO_DH(BXT_PHY_CTL_FAMILY(DPIO_PHY0), D_BXT, + NULL, bxt_phy_ctl_family_write); + MMIO_DH(BXT_PHY_CTL_FAMILY(DPIO_PHY1), D_BXT, + NULL, bxt_phy_ctl_family_write); + MMIO_D(BXT_PHY_CTL(PORT_A), D_BXT); + MMIO_D(BXT_PHY_CTL(PORT_B), D_BXT); + MMIO_D(BXT_PHY_CTL(PORT_C), D_BXT); + MMIO_DH(BXT_PORT_PLL_ENABLE(PORT_A), D_BXT, + NULL, bxt_port_pll_enable_write); + MMIO_DH(BXT_PORT_PLL_ENABLE(PORT_B), D_BXT, + NULL, bxt_port_pll_enable_write); + MMIO_DH(BXT_PORT_PLL_ENABLE(PORT_C), D_BXT, NULL, + bxt_port_pll_enable_write); + + MMIO_D(BXT_PORT_CL1CM_DW0(DPIO_PHY0), D_BXT); + MMIO_D(BXT_PORT_CL1CM_DW9(DPIO_PHY0), D_BXT); + MMIO_D(BXT_PORT_CL1CM_DW10(DPIO_PHY0), D_BXT); + MMIO_D(BXT_PORT_CL1CM_DW28(DPIO_PHY0), D_BXT); + MMIO_D(BXT_PORT_CL1CM_DW30(DPIO_PHY0), D_BXT); + MMIO_D(BXT_PORT_CL2CM_DW6(DPIO_PHY0), D_BXT); + MMIO_D(BXT_PORT_REF_DW3(DPIO_PHY0), D_BXT); + MMIO_D(BXT_PORT_REF_DW6(DPIO_PHY0), D_BXT); + MMIO_D(BXT_PORT_REF_DW8(DPIO_PHY0), D_BXT); + + MMIO_D(BXT_PORT_CL1CM_DW0(DPIO_PHY1), D_BXT); + MMIO_D(BXT_PORT_CL1CM_DW9(DPIO_PHY1), D_BXT); + MMIO_D(BXT_PORT_CL1CM_DW10(DPIO_PHY1), D_BXT); + MMIO_D(BXT_PORT_CL1CM_DW28(DPIO_PHY1), D_BXT); + MMIO_D(BXT_PORT_CL1CM_DW30(DPIO_PHY1), D_BXT); + MMIO_D(BXT_PORT_CL2CM_DW6(DPIO_PHY1), D_BXT); + MMIO_D(BXT_PORT_REF_DW3(DPIO_PHY1), D_BXT); + MMIO_D(BXT_PORT_REF_DW6(DPIO_PHY1), D_BXT); + MMIO_D(BXT_PORT_REF_DW8(DPIO_PHY1), D_BXT); + + MMIO_D(BXT_PORT_PLL_EBB_0(DPIO_PHY0, DPIO_CH0), D_BXT); + MMIO_D(BXT_PORT_PLL_EBB_4(DPIO_PHY0, DPIO_CH0), D_BXT); + MMIO_D(BXT_PORT_PCS_DW10_LN01(DPIO_PHY0, DPIO_CH0), D_BXT); + MMIO_D(BXT_PORT_PCS_DW10_GRP(DPIO_PHY0, DPIO_CH0), D_BXT); + MMIO_D(BXT_PORT_PCS_DW12_LN01(DPIO_PHY0, DPIO_CH0), D_BXT); + MMIO_D(BXT_PORT_PCS_DW12_LN23(DPIO_PHY0, DPIO_CH0), D_BXT); + MMIO_DH(BXT_PORT_PCS_DW12_GRP(DPIO_PHY0, DPIO_CH0), D_BXT, + NULL, bxt_pcs_dw12_grp_write); + MMIO_D(BXT_PORT_TX_DW2_LN0(DPIO_PHY0, DPIO_CH0), D_BXT); + MMIO_D(BXT_PORT_TX_DW2_GRP(DPIO_PHY0, DPIO_CH0), D_BXT); + MMIO_DH(BXT_PORT_TX_DW3_LN0(DPIO_PHY0, DPIO_CH0), D_BXT, + bxt_port_tx_dw3_read, NULL); + MMIO_D(BXT_PORT_TX_DW3_GRP(DPIO_PHY0, DPIO_CH0), D_BXT); + MMIO_D(BXT_PORT_TX_DW4_LN0(DPIO_PHY0, DPIO_CH0), D_BXT); + MMIO_D(BXT_PORT_TX_DW4_GRP(DPIO_PHY0, DPIO_CH0), D_BXT); + MMIO_D(BXT_PORT_TX_DW14_LN(DPIO_PHY0, DPIO_CH0, 0), D_BXT); + MMIO_D(BXT_PORT_TX_DW14_LN(DPIO_PHY0, DPIO_CH0, 1), D_BXT); + MMIO_D(BXT_PORT_TX_DW14_LN(DPIO_PHY0, DPIO_CH0, 2), D_BXT); + MMIO_D(BXT_PORT_TX_DW14_LN(DPIO_PHY0, DPIO_CH0, 3), D_BXT); + MMIO_D(BXT_PORT_PLL(DPIO_PHY0, DPIO_CH0, 0), D_BXT); + MMIO_D(BXT_PORT_PLL(DPIO_PHY0, DPIO_CH0, 1), D_BXT); + MMIO_D(BXT_PORT_PLL(DPIO_PHY0, DPIO_CH0, 2), D_BXT); + MMIO_D(BXT_PORT_PLL(DPIO_PHY0, DPIO_CH0, 3), D_BXT); + MMIO_D(BXT_PORT_PLL(DPIO_PHY0, DPIO_CH0, 6), D_BXT); + MMIO_D(BXT_PORT_PLL(DPIO_PHY0, DPIO_CH0, 8), D_BXT); + MMIO_D(BXT_PORT_PLL(DPIO_PHY0, DPIO_CH0, 9), D_BXT); + MMIO_D(BXT_PORT_PLL(DPIO_PHY0, DPIO_CH0, 10), D_BXT); + + MMIO_D(BXT_PORT_PLL_EBB_0(DPIO_PHY0, DPIO_CH1), D_BXT); + MMIO_D(BXT_PORT_PLL_EBB_4(DPIO_PHY0, DPIO_CH1), D_BXT); + MMIO_D(BXT_PORT_PCS_DW10_LN01(DPIO_PHY0, DPIO_CH1), D_BXT); + MMIO_D(BXT_PORT_PCS_DW10_GRP(DPIO_PHY0, DPIO_CH1), D_BXT); + MMIO_D(BXT_PORT_PCS_DW12_LN01(DPIO_PHY0, DPIO_CH1), D_BXT); + MMIO_D(BXT_PORT_PCS_DW12_LN23(DPIO_PHY0, DPIO_CH1), D_BXT); + MMIO_DH(BXT_PORT_PCS_DW12_GRP(DPIO_PHY0, DPIO_CH1), D_BXT, + NULL, bxt_pcs_dw12_grp_write); + MMIO_D(BXT_PORT_TX_DW2_LN0(DPIO_PHY0, DPIO_CH1), D_BXT); + MMIO_D(BXT_PORT_TX_DW2_GRP(DPIO_PHY0, DPIO_CH1), D_BXT); + MMIO_DH(BXT_PORT_TX_DW3_LN0(DPIO_PHY0, DPIO_CH1), D_BXT, + bxt_port_tx_dw3_read, NULL); + MMIO_D(BXT_PORT_TX_DW3_GRP(DPIO_PHY0, DPIO_CH1), D_BXT); + MMIO_D(BXT_PORT_TX_DW4_LN0(DPIO_PHY0, DPIO_CH1), D_BXT); + MMIO_D(BXT_PORT_TX_DW4_GRP(DPIO_PHY0, DPIO_CH1), D_BXT); + MMIO_D(BXT_PORT_TX_DW14_LN(DPIO_PHY0, DPIO_CH1, 0), D_BXT); + MMIO_D(BXT_PORT_TX_DW14_LN(DPIO_PHY0, DPIO_CH1, 1), D_BXT); + MMIO_D(BXT_PORT_TX_DW14_LN(DPIO_PHY0, DPIO_CH1, 2), D_BXT); + MMIO_D(BXT_PORT_TX_DW14_LN(DPIO_PHY0, DPIO_CH1, 3), D_BXT); + MMIO_D(BXT_PORT_PLL(DPIO_PHY0, DPIO_CH1, 0), D_BXT); + MMIO_D(BXT_PORT_PLL(DPIO_PHY0, DPIO_CH1, 1), D_BXT); + MMIO_D(BXT_PORT_PLL(DPIO_PHY0, DPIO_CH1, 2), D_BXT); + MMIO_D(BXT_PORT_PLL(DPIO_PHY0, DPIO_CH1, 3), D_BXT); + MMIO_D(BXT_PORT_PLL(DPIO_PHY0, DPIO_CH1, 6), D_BXT); + MMIO_D(BXT_PORT_PLL(DPIO_PHY0, DPIO_CH1, 8), D_BXT); + MMIO_D(BXT_PORT_PLL(DPIO_PHY0, DPIO_CH1, 9), D_BXT); + MMIO_D(BXT_PORT_PLL(DPIO_PHY0, DPIO_CH1, 10), D_BXT); + + MMIO_D(BXT_PORT_PLL_EBB_0(DPIO_PHY1, DPIO_CH0), D_BXT); + MMIO_D(BXT_PORT_PLL_EBB_4(DPIO_PHY1, DPIO_CH0), D_BXT); + MMIO_D(BXT_PORT_PCS_DW10_LN01(DPIO_PHY1, DPIO_CH0), D_BXT); + MMIO_D(BXT_PORT_PCS_DW10_GRP(DPIO_PHY1, DPIO_CH0), D_BXT); + MMIO_D(BXT_PORT_PCS_DW12_LN01(DPIO_PHY1, DPIO_CH0), D_BXT); + MMIO_D(BXT_PORT_PCS_DW12_LN23(DPIO_PHY1, DPIO_CH0), D_BXT); + MMIO_DH(BXT_PORT_PCS_DW12_GRP(DPIO_PHY1, DPIO_CH0), D_BXT, + NULL, bxt_pcs_dw12_grp_write); + MMIO_D(BXT_PORT_TX_DW2_LN0(DPIO_PHY1, DPIO_CH0), D_BXT); + MMIO_D(BXT_PORT_TX_DW2_GRP(DPIO_PHY1, DPIO_CH0), D_BXT); + MMIO_DH(BXT_PORT_TX_DW3_LN0(DPIO_PHY1, DPIO_CH0), D_BXT, + bxt_port_tx_dw3_read, NULL); + MMIO_D(BXT_PORT_TX_DW3_GRP(DPIO_PHY1, DPIO_CH0), D_BXT); + MMIO_D(BXT_PORT_TX_DW4_LN0(DPIO_PHY1, DPIO_CH0), D_BXT); + MMIO_D(BXT_PORT_TX_DW4_GRP(DPIO_PHY1, DPIO_CH0), D_BXT); + MMIO_D(BXT_PORT_TX_DW14_LN(DPIO_PHY1, DPIO_CH0, 0), D_BXT); + MMIO_D(BXT_PORT_TX_DW14_LN(DPIO_PHY1, DPIO_CH0, 1), D_BXT); + MMIO_D(BXT_PORT_TX_DW14_LN(DPIO_PHY1, DPIO_CH0, 2), D_BXT); + MMIO_D(BXT_PORT_TX_DW14_LN(DPIO_PHY1, DPIO_CH0, 3), D_BXT); + MMIO_D(BXT_PORT_PLL(DPIO_PHY1, DPIO_CH0, 0), D_BXT); + MMIO_D(BXT_PORT_PLL(DPIO_PHY1, DPIO_CH0, 1), D_BXT); + MMIO_D(BXT_PORT_PLL(DPIO_PHY1, DPIO_CH0, 2), D_BXT); + MMIO_D(BXT_PORT_PLL(DPIO_PHY1, DPIO_CH0, 3), D_BXT); + MMIO_D(BXT_PORT_PLL(DPIO_PHY1, DPIO_CH0, 6), D_BXT); + MMIO_D(BXT_PORT_PLL(DPIO_PHY1, DPIO_CH0, 8), D_BXT); + MMIO_D(BXT_PORT_PLL(DPIO_PHY1, DPIO_CH0, 9), D_BXT); + MMIO_D(BXT_PORT_PLL(DPIO_PHY1, DPIO_CH0, 10), D_BXT); + + MMIO_D(BXT_DE_PLL_CTL, D_BXT); + MMIO_DH(BXT_DE_PLL_ENABLE, D_BXT, NULL, bxt_de_pll_enable_write); + MMIO_D(BXT_DSI_PLL_CTL, D_BXT); + MMIO_D(BXT_DSI_PLL_ENABLE, D_BXT); + + MMIO_D(GEN9_CLKGATE_DIS_0, D_BXT); + + MMIO_D(HSW_TVIDEO_DIP_GCP(TRANSCODER_A), D_BXT); + MMIO_D(HSW_TVIDEO_DIP_GCP(TRANSCODER_B), D_BXT); + MMIO_D(HSW_TVIDEO_DIP_GCP(TRANSCODER_C), D_BXT); + + MMIO_D(RC6_CTX_BASE, D_BXT); + + MMIO_D(GEN8_PUSHBUS_CONTROL, D_BXT); + MMIO_D(GEN8_PUSHBUS_ENABLE, D_BXT); + MMIO_D(GEN8_PUSHBUS_SHIFT, D_BXT); + MMIO_D(GEN6_GFXPAUSE, D_BXT); + MMIO_D(GEN8_L3SQCREG1, D_BXT); + + MMIO_DFH(GEN9_CTX_PREEMPT_REG, D_BXT, F_CMD_ACCESS, NULL, NULL); return 0; } @@ -2966,6 +3255,16 @@ int intel_gvt_setup_mmio_info(struct intel_gvt *gvt) ret = init_skl_mmio_info(gvt); if (ret) goto err; + } else if (IS_BROXTON(dev_priv)) { + ret = init_broadwell_mmio_info(gvt); + if (ret) + goto err; + ret = init_skl_mmio_info(gvt); + if (ret) + goto err; + ret = init_bxt_mmio_info(gvt); + if (ret) + goto err; } gvt->mmio.mmio_block = mmio_blocks; -- GitLab From 57c8a484a9cbf1315b5299702d12aef04867eeee Mon Sep 17 00:00:00 2001 From: Colin Xu <colin.xu@intel.com> Date: Mon, 11 Jun 2018 15:39:40 +0800 Subject: [PATCH 0266/1506] drm/i915: Enable KVMGT for BXT. Enable KVMGT for BXT. is_supported_device() acting as the gatekeeper of GVT-g init. If all supported platforms share the same configurations for some specific feature, platform check will rely on this check only. Signed-off-by: Colin Xu <colin.xu@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> --- drivers/gpu/drm/i915/intel_gvt.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_gvt.c b/drivers/gpu/drm/i915/intel_gvt.c index a2fe7c8d44775..a6291f60545bf 100644 --- a/drivers/gpu/drm/i915/intel_gvt.c +++ b/drivers/gpu/drm/i915/intel_gvt.c @@ -47,6 +47,8 @@ static bool is_supported_device(struct drm_i915_private *dev_priv) return true; if (IS_KABYLAKE(dev_priv)) return true; + if (IS_BROXTON(dev_priv)) + return true; return false; } -- GitLab From e4dd27aadd205417a2e9ea9902b698a0252ec3a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Thu, 24 May 2018 15:54:03 +0300 Subject: [PATCH 0267/1506] drm/i915: Allow DBLSCAN user modes with eDP/LVDS/DSI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When encountering a connector with the scaling mode property both intel and modesetting ddxs sometimes add tons of DBLSCAN modes to the output's mode list. The idea presumably being that since the output will be going through the panel fitter anyway we can pretend to use any kind of mode. Sadly that means we can't reject user modes with the DBLSCAN flag until we know whether we're going to be using the panel's native mode or the user mode directly. Doing otherwise means X clients using xf86vidmode/xrandr will get a protocol error (and often self terminate as a result) when the kernel refuses to use the requested mode with the DBLSCAN flag. To undo the regression we'll move the DBLSCAN checks into the connector->mode_valid() and encoder->compute_config() hooks. Cc: stable@vger.kernel.org Cc: Vito Caputo <vcaputo@pengaru.com> Reported-by: Vito Caputo <vcaputo@pengaru.com> Fixes: e995ca0b8139 ("drm/i915: Provide a device level .mode_valid() hook") References: https://lkml.org/lkml/2018/5/21/715 Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180524125403.23445-1-ville.syrjala@linux.intel.com Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=106804 Tested-by: Arkadiusz Miskiewicz <arekm@maven.pl> --- drivers/gpu/drm/i915/intel_crt.c | 20 ++++++++++++++++++++ drivers/gpu/drm/i915/intel_display.c | 16 +++++++++++++--- drivers/gpu/drm/i915/intel_dp.c | 6 ++++++ drivers/gpu/drm/i915/intel_dp_mst.c | 6 ++++++ drivers/gpu/drm/i915/intel_dsi.c | 6 ++++++ drivers/gpu/drm/i915/intel_dvo.c | 6 ++++++ drivers/gpu/drm/i915/intel_hdmi.c | 6 ++++++ drivers/gpu/drm/i915/intel_lvds.c | 5 +++++ drivers/gpu/drm/i915/intel_sdvo.c | 6 ++++++ drivers/gpu/drm/i915/intel_tv.c | 12 ++++++++++-- 10 files changed, 84 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 211d601cd1b16..95aa29cf2d9c3 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -304,6 +304,9 @@ intel_crt_mode_valid(struct drm_connector *connector, int max_dotclk = dev_priv->max_dotclk_freq; int max_clock; + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) + return MODE_NO_DBLESCAN; + if (mode->clock < 25000) return MODE_CLOCK_LOW; @@ -337,6 +340,12 @@ static bool intel_crt_compute_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, struct drm_connector_state *conn_state) { + struct drm_display_mode *adjusted_mode = + &pipe_config->base.adjusted_mode; + + if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) + return false; + return true; } @@ -344,6 +353,12 @@ static bool pch_crt_compute_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, struct drm_connector_state *conn_state) { + struct drm_display_mode *adjusted_mode = + &pipe_config->base.adjusted_mode; + + if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) + return false; + pipe_config->has_pch_encoder = true; return true; @@ -354,6 +369,11 @@ static bool hsw_crt_compute_config(struct intel_encoder *encoder, struct drm_connector_state *conn_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct drm_display_mode *adjusted_mode = + &pipe_config->base.adjusted_mode; + + if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) + return false; pipe_config->has_pch_encoder = true; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 17c590b42fd76..3323470596ca9 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -14529,12 +14529,22 @@ static enum drm_mode_status intel_mode_valid(struct drm_device *dev, const struct drm_display_mode *mode) { + /* + * Can't reject DBLSCAN here because Xorg ddxen can add piles + * of DBLSCAN modes to the output's mode list when they detect + * the scaling mode property on the connector. And they don't + * ask the kernel to validate those modes in any way until + * modeset time at which point the client gets a protocol error. + * So in order to not upset those clients we silently ignore the + * DBLSCAN flag on such connectors. For other connectors we will + * reject modes with the DBLSCAN flag in encoder->compute_config(). + * And we always reject DBLSCAN modes in connector->mode_valid() + * as we never want such modes on the connector's mode list. + */ + if (mode->vscan > 1) return MODE_NO_VSCAN; - if (mode->flags & DRM_MODE_FLAG_DBLSCAN) - return MODE_NO_DBLESCAN; - if (mode->flags & DRM_MODE_FLAG_HSKEW) return MODE_H_ILLEGAL; diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 40ffd91631755..a58bac01aeeae 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -420,6 +420,9 @@ intel_dp_mode_valid(struct drm_connector *connector, int max_rate, mode_rate, max_lanes, max_link_clock; int max_dotclk; + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) + return MODE_NO_DBLESCAN; + max_dotclk = intel_dp_downstream_max_dotclock(intel_dp); if (intel_dp_is_edp(intel_dp) && fixed_mode) { @@ -1869,6 +1872,9 @@ intel_dp_compute_config(struct intel_encoder *encoder, conn_state->scaling_mode); } + if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) + return false; + if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) && adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) return false; diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index 9e6956c086883..5890500a3a8b6 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -48,6 +48,9 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, bool reduce_m_n = drm_dp_has_quirk(&intel_dp->desc, DP_DPCD_QUIRK_LIMITED_M_N); + if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) + return false; + pipe_config->has_pch_encoder = false; bpp = 24; if (intel_dp->compliance.test_data.bpc) { @@ -366,6 +369,9 @@ intel_dp_mst_mode_valid(struct drm_connector *connector, if (!intel_dp) return MODE_ERROR; + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) + return MODE_NO_DBLESCAN; + max_link_clock = intel_dp_max_link_rate(intel_dp); max_lanes = intel_dp_max_lane_count(intel_dp); diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index cf1231f9c33bb..3b7acb5a70b3e 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -326,6 +326,9 @@ static bool intel_dsi_compute_config(struct intel_encoder *encoder, conn_state->scaling_mode); } + if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) + return false; + /* DSI uses short packets for sync events, so clear mode flags for DSI */ adjusted_mode->flags = 0; @@ -1266,6 +1269,9 @@ intel_dsi_mode_valid(struct drm_connector *connector, DRM_DEBUG_KMS("\n"); + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) + return MODE_NO_DBLESCAN; + if (fixed_mode) { if (mode->hdisplay > fixed_mode->hdisplay) return MODE_PANEL; diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index 7b942b6c17000..27f16db8953a5 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -215,6 +215,9 @@ intel_dvo_mode_valid(struct drm_connector *connector, int max_dotclk = to_i915(connector->dev)->max_dotclk_freq; int target_clock = mode->clock; + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) + return MODE_NO_DBLESCAN; + /* XXX: Validate clock range */ if (fixed_mode) { @@ -250,6 +253,9 @@ static bool intel_dvo_compute_config(struct intel_encoder *encoder, if (fixed_mode) intel_fixed_panel_mode(fixed_mode, adjusted_mode); + if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) + return false; + return true; } diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index ef4de5a02cb53..447ffe590e555 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1540,6 +1540,9 @@ intel_hdmi_mode_valid(struct drm_connector *connector, bool force_dvi = READ_ONCE(to_intel_digital_connector_state(connector->state)->force_audio) == HDMI_AUDIO_OFF_DVI; + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) + return MODE_NO_DBLESCAN; + clock = mode->clock; if ((mode->flags & DRM_MODE_FLAG_3D_MASK) == DRM_MODE_FLAG_3D_FRAME_PACKING) @@ -1660,6 +1663,9 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, int desired_bpp; bool force_dvi = intel_conn_state->force_audio == HDMI_AUDIO_OFF_DVI; + if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) + return false; + pipe_config->has_hdmi_sink = !force_dvi && intel_hdmi->has_hdmi_sink; if (pipe_config->has_hdmi_sink) diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index e05c12e7629cc..bb06744d28a43 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -378,6 +378,8 @@ intel_lvds_mode_valid(struct drm_connector *connector, struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode; int max_pixclk = to_i915(connector->dev)->max_dotclk_freq; + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) + return MODE_NO_DBLESCAN; if (mode->hdisplay > fixed_mode->hdisplay) return MODE_PANEL; if (mode->vdisplay > fixed_mode->vdisplay) @@ -427,6 +429,9 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, intel_fixed_panel_mode(intel_connector->panel.fixed_mode, adjusted_mode); + if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) + return false; + if (HAS_PCH_SPLIT(dev_priv)) { pipe_config->has_pch_encoder = true; diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 848b03a542d69..9d9229a1f36cc 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1160,6 +1160,9 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder, adjusted_mode); } + if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) + return false; + /* * Make the CRTC code factor in the SDVO pixel multiplier. The * SDVO device will factor out the multiplier during mode_set. @@ -1631,6 +1634,9 @@ intel_sdvo_mode_valid(struct drm_connector *connector, struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); int max_dotclk = to_i915(connector->dev)->max_dotclk_freq; + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) + return MODE_NO_DBLESCAN; + if (intel_sdvo->pixel_clock_min > mode->clock) return MODE_CLOCK_LOW; diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 99bc2368dda03..24dc368fdaa1d 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -846,6 +846,9 @@ intel_tv_mode_valid(struct drm_connector *connector, const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state); int max_dotclk = to_i915(connector->dev)->max_dotclk_freq; + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) + return MODE_NO_DBLESCAN; + if (mode->clock > max_dotclk) return MODE_CLOCK_HIGH; @@ -873,16 +876,21 @@ intel_tv_compute_config(struct intel_encoder *encoder, struct drm_connector_state *conn_state) { const struct tv_mode *tv_mode = intel_tv_mode_find(conn_state); + struct drm_display_mode *adjusted_mode = + &pipe_config->base.adjusted_mode; if (!tv_mode) return false; - pipe_config->base.adjusted_mode.crtc_clock = tv_mode->clock; + if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) + return false; + + adjusted_mode->crtc_clock = tv_mode->clock; DRM_DEBUG_KMS("forcing bpc to 8 for TV\n"); pipe_config->pipe_bpp = 8*3; /* TV has it's own notion of sync and other mode flags, so clear them. */ - pipe_config->base.adjusted_mode.flags = 0; + adjusted_mode->flags = 0; /* * FIXME: We don't check whether the input mode is actually what we want -- GitLab From 697b9a8714cb4631fd0526b3c78955d5422c24ba Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Tue, 12 Jun 2018 11:51:35 +0100 Subject: [PATCH 0268/1506] drm/i915: Make closing request flush mandatory For symmetry, simplicity and ensuring the request is always truly idle upon its completion, always emit the closing flush prior to emitting the request breadcrumb. Previously, we would only emit the flush if we had started a user batch, but this just leaves all the other paths open to speculation (do they affect the GPU caches or not?) With mm switching, a key requirement is that the GPU is flushed and invalidated before hand, so for absolute safety, we want that closing flush be mandatory. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180612105135.4459-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 4 ++-- drivers/gpu/drm/i915/i915_gem_context.c | 9 +-------- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 4 ++-- drivers/gpu/drm/i915/i915_request.c | 18 ++---------------- drivers/gpu/drm/i915/i915_request.h | 4 +--- drivers/gpu/drm/i915/selftests/huge_pages.c | 2 +- .../drm/i915/selftests/i915_gem_coherency.c | 4 ++-- .../gpu/drm/i915/selftests/i915_gem_context.c | 4 ++-- drivers/gpu/drm/i915/selftests/i915_request.c | 2 +- .../gpu/drm/i915/selftests/intel_hangcheck.c | 16 ++++++++-------- drivers/gpu/drm/i915/selftests/intel_lrc.c | 2 +- .../gpu/drm/i915/selftests/intel_workarounds.c | 2 +- 12 files changed, 24 insertions(+), 47 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 93efd92362dbc..8dd4d35655afc 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3213,7 +3213,7 @@ void i915_gem_reset(struct drm_i915_private *dev_priv, rq = i915_request_alloc(engine, dev_priv->kernel_context); if (!IS_ERR(rq)) - __i915_request_add(rq, false); + i915_request_add(rq); } } @@ -5332,7 +5332,7 @@ static int __intel_engines_record_defaults(struct drm_i915_private *i915) if (engine->init_context) err = engine->init_context(rq); - __i915_request_add(rq, true); + i915_request_add(rq); if (err) goto err_active; } diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index b2c7ac1b074d4..ef6ea4bcd7733 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -700,14 +700,7 @@ int i915_gem_switch_to_kernel_context(struct drm_i915_private *i915) i915_timeline_sync_set(rq->timeline, &prev->fence); } - /* - * Force a flush after the switch to ensure that all rendering - * and operations prior to switching to the kernel context hits - * memory. This should be guaranteed by the previous request, - * but an extra layer of paranoia before we declare the system - * idle (on suspend etc) is advisable! - */ - __i915_request_add(rq, true); + i915_request_add(rq); } return 0; diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 2d2eb3075960c..60dc2a865f5f9 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -921,7 +921,7 @@ static void reloc_gpu_flush(struct reloc_cache *cache) i915_gem_object_unpin_map(cache->rq->batch->obj); i915_gem_chipset_flush(cache->rq->i915); - __i915_request_add(cache->rq, true); + i915_request_add(cache->rq); cache->rq = NULL; } @@ -2438,7 +2438,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, trace_i915_request_queue(eb.request, eb.batch_flags); err = eb_submit(&eb); err_request: - __i915_request_add(eb.request, err == 0); + i915_request_add(eb.request); add_to_client(eb.request, file); if (fences) diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index 9092f5464c24d..e1dbb544046fe 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -1018,14 +1018,13 @@ i915_request_await_object(struct i915_request *to, * request is not being tracked for completion but the work itself is * going to happen on the hardware. This would be a Bad Thing(tm). */ -void __i915_request_add(struct i915_request *request, bool flush_caches) +void i915_request_add(struct i915_request *request) { struct intel_engine_cs *engine = request->engine; struct i915_timeline *timeline = request->timeline; struct intel_ring *ring = request->ring; struct i915_request *prev; u32 *cs; - int err; GEM_TRACE("%s fence %llx:%d\n", engine->name, request->fence.context, request->fence.seqno); @@ -1046,20 +1045,7 @@ void __i915_request_add(struct i915_request *request, bool flush_caches) * know that it is time to use that space up. */ request->reserved_space = 0; - - /* - * Emit any outstanding flushes - execbuf can fail to emit the flush - * after having emitted the batchbuffer command. Hence we need to fix - * things up similar to emitting the lazy request. The difference here - * is that the flush _must_ happen before the next request, no matter - * what. - */ - if (flush_caches) { - err = engine->emit_flush(request, EMIT_FLUSH); - - /* Not allowed to fail! */ - WARN(err, "engine->emit_flush() failed: %d!\n", err); - } + engine->emit_flush(request, EMIT_FLUSH); /* * Record the position of the start of the breadcrumb so that diff --git a/drivers/gpu/drm/i915/i915_request.h b/drivers/gpu/drm/i915/i915_request.h index 0e9aba53d0e42..7ee220ded9c9a 100644 --- a/drivers/gpu/drm/i915/i915_request.h +++ b/drivers/gpu/drm/i915/i915_request.h @@ -253,9 +253,7 @@ int i915_request_await_object(struct i915_request *to, int i915_request_await_dma_fence(struct i915_request *rq, struct dma_fence *fence); -void __i915_request_add(struct i915_request *rq, bool flush_caches); -#define i915_request_add(rq) \ - __i915_request_add(rq, false) +void i915_request_add(struct i915_request *rq); void __i915_request_submit(struct i915_request *request); void i915_request_submit(struct i915_request *request); diff --git a/drivers/gpu/drm/i915/selftests/huge_pages.c b/drivers/gpu/drm/i915/selftests/huge_pages.c index 7846ea4a99bc6..fbe4324116d72 100644 --- a/drivers/gpu/drm/i915/selftests/huge_pages.c +++ b/drivers/gpu/drm/i915/selftests/huge_pages.c @@ -1003,7 +1003,7 @@ static int gpu_write(struct i915_vma *vma, reservation_object_unlock(vma->resv); err_request: - __i915_request_add(rq, err == 0); + i915_request_add(rq); return err; } diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c b/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c index 340a98c0c804a..a4900091ae3dc 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c @@ -199,7 +199,7 @@ static int gpu_set(struct drm_i915_gem_object *obj, cs = intel_ring_begin(rq, 4); if (IS_ERR(cs)) { - __i915_request_add(rq, false); + i915_request_add(rq); i915_vma_unpin(vma); return PTR_ERR(cs); } @@ -229,7 +229,7 @@ static int gpu_set(struct drm_i915_gem_object *obj, reservation_object_add_excl_fence(obj->resv, &rq->fence); reservation_object_unlock(obj->resv); - __i915_request_add(rq, true); + i915_request_add(rq); return 0; } diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_context.c b/drivers/gpu/drm/i915/selftests/i915_gem_context.c index 708e8d7214488..836f1af8b833c 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_context.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_context.c @@ -182,12 +182,12 @@ static int gpu_fill(struct drm_i915_gem_object *obj, reservation_object_add_excl_fence(obj->resv, &rq->fence); reservation_object_unlock(obj->resv); - __i915_request_add(rq, true); + i915_request_add(rq); return 0; err_request: - __i915_request_add(rq, false); + i915_request_add(rq); err_batch: i915_vma_unpin(batch); err_vma: diff --git a/drivers/gpu/drm/i915/selftests/i915_request.c b/drivers/gpu/drm/i915/selftests/i915_request.c index a3a89aadeccb0..f5d00332bb31e 100644 --- a/drivers/gpu/drm/i915/selftests/i915_request.c +++ b/drivers/gpu/drm/i915/selftests/i915_request.c @@ -466,7 +466,7 @@ empty_request(struct intel_engine_cs *engine, goto out_request; out_request: - __i915_request_add(request, err == 0); + i915_request_add(request); return err ? ERR_PTR(err) : request; } diff --git a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c index 390a157b37c3f..fe7d3190ebfee 100644 --- a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c +++ b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c @@ -245,7 +245,7 @@ hang_create_request(struct hang *h, struct intel_engine_cs *engine) err = emit_recurse_batch(h, rq); if (err) { - __i915_request_add(rq, false); + i915_request_add(rq); return ERR_PTR(err); } @@ -318,7 +318,7 @@ static int igt_hang_sanitycheck(void *arg) *h.batch = MI_BATCH_BUFFER_END; i915_gem_chipset_flush(i915); - __i915_request_add(rq, true); + i915_request_add(rq); timeout = i915_request_wait(rq, I915_WAIT_LOCKED, @@ -464,7 +464,7 @@ static int __igt_reset_engine(struct drm_i915_private *i915, bool active) } i915_request_get(rq); - __i915_request_add(rq, true); + i915_request_add(rq); mutex_unlock(&i915->drm.struct_mutex); if (!wait_until_running(&h, rq)) { @@ -742,7 +742,7 @@ static int __igt_reset_engines(struct drm_i915_private *i915, } i915_request_get(rq); - __i915_request_add(rq, true); + i915_request_add(rq); mutex_unlock(&i915->drm.struct_mutex); if (!wait_until_running(&h, rq)) { @@ -942,7 +942,7 @@ static int igt_wait_reset(void *arg) } i915_request_get(rq); - __i915_request_add(rq, true); + i915_request_add(rq); if (!wait_until_running(&h, rq)) { struct drm_printer p = drm_info_printer(i915->drm.dev); @@ -1037,7 +1037,7 @@ static int igt_reset_queue(void *arg) } i915_request_get(prev); - __i915_request_add(prev, true); + i915_request_add(prev); count = 0; do { @@ -1051,7 +1051,7 @@ static int igt_reset_queue(void *arg) } i915_request_get(rq); - __i915_request_add(rq, true); + i915_request_add(rq); /* * XXX We don't handle resetting the kernel context @@ -1184,7 +1184,7 @@ static int igt_handle_error(void *arg) } i915_request_get(rq); - __i915_request_add(rq, true); + i915_request_add(rq); if (!wait_until_running(&h, rq)) { struct drm_printer p = drm_info_printer(i915->drm.dev); diff --git a/drivers/gpu/drm/i915/selftests/intel_lrc.c b/drivers/gpu/drm/i915/selftests/intel_lrc.c index 0b6da08c8caec..ea27c7cfbf968 100644 --- a/drivers/gpu/drm/i915/selftests/intel_lrc.c +++ b/drivers/gpu/drm/i915/selftests/intel_lrc.c @@ -155,7 +155,7 @@ spinner_create_request(struct spinner *spin, err = emit_recurse_batch(spin, rq, arbitration_command); if (err) { - __i915_request_add(rq, false); + i915_request_add(rq); return ERR_PTR(err); } diff --git a/drivers/gpu/drm/i915/selftests/intel_workarounds.c b/drivers/gpu/drm/i915/selftests/intel_workarounds.c index f1cfb0fb6bea4..e1ea2d2bedd2f 100644 --- a/drivers/gpu/drm/i915/selftests/intel_workarounds.c +++ b/drivers/gpu/drm/i915/selftests/intel_workarounds.c @@ -75,7 +75,7 @@ read_nonprivs(struct i915_gem_context *ctx, struct intel_engine_cs *engine) i915_gem_object_get(result); i915_gem_object_set_active_reference(result); - __i915_request_add(rq, true); + i915_request_add(rq); i915_vma_unpin(vma); return result; -- GitLab From 6ebb6d8ebe56135b06b1427ecaa712580b878ea2 Mon Sep 17 00:00:00 2001 From: Jani Nikula <jani.nikula@intel.com> Date: Wed, 13 Jun 2018 14:49:29 +0300 Subject: [PATCH 0269/1506] drm/i915/perf: make oa format tables const No reason not to be const. Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180613114929.14541-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/i915_perf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index 881a992305ecd..447407fee3b89 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -315,7 +315,7 @@ static u32 i915_oa_max_sample_rate = 100000; * code assumes all reports have a power-of-two size and ~(size - 1) can * be used as a mask to align the OA tail pointer. */ -static struct i915_oa_format hsw_oa_formats[I915_OA_FORMAT_MAX] = { +static const struct i915_oa_format hsw_oa_formats[I915_OA_FORMAT_MAX] = { [I915_OA_FORMAT_A13] = { 0, 64 }, [I915_OA_FORMAT_A29] = { 1, 128 }, [I915_OA_FORMAT_A13_B8_C8] = { 2, 128 }, @@ -326,7 +326,7 @@ static struct i915_oa_format hsw_oa_formats[I915_OA_FORMAT_MAX] = { [I915_OA_FORMAT_C4_B8] = { 7, 64 }, }; -static struct i915_oa_format gen8_plus_oa_formats[I915_OA_FORMAT_MAX] = { +static const struct i915_oa_format gen8_plus_oa_formats[I915_OA_FORMAT_MAX] = { [I915_OA_FORMAT_A12] = { 0, 64 }, [I915_OA_FORMAT_A12_B8_C8] = { 2, 128 }, [I915_OA_FORMAT_A32u40_A4u32_B8_C8] = { 5, 256 }, -- GitLab From 2e932b9cdecebe3f41eaa86f8cec15c42fc62d41 Mon Sep 17 00:00:00 2001 From: Jani Nikula <jani.nikula@intel.com> Date: Wed, 13 Jun 2018 14:39:27 +0300 Subject: [PATCH 0270/1506] drm/i915/opregion: move acpi notifier to dev_priv Get rid of the silly static variable. Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180613113927.30033-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_opregion.c | 31 +++++++++++---------------- drivers/gpu/drm/i915/intel_opregion.h | 1 + 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index c58e5f53bab0d..e034b4166d322 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -608,16 +608,16 @@ void intel_opregion_asle_intr(struct drm_i915_private *dev_priv) #define ACPI_EV_LID (1<<1) #define ACPI_EV_DOCK (1<<2) -static struct intel_opregion *system_opregion; - +/* + * The only video events relevant to opregion are 0x80. These indicate either a + * docking event, lid switch or display switch request. In Linux, these are + * handled by the dock, button and video drivers. + */ static int intel_opregion_video_event(struct notifier_block *nb, unsigned long val, void *data) { - /* The only video events relevant to opregion are 0x80. These indicate - either a docking event, lid switch or display switch request. In - Linux, these are handled by the dock, button and video drivers. - */ - + struct intel_opregion *opregion = container_of(nb, struct intel_opregion, + acpi_notifier); struct acpi_bus_event *event = data; struct opregion_acpi *acpi; int ret = NOTIFY_OK; @@ -625,10 +625,7 @@ static int intel_opregion_video_event(struct notifier_block *nb, if (strcmp(event->device_class, ACPI_VIDEO_CLASS) != 0) return NOTIFY_DONE; - if (!system_opregion) - return NOTIFY_DONE; - - acpi = system_opregion->acpi; + acpi = opregion->acpi; if (event->type == 0x80 && ((acpi->cevt & 1) == 0)) ret = NOTIFY_BAD; @@ -638,10 +635,6 @@ static int intel_opregion_video_event(struct notifier_block *nb, return ret; } -static struct notifier_block intel_opregion_notifier = { - .notifier_call = intel_opregion_video_event, -}; - /* * Initialise the DIDL field in opregion. This passes a list of devices to * the firmware. Values are defined by section B.4.2 of the ACPI specification @@ -797,8 +790,8 @@ void intel_opregion_register(struct drm_i915_private *dev_priv) opregion->acpi->csts = 0; opregion->acpi->drdy = 1; - system_opregion = opregion; - register_acpi_notifier(&intel_opregion_notifier); + opregion->acpi_notifier.notifier_call = intel_opregion_video_event; + register_acpi_notifier(&opregion->acpi_notifier); } if (opregion->asle) { @@ -822,8 +815,8 @@ void intel_opregion_unregister(struct drm_i915_private *dev_priv) if (opregion->acpi) { opregion->acpi->drdy = 0; - system_opregion = NULL; - unregister_acpi_notifier(&intel_opregion_notifier); + unregister_acpi_notifier(&opregion->acpi_notifier); + opregion->acpi_notifier.notifier_call = NULL; } /* just clear all opregion memory pointers now */ diff --git a/drivers/gpu/drm/i915/intel_opregion.h b/drivers/gpu/drm/i915/intel_opregion.h index e0e437ba9e516..e8498a8cda3d1 100644 --- a/drivers/gpu/drm/i915/intel_opregion.h +++ b/drivers/gpu/drm/i915/intel_opregion.h @@ -49,6 +49,7 @@ struct intel_opregion { u32 vbt_size; u32 *lid_state; struct work_struct asle_work; + struct notifier_block acpi_notifier; }; #define OPREGION_SIZE (8 * 1024) -- GitLab From 1288786b18f7d979f1f9bcb0134ee5fbfcc8e3d1 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 14 Jun 2018 10:40:59 +0100 Subject: [PATCH 0271/1506] drm/i915: Move GEM sanitize from resume_early to resume This should be a no-op in terms of our control flow, we move the sanitization (GPU reset) from the bottom of the early resume phase to the top of the next. However, following hibernation debug, the power code skips the early resume phase, but as we are about to completely restore the GTT mappings, we first need to stop the GPU using them i.e. perform a GPU reset (i915_gem_sanitize()). Testcase: igt/gem_exec_suspend/basic-S4-devices Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Imre Deak <imre.deak@intel.com> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180614094103.18025-1-chris@chris-wilson.co.uk Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> --- drivers/gpu/drm/i915/i915_drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 4cdd70de5ed02..a9c8c66bb5258 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1698,6 +1698,8 @@ static int i915_drm_resume(struct drm_device *dev) disable_rpm_wakeref_asserts(dev_priv); intel_sanitize_gt_powersave(dev_priv); + i915_gem_sanitize(dev_priv); + ret = i915_ggtt_enable_hw(dev_priv); if (ret) DRM_ERROR("failed to re-enable GGTT\n"); @@ -1839,8 +1841,6 @@ static int i915_drm_resume_early(struct drm_device *dev) else intel_display_set_init_power(dev_priv, true); - i915_gem_sanitize(dev_priv); - enable_rpm_wakeref_asserts(dev_priv); out: -- GitLab From d6abe6df706c66d803e6dd4fe98c1b6b7f125a56 Mon Sep 17 00:00:00 2001 From: Inki Dae <inki.dae@samsung.com> Date: Thu, 24 May 2018 18:32:59 +0900 Subject: [PATCH 0272/1506] drm/bridge: sil_sii8620: do not have a dependency of RC_CORE This patch makes RC_CORE to be selected with this driver. sil_sii8620 driver calls remote controller interfaces directly so RC_CORE should be enabled mandatorily. And some boards not using remote controller device don't really need to know that RC_CORE config should be enabled to use sil_sii8620 driver only for HDMI. Changelog v2: - select INPUT because compiling will fail without INPUT. Signed-off-by: Inki Dae <inki.dae@samsung.com> Signed-off-by: Andrzej Hajda <a.hajda@samsung.com> Link: https://patchwork.freedesktop.org/patch/msgid/1527154379-31886-1-git-send-email-inki.dae@samsung.com --- drivers/gpu/drm/bridge/Kconfig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index 1d75d3a1f9513..5cc4a51e1e923 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -82,8 +82,10 @@ config DRM_PARADE_PS8622 config DRM_SIL_SII8620 tristate "Silicon Image SII8620 HDMI/MHL bridge" - depends on OF && RC_CORE + depends on OF select DRM_KMS_HELPER + select INPUT + select RC_CORE help Silicon Image SII8620 HDMI/MHL bridge chip driver. -- GitLab From 856e1b175650816dce554d2865ec258aa3b72098 Mon Sep 17 00:00:00 2001 From: Jani Nikula <jani.nikula@intel.com> Date: Thu, 14 Jun 2018 13:47:09 +0300 Subject: [PATCH 0273/1506] drm/i915/dsm: remove unnecessary dsm priv structure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pass a local acpi_handle around instead of having a static dsm priv structure. If we need it later, we can always move it to dev_priv, and the change at hand will make that easier as well. Care is taken to preserve old behaviour, particularly using the last non-NULL acpi handle, whether it makes sense or not. Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180614104709.2808-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_acpi.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_acpi.c b/drivers/gpu/drm/i915/intel_acpi.c index d1abf4bb7c819..6ba478e57b9bc 100644 --- a/drivers/gpu/drm/i915/intel_acpi.c +++ b/drivers/gpu/drm/i915/intel_acpi.c @@ -12,10 +12,6 @@ #define INTEL_DSM_REVISION_ID 1 /* For Calpella anyway... */ #define INTEL_DSM_FN_PLATFORM_MUX_INFO 1 /* No args */ -static struct intel_dsm_priv { - acpi_handle dhandle; -} intel_dsm_priv; - static const guid_t intel_dsm_guid = GUID_INIT(0x7ed873d3, 0xc2d0, 0x4e4f, 0xa8, 0x54, 0x0f, 0x13, 0x17, 0xb0, 0x1c, 0x2c); @@ -72,12 +68,12 @@ static char *intel_dsm_mux_type(u8 type) } } -static void intel_dsm_platform_mux_info(void) +static void intel_dsm_platform_mux_info(acpi_handle dhandle) { int i; union acpi_object *pkg, *connector_count; - pkg = acpi_evaluate_dsm_typed(intel_dsm_priv.dhandle, &intel_dsm_guid, + pkg = acpi_evaluate_dsm_typed(dhandle, &intel_dsm_guid, INTEL_DSM_REVISION_ID, INTEL_DSM_FN_PLATFORM_MUX_INFO, NULL, ACPI_TYPE_PACKAGE); if (!pkg) { @@ -107,41 +103,40 @@ static void intel_dsm_platform_mux_info(void) ACPI_FREE(pkg); } -static bool intel_dsm_pci_probe(struct pci_dev *pdev) +static acpi_handle intel_dsm_pci_probe(struct pci_dev *pdev) { acpi_handle dhandle; dhandle = ACPI_HANDLE(&pdev->dev); if (!dhandle) - return false; + return NULL; if (!acpi_check_dsm(dhandle, &intel_dsm_guid, INTEL_DSM_REVISION_ID, 1 << INTEL_DSM_FN_PLATFORM_MUX_INFO)) { DRM_DEBUG_KMS("no _DSM method for intel device\n"); - return false; + return NULL; } - intel_dsm_priv.dhandle = dhandle; - intel_dsm_platform_mux_info(); + intel_dsm_platform_mux_info(dhandle); - return true; + return dhandle; } static bool intel_dsm_detect(void) { + acpi_handle dhandle = NULL; char acpi_method_name[255] = { 0 }; struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name}; struct pci_dev *pdev = NULL; - bool has_dsm = false; int vga_count = 0; while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) { vga_count++; - has_dsm |= intel_dsm_pci_probe(pdev); + dhandle = intel_dsm_pci_probe(pdev) ?: dhandle; } - if (vga_count == 2 && has_dsm) { - acpi_get_name(intel_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer); + if (vga_count == 2 && dhandle) { + acpi_get_name(dhandle, ACPI_FULL_PATHNAME, &buffer); DRM_DEBUG_DRIVER("vga_switcheroo: detected DSM switching method %s handle\n", acpi_method_name); return true; -- GitLab From 83c317832eb1862e27f872606ee1a2fed6ab638f Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 14 Jun 2018 13:21:50 +0100 Subject: [PATCH 0274/1506] drm/i915: Dump the ringbuffer of the active request for debugging Sometimes we need to see what instructions we emitted for a request to try and gather a glimmer of insight into what the GPU is doing when it stops responding. v2: Move ring dumping into its own routine Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20180614122150.17552-1-chris@chris-wilson.co.uk Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> --- drivers/gpu/drm/i915/intel_engine_cs.c | 41 ++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index d278fed8cb31d..0ffce14ab08d9 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -1394,6 +1394,39 @@ static void intel_engine_print_registers(const struct intel_engine_cs *engine, } } +static void print_request_ring(struct drm_printer *m, struct i915_request *rq) +{ + void *ring; + int size; + + drm_printf(m, + "[head %04x, postfix %04x, tail %04x, batch 0x%08x_%08x]:\n", + rq->head, rq->postfix, rq->tail, + rq->batch ? upper_32_bits(rq->batch->node.start) : ~0u, + rq->batch ? lower_32_bits(rq->batch->node.start) : ~0u); + + size = rq->tail - rq->head; + if (rq->tail < rq->head) + size += rq->ring->size; + + ring = kmalloc(size, GFP_ATOMIC); + if (ring) { + const void *vaddr = rq->ring->vaddr; + unsigned int head = rq->head; + unsigned int len = 0; + + if (rq->tail < head) { + len = rq->ring->size - head; + memcpy(ring, vaddr + head, len); + head = 0; + } + memcpy(ring + len, vaddr + head, size - len); + + hexdump(m, ring, size); + kfree(ring); + } +} + void intel_engine_dump(struct intel_engine_cs *engine, struct drm_printer *m, const char *header, ...) @@ -1444,11 +1477,7 @@ void intel_engine_dump(struct intel_engine_cs *engine, rq = i915_gem_find_active_request(engine); if (rq) { print_request(m, rq, "\t\tactive "); - drm_printf(m, - "\t\t[head %04x, postfix %04x, tail %04x, batch 0x%08x_%08x]\n", - rq->head, rq->postfix, rq->tail, - rq->batch ? upper_32_bits(rq->batch->node.start) : ~0u, - rq->batch ? lower_32_bits(rq->batch->node.start) : ~0u); + drm_printf(m, "\t\tring->start: 0x%08x\n", i915_ggtt_offset(rq->ring->vma)); drm_printf(m, "\t\tring->head: 0x%08x\n", @@ -1459,6 +1488,8 @@ void intel_engine_dump(struct intel_engine_cs *engine, rq->ring->emit); drm_printf(m, "\t\tring->space: 0x%08x\n", rq->ring->space); + + print_request_ring(m, rq); } rcu_read_unlock(); -- GitLab From 286e615356000ae51fac0e497247543724414d52 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 14 Jun 2018 10:41:01 +0100 Subject: [PATCH 0275/1506] drm/i915: Make the hexdump row offset visually distinct Currently we use %08x for the row offset, and %08x for the binary contents of the buffer. This makes it very easily to confuse the two, so switch to using [%04x] for the start-of-row offset. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180614094103.18025-3-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_engine_cs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index 0ffce14ab08d9..8b3d7aa3dfde0 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -1258,7 +1258,7 @@ static void hexdump(struct drm_printer *m, const void *buf, size_t len) rowsize, sizeof(u32), line, sizeof(line), false) >= sizeof(line)); - drm_printf(m, "%08zx %s\n", pos, line); + drm_printf(m, "[%04zx] %s\n", pos, line); prev = buf + pos; skip = false; -- GitLab From e62230deeeae1f096a4be2360204536caf9ad8b6 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 14 Jun 2018 10:41:02 +0100 Subject: [PATCH 0276/1506] drm/i915: Show CCID in engine dumps For debugging context issues, knowing what context the GPU is loading/using is helpful. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180614094103.18025-4-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_engine_cs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index 8b3d7aa3dfde0..13bb8c7d2621b 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -1273,6 +1273,8 @@ static void intel_engine_print_registers(const struct intel_engine_cs *engine, &engine->execlists; u64 addr; + if (engine->id == RCS && IS_GEN(dev_priv, 4, 7)) + drm_printf(m, "\tCCID: 0x%08x\n", I915_READ(CCID)); drm_printf(m, "\tRING_START: 0x%08x\n", I915_READ(RING_START(engine->mmio_base))); drm_printf(m, "\tRING_HEAD: 0x%08x\n", -- GitLab From a2bbf714834288da0ed4668d4e4d895ffef73de2 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 14 Jun 2018 10:41:03 +0100 Subject: [PATCH 0277/1506] drm/i915/gtt: Only keep gen6 page directories pinned while active In order to be able to evict the gen6 ppgtt, we have to unpin it at some point. We can simply use our context activity tracking to know when the ppgtt is no longer in use by hardware, and so only keep it pinned while being used a request. For the kernel_context (and thus aliasing_ppgtt), it remains pinned at all times, as the kernel_context itself is pinned at all times. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: Matthew Auld <matthew.william.auld@gmail.com> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180614094103.18025-5-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_gtt.c | 36 ++++++++++++++----------- drivers/gpu/drm/i915/i915_gem_gtt.h | 5 ++++ drivers/gpu/drm/i915/intel_ringbuffer.c | 28 +++++++++++++++++++ 3 files changed, 54 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 267f1f97b9f09..0ee9e154359fd 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1912,7 +1912,6 @@ static void gen6_ppgtt_cleanup(struct i915_address_space *vm) { struct gen6_hw_ppgtt *ppgtt = to_gen6_ppgtt(i915_vm_to_ppgtt(vm)); - i915_vma_unpin(ppgtt->vma); i915_vma_destroy(ppgtt->vma); gen6_ppgtt_free_pd(ppgtt); @@ -1998,10 +1997,19 @@ static struct i915_vma *pd_vma_create(struct gen6_hw_ppgtt *ppgtt, int size) return vma; } -static int gen6_ppgtt_pin(struct i915_hw_ppgtt *base) +int gen6_ppgtt_pin(struct i915_hw_ppgtt *base) { struct gen6_hw_ppgtt *ppgtt = to_gen6_ppgtt(base); + /* + * Workaround the limited maximum vma->pin_count and the aliasing_ppgtt + * which will be pinned into every active context. + * (When vma->pin_count becomes atomic, I expect we will naturally + * need a larger, unpacked, type and kill this redundancy.) + */ + if (ppgtt->pin_count++) + return 0; + /* * PPGTT PDEs reside in the GGTT and consists of 512 entries. The * allocator works in address space sizes, so it's multiplied by page @@ -2012,6 +2020,17 @@ static int gen6_ppgtt_pin(struct i915_hw_ppgtt *base) PIN_GLOBAL | PIN_HIGH); } +void gen6_ppgtt_unpin(struct i915_hw_ppgtt *base) +{ + struct gen6_hw_ppgtt *ppgtt = to_gen6_ppgtt(base); + + GEM_BUG_ON(!ppgtt->pin_count); + if (--ppgtt->pin_count) + return; + + i915_vma_unpin(ppgtt->vma); +} + static struct i915_hw_ppgtt *gen6_ppgtt_create(struct drm_i915_private *i915) { struct i915_ggtt * const ggtt = &i915->ggtt; @@ -2053,21 +2072,8 @@ static struct i915_hw_ppgtt *gen6_ppgtt_create(struct drm_i915_private *i915) if (err) goto err_vma; - err = gen6_ppgtt_pin(&ppgtt->base); - if (err) - goto err_pd; - - DRM_DEBUG_DRIVER("Allocated pde space (%lldM) at GTT entry: %llx\n", - ppgtt->vma->node.size >> 20, - ppgtt->vma->node.start / PAGE_SIZE); - - DRM_DEBUG_DRIVER("Adding PPGTT at offset %x\n", - ppgtt->base.pd.base.ggtt_offset << 10); - return &ppgtt->base; -err_pd: - gen6_ppgtt_free_pd(ppgtt); err_vma: i915_vma_destroy(ppgtt->vma); err_scratch: diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index 6e9acd99ecc61..d7b7b4afe060b 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -412,6 +412,8 @@ struct gen6_hw_ppgtt { struct i915_vma *vma; gen6_pte_t __iomem *pd_addr; + + unsigned int pin_count; }; #define __to_gen6_ppgtt(base) container_of(base, struct gen6_hw_ppgtt, base) @@ -625,6 +627,9 @@ static inline void i915_ppgtt_put(struct i915_hw_ppgtt *ppgtt) kref_put(&ppgtt->ref, i915_ppgtt_release); } +int gen6_ppgtt_pin(struct i915_hw_ppgtt *base); +void gen6_ppgtt_unpin(struct i915_hw_ppgtt *base); + void i915_check_and_clear_faults(struct drm_i915_private *dev_priv); void i915_gem_suspend_gtt_mappings(struct drm_i915_private *dev_priv); void i915_gem_restore_gtt_mappings(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 735622dc73ec2..6a937a8966519 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1179,6 +1179,27 @@ static void intel_ring_context_destroy(struct intel_context *ce) __i915_gem_object_release_unless_active(ce->state->obj); } +static int __context_pin_ppgtt(struct i915_gem_context *ctx) +{ + struct i915_hw_ppgtt *ppgtt; + int err = 0; + + ppgtt = ctx->ppgtt ?: ctx->i915->mm.aliasing_ppgtt; + if (ppgtt) + err = gen6_ppgtt_pin(ppgtt); + + return err; +} + +static void __context_unpin_ppgtt(struct i915_gem_context *ctx) +{ + struct i915_hw_ppgtt *ppgtt; + + ppgtt = ctx->ppgtt ?: ctx->i915->mm.aliasing_ppgtt; + if (ppgtt) + gen6_ppgtt_unpin(ppgtt); +} + static int __context_pin(struct intel_context *ce) { struct i915_vma *vma; @@ -1227,6 +1248,7 @@ static void __context_unpin(struct intel_context *ce) static void intel_ring_context_unpin(struct intel_context *ce) { + __context_unpin_ppgtt(ce->gem_context); __context_unpin(ce); i915_gem_context_put(ce->gem_context); @@ -1324,6 +1346,10 @@ __ring_context_pin(struct intel_engine_cs *engine, if (err) goto err; + err = __context_pin_ppgtt(ce->gem_context); + if (err) + goto err_unpin; + i915_gem_context_get(ctx); /* One ringbuffer to rule them all */ @@ -1332,6 +1358,8 @@ __ring_context_pin(struct intel_engine_cs *engine, return ce; +err_unpin: + __context_unpin(ce); err: ce->pin_count = 0; return ERR_PTR(err); -- GitLab From 5422b37c907e7c00a15d5298d6717c6f7ba1403f Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi <rodrigo.vivi@intel.com> Date: Wed, 13 Jun 2018 12:26:00 -0700 Subject: [PATCH 0278/1506] drm/i915/psr: Kill delays when activating psr back. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The immediate enabling was actually not an issue for the HW perspective for core platforms that have HW tracking. HW will wait few identical idle frames before transitioning to actual psr active anyways. Now that we removed VLV/CHV out of the picture completely we can safely remove any delays. Note that this patch also remove the delayed activation on HSW and BDW introduced by commit 'd0ac896a477d ("drm/i915: Delay first PSR activation.")'. This was introduced to fix a blank screen on VLV/CHV and also masked some frozen screens on other core platforms. Probably the same that we are now properly hunting and fixing. v2:(DK): Remove unnecessary WARN_ONs and make some other VLV | CHV more readable. v3: Do it regardless the timer rework. v4: (DK/CI): Add VLV || CHV check on cancel work at psr_disable. v5: Kill remaining items and fully rework activation functions. v6: Rebase on top of VLV/CHV clean-up and keep the reactivation on a regular non-delayed work to avoid extra delays on exit calls and allow us to add few more safety checks before real activation. Cc: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Reviewed-by: José Roberto de Souza <jose.souza@intel.com> Reviewed-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180613192600.3955-1-rodrigo.vivi@intel.com --- drivers/gpu/drm/i915/i915_debugfs.c | 2 -- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/intel_psr.c | 29 +++++++---------------------- 3 files changed, 8 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 769ab97458342..948b973af0678 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2660,8 +2660,6 @@ static int i915_edp_psr_status(struct seq_file *m, void *data) seq_printf(m, "Enabled: %s\n", yesno((bool)dev_priv->psr.enabled)); seq_printf(m, "Busy frontbuffer bits: 0x%03x\n", dev_priv->psr.busy_frontbuffer_bits); - seq_printf(m, "Re-enable work scheduled: %s\n", - yesno(work_busy(&dev_priv->psr.work.work))); if (dev_priv->psr.psr2_enabled) enabled = I915_READ(EDP_PSR2_CTL) & EDP_PSR2_ENABLE; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index be8c2f0823c46..19defe73b1566 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -613,7 +613,7 @@ struct i915_psr { bool sink_support; struct intel_dp *enabled; bool active; - struct delayed_work work; + struct work_struct work; unsigned busy_frontbuffer_bits; bool sink_psr2_support; bool link_standby; diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 71dfe541740f0..ef0f4741a95d2 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -671,21 +671,7 @@ void intel_psr_enable(struct intel_dp *intel_dp, dev_priv->psr.enable_source(intel_dp, crtc_state); dev_priv->psr.enabled = intel_dp; - if (INTEL_GEN(dev_priv) >= 9) { - intel_psr_activate(intel_dp); - } else { - /* - * FIXME: Activation should happen immediately since this - * function is just called after pipe is fully trained and - * enabled. - * However on some platforms we face issues when first - * activation follows a modeset so quickly. - * - On HSW/BDW we get a recoverable frozen screen until - * next exit-activate sequence. - */ - schedule_delayed_work(&dev_priv->psr.work, - msecs_to_jiffies(intel_dp->panel_power_cycle_delay * 5)); - } + intel_psr_activate(intel_dp); unlock: mutex_unlock(&dev_priv->psr.lock); @@ -768,8 +754,6 @@ void intel_psr_disable(struct intel_dp *intel_dp, dev_priv->psr.enabled = NULL; mutex_unlock(&dev_priv->psr.lock); - - cancel_delayed_work_sync(&dev_priv->psr.work); } static bool psr_wait_for_idle(struct drm_i915_private *dev_priv) @@ -805,10 +789,13 @@ static bool psr_wait_for_idle(struct drm_i915_private *dev_priv) static void intel_psr_work(struct work_struct *work) { struct drm_i915_private *dev_priv = - container_of(work, typeof(*dev_priv), psr.work.work); + container_of(work, typeof(*dev_priv), psr.work); mutex_lock(&dev_priv->psr.lock); + if (!dev_priv->psr.enabled) + goto unlock; + /* * We have to make sure PSR is ready for re-enable * otherwise it keeps disabled until next full enable/disable cycle. @@ -949,9 +936,7 @@ void intel_psr_flush(struct drm_i915_private *dev_priv, } if (!dev_priv->psr.active && !dev_priv->psr.busy_frontbuffer_bits) - if (!work_busy(&dev_priv->psr.work.work)) - schedule_delayed_work(&dev_priv->psr.work, - msecs_to_jiffies(100)); + schedule_work(&dev_priv->psr.work); mutex_unlock(&dev_priv->psr.lock); } @@ -998,7 +983,7 @@ void intel_psr_init(struct drm_i915_private *dev_priv) dev_priv->psr.link_standby = false; } - INIT_DELAYED_WORK(&dev_priv->psr.work, intel_psr_work); + INIT_WORK(&dev_priv->psr.work, intel_psr_work); mutex_init(&dev_priv->psr.lock); dev_priv->psr.enable_source = hsw_psr_enable_source; -- GitLab From 24a28179ecc0011e41a0fc8034a1a8e0fefbb406 Mon Sep 17 00:00:00 2001 From: Imre Deak <imre.deak@intel.com> Date: Wed, 13 Jun 2018 20:07:06 +0300 Subject: [PATCH 0279/1506] drm/i915/ddi: s/crtc->config/old_crtc_state in haswell_crtc_disable() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit crtc->config points to the old crtc state at the point display.crtc_disable() is called, so use the more descriptive pointer instead. v2: - Convert one remaining instance of the ptr in the function. (Ville) Cc: Vandita Kulkarni <vandita.kulkarni@intel.com> Cc: Paulo Zanoni <paulo.r.zanoni@intel.com> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Imre Deak <imre.deak@intel.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180613170710.15080-2-imre.deak@intel.com --- drivers/gpu/drm/i915/intel_display.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3323470596ca9..59dd97a939cee 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5814,7 +5814,7 @@ static void haswell_crtc_disable(struct intel_crtc_state *old_crtc_state, struct drm_crtc *crtc = old_crtc_state->base.crtc; struct drm_i915_private *dev_priv = to_i915(crtc->dev); struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder; + enum transcoder cpu_transcoder = old_crtc_state->cpu_transcoder; intel_encoders_disable(crtc, old_crtc_state, old_state); @@ -5825,8 +5825,8 @@ static void haswell_crtc_disable(struct intel_crtc_state *old_crtc_state, if (!transcoder_is_dsi(cpu_transcoder)) intel_disable_pipe(old_crtc_state); - if (intel_crtc_has_type(intel_crtc->config, INTEL_OUTPUT_DP_MST)) - intel_ddi_set_vc_payload_alloc(intel_crtc->config, false); + if (intel_crtc_has_type(old_crtc_state, INTEL_OUTPUT_DP_MST)) + intel_ddi_set_vc_payload_alloc(old_crtc_state, false); if (!transcoder_is_dsi(cpu_transcoder)) intel_ddi_disable_transcoder_func(dev_priv, cpu_transcoder); @@ -5837,7 +5837,7 @@ static void haswell_crtc_disable(struct intel_crtc_state *old_crtc_state, ironlake_pfit_disable(intel_crtc, false); if (!transcoder_is_dsi(cpu_transcoder)) - intel_ddi_disable_pipe_clock(intel_crtc->config); + intel_ddi_disable_pipe_clock(old_crtc_state); intel_encoders_post_disable(crtc, old_crtc_state, old_state); -- GitLab From afb2c4437daeed2d0c49e246ad1ad4def5d913cd Mon Sep 17 00:00:00 2001 From: Imre Deak <imre.deak@intel.com> Date: Wed, 13 Jun 2018 20:27:46 +0300 Subject: [PATCH 0280/1506] drm/i915/ddi: Push pipe clock enabling to encoders MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On ICL the pipe clock needs to be enabled before setting the HDMI infoframe, but these steps are in the reverse order atm. Move the pipe clock enabling to the encoders, so reordering of the two steps can be done in a clean way. No functional change. v2: - Rebased on drm-tip. Cc: Vandita Kulkarni <vandita.kulkarni@intel.com> Cc: Paulo Zanoni <paulo.r.zanoni@intel.com> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Imre Deak <imre.deak@intel.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180613172746.18525-1-imre.deak@intel.com --- drivers/gpu/drm/i915/intel_crt.c | 4 ++++ drivers/gpu/drm/i915/intel_ddi.c | 8 ++++++++ drivers/gpu/drm/i915/intel_display.c | 6 ------ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 95aa29cf2d9c3..87c72c39f409c 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -232,6 +232,8 @@ static void hsw_post_disable_crt(struct intel_encoder *encoder, { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + intel_ddi_disable_pipe_clock(old_crtc_state); + pch_post_disable_crt(encoder, old_crtc_state, old_conn_state); lpt_disable_pch_transcoder(dev_priv); @@ -268,6 +270,8 @@ static void hsw_pre_enable_crt(struct intel_encoder *encoder, intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false); dev_priv->display.fdi_link_train(crtc, crtc_state); + + intel_ddi_enable_pipe_clock(crtc_state); } static void hsw_enable_crt(struct intel_encoder *encoder, diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index ca73387bd5964..df0e64a9721a5 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -2639,6 +2639,8 @@ static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder, intel_dp_start_link_train(intel_dp); if (port != PORT_A || INTEL_GEN(dev_priv) >= 9) intel_dp_stop_link_train(intel_dp); + + intel_ddi_enable_pipe_clock(crtc_state); } static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder, @@ -2672,6 +2674,8 @@ static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder, intel_dig_port->set_infoframes(&encoder->base, crtc_state->has_infoframe, crtc_state, conn_state); + + intel_ddi_enable_pipe_clock(crtc_state); } static void intel_ddi_pre_enable(struct intel_encoder *encoder, @@ -2738,6 +2742,8 @@ static void intel_ddi_post_disable_dp(struct intel_encoder *encoder, bool is_mst = intel_crtc_has_type(old_crtc_state, INTEL_OUTPUT_DP_MST); + intel_ddi_disable_pipe_clock(old_crtc_state); + /* * Power down sink before disabling the port, otherwise we end * up getting interrupts from the sink on detecting link loss. @@ -2763,6 +2769,8 @@ static void intel_ddi_post_disable_hdmi(struct intel_encoder *encoder, struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base); struct intel_hdmi *intel_hdmi = &dig_port->hdmi; + intel_ddi_disable_pipe_clock(old_crtc_state); + intel_disable_ddi_buf(encoder); dig_port->set_infoframes(&encoder->base, false, diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 59dd97a939cee..05abd23b526fc 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5647,9 +5647,6 @@ static void haswell_crtc_enable(struct intel_crtc_state *pipe_config, intel_encoders_pre_enable(crtc, pipe_config, old_state); - if (!transcoder_is_dsi(cpu_transcoder)) - intel_ddi_enable_pipe_clock(pipe_config); - if (intel_crtc_has_dp_encoder(intel_crtc->config)) intel_dp_set_m_n(intel_crtc, M1_N1); @@ -5836,9 +5833,6 @@ static void haswell_crtc_disable(struct intel_crtc_state *old_crtc_state, else ironlake_pfit_disable(intel_crtc, false); - if (!transcoder_is_dsi(cpu_transcoder)) - intel_ddi_disable_pipe_clock(old_crtc_state); - intel_encoders_post_disable(crtc, old_crtc_state, old_state); if (INTEL_GEN(dev_priv) >= 11) -- GitLab From 8fc0aa6eaa568caf72adb8482bf33738d579c32d Mon Sep 17 00:00:00 2001 From: Imre Deak <imre.deak@intel.com> Date: Wed, 13 Jun 2018 20:07:08 +0300 Subject: [PATCH 0281/1506] drm/i915/ddi: Check transcoder instead of port when setting HDMI infoframe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The only requirement by BSpec for setting the HDMI infoframes is on DDI platforms to do that before enabling the HDMI transcoder function, see VIDEO_DIP_CTL bit 16. Accordingly check for the transcoder function disabled state instead of the port's disabled state on DDI platforms. This is needed by the next patch as it will set the infoframe during crtc disabling where the port is still enabled. Suggested-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Cc: Vandita Kulkarni <vandita.kulkarni@intel.com> Cc: Paulo Zanoni <paulo.r.zanoni@intel.com> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Imre Deak <imre.deak@intel.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180613170710.15080-4-imre.deak@intel.com --- drivers/gpu/drm/i915/intel_hdmi.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 447ffe590e555..e88cdd9ab1b1a 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -59,6 +59,15 @@ assert_hdmi_port_disabled(struct intel_hdmi *intel_hdmi) "HDMI port enabled, expecting disabled\n"); } +static void +assert_hdmi_transcoder_func_disabled(struct drm_i915_private *dev_priv, + enum transcoder cpu_transcoder) +{ + WARN(I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder)) & + TRANS_DDI_FUNC_ENABLE, + "HDMI transcoder function enabled, expecting disabled\n"); +} + struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder) { struct intel_digital_port *intel_dig_port = @@ -834,11 +843,11 @@ static void hsw_set_infoframes(struct drm_encoder *encoder, const struct drm_connector_state *conn_state) { struct drm_i915_private *dev_priv = to_i915(encoder->dev); - struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); i915_reg_t reg = HSW_TVIDEO_DIP_CTL(crtc_state->cpu_transcoder); u32 val = I915_READ(reg); - assert_hdmi_port_disabled(intel_hdmi); + assert_hdmi_transcoder_func_disabled(dev_priv, + crtc_state->cpu_transcoder); val &= ~(VIDEO_DIP_ENABLE_VSC_HSW | VIDEO_DIP_ENABLE_AVI_HSW | VIDEO_DIP_ENABLE_GCP_HSW | VIDEO_DIP_ENABLE_VS_HSW | -- GitLab From c737376442e26c84ef188e7c829e15d42928fc03 Mon Sep 17 00:00:00 2001 From: Imre Deak <imre.deak@intel.com> Date: Wed, 13 Jun 2018 20:07:09 +0300 Subject: [PATCH 0282/1506] drm/i915/ddi: Set HDMI infoframes with pipe clocks enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On ICL for setting the HDMI infoframe the pipe clock needs to be enabled, otherwise accessing the VIDEO_DIP_CTL register will hang the machine. Cc: Vandita Kulkarni <vandita.kulkarni@intel.com> Cc: Paulo Zanoni <paulo.r.zanoni@intel.com> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Imre Deak <imre.deak@intel.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180613170710.15080-5-imre.deak@intel.com --- drivers/gpu/drm/i915/intel_ddi.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index df0e64a9721a5..936ff5a0b5222 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -2671,11 +2671,11 @@ static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder, if (IS_GEN9_BC(dev_priv)) skl_ddi_set_iboost(encoder, level, INTEL_OUTPUT_HDMI); + intel_ddi_enable_pipe_clock(crtc_state); + intel_dig_port->set_infoframes(&encoder->base, crtc_state->has_infoframe, crtc_state, conn_state); - - intel_ddi_enable_pipe_clock(crtc_state); } static void intel_ddi_pre_enable(struct intel_encoder *encoder, @@ -2769,13 +2769,13 @@ static void intel_ddi_post_disable_hdmi(struct intel_encoder *encoder, struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base); struct intel_hdmi *intel_hdmi = &dig_port->hdmi; + dig_port->set_infoframes(&encoder->base, false, + old_crtc_state, old_conn_state); + intel_ddi_disable_pipe_clock(old_crtc_state); intel_disable_ddi_buf(encoder); - dig_port->set_infoframes(&encoder->base, false, - old_crtc_state, old_conn_state); - intel_display_power_put(dev_priv, dig_port->ddi_io_power_domain); intel_ddi_clk_disable(encoder); -- GitLab From 3b567bb059b960a222c08d4d795360beb97e8551 Mon Sep 17 00:00:00 2001 From: Imre Deak <imre.deak@intel.com> Date: Wed, 13 Jun 2018 20:07:10 +0300 Subject: [PATCH 0283/1506] drm/i915/ddi: Removed unused var from hsw_write_infoframe() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Vandita Kulkarni <vandita.kulkarni@intel.com> Cc: Paulo Zanoni <paulo.r.zanoni@intel.com> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Imre Deak <imre.deak@intel.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180613170710.15080-6-imre.deak@intel.com --- drivers/gpu/drm/i915/intel_hdmi.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index e88cdd9ab1b1a..9a33432c1f6b2 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -390,14 +390,11 @@ static void hsw_write_infoframe(struct drm_encoder *encoder, struct drm_i915_private *dev_priv = to_i915(dev); enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; i915_reg_t ctl_reg = HSW_TVIDEO_DIP_CTL(cpu_transcoder); - i915_reg_t data_reg; int data_size = type == DP_SDP_VSC ? VIDEO_DIP_VSC_DATA_SIZE : VIDEO_DIP_DATA_SIZE; int i; u32 val = I915_READ(ctl_reg); - data_reg = hsw_dip_data_reg(dev_priv, cpu_transcoder, type, 0); - val &= ~hsw_infoframe_enable(type); I915_WRITE(ctl_reg, val); -- GitLab From 132c27c97cb958f637dc05adc35a61b47779bcd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Mon, 11 Jun 2018 23:02:55 +0300 Subject: [PATCH 0284/1506] drm/i915: Fix PIPESTAT irq ack on i965/g4x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On i965/g4x IIR is edge triggered. So in order for IIR to notice that there is still a pending interrupt we have to force and edge in ISR. For the ISR/IIR pipe event bits we can do that by temporarily clearing all the PIPESTAT enable bits when we ack the status bits. This will force the ISR pipe event bit low, and it can then go back high when we restore the PIPESTAT enable bits. This avoids the following race: 1. stat = read(PIPESTAT) 2. an enabled PIPESTAT status bit goes high 3. write(PIPESTAT, enable|stat); 4. write(IIR, PIPE_EVENT) The end result is IIR==0 and ISR!=0. This can lead to nasty vblank wait/flip_done timeouts if another interrupt source doesn't trick us into looking at the PIPESTAT status bits despite the IIR PIPE_EVENT bit being low. Before i965 IIR was level triggered so this problem can't actually happen there. And curiously VLV/CHV went back to the level triggered scheme as well. But for simplicity we'll use the same i965/g4x compatible code for all platforms. Cc: stable@vger.kernel.org Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=106033 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=105225 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=106030 Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180611200258.27121-1-ville.syrjala@linux.intel.com Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> --- drivers/gpu/drm/i915/i915_irq.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index c52060a353176..d5aee0b74f4b4 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1893,9 +1893,17 @@ static void i9xx_pipestat_irq_ack(struct drm_i915_private *dev_priv, /* * Clear the PIPE*STAT regs before the IIR + * + * Toggle the enable bits to make sure we get an + * edge in the ISR pipe event bit if we don't clear + * all the enabled status bits. Otherwise the edge + * triggered IIR on i965/g4x wouldn't notice that + * an interrupt is still pending. */ - if (pipe_stats[pipe]) - I915_WRITE(reg, enable_mask | pipe_stats[pipe]); + if (pipe_stats[pipe]) { + I915_WRITE(reg, pipe_stats[pipe]); + I915_WRITE(reg, enable_mask); + } } spin_unlock(&dev_priv->irq_lock); } -- GitLab From 929168c5f3df5d9ea0ef426c33e971157d045eab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Wed, 13 Jun 2018 19:05:52 +0300 Subject: [PATCH 0285/1506] drm/i915: Disallow interlaced modes on g4x DP outputs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Looks like interlaced DP output doesn't work on g4x either. Not all that surprising considering we already established that interlaced DP output is busted on VLV/CHV. Cc: stable@vger.kernel.org Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180613160553.11664-1-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/intel_dp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index a58bac01aeeae..2fe85c63d5ceb 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1875,7 +1875,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) return false; - if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) && + if (HAS_GMCH_DISPLAY(dev_priv) && adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) return false; @@ -6357,7 +6357,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, drm_connector_init(dev, connector, &intel_dp_connector_funcs, type); drm_connector_helper_add(connector, &intel_dp_connector_helper_funcs); - if (!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv)) + if (!HAS_GMCH_DISPLAY(dev_priv)) connector->interlace_allowed = true; connector->doublescan_allowed = 0; -- GitLab From 51a9f6dfc00d35f927ecfaf6f0ae8ebaba39b3fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Wed, 13 Jun 2018 19:05:53 +0300 Subject: [PATCH 0286/1506] drm/i915: Turn off g4x DP port in .post_disable() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While Bspec doesn't list a specific sequence for turning off the DP port on g4x we are getting an underrun if the port is disabled in the .disable() hook. Looks like the pipe stops when the port stops, and by that time the plane disable may not have completed yet. Also the plane(s) seem to end up in some wonky state when this happens as they also signal another underrun immediately after we turn them back on during the next enable sequence. We could add a vblank wait in .disable() to avoid wedging the planes, but I assume we're still tripping up the pipe in some way. So it seems better to me to just follow the ILK+ sequence and turn off the DP port in .post_disable() instead. This sequence doesn't seem to suffer from this problem. Could be it was always the intended sequence for DP and the gen4 bspec was just never updated to include it. Originally we used the bad sequence even on ilk+, but I changed that in commit 08aff3fe26ae ("drm/i915: Move DP port disable to post_disable for pch platforms") as it was causing issues on those platforms as well. I left out g4x then only because I didn't have the hardware to test it. Now that I do it's fairly clear that the ilk+ sequence is also the right choice for g4x. v2: Fix whitespace fail (Jani) Mention the ilk+ commit (Jani) Cc: stable@vger.kernel.org Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180613160553.11664-2-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula <jani.nikula@intel.com> --- drivers/gpu/drm/i915/intel_dp.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 2fe85c63d5ceb..67875b00c8df7 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2809,16 +2809,6 @@ static void intel_disable_dp(struct intel_encoder *encoder, static void g4x_disable_dp(struct intel_encoder *encoder, const struct intel_crtc_state *old_crtc_state, const struct drm_connector_state *old_conn_state) -{ - intel_disable_dp(encoder, old_crtc_state, old_conn_state); - - /* disable the port before the pipe on g4x */ - intel_dp_link_down(encoder, old_crtc_state); -} - -static void ilk_disable_dp(struct intel_encoder *encoder, - const struct intel_crtc_state *old_crtc_state, - const struct drm_connector_state *old_conn_state) { intel_disable_dp(encoder, old_crtc_state, old_conn_state); } @@ -2834,13 +2824,19 @@ static void vlv_disable_dp(struct intel_encoder *encoder, intel_disable_dp(encoder, old_crtc_state, old_conn_state); } -static void ilk_post_disable_dp(struct intel_encoder *encoder, +static void g4x_post_disable_dp(struct intel_encoder *encoder, const struct intel_crtc_state *old_crtc_state, const struct drm_connector_state *old_conn_state) { struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); enum port port = encoder->port; + /* + * Bspec does not list a specific disable sequence for g4x DP. + * Follow the ilk+ sequence (disable pipe before the port) for + * g4x DP as it does not suffer from underruns like the normal + * g4x modeset sequence (disable pipe after the port). + */ intel_dp_link_down(encoder, old_crtc_state); /* Only ilk+ has port A */ @@ -6456,15 +6452,11 @@ bool intel_dp_init(struct drm_i915_private *dev_priv, intel_encoder->enable = vlv_enable_dp; intel_encoder->disable = vlv_disable_dp; intel_encoder->post_disable = vlv_post_disable_dp; - } else if (INTEL_GEN(dev_priv) >= 5) { - intel_encoder->pre_enable = g4x_pre_enable_dp; - intel_encoder->enable = g4x_enable_dp; - intel_encoder->disable = ilk_disable_dp; - intel_encoder->post_disable = ilk_post_disable_dp; } else { intel_encoder->pre_enable = g4x_pre_enable_dp; intel_encoder->enable = g4x_enable_dp; intel_encoder->disable = g4x_disable_dp; + intel_encoder->post_disable = g4x_post_disable_dp; } intel_dig_port->dp.output_reg = output_reg; -- GitLab From 920d3fb1a00c3d7bb24c9b396c8b2950192c5ad8 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 14 Jun 2018 13:49:23 +0100 Subject: [PATCH 0287/1506] drm/i915/selftests: Initialise request to silence a compiler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With an old (4.7.3 on 32bit) gcc, it emits a warning for In file included from drivers/gpu/drm/i915/i915_request.c:1425:0: drivers/gpu/drm/i915/selftests/i915_request.c: In function ‘live_nop_request’: drivers/gpu/drm/i915/selftests/i915_request.c:380:21: error: ‘request’ may be used uninitialized in this function [-Werror=maybe-uninitialized] Silence it by just setting it to NULL on initialisation. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180614124923.18071-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/selftests/i915_request.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/selftests/i915_request.c b/drivers/gpu/drm/i915/selftests/i915_request.c index f5d00332bb31e..63cd9486cc139 100644 --- a/drivers/gpu/drm/i915/selftests/i915_request.c +++ b/drivers/gpu/drm/i915/selftests/i915_request.c @@ -342,9 +342,9 @@ static int live_nop_request(void *arg) mutex_lock(&i915->drm.struct_mutex); for_each_engine(engine, i915, id) { - IGT_TIMEOUT(end_time); - struct i915_request *request; + struct i915_request *request = NULL; unsigned long n, prime; + IGT_TIMEOUT(end_time); ktime_t times[2] = {}; err = begin_live_test(&t, i915, __func__, engine->name); -- GitLab From 5db1d4ea91b6ee447c4ae01f7f56803e32e690b1 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Mon, 4 Jun 2018 08:34:40 +0100 Subject: [PATCH 0288/1506] drm/i915/execlists: Push the tasklet kick after reset to reset_finish In the unlikely case where we have failed to keep submitting to the GPU, we end up with the ELSP queue empty but a pending queue of requests. Here, we skip the per-engine reset as there is no guilty request, but in doing so we also skip the engine restart leaving ourselves with a permanently hung engine. A quick way to recover is by moving the tasklet kick to execlists_reset_finish() (from init_hw). We still emit the error on hanging, so the error is not lost but we should be able to recover. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Mika Kuoppala <mika.kuoppala@intel.com> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Cc: Michel Thierry <michel.thierry@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180604073441.6737-2-chris@chris-wilson.co.uk Reviewed-by: Mika Kuoppala <mika.kuoppala@intel.com> --- drivers/gpu/drm/i915/intel_lrc.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 44e4c9e075712..8d56bcb009798 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1811,7 +1811,6 @@ static bool unexpected_starting_state(struct intel_engine_cs *engine) static int gen8_init_common_ring(struct intel_engine_cs *engine) { - struct intel_engine_execlists * const execlists = &engine->execlists; int ret; ret = intel_mocs_init_engine(engine); @@ -1829,10 +1828,6 @@ static int gen8_init_common_ring(struct intel_engine_cs *engine) enable_execlists(engine); - /* After a GPU reset, we may have requests to replay */ - if (execlists->first) - tasklet_schedule(&execlists->tasklet); - return 0; } @@ -2015,6 +2010,12 @@ static void execlists_reset(struct intel_engine_cs *engine, static void execlists_reset_finish(struct intel_engine_cs *engine) { + struct intel_engine_execlists * const execlists = &engine->execlists; + + /* After a GPU reset, we may have requests to replay */ + if (execlists->first) + tasklet_schedule(&execlists->tasklet); + /* * Flush the tasklet while we still have the forcewake to be sure * that it is not allowed to sleep before we restart and reload a @@ -2024,7 +2025,7 @@ static void execlists_reset_finish(struct intel_engine_cs *engine) * serialising multiple attempts to reset so that we know that we * are the only one manipulating tasklet state. */ - __tasklet_enable_sync_once(&engine->execlists.tasklet); + __tasklet_enable_sync_once(&execlists->tasklet); GEM_TRACE("%s\n", engine->name); } -- GitLab From 1fd00c0faeec0a89dfe97de842facbecc8a04efb Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Sat, 2 Jun 2018 11:48:53 +0100 Subject: [PATCH 0289/1506] drm/i915: Declare the driver wedged if hangcheck makes no progress Hangcheck is our back up in case the GPU or the driver gets stuck. It detects when the GPU is not making any progress and issues a GPU reset. However, if the driver is failing to make any progress, we can get ourselves into a situation where we continually try resetting the GPU to no avail. Employ a second timeout such that if we continue to see the same seqno (the stalled engine has made no progress at all) over the course of several hangchecks, declare the driver wedged and attempt to start afresh. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Mika Kuoppala <mika.kuoppala@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180602104853.17140-1-chris@chris-wilson.co.uk Reviewed-by: Mika Kuoppala <mika.kuoppala@intel.com> --- drivers/gpu/drm/i915/i915_debugfs.c | 5 +++-- drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/intel_hangcheck.c | 17 ++++++++++++++++- drivers/gpu/drm/i915/intel_ringbuffer.h | 3 ++- 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 948b973af0678..99d3272d82d80 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1359,11 +1359,12 @@ static int i915_hangcheck_info(struct seq_file *m, void *unused) seq_printf(m, "\tseqno = %x [current %x, last %x]\n", engine->hangcheck.seqno, seqno[id], intel_engine_last_submit(engine)); - seq_printf(m, "\twaiters? %s, fake irq active? %s, stalled? %s\n", + seq_printf(m, "\twaiters? %s, fake irq active? %s, stalled? %s, wedged? %s\n", yesno(intel_engine_has_waiter(engine)), yesno(test_bit(engine->id, &dev_priv->gpu_error.missed_irq_rings)), - yesno(engine->hangcheck.stalled)); + yesno(engine->hangcheck.stalled), + yesno(engine->hangcheck.wedged)); spin_lock_irq(&b->rb_lock); for (rb = rb_first(&b->waiters); rb; rb = rb_next(rb)) { diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 19defe73b1566..74dd88d8563e6 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1006,6 +1006,8 @@ struct i915_gem_mm { #define I915_ENGINE_DEAD_TIMEOUT (4 * HZ) /* Seqno, head and subunits dead */ #define I915_SEQNO_DEAD_TIMEOUT (12 * HZ) /* Seqno dead with active head */ +#define I915_ENGINE_WEDGED_TIMEOUT (60 * HZ) /* Reset but no recovery? */ + enum modeset_restore { MODESET_ON_LID_OPEN, MODESET_DONE, diff --git a/drivers/gpu/drm/i915/intel_hangcheck.c b/drivers/gpu/drm/i915/intel_hangcheck.c index d47e346bd49e9..2fc7a0dd0df9b 100644 --- a/drivers/gpu/drm/i915/intel_hangcheck.c +++ b/drivers/gpu/drm/i915/intel_hangcheck.c @@ -294,6 +294,7 @@ static void hangcheck_store_sample(struct intel_engine_cs *engine, engine->hangcheck.seqno = hc->seqno; engine->hangcheck.action = hc->action; engine->hangcheck.stalled = hc->stalled; + engine->hangcheck.wedged = hc->wedged; } static enum intel_engine_hangcheck_action @@ -368,6 +369,9 @@ static void hangcheck_accumulate_sample(struct intel_engine_cs *engine, hc->stalled = time_after(jiffies, engine->hangcheck.action_timestamp + timeout); + hc->wedged = time_after(jiffies, + engine->hangcheck.action_timestamp + + I915_ENGINE_WEDGED_TIMEOUT); } static void hangcheck_declare_hang(struct drm_i915_private *i915, @@ -409,7 +413,7 @@ static void i915_hangcheck_elapsed(struct work_struct *work) gpu_error.hangcheck_work.work); struct intel_engine_cs *engine; enum intel_engine_id id; - unsigned int hung = 0, stuck = 0; + unsigned int hung = 0, stuck = 0, wedged = 0; if (!i915_modparams.enable_hangcheck) return; @@ -440,6 +444,17 @@ static void i915_hangcheck_elapsed(struct work_struct *work) if (hc.action != ENGINE_DEAD) stuck |= intel_engine_flag(engine); } + + if (engine->hangcheck.wedged) + wedged |= intel_engine_flag(engine); + } + + if (wedged) { + dev_err(dev_priv->drm.dev, + "GPU recovery timed out," + " cancelling all in-flight rendering.\n"); + GEM_TRACE_DUMP(); + i915_gem_set_wedged(dev_priv); } if (hung) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 2c35dd3525a6e..4003f3ebe3d1b 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -122,7 +122,8 @@ struct intel_engine_hangcheck { int deadlock; struct intel_instdone instdone; struct i915_request *active_request; - bool stalled; + bool stalled:1; + bool wedged:1; }; struct intel_ring { -- GitLab From 549fe88bf71d30563f20dcfd7970b7424bf07907 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 14 Jun 2018 14:43:14 +0100 Subject: [PATCH 0290/1506] drm/i915/gtt: Lazily allocate page directories for gen7 As we were only supporting aliasing_ppgtt on gen7 for some time, we saved a few checks by preallocating the page directories on creation. However, since we need 2MiB of page directories for each ppgtt, to support arbitrary numbers of user contexts, we need to be more prudent in our allocations, and defer the page allocation until it is used. We don't recover unused pages yet as we found that doing so on the fly (i.e. altering TLB entries) would confuse the GPU. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: Matthew Auld <matthew.william.auld@gmail.com> Reviewed-by: Matthew Auld <matthew.william.auld@gmail.com> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180614134315.5900-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_gtt.c | 67 +++++++++++------------------ 1 file changed, 26 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 0ee9e154359fd..6a62c40b241ca 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -190,11 +190,19 @@ int intel_sanitize_enable_ppgtt(struct drm_i915_private *dev_priv, return 1; } -static int gen6_ppgtt_bind_vma(struct i915_vma *vma, - enum i915_cache_level cache_level, - u32 unused) +static int ppgtt_bind_vma(struct i915_vma *vma, + enum i915_cache_level cache_level, + u32 unused) { u32 pte_flags; + int err; + + if (!(vma->flags & I915_VMA_LOCAL_BIND)) { + err = vma->vm->allocate_va_range(vma->vm, + vma->node.start, vma->size); + if (err) + return err; + } /* Currently applicable only to VLV */ pte_flags = 0; @@ -206,22 +214,6 @@ static int gen6_ppgtt_bind_vma(struct i915_vma *vma, return 0; } -static int gen8_ppgtt_bind_vma(struct i915_vma *vma, - enum i915_cache_level cache_level, - u32 unused) -{ - int ret; - - if (!(vma->flags & I915_VMA_LOCAL_BIND)) { - ret = vma->vm->allocate_va_range(vma->vm, - vma->node.start, vma->size); - if (ret) - return ret; - } - - return gen6_ppgtt_bind_vma(vma, cache_level, unused); -} - static void ppgtt_unbind_vma(struct i915_vma *vma) { vma->vm->clear_range(vma->vm, vma->node.start, vma->size); @@ -1622,7 +1614,7 @@ static struct i915_hw_ppgtt *gen8_ppgtt_create(struct drm_i915_private *i915) ppgtt->vm.cleanup = gen8_ppgtt_cleanup; ppgtt->debug_dump = gen8_dump_ppgtt; - ppgtt->vm.vma_ops.bind_vma = gen8_ppgtt_bind_vma; + ppgtt->vm.vma_ops.bind_vma = ppgtt_bind_vma; ppgtt->vm.vma_ops.unbind_vma = ppgtt_unbind_vma; ppgtt->vm.vma_ops.set_pages = ppgtt_set_pages; ppgtt->vm.vma_ops.clear_pages = clear_pages; @@ -1776,7 +1768,8 @@ static void gen6_ppgtt_clear_range(struct i915_address_space *vm, num_entries -= end - pte; - /* Note that the hw doesn't support removing PDE on the fly + /* + * Note that the hw doesn't support removing PDE on the fly * (they are cached inside the context with no means to * invalidate the cache), so we can only reset the PTE * entries back to scratch. @@ -2046,12 +2039,13 @@ static struct i915_hw_ppgtt *gen6_ppgtt_create(struct drm_i915_private *i915) ppgtt->base.vm.total = I915_PDES * GEN6_PTES * PAGE_SIZE; + ppgtt->base.vm.allocate_va_range = gen6_alloc_va_range; ppgtt->base.vm.clear_range = gen6_ppgtt_clear_range; ppgtt->base.vm.insert_entries = gen6_ppgtt_insert_entries; ppgtt->base.vm.cleanup = gen6_ppgtt_cleanup; ppgtt->base.debug_dump = gen6_dump_ppgtt; - ppgtt->base.vm.vma_ops.bind_vma = gen6_ppgtt_bind_vma; + ppgtt->base.vm.vma_ops.bind_vma = ppgtt_bind_vma; ppgtt->base.vm.vma_ops.unbind_vma = ppgtt_unbind_vma; ppgtt->base.vm.vma_ops.set_pages = ppgtt_set_pages; ppgtt->base.vm.vma_ops.clear_pages = clear_pages; @@ -2068,14 +2062,8 @@ static struct i915_hw_ppgtt *gen6_ppgtt_create(struct drm_i915_private *i915) goto err_scratch; } - err = gen6_alloc_va_range(&ppgtt->base.vm, 0, ppgtt->base.vm.total); - if (err) - goto err_vma; - return &ppgtt->base; -err_vma: - i915_vma_destroy(ppgtt->vma); err_scratch: gen6_ppgtt_free_scratch(&ppgtt->base.vm); err_free: @@ -2671,8 +2659,7 @@ static int aliasing_gtt_bind_vma(struct i915_vma *vma, if (flags & I915_VMA_LOCAL_BIND) { struct i915_hw_ppgtt *appgtt = i915->mm.aliasing_ppgtt; - if (!(vma->flags & I915_VMA_LOCAL_BIND) && - appgtt->vm.allocate_va_range) { + if (!(vma->flags & I915_VMA_LOCAL_BIND)) { ret = appgtt->vm.allocate_va_range(&appgtt->vm, vma->node.start, vma->size); @@ -2776,17 +2763,15 @@ int i915_gem_init_aliasing_ppgtt(struct drm_i915_private *i915) goto err_ppgtt; } - if (ppgtt->vm.allocate_va_range) { - /* Note we only pre-allocate as far as the end of the global - * GTT. On 48b / 4-level page-tables, the difference is very, - * very significant! We have to preallocate as GVT/vgpu does - * not like the page directory disappearing. - */ - err = ppgtt->vm.allocate_va_range(&ppgtt->vm, - 0, ggtt->vm.total); - if (err) - goto err_ppgtt; - } + /* + * Note we only pre-allocate as far as the end of the global + * GTT. On 48b / 4-level page-tables, the difference is very, + * very significant! We have to preallocate as GVT/vgpu does + * not like the page directory disappearing. + */ + err = ppgtt->vm.allocate_va_range(&ppgtt->vm, 0, ggtt->vm.total); + if (err) + goto err_ppgtt; i915->mm.aliasing_ppgtt = ppgtt; -- GitLab From 4a192c7e8b14a2bf8f30b1fac3599a7d391dfcf9 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 14 Jun 2018 14:43:15 +0100 Subject: [PATCH 0291/1506] drm/i915/gtt: Free unused page tables on unbind the context As we cannot reliably change used page tables while the context is active, the earliest opportunity we have to recover excess pages is when the context becomes idle. So whenever we unbind the context (it must be idle, and indeed being evicted) free the unused ptes. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: Matthew Auld <matthew.william.auld@gmail.com> Reviewed-by: Matthew Auld <matthew.william.auld@gmail.com> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180614134315.5900-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_gtt.c | 44 +++++++++++++++++++++++++---- drivers/gpu/drm/i915/i915_gem_gtt.h | 1 + 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 6a62c40b241ca..50160be6357ed 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1753,20 +1753,28 @@ static void gen6_ppgtt_enable(struct drm_i915_private *dev_priv) static void gen6_ppgtt_clear_range(struct i915_address_space *vm, u64 start, u64 length) { - struct i915_hw_ppgtt *ppgtt = i915_vm_to_ppgtt(vm); + struct gen6_hw_ppgtt *ppgtt = to_gen6_ppgtt(i915_vm_to_ppgtt(vm)); unsigned int first_entry = start >> PAGE_SHIFT; unsigned int pde = first_entry / GEN6_PTES; unsigned int pte = first_entry % GEN6_PTES; unsigned int num_entries = length >> PAGE_SHIFT; - gen6_pte_t scratch_pte = + const gen6_pte_t scratch_pte = vm->pte_encode(vm->scratch_page.daddr, I915_CACHE_LLC, 0); while (num_entries) { - struct i915_page_table *pt = ppgtt->pd.page_table[pde++]; - unsigned int end = min(pte + num_entries, GEN6_PTES); + struct i915_page_table *pt = ppgtt->base.pd.page_table[pde++]; + const unsigned int end = min(pte + num_entries, GEN6_PTES); + const unsigned int count = end - pte; gen6_pte_t *vaddr; - num_entries -= end - pte; + GEM_BUG_ON(pt == vm->scratch_pt); + + num_entries -= count; + + GEM_BUG_ON(count > pt->used_ptes); + pt->used_ptes -= count; + if (!pt->used_ptes) + ppgtt->scan_for_unused_pt = true; /* * Note that the hw doesn't support removing PDE on the fly @@ -1798,6 +1806,8 @@ static void gen6_ppgtt_insert_entries(struct i915_address_space *vm, struct sgt_dma iter = sgt_dma(vma); gen6_pte_t *vaddr; + GEM_BUG_ON(ppgtt->pd.page_table[act_pt] == vm->scratch_pt); + vaddr = kmap_atomic_px(ppgtt->pd.page_table[act_pt]); do { vaddr[act_pte] = pte_encode | GEN6_PTE_ADDR_ENCODE(iter.dma); @@ -1833,6 +1843,8 @@ static int gen6_alloc_va_range(struct i915_address_space *vm, bool flush = false; gen6_for_each_pde(pt, &ppgtt->base.pd, start, length, pde) { + const unsigned int count = gen6_pte_count(start, length); + if (pt == vm->scratch_pt) { pt = alloc_pt(vm); if (IS_ERR(pt)) @@ -1846,7 +1858,11 @@ static int gen6_alloc_va_range(struct i915_address_space *vm, gen6_write_pde(ppgtt, pde, pt); flush = true; } + + GEM_BUG_ON(pt->used_ptes); } + + pt->used_ptes += count; } if (flush) { @@ -1948,6 +1964,24 @@ static int pd_vma_bind(struct i915_vma *vma, static void pd_vma_unbind(struct i915_vma *vma) { + struct gen6_hw_ppgtt *ppgtt = vma->private; + struct i915_page_table * const scratch_pt = ppgtt->base.vm.scratch_pt; + struct i915_page_table *pt; + unsigned int pde; + + if (!ppgtt->scan_for_unused_pt) + return; + + /* Free all no longer used page tables */ + gen6_for_all_pdes(pt, &ppgtt->base.pd, pde) { + if (pt->used_ptes || pt == scratch_pt) + continue; + + free_pt(&ppgtt->base.vm, pt); + ppgtt->base.pd.page_table[pde] = scratch_pt; + } + + ppgtt->scan_for_unused_pt = false; } static const struct i915_vma_ops pd_vma_ops = { diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index d7b7b4afe060b..46c95d1885804 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -414,6 +414,7 @@ struct gen6_hw_ppgtt { gen6_pte_t __iomem *pd_addr; unsigned int pin_count; + bool scan_for_unused_pt; }; #define __to_gen6_ppgtt(base) container_of(base, struct gen6_hw_ppgtt, base) -- GitLab From 986dbac4803c7eb2be0d0dac7bc642744502d080 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 14 Jun 2018 19:42:17 +0100 Subject: [PATCH 0292/1506] drm/i915/gtt: Cache the PTE encoding of the scratch page As the most frequent PTE encoding is for the scratch page, cache it upon creation. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: Matthew Auld <matthew.william.auld@gmail.com> Reviewed-by: Matthew Auld <matthew.william.auld@gmail.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180614184218.1606-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_gtt.c | 20 ++++++++++---------- drivers/gpu/drm/i915/i915_gem_gtt.h | 1 + 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 50160be6357ed..dec8a8401c2dc 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -640,11 +640,10 @@ static void gen8_initialize_pt(struct i915_address_space *vm, gen8_pte_encode(vm->scratch_page.daddr, I915_CACHE_LLC)); } -static void gen6_initialize_pt(struct i915_address_space *vm, +static void gen6_initialize_pt(struct gen6_hw_ppgtt *ppgtt, struct i915_page_table *pt) { - fill32_px(vm, pt, - vm->pte_encode(vm->scratch_page.daddr, I915_CACHE_LLC, 0)); + fill32_px(&ppgtt->base.vm, pt, ppgtt->scratch_pte); } static struct i915_page_directory *alloc_pd(struct i915_address_space *vm) @@ -1631,9 +1630,7 @@ static struct i915_hw_ppgtt *gen8_ppgtt_create(struct drm_i915_private *i915) static void gen6_dump_ppgtt(struct i915_hw_ppgtt *base, struct seq_file *m) { struct gen6_hw_ppgtt *ppgtt = to_gen6_ppgtt(base); - struct i915_address_space *vm = &base->vm; - const gen6_pte_t scratch_pte = - vm->pte_encode(vm->scratch_page.daddr, I915_CACHE_LLC, 0); + const gen6_pte_t scratch_pte = ppgtt->scratch_pte; struct i915_page_table *pt; u32 pte, pde; @@ -1758,8 +1755,7 @@ static void gen6_ppgtt_clear_range(struct i915_address_space *vm, unsigned int pde = first_entry / GEN6_PTES; unsigned int pte = first_entry % GEN6_PTES; unsigned int num_entries = length >> PAGE_SHIFT; - const gen6_pte_t scratch_pte = - vm->pte_encode(vm->scratch_page.daddr, I915_CACHE_LLC, 0); + const gen6_pte_t scratch_pte = ppgtt->scratch_pte; while (num_entries) { struct i915_page_table *pt = ppgtt->base.pd.page_table[pde++]; @@ -1850,7 +1846,7 @@ static int gen6_alloc_va_range(struct i915_address_space *vm, if (IS_ERR(pt)) goto unwind_out; - gen6_initialize_pt(vm, pt); + gen6_initialize_pt(ppgtt, pt); ppgtt->base.pd.page_table[pde] = pt; if (i915_vma_is_bound(ppgtt->vma, @@ -1888,13 +1884,17 @@ static int gen6_ppgtt_init_scratch(struct gen6_hw_ppgtt *ppgtt) if (ret) return ret; + ppgtt->scratch_pte = + vm->pte_encode(vm->scratch_page.daddr, + I915_CACHE_NONE, PTE_READ_ONLY); + vm->scratch_pt = alloc_pt(vm); if (IS_ERR(vm->scratch_pt)) { cleanup_scratch_page(vm); return PTR_ERR(vm->scratch_pt); } - gen6_initialize_pt(vm, vm->scratch_pt); + gen6_initialize_pt(ppgtt, vm->scratch_pt); gen6_for_all_pdes(unused, &ppgtt->base.pd, pde) ppgtt->base.pd.page_table[pde] = vm->scratch_pt; diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index 46c95d1885804..7ff5cc6127710 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -412,6 +412,7 @@ struct gen6_hw_ppgtt { struct i915_vma *vma; gen6_pte_t __iomem *pd_addr; + gen6_pte_t scratch_pte; unsigned int pin_count; bool scan_for_unused_pt; -- GitLab From a0fbacb58ce1b5885475d38338b8ad3e8c86e5e9 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 14 Jun 2018 19:42:18 +0100 Subject: [PATCH 0293/1506] drm/i915/gtt: Reduce a pair of runtime asserts We can stop asserting using WARN_ON as given sufficient CI coverage, we can rely on using GEM_BUG_ON() to catch problems before merging. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: Matthew Auld <matthew.william.auld@gmail.com> Reviewed-by: Matthew Auld <matthew.william.auld@gmail.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180614184218.1606-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_gtt.c | 2 +- drivers/gpu/drm/i915/i915_gem_gtt.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index dec8a8401c2dc..ba1aed07d6dce 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -2792,7 +2792,7 @@ int i915_gem_init_aliasing_ppgtt(struct drm_i915_private *i915) if (IS_ERR(ppgtt)) return PTR_ERR(ppgtt); - if (WARN_ON(ppgtt->vm.total < ggtt->vm.total)) { + if (GEM_WARN_ON(ppgtt->vm.total < ggtt->vm.total)) { err = -ENODEV; goto err_ppgtt; } diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index 7ff5cc6127710..9a4824cae68d2 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -464,8 +464,8 @@ static inline u32 i915_pte_count(u64 addr, u64 length, unsigned int pde_shift) const u64 mask = ~((1ULL << pde_shift) - 1); u64 end; - WARN_ON(length == 0); - WARN_ON(offset_in_page(addr|length)); + GEM_BUG_ON(length == 0); + GEM_BUG_ON(offset_in_page(addr | length)); end = addr + length; -- GitLab From 970888e7d130f19affc72ffbadf05b40b7693a27 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni <paulo.r.zanoni@intel.com> Date: Mon, 21 May 2018 17:25:44 -0700 Subject: [PATCH 0294/1506] drm/i915/icl: add icelake_get_ddi_pll() Implement the hardware state readout code. Thanks to Animesh Manna for spotting this problem. Cc: Animesh Manna <animesh.manna@intel.com> Credits-to: Animesh Manna <animesh.manna@intel.com> Reviewed-by: Lucas De Marchi <lucas.demarchi@intel.com> Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180522002558.29262-11-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/intel_display.c | 42 +++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 05abd23b526fc..1ac375879510e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9209,6 +9209,44 @@ static void cannonlake_get_ddi_pll(struct drm_i915_private *dev_priv, pipe_config->shared_dpll = intel_get_shared_dpll_by_id(dev_priv, id); } +static void icelake_get_ddi_pll(struct drm_i915_private *dev_priv, + enum port port, + struct intel_crtc_state *pipe_config) +{ + enum intel_dpll_id id; + u32 temp; + + /* TODO: TBT pll not implemented. */ + switch (port) { + case PORT_A: + case PORT_B: + temp = I915_READ(DPCLKA_CFGCR0_ICL) & + DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port); + id = temp >> DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(port); + + if (WARN_ON(id != DPLL_ID_ICL_DPLL0 && id != DPLL_ID_ICL_DPLL1)) + return; + break; + case PORT_C: + id = DPLL_ID_ICL_MGPLL1; + break; + case PORT_D: + id = DPLL_ID_ICL_MGPLL2; + break; + case PORT_E: + id = DPLL_ID_ICL_MGPLL3; + break; + case PORT_F: + id = DPLL_ID_ICL_MGPLL4; + break; + default: + MISSING_CASE(port); + return; + } + + pipe_config->shared_dpll = intel_get_shared_dpll_by_id(dev_priv, id); +} + static void bxt_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port, struct intel_crtc_state *pipe_config) @@ -9396,7 +9434,9 @@ static void haswell_get_ddi_port_state(struct intel_crtc *crtc, port = (tmp & TRANS_DDI_PORT_MASK) >> TRANS_DDI_PORT_SHIFT; - if (IS_CANNONLAKE(dev_priv)) + if (IS_ICELAKE(dev_priv)) + icelake_get_ddi_pll(dev_priv, port, pipe_config); + else if (IS_CANNONLAKE(dev_priv)) cannonlake_get_ddi_pll(dev_priv, port, pipe_config); else if (IS_GEN9_BC(dev_priv)) skylake_get_ddi_pll(dev_priv, port, pipe_config); -- GitLab From 00c92d929ac36848fbe88567ef14af947ab636e4 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni <paulo.r.zanoni@intel.com> Date: Mon, 21 May 2018 17:25:47 -0700 Subject: [PATCH 0295/1506] drm/i915/icl: unconditionally init DDI for every port On ICP, port present straps (from SFUSE_STRAP PCH register) are no longer supported. Software should determine the presence through BIOS VBT, hotplug or other mechanisms. v2: Improve commit message (Lucas). Reviewed-by: Lucas De Marchi <lucas.demarchi@intel.com> Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180522002558.29262-14-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/intel_display.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1ac375879510e..9939e092d9aab 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -14045,7 +14045,14 @@ static void intel_setup_outputs(struct drm_i915_private *dev_priv) if (intel_crt_present(dev_priv)) intel_crt_init(dev_priv); - if (IS_GEN9_LP(dev_priv)) { + if (IS_ICELAKE(dev_priv)) { + intel_ddi_init(dev_priv, PORT_A); + intel_ddi_init(dev_priv, PORT_B); + intel_ddi_init(dev_priv, PORT_C); + intel_ddi_init(dev_priv, PORT_D); + intel_ddi_init(dev_priv, PORT_E); + intel_ddi_init(dev_priv, PORT_F); + } else if (IS_GEN9_LP(dev_priv)) { /* * FIXME: Broxton doesn't support port detection via the * DDI_BUF_CTL_A or SFUSE_STRAP registers, find another way to -- GitLab From 1fa11ee2d9d0ccd58a6b56a9e490e336c99e98bf Mon Sep 17 00:00:00 2001 From: Paulo Zanoni <paulo.r.zanoni@intel.com> Date: Mon, 21 May 2018 17:25:48 -0700 Subject: [PATCH 0296/1506] drm/i915/icl: start adding the TBT pll This commit just adds the register addresses and the basic skeleton of the code. The next commits will expand on more specific functions. Reviewed-by: Lucas De Marchi <lucas.demarchi@intel.com> Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180522002558.29262-15-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 6 ++++++ drivers/gpu/drm/i915/intel_ddi.c | 16 ++++++++++++++++ drivers/gpu/drm/i915/intel_dpll_mgr.c | 20 ++++++++++++++++---- drivers/gpu/drm/i915/intel_dpll_mgr.h | 14 +++++++++----- 4 files changed, 47 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 140f6a27d6962..dd60761883196 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -8836,6 +8836,10 @@ enum skl_power_gate { #define DDI_CLK_SEL(port) PORT_CLK_SEL(port) #define DDI_CLK_SEL_NONE (0x0 << 28) #define DDI_CLK_SEL_MG (0x8 << 28) +#define DDI_CLK_SEL_TBT_162 (0xC << 28) +#define DDI_CLK_SEL_TBT_270 (0xD << 28) +#define DDI_CLK_SEL_TBT_540 (0xE << 28) +#define DDI_CLK_SEL_TBT_810 (0xF << 28) #define DDI_CLK_SEL_MASK (0xF << 28) /* Transcoder clock selection */ @@ -8985,6 +8989,8 @@ enum skl_power_gate { #define PLL_POWER_STATE (1 << 26) #define CNL_DPLL_ENABLE(pll) _MMIO_PLL(pll, DPLL0_ENABLE, DPLL1_ENABLE) +#define TBT_PLL_ENABLE _MMIO(0x46020) + #define _MG_PLL1_ENABLE 0x46030 #define _MG_PLL2_ENABLE 0x46034 #define _MG_PLL3_ENABLE 0x46038 diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 936ff5a0b5222..ce153b11c7656 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1062,6 +1062,8 @@ static uint32_t hsw_pll_to_ddi_pll_sel(const struct intel_shared_dpll *pll) static uint32_t icl_pll_to_ddi_pll_sel(struct intel_encoder *encoder, const struct intel_shared_dpll *pll) { + struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); + int clock = crtc->config->port_clock; const enum intel_dpll_id id = pll->info->id; switch (id) { @@ -1070,6 +1072,20 @@ static uint32_t icl_pll_to_ddi_pll_sel(struct intel_encoder *encoder, case DPLL_ID_ICL_DPLL0: case DPLL_ID_ICL_DPLL1: return DDI_CLK_SEL_NONE; + case DPLL_ID_ICL_TBTPLL: + switch (clock) { + case 162000: + return DDI_CLK_SEL_TBT_162; + case 270000: + return DDI_CLK_SEL_TBT_270; + case 540000: + return DDI_CLK_SEL_TBT_540; + case 810000: + return DDI_CLK_SEL_TBT_810; + default: + MISSING_CASE(clock); + break; + } case DPLL_ID_ICL_MGPLL1: case DPLL_ID_ICL_MGPLL2: case DPLL_ID_ICL_MGPLL3: diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c index 07bdbf2582ba1..132fe63e042af 100644 --- a/drivers/gpu/drm/i915/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c @@ -2857,10 +2857,17 @@ icl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state, case PORT_D: case PORT_E: case PORT_F: - min = icl_port_to_mg_pll_id(port); - max = min; - ret = icl_calc_mg_pll_state(crtc_state, encoder, clock, - &pll_state); + if (0 /* TODO: TBT PLLs */) { + min = DPLL_ID_ICL_TBTPLL; + max = min; + ret = icl_calc_dpll_state(crtc_state, encoder, clock, + &pll_state); + } else { + min = icl_port_to_mg_pll_id(port); + max = min; + ret = icl_calc_mg_pll_state(crtc_state, encoder, clock, + &pll_state); + } break; default: MISSING_CASE(port); @@ -2893,6 +2900,8 @@ static i915_reg_t icl_pll_id_to_enable_reg(enum intel_dpll_id id) case DPLL_ID_ICL_DPLL0: case DPLL_ID_ICL_DPLL1: return CNL_DPLL_ENABLE(id); + case DPLL_ID_ICL_TBTPLL: + return TBT_PLL_ENABLE; case DPLL_ID_ICL_MGPLL1: case DPLL_ID_ICL_MGPLL2: case DPLL_ID_ICL_MGPLL3: @@ -2920,6 +2929,7 @@ static bool icl_pll_get_hw_state(struct drm_i915_private *dev_priv, switch (id) { case DPLL_ID_ICL_DPLL0: case DPLL_ID_ICL_DPLL1: + case DPLL_ID_ICL_TBTPLL: hw_state->cfgcr0 = I915_READ(ICL_DPLL_CFGCR0(id)); hw_state->cfgcr1 = I915_READ(ICL_DPLL_CFGCR1(id)); break; @@ -3006,6 +3016,7 @@ static void icl_pll_enable(struct drm_i915_private *dev_priv, switch (id) { case DPLL_ID_ICL_DPLL0: case DPLL_ID_ICL_DPLL1: + case DPLL_ID_ICL_TBTPLL: icl_dpll_write(dev_priv, pll); break; case DPLL_ID_ICL_MGPLL1: @@ -3104,6 +3115,7 @@ static const struct intel_shared_dpll_funcs icl_pll_funcs = { static const struct dpll_info icl_plls[] = { { "DPLL 0", &icl_pll_funcs, DPLL_ID_ICL_DPLL0, 0 }, { "DPLL 1", &icl_pll_funcs, DPLL_ID_ICL_DPLL1, 0 }, + { "TBT PLL", &icl_pll_funcs, DPLL_ID_ICL_TBTPLL, 0 }, { "MG PLL 1", &icl_pll_funcs, DPLL_ID_ICL_MGPLL1, 0 }, { "MG PLL 2", &icl_pll_funcs, DPLL_ID_ICL_MGPLL2, 0 }, { "MG PLL 3", &icl_pll_funcs, DPLL_ID_ICL_MGPLL3, 0 }, diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.h b/drivers/gpu/drm/i915/intel_dpll_mgr.h index 78915057d2e65..ba925c7ee4828 100644 --- a/drivers/gpu/drm/i915/intel_dpll_mgr.h +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.h @@ -113,24 +113,28 @@ enum intel_dpll_id { * @DPLL_ID_ICL_DPLL1: ICL combo PHY DPLL1 */ DPLL_ID_ICL_DPLL1 = 1, + /** + * @DPLL_ID_ICL_TBTPLL: ICL TBT PLL + */ + DPLL_ID_ICL_TBTPLL = 2, /** * @DPLL_ID_ICL_MGPLL1: ICL MG PLL 1 port 1 (C) */ - DPLL_ID_ICL_MGPLL1 = 2, + DPLL_ID_ICL_MGPLL1 = 3, /** * @DPLL_ID_ICL_MGPLL2: ICL MG PLL 1 port 2 (D) */ - DPLL_ID_ICL_MGPLL2 = 3, + DPLL_ID_ICL_MGPLL2 = 4, /** * @DPLL_ID_ICL_MGPLL3: ICL MG PLL 1 port 3 (E) */ - DPLL_ID_ICL_MGPLL3 = 4, + DPLL_ID_ICL_MGPLL3 = 5, /** * @DPLL_ID_ICL_MGPLL4: ICL MG PLL 1 port 4 (F) */ - DPLL_ID_ICL_MGPLL4 = 5, + DPLL_ID_ICL_MGPLL4 = 6, }; -#define I915_NUM_PLLS 6 +#define I915_NUM_PLLS 7 struct intel_dpll_hw_state { /* i9xx, pch plls */ -- GitLab From 46b527d19c4327897197d09748a8b332e322a1d7 Mon Sep 17 00:00:00 2001 From: Manasi Navare <manasi.d.navare@intel.com> Date: Mon, 11 Jun 2018 15:26:54 -0700 Subject: [PATCH 0297/1506] drm/i915/icl: Add allowed DP rates for Icelake For ICL, on Combo PHY the allowed max rates are: - HBR3 8.1 eDP (DDIA) - HBR2 5.4 DisplayPort (DDIB) and for MG PHY/TC DDI Ports allowed DP rates are: - HBR3 8.1 DisplayPort (DP alternate mode, DP over TBT, - DP on legacy connector - DDIC/D/E/F) v2 (from Paulo): Remove misleading comment (Ville). Cc: Rodrigo Vivi <rodrigo.vivi@intel.com> Cc: Jani Nikula <jani.nikula@linux.intel.com> Reviewed-by: James Ausmus <james.ausmus@intel.com> Signed-off-by: Manasi Navare <manasi.d.navare@intel.com> Signed-off-by: James Ausmus <james.ausmus@intel.com> [Paulo: bikeshed to keep future platforms on "else", v2.] Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180611222655.5696-1-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/intel_dp.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 67875b00c8df7..af5314229ffef 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -256,6 +256,17 @@ static int cnl_max_source_rate(struct intel_dp *intel_dp) return 810000; } +static int icl_max_source_rate(struct intel_dp *intel_dp) +{ + struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); + enum port port = dig_port->base.port; + + if (port == PORT_B) + return 540000; + + return 810000; +} + static void intel_dp_set_source_rates(struct intel_dp *intel_dp) { @@ -285,10 +296,13 @@ intel_dp_set_source_rates(struct intel_dp *intel_dp) /* This should only be done once */ WARN_ON(intel_dp->source_rates || intel_dp->num_source_rates); - if (IS_CANNONLAKE(dev_priv)) { + if (INTEL_GEN(dev_priv) >= 10) { source_rates = cnl_rates; size = ARRAY_SIZE(cnl_rates); - max_rate = cnl_max_source_rate(intel_dp); + if (INTEL_GEN(dev_priv) == 10) + max_rate = cnl_max_source_rate(intel_dp); + else + max_rate = icl_max_source_rate(intel_dp); } else if (IS_GEN9_LP(dev_priv)) { source_rates = bxt_rates; size = ARRAY_SIZE(bxt_rates); -- GitLab From 2edd53272120ea3fd32193ef7f921580a534e218 Mon Sep 17 00:00:00 2001 From: Manasi Navare <manasi.d.navare@intel.com> Date: Mon, 11 Jun 2018 15:26:55 -0700 Subject: [PATCH 0298/1506] drm/i915/dp: Add support for HBR3 and TPS4 during link training DP spec 1.4 supports training pattern set 4 (TPS4) for HBR3 link rate. This will be used in link training's channel equalization phase if supported by both source and sink. This patch adds the helpers to check if HBR3 is supported and uses TPS4 in training pattern selection during link training. Cc: Rodrigo Vivi <rodrigo.vivi@intel.com> Cc: Jani Nikula <jani.nikula@linux.intel.com> Reviewed-by: James Ausmus <james.ausmus@intel.com> Signed-off-by: Manasi Navare <manasi.d.navare@intel.com> Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180611222655.5696-2-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_dp.c | 17 ++++++-- drivers/gpu/drm/i915/intel_dp_link_training.c | 39 +++++++++++++------ drivers/gpu/drm/i915/intel_drv.h | 1 + 4 files changed, 44 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index dd60761883196..b8c0ebd508896 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -8703,6 +8703,7 @@ enum skl_power_gate { #define DP_TP_CTL_LINK_TRAIN_PAT1 (0<<8) #define DP_TP_CTL_LINK_TRAIN_PAT2 (1<<8) #define DP_TP_CTL_LINK_TRAIN_PAT3 (4<<8) +#define DP_TP_CTL_LINK_TRAIN_PAT4 (5<<8) #define DP_TP_CTL_LINK_TRAIN_IDLE (2<<8) #define DP_TP_CTL_LINK_TRAIN_NORMAL (3<<8) #define DP_TP_CTL_SCRAMBLE_DISABLE (1<<7) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index af5314229ffef..afa0574c1908a 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1565,6 +1565,13 @@ bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp) return max_rate >= 540000; } +bool intel_dp_source_supports_hbr3(struct intel_dp *intel_dp) +{ + int max_rate = intel_dp->source_rates[intel_dp->num_source_rates - 1]; + + return max_rate >= 810000; +} + static void intel_dp_set_clock(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config) @@ -2889,10 +2896,11 @@ _intel_dp_set_link_train(struct intel_dp *intel_dp, struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); enum port port = intel_dig_port->base.port; + uint8_t train_pat_mask = drm_dp_training_pattern_mask(intel_dp->dpcd); - if (dp_train_pat & DP_TRAINING_PATTERN_MASK) + if (dp_train_pat & train_pat_mask) DRM_DEBUG_KMS("Using DP training pattern TPS%d\n", - dp_train_pat & DP_TRAINING_PATTERN_MASK); + dp_train_pat & train_pat_mask); if (HAS_DDI(dev_priv)) { uint32_t temp = I915_READ(DP_TP_CTL(port)); @@ -2903,7 +2911,7 @@ _intel_dp_set_link_train(struct intel_dp *intel_dp, temp &= ~DP_TP_CTL_SCRAMBLE_DISABLE; temp &= ~DP_TP_CTL_LINK_TRAIN_MASK; - switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) { + switch (dp_train_pat & train_pat_mask) { case DP_TRAINING_PATTERN_DISABLE: temp |= DP_TP_CTL_LINK_TRAIN_NORMAL; @@ -2917,6 +2925,9 @@ _intel_dp_set_link_train(struct intel_dp *intel_dp, case DP_TRAINING_PATTERN_3: temp |= DP_TP_CTL_LINK_TRAIN_PAT3; break; + case DP_TRAINING_PATTERN_4: + temp |= DP_TP_CTL_LINK_TRAIN_PAT4; + break; } I915_WRITE(DP_TP_CTL(port), temp); diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c index 3fcaa98b90555..4da6e33c7fa1c 100644 --- a/drivers/gpu/drm/i915/intel_dp_link_training.c +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c @@ -219,14 +219,30 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp) } /* - * Pick training pattern for channel equalization. Training Pattern 3 for HBR2 + * Pick training pattern for channel equalization. Training pattern 4 for HBR3 + * or for 1.4 devices that support it, training Pattern 3 for HBR2 * or 1.2 devices that support it, Training Pattern 2 otherwise. */ static u32 intel_dp_training_pattern(struct intel_dp *intel_dp) { - u32 training_pattern = DP_TRAINING_PATTERN_2; - bool source_tps3, sink_tps3; + bool source_tps3, sink_tps3, source_tps4, sink_tps4; + /* + * Intel platforms that support HBR3 also support TPS4. It is mandatory + * for all downstream devices that support HBR3. There are no known eDP + * panels that support TPS4 as of Feb 2018 as per VESA eDP_v1.4b_E1 + * specification. + */ + source_tps4 = intel_dp_source_supports_hbr3(intel_dp); + sink_tps4 = drm_dp_tps4_supported(intel_dp->dpcd); + if (source_tps4 && sink_tps4) { + return DP_TRAINING_PATTERN_4; + } else if (intel_dp->link_rate == 810000) { + if (!source_tps4) + DRM_DEBUG_KMS("8.1 Gbps link rate without source HBR3/TPS4 support\n"); + if (!sink_tps4) + DRM_DEBUG_KMS("8.1 Gbps link rate without sink TPS4 support\n"); + } /* * Intel platforms that support HBR2 also support TPS3. TPS3 support is * also mandatory for downstream devices that support HBR2. However, not @@ -234,17 +250,16 @@ static u32 intel_dp_training_pattern(struct intel_dp *intel_dp) */ source_tps3 = intel_dp_source_supports_hbr2(intel_dp); sink_tps3 = drm_dp_tps3_supported(intel_dp->dpcd); - if (source_tps3 && sink_tps3) { - training_pattern = DP_TRAINING_PATTERN_3; - } else if (intel_dp->link_rate == 540000) { + return DP_TRAINING_PATTERN_3; + } else if (intel_dp->link_rate >= 540000) { if (!source_tps3) - DRM_DEBUG_KMS("5.4 Gbps link rate without source HBR2/TPS3 support\n"); + DRM_DEBUG_KMS(">=5.4/6.48 Gbps link rate without source HBR2/TPS3 support\n"); if (!sink_tps3) - DRM_DEBUG_KMS("5.4 Gbps link rate without sink TPS3 support\n"); + DRM_DEBUG_KMS(">=5.4/6.48 Gbps link rate without sink TPS3 support\n"); } - return training_pattern; + return DP_TRAINING_PATTERN_2; } static bool @@ -256,11 +271,13 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp) bool channel_eq = false; training_pattern = intel_dp_training_pattern(intel_dp); + /* Scrambling is disabled for TPS2/3 and enabled for TPS4 */ + if (training_pattern != DP_TRAINING_PATTERN_4) + training_pattern |= DP_LINK_SCRAMBLING_DISABLE; /* channel equalization */ if (!intel_dp_set_link_train(intel_dp, - training_pattern | - DP_LINK_SCRAMBLING_DISABLE)) { + training_pattern)) { DRM_ERROR("failed to start channel equalization\n"); return false; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 8641583842be6..fd2e4de776975 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1715,6 +1715,7 @@ intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t voltage_swing); void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock, uint8_t *link_bw, uint8_t *rate_select); bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp); +bool intel_dp_source_supports_hbr3(struct intel_dp *intel_dp); bool intel_dp_get_link_status(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_STATUS_SIZE]); -- GitLab From 548764bb7ce050afdba15892fb4add79d15974db Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 15 Jun 2018 13:02:07 +0100 Subject: [PATCH 0299/1506] drm/i915: Keep the ctx workarounds tightly packed For each platform, we have a few registers that are rewritten with different values -- they are not part of a sequence, just different parts of a masked register set at different times (e.g. platform and gen workarounds). Consolidate these into a single register write to keep the table compact, important since we are running of room in the current fixed sized buffer. While adjusting the construction of the wa table, make it non fatal so that the driver still loads but keeping the warning and extra details for inspection. Inspecting the changes for a Kabylake system, Before: Address val mask read 0x07014 0x20002000 0x00002000 0x00002100 0x0E194 0x01000100 0x00000100 0x00000114 0x0E4F0 0x81008100 0x00008100 0xFFFF8120 0x0E184 0x00200020 0x00000020 0x00000022 0x0E194 0x00140014 0x00000014 0x00000114 0x07004 0x00420042 0x00000042 0x000029C2 0x0E188 0x00080000 0x00000008 0x00008030 0x07300 0x80208020 0x00008020 0x00008830 0x07300 0x00100010 0x00000010 0x00008830 0x0E184 0x00020002 0x00000002 0x00000022 0x0E180 0x20002000 0x00002000 0x00002000 0x02580 0x00010000 0x00000001 0x00000004 0x02580 0x00060004 0x00000006 0x00000004 0x07014 0x01000100 0x00000100 0x00002100 0x0E100 0x00100010 0x00000010 0x00008050 After: Address val mask read 0x02580 0x00070004 0x00000007 0x00000004 0x07004 0x00420042 0x00000042 0x000029C2 0x07014 0x21002100 0x00002100 0x00002100 0x07300 0x80308030 0x00008030 0x00008830 0x0E100 0x00100010 0x00000010 0x00008050 0x0E180 0x20002000 0x00002000 0x00002000 0x0E184 0x00220022 0x00000022 0x00000022 0x0E188 0x00080000 0x00000008 0x00008030 0x0E194 0x01140114 0x00000114 0x00000114 0x0E4F0 0x81008100 0x00008100 0xFFFF8120 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Oscar Mateo <oscar.mateo@intel.com> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180615120207.13952-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_debugfs.c | 25 ++-------- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/intel_workarounds.c | 63 +++++++++++++++++------- 3 files changed, 52 insertions(+), 38 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 99d3272d82d80..c400f42a54ec7 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -3378,28 +3378,13 @@ static int i915_shared_dplls_info(struct seq_file *m, void *unused) static int i915_wa_registers(struct seq_file *m, void *unused) { - struct drm_i915_private *dev_priv = node_to_i915(m->private); - struct i915_workarounds *workarounds = &dev_priv->workarounds; + struct i915_workarounds *wa = &node_to_i915(m->private)->workarounds; int i; - intel_runtime_pm_get(dev_priv); - - seq_printf(m, "Workarounds applied: %d\n", workarounds->count); - for (i = 0; i < workarounds->count; ++i) { - i915_reg_t addr; - u32 mask, value, read; - bool ok; - - addr = workarounds->reg[i].addr; - mask = workarounds->reg[i].mask; - value = workarounds->reg[i].value; - read = I915_READ(addr); - ok = (value & mask) == (read & mask); - seq_printf(m, "0x%X: 0x%08X, mask: 0x%08X, read: 0x%08x, status: %s\n", - i915_mmio_reg_offset(addr), value, mask, read, ok ? "OK" : "FAIL"); - } - - intel_runtime_pm_put(dev_priv); + seq_printf(m, "Workarounds applied: %d\n", wa->count); + for (i = 0; i < wa->count; ++i) + seq_printf(m, "0x%X: 0x%08X, mask: 0x%08X\n", + wa->reg[i].addr, wa->reg[i].value, wa->reg[i].mask); return 0; } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 74dd88d8563e6..ea389771f9175 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1305,7 +1305,7 @@ struct i915_frontbuffer_tracking { }; struct i915_wa_reg { - i915_reg_t addr; + u32 addr; u32 value; /* bitmask representing WA bits */ u32 mask; diff --git a/drivers/gpu/drm/i915/intel_workarounds.c b/drivers/gpu/drm/i915/intel_workarounds.c index 24b929ce3341b..f8bb32e974f65 100644 --- a/drivers/gpu/drm/i915/intel_workarounds.c +++ b/drivers/gpu/drm/i915/intel_workarounds.c @@ -48,29 +48,58 @@ * - Public functions to init or apply the given workaround type. */ -static int wa_add(struct drm_i915_private *dev_priv, - i915_reg_t addr, - const u32 mask, const u32 val) +static void wa_add(struct drm_i915_private *i915, + i915_reg_t reg, const u32 mask, const u32 val) { - const unsigned int idx = dev_priv->workarounds.count; + struct i915_workarounds *wa = &i915->workarounds; + unsigned int start = 0, end = wa->count; + unsigned int addr = i915_mmio_reg_offset(reg); + struct i915_wa_reg *r; + + while (start < end) { + unsigned int mid = start + (end - start) / 2; + + if (wa->reg[mid].addr < addr) { + start = mid + 1; + } else if (wa->reg[mid].addr > addr) { + end = mid; + } else { + r = &wa->reg[mid]; + + if ((mask & ~r->mask) == 0) { + DRM_ERROR("Discarding overwritten w/a for reg %04x (mask: %08x, value: %08x)\n", + addr, r->mask, r->value); + + r->value &= ~mask; + } + + r->value |= val; + r->mask |= mask; + return; + } + } - if (WARN_ON(idx >= I915_MAX_WA_REGS)) - return -ENOSPC; + if (WARN_ON_ONCE(wa->count >= I915_MAX_WA_REGS)) { + DRM_ERROR("Dropping w/a for reg %04x (mask: %08x, value: %08x)\n", + addr, mask, val); + return; + } - dev_priv->workarounds.reg[idx].addr = addr; - dev_priv->workarounds.reg[idx].value = val; - dev_priv->workarounds.reg[idx].mask = mask; + r = &wa->reg[wa->count++]; + r->addr = addr; + r->value = val; + r->mask = mask; - dev_priv->workarounds.count++; + while (r-- > wa->reg) { + GEM_BUG_ON(r[0].addr == r[1].addr); + if (r[1].addr > r[0].addr) + break; - return 0; + swap(r[1], r[0]); + } } -#define WA_REG(addr, mask, val) do { \ - const int r = wa_add(dev_priv, (addr), (mask), (val)); \ - if (r) \ - return r; \ - } while (0) +#define WA_REG(addr, mask, val) wa_add(dev_priv, (addr), (mask), (val)) #define WA_SET_BIT_MASKED(addr, mask) \ WA_REG(addr, (mask), _MASKED_BIT_ENABLE(mask)) @@ -540,7 +569,7 @@ int intel_ctx_workarounds_emit(struct i915_request *rq) *cs++ = MI_LOAD_REGISTER_IMM(w->count); for (i = 0; i < w->count; i++) { - *cs++ = i915_mmio_reg_offset(w->reg[i].addr); + *cs++ = w->reg[i].addr; *cs++ = w->reg[i].value; } *cs++ = MI_NOOP; -- GitLab From 14921f3cef85b0167a9145e5f29b9dfc3b2a84dc Mon Sep 17 00:00:00 2001 From: Mika Kuoppala <mika.kuoppala@linux.intel.com> Date: Fri, 15 Jun 2018 13:44:29 +0300 Subject: [PATCH 0300/1506] drm/i915: Fix context ban and hang accounting for client If client is smart or lucky enough to create a new context after each hang, our context banning mechanism will never catch up, and as a result of that it will be saved from client banning. This can result in a never ending streak of gpu hangs caused by bad or malicious client, preventing access from other legit gpu clients. Fix this by always incrementing per client ban score if it hangs in short successions regardless of context ban scoring. The exception are non bannable contexts. They remain detached from client ban scoring mechanism. v2: xchg timestamp, tidyup (Chris) v3: comment, bannable & banned together (Chris) Fixes: b083a0870c79 ("drm/i915: Add per client max context ban limit") Cc: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20180615104429.31477-1-mika.kuoppala@linux.intel.com --- drivers/gpu/drm/i915/i915_drv.h | 21 ++++++--- drivers/gpu/drm/i915/i915_gem.c | 57 +++++++++++++++++-------- drivers/gpu/drm/i915/i915_gem_context.c | 2 +- 3 files changed, 55 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ea389771f9175..d00761a06f056 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -352,14 +352,21 @@ struct drm_i915_file_private { unsigned int bsd_engine; -/* Client can have a maximum of 3 contexts banned before - * it is denied of creating new contexts. As one context - * ban needs 4 consecutive hangs, and more if there is - * progress in between, this is a last resort stop gap measure - * to limit the badly behaving clients access to gpu. +/* + * Every context ban increments per client ban score. Also + * hangs in short succession increments ban score. If ban threshold + * is reached, client is considered banned and submitting more work + * will fail. This is a stop gap measure to limit the badly behaving + * clients access to gpu. Note that unbannable contexts never increment + * the client ban score. */ -#define I915_MAX_CLIENT_CONTEXT_BANS 3 - atomic_t context_bans; +#define I915_CLIENT_SCORE_HANG_FAST 1 +#define I915_CLIENT_FAST_HANG_JIFFIES (60 * HZ) +#define I915_CLIENT_SCORE_CONTEXT_BAN 3 +#define I915_CLIENT_SCORE_BANNED 9 + /** ban_score: Accumulated score of all ctx bans and fast hangs. */ + atomic_t ban_score; + unsigned long hang_timestamp; }; /* Interface history: diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 8dd4d35655afc..977982a987c8f 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2941,32 +2941,54 @@ i915_gem_object_pwrite_gtt(struct drm_i915_gem_object *obj, return 0; } +static void i915_gem_client_mark_guilty(struct drm_i915_file_private *file_priv, + const struct i915_gem_context *ctx) +{ + unsigned int score; + unsigned long prev_hang; + + if (i915_gem_context_is_banned(ctx)) + score = I915_CLIENT_SCORE_CONTEXT_BAN; + else + score = 0; + + prev_hang = xchg(&file_priv->hang_timestamp, jiffies); + if (time_before(jiffies, prev_hang + I915_CLIENT_FAST_HANG_JIFFIES)) + score += I915_CLIENT_SCORE_HANG_FAST; + + if (score) { + atomic_add(score, &file_priv->ban_score); + + DRM_DEBUG_DRIVER("client %s: gained %u ban score, now %u\n", + ctx->name, score, + atomic_read(&file_priv->ban_score)); + } +} + static void i915_gem_context_mark_guilty(struct i915_gem_context *ctx) { - bool banned; + unsigned int score; + bool banned, bannable; atomic_inc(&ctx->guilty_count); - banned = false; - if (i915_gem_context_is_bannable(ctx)) { - unsigned int score; + bannable = i915_gem_context_is_bannable(ctx); + score = atomic_add_return(CONTEXT_SCORE_GUILTY, &ctx->ban_score); + banned = score >= CONTEXT_SCORE_BAN_THRESHOLD; - score = atomic_add_return(CONTEXT_SCORE_GUILTY, - &ctx->ban_score); - banned = score >= CONTEXT_SCORE_BAN_THRESHOLD; + DRM_DEBUG_DRIVER("context %s: guilty %d, score %u, ban %s\n", + ctx->name, atomic_read(&ctx->guilty_count), + score, yesno(banned && bannable)); - DRM_DEBUG_DRIVER("context %s marked guilty (score %d) banned? %s\n", - ctx->name, score, yesno(banned)); - } - if (!banned) + /* Cool contexts don't accumulate client ban score */ + if (!bannable) return; - i915_gem_context_set_banned(ctx); - if (!IS_ERR_OR_NULL(ctx->file_priv)) { - atomic_inc(&ctx->file_priv->context_bans); - DRM_DEBUG_DRIVER("client %s has had %d context banned\n", - ctx->name, atomic_read(&ctx->file_priv->context_bans)); - } + if (banned) + i915_gem_context_set_banned(ctx); + + if (!IS_ERR_OR_NULL(ctx->file_priv)) + i915_gem_client_mark_guilty(ctx->file_priv, ctx); } static void i915_gem_context_mark_innocent(struct i915_gem_context *ctx) @@ -5820,6 +5842,7 @@ int i915_gem_open(struct drm_i915_private *i915, struct drm_file *file) INIT_LIST_HEAD(&file_priv->mm.request_list); file_priv->bsd_engine = -1; + file_priv->hang_timestamp = jiffies; ret = i915_gem_context_open(i915, file); if (ret) diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index ef6ea4bcd7733..ccf463ab6562f 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -708,7 +708,7 @@ int i915_gem_switch_to_kernel_context(struct drm_i915_private *i915) static bool client_is_banned(struct drm_i915_file_private *file_priv) { - return atomic_read(&file_priv->context_bans) > I915_MAX_CLIENT_CONTEXT_BANS; + return atomic_read(&file_priv->ban_score) >= I915_CLIENT_SCORE_BANNED; } int i915_gem_context_create_ioctl(struct drm_device *dev, void *data, -- GitLab From b1dc9d8755d9ee605990f32d82ca39b57c7cdcbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Mon, 11 Jun 2018 15:10:02 +0200 Subject: [PATCH 0301/1506] drm/amdgpu: allocate shared fence slot in VA IOCTL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per VM BOs share the reservation object with the PD and so need to reserve a shared fence slot for the update. Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Chunming Zhou <david1.zhou@amd.com> Reviewed-by: Junwei Zhang <Jerry.Zhang@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index 5fb156a01774e..7f27cdb7afe2e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -612,7 +612,7 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, return -ENOENT; abo = gem_to_amdgpu_bo(gobj); tv.bo = &abo->tbo; - tv.shared = false; + tv.shared = !!(abo->flags & AMDGPU_GEM_CREATE_VM_ALWAYS_VALID); list_add(&tv.head, &list); } else { gobj = NULL; -- GitLab From ecfee95a8ae7f35d43b8f63d61220e70ec8d2ea8 Mon Sep 17 00:00:00 2001 From: Rex Zhu <Rex.Zhu@amd.com> Date: Wed, 13 Jun 2018 18:26:38 +0800 Subject: [PATCH 0302/1506] drm/amd/pp: Add S3 support for OD feature make custom values survive when S3 sleep transitions. so not reset the od table if it is not null. Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c | 126 +++++++++--------- .../drm/amd/powerplay/hwmgr/vega10_hwmgr.c | 79 ++++++----- 2 files changed, 107 insertions(+), 98 deletions(-) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c index f8e866ceda022..fdb20db9c147f 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c @@ -885,6 +885,60 @@ static void smu7_setup_voltage_range_from_vbios(struct pp_hwmgr *hwmgr) data->odn_dpm_table.max_vddc = max_vddc; } +static void smu7_check_dpm_table_updated(struct pp_hwmgr *hwmgr) +{ + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); + struct smu7_odn_dpm_table *odn_table = &(data->odn_dpm_table); + struct phm_ppt_v1_information *table_info = + (struct phm_ppt_v1_information *)(hwmgr->pptable); + uint32_t i; + + struct phm_ppt_v1_clock_voltage_dependency_table *dep_table; + struct phm_ppt_v1_clock_voltage_dependency_table *odn_dep_table; + + if (table_info == NULL) + return; + + for (i = 0; i < data->dpm_table.sclk_table.count; i++) { + if (odn_table->odn_core_clock_dpm_levels.entries[i].clock != + data->dpm_table.sclk_table.dpm_levels[i].value) { + data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_SCLK; + break; + } + } + + for (i = 0; i < data->dpm_table.mclk_table.count; i++) { + if (odn_table->odn_memory_clock_dpm_levels.entries[i].clock != + data->dpm_table.mclk_table.dpm_levels[i].value) { + data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_MCLK; + break; + } + } + + dep_table = table_info->vdd_dep_on_mclk; + odn_dep_table = (struct phm_ppt_v1_clock_voltage_dependency_table *)&(odn_table->vdd_dependency_on_mclk); + + for (i = 0; i < dep_table->count; i++) { + if (dep_table->entries[i].vddc != odn_dep_table->entries[i].vddc) { + data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_VDDC | DPMTABLE_OD_UPDATE_MCLK; + return; + } + } + + dep_table = table_info->vdd_dep_on_sclk; + odn_dep_table = (struct phm_ppt_v1_clock_voltage_dependency_table *)&(odn_table->vdd_dependency_on_sclk); + for (i = 0; i < dep_table->count; i++) { + if (dep_table->entries[i].vddc != odn_dep_table->entries[i].vddc) { + data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_VDDC | DPMTABLE_OD_UPDATE_SCLK; + return; + } + } + if (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_VDDC) { + data->need_update_smu7_dpm_table &= ~DPMTABLE_OD_UPDATE_VDDC; + data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_SCLK | DPMTABLE_OD_UPDATE_MCLK; + } +} + static int smu7_setup_default_dpm_tables(struct pp_hwmgr *hwmgr) { struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); @@ -904,10 +958,13 @@ static int smu7_setup_default_dpm_tables(struct pp_hwmgr *hwmgr) /* initialize ODN table */ if (hwmgr->od_enabled) { - smu7_setup_voltage_range_from_vbios(hwmgr); - smu7_odn_initial_default_setting(hwmgr); + if (data->odn_dpm_table.max_vddc) { + smu7_check_dpm_table_updated(hwmgr); + } else { + smu7_setup_voltage_range_from_vbios(hwmgr); + smu7_odn_initial_default_setting(hwmgr); + } } - return 0; } @@ -3717,8 +3774,9 @@ static int smu7_trim_single_dpm_states(struct pp_hwmgr *hwmgr, uint32_t i; for (i = 0; i < dpm_table->count; i++) { - if ((dpm_table->dpm_levels[i].value < low_limit) - || (dpm_table->dpm_levels[i].value > high_limit)) + /*skip the trim if od is enabled*/ + if (!hwmgr->od_enabled && (dpm_table->dpm_levels[i].value < low_limit + || dpm_table->dpm_levels[i].value > high_limit)) dpm_table->dpm_levels[i].enabled = false; else dpm_table->dpm_levels[i].enabled = true; @@ -3762,10 +3820,8 @@ static int smu7_generate_dpm_level_enable_mask( const struct smu7_power_state *smu7_ps = cast_const_phw_smu7_power_state(states->pnew_state); - /*skip the trim if od is enabled*/ - if (!hwmgr->od_enabled) - result = smu7_trim_dpm_states(hwmgr, smu7_ps); + result = smu7_trim_dpm_states(hwmgr, smu7_ps); if (result) return result; @@ -4739,60 +4795,6 @@ static bool smu7_check_clk_voltage_valid(struct pp_hwmgr *hwmgr, return true; } -static void smu7_check_dpm_table_updated(struct pp_hwmgr *hwmgr) -{ - struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); - struct smu7_odn_dpm_table *odn_table = &(data->odn_dpm_table); - struct phm_ppt_v1_information *table_info = - (struct phm_ppt_v1_information *)(hwmgr->pptable); - uint32_t i; - - struct phm_ppt_v1_clock_voltage_dependency_table *dep_table; - struct phm_ppt_v1_clock_voltage_dependency_table *odn_dep_table; - - if (table_info == NULL) - return; - - for (i=0; i<data->dpm_table.sclk_table.count; i++) { - if (odn_table->odn_core_clock_dpm_levels.entries[i].clock != - data->dpm_table.sclk_table.dpm_levels[i].value) { - data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_SCLK; - break; - } - } - - for (i=0; i<data->dpm_table.mclk_table.count; i++) { - if (odn_table->odn_memory_clock_dpm_levels.entries[i].clock != - data->dpm_table.mclk_table.dpm_levels[i].value) { - data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_MCLK; - break; - } - } - - dep_table = table_info->vdd_dep_on_mclk; - odn_dep_table = (struct phm_ppt_v1_clock_voltage_dependency_table *)&(odn_table->vdd_dependency_on_mclk); - - for (i=0; i < dep_table->count; i++) { - if (dep_table->entries[i].vddc != odn_dep_table->entries[i].vddc) { - data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_VDDC | DPMTABLE_OD_UPDATE_MCLK; - return; - } - } - - dep_table = table_info->vdd_dep_on_sclk; - odn_dep_table = (struct phm_ppt_v1_clock_voltage_dependency_table *)&(odn_table->vdd_dependency_on_sclk); - for (i=0; i < dep_table->count; i++) { - if (dep_table->entries[i].vddc != odn_dep_table->entries[i].vddc) { - data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_VDDC | DPMTABLE_OD_UPDATE_SCLK; - return; - } - } - if (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_VDDC) { - data->need_update_smu7_dpm_table &= ~DPMTABLE_OD_UPDATE_VDDC; - data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_SCLK | DPMTABLE_OD_UPDATE_MCLK; - } -} - static int smu7_odn_edit_dpm_table(struct pp_hwmgr *hwmgr, enum PP_OD_DPM_TABLE_COMMAND type, long *input, uint32_t size) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c index 05e680d55dbbe..66fd1a43e346b 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c @@ -2414,6 +2414,40 @@ static int vega10_populate_and_upload_avfs_fuse_override(struct pp_hwmgr *hwmgr) return result; } +static void vega10_check_dpm_table_updated(struct pp_hwmgr *hwmgr) +{ + struct vega10_hwmgr *data = hwmgr->backend; + struct vega10_odn_dpm_table *odn_table = &(data->odn_dpm_table); + struct phm_ppt_v2_information *table_info = hwmgr->pptable; + struct phm_ppt_v1_clock_voltage_dependency_table *dep_table; + struct phm_ppt_v1_clock_voltage_dependency_table *odn_dep_table; + uint32_t i; + + dep_table = table_info->vdd_dep_on_mclk; + odn_dep_table = (struct phm_ppt_v1_clock_voltage_dependency_table *)&(odn_table->vdd_dep_on_mclk); + + for (i = 0; i < dep_table->count; i++) { + if (dep_table->entries[i].vddc != odn_dep_table->entries[i].vddc) { + data->need_update_dpm_table |= DPMTABLE_OD_UPDATE_VDDC | DPMTABLE_OD_UPDATE_MCLK; + return; + } + } + + dep_table = table_info->vdd_dep_on_sclk; + odn_dep_table = (struct phm_ppt_v1_clock_voltage_dependency_table *)&(odn_table->vdd_dep_on_sclk); + for (i = 0; i < dep_table->count; i++) { + if (dep_table->entries[i].vddc != odn_dep_table->entries[i].vddc) { + data->need_update_dpm_table |= DPMTABLE_OD_UPDATE_VDDC | DPMTABLE_OD_UPDATE_SCLK; + return; + } + } + + if (data->need_update_dpm_table & DPMTABLE_OD_UPDATE_VDDC) { + data->need_update_dpm_table &= ~DPMTABLE_OD_UPDATE_VDDC; + data->need_update_dpm_table |= DPMTABLE_OD_UPDATE_SCLK | DPMTABLE_OD_UPDATE_MCLK; + } +} + /** * Initializes the SMC table and uploads it * @@ -2430,6 +2464,7 @@ static int vega10_init_smc_table(struct pp_hwmgr *hwmgr) PPTable_t *pp_table = &(data->smc_state_table.pp_table); struct pp_atomfwctrl_voltage_table voltage_table; struct pp_atomfwctrl_bios_boot_up_values boot_up_values; + struct vega10_odn_dpm_table *odn_table = &(data->odn_dpm_table); result = vega10_setup_default_dpm_tables(hwmgr); PP_ASSERT_WITH_CODE(!result, @@ -2437,8 +2472,14 @@ static int vega10_init_smc_table(struct pp_hwmgr *hwmgr) return result); /* initialize ODN table */ - if (hwmgr->od_enabled) - vega10_odn_initial_default_setting(hwmgr); + if (hwmgr->od_enabled) { + if (odn_table->max_vddc) { + data->need_update_dpm_table |= DPMTABLE_OD_UPDATE_SCLK | DPMTABLE_OD_UPDATE_MCLK; + vega10_check_dpm_table_updated(hwmgr); + } else { + vega10_odn_initial_default_setting(hwmgr); + } + } pp_atomfwctrl_get_voltage_table_v4(hwmgr, VOLTAGE_TYPE_VDDC, VOLTAGE_OBJ_SVID2, &voltage_table); @@ -4695,40 +4736,6 @@ static bool vega10_check_clk_voltage_valid(struct pp_hwmgr *hwmgr, return true; } -static void vega10_check_dpm_table_updated(struct pp_hwmgr *hwmgr) -{ - struct vega10_hwmgr *data = hwmgr->backend; - struct vega10_odn_dpm_table *odn_table = &(data->odn_dpm_table); - struct phm_ppt_v2_information *table_info = hwmgr->pptable; - struct phm_ppt_v1_clock_voltage_dependency_table *dep_table; - struct phm_ppt_v1_clock_voltage_dependency_table *odn_dep_table; - uint32_t i; - - dep_table = table_info->vdd_dep_on_mclk; - odn_dep_table = (struct phm_ppt_v1_clock_voltage_dependency_table *)&(odn_table->vdd_dep_on_mclk); - - for (i = 0; i < dep_table->count; i++) { - if (dep_table->entries[i].vddc != odn_dep_table->entries[i].vddc) { - data->need_update_dpm_table |= DPMTABLE_OD_UPDATE_VDDC | DPMTABLE_OD_UPDATE_MCLK; - return; - } - } - - dep_table = table_info->vdd_dep_on_sclk; - odn_dep_table = (struct phm_ppt_v1_clock_voltage_dependency_table *)&(odn_table->vdd_dep_on_sclk); - for (i = 0; i < dep_table->count; i++) { - if (dep_table->entries[i].vddc != odn_dep_table->entries[i].vddc) { - data->need_update_dpm_table |= DPMTABLE_OD_UPDATE_VDDC | DPMTABLE_OD_UPDATE_SCLK; - return; - } - } - - if (data->need_update_dpm_table & DPMTABLE_OD_UPDATE_VDDC) { - data->need_update_dpm_table &= ~DPMTABLE_OD_UPDATE_VDDC; - data->need_update_dpm_table |= DPMTABLE_OD_UPDATE_SCLK | DPMTABLE_OD_UPDATE_MCLK; - } -} - static void vega10_odn_update_soc_table(struct pp_hwmgr *hwmgr, enum PP_OD_DPM_TABLE_COMMAND type) { -- GitLab From e1fa921f022d2401f3e3328ebf0c2ded84d4924a Mon Sep 17 00:00:00 2001 From: Rex Zhu <Rex.Zhu@amd.com> Date: Wed, 13 Jun 2018 18:53:49 +0800 Subject: [PATCH 0303/1506] drm/amd/pp: Make sure clock_voltage_limit_table on dc is valid if vbios not set the max clock voltage limit table for DC mode, Set the table as sama as the table for AC mode. Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c index e63bc47dc715f..4ef77cebc6284 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c @@ -236,6 +236,11 @@ int hwmgr_hw_init(struct pp_hwmgr *hwmgr) ret = hwmgr->hwmgr_func->backend_init(hwmgr); if (ret) goto err1; + /* make sure dc limits are valid */ + if ((hwmgr->dyn_state.max_clock_voltage_on_dc.sclk == 0) || + (hwmgr->dyn_state.max_clock_voltage_on_dc.mclk == 0)) + hwmgr->dyn_state.max_clock_voltage_on_dc = + hwmgr->dyn_state.max_clock_voltage_on_ac; ret = psm_init_power_state_table(hwmgr); if (ret) -- GitLab From dd06eecb73d2e5f5c4039bcd9d83d4f7e0156d6f Mon Sep 17 00:00:00 2001 From: James Zhu <James.Zhu@amd.com> Date: Wed, 6 Jun 2018 14:38:14 -0400 Subject: [PATCH 0304/1506] drm/amdgpu/vg20:support new UVD FW version naming convention Vega20 UVD Firmware has a new version naming convention: [31, 30] for encode interface major [29, 24] for encode interface minor [15, 8] for decode interface minor [7, 0] for hardware family id Signed-off-by: James Zhu <James.Zhu@amd.com> Reviewed-by: Leo Liu <leo.liu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c index bcf68f80bbf05..630e273c16ceb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c @@ -208,10 +208,21 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev) hdr = (const struct common_firmware_header *)adev->uvd.fw->data; family_id = le32_to_cpu(hdr->ucode_version) & 0xff; - version_major = (le32_to_cpu(hdr->ucode_version) >> 24) & 0xff; - version_minor = (le32_to_cpu(hdr->ucode_version) >> 8) & 0xff; - DRM_INFO("Found UVD firmware Version: %hu.%hu Family ID: %hu\n", - version_major, version_minor, family_id); + + if (adev->asic_type < CHIP_VEGA20) { + version_major = (le32_to_cpu(hdr->ucode_version) >> 24) & 0xff; + version_minor = (le32_to_cpu(hdr->ucode_version) >> 8) & 0xff; + DRM_INFO("Found UVD firmware Version: %hu.%hu Family ID: %hu\n", + version_major, version_minor, family_id); + } else { + unsigned int enc_major, enc_minor, dec_minor; + + dec_minor = (le32_to_cpu(hdr->ucode_version) >> 8) & 0xff; + enc_minor = (le32_to_cpu(hdr->ucode_version) >> 24) & 0x3f; + enc_major = (le32_to_cpu(hdr->ucode_version) >> 30) & 0x3; + DRM_INFO("Found UVD firmware ENC: %hu.%hu DEC: .%hu Family ID: %hu\n", + enc_major, enc_minor, dec_minor, family_id); + } /* * Limit the number of UVD handles depending on microcode major @@ -219,7 +230,7 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev) * instances support is 1.80. So all subsequent versions should * also have the same support. */ - if ((version_major > 0x01) || + if (adev->asic_type >= CHIP_VEGA20 || (version_major > 0x01) || ((version_major == 0x01) && (version_minor >= 0x50))) adev->uvd.max_handles = AMDGPU_MAX_UVD_HANDLES; -- GitLab From 5c2199270275581a06571960e7d6abac008ff060 Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexander.deucher@amd.com> Date: Thu, 14 Jun 2018 10:24:06 -0500 Subject: [PATCH 0305/1506] drm/amdgpu: Fix uvd firmware version information for vega20 (v2) The uvd version information was not set correctly for vega20. Rearrange the logic to set it correctly and fix the warnings as a result. v2: fix version formatting for userspace based on feedback from Leo Fixes: 96ca7f298f (drm/amdgpu/vg20:support new UVD FW version naming convention) Reviewed-by: Leo Liu <leo.liu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 42 ++++++++++++++----------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c index 630e273c16ceb..04d77f19acc85 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c @@ -127,7 +127,7 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev) unsigned long bo_size; const char *fw_name; const struct common_firmware_header *hdr; - unsigned version_major, version_minor, family_id; + unsigned family_id; int i, j, r; INIT_DELAYED_WORK(&adev->uvd.inst->idle_work, amdgpu_uvd_idle_work_handler); @@ -210,10 +210,31 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev) family_id = le32_to_cpu(hdr->ucode_version) & 0xff; if (adev->asic_type < CHIP_VEGA20) { + unsigned version_major, version_minor; + version_major = (le32_to_cpu(hdr->ucode_version) >> 24) & 0xff; version_minor = (le32_to_cpu(hdr->ucode_version) >> 8) & 0xff; DRM_INFO("Found UVD firmware Version: %hu.%hu Family ID: %hu\n", version_major, version_minor, family_id); + + /* + * Limit the number of UVD handles depending on microcode major + * and minor versions. The firmware version which has 40 UVD + * instances support is 1.80. So all subsequent versions should + * also have the same support. + */ + if ((version_major > 0x01) || + ((version_major == 0x01) && (version_minor >= 0x50))) + adev->uvd.max_handles = AMDGPU_MAX_UVD_HANDLES; + + adev->uvd.fw_version = ((version_major << 24) | (version_minor << 16) | + (family_id << 8)); + + if ((adev->asic_type == CHIP_POLARIS10 || + adev->asic_type == CHIP_POLARIS11) && + (adev->uvd.fw_version < FW_1_66_16)) + DRM_ERROR("POLARIS10/11 UVD firmware version %hu.%hu is too old.\n", + version_major, version_minor); } else { unsigned int enc_major, enc_minor, dec_minor; @@ -222,26 +243,11 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev) enc_major = (le32_to_cpu(hdr->ucode_version) >> 30) & 0x3; DRM_INFO("Found UVD firmware ENC: %hu.%hu DEC: .%hu Family ID: %hu\n", enc_major, enc_minor, dec_minor, family_id); - } - /* - * Limit the number of UVD handles depending on microcode major - * and minor versions. The firmware version which has 40 UVD - * instances support is 1.80. So all subsequent versions should - * also have the same support. - */ - if (adev->asic_type >= CHIP_VEGA20 || (version_major > 0x01) || - ((version_major == 0x01) && (version_minor >= 0x50))) adev->uvd.max_handles = AMDGPU_MAX_UVD_HANDLES; - adev->uvd.fw_version = ((version_major << 24) | (version_minor << 16) | - (family_id << 8)); - - if ((adev->asic_type == CHIP_POLARIS10 || - adev->asic_type == CHIP_POLARIS11) && - (adev->uvd.fw_version < FW_1_66_16)) - DRM_ERROR("POLARIS10/11 UVD firmware version %hu.%hu is too old.\n", - version_major, version_minor); + adev->uvd.fw_version = le32_to_cpu(hdr->ucode_version); + } bo_size = AMDGPU_UVD_STACK_SIZE + AMDGPU_UVD_HEAP_SIZE + AMDGPU_UVD_SESSION_SIZE * adev->uvd.max_handles; -- GitLab From fe78627d430435d22316fe39f2012ece31bf23c2 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" <gustavo@embeddedor.com> Date: Fri, 15 Jun 2018 08:32:28 -0500 Subject: [PATCH 0306/1506] drm/amd/display: fix type of variable Currently, the maximum value that *counter* can reach is 255, and code at line 150: while (counter < 1000) { implies a bigger value could be expected. Fix this by changing the type of variable *counter* from uint8_t to uint16_t. Addresses-Coverity-ID: 1470030 ("Operands don't affect result") Fixes: 2b6199a1d1b7 ("drm/amd/display: replace msleep with udelay in fbc path") Signed-off-by: Gustavo A. R. Silva <gustavo@embeddedor.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> Cc: stable@vger.kernel.org Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c index e2994d3370448..111c4921987fe 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c @@ -143,7 +143,7 @@ static void wait_for_fbc_state_changed( struct dce110_compressor *cp110, bool enabled) { - uint8_t counter = 0; + uint16_t counter = 0; uint32_t addr = mmFBC_STATUS; uint32_t value; -- GitLab From 2d33948e4e00b501b91367fed21243a948426591 Mon Sep 17 00:00:00 2001 From: Nayan Deshmukh <nayan26deshmukh@gmail.com> Date: Tue, 29 May 2018 11:23:07 +0530 Subject: [PATCH 0307/1506] drm/scheduler: add documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit convert existing raw comments into kernel-doc format as well as add new documentation v2: reword the overview Signed-off-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Nayan Deshmukh <nayan26deshmukh@gmail.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Acked-by: Daniel Vetter <daniel@ffwll.ch> --- drivers/gpu/drm/scheduler/gpu_scheduler.c | 214 +++++++++++++++++----- include/drm/gpu_scheduler.h | 153 +++++++++++++--- 2 files changed, 296 insertions(+), 71 deletions(-) diff --git a/drivers/gpu/drm/scheduler/gpu_scheduler.c b/drivers/gpu/drm/scheduler/gpu_scheduler.c index 44d480768dfe2..8c1e80c9b6742 100644 --- a/drivers/gpu/drm/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/scheduler/gpu_scheduler.c @@ -21,6 +21,29 @@ * */ +/** + * DOC: Overview + * + * The GPU scheduler provides entities which allow userspace to push jobs + * into software queues which are then scheduled on a hardware run queue. + * The software queues have a priority among them. The scheduler selects the entities + * from the run queue using a FIFO. The scheduler provides dependency handling + * features among jobs. The driver is supposed to provide callback functions for + * backend operations to the scheduler like submitting a job to hardware run queue, + * returning the dependencies of a job etc. + * + * The organisation of the scheduler is the following: + * + * 1. Each hw run queue has one scheduler + * 2. Each scheduler has multiple run queues with different priorities + * (e.g., HIGH_HW,HIGH_SW, KERNEL, NORMAL) + * 3. Each scheduler run queue has a queue of entities to schedule + * 4. Entities themselves maintain a queue of jobs that will be scheduled on + * the hardware. + * + * The jobs in a entity are always scheduled in the order that they were pushed. + */ + #include <linux/kthread.h> #include <linux/wait.h> #include <linux/sched.h> @@ -39,7 +62,13 @@ static bool drm_sched_entity_is_ready(struct drm_sched_entity *entity); static void drm_sched_wakeup(struct drm_gpu_scheduler *sched); static void drm_sched_process_job(struct dma_fence *f, struct dma_fence_cb *cb); -/* Initialize a given run queue struct */ +/** + * drm_sched_rq_init - initialize a given run queue struct + * + * @rq: scheduler run queue + * + * Initializes a scheduler runqueue. + */ static void drm_sched_rq_init(struct drm_sched_rq *rq) { spin_lock_init(&rq->lock); @@ -47,6 +76,14 @@ static void drm_sched_rq_init(struct drm_sched_rq *rq) rq->current_entity = NULL; } +/** + * drm_sched_rq_add_entity - add an entity + * + * @rq: scheduler run queue + * @entity: scheduler entity + * + * Adds a scheduler entity to the run queue. + */ static void drm_sched_rq_add_entity(struct drm_sched_rq *rq, struct drm_sched_entity *entity) { @@ -57,6 +94,14 @@ static void drm_sched_rq_add_entity(struct drm_sched_rq *rq, spin_unlock(&rq->lock); } +/** + * drm_sched_rq_remove_entity - remove an entity + * + * @rq: scheduler run queue + * @entity: scheduler entity + * + * Removes a scheduler entity from the run queue. + */ static void drm_sched_rq_remove_entity(struct drm_sched_rq *rq, struct drm_sched_entity *entity) { @@ -70,9 +115,9 @@ static void drm_sched_rq_remove_entity(struct drm_sched_rq *rq, } /** - * Select an entity which could provide a job to run + * drm_sched_rq_select_entity - Select an entity which could provide a job to run * - * @rq The run queue to check. + * @rq: scheduler run queue to check. * * Try to find a ready entity, returns NULL if none found. */ @@ -112,15 +157,16 @@ drm_sched_rq_select_entity(struct drm_sched_rq *rq) } /** - * Init a context entity used by scheduler when submit to HW ring. + * drm_sched_entity_init - Init a context entity used by scheduler when + * submit to HW ring. * - * @sched The pointer to the scheduler - * @entity The pointer to a valid drm_sched_entity - * @rq The run queue this entity belongs - * @guilty atomic_t set to 1 when a job on this queue - * is found to be guilty causing a timeout + * @sched: scheduler instance + * @entity: scheduler entity to init + * @rq: the run queue this entity belongs + * @guilty: atomic_t set to 1 when a job on this queue + * is found to be guilty causing a timeout * - * return 0 if succeed. negative error code on failure + * Returns 0 on success or a negative error code on failure. */ int drm_sched_entity_init(struct drm_gpu_scheduler *sched, struct drm_sched_entity *entity, @@ -149,10 +195,10 @@ int drm_sched_entity_init(struct drm_gpu_scheduler *sched, EXPORT_SYMBOL(drm_sched_entity_init); /** - * Query if entity is initialized + * drm_sched_entity_is_initialized - Query if entity is initialized * - * @sched Pointer to scheduler instance - * @entity The pointer to a valid scheduler entity + * @sched: Pointer to scheduler instance + * @entity: The pointer to a valid scheduler entity * * return true if entity is initialized, false otherwise */ @@ -164,11 +210,11 @@ static bool drm_sched_entity_is_initialized(struct drm_gpu_scheduler *sched, } /** - * Check if entity is idle + * drm_sched_entity_is_idle - Check if entity is idle * - * @entity The pointer to a valid scheduler entity + * @entity: scheduler entity * - * Return true if entity don't has any unscheduled jobs. + * Returns true if the entity does not have any unscheduled jobs. */ static bool drm_sched_entity_is_idle(struct drm_sched_entity *entity) { @@ -180,9 +226,9 @@ static bool drm_sched_entity_is_idle(struct drm_sched_entity *entity) } /** - * Check if entity is ready + * drm_sched_entity_is_ready - Check if entity is ready * - * @entity The pointer to a valid scheduler entity + * @entity: scheduler entity * * Return true if entity could provide a job. */ @@ -210,12 +256,12 @@ static void drm_sched_entity_kill_jobs_cb(struct dma_fence *f, /** - * Destroy a context entity + * drm_sched_entity_do_release - Destroy a context entity * - * @sched Pointer to scheduler instance - * @entity The pointer to a valid scheduler entity + * @sched: scheduler instance + * @entity: scheduler entity * - * Splitting drm_sched_entity_fini() into two functions, The first one is does the waiting, + * Splitting drm_sched_entity_fini() into two functions, The first one does the waiting, * removes the entity from the runqueue and returns an error when the process was killed. */ void drm_sched_entity_do_release(struct drm_gpu_scheduler *sched, @@ -237,12 +283,13 @@ void drm_sched_entity_do_release(struct drm_gpu_scheduler *sched, EXPORT_SYMBOL(drm_sched_entity_do_release); /** - * Destroy a context entity + * drm_sched_entity_cleanup - Destroy a context entity * - * @sched Pointer to scheduler instance - * @entity The pointer to a valid scheduler entity + * @sched: scheduler instance + * @entity: scheduler entity * - * The second one then goes over the entity and signals all jobs with an error code. + * This should be called after @drm_sched_entity_do_release. It goes over the + * entity and signals all jobs with an error code if the process was killed. */ void drm_sched_entity_cleanup(struct drm_gpu_scheduler *sched, struct drm_sched_entity *entity) @@ -281,6 +328,14 @@ void drm_sched_entity_cleanup(struct drm_gpu_scheduler *sched, } EXPORT_SYMBOL(drm_sched_entity_cleanup); +/** + * drm_sched_entity_fini - Destroy a context entity + * + * @sched: scheduler instance + * @entity: scheduler entity + * + * Calls drm_sched_entity_do_release() and drm_sched_entity_cleanup() + */ void drm_sched_entity_fini(struct drm_gpu_scheduler *sched, struct drm_sched_entity *entity) { @@ -306,6 +361,15 @@ static void drm_sched_entity_clear_dep(struct dma_fence *f, struct dma_fence_cb dma_fence_put(f); } +/** + * drm_sched_entity_set_rq - Sets the run queue for an entity + * + * @entity: scheduler entity + * @rq: scheduler run queue + * + * Sets the run queue for an entity and removes the entity from the previous + * run queue in which was present. + */ void drm_sched_entity_set_rq(struct drm_sched_entity *entity, struct drm_sched_rq *rq) { @@ -325,6 +389,14 @@ void drm_sched_entity_set_rq(struct drm_sched_entity *entity, } EXPORT_SYMBOL(drm_sched_entity_set_rq); +/** + * drm_sched_dependency_optimized + * + * @fence: the dependency fence + * @entity: the entity which depends on the above fence + * + * Returns true if the dependency can be optimized and false otherwise + */ bool drm_sched_dependency_optimized(struct dma_fence* fence, struct drm_sched_entity *entity) { @@ -413,9 +485,10 @@ drm_sched_entity_pop_job(struct drm_sched_entity *entity) } /** - * Submit a job to the job queue + * drm_sched_entity_push_job - Submit a job to the entity's job queue * - * @sched_job The pointer to job required to submit + * @sched_job: job to submit + * @entity: scheduler entity * * Note: To guarantee that the order of insertion to queue matches * the job's fence sequence number this function should be @@ -506,6 +579,13 @@ static void drm_sched_job_timedout(struct work_struct *work) job->sched->ops->timedout_job(job); } +/** + * drm_sched_hw_job_reset - stop the scheduler if it contains the bad job + * + * @sched: scheduler instance + * @bad: bad scheduler job + * + */ void drm_sched_hw_job_reset(struct drm_gpu_scheduler *sched, struct drm_sched_job *bad) { struct drm_sched_job *s_job; @@ -550,6 +630,12 @@ void drm_sched_hw_job_reset(struct drm_gpu_scheduler *sched, struct drm_sched_jo } EXPORT_SYMBOL(drm_sched_hw_job_reset); +/** + * drm_sched_job_recovery - recover jobs after a reset + * + * @sched: scheduler instance + * + */ void drm_sched_job_recovery(struct drm_gpu_scheduler *sched) { struct drm_sched_job *s_job, *tmp; @@ -599,10 +685,17 @@ void drm_sched_job_recovery(struct drm_gpu_scheduler *sched) EXPORT_SYMBOL(drm_sched_job_recovery); /** - * Init a sched_job with basic field + * drm_sched_job_init - init a scheduler job * - * Note: Refer to drm_sched_entity_push_job documentation + * @job: scheduler job to init + * @sched: scheduler instance + * @entity: scheduler entity to use + * @owner: job owner for debugging + * + * Refer to drm_sched_entity_push_job() documentation * for locking considerations. + * + * Returns 0 for success, negative error code otherwise. */ int drm_sched_job_init(struct drm_sched_job *job, struct drm_gpu_scheduler *sched, @@ -626,7 +719,11 @@ int drm_sched_job_init(struct drm_sched_job *job, EXPORT_SYMBOL(drm_sched_job_init); /** - * Return ture if we can push more jobs to the hw. + * drm_sched_ready - is the scheduler ready + * + * @sched: scheduler instance + * + * Return true if we can push more jobs to the hw, otherwise false. */ static bool drm_sched_ready(struct drm_gpu_scheduler *sched) { @@ -635,7 +732,10 @@ static bool drm_sched_ready(struct drm_gpu_scheduler *sched) } /** - * Wake up the scheduler when it is ready + * drm_sched_wakeup - Wake up the scheduler when it is ready + * + * @sched: scheduler instance + * */ static void drm_sched_wakeup(struct drm_gpu_scheduler *sched) { @@ -644,8 +744,12 @@ static void drm_sched_wakeup(struct drm_gpu_scheduler *sched) } /** - * Select next entity to process -*/ + * drm_sched_select_entity - Select next entity to process + * + * @sched: scheduler instance + * + * Returns the entity to process or NULL if none are found. + */ static struct drm_sched_entity * drm_sched_select_entity(struct drm_gpu_scheduler *sched) { @@ -665,6 +769,14 @@ drm_sched_select_entity(struct drm_gpu_scheduler *sched) return entity; } +/** + * drm_sched_process_job - process a job + * + * @f: fence + * @cb: fence callbacks + * + * Called after job has finished execution. + */ static void drm_sched_process_job(struct dma_fence *f, struct dma_fence_cb *cb) { struct drm_sched_fence *s_fence = @@ -680,6 +792,13 @@ static void drm_sched_process_job(struct dma_fence *f, struct dma_fence_cb *cb) wake_up_interruptible(&sched->wake_up_worker); } +/** + * drm_sched_blocked - check if the scheduler is blocked + * + * @sched: scheduler instance + * + * Returns true if blocked, otherwise false. + */ static bool drm_sched_blocked(struct drm_gpu_scheduler *sched) { if (kthread_should_park()) { @@ -690,6 +809,13 @@ static bool drm_sched_blocked(struct drm_gpu_scheduler *sched) return false; } +/** + * drm_sched_main - main scheduler thread + * + * @param: scheduler instance + * + * Returns 0. + */ static int drm_sched_main(void *param) { struct sched_param sparam = {.sched_priority = 1}; @@ -744,15 +870,17 @@ static int drm_sched_main(void *param) } /** - * Init a gpu scheduler instance + * drm_sched_init - Init a gpu scheduler instance * - * @sched The pointer to the scheduler - * @ops The backend operations for this scheduler. - * @hw_submissions Number of hw submissions to do. - * @name Name used for debugging + * @sched: scheduler instance + * @ops: backend operations for this scheduler + * @hw_submission: number of hw submissions that can be in flight + * @hang_limit: number of times to allow a job to hang before dropping it + * @timeout: timeout value in jiffies for the scheduler + * @name: name used for debugging * * Return 0 on success, otherwise error code. -*/ + */ int drm_sched_init(struct drm_gpu_scheduler *sched, const struct drm_sched_backend_ops *ops, unsigned hw_submission, @@ -788,9 +916,11 @@ int drm_sched_init(struct drm_gpu_scheduler *sched, EXPORT_SYMBOL(drm_sched_init); /** - * Destroy a gpu scheduler + * drm_sched_fini - Destroy a gpu scheduler + * + * @sched: scheduler instance * - * @sched The pointer to the scheduler + * Tears down and cleans up the scheduler. */ void drm_sched_fini(struct drm_gpu_scheduler *sched) { diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h index dec655894d080..496442f12bff4 100644 --- a/include/drm/gpu_scheduler.h +++ b/include/drm/gpu_scheduler.h @@ -43,13 +43,33 @@ enum drm_sched_priority { }; /** - * drm_sched_entity - A wrapper around a job queue (typically attached - * to the DRM file_priv). + * struct drm_sched_entity - A wrapper around a job queue (typically + * attached to the DRM file_priv). + * + * @list: used to append this struct to the list of entities in the + * runqueue. + * @rq: runqueue to which this entity belongs. + * @rq_lock: lock to modify the runqueue to which this entity belongs. + * @sched: the scheduler instance to which this entity is enqueued. + * @job_queue: the list of jobs of this entity. + * @fence_seq: a linearly increasing seqno incremented with each + * new &drm_sched_fence which is part of the entity. + * @fence_context: a unique context for all the fences which belong + * to this entity. + * The &drm_sched_fence.scheduled uses the + * fence_context but &drm_sched_fence.finished uses + * fence_context + 1. + * @dependency: the dependency fence of the job which is on the top + * of the job queue. + * @cb: callback for the dependency fence above. + * @guilty: points to ctx's guilty. + * @fini_status: contains the exit status in case the process was signalled. + * @last_scheduled: points to the finished fence of the last scheduled job. * * Entities will emit jobs in order to their corresponding hardware * ring, and the scheduler will alternate between entities based on * scheduling policy. -*/ + */ struct drm_sched_entity { struct list_head list; struct drm_sched_rq *rq; @@ -63,47 +83,96 @@ struct drm_sched_entity { struct dma_fence *dependency; struct dma_fence_cb cb; - atomic_t *guilty; /* points to ctx's guilty */ - int fini_status; - struct dma_fence *last_scheduled; + atomic_t *guilty; + int fini_status; + struct dma_fence *last_scheduled; }; /** + * struct drm_sched_rq - queue of entities to be scheduled. + * + * @lock: to modify the entities list. + * @entities: list of the entities to be scheduled. + * @current_entity: the entity which is to be scheduled. + * * Run queue is a set of entities scheduling command submissions for * one specific ring. It implements the scheduling policy that selects * the next entity to emit commands from. -*/ + */ struct drm_sched_rq { spinlock_t lock; struct list_head entities; struct drm_sched_entity *current_entity; }; +/** + * struct drm_sched_fence - fences corresponding to the scheduling of a job. + */ struct drm_sched_fence { + /** + * @scheduled: this fence is what will be signaled by the scheduler + * when the job is scheduled. + */ struct dma_fence scheduled; - /* This fence is what will be signaled by the scheduler when - * the job is completed. - * - * When setting up an out fence for the job, you should use - * this, since it's available immediately upon - * drm_sched_job_init(), and the fence returned by the driver - * from run_job() won't be created until the dependencies have - * resolved. - */ + /** + * @finished: this fence is what will be signaled by the scheduler + * when the job is completed. + * + * When setting up an out fence for the job, you should use + * this, since it's available immediately upon + * drm_sched_job_init(), and the fence returned by the driver + * from run_job() won't be created until the dependencies have + * resolved. + */ struct dma_fence finished; + /** + * @cb: the callback for the parent fence below. + */ struct dma_fence_cb cb; + /** + * @parent: the fence returned by &drm_sched_backend_ops.run_job + * when scheduling the job on hardware. We signal the + * &drm_sched_fence.finished fence once parent is signalled. + */ struct dma_fence *parent; + /** + * @sched: the scheduler instance to which the job having this struct + * belongs to. + */ struct drm_gpu_scheduler *sched; + /** + * @lock: the lock used by the scheduled and the finished fences. + */ spinlock_t lock; + /** + * @owner: job owner for debugging + */ void *owner; }; struct drm_sched_fence *to_drm_sched_fence(struct dma_fence *f); /** - * drm_sched_job - A job to be run by an entity. + * struct drm_sched_job - A job to be run by an entity. + * + * @queue_node: used to append this struct to the queue of jobs in an entity. + * @sched: the scheduler instance on which this job is scheduled. + * @s_fence: contains the fences for the scheduling of job. + * @finish_cb: the callback for the finished fence. + * @finish_work: schedules the function @drm_sched_job_finish once the job has + * finished to remove the job from the + * @drm_gpu_scheduler.ring_mirror_list. + * @node: used to append this struct to the @drm_gpu_scheduler.ring_mirror_list. + * @work_tdr: schedules a delayed call to @drm_sched_job_timedout after the timeout + * interval is over. + * @id: a unique id assigned to each job scheduled on the scheduler. + * @karma: increment on every hang caused by this job. If this exceeds the hang + * limit of the scheduler then the job is marked guilty and will not + * be scheduled further. + * @s_priority: the priority of the job. + * @entity: the entity to which this job belongs. * * A job is created by the driver using drm_sched_job_init(), and * should call drm_sched_entity_push_job() once it wants the scheduler @@ -130,38 +199,64 @@ static inline bool drm_sched_invalidate_job(struct drm_sched_job *s_job, } /** + * struct drm_sched_backend_ops + * * Define the backend operations called by the scheduler, - * these functions should be implemented in driver side -*/ + * these functions should be implemented in driver side. + */ struct drm_sched_backend_ops { - /* Called when the scheduler is considering scheduling this - * job next, to get another struct dma_fence for this job to + /** + * @dependency: Called when the scheduler is considering scheduling + * this job next, to get another struct dma_fence for this job to * block on. Once it returns NULL, run_job() may be called. */ struct dma_fence *(*dependency)(struct drm_sched_job *sched_job, struct drm_sched_entity *s_entity); - /* Called to execute the job once all of the dependencies have - * been resolved. This may be called multiple times, if + /** + * @run_job: Called to execute the job once all of the dependencies + * have been resolved. This may be called multiple times, if * timedout_job() has happened and drm_sched_job_recovery() * decides to try it again. */ struct dma_fence *(*run_job)(struct drm_sched_job *sched_job); - /* Called when a job has taken too long to execute, to trigger - * GPU recovery. + /** + * @timedout_job: Called when a job has taken too long to execute, + * to trigger GPU recovery. */ void (*timedout_job)(struct drm_sched_job *sched_job); - /* Called once the job's finished fence has been signaled and - * it's time to clean it up. + /** + * @free_job: Called once the job's finished fence has been signaled + * and it's time to clean it up. */ void (*free_job)(struct drm_sched_job *sched_job); }; /** - * One scheduler is implemented for each hardware ring -*/ + * struct drm_gpu_scheduler + * + * @ops: backend operations provided by the driver. + * @hw_submission_limit: the max size of the hardware queue. + * @timeout: the time after which a job is removed from the scheduler. + * @name: name of the ring for which this scheduler is being used. + * @sched_rq: priority wise array of run queues. + * @wake_up_worker: the wait queue on which the scheduler sleeps until a job + * is ready to be scheduled. + * @job_scheduled: once @drm_sched_entity_do_release is called the scheduler + * waits on this wait queue until all the scheduled jobs are + * finished. + * @hw_rq_count: the number of jobs currently in the hardware queue. + * @job_id_count: used to assign unique id to the each job. + * @thread: the kthread on which the scheduler which run. + * @ring_mirror_list: the list of jobs which are currently in the job queue. + * @job_list_lock: lock to protect the ring_mirror_list. + * @hang_limit: once the hangs by a job crosses this limit then it is marked + * guilty and it will be considered for scheduling further. + * + * One scheduler is implemented for each hardware ring. + */ struct drm_gpu_scheduler { const struct drm_sched_backend_ops *ops; uint32_t hw_submission_limit; -- GitLab From 677e8622a9ae8cd9d351f98ecf120fb1c83b59d1 Mon Sep 17 00:00:00 2001 From: Nayan Deshmukh <nayan26deshmukh@gmail.com> Date: Fri, 25 May 2018 10:15:48 +0530 Subject: [PATCH 0308/1506] drm/doc: add a chapter for gpu scheduler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nayan Deshmukh <nayan26deshmukh@gmail.com> Reviewed-by: Christian König <christian.koenig@amd.com> Acked-by: Daniel Vetter <daniel@ffwll.ch> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- Documentation/gpu/drm-mm.rst | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Documentation/gpu/drm-mm.rst b/Documentation/gpu/drm-mm.rst index b08e9dcd91771..96ebcc2a7b415 100644 --- a/Documentation/gpu/drm-mm.rst +++ b/Documentation/gpu/drm-mm.rst @@ -496,3 +496,21 @@ DRM Sync Objects .. kernel-doc:: drivers/gpu/drm/drm_syncobj.c :export: + +GPU Scheduler +============= + +Overview +-------- + +.. kernel-doc:: drivers/gpu/drm/scheduler/gpu_scheduler.c + :doc: Overview + +Scheduler Function References +----------------------------- + +.. kernel-doc:: include/drm/gpu_scheduler.h + :internal: + +.. kernel-doc:: drivers/gpu/drm/scheduler/gpu_scheduler.c + :export: -- GitLab From ea4a202053c94b1be0e056b66032961523cc9aa3 Mon Sep 17 00:00:00 2001 From: Eric Bernstein <eric.bernstein@amd.com> Date: Tue, 1 May 2018 15:21:42 -0400 Subject: [PATCH 0309/1506] drm/amd/display: pass pipe_ctx straight to blank_pixel_data Signed-off-by: Eric Bernstein <eric.bernstein@amd.com> Reviewed-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c | 10 +++++----- drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h | 3 +-- 2 files changed, 6 insertions(+), 7 deletions(-) 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 f8e0576af6e0b..52924ef50db6a 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 @@ -2063,12 +2063,13 @@ static void update_dchubp_dpp( static void dcn10_blank_pixel_data( struct dc *dc, - struct stream_resource *stream_res, - struct dc_stream_state *stream, + struct pipe_ctx *pipe_ctx, bool blank) { enum dc_color_space color_space; struct tg_color black_color = {0}; + struct stream_resource *stream_res = &pipe_ctx->stream_res; + struct dc_stream_state *stream = pipe_ctx->stream; /* program otg blank color */ color_space = stream->output_color_space; @@ -2127,8 +2128,7 @@ static void program_all_pipe_in_tree( pipe_ctx->stream_res.tg->funcs->program_global_sync( pipe_ctx->stream_res.tg); - dc->hwss.blank_pixel_data(dc, &pipe_ctx->stream_res, - pipe_ctx->stream, blank); + dc->hwss.blank_pixel_data(dc, pipe_ctx, blank); } if (pipe_ctx->plane_state != NULL) { @@ -2247,7 +2247,7 @@ static void dcn10_apply_ctx_for_surface( if (num_planes == 0) { /* OTG blank before remove all front end */ - dc->hwss.blank_pixel_data(dc, &top_pipe_to_program->stream_res, top_pipe_to_program->stream, true); + dc->hwss.blank_pixel_data(dc, top_pipe_to_program, true); } /* Disconnect unused mpcc */ 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 63fc6c4997892..52db80fbe9876 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h @@ -160,8 +160,7 @@ struct hw_sequencer_funcs { bool lock); void (*blank_pixel_data)( struct dc *dc, - struct stream_resource *stream_res, - struct dc_stream_state *stream, + struct pipe_ctx *pipe_ctx, bool blank); void (*set_bandwidth)( -- GitLab From 66e48cd37147e153cef61bcbfbfa4771fe632207 Mon Sep 17 00:00:00 2001 From: Charlene Liu <charlene.liu@amd.com> Date: Thu, 3 May 2018 17:51:07 -0400 Subject: [PATCH 0310/1506] drm/amd/display: Clean up submit_channel_request Signed-off-by: Charlene Liu <charlene.liu@amd.com> Reviewed-by: Vitaly Prosyak <Vitaly.Prosyak@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../dc/i2caux/dce110/aux_engine_dce110.c | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.c b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.c index 5f47f6c007ac0..90535787a4618 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.c +++ b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.c @@ -198,27 +198,27 @@ static void submit_channel_request( ((request->type == AUX_TRANSACTION_TYPE_I2C) && ((request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE) || (request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT))); + if (REG(AUXN_IMPCAL)) { + /* clear_aux_error */ + REG_UPDATE_SEQ(AUXN_IMPCAL, AUXN_CALOUT_ERROR_AK, + 1, + 0); - /* clear_aux_error */ - REG_UPDATE_SEQ(AUXN_IMPCAL, AUXN_CALOUT_ERROR_AK, - 1, - 0); - - REG_UPDATE_SEQ(AUXP_IMPCAL, AUXP_CALOUT_ERROR_AK, - 1, - 0); - - /* force_default_calibrate */ - REG_UPDATE_1BY1_2(AUXN_IMPCAL, - AUXN_IMPCAL_ENABLE, 1, - AUXN_IMPCAL_OVERRIDE_ENABLE, 0); + REG_UPDATE_SEQ(AUXP_IMPCAL, AUXP_CALOUT_ERROR_AK, + 1, + 0); - /* bug? why AUXN update EN and OVERRIDE_EN 1 by 1 while AUX P toggles OVERRIDE? */ + /* force_default_calibrate */ + REG_UPDATE_1BY1_2(AUXN_IMPCAL, + AUXN_IMPCAL_ENABLE, 1, + AUXN_IMPCAL_OVERRIDE_ENABLE, 0); - REG_UPDATE_SEQ(AUXP_IMPCAL, AUXP_IMPCAL_OVERRIDE_ENABLE, - 1, - 0); + /* bug? why AUXN update EN and OVERRIDE_EN 1 by 1 while AUX P toggles OVERRIDE? */ + REG_UPDATE_SEQ(AUXP_IMPCAL, AUXP_IMPCAL_OVERRIDE_ENABLE, + 1, + 0); + } /* set the delay and the number of bytes to write */ /* The length include -- GitLab From 9a08f51fa737d6cc167beb98bc21db8821b2dff2 Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Date: Thu, 3 May 2018 13:42:43 -0400 Subject: [PATCH 0311/1506] drm/amd/display: upgrade scaler math This change will allow the viewport overlap to apply to rotated/ mirrored surfaces. Viewport overlap results in extra pixels being added to viewport allowing the first few pixels to be scaled as if there is no cut-off(mpo or pipe split) and allows us to get matching crc's between scaled split and unsplit outputs of the same thing. Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Reviewed-by: Charlene Liu <Charlene.Liu@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/display/dc/core/dc_resource.c | 419 ++++++++++++------ 1 file changed, 289 insertions(+), 130 deletions(-) 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 751f3ac9d9214..1d716171e581b 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -522,13 +522,12 @@ static void calculate_viewport(struct pipe_ctx *pipe_ctx) } } -static void calculate_recout(struct pipe_ctx *pipe_ctx, struct view *recout_skip) +static void calculate_recout(struct pipe_ctx *pipe_ctx, struct rect *recout_full) { 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; - int recout_full_x, recout_full_y; bool pri_split = pipe_ctx->bottom_pipe && pipe_ctx->bottom_pipe->plane_state == pipe_ctx->plane_state; bool sec_split = pipe_ctx->top_pipe && @@ -597,20 +596,22 @@ static void calculate_recout(struct pipe_ctx *pipe_ctx, struct view *recout_skip } } /* 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) + * * 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) + 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) + 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_skip->width = pipe_ctx->plane_res.scl_data.recout.x - recout_full_x; - recout_skip->height = pipe_ctx->plane_res.scl_data.recout.y - recout_full_y; + 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; } static void calculate_scaling_ratios(struct pipe_ctx *pipe_ctx) @@ -662,7 +663,7 @@ 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 view *recout_skip) +static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx, struct rect *recout_full) { struct scaler_data *data = &pipe_ctx->plane_res.scl_data; struct rect src = pipe_ctx->plane_state->src_rect; @@ -680,15 +681,14 @@ static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx, struct view *r 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); - } + } else if (pipe_ctx->plane_state->horizontal_mirror) + flip_horz_scan_dir = !flip_horz_scan_dir; /* * Init calculated according to formula: @@ -708,127 +708,286 @@ static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx, struct view *r 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) { + /* 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)); + + int_part = int_part > 0 ? int_part : 0; + data->viewport_c.width += int_part < vp_clip ? int_part : vp_clip; + } - /* Adjust for viewport end clip-off */ - if ((data->viewport.x + data->viewport.width) < (src.x + src.width) && !flip_horz_scan_dir) { - 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.y + data->viewport.height) < (src.y + src.height) && !flip_vert_scan_dir) { - 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.x + data->viewport_c.width) < (src.x + src.width) / vpc_div && !flip_horz_scan_dir) { - 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)); - - int_part = int_part > 0 ? int_part : 0; - data->viewport_c.width += int_part < vp_clip ? int_part : vp_clip; - } - if ((data->viewport_c.y + data->viewport_c.height) < (src.y + src.height) / vpc_div && !flip_vert_scan_dir) { - 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.x && !flip_horz_scan_dir) { - int int_part; - - data->inits.h = dc_fixpt_add(data->inits.h, dc_fixpt_mul_int( - data->ratios.horz, recout_skip->width)); - 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; - 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; + /* Adjust for non-0 viewport offset */ + if (data->viewport.x) { + 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; + 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; + } + data->inits.h.value &= 0xffffffff; + data->inits.h = dc_fixpt_add_int(data->inits.h, int_part); } - data->inits.h.value &= 0xffffffff; - data->inits.h = dc_fixpt_add_int(data->inits.h, int_part); - } - - if (data->viewport_c.x && !flip_horz_scan_dir) { - int int_part; - - data->inits.h_c = dc_fixpt_add(data->inits.h_c, dc_fixpt_mul_int( - data->ratios.horz_c, recout_skip->width)); - 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; + + 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); } - data->inits.h_c.value &= 0xffffffff; - data->inits.h_c = dc_fixpt_add_int(data->inits.h_c, int_part); - } - - if (data->viewport.y && !flip_vert_scan_dir) { - int int_part; - - data->inits.v = dc_fixpt_add(data->inits.v, dc_fixpt_mul_int( - data->ratios.vert, recout_skip->height)); - 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; + } 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)); + + 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; } - data->inits.v.value &= 0xffffffff; - data->inits.v = dc_fixpt_add_int(data->inits.v, int_part); - } - - if (data->viewport_c.y && !flip_vert_scan_dir) { - int int_part; - - data->inits.v_c = dc_fixpt_add(data->inits.v_c, dc_fixpt_mul_int( - data->ratios.vert_c, recout_skip->height)); - 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; + + /* Adjust for viewport end clip-off */ + if ((data->viewport.x + data->viewport.width) < (src.x + src.width)) { + int int_part; + int end_offset = src.x + src.width + - data->viewport.x - data->viewport.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 = dc_fixpt_add(data->inits.h, dc_fixpt_mul_int( + data->ratios.horz, 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) - 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 += 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; + } + data->inits.h.value &= 0xffffffff; + data->inits.h = dc_fixpt_add_int(data->inits.h, 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)); + + 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)); + + 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; + } + + /* 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; + + /* + * 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); + } + + 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; + + /* + * 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); } - data->inits.v_c.value &= 0xffffffff; - data->inits.v_c = dc_fixpt_add_int(data->inits.v_c, int_part); } /* Interlaced inits based on final vert inits */ @@ -846,7 +1005,7 @@ 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 view recout_skip = { 0 }; + struct rect recout_full = { 0 }; bool res = false; DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger); /* Important: scaling ratio calculation requires pixel format, @@ -866,7 +1025,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_skip); + calculate_recout(pipe_ctx, &recout_full); /** * Setting line buffer pixel depth to 24bpp yields banding @@ -910,7 +1069,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_skip); + calculate_inits_and_adj_vp(pipe_ctx, &recout_full); DC_LOG_SCALER( "%s: Viewport:\nheight:%d width:%d x:%d " -- GitLab From ae2389e0fc3d4608ebb212c5c655ac964a4ee501 Mon Sep 17 00:00:00 2001 From: Tony Cheng <tony.cheng@amd.com> Date: Mon, 16 Apr 2018 13:31:05 -0400 Subject: [PATCH 0312/1506] drm/amd/display: dal 3.1.45 Signed-off-by: Tony Cheng <tony.cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 9cfde0ccf4e9d..f01c6c1711d7c 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.1.44" +#define DC_VER "3.1.45" #define MAX_SURFACES 3 #define MAX_STREAMS 6 -- GitLab From f9430b235dd46c7753a018fa39e3c31981b0a54d Mon Sep 17 00:00:00 2001 From: Anthony Koo <Anthony.Koo@amd.com> Date: Tue, 8 May 2018 11:24:05 -0400 Subject: [PATCH 0313/1506] drm/amd/display: Prefix event prints with ==Event== Signed-off-by: Anthony Koo <Anthony.Koo@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/modules/stats/stats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/modules/stats/stats.c b/drivers/gpu/drm/amd/display/modules/stats/stats.c index 3f7d47fdc3679..fa0665d09075e 100644 --- a/drivers/gpu/drm/amd/display/modules/stats/stats.c +++ b/drivers/gpu/drm/amd/display/modules/stats/stats.c @@ -240,7 +240,7 @@ void mod_stats_dump(struct mod_stats *mod_stats) for (int i = 0; i < core_stats->entry_id; i++) { if (event_index < core_stats->event_index && i == events[event_index].entry_id) { - DISPLAY_STATS("%s\n", events[event_index].event_string); + DISPLAY_STATS("==Event==%s\n", events[event_index].event_string); event_index++; } else if (time_index < core_stats->index && i == time[time_index].entry_id) { -- GitLab From 73770ca53f63489b32175ab8b5ddd4632b747275 Mon Sep 17 00:00:00 2001 From: Hersen Wu <hersenxs.wu@amd.com> Date: Mon, 23 Apr 2018 19:21:45 -0400 Subject: [PATCH 0314/1506] drm/amd/display: AUX will exit when HPD LOW detected This change shorten wait time when HPD LOW. With HPD LOW, without this change, AUX routine delay is 450us. With this change, it is 42us. Signed-off-by: Hersen Wu <hersenxs.wu@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Reviewed-by: Harry Wentland <Harry.Wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../drm/amd/display/dc/i2caux/aux_engine.c | 16 ++++++++++++++ .../drm/amd/display/dc/i2caux/aux_engine.h | 5 ++++- .../dc/i2caux/dce110/aux_engine_dce110.c | 22 ++++++++++++++----- .../gpu/drm/amd/display/dc/i2caux/engine.h | 3 ++- .../amd/display/include/ddc_service_types.h | 3 ++- 5 files changed, 41 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.c b/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.c index bb526ad326e59..1d7309611978e 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.c +++ b/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.c @@ -157,6 +157,10 @@ static void process_read_reply( ctx->operation_succeeded = false; } break; + case AUX_TRANSACTION_REPLY_HPD_DISCON: + ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON; + ctx->operation_succeeded = false; + break; default: ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN; ctx->operation_succeeded = false; @@ -215,6 +219,10 @@ static void process_read_request( * so we should not wait here */ } break; + case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON: + ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON; + ctx->operation_succeeded = false; + break; default: ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN; ctx->operation_succeeded = false; @@ -370,6 +378,10 @@ static void process_write_reply( ctx->operation_succeeded = false; } break; + case AUX_TRANSACTION_REPLY_HPD_DISCON: + ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON; + ctx->operation_succeeded = false; + break; default: ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN; ctx->operation_succeeded = false; @@ -422,6 +434,10 @@ static void process_write_request( * so we should not wait here */ } break; + case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON: + ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON; + ctx->operation_succeeded = false; + break; default: ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN; ctx->operation_succeeded = false; diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.h b/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.h index 8e71324ccb109..b9e35d0474c6a 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.h +++ b/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.h @@ -51,6 +51,8 @@ enum aux_transaction_reply { AUX_TRANSACTION_REPLY_I2C_NACK = 0x10, AUX_TRANSACTION_REPLY_I2C_DEFER = 0x20, + AUX_TRANSACTION_REPLY_HPD_DISCON = 0x40, + AUX_TRANSACTION_REPLY_INVALID = 0xFF }; @@ -64,7 +66,8 @@ enum aux_channel_operation_result { AUX_CHANNEL_OPERATION_SUCCEEDED, AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN, AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY, - AUX_CHANNEL_OPERATION_FAILED_TIMEOUT + AUX_CHANNEL_OPERATION_FAILED_TIMEOUT, + AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON }; struct aux_engine; diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.c b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.c index 90535787a4618..2b927f25937b4 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.c +++ b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.c @@ -291,6 +291,12 @@ static void process_channel_reply( value = REG_GET(AUX_SW_STATUS, AUX_SW_REPLY_BYTE_COUNT, &bytes_replied); + /* in case HPD is LOW, exit AUX transaction */ + if ((value & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) { + reply->status = AUX_TRANSACTION_REPLY_HPD_DISCON; + return; + } + if (bytes_replied) { uint32_t reply_result; @@ -347,8 +353,10 @@ static void process_channel_reply( * because there was surely an error that was asserted * that should have been handled * for hot plug case, this could happens*/ - if (!(value & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) + if (!(value & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) { + reply->status = AUX_TRANSACTION_REPLY_INVALID; ASSERT_CRITICAL(false); + } } } @@ -371,6 +379,10 @@ static enum aux_channel_operation_result get_channel_status( value = REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 1, 10, aux110->timeout_period/10); + /* in case HPD is LOW, exit AUX transaction */ + if ((value & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) + return AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON; + /* Note that the following bits are set in 'status.bits' * during CTS 4.2.1.2 (FW 3.3.1): * AUX_SW_RX_MIN_COUNT_VIOL, AUX_SW_RX_INVALID_STOP, @@ -402,10 +414,10 @@ static enum aux_channel_operation_result get_channel_status( return AUX_CHANNEL_OPERATION_SUCCEEDED; } } else { - /*time_elapsed >= aux_engine->timeout_period */ - if (!(value & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) - ASSERT_CRITICAL(false); - + /*time_elapsed >= aux_engine->timeout_period + * AUX_SW_STATUS__AUX_SW_HPD_DISCON = at this point + */ + ASSERT_CRITICAL(false); return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT; } } diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/engine.h b/drivers/gpu/drm/amd/display/dc/i2caux/engine.h index 33de8a8834dc1..c1109706a8808 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/engine.h +++ b/drivers/gpu/drm/amd/display/dc/i2caux/engine.h @@ -53,7 +53,8 @@ enum i2caux_transaction_status { I2CAUX_TRANSACTION_STATUS_FAILED_INCOMPLETE, I2CAUX_TRANSACTION_STATUS_FAILED_OPERATION, I2CAUX_TRANSACTION_STATUS_FAILED_INVALID_OPERATION, - I2CAUX_TRANSACTION_STATUS_FAILED_BUFFER_OVERFLOW + I2CAUX_TRANSACTION_STATUS_FAILED_BUFFER_OVERFLOW, + I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON }; struct i2caux_transaction_request { diff --git a/drivers/gpu/drm/amd/display/include/ddc_service_types.h b/drivers/gpu/drm/amd/display/include/ddc_service_types.h index 019e7a095ea10..d968956a10cd5 100644 --- a/drivers/gpu/drm/amd/display/include/ddc_service_types.h +++ b/drivers/gpu/drm/amd/display/include/ddc_service_types.h @@ -40,7 +40,8 @@ enum ddc_result { DDC_RESULT_FAILED_INCOMPLETE, DDC_RESULT_FAILED_OPERATION, DDC_RESULT_FAILED_INVALID_OPERATION, - DDC_RESULT_FAILED_BUFFER_OVERFLOW + DDC_RESULT_FAILED_BUFFER_OVERFLOW, + DDC_RESULT_FAILED_HPD_DISCON }; enum ddc_service_type { -- GitLab From 0f6ca3bac44dd6c16e3b4c484243bbb1dad3f6a7 Mon Sep 17 00:00:00 2001 From: Eric Bernstein <eric.bernstein@amd.com> Date: Tue, 8 May 2018 16:20:52 -0400 Subject: [PATCH 0315/1506] drm/amd/display: Add function to get optc active size Signed-off-by: Eric Bernstein <eric.bernstein@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/display/dc/dcn10/dcn10_optc.c | 32 +++++++++++++++++++ .../gpu/drm/amd/display/dc/dcn10/dcn10_optc.h | 4 +++ .../amd/display/dc/inc/hw/timing_generator.h | 3 ++ 3 files changed, 39 insertions(+) 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 f2fbce0e3fc56..e6a3ade154b92 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c @@ -1257,6 +1257,37 @@ void optc1_read_otg_state(struct optc *optc1, OPTC_UNDERFLOW_OCCURRED_STATUS, &s->underflow_occurred_status); } +bool optc1_get_otg_active_size(struct timing_generator *optc, + uint32_t *otg_active_width, + uint32_t *otg_active_height) +{ + uint32_t otg_enabled; + uint32_t v_blank_start; + uint32_t v_blank_end; + uint32_t h_blank_start; + uint32_t h_blank_end; + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + + REG_GET(OTG_CONTROL, + OTG_MASTER_EN, &otg_enabled); + + if (otg_enabled == 0) + return false; + + REG_GET_2(OTG_V_BLANK_START_END, + OTG_V_BLANK_START, &v_blank_start, + OTG_V_BLANK_END, &v_blank_end); + + REG_GET_2(OTG_H_BLANK_START_END, + OTG_H_BLANK_START, &h_blank_start, + OTG_H_BLANK_END, &h_blank_end); + + *otg_active_width = v_blank_start - v_blank_end; + *otg_active_height = h_blank_start - h_blank_end; + return true; +} + void optc1_clear_optc_underflow(struct timing_generator *optc) { struct optc *optc1 = DCN10TG_FROM_TG(optc); @@ -1305,6 +1336,7 @@ static const struct timing_generator_funcs dcn10_tg_funcs = { .get_position = optc1_get_position, .get_frame_count = optc1_get_vblank_counter, .get_scanoutpos = optc1_get_crtc_scanoutpos, + .get_otg_active_size = optc1_get_otg_active_size, .set_early_control = optc1_set_early_control, /* used by enable_timing_synchronization. Not need for FPGA */ .wait_for_state = optc1_wait_for_state, 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 c62052f46460e..59ed272e0c493 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h @@ -507,4 +507,8 @@ bool optc1_is_optc_underflow_occurred(struct timing_generator *optc); void optc1_set_blank_data_double_buffer(struct timing_generator *optc, bool enable); +bool optc1_get_otg_active_size(struct timing_generator *optc, + uint32_t *otg_active_width, + uint32_t *otg_active_height); + #endif /* __DC_TIMING_GENERATOR_DCN10_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h index 69cb0a1053000..af700c7dac508 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h @@ -156,6 +156,9 @@ struct timing_generator_funcs { uint32_t *v_blank_end, uint32_t *h_position, uint32_t *v_position); + bool (*get_otg_active_size)(struct timing_generator *optc, + uint32_t *otg_active_width, + uint32_t *otg_active_height); void (*set_early_control)(struct timing_generator *tg, uint32_t early_cntl); void (*wait_for_state)(struct timing_generator *tg, -- GitLab From 8ca809008571f87e7d73535175601328175dac81 Mon Sep 17 00:00:00 2001 From: Anthony Koo <Anthony.Koo@amd.com> Date: Tue, 8 May 2018 17:08:57 -0400 Subject: [PATCH 0316/1506] drm/amd/display: add DPCD read for Sink ieee OUI Signed-off-by: Anthony Koo <Anthony.Koo@amd.com> Reviewed-by: Aric Cyr <Aric.Cyr@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) 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 7857cb42b3e62..1a42ee5113a92 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 @@ -2305,6 +2305,7 @@ static bool retrieve_link_cap(struct dc_link *link) { uint8_t dpcd_data[DP_ADAPTER_CAP - DP_DPCD_REV + 1]; + struct dp_device_vendor_id sink_id; union down_stream_port_count down_strm_port_count; union edp_configuration_cap edp_config_cap; union dp_downstream_port_present ds_port = { 0 }; @@ -2391,6 +2392,17 @@ static bool retrieve_link_cap(struct dc_link *link) &link->dpcd_caps.sink_count.raw, sizeof(link->dpcd_caps.sink_count.raw)); + /* read sink ieee oui */ + core_link_read_dpcd(link, + DP_SINK_OUI, + (uint8_t *)(&sink_id), + sizeof(sink_id)); + + link->dpcd_caps.sink_dev_id = + (sink_id.ieee_oui[0] << 16) + + (sink_id.ieee_oui[1] << 8) + + (sink_id.ieee_oui[2]); + /* Connectivity log: detection */ CONN_DATA_DETECT(link, dpcd_data, sizeof(dpcd_data), "Rx Caps: "); -- GitLab From cb1d7eacb58f7d1b7d0e57b26dc02d45eada4a3c Mon Sep 17 00:00:00 2001 From: Hersen Wu <hersenxs.wu@amd.com> Date: Tue, 8 May 2018 16:35:09 -0400 Subject: [PATCH 0317/1506] drm/amd/display: Fix indentation in dcn10 resource constructor Signed-off-by: Hersen Wu <hersenxs.wu@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c index df5cb2d1d1645..99c223bcad71f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c @@ -1004,7 +1004,8 @@ static bool construct( ctx->dc_bios->regs = &bios_regs; - pool->base.res_cap = &res_cap; + pool->base.res_cap = &res_cap; + pool->base.funcs = &dcn10_res_pool_funcs; /* -- GitLab From bf58968647729ce320a7ef27077d60b7b2cdcd00 Mon Sep 17 00:00:00 2001 From: Aric Cyr <aric.cyr@amd.com> Date: Wed, 9 May 2018 14:36:50 -0400 Subject: [PATCH 0318/1506] drm/amd/display: Default log masks should include all connectivity events Signed-off-by: Aric Cyr <aric.cyr@amd.com> Reviewed-by: Jun Lei <Jun.Lei@amd.com> Reviewed-by: Aric Cyr <Aric.Cyr@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../drm/amd/display/dc/basics/log_helpers.c | 2 + .../gpu/drm/amd/display/dc/basics/logger.c | 83 ++++++++++--------- .../amd/display/include/logger_interface.h | 2 + 3 files changed, 46 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/basics/log_helpers.c b/drivers/gpu/drm/amd/display/dc/basics/log_helpers.c index 021451549ff78..f6c00a51d51a3 100644 --- a/drivers/gpu/drm/amd/display/dc/basics/log_helpers.c +++ b/drivers/gpu/drm/amd/display/dc/basics/log_helpers.c @@ -78,6 +78,8 @@ void dc_conn_log(struct dc_context *ctx, if (i == NUM_ELEMENTS(signal_type_info_tbl)) goto fail; + dm_logger_append_heading(&entry); + dm_logger_append(&entry, "[%s][ConnIdx:%d] ", signal_type_info_tbl[i].name, link->link_index); diff --git a/drivers/gpu/drm/amd/display/dc/basics/logger.c b/drivers/gpu/drm/amd/display/dc/basics/logger.c index 738a818d58d1c..733bc5bd760b8 100644 --- a/drivers/gpu/drm/amd/display/dc/basics/logger.c +++ b/drivers/gpu/drm/amd/display/dc/basics/logger.c @@ -32,8 +32,9 @@ static const struct dc_log_type_info log_type_info_tbl[] = { {LOG_ERROR, "Error"}, {LOG_WARNING, "Warning"}, - {LOG_DEBUG, "Debug"}, + {LOG_DEBUG, "Debug"}, {LOG_DC, "DC_Interface"}, + {LOG_DTN, "DTN"}, {LOG_SURFACE, "Surface"}, {LOG_HW_HOTPLUG, "HW_Hotplug"}, {LOG_HW_LINK_TRAINING, "HW_LKTN"}, @@ -60,7 +61,7 @@ static const struct dc_log_type_info log_type_info_tbl[] = { {LOG_EVENT_LINK_LOSS, "LinkLoss"}, {LOG_EVENT_UNDERFLOW, "Underflow"}, {LOG_IF_TRACE, "InterfaceTrace"}, - {LOG_DTN, "DTN"}, + {LOG_PERF_TRACE, "PerfTrace"}, {LOG_DISPLAYSTATS, "DisplayStats"} }; @@ -128,8 +129,45 @@ uint32_t dal_logger_destroy(struct dal_logger **logger) } /* ------------------------------------------------------------------------ */ +void dm_logger_append_heading(struct log_entry *entry) +{ + int j; + + for (j = 0; j < NUM_ELEMENTS(log_type_info_tbl); j++) { + const struct dc_log_type_info *info = &log_type_info_tbl[j]; + if (info->type == entry->type) + dm_logger_append(entry, "[%s]\t", info->name); + } +} + + +/* Print everything unread existing in log_buffer to debug console*/ +void dm_logger_flush_buffer(struct dal_logger *logger, bool should_warn) +{ + char *string_start = &logger->log_buffer[logger->buffer_read_offset]; + + if (should_warn) + dm_output_to_console( + "---------------- FLUSHING LOG BUFFER ----------------\n"); + while (logger->buffer_read_offset < logger->buffer_write_offset) { + + if (logger->log_buffer[logger->buffer_read_offset] == '\0') { + dm_output_to_console("%s", string_start); + string_start = logger->log_buffer + logger->buffer_read_offset + 1; + } + logger->buffer_read_offset++; + } + if (should_warn) + dm_output_to_console( + "-------------- END FLUSHING LOG BUFFER --------------\n\n"); +} +/* ------------------------------------------------------------------------ */ + +/* Warning: Be careful that 'msg' is null terminated and the total size is + * less than DAL_LOGGER_BUFFER_MAX_LOG_LINE_SIZE (256) including '\0' + */ static bool dal_logger_should_log( struct dal_logger *logger, enum dc_log_type log_type) @@ -159,26 +197,6 @@ static void log_to_debug_console(struct log_entry *entry) } } -/* Print everything unread existing in log_buffer to debug console*/ -void dm_logger_flush_buffer(struct dal_logger *logger, bool should_warn) -{ - char *string_start = &logger->log_buffer[logger->buffer_read_offset]; - - if (should_warn) - dm_output_to_console( - "---------------- FLUSHING LOG BUFFER ----------------\n"); - while (logger->buffer_read_offset < logger->buffer_write_offset) { - - if (logger->log_buffer[logger->buffer_read_offset] == '\0') { - dm_output_to_console("%s", string_start); - string_start = logger->log_buffer + logger->buffer_read_offset + 1; - } - logger->buffer_read_offset++; - } - if (should_warn) - dm_output_to_console( - "-------------- END FLUSHING LOG BUFFER --------------\n\n"); -} static void log_to_internal_buffer(struct log_entry *entry) { @@ -229,19 +247,6 @@ static void log_to_internal_buffer(struct log_entry *entry) } } -static void log_heading(struct log_entry *entry) -{ - int j; - - for (j = 0; j < NUM_ELEMENTS(log_type_info_tbl); j++) { - - const struct dc_log_type_info *info = &log_type_info_tbl[j]; - - if (info->type == entry->type) - dm_logger_append(entry, "[%s]\t", info->name); - } -} - static void append_entry( struct log_entry *entry, char *buffer, @@ -259,11 +264,7 @@ static void append_entry( entry->buf_offset += buf_size; } -/* ------------------------------------------------------------------------ */ -/* Warning: Be careful that 'msg' is null terminated and the total size is - * less than DAL_LOGGER_BUFFER_MAX_LOG_LINE_SIZE (256) including '\0' - */ void dm_logger_write( struct dal_logger *logger, enum dc_log_type log_type, @@ -287,7 +288,7 @@ void dm_logger_write( entry.type = log_type; - log_heading(&entry); + dm_logger_append_heading(&entry); size = dm_log_to_buffer( buffer, LOG_MAX_LINE_SIZE - 1, msg, args); @@ -372,7 +373,7 @@ void dm_logger_open( logger->open_count++; - log_heading(entry); + dm_logger_append_heading(entry); } void dm_logger_close(struct log_entry *entry) diff --git a/drivers/gpu/drm/amd/display/include/logger_interface.h b/drivers/gpu/drm/amd/display/include/logger_interface.h index dc98d6d4b2bd0..0f10ed710e0d0 100644 --- a/drivers/gpu/drm/amd/display/include/logger_interface.h +++ b/drivers/gpu/drm/amd/display/include/logger_interface.h @@ -62,6 +62,8 @@ void dm_logger_append_va( const char *msg, va_list args); +void dm_logger_append_heading(struct log_entry *entry); + void dm_logger_open( struct dal_logger *logger, struct log_entry *entry, -- GitLab From 3c8e4316a0bf6f65e8fbcf777abbc3b0e629e800 Mon Sep 17 00:00:00 2001 From: Nikola Cornij <nikola.cornij@amd.com> Date: Wed, 9 May 2018 17:07:36 -0400 Subject: [PATCH 0319/1506] drm/amd/display: Optimize DP_SINK_STATUS_ESI range read on HPD DP_SINK_STATUS_ESI range data is not continual, but rather than getting it in two AUX reads, it's quicker to read more bytes in a AUX read and then memcpy the required fields (it's only 8 more bytes to read). Signed-off-by: Nikola Cornij <nikola.cornij@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/display/dc/core/dc_link_dp.c | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) 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 1a42ee5113a92..509f265663d27 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 @@ -1647,22 +1647,26 @@ static enum dc_status read_hpd_rx_irq_data( irq_data->raw, sizeof(union hpd_irq_data)); else { - /* Read 2 bytes at this location,... */ + /* Read 14 bytes in a single read and then copy only the required fields. + * This is more efficient than doing it in two separate AUX reads. */ + + uint8_t tmp[DP_SINK_STATUS_ESI - DP_SINK_COUNT_ESI + 1]; + retval = core_link_read_dpcd( link, DP_SINK_COUNT_ESI, - irq_data->raw, - 2); + tmp, + sizeof(tmp)); if (retval != DC_OK) return retval; - /* ... then read remaining 4 at the other location */ - retval = core_link_read_dpcd( - link, - DP_LANE0_1_STATUS_ESI, - &irq_data->raw[2], - 4); + irq_data->bytes.sink_cnt.raw = tmp[DP_SINK_COUNT_ESI - DP_SINK_COUNT_ESI]; + irq_data->bytes.device_service_irq.raw = tmp[DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0 - DP_SINK_COUNT_ESI]; + irq_data->bytes.lane01_status.raw = tmp[DP_LANE0_1_STATUS_ESI - DP_SINK_COUNT_ESI]; + irq_data->bytes.lane23_status.raw = tmp[DP_LANE2_3_STATUS_ESI - DP_SINK_COUNT_ESI]; + irq_data->bytes.lane_status_updated.raw = tmp[DP_LANE_ALIGN_STATUS_UPDATED_ESI - DP_SINK_COUNT_ESI]; + irq_data->bytes.sink_status.raw = tmp[DP_SINK_STATUS_ESI - DP_SINK_COUNT_ESI]; } return retval; -- GitLab From 4ea209073d229a0cb65f9978e83fa7c044026416 Mon Sep 17 00:00:00 2001 From: Krunoslav Kovac <Krunoslav.Kovac@amd.com> Date: Tue, 8 May 2018 16:03:58 -0400 Subject: [PATCH 0320/1506] drm/amd/display: Dynamic HDR metadata mem buffer Basic framework: - caps for reporting dynamic HDR metadata support - allocation of frame buffer memory and storage Signed-off-by: Krunoslav Kovac <Krunoslav.Kovac@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Reviewed-by: Anthony Koo <Anthony.Koo@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dc.h | 1 + drivers/gpu/drm/amd/display/dc/dc_stream.h | 2 ++ 2 files changed, 3 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index f01c6c1711d7c..22d113eca4529 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -68,6 +68,7 @@ struct dc_caps { uint32_t max_planes; uint32_t max_downscale_ratio; uint32_t i2c_speed_in_khz; + uint32_t dmdata_alloc_size; unsigned int max_cursor_size; unsigned int max_video_width; int linear_pitch_alignment; diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index d7e6d53bb3834..e6e944423b3c1 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -59,6 +59,8 @@ struct dc_stream_state { struct freesync_context freesync_ctx; struct dc_info_packet hdr_static_metadata; + PHYSICAL_ADDRESS_LOC dmdata_address; + struct dc_transfer_func *out_transfer_func; struct colorspace_transform gamut_remap_matrix; struct dc_csc_transform csc_color_matrix; -- GitLab From 1a05873f21d6192575382afd2feb18df935e46f0 Mon Sep 17 00:00:00 2001 From: Anthony Koo <Anthony.Koo@amd.com> Date: Thu, 10 May 2018 14:21:47 -0400 Subject: [PATCH 0321/1506] drm/amd/display: Refactor audio programming Signed-off-by: Anthony Koo <Anthony.Koo@amd.com> Reviewed-by: Aric Cyr <Aric.Cyr@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 24 +- .../display/dc/dce110/dce110_hw_sequencer.c | 256 ++++++++++-------- .../display/dc/dce110/dce110_hw_sequencer.h | 4 + .../amd/display/dc/dcn10/dcn10_hw_sequencer.c | 16 +- .../gpu/drm/amd/display/dc/inc/hw_sequencer.h | 5 + 5 files changed, 163 insertions(+), 142 deletions(-) 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 2fa521812d23b..a9485c10fd77a 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -1861,28 +1861,6 @@ static enum dc_status enable_link( break; } - if (pipe_ctx->stream_res.audio && status == DC_OK) { - struct dc *core_dc = pipe_ctx->stream->ctx->dc; - /* notify audio driver for audio modes of monitor */ - struct pp_smu_funcs_rv *pp_smu = core_dc->res_pool->pp_smu; - unsigned int i, num_audio = 1; - for (i = 0; i < MAX_PIPES; i++) { - /*current_state not updated yet*/ - if (core_dc->current_state->res_ctx.pipe_ctx[i].stream_res.audio != NULL) - num_audio++; - } - - pipe_ctx->stream_res.audio->funcs->az_enable(pipe_ctx->stream_res.audio); - - if (num_audio == 1 && pp_smu != NULL && pp_smu->set_pme_wa_enable != NULL) - /*this is the first audio. apply the PME w/a in order to wake AZ from D3*/ - pp_smu->set_pme_wa_enable(&pp_smu->pp_smu); - /* un-mute audio */ - /* TODO: audio should be per stream rather than per link */ - pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control( - pipe_ctx->stream_res.stream_enc, false); - } - return status; } @@ -2415,6 +2393,8 @@ void core_link_enable_stream( } } + core_dc->hwss.enable_audio_stream(pipe_ctx); + /* turn off otg test pattern if enable */ pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg, CONTROLLER_DP_TEST_PATTERN_VIDEOMODE, 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 c29052b6da5a8..cae0054c102a1 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 @@ -972,19 +972,35 @@ void hwss_edp_backlight_control( edp_receiver_ready_T9(link); } -void dce110_disable_stream(struct pipe_ctx *pipe_ctx, int option) +void dce110_enable_audio_stream(struct pipe_ctx *pipe_ctx) { - struct dc_stream_state *stream = pipe_ctx->stream; - struct dc_link *link = stream->sink->link; - struct dc *dc = pipe_ctx->stream->ctx->dc; + struct dc *core_dc = pipe_ctx->stream->ctx->dc; + /* notify audio driver for audio modes of monitor */ + struct pp_smu_funcs_rv *pp_smu = core_dc->res_pool->pp_smu; + unsigned int i, num_audio = 1; - if (dc_is_hdmi_signal(pipe_ctx->stream->signal)) - pipe_ctx->stream_res.stream_enc->funcs->stop_hdmi_info_packets( - pipe_ctx->stream_res.stream_enc); + if (pipe_ctx->stream_res.audio) { + for (i = 0; i < MAX_PIPES; i++) { + /*current_state not updated yet*/ + if (core_dc->current_state->res_ctx.pipe_ctx[i].stream_res.audio != NULL) + num_audio++; + } - if (dc_is_dp_signal(pipe_ctx->stream->signal)) - pipe_ctx->stream_res.stream_enc->funcs->stop_dp_info_packets( - pipe_ctx->stream_res.stream_enc); + pipe_ctx->stream_res.audio->funcs->az_enable(pipe_ctx->stream_res.audio); + + if (num_audio == 1 && pp_smu != NULL && pp_smu->set_pme_wa_enable != NULL) + /*this is the first audio. apply the PME w/a in order to wake AZ from D3*/ + pp_smu->set_pme_wa_enable(&pp_smu->pp_smu); + /* un-mute audio */ + /* TODO: audio should be per stream rather than per link */ + pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control( + pipe_ctx->stream_res.stream_enc, false); + } +} + +void dce110_disable_audio_stream(struct pipe_ctx *pipe_ctx, int option) +{ + struct dc *dc = pipe_ctx->stream->ctx->dc; pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control( pipe_ctx->stream_res.stream_enc, true); @@ -1015,7 +1031,23 @@ void dce110_disable_stream(struct pipe_ctx *pipe_ctx, int option) * stream->stream_engine_id); */ } +} +void dce110_disable_stream(struct pipe_ctx *pipe_ctx, int option) +{ + struct dc_stream_state *stream = pipe_ctx->stream; + struct dc_link *link = stream->sink->link; + struct dc *dc = pipe_ctx->stream->ctx->dc; + + if (dc_is_hdmi_signal(pipe_ctx->stream->signal)) + pipe_ctx->stream_res.stream_enc->funcs->stop_hdmi_info_packets( + pipe_ctx->stream_res.stream_enc); + + if (dc_is_dp_signal(pipe_ctx->stream->signal)) + pipe_ctx->stream_res.stream_enc->funcs->stop_dp_info_packets( + pipe_ctx->stream_res.stream_enc); + + dc->hwss.disable_audio_stream(pipe_ctx, option); link->link_enc->funcs->connect_dig_be_to_fe( link->link_enc, @@ -1298,6 +1330,30 @@ static enum dc_status apply_single_controller_ctx_to_hw( struct pipe_ctx *pipe_ctx_old = &dc->current_state->res_ctx. pipe_ctx[pipe_ctx->pipe_idx]; + if (pipe_ctx->stream_res.audio != NULL) { + struct audio_output audio_output; + + build_audio_output(context, pipe_ctx, &audio_output); + + if (dc_is_dp_signal(pipe_ctx->stream->signal)) + pipe_ctx->stream_res.stream_enc->funcs->dp_audio_setup( + pipe_ctx->stream_res.stream_enc, + pipe_ctx->stream_res.audio->inst, + &pipe_ctx->stream->audio_info); + else + pipe_ctx->stream_res.stream_enc->funcs->hdmi_audio_setup( + pipe_ctx->stream_res.stream_enc, + pipe_ctx->stream_res.audio->inst, + &pipe_ctx->stream->audio_info, + &audio_output.crtc_info); + + pipe_ctx->stream_res.audio->funcs->az_configure( + pipe_ctx->stream_res.audio, + pipe_ctx->stream->signal, + &audio_output.crtc_info, + &pipe_ctx->stream->audio_info); + } + /* */ dc->hwss.enable_stream_timing(pipe_ctx, context, dc); @@ -1949,6 +2005,86 @@ static void dce110_reset_hw_ctx_wrap( } } +static void dce110_setup_audio_dto( + struct dc *dc, + struct dc_state *context) +{ + int i; + + /* program audio wall clock. use HDMI as clock source if HDMI + * audio active. Otherwise, use DP as clock source + * first, loop to find any HDMI audio, if not, loop find DP audio + */ + /* Setup audio rate clock source */ + /* Issue: + * Audio lag happened on DP monitor when unplug a HDMI monitor + * + * Cause: + * In case of DP and HDMI connected or HDMI only, DCCG_AUDIO_DTO_SEL + * is set to either dto0 or dto1, audio should work fine. + * In case of DP connected only, DCCG_AUDIO_DTO_SEL should be dto1, + * set to dto0 will cause audio lag. + * + * Solution: + * Not optimized audio wall dto setup. When mode set, iterate pipe_ctx, + * find first available pipe with audio, setup audio wall DTO per topology + * instead of per pipe. + */ + 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 == NULL) + continue; + + if (pipe_ctx->top_pipe) + continue; + + if (pipe_ctx->stream->signal != SIGNAL_TYPE_HDMI_TYPE_A) + continue; + + if (pipe_ctx->stream_res.audio != NULL) { + struct audio_output audio_output; + + build_audio_output(context, pipe_ctx, &audio_output); + + pipe_ctx->stream_res.audio->funcs->wall_dto_setup( + pipe_ctx->stream_res.audio, + pipe_ctx->stream->signal, + &audio_output.crtc_info, + &audio_output.pll_info); + break; + } + } + + /* no HDMI audio is found, try DP audio */ + if (i == dc->res_pool->pipe_count) { + 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 == NULL) + continue; + + if (pipe_ctx->top_pipe) + continue; + + if (!dc_is_dp_signal(pipe_ctx->stream->signal)) + continue; + + if (pipe_ctx->stream_res.audio != NULL) { + struct audio_output audio_output; + + build_audio_output(context, pipe_ctx, &audio_output); + + pipe_ctx->stream_res.audio->funcs->wall_dto_setup( + pipe_ctx->stream_res.audio, + pipe_ctx->stream->signal, + &audio_output.crtc_info, + &audio_output.pll_info); + break; + } + } + } +} enum dc_status dce110_apply_ctx_to_hw( struct dc *dc, @@ -2040,79 +2176,8 @@ enum dc_status dce110_apply_ctx_to_hw( dc->res_pool->display_clock, context->bw.dce.dispclk_khz * 115 / 100); } - /* program audio wall clock. use HDMI as clock source if HDMI - * audio active. Otherwise, use DP as clock source - * first, loop to find any HDMI audio, if not, loop find DP audio - */ - /* Setup audio rate clock source */ - /* Issue: - * Audio lag happened on DP monitor when unplug a HDMI monitor - * - * Cause: - * In case of DP and HDMI connected or HDMI only, DCCG_AUDIO_DTO_SEL - * is set to either dto0 or dto1, audio should work fine. - * In case of DP connected only, DCCG_AUDIO_DTO_SEL should be dto1, - * set to dto0 will cause audio lag. - * - * Solution: - * Not optimized audio wall dto setup. When mode set, iterate pipe_ctx, - * find first available pipe with audio, setup audio wall DTO per topology - * instead of per pipe. - */ - 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 == NULL) - continue; - - if (pipe_ctx->top_pipe) - continue; - - if (pipe_ctx->stream->signal != SIGNAL_TYPE_HDMI_TYPE_A) - continue; - - if (pipe_ctx->stream_res.audio != NULL) { - struct audio_output audio_output; - - build_audio_output(context, pipe_ctx, &audio_output); - - pipe_ctx->stream_res.audio->funcs->wall_dto_setup( - pipe_ctx->stream_res.audio, - pipe_ctx->stream->signal, - &audio_output.crtc_info, - &audio_output.pll_info); - break; - } - } - - /* no HDMI audio is found, try DP audio */ - if (i == dc->res_pool->pipe_count) { - 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 == NULL) - continue; - - if (pipe_ctx->top_pipe) - continue; - - if (!dc_is_dp_signal(pipe_ctx->stream->signal)) - continue; - - if (pipe_ctx->stream_res.audio != NULL) { - struct audio_output audio_output; - - build_audio_output(context, pipe_ctx, &audio_output); - pipe_ctx->stream_res.audio->funcs->wall_dto_setup( - pipe_ctx->stream_res.audio, - pipe_ctx->stream->signal, - &audio_output.crtc_info, - &audio_output.pll_info); - break; - } - } - } + dce110_setup_audio_dto(dc, context); for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe_ctx_old = @@ -2131,31 +2196,6 @@ enum dc_status dce110_apply_ctx_to_hw( if (pipe_ctx->top_pipe) continue; - if (context->res_ctx.pipe_ctx[i].stream_res.audio != NULL) { - - struct audio_output audio_output; - - build_audio_output(context, pipe_ctx, &audio_output); - - if (dc_is_dp_signal(pipe_ctx->stream->signal)) - pipe_ctx->stream_res.stream_enc->funcs->dp_audio_setup( - pipe_ctx->stream_res.stream_enc, - pipe_ctx->stream_res.audio->inst, - &pipe_ctx->stream->audio_info); - else - pipe_ctx->stream_res.stream_enc->funcs->hdmi_audio_setup( - pipe_ctx->stream_res.stream_enc, - pipe_ctx->stream_res.audio->inst, - &pipe_ctx->stream->audio_info, - &audio_output.crtc_info); - - pipe_ctx->stream_res.audio->funcs->az_configure( - pipe_ctx->stream_res.audio, - pipe_ctx->stream->signal, - &audio_output.crtc_info, - &pipe_ctx->stream->audio_info); - } - status = apply_single_controller_ctx_to_hw( pipe_ctx, context, @@ -2968,6 +3008,8 @@ static const struct hw_sequencer_funcs dce110_funcs = { .disable_stream = dce110_disable_stream, .unblank_stream = dce110_unblank_stream, .blank_stream = dce110_blank_stream, + .enable_audio_stream = dce110_enable_audio_stream, + .disable_audio_stream = dce110_disable_audio_stream, .enable_display_pipe_clock_gating = enable_display_pipe_clock_gating, .enable_display_power_gating = dce110_enable_display_power_gating, .disable_plane = dce110_power_down_fe, diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h index 5d7e9f5168277..f48d5a68d2386 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h @@ -49,6 +49,10 @@ void dce110_unblank_stream(struct pipe_ctx *pipe_ctx, struct dc_link_settings *link_settings); void dce110_blank_stream(struct pipe_ctx *pipe_ctx); + +void dce110_enable_audio_stream(struct pipe_ctx *pipe_ctx); +void dce110_disable_audio_stream(struct pipe_ctx *pipe_ctx, int option); + void dce110_update_info_frame(struct pipe_ctx *pipe_ctx); void dce110_set_avmute(struct pipe_ctx *pipe_ctx, bool enable); 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 52924ef50db6a..03eb736a312ff 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 @@ -719,19 +719,7 @@ static void reset_back_end_for_pipe( if (!pipe_ctx->stream->dpms_off) core_link_disable_stream(pipe_ctx, FREE_ACQUIRED_RESOURCE); else if (pipe_ctx->stream_res.audio) { - /* - * if stream is already disabled outside of commit streams path, - * audio disable was skipped. Need to do it here - */ - pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio); - - if (dc->caps.dynamic_audio == true) { - /*we have to dynamic arbitrate the audio endpoints*/ - pipe_ctx->stream_res.audio = NULL; - /*we free the resource, need reset is_audio_acquired*/ - update_audio_usage(&dc->current_state->res_ctx, dc->res_pool, pipe_ctx->stream_res.audio, false); - } - + dc->hwss.disable_audio_stream(pipe_ctx, FREE_ACQUIRED_RESOURCE); } } @@ -2778,6 +2766,8 @@ static const struct hw_sequencer_funcs dcn10_funcs = { .disable_stream = dce110_disable_stream, .unblank_stream = dce110_unblank_stream, .blank_stream = dce110_blank_stream, + .enable_audio_stream = dce110_enable_audio_stream, + .disable_audio_stream = dce110_disable_audio_stream, .enable_display_power_gating = dcn10_dummy_display_power_gating, .disable_plane = dcn10_disable_plane, .blank_pixel_data = dcn10_blank_pixel_data, 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 52db80fbe9876..a71770ed4b9f6 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h @@ -154,6 +154,11 @@ struct hw_sequencer_funcs { struct dc_link_settings *link_settings); void (*blank_stream)(struct pipe_ctx *pipe_ctx); + + void (*enable_audio_stream)(struct pipe_ctx *pipe_ctx); + + void (*disable_audio_stream)(struct pipe_ctx *pipe_ctx, int option); + void (*pipe_control_lock)( struct dc *dc, struct pipe_ctx *pipe, -- GitLab From 43610a9be188ca67189363334833c5e815e5e86c Mon Sep 17 00:00:00 2001 From: Vitaly Prosyak <vitaly.prosyak@amd.com> Date: Thu, 10 May 2018 12:37:35 -0500 Subject: [PATCH 0322/1506] drm/amd/display: HLG support Low level calculation methods. Signed-off-by: Vitaly Prosyak <vitaly.prosyak@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dc.h | 2 + .../amd/display/modules/color/color_gamma.c | 137 ++++++++++++++++++ 2 files changed, 139 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 22d113eca4529..7a70a24ef736c 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -378,6 +378,8 @@ enum dc_transfer_func_predefined { TRANSFER_FUNCTION_PQ, TRANSFER_FUNCTION_LINEAR, TRANSFER_FUNCTION_UNITY, + TRANSFER_FUNCTION_HLG, + TRANSFER_FUNCTION_HLG12 }; struct dc_transfer_func { diff --git a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c index 0cd111d590183..b422fa2c6a79f 100644 --- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c +++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c @@ -131,6 +131,63 @@ static void compute_de_pq(struct fixed31_32 in_x, struct fixed31_32 *out_y) dc_fixpt_div(dc_fixpt_one, m1)); } + +/*de gamma, none linear to linear*/ +static void compute_hlg_oetf(struct fixed31_32 in_x, bool is_light0_12, struct fixed31_32 *out_y) +{ + struct fixed31_32 a; + struct fixed31_32 b; + struct fixed31_32 c; + struct fixed31_32 threshold; + struct fixed31_32 reference_white_level; + + a = dc_fixpt_from_fraction(17883277, 100000000); + if (is_light0_12) { + /*light 0-12*/ + b = dc_fixpt_from_fraction(28466892, 100000000); + c = dc_fixpt_from_fraction(55991073, 100000000); + threshold = dc_fixpt_one; + reference_white_level = dc_fixpt_half; + } else { + /*light 0-1*/ + b = dc_fixpt_from_fraction(2372241, 100000000); + c = dc_fixpt_add(dc_fixpt_one, dc_fixpt_from_fraction(429347, 100000000)); + threshold = dc_fixpt_from_fraction(1, 12); + reference_white_level = dc_fixpt_pow(dc_fixpt_from_fraction(3, 1), dc_fixpt_half); + } + if (dc_fixpt_lt(threshold, in_x)) + *out_y = dc_fixpt_add(c, dc_fixpt_mul(a, dc_fixpt_log(dc_fixpt_sub(in_x, b)))); + else + *out_y = dc_fixpt_mul(dc_fixpt_pow(in_x, dc_fixpt_half), reference_white_level); +} + +/*re gamma, linear to none linear*/ +static void compute_hlg_eotf(struct fixed31_32 in_x, bool is_light0_12, struct fixed31_32 *out_y) +{ + struct fixed31_32 a; + struct fixed31_32 b; + struct fixed31_32 c; + struct fixed31_32 reference_white_level; + + a = dc_fixpt_from_fraction(17883277, 100000000); + if (is_light0_12) { + /*light 0-12*/ + b = dc_fixpt_from_fraction(28466892, 100000000); + c = dc_fixpt_from_fraction(55991073, 100000000); + reference_white_level = dc_fixpt_from_fraction(4, 1); + } else { + /*light 0-1*/ + b = dc_fixpt_from_fraction(2372241, 100000000); + c = dc_fixpt_add(dc_fixpt_one, dc_fixpt_from_fraction(429347, 100000000)); + reference_white_level = dc_fixpt_from_fraction(1, 3); + } + if (dc_fixpt_lt(dc_fixpt_half, in_x)) + *out_y = dc_fixpt_add(dc_fixpt_exp(dc_fixpt_div(dc_fixpt_sub(in_x, c), a)), b); + else + *out_y = dc_fixpt_mul(dc_fixpt_pow(in_x, dc_fixpt_from_fraction(2, 1)), reference_white_level); +} + + /* one-time pre-compute PQ values - only for sdr_white_level 80 */ void precompute_pq(void) { @@ -691,6 +748,48 @@ static void build_degamma(struct pwl_float_data_ex *curve, } } +static void build_hlg_degamma(struct pwl_float_data_ex *degamma, + uint32_t hw_points_num, + const struct hw_x_point *coordinate_x, bool is_light0_12) +{ + uint32_t i; + + struct pwl_float_data_ex *rgb = degamma; + const struct hw_x_point *coord_x = coordinate_x; + + i = 0; + + while (i != hw_points_num + 1) { + compute_hlg_oetf(coord_x->x, is_light0_12, &rgb->r); + rgb->g = rgb->r; + rgb->b = rgb->r; + ++coord_x; + ++rgb; + ++i; + } +} + +static void build_hlg_regamma(struct pwl_float_data_ex *regamma, + uint32_t hw_points_num, + const struct hw_x_point *coordinate_x, bool is_light0_12) +{ + uint32_t i; + + struct pwl_float_data_ex *rgb = regamma; + const struct hw_x_point *coord_x = coordinate_x; + + i = 0; + + while (i != hw_points_num + 1) { + compute_hlg_eotf(coord_x->x, is_light0_12, &rgb->r); + rgb->g = rgb->r; + rgb->b = rgb->r; + ++coord_x; + ++rgb; + ++i; + } +} + static void scale_gamma(struct pwl_float_data *pwl_rgb, const struct dc_gamma *ramp, struct dividers dividers) @@ -1614,6 +1713,25 @@ bool mod_color_calculate_curve(enum dc_transfer_func_predefined trans, } ret = true; + kvfree(rgb_regamma); + } else if (trans == TRANSFER_FUNCTION_HLG || + trans == TRANSFER_FUNCTION_HLG12) { + rgb_regamma = kvzalloc(sizeof(*rgb_regamma) * + (MAX_HW_POINTS + _EXTRA_POINTS), + GFP_KERNEL); + if (!rgb_regamma) + goto rgb_regamma_alloc_fail; + + build_hlg_regamma(rgb_regamma, + MAX_HW_POINTS, + coordinates_x, + trans == TRANSFER_FUNCTION_HLG12 ? true:false); + for (i = 0; i <= MAX_HW_POINTS ; i++) { + points->red[i] = rgb_regamma[i].r; + points->green[i] = rgb_regamma[i].g; + points->blue[i] = rgb_regamma[i].b; + } + ret = true; kvfree(rgb_regamma); } rgb_regamma_alloc_fail: @@ -1674,6 +1792,25 @@ bool mod_color_calculate_degamma_curve(enum dc_transfer_func_predefined trans, } ret = true; + kvfree(rgb_degamma); + } else if (trans == TRANSFER_FUNCTION_HLG || + trans == TRANSFER_FUNCTION_HLG12) { + rgb_degamma = kvzalloc(sizeof(*rgb_degamma) * + (MAX_HW_POINTS + _EXTRA_POINTS), + GFP_KERNEL); + if (!rgb_degamma) + goto rgb_degamma_alloc_fail; + + build_hlg_degamma(rgb_degamma, + MAX_HW_POINTS, + coordinates_x, + trans == TRANSFER_FUNCTION_HLG12 ? true:false); + for (i = 0; i <= MAX_HW_POINTS ; i++) { + points->red[i] = rgb_degamma[i].r; + points->green[i] = rgb_degamma[i].g; + points->blue[i] = rgb_degamma[i].b; + } + ret = true; kvfree(rgb_degamma); } points->end_exponent = 0; -- GitLab From a27f1996778363adc5ca3a31f6306edd8fa54350 Mon Sep 17 00:00:00 2001 From: Yasir Al Shekerchi <YasirAl.Shekerchi@amd.com> Date: Fri, 4 May 2018 16:53:03 -0400 Subject: [PATCH 0323/1506] drm/amd/display: Added documentation for some DC interface functions Signed-off-by: Yasir Al Shekerchi <YasirAl.Shekerchi@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/core/dc.c | 16 ++++++++++++++++ drivers/gpu/drm/amd/display/dc/core/dc_link.c | 16 ++++++++++++++++ drivers/gpu/drm/amd/display/dc/core/dc_surface.c | 11 +++++++++++ 3 files changed, 43 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 644b2187507b9..2b1a92844c383 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -169,6 +169,22 @@ static bool create_links( return false; } +/** + ***************************************************************************** + * Function: dc_stream_adjust_vmin_vmax + * + * @brief + * Looks up the pipe context of dc_stream_state and updates the + * vertical_total_min and vertical_total_max of the DRR, Dynamic Refresh + * Rate, which is a power-saving feature that targets reducing panel + * refresh rate while the screen is static + * + * @param [in] dc: dc reference + * @param [in] stream: Initial dc stream state + * @param [in] adjust: Updated parameters for vertical_total_min and + * vertical_total_max + ***************************************************************************** + */ bool dc_stream_adjust_vmin_vmax(struct dc *dc, struct dc_stream_state **streams, int num_streams, int vmin, int vmax) 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 a9485c10fd77a..08b7ee526f0fe 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -2433,6 +2433,22 @@ void core_link_set_avmute(struct pipe_ctx *pipe_ctx, bool enable) core_dc->hwss.set_avmute(pipe_ctx, enable); } +/** + ***************************************************************************** + * Function: dc_link_enable_hpd_filter + * + * @brief + * If enable is true, programs HPD filter on associated HPD line using + * delay_on_disconnect/delay_on_connect values dependent on + * link->connector_signal + * + * If enable is false, programs HPD filter on associated HPD line with no + * delays on connect or disconnect + * + * @param [in] link: pointer to the dc link + * @param [in] enable: boolean specifying whether to enable hbd + ***************************************************************************** + */ void dc_link_enable_hpd_filter(struct dc_link *link, bool enable) { struct gpio *hpd; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_surface.c b/drivers/gpu/drm/amd/display/dc/core/dc_surface.c index 68a71adeb12e4..815dfb50089b8 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_surface.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_surface.c @@ -84,6 +84,17 @@ struct dc_plane_state *dc_create_plane_state(struct dc *dc) return plane_state; } +/** + ***************************************************************************** + * Function: dc_plane_get_status + * + * @brief + * Looks up the pipe context of plane_state and updates the pending status + * of the pipe context. Then returns plane_state->status + * + * @param [in] plane_state: pointer to the plane_state to get the status of + ***************************************************************************** + */ const struct dc_plane_status *dc_plane_get_status( const struct dc_plane_state *plane_state) { -- GitLab From e0d4234982b3e9ce7eaa6c1726ceb04efd0b800f Mon Sep 17 00:00:00 2001 From: Tony Cheng <tony.cheng@amd.com> Date: Tue, 8 May 2018 12:24:40 -0400 Subject: [PATCH 0324/1506] drm/amd/display: dal 3.1.46 Signed-off-by: Tony Cheng <tony.cheng@amd.com> Reviewed-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 7a70a24ef736c..74fc4f6d9cdf7 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.1.45" +#define DC_VER "3.1.46" #define MAX_SURFACES 3 #define MAX_STREAMS 6 -- GitLab From 8de94233f4cdcd5b3065fa9b9af3edc10874a120 Mon Sep 17 00:00:00 2001 From: Reza Amini <Reza.Amini@amd.com> Date: Wed, 9 May 2018 15:41:47 -0400 Subject: [PATCH 0325/1506] drm/amd/display: Prefix TIMING_STANDARD entries with DC_ Signed-off-by: Reza Amini <Reza.Amini@amd.com> Reviewed-by: Aric Cyr <Aric.Cyr@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/core/dc.c | 2 +- drivers/gpu/drm/amd/display/dc/dc_ddc_types.h | 2 +- drivers/gpu/drm/amd/display/dc/dc_hw_types.h | 34 +++++++++---------- drivers/gpu/drm/amd/display/dc/dc_types.h | 18 +++++----- .../gpu/drm/amd/display/include/fixed31_32.h | 7 ++++ 5 files changed, 35 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 2b1a92844c383..2c05630e78fb5 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -1564,7 +1564,7 @@ struct dc_sink *dc_link_add_remote_sink( struct dc_sink *dc_sink; enum dc_edid_status edid_status; - if (len > MAX_EDID_BUFFER_SIZE) { + if (len > DC_MAX_EDID_BUFFER_SIZE) { dm_error("Max EDID buffer size breached!\n"); return NULL; } diff --git a/drivers/gpu/drm/amd/display/dc/dc_ddc_types.h b/drivers/gpu/drm/amd/display/dc/dc_ddc_types.h index e1affeb5cc512..ee04812b44926 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_ddc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_ddc_types.h @@ -109,7 +109,7 @@ struct ddc_service { uint32_t address; uint32_t edid_buf_len; - uint8_t edid_buf[MAX_EDID_BUFFER_SIZE]; + uint8_t edid_buf[DC_MAX_EDID_BUFFER_SIZE]; }; #endif /* DC_DDC_TYPES_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h index b1f70579d61b8..d31023d57b58a 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h @@ -567,25 +567,25 @@ struct scaling_taps { }; enum dc_timing_standard { - TIMING_STANDARD_UNDEFINED, - TIMING_STANDARD_DMT, - TIMING_STANDARD_GTF, - TIMING_STANDARD_CVT, - TIMING_STANDARD_CVT_RB, - TIMING_STANDARD_CEA770, - TIMING_STANDARD_CEA861, - TIMING_STANDARD_HDMI, - TIMING_STANDARD_TV_NTSC, - TIMING_STANDARD_TV_NTSC_J, - TIMING_STANDARD_TV_PAL, - TIMING_STANDARD_TV_PAL_M, - TIMING_STANDARD_TV_PAL_CN, - TIMING_STANDARD_TV_SECAM, - TIMING_STANDARD_EXPLICIT, + DC_TIMING_STANDARD_UNDEFINED, + DC_TIMING_STANDARD_DMT, + DC_TIMING_STANDARD_GTF, + DC_TIMING_STANDARD_CVT, + DC_TIMING_STANDARD_CVT_RB, + DC_TIMING_STANDARD_CEA770, + DC_TIMING_STANDARD_CEA861, + DC_TIMING_STANDARD_HDMI, + DC_TIMING_STANDARD_TV_NTSC, + DC_TIMING_STANDARD_TV_NTSC_J, + DC_TIMING_STANDARD_TV_PAL, + DC_TIMING_STANDARD_TV_PAL_M, + DC_TIMING_STANDARD_TV_PAL_CN, + DC_TIMING_STANDARD_TV_SECAM, + DC_TIMING_STANDARD_EXPLICIT, /*!< For explicit timings from EDID, VBIOS, etc.*/ - TIMING_STANDARD_USER_OVERRIDE, + DC_TIMING_STANDARD_USER_OVERRIDE, /*!< For mode timing override by user*/ - TIMING_STANDARD_MAX + DC_TIMING_STANDARD_MAX }; enum dc_color_depth { diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index 76df2534c4a41..7d603c53e45e7 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -98,7 +98,7 @@ struct dc_context { }; -#define MAX_EDID_BUFFER_SIZE 512 +#define DC_MAX_EDID_BUFFER_SIZE 512 #define EDID_BLOCK_SIZE 128 #define MAX_SURFACE_NUM 4 #define NUM_PIXEL_FORMATS 10 @@ -137,13 +137,13 @@ enum plane_stereo_format { */ enum dc_edid_connector_type { - EDID_CONNECTOR_UNKNOWN = 0, - EDID_CONNECTOR_ANALOG = 1, - EDID_CONNECTOR_DIGITAL = 10, - EDID_CONNECTOR_DVI = 11, - EDID_CONNECTOR_HDMIA = 12, - EDID_CONNECTOR_MDDI = 14, - EDID_CONNECTOR_DISPLAYPORT = 15 + DC_EDID_CONNECTOR_UNKNOWN = 0, + DC_EDID_CONNECTOR_ANALOG = 1, + DC_EDID_CONNECTOR_DIGITAL = 10, + DC_EDID_CONNECTOR_DVI = 11, + DC_EDID_CONNECTOR_HDMIA = 12, + DC_EDID_CONNECTOR_MDDI = 14, + DC_EDID_CONNECTOR_DISPLAYPORT = 15 }; enum dc_edid_status { @@ -169,7 +169,7 @@ struct dc_cea_audio_mode { struct dc_edid { uint32_t length; - uint8_t raw_edid[MAX_EDID_BUFFER_SIZE]; + uint8_t raw_edid[DC_MAX_EDID_BUFFER_SIZE]; }; /* When speaker location data block is not available, DEFAULT_SPEAKER_LOCATION diff --git a/drivers/gpu/drm/amd/display/include/fixed31_32.h b/drivers/gpu/drm/amd/display/include/fixed31_32.h index a981b3e99ab39..52a73332befb9 100644 --- a/drivers/gpu/drm/amd/display/include/fixed31_32.h +++ b/drivers/gpu/drm/amd/display/include/fixed31_32.h @@ -26,6 +26,13 @@ #ifndef __DAL_FIXED31_32_H__ #define __DAL_FIXED31_32_H__ +#ifndef LLONG_MAX +#define LLONG_MAX 9223372036854775807ll +#endif +#ifndef LLONG_MIN +#define LLONG_MIN (-LLONG_MAX - 1ll) +#endif + #define FIXED31_32_BITS_PER_FRACTIONAL_PART 32 #ifndef LLONG_MIN #define LLONG_MIN (1LL<<63) -- GitLab From 0b126112e90a96907aa14c39374fc7bfdbba131a Mon Sep 17 00:00:00 2001 From: Eric Bernstein <eric.bernstein@amd.com> Date: Mon, 14 May 2018 17:01:00 -0400 Subject: [PATCH 0326/1506] drm/amd/display: DP YCbCr 4:2:0 support Update MSA MISC1 bit 6 programming to handle YCbCr 4:2:0 and BT2020 cases. Signed-off-by: Eric Bernstein <eric.bernstein@amd.com> Reviewed-by: Hersen Wu <hersenxs.wu@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../amd/display/dc/dcn10/dcn10_stream_encoder.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) 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 c928ee4cd3826..147f61416fa5c 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 @@ -298,9 +298,20 @@ void enc1_stream_encoder_dp_set_stream_attribute( } misc1 = REG_READ(DP_MSA_MISC); + /* For YCbCr420 and BT2020 Colorimetry Formats, VSC SDP shall be used. + * When MISC1, bit 6, is Set to 1, a Source device uses a VSC SDP to indicate the + * Pixel Encoding/Colorimetry Format and that a Sink device shall ignore MISC1, bit 7, + * and MISC0, bits 7:1 (MISC1, bit 7, and MISC0, bits 7:1, become “don’t careâ€). + */ + if ((crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) || + (output_color_space == COLOR_SPACE_2020_YCBCR) || + (output_color_space == COLOR_SPACE_2020_RGB_FULLRANGE) || + (output_color_space == COLOR_SPACE_2020_RGB_LIMITEDRANGE)) + misc1 = misc1 | 0x40; + else + misc1 = misc1 & ~0x40; /* set color depth */ - switch (crtc_timing->display_color_depth) { case COLOR_DEPTH_666: REG_UPDATE(DP_PIXEL_FORMAT, DP_COMPONENT_DEPTH, @@ -354,7 +365,6 @@ void enc1_stream_encoder_dp_set_stream_attribute( switch (output_color_space) { case COLOR_SPACE_SRGB: - misc0 = misc0 | 0x0; misc1 = misc1 & ~0x80; /* bit7 = 0*/ dynamic_range_rgb = 0; /*full range*/ break; -- GitLab From 0dd6cfe15cbd888e7e43ec1bb28f372de7d1b3e1 Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Date: Wed, 16 May 2018 08:51:11 -0400 Subject: [PATCH 0327/1506] drm/amd/display: add dentist frequency to resource pool Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/inc/core_types.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h index a94942d4e66b9..4beddca0180c3 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h @@ -148,6 +148,7 @@ struct resource_pool { unsigned int underlay_pipe_index; unsigned int stream_enc_count; unsigned int ref_clock_inKhz; + unsigned int dentist_vco_freq_khz; unsigned int timing_generator_count; /* -- GitLab From 0ce55b4676f2e237e46d9196eb84fe35499a0d2e Mon Sep 17 00:00:00 2001 From: Tony Cheng <tony.cheng@amd.com> Date: Tue, 8 May 2018 12:25:02 -0400 Subject: [PATCH 0328/1506] drm/amd/display: dal 3.1.47 Signed-off-by: Tony Cheng <tony.cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 74fc4f6d9cdf7..be0dee18e09f6 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.1.46" +#define DC_VER "3.1.47" #define MAX_SURFACES 3 #define MAX_STREAMS 6 -- GitLab From 6f4e8d6e592a5ca998337525b6f5133555228326 Mon Sep 17 00:00:00 2001 From: Samuel Li <Samuel.Li@amd.com> Date: Thu, 17 May 2018 17:58:45 -0400 Subject: [PATCH 0329/1506] drm/amdgpu: add kernel doc for amdgpu_object.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document the amdgpu buffer object API. v2: Add a DOC section and some more clarification. v3: Add some clarification and fix a spelling. Suggested-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Samuel Li <Samuel.Li@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 269 +++++++++++++++++++++ 1 file changed, 269 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 5e4e1bd903837..78d75ae5932f8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -38,6 +38,19 @@ #include "amdgpu_trace.h" #include "amdgpu_amdkfd.h" +/** + * DOC: amdgpu_object + * + * This defines the interfaces to operate on an &amdgpu_bo buffer object which + * represents memory used by driver (VRAM, system memory, etc.). The driver + * provides DRM/GEM APIs to userspace. DRM/GEM APIs then use these interfaces + * to create/destroy/set buffer object which are then managed by the kernel TTM + * memory manager. + * The interfaces are also used internally by kernel clients, including gfx, + * uvd, etc. for kernel managed allocations used by the GPU. + * + */ + static bool amdgpu_need_backup(struct amdgpu_device *adev) { if (adev->flags & AMD_IS_APU) @@ -73,6 +86,15 @@ static void amdgpu_ttm_bo_destroy(struct ttm_buffer_object *tbo) kfree(bo); } +/** + * amdgpu_ttm_bo_is_amdgpu_bo - check if the buffer object is an &amdgpu_bo + * @bo: buffer object to be checked + * + * Uses destroy function associated with the object to determine if this is + * an &amdgpu_bo. + * + * Returns true if the object belongs to &amdgpu_bo, false if not. + */ bool amdgpu_ttm_bo_is_amdgpu_bo(struct ttm_buffer_object *bo) { if (bo->destroy == &amdgpu_ttm_bo_destroy) @@ -80,6 +102,14 @@ bool amdgpu_ttm_bo_is_amdgpu_bo(struct ttm_buffer_object *bo) return false; } +/** + * amdgpu_ttm_placement_from_domain - set buffer's placement + * @abo: &amdgpu_bo buffer object whose placement is to be set + * @domain: requested domain + * + * Sets buffer's placement according to requested domain and the buffer's + * flags. + */ void amdgpu_ttm_placement_from_domain(struct amdgpu_bo *abo, u32 domain) { struct amdgpu_device *adev = amdgpu_ttm_adev(abo->tbo.bdev); @@ -498,6 +528,19 @@ static int amdgpu_bo_create_shadow(struct amdgpu_device *adev, return r; } +/** + * amdgpu_bo_create - create an &amdgpu_bo buffer object + * @adev: amdgpu device object + * @bp: parameters to be used for the buffer object + * @bo_ptr: pointer to the buffer object pointer + * + * Creates an &amdgpu_bo buffer object; and if requested, also creates a + * shadow object. + * Shadow object is used to backup the original buffer object, and is always + * in GTT. + * + * Returns 0 for success or a negative error code on failure. + */ int amdgpu_bo_create(struct amdgpu_device *adev, struct amdgpu_bo_param *bp, struct amdgpu_bo **bo_ptr) @@ -527,6 +570,20 @@ int amdgpu_bo_create(struct amdgpu_device *adev, return r; } +/** + * amdgpu_bo_backup_to_shadow - Backs up an &amdgpu_bo buffer object + * @adev: amdgpu device object + * @ring: amdgpu_ring for the engine handling the buffer operations + * @bo: &amdgpu_bo buffer to be backed up + * @resv: reservation object with embedded fence + * @fence: dma_fence associated with the operation + * @direct: whether to submit the job directly + * + * Copies an &amdgpu_bo buffer object to its shadow object. + * Not used for now. + * + * Returns 0 for success or a negative error code on failure. + */ int amdgpu_bo_backup_to_shadow(struct amdgpu_device *adev, struct amdgpu_ring *ring, struct amdgpu_bo *bo, @@ -559,6 +616,17 @@ int amdgpu_bo_backup_to_shadow(struct amdgpu_device *adev, return r; } +/** + * amdgpu_bo_validate - validate an &amdgpu_bo buffer object + * @bo: pointer to the buffer object + * + * Sets placement according to domain; and changes placement and caching + * policy of the buffer object according to the placement. + * This is used for validating shadow bos. It calls ttm_bo_validate() to + * make sure the buffer is resident where it needs to be. + * + * Returns 0 for success or a negative error code on failure. + */ int amdgpu_bo_validate(struct amdgpu_bo *bo) { struct ttm_operation_ctx ctx = { false, false }; @@ -581,6 +649,21 @@ int amdgpu_bo_validate(struct amdgpu_bo *bo) return r; } +/** + * amdgpu_bo_restore_from_shadow - restore an &amdgpu_bo buffer object + * @adev: amdgpu device object + * @ring: amdgpu_ring for the engine handling the buffer operations + * @bo: &amdgpu_bo buffer to be restored + * @resv: reservation object with embedded fence + * @fence: dma_fence associated with the operation + * @direct: whether to submit the job directly + * + * Copies a buffer object's shadow content back to the object. + * This is used for recovering a buffer from its shadow in case of a gpu + * reset where vram context may be lost. + * + * Returns 0 for success or a negative error code on failure. + */ int amdgpu_bo_restore_from_shadow(struct amdgpu_device *adev, struct amdgpu_ring *ring, struct amdgpu_bo *bo, @@ -613,6 +696,16 @@ int amdgpu_bo_restore_from_shadow(struct amdgpu_device *adev, return r; } +/** + * amdgpu_bo_kmap - map an &amdgpu_bo buffer object + * @bo: &amdgpu_bo buffer object to be mapped + * @ptr: kernel virtual address to be returned + * + * Calls ttm_bo_kmap() to set up the kernel virtual mapping; calls + * amdgpu_bo_kptr() to get the kernel virtual address. + * + * Returns 0 for success or a negative error code on failure. + */ int amdgpu_bo_kmap(struct amdgpu_bo *bo, void **ptr) { void *kptr; @@ -643,6 +736,14 @@ int amdgpu_bo_kmap(struct amdgpu_bo *bo, void **ptr) return 0; } +/** + * amdgpu_bo_kptr - returns a kernel virtual address of the buffer object + * @bo: &amdgpu_bo buffer object + * + * Calls ttm_kmap_obj_virtual() to get the kernel virtual address + * + * Returns the virtual address of a buffer object area. + */ void *amdgpu_bo_kptr(struct amdgpu_bo *bo) { bool is_iomem; @@ -650,12 +751,26 @@ void *amdgpu_bo_kptr(struct amdgpu_bo *bo) return ttm_kmap_obj_virtual(&bo->kmap, &is_iomem); } +/** + * amdgpu_bo_kunmap - unmap an &amdgpu_bo buffer object + * @bo: &amdgpu_bo buffer object to be unmapped + * + * Unmaps a kernel map set up by amdgpu_bo_kmap(). + */ void amdgpu_bo_kunmap(struct amdgpu_bo *bo) { if (bo->kmap.bo) ttm_bo_kunmap(&bo->kmap); } +/** + * amdgpu_bo_ref - reference an &amdgpu_bo buffer object + * @bo: &amdgpu_bo buffer object + * + * References the contained &ttm_buffer_object. + * + * Returns a refcounted pointer to the &amdgpu_bo buffer object. + */ struct amdgpu_bo *amdgpu_bo_ref(struct amdgpu_bo *bo) { if (bo == NULL) @@ -665,6 +780,12 @@ struct amdgpu_bo *amdgpu_bo_ref(struct amdgpu_bo *bo) return bo; } +/** + * amdgpu_bo_unref - unreference an &amdgpu_bo buffer object + * @bo: &amdgpu_bo buffer object + * + * Unreferences the contained &ttm_buffer_object and clear the pointer + */ void amdgpu_bo_unref(struct amdgpu_bo **bo) { struct ttm_buffer_object *tbo; @@ -678,6 +799,28 @@ void amdgpu_bo_unref(struct amdgpu_bo **bo) *bo = NULL; } +/** + * amdgpu_bo_pin_restricted - pin an &amdgpu_bo buffer object + * @bo: &amdgpu_bo buffer object to be pinned + * @domain: domain to be pinned to + * @min_offset: the start of requested address range + * @max_offset: the end of requested address range + * @gpu_addr: GPU offset of the &amdgpu_bo buffer object + * + * Pins the buffer object according to requested domain and address range. If + * the memory is unbound gart memory, binds the pages into gart table. Adjusts + * pin_count and pin_size accordingly. + * + * Pinning means to lock pages in memory along with keeping them at a fixed + * offset. It is required when a buffer can not be moved, for example, when + * a display buffer is being scanned out. + * + * Compared with amdgpu_bo_pin(), this function gives more flexibility on + * where to pin a buffer if there are specific restrictions on where a buffer + * must be located. + * + * Returns 0 for success or a negative error code on failure. + */ int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain, u64 min_offset, u64 max_offset, u64 *gpu_addr) @@ -772,11 +915,32 @@ int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain, return r; } +/** + * amdgpu_bo_pin - pin an &amdgpu_bo buffer object + * @bo: &amdgpu_bo buffer object to be pinned + * @domain: domain to be pinned to + * @gpu_addr: GPU offset of the &amdgpu_bo buffer object + * + * A simple wrapper to amdgpu_bo_pin_restricted(). + * Provides a simpler API for buffers that do not have any strict restrictions + * on where a buffer must be located. + * + * Returns 0 for success or a negative error code on failure. + */ int amdgpu_bo_pin(struct amdgpu_bo *bo, u32 domain, u64 *gpu_addr) { return amdgpu_bo_pin_restricted(bo, domain, 0, 0, gpu_addr); } +/** + * amdgpu_bo_unpin - unpin an &amdgpu_bo buffer object + * @bo: &amdgpu_bo buffer object to be unpinned + * + * Decreases the pin_count, and clears the flags if pin_count reaches 0. + * Changes placement and pin size accordingly. + * + * Returns 0 for success or a negative error code on failure. + */ int amdgpu_bo_unpin(struct amdgpu_bo *bo) { struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); @@ -812,6 +976,15 @@ int amdgpu_bo_unpin(struct amdgpu_bo *bo) return r; } +/** + * amdgpu_bo_evict_vram - evict VRAM buffers + * @adev: amdgpu device object + * + * Evicts all VRAM buffers on the lru list of the memory type. + * Mainly used for evicting vram at suspend time. + * + * Returns 0 for success or a negative error code on failure. + */ int amdgpu_bo_evict_vram(struct amdgpu_device *adev) { /* late 2.6.33 fix IGP hibernate - we need pm ops to do this correct */ @@ -834,6 +1007,14 @@ static const char *amdgpu_vram_names[] = { "DDR4", }; +/** + * amdgpu_bo_init - initialize memory manager + * @adev: amdgpu device object + * + * Calls amdgpu_ttm_init() to initialize amdgpu memory manager. + * + * Returns 0 for success or a negative error code on failure. + */ int amdgpu_bo_init(struct amdgpu_device *adev) { /* reserve PAT memory space to WC for VRAM */ @@ -851,6 +1032,15 @@ int amdgpu_bo_init(struct amdgpu_device *adev) return amdgpu_ttm_init(adev); } +/** + * amdgpu_bo_late_init - late init + * @adev: amdgpu device object + * + * Calls amdgpu_ttm_late_init() to free resources used earlier during + * initialization. + * + * Returns 0 for success or a negative error code on failure. + */ int amdgpu_bo_late_init(struct amdgpu_device *adev) { amdgpu_ttm_late_init(adev); @@ -858,6 +1048,12 @@ int amdgpu_bo_late_init(struct amdgpu_device *adev) return 0; } +/** + * amdgpu_bo_fini - tear down memory manager + * @adev: amdgpu device object + * + * Reverses amdgpu_bo_init() to tear down memory manager. + */ void amdgpu_bo_fini(struct amdgpu_device *adev) { amdgpu_ttm_fini(adev); @@ -865,12 +1061,31 @@ void amdgpu_bo_fini(struct amdgpu_device *adev) arch_io_free_memtype_wc(adev->gmc.aper_base, adev->gmc.aper_size); } +/** + * amdgpu_bo_fbdev_mmap - mmap fbdev memory + * @bo: &amdgpu_bo buffer object + * @vma: vma as input from the fbdev mmap method + * + * Calls ttm_fbdev_mmap() to mmap fbdev memory if it is backed by a bo. + * + * Returns 0 for success or a negative error code on failure. + */ int amdgpu_bo_fbdev_mmap(struct amdgpu_bo *bo, struct vm_area_struct *vma) { return ttm_fbdev_mmap(vma, &bo->tbo); } +/** + * amdgpu_bo_set_tiling_flags - set tiling flags + * @bo: &amdgpu_bo buffer object + * @tiling_flags: new flags + * + * Sets buffer object's tiling flags with the new one. Used by GEM ioctl or + * kernel driver to set the tiling flags on a buffer. + * + * Returns 0 for success or a negative error code on failure. + */ int amdgpu_bo_set_tiling_flags(struct amdgpu_bo *bo, u64 tiling_flags) { struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); @@ -883,6 +1098,14 @@ int amdgpu_bo_set_tiling_flags(struct amdgpu_bo *bo, u64 tiling_flags) return 0; } +/** + * amdgpu_bo_get_tiling_flags - get tiling flags + * @bo: &amdgpu_bo buffer object + * @tiling_flags: returned flags + * + * Gets buffer object's tiling flags. Used by GEM ioctl or kernel driver to + * set the tiling flags on a buffer. + */ void amdgpu_bo_get_tiling_flags(struct amdgpu_bo *bo, u64 *tiling_flags) { lockdep_assert_held(&bo->tbo.resv->lock.base); @@ -891,6 +1114,18 @@ void amdgpu_bo_get_tiling_flags(struct amdgpu_bo *bo, u64 *tiling_flags) *tiling_flags = bo->tiling_flags; } +/** + * amdgpu_bo_set_metadata - set metadata + * @bo: &amdgpu_bo buffer object + * @metadata: new metadata + * @metadata_size: size of the new metadata + * @flags: flags of the new metadata + * + * Sets buffer object's metadata, its size and flags. + * Used via GEM ioctl. + * + * Returns 0 for success or a negative error code on failure. + */ int amdgpu_bo_set_metadata (struct amdgpu_bo *bo, void *metadata, uint32_t metadata_size, uint64_t flags) { @@ -920,6 +1155,20 @@ int amdgpu_bo_set_metadata (struct amdgpu_bo *bo, void *metadata, return 0; } +/** + * amdgpu_bo_get_metadata - get metadata + * @bo: &amdgpu_bo buffer object + * @buffer: returned metadata + * @buffer_size: size of the buffer + * @metadata_size: size of the returned metadata + * @flags: flags of the returned metadata + * + * Gets buffer object's metadata, its size and flags. buffer_size shall not be + * less than metadata_size. + * Used via GEM ioctl. + * + * Returns 0 for success or a negative error code on failure. + */ int amdgpu_bo_get_metadata(struct amdgpu_bo *bo, void *buffer, size_t buffer_size, uint32_t *metadata_size, uint64_t *flags) @@ -943,6 +1192,16 @@ int amdgpu_bo_get_metadata(struct amdgpu_bo *bo, void *buffer, return 0; } +/** + * amdgpu_bo_move_notify - notification about a memory move + * @bo: pointer to a buffer object + * @evict: if this move is evicting the buffer from the graphics address space + * @new_mem: new information of the bufer object + * + * Marks the corresponding &amdgpu_bo buffer object as invalid, also performs + * bookkeeping. + * TTM driver callback which is called when ttm moves a buffer. + */ void amdgpu_bo_move_notify(struct ttm_buffer_object *bo, bool evict, struct ttm_mem_reg *new_mem) @@ -971,6 +1230,16 @@ void amdgpu_bo_move_notify(struct ttm_buffer_object *bo, trace_amdgpu_ttm_bo_move(abo, new_mem->mem_type, old_mem->mem_type); } +/** + * amdgpu_bo_fault_reserve_notify - notification about a memory fault + * @bo: pointer to a buffer object + * + * Notifies the driver we are taking a fault on this BO and have reserved it, + * also performs bookkeeping. + * TTM driver callback for dealing with vm faults. + * + * Returns 0 for success or a negative error code on failure. + */ int amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo) { struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev); -- GitLab From b646c1dc835b6b73884a88643c2534f1a4a1928f Mon Sep 17 00:00:00 2001 From: Samuel Li <Samuel.Li@amd.com> Date: Thu, 24 May 2018 14:32:49 -0400 Subject: [PATCH 0330/1506] drm/amdgpu: add kernel doc for memory domains. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document the GEM domains exposed to userspace. Suggested-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Samuel Li <Samuel.Li@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- include/uapi/drm/amdgpu_drm.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/include/uapi/drm/amdgpu_drm.h b/include/uapi/drm/amdgpu_drm.h index 78b4dd89fcb4d..0dc9e606114ed 100644 --- a/include/uapi/drm/amdgpu_drm.h +++ b/include/uapi/drm/amdgpu_drm.h @@ -72,6 +72,29 @@ extern "C" { #define DRM_IOCTL_AMDGPU_FENCE_TO_HANDLE DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_FENCE_TO_HANDLE, union drm_amdgpu_fence_to_handle) #define DRM_IOCTL_AMDGPU_SCHED DRM_IOW(DRM_COMMAND_BASE + DRM_AMDGPU_SCHED, union drm_amdgpu_sched) +/** + * DOC: memory domains + * + * %AMDGPU_GEM_DOMAIN_CPU System memory that is not GPU accessible. + * Memory in this pool could be swapped out to disk if there is pressure. + * + * %AMDGPU_GEM_DOMAIN_GTT GPU accessible system memory, mapped into the + * GPU's virtual address space via gart. Gart memory linearizes non-contiguous + * pages of system memory, allows GPU access system memory in a linezrized + * fashion. + * + * %AMDGPU_GEM_DOMAIN_VRAM Local video memory. For APUs, it is memory + * carved out by the BIOS. + * + * %AMDGPU_GEM_DOMAIN_GDS Global on-chip data storage used to share data + * across shader threads. + * + * %AMDGPU_GEM_DOMAIN_GWS Global wave sync, used to synchronize the + * execution of all the waves on a device. + * + * %AMDGPU_GEM_DOMAIN_OA Ordered append, used by 3D or Compute engines + * for appending data. + */ #define AMDGPU_GEM_DOMAIN_CPU 0x1 #define AMDGPU_GEM_DOMAIN_GTT 0x2 #define AMDGPU_GEM_DOMAIN_VRAM 0x4 -- GitLab From 5099114ba3b2e5ae9fb487aeb3ae0434fe38a7da Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexander.deucher@amd.com> Date: Thu, 31 May 2018 09:09:59 -0500 Subject: [PATCH 0331/1506] drm/amdgpu/display: drop DRM_AMD_DC_FBC kconfig option Just enable it always. This was leftover from feature bring up. Reviewed-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/Kconfig | 10 --------- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 5 +---- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 5 +---- drivers/gpu/drm/amd/display/dc/dc.h | 2 -- drivers/gpu/drm/amd/display/dc/dc_types.h | 2 -- .../amd/display/dc/dce110/dce110_compressor.c | 2 -- .../display/dc/dce110/dce110_hw_sequencer.c | 22 ++----------------- .../amd/display/dc/dce110/dce110_resource.c | 7 +----- 8 files changed, 5 insertions(+), 50 deletions(-) diff --git a/drivers/gpu/drm/amd/display/Kconfig b/drivers/gpu/drm/amd/display/Kconfig index d5d4586e61765..9d56889279b31 100644 --- a/drivers/gpu/drm/amd/display/Kconfig +++ b/drivers/gpu/drm/amd/display/Kconfig @@ -9,16 +9,6 @@ config DRM_AMD_DC support for AMDGPU. This adds required support for Vega and Raven ASICs. -config DRM_AMD_DC_FBC - bool "AMD FBC - Enable Frame Buffer Compression" - depends on DRM_AMD_DC - help - Choose this option if you want to use frame buffer compression - support. - This is a power optimisation feature, check its availability - on your hardware before enabling this option. - - config DRM_AMD_DC_DCN1_0 bool "DCN 1.0 Raven family" depends on DRM_AMD_DC && X86 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 d7d1245c10506..adeb795d80f65 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -347,7 +347,6 @@ static void hotplug_notify_work_func(struct work_struct *work) drm_kms_helper_hotplug_event(dev); } -#if defined(CONFIG_DRM_AMD_DC_FBC) /* Allocate memory for FBC compressed data */ static void amdgpu_dm_fbc_init(struct drm_connector *connector) { @@ -388,7 +387,6 @@ static void amdgpu_dm_fbc_init(struct drm_connector *connector) } } -#endif /* Init display KMS @@ -3429,9 +3427,8 @@ static int amdgpu_dm_connector_get_modes(struct drm_connector *connector) amdgpu_dm_connector_ddc_get_modes(connector, edid); amdgpu_dm_connector_add_common_modes(encoder, connector); -#if defined(CONFIG_DRM_AMD_DC_FBC) amdgpu_dm_fbc_init(connector); -#endif + return amdgpu_dm_connector->num_modes; } 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 d5aa89ad5571d..a29dc35954c9a 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -72,13 +72,11 @@ struct irq_list_head { struct work_struct work; }; -#if defined(CONFIG_DRM_AMD_DC_FBC) struct dm_comressor_info { void *cpu_addr; struct amdgpu_bo *bo_ptr; uint64_t gpu_addr; }; -#endif struct amdgpu_display_manager { @@ -129,9 +127,8 @@ struct amdgpu_display_manager { * Caches device atomic state for suspend/resume */ struct drm_atomic_state *cached_state; -#if defined(CONFIG_DRM_AMD_DC_FBC) + struct dm_comressor_info compressor; -#endif }; struct amdgpu_dm_connector { diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index be0dee18e09f6..f09fa4722fc98 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -289,9 +289,7 @@ struct dc { bool apply_edp_fast_boot_optimization; /* FBC compressor */ -#if defined(CONFIG_DRM_AMD_DC_FBC) struct compressor *fbc_compressor; -#endif }; enum frame_buffer_mode { diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index 7d603c53e45e7..e026ce5ac78fd 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -92,9 +92,7 @@ struct dc_context { bool created_bios; struct gpio_service *gpio_service; struct i2caux *i2caux; -#if defined(CONFIG_DRM_AMD_DC_FBC) uint64_t fbc_gpu_addr; -#endif }; diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c index 111c4921987fe..df027013e50c4 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c @@ -551,9 +551,7 @@ void dce110_compressor_construct(struct dce110_compressor *compressor, compressor->base.lpt_channels_num = 0; compressor->base.attached_inst = 0; compressor->base.is_enabled = false; -#if defined(CONFIG_DRM_AMD_DC_FBC) compressor->base.funcs = &dce110_compressor_funcs; -#endif } 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 cae0054c102a1..1dd2ae46d505c 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 @@ -34,9 +34,7 @@ #include "dce/dce_hwseq.h" #include "gpio_service_interface.h" -#if defined(CONFIG_DRM_AMD_DC_FBC) #include "dce110_compressor.h" -#endif #include "bios/bios_parser_helper.h" #include "timing_generator.h" @@ -1497,10 +1495,8 @@ static void power_down_all_hw_blocks(struct dc *dc) power_down_clock_sources(dc); -#if defined(CONFIG_DRM_AMD_DC_FBC) if (dc->fbc_compressor) dc->fbc_compressor->funcs->disable_fbc(dc->fbc_compressor); -#endif } static void disable_vga_and_power_gate_all_controllers( @@ -1742,9 +1738,7 @@ static void set_static_screen_control(struct pipe_ctx **pipe_ctx, if (events->force_trigger) value |= 0x1; -#if defined(CONFIG_DRM_AMD_DC_FBC) value |= 0x84; -#endif for (i = 0; i < num_pipes; i++) pipe_ctx[i]->stream_res.tg->funcs-> @@ -1872,8 +1866,6 @@ static void apply_min_clocks( } } -#if defined(CONFIG_DRM_AMD_DC_FBC) - /* * Check if FBC can be enabled */ @@ -1952,7 +1944,6 @@ static void enable_fbc(struct dc *dc, compr->funcs->enable_fbc(compr, ¶ms); } } -#endif static void dce110_reset_hw_ctx_wrap( struct dc *dc, @@ -2129,10 +2120,9 @@ enum dc_status dce110_apply_ctx_to_hw( set_safe_displaymarks(&context->res_ctx, dc->res_pool); -#if defined(CONFIG_DRM_AMD_DC_FBC) if (dc->fbc_compressor) dc->fbc_compressor->funcs->disable_fbc(dc->fbc_compressor); -#endif + /*TODO: when pplib works*/ apply_min_clocks(dc, context, &clocks_state, true); @@ -2210,12 +2200,9 @@ enum dc_status dce110_apply_ctx_to_hw( dcb->funcs->set_scratch_critical_state(dcb, false); -#if defined(CONFIG_DRM_AMD_DC_FBC) if (dc->fbc_compressor) enable_fbc(dc, context); -#endif - return DC_OK; } @@ -2530,10 +2517,9 @@ static void init_hw(struct dc *dc) abm->funcs->init_backlight(abm); abm->funcs->abm_init(abm); } -#if defined(CONFIG_DRM_AMD_DC_FBC) + if (dc->fbc_compressor) dc->fbc_compressor->funcs->power_up_fbc(dc->fbc_compressor); -#endif } @@ -2719,9 +2705,7 @@ static void dce110_program_front_end_for_pipe( struct dc_plane_state *plane_state = pipe_ctx->plane_state; struct xfm_grph_csc_adjustment adjust; struct out_csc_color_matrix tbl_entry; -#if defined(CONFIG_DRM_AMD_DC_FBC) unsigned int underlay_idx = dc->res_pool->underlay_pipe_index; -#endif unsigned int i; DC_LOGGER_INIT(); memset(&tbl_entry, 0, sizeof(tbl_entry)); @@ -2762,7 +2746,6 @@ static void dce110_program_front_end_for_pipe( program_scaler(dc, pipe_ctx); -#if defined(CONFIG_DRM_AMD_DC_FBC) /* fbc not applicable on Underlay pipe */ if (dc->fbc_compressor && old_pipe->stream && pipe_ctx->pipe_idx != underlay_idx) { @@ -2771,7 +2754,6 @@ static void dce110_program_front_end_for_pipe( else enable_fbc(dc, dc->current_state); } -#endif mi->funcs->mem_input_program_surface_config( mi, diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c index ee33786bdef63..20c0290895515 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c @@ -54,9 +54,8 @@ #define DC_LOGGER \ dc->ctx->logger -#if defined(CONFIG_DRM_AMD_DC_FBC) + #include "dce110/dce110_compressor.h" -#endif #include "reg_helper.h" @@ -1267,12 +1266,8 @@ static bool construct( } } -#if defined(CONFIG_DRM_AMD_DC_FBC) dc->fbc_compressor = dce110_compressor_create(ctx); - - -#endif if (!underlay_create(ctx, &pool->base)) goto res_create_fail; -- GitLab From d1a9146b3a98a139c79b79c7e1426f1128e2bbdf Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexander.deucher@amd.com> Date: Thu, 31 May 2018 09:28:47 -0500 Subject: [PATCH 0332/1506] drm/amdgpu/display: enable CONFIG_DRM_AMD_DC_DCN1_0 by default It's required for displays on Raven. The DCN bandwidth calcs use floating point, but DCN is APU only and it already depends on X86. Reviewed-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/display/Kconfig b/drivers/gpu/drm/amd/display/Kconfig index 9d56889279b31..4c35625eb2c77 100644 --- a/drivers/gpu/drm/amd/display/Kconfig +++ b/drivers/gpu/drm/amd/display/Kconfig @@ -12,6 +12,7 @@ config DRM_AMD_DC config DRM_AMD_DC_DCN1_0 bool "DCN 1.0 Raven family" depends on DRM_AMD_DC && X86 + default y help Choose this option if you want to have RV family for display engine -- GitLab From 3120e2a390a9322a8247d7e9b8be52a7efc26dab Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexander.deucher@amd.com> Date: Thu, 31 May 2018 12:46:08 -0500 Subject: [PATCH 0333/1506] drm/amdgpu/pp: switch the default dpm implementation for CI Switch hawaii and bonaire to use powerplay rather than the old dpm implementation. Powerplay supports more features and is better maintained. Ultimately, we can drop the older dpm implementation like we did for other older asics. Reviewed-by: Huang Rui <ray.huang@amd.com> Reviewed-by: Rex Zhu <rezhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/cik.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/cik.c b/drivers/gpu/drm/amd/amdgpu/cik.c index 8ff4c60d1b595..702e257a483ff 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik.c +++ b/drivers/gpu/drm/amd/amdgpu/cik.c @@ -2003,9 +2003,9 @@ int cik_set_ip_blocks(struct amdgpu_device *adev) amdgpu_device_ip_block_add(adev, &gmc_v7_0_ip_block); amdgpu_device_ip_block_add(adev, &cik_ih_ip_block); if (amdgpu_dpm == -1) - amdgpu_device_ip_block_add(adev, &ci_smu_ip_block); - else amdgpu_device_ip_block_add(adev, &pp_smu_ip_block); + else + amdgpu_device_ip_block_add(adev, &ci_smu_ip_block); if (adev->enable_virtual_display) amdgpu_device_ip_block_add(adev, &dce_virtual_ip_block); #if defined(CONFIG_DRM_AMD_DC) @@ -2024,9 +2024,9 @@ int cik_set_ip_blocks(struct amdgpu_device *adev) amdgpu_device_ip_block_add(adev, &gmc_v7_0_ip_block); amdgpu_device_ip_block_add(adev, &cik_ih_ip_block); if (amdgpu_dpm == -1) - amdgpu_device_ip_block_add(adev, &ci_smu_ip_block); - else amdgpu_device_ip_block_add(adev, &pp_smu_ip_block); + else + amdgpu_device_ip_block_add(adev, &ci_smu_ip_block); if (adev->enable_virtual_display) amdgpu_device_ip_block_add(adev, &dce_virtual_ip_block); #if defined(CONFIG_DRM_AMD_DC) -- GitLab From 41f507080e45010f916698165420640422942f7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= <michel.daenzer@amd.com> Date: Wed, 30 May 2018 13:00:46 +0200 Subject: [PATCH 0334/1506] drm/doc: Add a label for the PRIME Buffer Sharing chapter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So that it can be referenced from e.g. DOC comments. Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Michel Dänzer <michel.daenzer@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- Documentation/gpu/drm-mm.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/gpu/drm-mm.rst b/Documentation/gpu/drm-mm.rst index 96ebcc2a7b415..21b6b72a9ba8f 100644 --- a/Documentation/gpu/drm-mm.rst +++ b/Documentation/gpu/drm-mm.rst @@ -395,6 +395,8 @@ VMA Offset Manager .. kernel-doc:: drivers/gpu/drm/drm_vma_manager.c :export: +.. _prime_buffer_sharing: + PRIME Buffer Sharing ==================== -- GitLab From 99fa7ce3a82bf8047b6104682da6ae276beb22d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= <michel.daenzer@amd.com> Date: Tue, 29 May 2018 18:39:04 +0200 Subject: [PATCH 0335/1506] drm/doc: Add initial amdgpu driver documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Michel Dänzer <michel.daenzer@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- Documentation/gpu/amdgpu.rst | 6 ++++++ Documentation/gpu/drivers.rst | 1 + 2 files changed, 7 insertions(+) create mode 100644 Documentation/gpu/amdgpu.rst diff --git a/Documentation/gpu/amdgpu.rst b/Documentation/gpu/amdgpu.rst new file mode 100644 index 0000000000000..41a14e4aa4ac7 --- /dev/null +++ b/Documentation/gpu/amdgpu.rst @@ -0,0 +1,6 @@ +========================= + drm/amdgpu AMDgpu driver +========================= + +The drm/amdgpu driver supports all AMD Radeon GPUs based on the Graphics Core +Next (GCN) architecture. diff --git a/Documentation/gpu/drivers.rst b/Documentation/gpu/drivers.rst index f982558fc25d4..65be325bf282a 100644 --- a/Documentation/gpu/drivers.rst +++ b/Documentation/gpu/drivers.rst @@ -4,6 +4,7 @@ GPU Driver Documentation .. toctree:: + amdgpu i915 meson pl111 -- GitLab From baca30fabdc9ba2712481e1b9e14ded1de6cfa3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= <michel.daenzer@amd.com> Date: Tue, 29 May 2018 18:33:41 +0200 Subject: [PATCH 0336/1506] drm/amdgpu: Add documentation for PRIME related code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Michel Dänzer <michel.daenzer@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- Documentation/gpu/amdgpu.rst | 14 +++ drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c | 119 ++++++++++++++++++++++ 2 files changed, 133 insertions(+) diff --git a/Documentation/gpu/amdgpu.rst b/Documentation/gpu/amdgpu.rst index 41a14e4aa4ac7..f557866f67886 100644 --- a/Documentation/gpu/amdgpu.rst +++ b/Documentation/gpu/amdgpu.rst @@ -4,3 +4,17 @@ The drm/amdgpu driver supports all AMD Radeon GPUs based on the Graphics Core Next (GCN) architecture. + +Core Driver Infrastructure +========================== + +This section covers core driver infrastructure. + +PRIME Buffer Sharing +-------------------- + +.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c + :doc: PRIME Buffer Sharing + +.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c + :internal: diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c index 4683626b065ff..d1f05489595bc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c @@ -23,6 +23,14 @@ * * Authors: Alex Deucher */ + +/** + * DOC: PRIME Buffer Sharing + * + * The following callback implementations are used for :ref:`sharing GEM buffer + * objects between different devices via PRIME <prime_buffer_sharing>`. + */ + #include <drm/drmP.h> #include "amdgpu.h" @@ -32,6 +40,14 @@ static const struct dma_buf_ops amdgpu_dmabuf_ops; +/** + * amdgpu_gem_prime_get_sg_table - &drm_driver.gem_prime_get_sg_table + * implementation + * @obj: GEM buffer object + * + * Returns: + * A scatter/gather table for the pinned pages of the buffer object's memory. + */ struct sg_table *amdgpu_gem_prime_get_sg_table(struct drm_gem_object *obj) { struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj); @@ -40,6 +56,15 @@ struct sg_table *amdgpu_gem_prime_get_sg_table(struct drm_gem_object *obj) return drm_prime_pages_to_sg(bo->tbo.ttm->pages, npages); } +/** + * amdgpu_gem_prime_vmap - &dma_buf_ops.vmap implementation + * @obj: GEM buffer object + * + * Sets up an in-kernel virtual mapping of the buffer object's memory. + * + * Returns: + * The virtual address of the mapping or an error pointer. + */ void *amdgpu_gem_prime_vmap(struct drm_gem_object *obj) { struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj); @@ -53,6 +78,13 @@ void *amdgpu_gem_prime_vmap(struct drm_gem_object *obj) return bo->dma_buf_vmap.virtual; } +/** + * amdgpu_gem_prime_vunmap - &dma_buf_ops.vunmap implementation + * @obj: GEM buffer object + * @vaddr: virtual address (unused) + * + * Tears down the in-kernel virtual mapping of the buffer object's memory. + */ void amdgpu_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr) { struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj); @@ -60,6 +92,17 @@ void amdgpu_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr) ttm_bo_kunmap(&bo->dma_buf_vmap); } +/** + * amdgpu_gem_prime_mmap - &drm_driver.gem_prime_mmap implementation + * @obj: GEM buffer object + * @vma: virtual memory area + * + * Sets up a userspace mapping of the buffer object's memory in the given + * virtual memory area. + * + * Returns: + * 0 on success or negative error code. + */ int amdgpu_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) { struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj); @@ -94,6 +137,19 @@ int amdgpu_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma return ret; } +/** + * amdgpu_gem_prime_import_sg_table - &drm_driver.gem_prime_import_sg_table + * implementation + * @dev: DRM device + * @attach: DMA-buf attachment + * @sg: Scatter/gather table + * + * Import shared DMA buffer memory exported by another device. + * + * Returns: + * A new GEM buffer object of the given DRM device, representing the memory + * described by the given DMA-buf attachment and scatter/gather table. + */ struct drm_gem_object * amdgpu_gem_prime_import_sg_table(struct drm_device *dev, struct dma_buf_attachment *attach, @@ -132,6 +188,19 @@ amdgpu_gem_prime_import_sg_table(struct drm_device *dev, return ERR_PTR(ret); } +/** + * amdgpu_gem_map_attach - &dma_buf_ops.attach implementation + * @dma_buf: shared DMA buffer + * @target_dev: target device + * @attach: DMA-buf attachment + * + * Makes sure that the shared DMA buffer can be accessed by the target device. + * For now, simply pins it to the GTT domain, where it should be accessible by + * all DMA devices. + * + * Returns: + * 0 on success or negative error code. + */ static int amdgpu_gem_map_attach(struct dma_buf *dma_buf, struct device *target_dev, struct dma_buf_attachment *attach) @@ -181,6 +250,14 @@ static int amdgpu_gem_map_attach(struct dma_buf *dma_buf, return r; } +/** + * amdgpu_gem_map_detach - &dma_buf_ops.detach implementation + * @dma_buf: shared DMA buffer + * @attach: DMA-buf attachment + * + * This is called when a shared DMA buffer no longer needs to be accessible by + * the other device. For now, simply unpins the buffer from GTT. + */ static void amdgpu_gem_map_detach(struct dma_buf *dma_buf, struct dma_buf_attachment *attach) { @@ -202,6 +279,13 @@ static void amdgpu_gem_map_detach(struct dma_buf *dma_buf, drm_gem_map_detach(dma_buf, attach); } +/** + * amdgpu_gem_prime_res_obj - &drm_driver.gem_prime_res_obj implementation + * @obj: GEM buffer object + * + * Returns: + * The buffer object's reservation object. + */ struct reservation_object *amdgpu_gem_prime_res_obj(struct drm_gem_object *obj) { struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj); @@ -209,6 +293,18 @@ struct reservation_object *amdgpu_gem_prime_res_obj(struct drm_gem_object *obj) return bo->tbo.resv; } +/** + * amdgpu_gem_begin_cpu_access - &dma_buf_ops.begin_cpu_access implementation + * @dma_buf: shared DMA buffer + * @direction: direction of DMA transfer + * + * This is called before CPU access to the shared DMA buffer's memory. If it's + * a read access, the buffer is moved to the GTT domain if possible, for optimal + * CPU read performance. + * + * Returns: + * 0 on success or negative error code. + */ static int amdgpu_gem_begin_cpu_access(struct dma_buf *dma_buf, enum dma_data_direction direction) { @@ -253,6 +349,18 @@ static const struct dma_buf_ops amdgpu_dmabuf_ops = { .vunmap = drm_gem_dmabuf_vunmap, }; +/** + * amdgpu_gem_prime_export - &drm_driver.gem_prime_export implementation + * @dev: DRM device + * @gobj: GEM buffer object + * @flags: flags like DRM_CLOEXEC and DRM_RDWR + * + * The main work is done by the &drm_gem_prime_export helper, which in turn + * uses &amdgpu_gem_prime_res_obj. + * + * Returns: + * Shared DMA buffer representing the GEM buffer object from the given device. + */ struct dma_buf *amdgpu_gem_prime_export(struct drm_device *dev, struct drm_gem_object *gobj, int flags) @@ -273,6 +381,17 @@ struct dma_buf *amdgpu_gem_prime_export(struct drm_device *dev, return buf; } +/** + * amdgpu_gem_prime_import - &drm_driver.gem_prime_import implementation + * @dev: DRM device + * @dma_buf: Shared DMA buffer + * + * The main work is done by the &drm_gem_prime_import helper, which in turn + * uses &amdgpu_gem_prime_import_sg_table. + * + * Returns: + * GEM buffer object representing the shared DMA buffer for the given device. + */ struct drm_gem_object *amdgpu_gem_prime_import(struct drm_device *dev, struct dma_buf *dma_buf) { -- GitLab From 8f4805a265fd710a2827b2c0e10c08ef2b526870 Mon Sep 17 00:00:00 2001 From: Shirish S <shirish.s@amd.com> Date: Tue, 29 May 2018 09:23:53 +0530 Subject: [PATCH 0337/1506] drm/amdgpu: avoid sleep while executing atombios table (V2) This patch replaces kzalloc's flag from GFP_KERNEL to GFP_ATOMIC to avoid sleeping in atomic context. Below is the stack trace: BUG: sleeping function called from invalid context at mm/slab.h:*** in_atomic(): 1, irqs_disabled(): 0, pid: 1137, name: DrmThread CPU: 1 PID: 1137 Comm: DrmThread Tainted: G W 4.14.43 #10 Call Trace: dump_stack+0x4d/0x63 ___might_sleep+0x11f/0x12e __kmalloc+0x76/0x126 amdgpu_atom_execute_table_locked+0xfc/0x285 amdgpu_atom_execute_table+0x5d/0x72 transmitter_control_v1_5+0xef/0x11a hwss_edp_backlight_control+0x132/0x151 dce110_disable_stream+0x133/0x16e core_link_disable_stream+0x1c5/0x23b dce110_reset_hw_ctx_wrap+0xb4/0x1aa dce110_apply_ctx_to_hw+0x4e/0x6da ? generic_reg_get+0x1f/0x33 dc_commit_state+0x33f/0x3d2 amdgpu_dm_atomic_commit_tail+0x2cf/0x5d2 ? wait_for_common+0x5b/0x69 commit_tail+0x42/0x64 drm_atomic_helper_commit+0xdc/0xf9 drm_atomic_helper_set_config+0x5c/0x76 __drm_mode_set_config_internal+0x64/0x105 drm_mode_setcrtc+0x474/0x56f ? drm_mode_getcrtc+0x155/0x155 drm_ioctl_kernel+0x6c/0xa8 drm_ioctl+0x267/0x353 ? drm_mode_getcrtc+0x155/0x155 amdgpu_drm_ioctl+0x4f/0x7f vfs_ioctl+0x21/0x2f do_vfs_ioctl+0x4c4/0x4e7 ? security_file_ioctl+0x3b/0x4f SyS_ioctl+0x57/0x79 do_syscall_64+0x64/0x72 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 V2: Added stack trace in commit message. Signed-off-by: Shirish S <shirish.s@amd.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/atom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/atom.c b/drivers/gpu/drm/amd/amdgpu/atom.c index 69500a8b4e2df..6cd518f6f7a4a 100644 --- a/drivers/gpu/drm/amd/amdgpu/atom.c +++ b/drivers/gpu/drm/amd/amdgpu/atom.c @@ -1221,7 +1221,7 @@ static int amdgpu_atom_execute_table_locked(struct atom_context *ctx, int index, ectx.abort = false; ectx.last_jump = 0; if (ws) - ectx.ws = kzalloc(4 * ws, GFP_KERNEL); + ectx.ws = kzalloc(4 * ws, GFP_ATOMIC); else ectx.ws = NULL; -- GitLab From 0152ac16522b6c6dd9319e005bf2945f585328d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= <michel.daenzer@amd.com> Date: Fri, 1 Jun 2018 12:10:02 +0200 Subject: [PATCH 0338/1506] drm/amdgpu: Hook up documentation about memory domains MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Michel Dänzer <michel.daenzer@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- Documentation/gpu/amdgpu.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/gpu/amdgpu.rst b/Documentation/gpu/amdgpu.rst index f557866f67886..ad3711fd2a286 100644 --- a/Documentation/gpu/amdgpu.rst +++ b/Documentation/gpu/amdgpu.rst @@ -10,6 +10,14 @@ Core Driver Infrastructure This section covers core driver infrastructure. +.. _amdgpu_memory_domains: + +Memory Domains +-------------- + +.. kernel-doc:: include/uapi/drm/amdgpu_drm.h + :doc: memory domains + PRIME Buffer Sharing -------------------- -- GitLab From 2472e11b85f08e56519b988c4b76c610c818b1b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= <michel.daenzer@amd.com> Date: Fri, 1 Jun 2018 12:29:45 +0200 Subject: [PATCH 0339/1506] drm/amdgpu: Fix-ups for amdgpu_object.c documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix format of return value descriptions * Document all parameters of amdgpu_bo_free_kernel * Document amdgpu_bo_get_preferred_pin_domain Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Michel Dänzer <michel.daenzer@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 78 +++++++++++++++------- 1 file changed, 55 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 78d75ae5932f8..987a9fa33d359 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -93,7 +93,8 @@ static void amdgpu_ttm_bo_destroy(struct ttm_buffer_object *tbo) * Uses destroy function associated with the object to determine if this is * an &amdgpu_bo. * - * Returns true if the object belongs to &amdgpu_bo, false if not. + * Returns: + * true if the object belongs to &amdgpu_bo, false if not. */ bool amdgpu_ttm_bo_is_amdgpu_bo(struct ttm_buffer_object *bo) { @@ -214,7 +215,8 @@ void amdgpu_ttm_placement_from_domain(struct amdgpu_bo *abo, u32 domain) * * Note: For bo_ptr new BO is only created if bo_ptr points to NULL. * - * Returns 0 on success, negative error code otherwise. + * Returns: + * 0 on success, negative error code otherwise. */ int amdgpu_bo_create_reserved(struct amdgpu_device *adev, unsigned long size, int align, @@ -291,7 +293,8 @@ int amdgpu_bo_create_reserved(struct amdgpu_device *adev, * * Note: For bo_ptr new BO is only created if bo_ptr points to NULL. * - * Returns 0 on success, negative error code otherwise. + * Returns: + * 0 on success, negative error code otherwise. */ int amdgpu_bo_create_kernel(struct amdgpu_device *adev, unsigned long size, int align, @@ -315,6 +318,8 @@ int amdgpu_bo_create_kernel(struct amdgpu_device *adev, * amdgpu_bo_free_kernel - free BO for kernel use * * @bo: amdgpu BO to free + * @gpu_addr: pointer to where the BO's GPU memory space address was stored + * @cpu_addr: pointer to where the BO's CPU memory space address was stored * * unmaps and unpin a BO for kernel internal use. */ @@ -539,7 +544,8 @@ static int amdgpu_bo_create_shadow(struct amdgpu_device *adev, * Shadow object is used to backup the original buffer object, and is always * in GTT. * - * Returns 0 for success or a negative error code on failure. + * Returns: + * 0 for success or a negative error code on failure. */ int amdgpu_bo_create(struct amdgpu_device *adev, struct amdgpu_bo_param *bp, @@ -582,7 +588,8 @@ int amdgpu_bo_create(struct amdgpu_device *adev, * Copies an &amdgpu_bo buffer object to its shadow object. * Not used for now. * - * Returns 0 for success or a negative error code on failure. + * Returns: + * 0 for success or a negative error code on failure. */ int amdgpu_bo_backup_to_shadow(struct amdgpu_device *adev, struct amdgpu_ring *ring, @@ -625,7 +632,8 @@ int amdgpu_bo_backup_to_shadow(struct amdgpu_device *adev, * This is used for validating shadow bos. It calls ttm_bo_validate() to * make sure the buffer is resident where it needs to be. * - * Returns 0 for success or a negative error code on failure. + * Returns: + * 0 for success or a negative error code on failure. */ int amdgpu_bo_validate(struct amdgpu_bo *bo) { @@ -662,7 +670,8 @@ int amdgpu_bo_validate(struct amdgpu_bo *bo) * This is used for recovering a buffer from its shadow in case of a gpu * reset where vram context may be lost. * - * Returns 0 for success or a negative error code on failure. + * Returns: + * 0 for success or a negative error code on failure. */ int amdgpu_bo_restore_from_shadow(struct amdgpu_device *adev, struct amdgpu_ring *ring, @@ -704,7 +713,8 @@ int amdgpu_bo_restore_from_shadow(struct amdgpu_device *adev, * Calls ttm_bo_kmap() to set up the kernel virtual mapping; calls * amdgpu_bo_kptr() to get the kernel virtual address. * - * Returns 0 for success or a negative error code on failure. + * Returns: + * 0 for success or a negative error code on failure. */ int amdgpu_bo_kmap(struct amdgpu_bo *bo, void **ptr) { @@ -742,7 +752,8 @@ int amdgpu_bo_kmap(struct amdgpu_bo *bo, void **ptr) * * Calls ttm_kmap_obj_virtual() to get the kernel virtual address * - * Returns the virtual address of a buffer object area. + * Returns: + * the virtual address of a buffer object area. */ void *amdgpu_bo_kptr(struct amdgpu_bo *bo) { @@ -769,7 +780,8 @@ void amdgpu_bo_kunmap(struct amdgpu_bo *bo) * * References the contained &ttm_buffer_object. * - * Returns a refcounted pointer to the &amdgpu_bo buffer object. + * Returns: + * a refcounted pointer to the &amdgpu_bo buffer object. */ struct amdgpu_bo *amdgpu_bo_ref(struct amdgpu_bo *bo) { @@ -819,7 +831,8 @@ void amdgpu_bo_unref(struct amdgpu_bo **bo) * where to pin a buffer if there are specific restrictions on where a buffer * must be located. * - * Returns 0 for success or a negative error code on failure. + * Returns: + * 0 for success or a negative error code on failure. */ int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain, u64 min_offset, u64 max_offset, @@ -925,7 +938,8 @@ int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain, * Provides a simpler API for buffers that do not have any strict restrictions * on where a buffer must be located. * - * Returns 0 for success or a negative error code on failure. + * Returns: + * 0 for success or a negative error code on failure. */ int amdgpu_bo_pin(struct amdgpu_bo *bo, u32 domain, u64 *gpu_addr) { @@ -939,7 +953,8 @@ int amdgpu_bo_pin(struct amdgpu_bo *bo, u32 domain, u64 *gpu_addr) * Decreases the pin_count, and clears the flags if pin_count reaches 0. * Changes placement and pin size accordingly. * - * Returns 0 for success or a negative error code on failure. + * Returns: + * 0 for success or a negative error code on failure. */ int amdgpu_bo_unpin(struct amdgpu_bo *bo) { @@ -983,7 +998,8 @@ int amdgpu_bo_unpin(struct amdgpu_bo *bo) * Evicts all VRAM buffers on the lru list of the memory type. * Mainly used for evicting vram at suspend time. * - * Returns 0 for success or a negative error code on failure. + * Returns: + * 0 for success or a negative error code on failure. */ int amdgpu_bo_evict_vram(struct amdgpu_device *adev) { @@ -1013,7 +1029,8 @@ static const char *amdgpu_vram_names[] = { * * Calls amdgpu_ttm_init() to initialize amdgpu memory manager. * - * Returns 0 for success or a negative error code on failure. + * Returns: + * 0 for success or a negative error code on failure. */ int amdgpu_bo_init(struct amdgpu_device *adev) { @@ -1039,7 +1056,8 @@ int amdgpu_bo_init(struct amdgpu_device *adev) * Calls amdgpu_ttm_late_init() to free resources used earlier during * initialization. * - * Returns 0 for success or a negative error code on failure. + * Returns: + * 0 for success or a negative error code on failure. */ int amdgpu_bo_late_init(struct amdgpu_device *adev) { @@ -1068,7 +1086,8 @@ void amdgpu_bo_fini(struct amdgpu_device *adev) * * Calls ttm_fbdev_mmap() to mmap fbdev memory if it is backed by a bo. * - * Returns 0 for success or a negative error code on failure. + * Returns: + * 0 for success or a negative error code on failure. */ int amdgpu_bo_fbdev_mmap(struct amdgpu_bo *bo, struct vm_area_struct *vma) @@ -1084,7 +1103,8 @@ int amdgpu_bo_fbdev_mmap(struct amdgpu_bo *bo, * Sets buffer object's tiling flags with the new one. Used by GEM ioctl or * kernel driver to set the tiling flags on a buffer. * - * Returns 0 for success or a negative error code on failure. + * Returns: + * 0 for success or a negative error code on failure. */ int amdgpu_bo_set_tiling_flags(struct amdgpu_bo *bo, u64 tiling_flags) { @@ -1124,7 +1144,8 @@ void amdgpu_bo_get_tiling_flags(struct amdgpu_bo *bo, u64 *tiling_flags) * Sets buffer object's metadata, its size and flags. * Used via GEM ioctl. * - * Returns 0 for success or a negative error code on failure. + * Returns: + * 0 for success or a negative error code on failure. */ int amdgpu_bo_set_metadata (struct amdgpu_bo *bo, void *metadata, uint32_t metadata_size, uint64_t flags) @@ -1167,7 +1188,8 @@ int amdgpu_bo_set_metadata (struct amdgpu_bo *bo, void *metadata, * less than metadata_size. * Used via GEM ioctl. * - * Returns 0 for success or a negative error code on failure. + * Returns: + * 0 for success or a negative error code on failure. */ int amdgpu_bo_get_metadata(struct amdgpu_bo *bo, void *buffer, size_t buffer_size, uint32_t *metadata_size, @@ -1238,7 +1260,8 @@ void amdgpu_bo_move_notify(struct ttm_buffer_object *bo, * also performs bookkeeping. * TTM driver callback for dealing with vm faults. * - * Returns 0 for success or a negative error code on failure. + * Returns: + * 0 for success or a negative error code on failure. */ int amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo) { @@ -1313,10 +1336,11 @@ void amdgpu_bo_fence(struct amdgpu_bo *bo, struct dma_fence *fence, * amdgpu_bo_gpu_offset - return GPU offset of bo * @bo: amdgpu object for which we query the offset * - * Returns current GPU offset of the object. - * * Note: object should either be pinned or reserved when calling this * function, it might be useful to add check for this for debugging. + * + * Returns: + * current GPU offset of the object. */ u64 amdgpu_bo_gpu_offset(struct amdgpu_bo *bo) { @@ -1332,6 +1356,14 @@ u64 amdgpu_bo_gpu_offset(struct amdgpu_bo *bo) return bo->tbo.offset; } +/** + * amdgpu_bo_get_preferred_pin_domain - get preferred domain for scanout + * @adev: amdgpu device object + * @domain: allowed :ref:`memory domains <amdgpu_memory_domains>` + * + * Returns: + * Which of the allowed domains is preferred for pinning the BO for scanout. + */ uint32_t amdgpu_bo_get_preferred_pin_domain(struct amdgpu_device *adev, uint32_t domain) { -- GitLab From a2d19d66b1454b88bfcf1929837b329378d3377f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= <michel.daenzer@amd.com> Date: Fri, 1 Jun 2018 12:30:44 +0200 Subject: [PATCH 0340/1506] drm/amdgpu: Hook up amdgpu_object.c documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Michel Dänzer <michel.daenzer@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- Documentation/gpu/amdgpu.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Documentation/gpu/amdgpu.rst b/Documentation/gpu/amdgpu.rst index ad3711fd2a286..1fbf3876a3d88 100644 --- a/Documentation/gpu/amdgpu.rst +++ b/Documentation/gpu/amdgpu.rst @@ -18,6 +18,15 @@ Memory Domains .. kernel-doc:: include/uapi/drm/amdgpu_drm.h :doc: memory domains +Buffer Objects +-------------- + +.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_object.c + :doc: amdgpu_object + +.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_object.c + :internal: + PRIME Buffer Sharing -------------------- -- GitLab From 741f01e636b72ff3f81204fd595ac1078907671b Mon Sep 17 00:00:00 2001 From: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Date: Wed, 30 May 2018 15:11:01 -0400 Subject: [PATCH 0341/1506] drm/scheduler: Avoid using wait_event_killable for dying process (V4) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dying process might be blocked from receiving any more signals so avoid using it. Also retire enity->fini_status and just check the SW queue, if it's not empty do the fallback cleanup. Also handle entity->last_scheduled == NULL use case which happens when HW ring is already hangged whem a new entity tried to enqeue jobs. v2: Return the remaining timeout and use that as parameter for the next call. This way when we need to cleanup multiple queues we don't wait for the entire TO period for each queue but rather in total. Styling comments. Rebase. v3: Update types from unsigned to long. Work with jiffies instead of ms. Return 0 when TO expires. Rebase. v4: Remove unnecessary timeout calculation. Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/scheduler/gpu_scheduler.c | 67 +++++++++++++++++------ include/drm/gpu_scheduler.h | 7 ++- 2 files changed, 53 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/scheduler/gpu_scheduler.c b/drivers/gpu/drm/scheduler/gpu_scheduler.c index 8c1e80c9b6742..6a316701da739 100644 --- a/drivers/gpu/drm/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/scheduler/gpu_scheduler.c @@ -181,7 +181,6 @@ int drm_sched_entity_init(struct drm_gpu_scheduler *sched, entity->rq = rq; entity->sched = sched; entity->guilty = guilty; - entity->fini_status = 0; entity->last_scheduled = NULL; spin_lock_init(&entity->rq_lock); @@ -219,7 +218,8 @@ static bool drm_sched_entity_is_initialized(struct drm_gpu_scheduler *sched, static bool drm_sched_entity_is_idle(struct drm_sched_entity *entity) { rmb(); - if (spsc_queue_peek(&entity->job_queue) == NULL) + + if (!entity->rq || spsc_queue_peek(&entity->job_queue) == NULL) return true; return false; @@ -260,25 +260,39 @@ static void drm_sched_entity_kill_jobs_cb(struct dma_fence *f, * * @sched: scheduler instance * @entity: scheduler entity + * @timeout: time to wait in for Q to become empty in jiffies. * * Splitting drm_sched_entity_fini() into two functions, The first one does the waiting, * removes the entity from the runqueue and returns an error when the process was killed. + * + * Returns the remaining time in jiffies left from the input timeout */ -void drm_sched_entity_do_release(struct drm_gpu_scheduler *sched, - struct drm_sched_entity *entity) +long drm_sched_entity_do_release(struct drm_gpu_scheduler *sched, + struct drm_sched_entity *entity, long timeout) { + long ret = timeout; + if (!drm_sched_entity_is_initialized(sched, entity)) - return; + return ret; /** * The client will not queue more IBs during this fini, consume existing * queued IBs or discard them on SIGKILL */ - if ((current->flags & PF_SIGNALED) && current->exit_code == SIGKILL) - entity->fini_status = -ERESTARTSYS; - else - entity->fini_status = wait_event_killable(sched->job_scheduled, - drm_sched_entity_is_idle(entity)); - drm_sched_entity_set_rq(entity, NULL); + if (current->flags & PF_EXITING) { + if (timeout) + ret = wait_event_timeout( + sched->job_scheduled, + drm_sched_entity_is_idle(entity), + timeout); + } else + wait_event_killable(sched->job_scheduled, drm_sched_entity_is_idle(entity)); + + + /* For killed process disable any more IBs enqueue right now */ + if ((current->flags & PF_EXITING) && (current->exit_code == SIGKILL)) + drm_sched_entity_set_rq(entity, NULL); + + return ret; } EXPORT_SYMBOL(drm_sched_entity_do_release); @@ -290,11 +304,18 @@ EXPORT_SYMBOL(drm_sched_entity_do_release); * * This should be called after @drm_sched_entity_do_release. It goes over the * entity and signals all jobs with an error code if the process was killed. + * */ void drm_sched_entity_cleanup(struct drm_gpu_scheduler *sched, struct drm_sched_entity *entity) { - if (entity->fini_status) { + + drm_sched_entity_set_rq(entity, NULL); + + /* Consumption of existing IBs wasn't completed. Forcefully + * remove them here. + */ + if (spsc_queue_peek(&entity->job_queue)) { struct drm_sched_job *job; int r; @@ -314,12 +335,22 @@ void drm_sched_entity_cleanup(struct drm_gpu_scheduler *sched, struct drm_sched_fence *s_fence = job->s_fence; drm_sched_fence_scheduled(s_fence); dma_fence_set_error(&s_fence->finished, -ESRCH); - r = dma_fence_add_callback(entity->last_scheduled, &job->finish_cb, - drm_sched_entity_kill_jobs_cb); - if (r == -ENOENT) + + /* + * When pipe is hanged by older entity, new entity might + * not even have chance to submit it's first job to HW + * and so entity->last_scheduled will remain NULL + */ + if (!entity->last_scheduled) { drm_sched_entity_kill_jobs_cb(NULL, &job->finish_cb); - else if (r) - DRM_ERROR("fence add callback failed (%d)\n", r); + } else { + r = dma_fence_add_callback(entity->last_scheduled, &job->finish_cb, + drm_sched_entity_kill_jobs_cb); + if (r == -ENOENT) + drm_sched_entity_kill_jobs_cb(NULL, &job->finish_cb); + else if (r) + DRM_ERROR("fence add callback failed (%d)\n", r); + } } } @@ -339,7 +370,7 @@ EXPORT_SYMBOL(drm_sched_entity_cleanup); void drm_sched_entity_fini(struct drm_gpu_scheduler *sched, struct drm_sched_entity *entity) { - drm_sched_entity_do_release(sched, entity); + drm_sched_entity_do_release(sched, entity, MAX_WAIT_SCHED_ENTITY_Q_EMPTY); drm_sched_entity_cleanup(sched, entity); } EXPORT_SYMBOL(drm_sched_entity_fini); diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h index 496442f12bff4..7c2dfd6cc1afb 100644 --- a/include/drm/gpu_scheduler.h +++ b/include/drm/gpu_scheduler.h @@ -27,6 +27,8 @@ #include <drm/spsc_queue.h> #include <linux/dma-fence.h> +#define MAX_WAIT_SCHED_ENTITY_Q_EMPTY msecs_to_jiffies(1000) + struct drm_gpu_scheduler; struct drm_sched_rq; @@ -84,7 +86,6 @@ struct drm_sched_entity { struct dma_fence *dependency; struct dma_fence_cb cb; atomic_t *guilty; - int fini_status; struct dma_fence *last_scheduled; }; @@ -283,8 +284,8 @@ int drm_sched_entity_init(struct drm_gpu_scheduler *sched, struct drm_sched_entity *entity, struct drm_sched_rq *rq, atomic_t *guilty); -void drm_sched_entity_do_release(struct drm_gpu_scheduler *sched, - struct drm_sched_entity *entity); +long drm_sched_entity_do_release(struct drm_gpu_scheduler *sched, + struct drm_sched_entity *entity, long timeout); void drm_sched_entity_cleanup(struct drm_gpu_scheduler *sched, struct drm_sched_entity *entity); void drm_sched_entity_fini(struct drm_gpu_scheduler *sched, -- GitLab From 48ad368a8a3ab2fd3c2bc2ccccc6e29b1acda1bb Mon Sep 17 00:00:00 2001 From: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Date: Wed, 30 May 2018 15:28:52 -0400 Subject: [PATCH 0342/1506] drm/amdgpu: move amdgpu_ctx_mgr_entity_fini to f_ops flush hook (V4) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With this we can now terminate jobs enqueue into SW queue the moment the task is being killed instead of waiting for last user of drm file to release it. Also stop checking for kref_read(&ctx->refcount) == 1 when calling drm_sched_entity_do_release since other task might still hold a reference to this entity but we don't care since KILL means terminate job submission regardless of what other tasks are doing. v2: Use returned remaining timeout as parameter for the next call. Rebase. v3: Switch to working with jiffies. Streamline remainder TO usage. Rebase. v4: Rebase. Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c | 14 ++++++++------ drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 12 ++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 1 - 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c index c5bb36275e937..64b3a1ed04dca 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c @@ -449,26 +449,28 @@ void amdgpu_ctx_mgr_entity_fini(struct amdgpu_ctx_mgr *mgr) struct amdgpu_ctx *ctx; struct idr *idp; uint32_t id, i; + long max_wait = MAX_WAIT_SCHED_ENTITY_Q_EMPTY; idp = &mgr->ctx_handles; + mutex_lock(&mgr->lock); idr_for_each_entry(idp, ctx, id) { - if (!ctx->adev) + if (!ctx->adev) { + mutex_unlock(&mgr->lock); return; + } for (i = 0; i < ctx->adev->num_rings; i++) { if (ctx->adev->rings[i] == &ctx->adev->gfx.kiq.ring) continue; - if (kref_read(&ctx->refcount) == 1) - drm_sched_entity_do_release(&ctx->adev->rings[i]->sched, - &ctx->rings[i].entity); - else - DRM_ERROR("ctx %p is still alive\n", ctx); + max_wait = drm_sched_entity_do_release(&ctx->adev->rings[i]->sched, + &ctx->rings[i].entity, max_wait); } } + mutex_unlock(&mgr->lock); } void amdgpu_ctx_mgr_entity_cleanup(struct amdgpu_ctx_mgr *mgr) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index b0bf2f24da48f..a549483032b05 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -855,9 +855,21 @@ static const struct dev_pm_ops amdgpu_pm_ops = { .runtime_idle = amdgpu_pmops_runtime_idle, }; +static int amdgpu_flush(struct file *f, fl_owner_t id) +{ + struct drm_file *file_priv = f->private_data; + struct amdgpu_fpriv *fpriv = file_priv->driver_priv; + + amdgpu_ctx_mgr_entity_fini(&fpriv->ctx_mgr); + + return 0; +} + + static const struct file_operations amdgpu_driver_kms_fops = { .owner = THIS_MODULE, .open = drm_open, + .flush = amdgpu_flush, .release = drm_release, .unlocked_ioctl = amdgpu_drm_ioctl, .mmap = amdgpu_mmap, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index 91517b166a3b8..c472bb53e41df 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -930,7 +930,6 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev, return; pm_runtime_get_sync(dev->dev); - amdgpu_ctx_mgr_entity_fini(&fpriv->ctx_mgr); if (adev->asic_type != CHIP_RAVEN) { amdgpu_uvd_free_handles(adev, file_priv); -- GitLab From 8e0fce5a96cfcce77cda3f0fccc2799d6be2524d Mon Sep 17 00:00:00 2001 From: Boyuan Zhang <boyuan.zhang@amd.com> Date: Mon, 30 Apr 2018 16:35:34 -0400 Subject: [PATCH 0343/1506] drm/amdgpu: define vcn jpeg ring MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add AMDGPU_RING_TYPE_VCN_JPEG ring define Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h index 1513124c5659d..a3908efabb662 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h @@ -53,7 +53,8 @@ enum amdgpu_ring_type { AMDGPU_RING_TYPE_KIQ, AMDGPU_RING_TYPE_UVD_ENC, AMDGPU_RING_TYPE_VCN_DEC, - AMDGPU_RING_TYPE_VCN_ENC + AMDGPU_RING_TYPE_VCN_ENC, + AMDGPU_RING_TYPE_VCN_JPEG }; struct amdgpu_device; -- GitLab From fa3087f7682e714af30c1dd8a7cdf95da38e43ff Mon Sep 17 00:00:00 2001 From: Boyuan Zhang <boyuan.zhang@amd.com> Date: Wed, 30 May 2018 14:13:33 -0400 Subject: [PATCH 0344/1506] drm/amdgpu: add vcn jpeg ring MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add jpeg to amdgpu_vcn v2: remove unnecessary scheduler entity Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h index 773010b9ff153..6f3bed1cc1b3e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h @@ -66,6 +66,7 @@ struct amdgpu_vcn { const struct firmware *fw; /* VCN firmware */ struct amdgpu_ring ring_dec; struct amdgpu_ring ring_enc[AMDGPU_VCN_MAX_ENC_RINGS]; + struct amdgpu_ring ring_jpeg; struct amdgpu_irq_src irq; unsigned num_enc_rings; }; -- GitLab From d521093a5f84cacf9935e8c9834ad3054b423ee1 Mon Sep 17 00:00:00 2001 From: Boyuan Zhang <boyuan.zhang@amd.com> Date: Mon, 30 Apr 2018 16:51:33 -0400 Subject: [PATCH 0345/1506] drm/amdgpu: add jpeg packet defines to soc15d.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add new packet for vcn jpeg, including condition checks, types and packet Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/soc15d.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/soc15d.h b/drivers/gpu/drm/amd/amdgpu/soc15d.h index 8dc29107228fd..edfe50821cd9b 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc15d.h +++ b/drivers/gpu/drm/amd/amdgpu/soc15d.h @@ -53,6 +53,29 @@ #define PACKET3_COMPUTE(op, n) (PACKET3(op, n) | 1 << 1) +#define PACKETJ_CONDITION_CHECK0 0 +#define PACKETJ_CONDITION_CHECK1 1 +#define PACKETJ_CONDITION_CHECK2 2 +#define PACKETJ_CONDITION_CHECK3 3 +#define PACKETJ_CONDITION_CHECK4 4 +#define PACKETJ_CONDITION_CHECK5 5 +#define PACKETJ_CONDITION_CHECK6 6 +#define PACKETJ_CONDITION_CHECK7 7 + +#define PACKETJ_TYPE0 0 +#define PACKETJ_TYPE1 1 +#define PACKETJ_TYPE2 2 +#define PACKETJ_TYPE3 3 +#define PACKETJ_TYPE4 4 +#define PACKETJ_TYPE5 5 +#define PACKETJ_TYPE6 6 +#define PACKETJ_TYPE7 7 + +#define PACKETJ(reg, r, cond, type) ((reg & 0x3FFFF) | \ + ((r & 0x3F) << 18) | \ + ((cond & 0xF) << 24) | \ + ((type & 0xF) << 28)) + /* Packet 3 types */ #define PACKET3_NOP 0x10 #define PACKET3_SET_BASE 0x11 -- GitLab From 50613395abc00f150f051d6bc440877741b6fae9 Mon Sep 17 00:00:00 2001 From: Boyuan Zhang <boyuan.zhang@amd.com> Date: Mon, 30 Apr 2018 16:55:39 -0400 Subject: [PATCH 0346/1506] drm/amdgpu: add more jpeg register offset headers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add more jpeg registers defines that are needed for jpeg ring functions Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../amd/include/asic_reg/vcn/vcn_1_0_offset.h | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/gpu/drm/amd/include/asic_reg/vcn/vcn_1_0_offset.h b/drivers/gpu/drm/amd/include/asic_reg/vcn/vcn_1_0_offset.h index 18a32477ed1d2..fe0cbaade3c32 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/vcn/vcn_1_0_offset.h +++ b/drivers/gpu/drm/amd/include/asic_reg/vcn/vcn_1_0_offset.h @@ -89,6 +89,8 @@ #define mmUVD_JPEG_RB_SIZE_BASE_IDX 1 #define mmUVD_JPEG_ADDR_CONFIG 0x021f #define mmUVD_JPEG_ADDR_CONFIG_BASE_IDX 1 +#define mmUVD_JPEG_PITCH 0x0222 +#define mmUVD_JPEG_PITCH_BASE_IDX 1 #define mmUVD_JPEG_GPCOM_CMD 0x022c #define mmUVD_JPEG_GPCOM_CMD_BASE_IDX 1 #define mmUVD_JPEG_GPCOM_DATA0 0x022d @@ -203,6 +205,8 @@ #define mmUVD_RB_WPTR4_BASE_IDX 1 #define mmUVD_JRBC_RB_RPTR 0x0457 #define mmUVD_JRBC_RB_RPTR_BASE_IDX 1 +#define mmUVD_LMI_JPEG_VMID 0x045d +#define mmUVD_LMI_JPEG_VMID_BASE_IDX 1 #define mmUVD_LMI_VCPU_CACHE_64BIT_BAR_HIGH 0x045e #define mmUVD_LMI_VCPU_CACHE_64BIT_BAR_HIGH_BASE_IDX 1 #define mmUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW 0x045f @@ -231,6 +235,8 @@ #define mmUVD_LMI_JRBC_IB_64BIT_BAR_HIGH_BASE_IDX 1 #define mmUVD_LMI_JRBC_IB_VMID 0x0507 #define mmUVD_LMI_JRBC_IB_VMID_BASE_IDX 1 +#define mmUVD_LMI_JRBC_RB_VMID 0x0508 +#define mmUVD_LMI_JRBC_RB_VMID_BASE_IDX 1 #define mmUVD_JRBC_RB_WPTR 0x0509 #define mmUVD_JRBC_RB_WPTR_BASE_IDX 1 #define mmUVD_JRBC_RB_CNTL 0x050a @@ -239,6 +245,20 @@ #define mmUVD_JRBC_IB_SIZE_BASE_IDX 1 #define mmUVD_JRBC_LMI_SWAP_CNTL 0x050d #define mmUVD_JRBC_LMI_SWAP_CNTL_BASE_IDX 1 +#define mmUVD_LMI_JRBC_RB_MEM_WR_64BIT_BAR_LOW 0x050e +#define mmUVD_LMI_JRBC_RB_MEM_WR_64BIT_BAR_LOW_BASE_IDX 1 +#define mmUVD_LMI_JRBC_RB_MEM_WR_64BIT_BAR_HIGH 0x050f +#define mmUVD_LMI_JRBC_RB_MEM_WR_64BIT_BAR_HIGH_BASE_IDX 1 +#define mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_LOW 0x0510 +#define mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_LOW_BASE_IDX 1 +#define mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_HIGH 0x0511 +#define mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_HIGH_BASE_IDX 1 +#define mmUVD_JRBC_RB_REF_DATA 0x0512 +#define mmUVD_JRBC_RB_REF_DATA_BASE_IDX 1 +#define mmUVD_JRBC_RB_COND_RD_TIMER 0x0513 +#define mmUVD_JRBC_RB_COND_RD_TIMER_BASE_IDX 1 +#define mmUVD_JRBC_EXTERNAL_REG_BASE 0x0517 +#define mmUVD_JRBC_EXTERNAL_REG_BASE_BASE_IDX 1 #define mmUVD_JRBC_SOFT_RESET 0x0519 #define mmUVD_JRBC_SOFT_RESET_BASE_IDX 1 #define mmUVD_JRBC_STATUS 0x051a -- GitLab From 221f36c460d7d671e9d19d0d8184225aa068d3a8 Mon Sep 17 00:00:00 2001 From: Boyuan Zhang <boyuan.zhang@amd.com> Date: Wed, 30 May 2018 14:39:07 -0400 Subject: [PATCH 0347/1506] drm/amdgpu: implement jpeg ring functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement all ring functions needed for jpeg ring v2: remove unnecessary mem read function. Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c | 286 ++++++++++++++++++++++++++ 1 file changed, 286 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c index 29684c3ea4ef2..4f15833df8aaf 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c @@ -1126,6 +1126,292 @@ static void vcn_v1_0_enc_ring_emit_wreg(struct amdgpu_ring *ring, amdgpu_ring_write(ring, val); } + +/** + * vcn_v1_0_jpeg_ring_get_rptr - get read pointer + * + * @ring: amdgpu_ring pointer + * + * Returns the current hardware read pointer + */ +static uint64_t vcn_v1_0_jpeg_ring_get_rptr(struct amdgpu_ring *ring) +{ + struct amdgpu_device *adev = ring->adev; + + return RREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_RPTR); +} + +/** + * vcn_v1_0_jpeg_ring_get_wptr - get write pointer + * + * @ring: amdgpu_ring pointer + * + * Returns the current hardware write pointer + */ +static uint64_t vcn_v1_0_jpeg_ring_get_wptr(struct amdgpu_ring *ring) +{ + struct amdgpu_device *adev = ring->adev; + + return RREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_WPTR); +} + +/** + * vcn_v1_0_jpeg_ring_set_wptr - set write pointer + * + * @ring: amdgpu_ring pointer + * + * Commits the write pointer to the hardware + */ +static void vcn_v1_0_jpeg_ring_set_wptr(struct amdgpu_ring *ring) +{ + struct amdgpu_device *adev = ring->adev; + + WREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_WPTR, lower_32_bits(ring->wptr)); +} + +/** + * vcn_v1_0_jpeg_ring_insert_start - insert a start command + * + * @ring: amdgpu_ring pointer + * + * Write a start command to the ring. + */ +static void vcn_v1_0_jpeg_ring_insert_start(struct amdgpu_ring *ring) +{ + struct amdgpu_device *adev = ring->adev; + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_EXTERNAL_REG_BASE), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, 0x68e04); + + amdgpu_ring_write(ring, PACKETJ(0, 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, 0x80010000); +} + +/** + * vcn_v1_0_jpeg_ring_insert_end - insert a end command + * + * @ring: amdgpu_ring pointer + * + * Write a end command to the ring. + */ +static void vcn_v1_0_jpeg_ring_insert_end(struct amdgpu_ring *ring) +{ + struct amdgpu_device *adev = ring->adev; + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_EXTERNAL_REG_BASE), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, 0x68e04); + + amdgpu_ring_write(ring, PACKETJ(0, 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, 0x00010000); +} + +/** + * vcn_v1_0_jpeg_ring_emit_fence - emit an fence & trap command + * + * @ring: amdgpu_ring pointer + * @fence: fence to emit + * + * Write a fence and a trap command to the ring. + */ +static void vcn_v1_0_jpeg_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 seq, + unsigned flags) +{ + struct amdgpu_device *adev = ring->adev; + + WARN_ON(flags & AMDGPU_FENCE_FLAG_64BIT); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JPEG_GPCOM_DATA0), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, seq); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JPEG_GPCOM_DATA1), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, seq); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_RB_MEM_WR_64BIT_BAR_LOW), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, lower_32_bits(addr)); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_RB_MEM_WR_64BIT_BAR_HIGH), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, upper_32_bits(addr)); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JPEG_GPCOM_CMD), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, 0x8); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JPEG_GPCOM_CMD), 0, PACKETJ_CONDITION_CHECK0, PACKETJ_TYPE4)); + amdgpu_ring_write(ring, 0); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_COND_RD_TIMER), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, 0x01400200); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_REF_DATA), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, seq); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_LOW), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, lower_32_bits(addr)); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_HIGH), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, upper_32_bits(addr)); + + amdgpu_ring_write(ring, + PACKETJ(0, 0, PACKETJ_CONDITION_CHECK3, PACKETJ_TYPE2)); + amdgpu_ring_write(ring, 0xffffffff); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_EXTERNAL_REG_BASE), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, 0x3fbc); + + amdgpu_ring_write(ring, + PACKETJ(0, 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, 0x1); +} + +/** + * vcn_v1_0_jpeg_ring_emit_ib - execute indirect buffer + * + * @ring: amdgpu_ring pointer + * @ib: indirect buffer to execute + * + * Write ring commands to execute the indirect buffer. + */ +static void vcn_v1_0_jpeg_ring_emit_ib(struct amdgpu_ring *ring, + struct amdgpu_ib *ib, + unsigned vmid, bool ctx_switch) +{ + struct amdgpu_device *adev = ring->adev; + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_IB_VMID), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, (vmid | (vmid << 4))); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JPEG_VMID), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, (vmid | (vmid << 4))); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_IB_64BIT_BAR_LOW), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr)); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_IB_64BIT_BAR_HIGH), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr)); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_IB_SIZE), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, ib->length_dw); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_LOW), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, lower_32_bits(ring->gpu_addr)); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_HIGH), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, upper_32_bits(ring->gpu_addr)); + + amdgpu_ring_write(ring, + PACKETJ(0, 0, PACKETJ_CONDITION_CHECK0, PACKETJ_TYPE2)); + amdgpu_ring_write(ring, 0); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_COND_RD_TIMER), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, 0x01400200); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_REF_DATA), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, 0x2); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_STATUS), 0, PACKETJ_CONDITION_CHECK3, PACKETJ_TYPE3)); + amdgpu_ring_write(ring, 0x2); +} + +static void vcn_v1_0_jpeg_ring_emit_reg_wait(struct amdgpu_ring *ring, + uint32_t reg, uint32_t val, + uint32_t mask) +{ + struct amdgpu_device *adev = ring->adev; + uint32_t reg_offset = (reg << 2); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_COND_RD_TIMER), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, 0x01400200); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_REF_DATA), 0, 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, val); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_EXTERNAL_REG_BASE), 0, 0, PACKETJ_TYPE0)); + if (((reg_offset >= 0x1f800) && (reg_offset <= 0x21fff)) || + ((reg_offset >= 0x1e000) && (reg_offset <= 0x1e1ff))) { + amdgpu_ring_write(ring, 0); + amdgpu_ring_write(ring, + PACKETJ((reg_offset >> 2), 0, 0, PACKETJ_TYPE3)); + } else { + amdgpu_ring_write(ring, reg_offset); + amdgpu_ring_write(ring, + PACKETJ(0, 0, 0, PACKETJ_TYPE3)); + } + amdgpu_ring_write(ring, mask); +} + +static void vcn_v1_0_jpeg_ring_emit_vm_flush(struct amdgpu_ring *ring, + unsigned vmid, uint64_t pd_addr) +{ + struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->funcs->vmhub]; + uint32_t data0, data1, mask; + + pd_addr = amdgpu_gmc_emit_flush_gpu_tlb(ring, vmid, pd_addr); + + /* wait for register write */ + data0 = hub->ctx0_ptb_addr_lo32 + vmid * 2; + data1 = lower_32_bits(pd_addr); + mask = 0xffffffff; + vcn_v1_0_jpeg_ring_emit_reg_wait(ring, data0, data1, mask); +} + +static void vcn_v1_0_jpeg_ring_emit_wreg(struct amdgpu_ring *ring, + uint32_t reg, uint32_t val) +{ + struct amdgpu_device *adev = ring->adev; + uint32_t reg_offset = (reg << 2); + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_EXTERNAL_REG_BASE), 0, 0, PACKETJ_TYPE0)); + if (((reg_offset >= 0x1f800) && (reg_offset <= 0x21fff)) || + ((reg_offset >= 0x1e000) && (reg_offset <= 0x1e1ff))) { + amdgpu_ring_write(ring, 0); + amdgpu_ring_write(ring, + PACKETJ((reg_offset >> 2), 0, 0, PACKETJ_TYPE0)); + } else { + amdgpu_ring_write(ring, reg_offset); + amdgpu_ring_write(ring, + PACKETJ(0, 0, 0, PACKETJ_TYPE0)); + } + amdgpu_ring_write(ring, val); +} + +static void vcn_v1_0_jpeg_ring_nop(struct amdgpu_ring *ring, uint32_t count) +{ + int i; + + WARN_ON(ring->wptr % 2 || count % 2); + + for (i = 0; i < count / 2; i++) { + amdgpu_ring_write(ring, PACKETJ(0, 0, 0, PACKETJ_TYPE6)); + amdgpu_ring_write(ring, 0); + } +} + static int vcn_v1_0_set_interrupt_state(struct amdgpu_device *adev, struct amdgpu_irq_src *source, unsigned type, -- GitLab From e612bcc3abbb10b6a2204e17849f9aed8627a46e Mon Sep 17 00:00:00 2001 From: Boyuan Zhang <boyuan.zhang@amd.com> Date: Wed, 30 May 2018 14:23:33 -0400 Subject: [PATCH 0348/1506] drm/amdgpu: set jpeg ring functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Set all vcn jpeg ring function pointers. Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c | 40 +++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c index 4f15833df8aaf..8b29f471dad1f 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c @@ -38,6 +38,7 @@ static int vcn_v1_0_stop(struct amdgpu_device *adev); static void vcn_v1_0_set_dec_ring_funcs(struct amdgpu_device *adev); static void vcn_v1_0_set_enc_ring_funcs(struct amdgpu_device *adev); +static void vcn_v1_0_set_jpeg_ring_funcs(struct amdgpu_device *adev); static void vcn_v1_0_set_irq_funcs(struct amdgpu_device *adev); /** @@ -55,6 +56,7 @@ static int vcn_v1_0_early_init(void *handle) vcn_v1_0_set_dec_ring_funcs(adev); vcn_v1_0_set_enc_ring_funcs(adev); + vcn_v1_0_set_jpeg_ring_funcs(adev); vcn_v1_0_set_irq_funcs(adev); return 0; @@ -1559,6 +1561,38 @@ static const struct amdgpu_ring_funcs vcn_v1_0_enc_ring_vm_funcs = { .emit_reg_write_reg_wait = amdgpu_ring_emit_reg_write_reg_wait_helper, }; +static const struct amdgpu_ring_funcs vcn_v1_0_jpeg_ring_vm_funcs = { + .type = AMDGPU_RING_TYPE_VCN_JPEG, + .align_mask = 0xf, + .nop = PACKET0(0x81ff, 0), + .support_64bit_ptrs = false, + .vmhub = AMDGPU_MMHUB, + .get_rptr = vcn_v1_0_jpeg_ring_get_rptr, + .get_wptr = vcn_v1_0_jpeg_ring_get_wptr, + .set_wptr = vcn_v1_0_jpeg_ring_set_wptr, + .emit_frame_size = + 6 + 6 + /* hdp invalidate / flush */ + SOC15_FLUSH_GPU_TLB_NUM_WREG * 6 + + SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 8 + + 8 + /* vcn_v1_0_dec_ring_emit_vm_flush */ + 14 + 14 + /* vcn_v1_0_dec_ring_emit_fence x2 vm fence */ + 6, + .emit_ib_size = 22, /* vcn_v1_0_dec_ring_emit_ib */ + .emit_ib = vcn_v1_0_jpeg_ring_emit_ib, + .emit_fence = vcn_v1_0_jpeg_ring_emit_fence, + .emit_vm_flush = vcn_v1_0_jpeg_ring_emit_vm_flush, + //.test_ring + //.test_ib + .insert_nop = vcn_v1_0_jpeg_ring_nop, + .insert_start = vcn_v1_0_jpeg_ring_insert_start, + .insert_end = vcn_v1_0_jpeg_ring_insert_end, + .pad_ib = amdgpu_ring_generic_pad_ib, + .begin_use = amdgpu_vcn_ring_begin_use, + .end_use = amdgpu_vcn_ring_end_use, + .emit_wreg = vcn_v1_0_jpeg_ring_emit_wreg, + .emit_reg_wait = vcn_v1_0_jpeg_ring_emit_reg_wait, +}; + static void vcn_v1_0_set_dec_ring_funcs(struct amdgpu_device *adev) { adev->vcn.ring_dec.funcs = &vcn_v1_0_dec_ring_vm_funcs; @@ -1575,6 +1609,12 @@ static void vcn_v1_0_set_enc_ring_funcs(struct amdgpu_device *adev) DRM_INFO("VCN encode is enabled in VM mode\n"); } +static void vcn_v1_0_set_jpeg_ring_funcs(struct amdgpu_device *adev) +{ + adev->vcn.ring_jpeg.funcs = &vcn_v1_0_jpeg_ring_vm_funcs; + DRM_INFO("VCN jpeg decode is enabled in VM mode\n"); +} + static const struct amdgpu_irq_src_funcs vcn_v1_0_irq_funcs = { .set = vcn_v1_0_set_interrupt_state, .process = vcn_v1_0_process_interrupt, -- GitLab From 59dd2b883fcd50d76b644d2ade084dae0137a8f7 Mon Sep 17 00:00:00 2001 From: Boyuan Zhang <boyuan.zhang@amd.com> Date: Wed, 30 May 2018 14:42:33 -0400 Subject: [PATCH 0349/1506] drm/amdgpu: add vcn jpeg irq support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add vcn jpeg irq support. Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c index 8b29f471dad1f..076c49c91c2a8 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c @@ -88,6 +88,11 @@ static int vcn_v1_0_sw_init(void *handle) return r; } + /* VCN JPEG TRAP */ + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_VCN, 126, &adev->vcn.irq); + if (r) + return r; + r = amdgpu_vcn_sw_init(adev); if (r) return r; @@ -1438,6 +1443,9 @@ static int vcn_v1_0_process_interrupt(struct amdgpu_device *adev, case 120: amdgpu_fence_process(&adev->vcn.ring_enc[1]); break; + case 126: + amdgpu_fence_process(&adev->vcn.ring_jpeg); + break; default: DRM_ERROR("Unhandled interrupt: %d %d\n", entry->src_id, entry->src_data[0]); -- GitLab From d2314b48d62110d5ce9aebcc8900bc44eed72700 Mon Sep 17 00:00:00 2001 From: Boyuan Zhang <boyuan.zhang@amd.com> Date: Wed, 30 May 2018 14:47:39 -0400 Subject: [PATCH 0350/1506] drm/amdgpu: initialize vcn jpeg ring MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add implementations for vcn jpeg ring initialization Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c index 076c49c91c2a8..ea1d677d02c82 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c @@ -115,6 +115,12 @@ static int vcn_v1_0_sw_init(void *handle) return r; } + ring = &adev->vcn.ring_jpeg; + sprintf(ring->name, "vcn_jpeg"); + r = amdgpu_ring_init(adev, ring, 512, &adev->vcn.irq, 0); + if (r) + return r; + return r; } @@ -169,6 +175,14 @@ static int vcn_v1_0_hw_init(void *handle) } } + ring = &adev->vcn.ring_jpeg; + ring->ready = true; + r = amdgpu_ring_test_ring(ring); + if (r) { + ring->ready = false; + goto done; + } + done: if (!r) DRM_INFO("VCN decode and encode initialized successfully.\n"); @@ -736,6 +750,15 @@ static int vcn_v1_0_start(struct amdgpu_device *adev) WREG32_SOC15(UVD, 0, mmUVD_RB_BASE_HI2, upper_32_bits(ring->gpu_addr)); WREG32_SOC15(UVD, 0, mmUVD_RB_SIZE2, ring->ring_size / 4); + ring = &adev->vcn.ring_jpeg; + WREG32_SOC15(UVD, 0, mmUVD_LMI_JRBC_RB_VMID, 0); + WREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_CNTL, (0x00000001L | 0x00000002L)); + WREG32_SOC15(UVD, 0, mmUVD_LMI_JRBC_RB_64BIT_BAR_LOW, lower_32_bits(ring->gpu_addr)); + WREG32_SOC15(UVD, 0, mmUVD_LMI_JRBC_RB_64BIT_BAR_HIGH, upper_32_bits(ring->gpu_addr)); + WREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_RPTR, 0); + WREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_WPTR, 0); + WREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_CNTL, 0x00000002L); + return 0; } -- GitLab From 8a998052f29b811497b004b87dfe1ea1dfef75d1 Mon Sep 17 00:00:00 2001 From: Boyuan Zhang <boyuan.zhang@amd.com> Date: Wed, 30 May 2018 14:57:16 -0400 Subject: [PATCH 0351/1506] drm/amdgpu: implement patch for fixing a known bug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement a patch to maunally reset read pointer v2: using ring assignment instead of amdgpu_ring_write. adding comments for each steps in the patch function. v3: fixing a typo bug. v4: fixing a bug in v3. Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c | 92 +++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c index ea1d677d02c82..92f78c559fc5a 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c @@ -40,6 +40,7 @@ static void vcn_v1_0_set_dec_ring_funcs(struct amdgpu_device *adev); static void vcn_v1_0_set_enc_ring_funcs(struct amdgpu_device *adev); static void vcn_v1_0_set_jpeg_ring_funcs(struct amdgpu_device *adev); static void vcn_v1_0_set_irq_funcs(struct amdgpu_device *adev); +static void vcn_v1_0_jpeg_ring_set_patch_ring(struct amdgpu_ring *ring, uint32_t ptr); /** * vcn_v1_0_early_init - set function pointers @@ -1442,6 +1443,97 @@ static void vcn_v1_0_jpeg_ring_nop(struct amdgpu_ring *ring, uint32_t count) } } +static void vcn_v1_0_jpeg_ring_patch_wreg(struct amdgpu_ring *ring, uint32_t *ptr, uint32_t reg_offset, uint32_t val) +{ + struct amdgpu_device *adev = ring->adev; + ring->ring[(*ptr)++] = PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_EXTERNAL_REG_BASE), 0, 0, PACKETJ_TYPE0); + if (((reg_offset >= 0x1f800) && (reg_offset <= 0x21fff)) || + ((reg_offset >= 0x1e000) && (reg_offset <= 0x1e1ff))) { + ring->ring[(*ptr)++] = 0; + ring->ring[(*ptr)++] = PACKETJ((reg_offset >> 2), 0, 0, PACKETJ_TYPE0); + } else { + ring->ring[(*ptr)++] = reg_offset; + ring->ring[(*ptr)++] = PACKETJ(0, 0, 0, PACKETJ_TYPE0); + } + ring->ring[(*ptr)++] = val; +} + +static void vcn_v1_0_jpeg_ring_set_patch_ring(struct amdgpu_ring *ring, uint32_t ptr) +{ + struct amdgpu_device *adev = ring->adev; + + uint32_t reg, reg_offset, val, mask, i; + + // 1st: program mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_LOW + reg = SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_LOW); + reg_offset = (reg << 2); + val = lower_32_bits(ring->gpu_addr); + vcn_v1_0_jpeg_ring_patch_wreg(ring, &ptr, reg_offset, val); + + // 2nd: program mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_HIGH + reg = SOC15_REG_OFFSET(UVD, 0, mmUVD_LMI_JRBC_RB_MEM_RD_64BIT_BAR_HIGH); + reg_offset = (reg << 2); + val = upper_32_bits(ring->gpu_addr); + vcn_v1_0_jpeg_ring_patch_wreg(ring, &ptr, reg_offset, val); + + // 3rd to 5th: issue MEM_READ commands + for (i = 0; i <= 2; i++) { + ring->ring[ptr++] = PACKETJ(0, 0, 0, PACKETJ_TYPE2); + ring->ring[ptr++] = 0; + } + + // 6th: program mmUVD_JRBC_RB_CNTL register to enable NO_FETCH and RPTR write ability + reg = SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_CNTL); + reg_offset = (reg << 2); + val = 0x13; + vcn_v1_0_jpeg_ring_patch_wreg(ring, &ptr, reg_offset, val); + + // 7th: program mmUVD_JRBC_RB_REF_DATA + reg = SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_REF_DATA); + reg_offset = (reg << 2); + val = 0x1; + vcn_v1_0_jpeg_ring_patch_wreg(ring, &ptr, reg_offset, val); + + // 8th: issue conditional register read mmUVD_JRBC_RB_CNTL + reg = SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_CNTL); + reg_offset = (reg << 2); + val = 0x1; + mask = 0x1; + + ring->ring[ptr++] = PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_COND_RD_TIMER), 0, 0, PACKETJ_TYPE0); + ring->ring[ptr++] = 0x01400200; + ring->ring[ptr++] = PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_REF_DATA), 0, 0, PACKETJ_TYPE0); + ring->ring[ptr++] = val; + ring->ring[ptr++] = PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_EXTERNAL_REG_BASE), 0, 0, PACKETJ_TYPE0); + if (((reg_offset >= 0x1f800) && (reg_offset <= 0x21fff)) || + ((reg_offset >= 0x1e000) && (reg_offset <= 0x1e1ff))) { + ring->ring[ptr++] = 0; + ring->ring[ptr++] = PACKETJ((reg_offset >> 2), 0, 0, PACKETJ_TYPE3); + } else { + ring->ring[ptr++] = reg_offset; + ring->ring[ptr++] = PACKETJ(0, 0, 0, PACKETJ_TYPE3); + } + ring->ring[ptr++] = mask; + + //9th to 21st: insert no-op + for (i = 0; i <= 12; i++) { + ring->ring[ptr++] = PACKETJ(0, 0, 0, PACKETJ_TYPE6); + ring->ring[ptr++] = 0; + } + + //22nd: reset mmUVD_JRBC_RB_RPTR + reg = SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_RPTR); + reg_offset = (reg << 2); + val = 0; + vcn_v1_0_jpeg_ring_patch_wreg(ring, &ptr, reg_offset, val); + + //23rd: program mmUVD_JRBC_RB_CNTL to disable no_fetch + reg = SOC15_REG_OFFSET(UVD, 0, mmUVD_JRBC_RB_CNTL); + reg_offset = (reg << 2); + val = 0x12; + vcn_v1_0_jpeg_ring_patch_wreg(ring, &ptr, reg_offset, val); +} + static int vcn_v1_0_set_interrupt_state(struct amdgpu_device *adev, struct amdgpu_irq_src *source, unsigned type, -- GitLab From c8c1a1d2ef040d2661fc9c7f0b32aec5b1058ae3 Mon Sep 17 00:00:00 2001 From: Boyuan Zhang <boyuan.zhang@amd.com> Date: Fri, 1 Jun 2018 12:30:17 -0400 Subject: [PATCH 0352/1506] drm/amdgpu: define and add extra dword for jpeg ring MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Define extra dword for jpeg ring. Jpeg ring will allocate extra dword to store the patch commands for fixing the known issue. v2: dropping extra_dw for rings other than jpeg. Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h | 1 + drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c index c6850b629d0e6..19e45a3953e07 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c @@ -304,7 +304,7 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring, 0xffffffffffffffff : ring->buf_mask; /* Allocate ring buffer */ if (ring->ring_obj == NULL) { - r = amdgpu_bo_create_kernel(adev, ring->ring_size, PAGE_SIZE, + r = amdgpu_bo_create_kernel(adev, ring->ring_size + ring->funcs->extra_dw, PAGE_SIZE, AMDGPU_GEM_DOMAIN_GTT, &ring->ring_obj, &ring->gpu_addr, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h index a3908efabb662..a293f4e6760db 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h @@ -113,6 +113,7 @@ struct amdgpu_ring_funcs { u32 nop; bool support_64bit_ptrs; unsigned vmhub; + unsigned extra_dw; /* ring read/write ptr handling */ u64 (*get_rptr)(struct amdgpu_ring *ring); diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c index 92f78c559fc5a..8fecdc5cef43e 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c @@ -1690,6 +1690,7 @@ static const struct amdgpu_ring_funcs vcn_v1_0_jpeg_ring_vm_funcs = { .nop = PACKET0(0x81ff, 0), .support_64bit_ptrs = false, .vmhub = AMDGPU_MMHUB, + .extra_dw = 64, .get_rptr = vcn_v1_0_jpeg_ring_get_rptr, .get_wptr = vcn_v1_0_jpeg_ring_get_wptr, .set_wptr = vcn_v1_0_jpeg_ring_set_wptr, -- GitLab From b7fe681e35aaf8c844755297777bdceae030f6c3 Mon Sep 17 00:00:00 2001 From: Boyuan Zhang <boyuan.zhang@amd.com> Date: Wed, 30 May 2018 15:19:52 -0400 Subject: [PATCH 0353/1506] drm/amdgpu: add patch to jpeg ring MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add patch commands to jepg ring by calling set patch ring function. v2: remove modifications on max_dw, buf_mask and ptr_mask, since we are now using extra_dw for jpeg ring. Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c index 8fecdc5cef43e..32b70049fd918 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c @@ -760,6 +760,13 @@ static int vcn_v1_0_start(struct amdgpu_device *adev) WREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_WPTR, 0); WREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_CNTL, 0x00000002L); + /* initialize wptr */ + ring->wptr = RREG32_SOC15(UVD, 0, mmUVD_JRBC_RB_WPTR); + + /* copy patch commands to the jpeg ring */ + vcn_v1_0_jpeg_ring_set_patch_ring(ring, + (ring->wptr + ring->max_dw * amdgpu_sched_hw_submission)); + return 0; } -- GitLab From 0c5e4b3e1e8a13cf918c1d2197e5b91fd865138a Mon Sep 17 00:00:00 2001 From: Boyuan Zhang <boyuan.zhang@amd.com> Date: Wed, 30 May 2018 15:32:16 -0400 Subject: [PATCH 0354/1506] drm/amdgpu: add vcn jpeg sw finish MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add software finish for vcn jpeg ring. v2: remove unnecessary scheduler entity. Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c index 127e87b470ff4..d485a74de44d8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c @@ -119,6 +119,8 @@ int amdgpu_vcn_sw_fini(struct amdgpu_device *adev) for (i = 0; i < adev->vcn.num_enc_rings; ++i) amdgpu_ring_fini(&adev->vcn.ring_enc[i]); + amdgpu_ring_fini(&adev->vcn.ring_jpeg); + release_firmware(adev->vcn.fw); return 0; -- GitLab From b1d3760645acd7f16c377499460305d8f35bad00 Mon Sep 17 00:00:00 2001 From: Boyuan Zhang <boyuan.zhang@amd.com> Date: Wed, 30 May 2018 15:49:51 -0400 Subject: [PATCH 0355/1506] drm/amdgpu: add vcn jpeg ring test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a ring test for vcn jpeg. Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c | 40 +++++++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h | 2 ++ drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c | 2 +- 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c index d485a74de44d8..0b97a72cc2021 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c @@ -578,3 +578,43 @@ int amdgpu_vcn_enc_ring_test_ib(struct amdgpu_ring *ring, long timeout) dma_fence_put(fence); return r; } + +int amdgpu_vcn_jpeg_ring_test_ring(struct amdgpu_ring *ring) +{ + struct amdgpu_device *adev = ring->adev; + uint32_t tmp = 0; + unsigned i; + int r; + + WREG32(SOC15_REG_OFFSET(UVD, 0, mmUVD_CONTEXT_ID), 0xCAFEDEAD); + r = amdgpu_ring_alloc(ring, 3); + + if (r) { + DRM_ERROR("amdgpu: cp failed to lock ring %d (%d).\n", + ring->idx, r); + return r; + } + + amdgpu_ring_write(ring, + PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_CONTEXT_ID), 0, 0, 0)); + amdgpu_ring_write(ring, 0xDEADBEEF); + amdgpu_ring_commit(ring); + + for (i = 0; i < adev->usec_timeout; i++) { + tmp = RREG32(SOC15_REG_OFFSET(UVD, 0, mmUVD_CONTEXT_ID)); + if (tmp == 0xDEADBEEF) + break; + DRM_UDELAY(1); + } + + if (i < adev->usec_timeout) { + DRM_DEBUG("ring test on %d succeeded in %d usecs\n", + ring->idx, i); + } else { + DRM_ERROR("amdgpu: ring %d test failed (0x%08X)\n", + ring->idx, tmp); + r = -EINVAL; + } + + return r; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h index 6f3bed1cc1b3e..0447faefb95ab 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h @@ -84,4 +84,6 @@ int amdgpu_vcn_dec_ring_test_ib(struct amdgpu_ring *ring, long timeout); int amdgpu_vcn_enc_ring_test_ring(struct amdgpu_ring *ring); int amdgpu_vcn_enc_ring_test_ib(struct amdgpu_ring *ring, long timeout); +int amdgpu_vcn_jpeg_ring_test_ring(struct amdgpu_ring *ring); + #endif diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c index 32b70049fd918..5fc58de0c4026 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c @@ -1712,7 +1712,7 @@ static const struct amdgpu_ring_funcs vcn_v1_0_jpeg_ring_vm_funcs = { .emit_ib = vcn_v1_0_jpeg_ring_emit_ib, .emit_fence = vcn_v1_0_jpeg_ring_emit_fence, .emit_vm_flush = vcn_v1_0_jpeg_ring_emit_vm_flush, - //.test_ring + .test_ring = amdgpu_vcn_jpeg_ring_test_ring, //.test_ib .insert_nop = vcn_v1_0_jpeg_ring_nop, .insert_start = vcn_v1_0_jpeg_ring_insert_start, -- GitLab From 6173040f167e2529c514765c6343abb55a4e0b44 Mon Sep 17 00:00:00 2001 From: Boyuan Zhang <boyuan.zhang@amd.com> Date: Wed, 30 May 2018 15:56:43 -0400 Subject: [PATCH 0356/1506] drm/amdgpu: add vcn jpeg ib test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an ib test for vcn jpeg. Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c | 86 +++++++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h | 1 + drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c | 2 +- 3 files changed, 88 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c index 0b97a72cc2021..3f2a5e73e69ff 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c @@ -618,3 +618,89 @@ int amdgpu_vcn_jpeg_ring_test_ring(struct amdgpu_ring *ring) return r; } + +static int amdgpu_vcn_jpeg_set_reg(struct amdgpu_ring *ring, uint32_t handle, + struct dma_fence **fence) +{ + struct amdgpu_device *adev = ring->adev; + struct amdgpu_job *job; + struct amdgpu_ib *ib; + struct dma_fence *f = NULL; + const unsigned ib_size_dw = 16; + int i, r; + + r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4, &job); + if (r) + return r; + + ib = &job->ibs[0]; + + ib->ptr[0] = PACKETJ(SOC15_REG_OFFSET(UVD, 0, mmUVD_JPEG_PITCH), 0, 0, PACKETJ_TYPE0); + ib->ptr[1] = 0xDEADBEEF; + for (i = 2; i < 16; i += 2) { + ib->ptr[i] = PACKETJ(0, 0, 0, PACKETJ_TYPE6); + ib->ptr[i+1] = 0; + } + ib->length_dw = 16; + + r = amdgpu_ib_schedule(ring, 1, ib, NULL, &f); + job->fence = dma_fence_get(f); + if (r) + goto err; + + amdgpu_job_free(job); + if (fence) + *fence = dma_fence_get(f); + dma_fence_put(f); + + return 0; + +err: + amdgpu_job_free(job); + return r; +} + +int amdgpu_vcn_jpeg_ring_test_ib(struct amdgpu_ring *ring, long timeout) +{ + struct amdgpu_device *adev = ring->adev; + uint32_t tmp = 0; + unsigned i; + struct dma_fence *fence = NULL; + long r = 0; + + r = amdgpu_vcn_jpeg_set_reg(ring, 1, &fence); + if (r) { + DRM_ERROR("amdgpu: failed to set jpeg register (%ld).\n", r); + goto error; + } + + r = dma_fence_wait_timeout(fence, false, timeout); + if (r == 0) { + DRM_ERROR("amdgpu: IB test timed out.\n"); + r = -ETIMEDOUT; + goto error; + } else if (r < 0) { + DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r); + goto error; + } else + r = 0; + + for (i = 0; i < adev->usec_timeout; i++) { + tmp = RREG32(SOC15_REG_OFFSET(UVD, 0, mmUVD_JPEG_PITCH)); + if (tmp == 0xDEADBEEF) + break; + DRM_UDELAY(1); + } + + if (i < adev->usec_timeout) + DRM_DEBUG("ib test on ring %d succeeded\n", ring->idx); + else { + DRM_ERROR("ib test failed (0x%08X)\n", tmp); + r = -EINVAL; + } + + dma_fence_put(fence); + +error: + return r; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h index 0447faefb95ab..0b0b8638d73fb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h @@ -85,5 +85,6 @@ int amdgpu_vcn_enc_ring_test_ring(struct amdgpu_ring *ring); int amdgpu_vcn_enc_ring_test_ib(struct amdgpu_ring *ring, long timeout); int amdgpu_vcn_jpeg_ring_test_ring(struct amdgpu_ring *ring); +int amdgpu_vcn_jpeg_ring_test_ib(struct amdgpu_ring *ring, long timeout); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c index 5fc58de0c4026..b82c92084b6f4 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c @@ -1713,7 +1713,7 @@ static const struct amdgpu_ring_funcs vcn_v1_0_jpeg_ring_vm_funcs = { .emit_fence = vcn_v1_0_jpeg_ring_emit_fence, .emit_vm_flush = vcn_v1_0_jpeg_ring_emit_vm_flush, .test_ring = amdgpu_vcn_jpeg_ring_test_ring, - //.test_ib + .test_ib = amdgpu_vcn_jpeg_ring_test_ib, .insert_nop = vcn_v1_0_jpeg_ring_nop, .insert_start = vcn_v1_0_jpeg_ring_insert_start, .insert_end = vcn_v1_0_jpeg_ring_insert_end, -- GitLab From 5b2329b61875e7118a599f2f1cf6d23c8ac75a69 Mon Sep 17 00:00:00 2001 From: Boyuan Zhang <boyuan.zhang@amd.com> Date: Tue, 1 May 2018 14:40:24 -0400 Subject: [PATCH 0357/1506] drm/amdgpu: enable vcn jpeg ib test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable vcn jpeg ib ring test in amdgpu_ib.c Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c index f70eeed9ed76f..31f8170313b44 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c @@ -353,7 +353,8 @@ int amdgpu_ib_ring_tests(struct amdgpu_device *adev) ring->funcs->type == AMDGPU_RING_TYPE_VCE || ring->funcs->type == AMDGPU_RING_TYPE_UVD_ENC || ring->funcs->type == AMDGPU_RING_TYPE_VCN_DEC || - ring->funcs->type == AMDGPU_RING_TYPE_VCN_ENC) + ring->funcs->type == AMDGPU_RING_TYPE_VCN_ENC || + ring->funcs->type == AMDGPU_RING_TYPE_VCN_JPEG) tmo = tmo_mm; else tmo = tmo_gfx; -- GitLab From 81d350144bd4590ae546d83344421106e8faf69a Mon Sep 17 00:00:00 2001 From: Boyuan Zhang <boyuan.zhang@amd.com> Date: Tue, 1 May 2018 14:47:31 -0400 Subject: [PATCH 0358/1506] uapi/drm: add AMDGPU_HW_IP_VCN_JPEG for jpeg CS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add AMDGPU_HW_IP_VCN_JPEG define for jpeg CS Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- include/uapi/drm/amdgpu_drm.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/uapi/drm/amdgpu_drm.h b/include/uapi/drm/amdgpu_drm.h index 0dc9e606114ed..784b0fe470eea 100644 --- a/include/uapi/drm/amdgpu_drm.h +++ b/include/uapi/drm/amdgpu_drm.h @@ -506,7 +506,8 @@ struct drm_amdgpu_gem_va { #define AMDGPU_HW_IP_UVD_ENC 5 #define AMDGPU_HW_IP_VCN_DEC 6 #define AMDGPU_HW_IP_VCN_ENC 7 -#define AMDGPU_HW_IP_NUM 8 +#define AMDGPU_HW_IP_VCN_JPEG 8 +#define AMDGPU_HW_IP_NUM 9 #define AMDGPU_HW_IP_INSTANCE_MAX_COUNT 1 -- GitLab From 4bafe44024295f087fd633a16e100a34ca363e7c Mon Sep 17 00:00:00 2001 From: Boyuan Zhang <boyuan.zhang@amd.com> Date: Tue, 1 May 2018 14:58:25 -0400 Subject: [PATCH 0359/1506] drm/amdgpu: add AMDGPU_HW_IP_VCN_JPEG to info query MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add AMDGPU_HW_IP_VCN_JPEG to info query Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index c472bb53e41df..ec1060a5eab3a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -383,6 +383,12 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file ib_start_alignment = AMDGPU_GPU_PAGE_SIZE; ib_size_alignment = 1; break; + case AMDGPU_HW_IP_VCN_JPEG: + type = AMD_IP_BLOCK_TYPE_VCN; + ring_mask = adev->vcn.ring_jpeg.ready ? 1 : 0; + ib_start_alignment = AMDGPU_GPU_PAGE_SIZE; + ib_size_alignment = 16; + break; default: return -EINVAL; } @@ -427,6 +433,7 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file break; case AMDGPU_HW_IP_VCN_DEC: case AMDGPU_HW_IP_VCN_ENC: + case AMDGPU_HW_IP_VCN_JPEG: type = AMD_IP_BLOCK_TYPE_VCN; break; default: -- GitLab From b7e6cd57027f5151d4f330dfabb0182f78d26e83 Mon Sep 17 00:00:00 2001 From: Boyuan Zhang <boyuan.zhang@amd.com> Date: Tue, 1 May 2018 14:59:12 -0400 Subject: [PATCH 0360/1506] drm/amdgpu: add AMDGPU_HW_IP_VCN_JPEG to queue mgr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add AMDGPU_HW_IP_VCN_JPEG to queue mgr Signed-off-by: Boyuan Zhang <boyuan.zhang@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_queue_mgr.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_queue_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_queue_mgr.c index 8af16e81c7d44..ea9850c9224d6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_queue_mgr.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_queue_mgr.c @@ -96,6 +96,9 @@ static int amdgpu_identity_map(struct amdgpu_device *adev, case AMDGPU_HW_IP_VCN_ENC: *out_ring = &adev->vcn.ring_enc[ring]; break; + case AMDGPU_HW_IP_VCN_JPEG: + *out_ring = &adev->vcn.ring_jpeg; + break; default: *out_ring = NULL; DRM_ERROR("unknown HW IP type: %d\n", mapper->hw_ip); @@ -260,6 +263,9 @@ int amdgpu_queue_mgr_map(struct amdgpu_device *adev, case AMDGPU_HW_IP_VCN_ENC: ip_num_rings = adev->vcn.num_enc_rings; break; + case AMDGPU_HW_IP_VCN_JPEG: + ip_num_rings = 1; + break; default: DRM_DEBUG("unknown ip type: %d\n", hw_ip); return -EINVAL; @@ -287,6 +293,7 @@ int amdgpu_queue_mgr_map(struct amdgpu_device *adev, case AMDGPU_HW_IP_UVD_ENC: case AMDGPU_HW_IP_VCN_DEC: case AMDGPU_HW_IP_VCN_ENC: + case AMDGPU_HW_IP_VCN_JPEG: r = amdgpu_identity_map(adev, mapper, ring, out_ring); break; case AMDGPU_HW_IP_DMA: -- GitLab From 11528640c77891363bc7dea749ced64607aa1b22 Mon Sep 17 00:00:00 2001 From: Emily Deng <Emily.Deng@amd.com> Date: Fri, 8 Jun 2018 16:36:22 +0800 Subject: [PATCH 0361/1506] drm/amdgpu: Correct the ndw of bo update mapping. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For buffer object that has shadow buffer, need twice commands. Signed-off-by: Emily Deng <Emily.Deng@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index b0eb2f537392d..d88687b617e2f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -1324,7 +1324,10 @@ static int amdgpu_vm_bo_update_mapping(struct amdgpu_device *adev, ndw += ncmds * 10; /* extra commands for begin/end fragments */ - ndw += 2 * 10 * adev->vm_manager.fragment_size; + if (vm->root.base.bo->shadow) + ndw += 2 * 10 * adev->vm_manager.fragment_size * 2; + else + ndw += 2 * 10 * adev->vm_manager.fragment_size; params.func = amdgpu_vm_do_set_ptes; } -- GitLab From 8f4039fefd94a0ca2c61507975f6d47f9fc9943a Mon Sep 17 00:00:00 2001 From: Shirish S <shirish.s@amd.com> Date: Fri, 8 Jun 2018 10:15:42 +0530 Subject: [PATCH 0362/1506] drm/amdgpu: change gfx8 ib test to use WB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch is extends the usage of WB in gfx8's ib test which was originally implemented in the below upstream patch "ed9324a drm/amdgpu: change gfx9 ib test to use WB" For reference below are the reasons for switching to WB: 1)Because when doing IB test we don't want to involve KIQ health status affect, and since SCRATCH register access is go through KIQ that way GFX IB test would failed due to KIQ fail. 2)acccessing SCRATCH register cost much more time than WB method because SCRATCH register access runs through KIQ which at least could begin after GPU world switch back to current Guest VF Signed-off-by: Shirish S <shirish.s@amd.com> Reviewed-by: Chunming Zhou <david1.zhou@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 35 ++++++++++++++++----------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index 818874b13c99d..61452c7c4024d 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -866,26 +866,32 @@ static int gfx_v8_0_ring_test_ib(struct amdgpu_ring *ring, long timeout) struct amdgpu_device *adev = ring->adev; struct amdgpu_ib ib; struct dma_fence *f = NULL; - uint32_t scratch; - uint32_t tmp = 0; + + unsigned int index; + uint64_t gpu_addr; + uint32_t tmp; long r; - r = amdgpu_gfx_scratch_get(adev, &scratch); + r = amdgpu_device_wb_get(adev, &index); if (r) { - DRM_ERROR("amdgpu: failed to get scratch reg (%ld).\n", r); + dev_err(adev->dev, "(%ld) failed to allocate wb slot\n", r); return r; } - WREG32(scratch, 0xCAFEDEAD); + + gpu_addr = adev->wb.gpu_addr + (index * 4); + adev->wb.wb[index] = cpu_to_le32(0xCAFEDEAD); memset(&ib, 0, sizeof(ib)); - r = amdgpu_ib_get(adev, NULL, 256, &ib); + r = amdgpu_ib_get(adev, NULL, 16, &ib); if (r) { DRM_ERROR("amdgpu: failed to get ib (%ld).\n", r); goto err1; } - ib.ptr[0] = PACKET3(PACKET3_SET_UCONFIG_REG, 1); - ib.ptr[1] = ((scratch - PACKET3_SET_UCONFIG_REG_START)); - ib.ptr[2] = 0xDEADBEEF; - ib.length_dw = 3; + ib.ptr[0] = PACKET3(PACKET3_WRITE_DATA, 3); + ib.ptr[1] = WRITE_DATA_DST_SEL(5) | WR_CONFIRM; + ib.ptr[2] = lower_32_bits(gpu_addr); + ib.ptr[3] = upper_32_bits(gpu_addr); + ib.ptr[4] = 0xDEADBEEF; + ib.length_dw = 5; r = amdgpu_ib_schedule(ring, 1, &ib, NULL, &f); if (r) @@ -900,20 +906,21 @@ static int gfx_v8_0_ring_test_ib(struct amdgpu_ring *ring, long timeout) DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r); goto err2; } - tmp = RREG32(scratch); + + tmp = adev->wb.wb[index]; if (tmp == 0xDEADBEEF) { DRM_DEBUG("ib test on ring %d succeeded\n", ring->idx); r = 0; } else { - DRM_ERROR("amdgpu: ib test failed (scratch(0x%04X)=0x%08X)\n", - scratch, tmp); + DRM_ERROR("ib test on ring %d failed\n", ring->idx); r = -EINVAL; } + err2: amdgpu_ib_free(adev, &ib, NULL); dma_fence_put(f); err1: - amdgpu_gfx_scratch_free(adev, scratch); + amdgpu_device_wb_free(adev, index); return r; } -- GitLab From 5a2f291343bc349aef45b9fdbe73332b933fa92b Mon Sep 17 00:00:00 2001 From: David Panariti <David.Panariti@amd.com> Date: Tue, 15 May 2018 11:45:11 -0400 Subject: [PATCH 0363/1506] drm/amdgpu: Added ISR for CP ECC/EDC interrupt v2. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ISR will DRM_ERROR ECC error message. v2: Remove CZ only limitation. Rebase. Signed-off-by: David Panariti <David.Panariti@amd.com> Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Reviewed-by: Nicolai Hähnle <nicolai.haehnle@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 1 + drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 75 +++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index a59c07590ceec..54be18b1ac94c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -968,6 +968,7 @@ struct amdgpu_gfx { struct amdgpu_irq_src eop_irq; struct amdgpu_irq_src priv_reg_irq; struct amdgpu_irq_src priv_inst_irq; + struct amdgpu_irq_src cp_ecc_error_irq; /* gfx status */ uint32_t gfx_current_status; /* ce ram size*/ diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index 61452c7c4024d..dbc47a727fe72 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -2055,6 +2055,12 @@ static int gfx_v8_0_sw_init(void *handle) if (r) return r; + /* Add CP EDC/ECC irq */ + r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 197, + &adev->gfx.cp_ecc_error_irq); + if (r) + return r; + adev->gfx.gfx_current_status = AMDGPU_GFX_NORMAL_MODE; gfx_v8_0_scratch_init(adev); @@ -5118,6 +5124,8 @@ static int gfx_v8_0_hw_fini(void *handle) amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0); amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0); + amdgpu_irq_put(adev, &adev->gfx.cp_ecc_error_irq, 0); + /* disable KCQ to avoid CPC touch memory not valid anymore */ for (i = 0; i < adev->gfx.num_compute_rings; i++) gfx_v8_0_kcq_disable(&adev->gfx.kiq.ring, &adev->gfx.compute_ring[i]); @@ -5549,6 +5557,12 @@ static int gfx_v8_0_late_init(void *handle) if (r) return r; + r = amdgpu_irq_get(adev, &adev->gfx.cp_ecc_error_irq, 0); + if (r) { + DRM_ERROR("amdgpu_irq_get() failed to get IRQ for EDC, r: %d.\n", r); + return r; + } + amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_GFX, AMD_PG_STATE_GATE); @@ -6794,6 +6808,51 @@ static int gfx_v8_0_set_eop_interrupt_state(struct amdgpu_device *adev, return 0; } +static int gfx_v8_0_set_cp_ecc_int_state(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + unsigned int type, + enum amdgpu_interrupt_state state) +{ + int enable_flag; + + switch (state) { + case AMDGPU_IRQ_STATE_DISABLE: + enable_flag = 0; + break; + + case AMDGPU_IRQ_STATE_ENABLE: + enable_flag = 1; + break; + + default: + return -EINVAL; + } + + WREG32_FIELD(CP_INT_CNTL, CP_ECC_ERROR_INT_ENABLE, enable_flag); + WREG32_FIELD(CP_INT_CNTL_RING0, CP_ECC_ERROR_INT_ENABLE, enable_flag); + WREG32_FIELD(CP_INT_CNTL_RING1, CP_ECC_ERROR_INT_ENABLE, enable_flag); + WREG32_FIELD(CP_INT_CNTL_RING2, CP_ECC_ERROR_INT_ENABLE, enable_flag); + WREG32_FIELD(CPC_INT_CNTL, CP_ECC_ERROR_INT_ENABLE, enable_flag); + WREG32_FIELD(CP_ME1_PIPE0_INT_CNTL, CP_ECC_ERROR_INT_ENABLE, + enable_flag); + WREG32_FIELD(CP_ME1_PIPE1_INT_CNTL, CP_ECC_ERROR_INT_ENABLE, + enable_flag); + WREG32_FIELD(CP_ME1_PIPE2_INT_CNTL, CP_ECC_ERROR_INT_ENABLE, + enable_flag); + WREG32_FIELD(CP_ME1_PIPE3_INT_CNTL, CP_ECC_ERROR_INT_ENABLE, + enable_flag); + WREG32_FIELD(CP_ME2_PIPE0_INT_CNTL, CP_ECC_ERROR_INT_ENABLE, + enable_flag); + WREG32_FIELD(CP_ME2_PIPE1_INT_CNTL, CP_ECC_ERROR_INT_ENABLE, + enable_flag); + WREG32_FIELD(CP_ME2_PIPE2_INT_CNTL, CP_ECC_ERROR_INT_ENABLE, + enable_flag); + WREG32_FIELD(CP_ME2_PIPE3_INT_CNTL, CP_ECC_ERROR_INT_ENABLE, + enable_flag); + + return 0; +} + static int gfx_v8_0_eop_irq(struct amdgpu_device *adev, struct amdgpu_irq_src *source, struct amdgpu_iv_entry *entry) @@ -6844,6 +6903,14 @@ static int gfx_v8_0_priv_inst_irq(struct amdgpu_device *adev, return 0; } +static int gfx_v8_0_cp_ecc_error_irq(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + struct amdgpu_iv_entry *entry) +{ + DRM_ERROR("ECC error detected."); + return 0; +} + static int gfx_v8_0_kiq_set_interrupt_state(struct amdgpu_device *adev, struct amdgpu_irq_src *src, unsigned int type, @@ -7044,6 +7111,11 @@ static const struct amdgpu_irq_src_funcs gfx_v8_0_kiq_irq_funcs = { .process = gfx_v8_0_kiq_irq, }; +static const struct amdgpu_irq_src_funcs gfx_v8_0_cp_ecc_error_irq_funcs = { + .set = gfx_v8_0_set_cp_ecc_int_state, + .process = gfx_v8_0_cp_ecc_error_irq, +}; + static void gfx_v8_0_set_irq_funcs(struct amdgpu_device *adev) { adev->gfx.eop_irq.num_types = AMDGPU_CP_IRQ_LAST; @@ -7057,6 +7129,9 @@ static void gfx_v8_0_set_irq_funcs(struct amdgpu_device *adev) adev->gfx.kiq.irq.num_types = AMDGPU_CP_KIQ_IRQ_LAST; adev->gfx.kiq.irq.funcs = &gfx_v8_0_kiq_irq_funcs; + + adev->gfx.cp_ecc_error_irq.num_types = 1; + adev->gfx.cp_ecc_error_irq.funcs = &gfx_v8_0_cp_ecc_error_irq_funcs; } static void gfx_v8_0_set_rlc_funcs(struct amdgpu_device *adev) -- GitLab From 981658c67a97591ce03b5b94f7be9f5f92720e8d Mon Sep 17 00:00:00 2001 From: David Panariti <David.Panariti@amd.com> Date: Tue, 22 May 2018 14:09:06 -0400 Subject: [PATCH 0364/1506] drm/amdgpu: Add interrupt SQ source struct to amdgpu_gfx struct v2. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SQ can generate interrupts on EDC/ECC errors and this struct controls how the interrupt is handled. The guts are filled in in the gf_v<major>_<minor>.c files. v2: Rebase. Signed-off-by: David Panariti <David.Panariti@amd.com> Reviewed-by: Nicolai Hähnle <nicolai.haehnle@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 54be18b1ac94c..71b9b861f60e5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -969,6 +969,7 @@ struct amdgpu_gfx { struct amdgpu_irq_src priv_reg_irq; struct amdgpu_irq_src priv_inst_irq; struct amdgpu_irq_src cp_ecc_error_irq; + struct amdgpu_irq_src sq_irq; /* gfx status */ uint32_t gfx_current_status; /* ce ram size*/ -- GitLab From 04ad26bbc41edea0529aed9a92e146e46b6efe5e Mon Sep 17 00:00:00 2001 From: David Panariti <David.Panariti@amd.com> Date: Tue, 22 May 2018 14:25:49 -0400 Subject: [PATCH 0365/1506] drm/amdgpu: Add plumbing for handling SQ EDC/ECC interrupts v2. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SQ can generate interrupts and installs the ISR to handle the SQ interrupts. Add parsing SQ data in interrupt handler. v2: Remove CZ only limitation. Rebase. Signed-off-by: David Panariti <David.Panariti@amd.com> Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Reviewed-by: Nicolai Hähnle <nicolai.haehnle@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 109 +++++++++++++++++++++++++- 1 file changed, 108 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index dbc47a727fe72..807ee0dd623ce 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -2061,6 +2061,14 @@ static int gfx_v8_0_sw_init(void *handle) if (r) return r; + /* SQ interrupts. */ + r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 239, + &adev->gfx.sq_irq); + if (r) { + DRM_ERROR("amdgpu_irq_add() for SQ failed: %d\n", r); + return r; + } + adev->gfx.gfx_current_status = AMDGPU_GFX_NORMAL_MODE; gfx_v8_0_scratch_init(adev); @@ -5126,6 +5134,8 @@ static int gfx_v8_0_hw_fini(void *handle) amdgpu_irq_put(adev, &adev->gfx.cp_ecc_error_irq, 0); + amdgpu_irq_put(adev, &adev->gfx.sq_irq, 0); + /* disable KCQ to avoid CPC touch memory not valid anymore */ for (i = 0; i < adev->gfx.num_compute_rings; i++) gfx_v8_0_kcq_disable(&adev->gfx.kiq.ring, &adev->gfx.compute_ring[i]); @@ -5563,6 +5573,14 @@ static int gfx_v8_0_late_init(void *handle) return r; } + r = amdgpu_irq_get(adev, &adev->gfx.sq_irq, 0); + if (r) { + DRM_ERROR( + "amdgpu_irq_get() failed to get IRQ for SQ, r: %d.\n", + r); + return r; + } + amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_GFX, AMD_PG_STATE_GATE); @@ -6853,6 +6871,32 @@ static int gfx_v8_0_set_cp_ecc_int_state(struct amdgpu_device *adev, return 0; } +static int gfx_v8_0_set_sq_int_state(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + unsigned int type, + enum amdgpu_interrupt_state state) +{ + int enable_flag; + + switch (state) { + case AMDGPU_IRQ_STATE_DISABLE: + enable_flag = 1; + break; + + case AMDGPU_IRQ_STATE_ENABLE: + enable_flag = 0; + break; + + default: + return -EINVAL; + } + + WREG32_FIELD(SQ_INTERRUPT_MSG_CTRL, STALL, + enable_flag); + + return 0; +} + static int gfx_v8_0_eop_irq(struct amdgpu_device *adev, struct amdgpu_irq_src *source, struct amdgpu_iv_entry *entry) @@ -6907,7 +6951,62 @@ static int gfx_v8_0_cp_ecc_error_irq(struct amdgpu_device *adev, struct amdgpu_irq_src *source, struct amdgpu_iv_entry *entry) { - DRM_ERROR("ECC error detected."); + DRM_ERROR("CP EDC/ECC error detected."); + return 0; +} + +static int gfx_v8_0_sq_irq(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + struct amdgpu_iv_entry *entry) +{ + u8 enc, se_id; + char type[20]; + + /* Parse all fields according to SQ_INTERRUPT* registers */ + enc = (entry->src_data[0] >> 26) & 0x3; + se_id = (entry->src_data[0] >> 24) & 0x3; + + switch (enc) { + case 0: + DRM_INFO("SQ general purpose intr detected:" + "se_id %d, immed_overflow %d, host_reg_overflow %d," + "host_cmd_overflow %d, cmd_timestamp %d," + "reg_timestamp %d, thread_trace_buff_full %d," + "wlt %d, thread_trace %d.\n", + se_id, + (entry->src_data[0] >> 7) & 0x1, + (entry->src_data[0] >> 6) & 0x1, + (entry->src_data[0] >> 5) & 0x1, + (entry->src_data[0] >> 4) & 0x1, + (entry->src_data[0] >> 3) & 0x1, + (entry->src_data[0] >> 2) & 0x1, + (entry->src_data[0] >> 1) & 0x1, + entry->src_data[0] & 0x1 + ); + break; + case 1: + case 2: + + if (enc == 1) + sprintf(type, "instruction intr"); + else + sprintf(type, "EDC/ECC error"); + + DRM_INFO( + "SQ %s detected: " + "se_id %d, cu_id %d, simd_id %d, wave_id %d, vm_id %d\n", + type, se_id, + (entry->src_data[0] >> 20) & 0xf, + (entry->src_data[0] >> 18) & 0x3, + (entry->src_data[0] >> 14) & 0xf, + (entry->src_data[0] >> 10) & 0xf + ); + break; + default: + DRM_ERROR("SQ invalid encoding type\n."); + return -EINVAL; + } + return 0; } @@ -7116,6 +7215,11 @@ static const struct amdgpu_irq_src_funcs gfx_v8_0_cp_ecc_error_irq_funcs = { .process = gfx_v8_0_cp_ecc_error_irq, }; +static const struct amdgpu_irq_src_funcs gfx_v8_0_sq_irq_funcs = { + .set = gfx_v8_0_set_sq_int_state, + .process = gfx_v8_0_sq_irq, +}; + static void gfx_v8_0_set_irq_funcs(struct amdgpu_device *adev) { adev->gfx.eop_irq.num_types = AMDGPU_CP_IRQ_LAST; @@ -7132,6 +7236,9 @@ static void gfx_v8_0_set_irq_funcs(struct amdgpu_device *adev) adev->gfx.cp_ecc_error_irq.num_types = 1; adev->gfx.cp_ecc_error_irq.funcs = &gfx_v8_0_cp_ecc_error_irq_funcs; + + adev->gfx.sq_irq.num_types = 1; + adev->gfx.sq_irq.funcs = &gfx_v8_0_sq_irq_funcs; } static void gfx_v8_0_set_rlc_funcs(struct amdgpu_device *adev) -- GitLab From 59d61be2229fcb8d52db6ba3f82658f501c06333 Mon Sep 17 00:00:00 2001 From: Junwei Zhang <Jerry.Zhang@amd.com> Date: Tue, 12 Jun 2018 13:57:45 +0800 Subject: [PATCH 0366/1506] drm/amdgpu: remove unused parameter for va update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't need validation list any more Signed-off-by: Junwei Zhang <Jerry.Zhang@amd.com> Reviewed-by: David Zhou <david1.zhou@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index 7f27cdb7afe2e..89743cdc1c2c1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -510,7 +510,6 @@ int amdgpu_gem_metadata_ioctl(struct drm_device *dev, void *data, * @adev: amdgpu_device pointer * @vm: vm to update * @bo_va: bo_va to update - * @list: validation list * @operation: map, unmap or clear * * Update the bo_va directly after setting its address. Errors are not @@ -519,7 +518,6 @@ int amdgpu_gem_metadata_ioctl(struct drm_device *dev, void *data, static void amdgpu_gem_va_update_vm(struct amdgpu_device *adev, struct amdgpu_vm *vm, struct amdgpu_bo_va *bo_va, - struct list_head *list, uint32_t operation) { int r; @@ -673,7 +671,7 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, break; } if (!r && !(args->flags & AMDGPU_VM_DELAY_UPDATE) && !amdgpu_vm_debug) - amdgpu_gem_va_update_vm(adev, &fpriv->vm, bo_va, &list, + amdgpu_gem_va_update_vm(adev, &fpriv->vm, bo_va, args->operation); error_backoff: -- GitLab From abea57d70e90b0c41b9a3b9d7b7d39ab81146e19 Mon Sep 17 00:00:00 2001 From: Harry Wentland <harry.wentland@amd.com> Date: Thu, 7 Jun 2018 15:45:08 -0400 Subject: [PATCH 0367/1506] drm/amdgpu: Add BRACKET_LAYOUT_ENUMs to ObjectID.h DC has an upcoming change that requires these to read the board layout. Signed-off-by: Harry Wentland <harry.wentland@amd.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/ObjectID.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/ObjectID.h b/drivers/gpu/drm/amd/amdgpu/ObjectID.h index 06192698bd96e..5b393622f5920 100644 --- a/drivers/gpu/drm/amd/amdgpu/ObjectID.h +++ b/drivers/gpu/drm/amd/amdgpu/ObjectID.h @@ -136,6 +136,7 @@ #define GENERIC_OBJECT_ID_PX2_NON_DRIVABLE 0x02 #define GENERIC_OBJECT_ID_MXM_OPM 0x03 #define GENERIC_OBJECT_ID_STEREO_PIN 0x04 //This object could show up from Misc Object table, it follows ATOM_OBJECT format, and contains one ATOM_OBJECT_GPIO_CNTL_RECORD for the stereo pin +#define GENERIC_OBJECT_ID_BRACKET_LAYOUT 0x05 /****************************************************/ /* Graphics Object ENUM ID Definition */ @@ -714,6 +715,13 @@ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ GENERIC_OBJECT_ID_STEREO_PIN << OBJECT_ID_SHIFT) +#define GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID1 (GRAPH_OBJECT_TYPE_GENERIC << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + GENERIC_OBJECT_ID_BRACKET_LAYOUT << OBJECT_ID_SHIFT) + +#define GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID2 (GRAPH_OBJECT_TYPE_GENERIC << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + GENERIC_OBJECT_ID_BRACKET_LAYOUT << OBJECT_ID_SHIFT) /****************************************************/ /* Object Cap definition - Shared with BIOS */ /****************************************************/ -- GitLab From 528e083d85bd0306e056fe1bdfd05493ebbff9cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Wed, 13 Jun 2018 14:55:20 -0500 Subject: [PATCH 0368/1506] drm/amdgpu: rename rmn to amn in the MMU notifier code (v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just a copy&paste leftover from radeon. v2: rebase (Alex) Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Michel Dänzer <michel.daenzer@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c | 140 ++++++++++++------------- 1 file changed, 70 insertions(+), 70 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c index 83e344fbb50a2..37570a1c6db88 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c @@ -64,7 +64,7 @@ struct amdgpu_mn_node { }; /** - * amdgpu_mn_destroy - destroy the rmn + * amdgpu_mn_destroy - destroy the amn * * @work: previously sheduled work item * @@ -72,26 +72,26 @@ struct amdgpu_mn_node { */ static void amdgpu_mn_destroy(struct work_struct *work) { - struct amdgpu_mn *rmn = container_of(work, struct amdgpu_mn, work); - struct amdgpu_device *adev = rmn->adev; + struct amdgpu_mn *amn = container_of(work, struct amdgpu_mn, work); + struct amdgpu_device *adev = amn->adev; struct amdgpu_mn_node *node, *next_node; struct amdgpu_bo *bo, *next_bo; mutex_lock(&adev->mn_lock); - down_write(&rmn->lock); - hash_del(&rmn->node); + down_write(&amn->lock); + hash_del(&amn->node); rbtree_postorder_for_each_entry_safe(node, next_node, - &rmn->objects.rb_root, it.rb) { + &amn->objects.rb_root, it.rb) { list_for_each_entry_safe(bo, next_bo, &node->bos, mn_list) { bo->mn = NULL; list_del_init(&bo->mn_list); } kfree(node); } - up_write(&rmn->lock); + up_write(&amn->lock); mutex_unlock(&adev->mn_lock); - mmu_notifier_unregister_no_release(&rmn->mn, rmn->mm); - kfree(rmn); + mmu_notifier_unregister_no_release(&amn->mn, amn->mm); + kfree(amn); } /** @@ -105,9 +105,9 @@ static void amdgpu_mn_destroy(struct work_struct *work) static void amdgpu_mn_release(struct mmu_notifier *mn, struct mm_struct *mm) { - struct amdgpu_mn *rmn = container_of(mn, struct amdgpu_mn, mn); - INIT_WORK(&rmn->work, amdgpu_mn_destroy); - schedule_work(&rmn->work); + struct amdgpu_mn *amn = container_of(mn, struct amdgpu_mn, mn); + INIT_WORK(&amn->work, amdgpu_mn_destroy); + schedule_work(&amn->work); } @@ -130,31 +130,31 @@ void amdgpu_mn_unlock(struct amdgpu_mn *mn) } /** - * amdgpu_mn_read_lock - take the rmn read lock + * amdgpu_mn_read_lock - take the amn read lock * - * @rmn: our notifier + * @amn: our notifier * - * Take the rmn read side lock. + * Take the amn read side lock. */ -static void amdgpu_mn_read_lock(struct amdgpu_mn *rmn) +static void amdgpu_mn_read_lock(struct amdgpu_mn *amn) { - mutex_lock(&rmn->read_lock); - if (atomic_inc_return(&rmn->recursion) == 1) - down_read_non_owner(&rmn->lock); - mutex_unlock(&rmn->read_lock); + mutex_lock(&amn->read_lock); + if (atomic_inc_return(&amn->recursion) == 1) + down_read_non_owner(&amn->lock); + mutex_unlock(&amn->read_lock); } /** - * amdgpu_mn_read_unlock - drop the rmn read lock + * amdgpu_mn_read_unlock - drop the amn read lock * - * @rmn: our notifier + * @amn: our notifier * - * Drop the rmn read side lock. + * Drop the amn read side lock. */ -static void amdgpu_mn_read_unlock(struct amdgpu_mn *rmn) +static void amdgpu_mn_read_unlock(struct amdgpu_mn *amn) { - if (atomic_dec_return(&rmn->recursion) == 0) - up_read_non_owner(&rmn->lock); + if (atomic_dec_return(&amn->recursion) == 0) + up_read_non_owner(&amn->lock); } /** @@ -202,15 +202,15 @@ static void amdgpu_mn_invalidate_range_start_gfx(struct mmu_notifier *mn, unsigned long start, unsigned long end) { - struct amdgpu_mn *rmn = container_of(mn, struct amdgpu_mn, mn); + struct amdgpu_mn *amn = container_of(mn, struct amdgpu_mn, mn); struct interval_tree_node *it; /* notification is exclusive, but interval is inclusive */ end -= 1; - amdgpu_mn_read_lock(rmn); + amdgpu_mn_read_lock(amn); - it = interval_tree_iter_first(&rmn->objects, start, end); + it = interval_tree_iter_first(&amn->objects, start, end); while (it) { struct amdgpu_mn_node *node; @@ -238,15 +238,15 @@ static void amdgpu_mn_invalidate_range_start_hsa(struct mmu_notifier *mn, unsigned long start, unsigned long end) { - struct amdgpu_mn *rmn = container_of(mn, struct amdgpu_mn, mn); + struct amdgpu_mn *amn = container_of(mn, struct amdgpu_mn, mn); struct interval_tree_node *it; /* notification is exclusive, but interval is inclusive */ end -= 1; - amdgpu_mn_read_lock(rmn); + amdgpu_mn_read_lock(amn); - it = interval_tree_iter_first(&rmn->objects, start, end); + it = interval_tree_iter_first(&amn->objects, start, end); while (it) { struct amdgpu_mn_node *node; struct amdgpu_bo *bo; @@ -279,9 +279,9 @@ static void amdgpu_mn_invalidate_range_end(struct mmu_notifier *mn, unsigned long start, unsigned long end) { - struct amdgpu_mn *rmn = container_of(mn, struct amdgpu_mn, mn); + struct amdgpu_mn *amn = container_of(mn, struct amdgpu_mn, mn); - amdgpu_mn_read_unlock(rmn); + amdgpu_mn_read_unlock(amn); } static const struct mmu_notifier_ops amdgpu_mn_ops[] = { @@ -315,7 +315,7 @@ struct amdgpu_mn *amdgpu_mn_get(struct amdgpu_device *adev, enum amdgpu_mn_type type) { struct mm_struct *mm = current->mm; - struct amdgpu_mn *rmn; + struct amdgpu_mn *amn; unsigned long key = AMDGPU_MN_KEY(mm, type); int r; @@ -325,41 +325,41 @@ struct amdgpu_mn *amdgpu_mn_get(struct amdgpu_device *adev, return ERR_PTR(-EINTR); } - hash_for_each_possible(adev->mn_hash, rmn, node, key) - if (AMDGPU_MN_KEY(rmn->mm, rmn->type) == key) + hash_for_each_possible(adev->mn_hash, amn, node, key) + if (AMDGPU_MN_KEY(amn->mm, amn->type) == key) goto release_locks; - rmn = kzalloc(sizeof(*rmn), GFP_KERNEL); - if (!rmn) { - rmn = ERR_PTR(-ENOMEM); + amn = kzalloc(sizeof(*amn), GFP_KERNEL); + if (!amn) { + amn = ERR_PTR(-ENOMEM); goto release_locks; } - rmn->adev = adev; - rmn->mm = mm; - init_rwsem(&rmn->lock); - rmn->type = type; - rmn->mn.ops = &amdgpu_mn_ops[type]; - rmn->objects = RB_ROOT_CACHED; - mutex_init(&rmn->read_lock); - atomic_set(&rmn->recursion, 0); + amn->adev = adev; + amn->mm = mm; + init_rwsem(&amn->lock); + amn->type = type; + amn->mn.ops = &amdgpu_mn_ops[type]; + amn->objects = RB_ROOT_CACHED; + mutex_init(&amn->read_lock); + atomic_set(&amn->recursion, 0); - r = __mmu_notifier_register(&rmn->mn, mm); + r = __mmu_notifier_register(&amn->mn, mm); if (r) - goto free_rmn; + goto free_amn; - hash_add(adev->mn_hash, &rmn->node, AMDGPU_MN_KEY(mm, type)); + hash_add(adev->mn_hash, &amn->node, AMDGPU_MN_KEY(mm, type)); release_locks: up_write(&mm->mmap_sem); mutex_unlock(&adev->mn_lock); - return rmn; + return amn; -free_rmn: +free_amn: up_write(&mm->mmap_sem); mutex_unlock(&adev->mn_lock); - kfree(rmn); + kfree(amn); return ERR_PTR(r); } @@ -379,14 +379,14 @@ int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr) struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); enum amdgpu_mn_type type = bo->kfd_bo ? AMDGPU_MN_TYPE_HSA : AMDGPU_MN_TYPE_GFX; - struct amdgpu_mn *rmn; + struct amdgpu_mn *amn; struct amdgpu_mn_node *node = NULL, *new_node; struct list_head bos; struct interval_tree_node *it; - rmn = amdgpu_mn_get(adev, type); - if (IS_ERR(rmn)) - return PTR_ERR(rmn); + amn = amdgpu_mn_get(adev, type); + if (IS_ERR(amn)) + return PTR_ERR(amn); new_node = kmalloc(sizeof(*new_node), GFP_KERNEL); if (!new_node) @@ -394,12 +394,12 @@ int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr) INIT_LIST_HEAD(&bos); - down_write(&rmn->lock); + down_write(&amn->lock); - while ((it = interval_tree_iter_first(&rmn->objects, addr, end))) { + while ((it = interval_tree_iter_first(&amn->objects, addr, end))) { kfree(node); node = container_of(it, struct amdgpu_mn_node, it); - interval_tree_remove(&node->it, &rmn->objects); + interval_tree_remove(&node->it, &amn->objects); addr = min(it->start, addr); end = max(it->last, end); list_splice(&node->bos, &bos); @@ -410,7 +410,7 @@ int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr) else kfree(new_node); - bo->mn = rmn; + bo->mn = amn; node->it.start = addr; node->it.last = end; @@ -418,9 +418,9 @@ int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr) list_splice(&bos, &node->bos); list_add(&bo->mn_list, &node->bos); - interval_tree_insert(&node->it, &rmn->objects); + interval_tree_insert(&node->it, &amn->objects); - up_write(&rmn->lock); + up_write(&amn->lock); return 0; } @@ -435,18 +435,18 @@ int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr) void amdgpu_mn_unregister(struct amdgpu_bo *bo) { struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); - struct amdgpu_mn *rmn; + struct amdgpu_mn *amn; struct list_head *head; mutex_lock(&adev->mn_lock); - rmn = bo->mn; - if (rmn == NULL) { + amn = bo->mn; + if (amn == NULL) { mutex_unlock(&adev->mn_lock); return; } - down_write(&rmn->lock); + down_write(&amn->lock); /* save the next list entry for later */ head = bo->mn_list.next; @@ -457,11 +457,11 @@ void amdgpu_mn_unregister(struct amdgpu_bo *bo) if (list_empty(head)) { struct amdgpu_mn_node *node; node = container_of(head, struct amdgpu_mn_node, bos); - interval_tree_remove(&node->it, &rmn->objects); + interval_tree_remove(&node->it, &amn->objects); kfree(node); } - up_write(&rmn->lock); + up_write(&amn->lock); mutex_unlock(&adev->mn_lock); } -- GitLab From ad7f0b6334fe3cf52f2d79345791a4ef4547353f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Tue, 5 Jun 2018 11:47:43 +0200 Subject: [PATCH 0369/1506] drm/amdgpu: fix documentation of amdgpu_mn.c v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit And wire it up as well. v2: improve the wording, fix label mismatch Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Michel Dänzer <michel.daenzer@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- Documentation/gpu/amdgpu.rst | 9 ++++ drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c | 74 ++++++++++++++++++++------ 2 files changed, 67 insertions(+), 16 deletions(-) diff --git a/Documentation/gpu/amdgpu.rst b/Documentation/gpu/amdgpu.rst index 1fbf3876a3d88..a4852f9a61419 100644 --- a/Documentation/gpu/amdgpu.rst +++ b/Documentation/gpu/amdgpu.rst @@ -35,3 +35,12 @@ PRIME Buffer Sharing .. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c :internal: + +MMU Notifier +------------ + +.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c + :doc: MMU Notifier + +.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c + :internal: diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c index 37570a1c6db88..40fcb2af2914f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c @@ -28,6 +28,21 @@ * Christian König <christian.koenig@amd.com> */ +/** + * DOC: MMU Notifier + * + * For coherent userptr handling registers an MMU notifier to inform the driver + * about updates on the page tables of a process. + * + * When somebody tries to invalidate the page tables we block the update until + * all operations on the pages in question are completed, then those pages are + * marked as accessed and also dirty if it wasn't a read only access. + * + * New command submissions using the userptrs in question are delayed until all + * page table invalidation are completed and we once more see a coherent process + * address space. + */ + #include <linux/firmware.h> #include <linux/module.h> #include <linux/mmu_notifier.h> @@ -38,6 +53,21 @@ #include "amdgpu.h" #include "amdgpu_amdkfd.h" +/** + * struct amdgpu_mn + * + * @adev: amdgpu device pointer + * @mm: process address space + * @mn: MMU notifier structur + * @work: destrution work item + * @node: hash table node to find structure by adev and mn + * @lock: rw semaphore protecting the notifier nodes + * @objects: interval tree containing amdgpu_mn_nodes + * @read_lock: mutex for recursive locking of @lock + * @recursion: depth of recursion + * + * Data for each amdgpu device and process address space. + */ struct amdgpu_mn { /* constant after initialisation */ struct amdgpu_device *adev; @@ -58,13 +88,21 @@ struct amdgpu_mn { atomic_t recursion; }; +/** + * struct amdgpu_mn_node + * + * @it: interval node defining start-last of the affected address range + * @bos: list of all BOs in the affected address range + * + * Manages all BOs which are affected of a certain range of address space. + */ struct amdgpu_mn_node { struct interval_tree_node it; struct list_head bos; }; /** - * amdgpu_mn_destroy - destroy the amn + * amdgpu_mn_destroy - destroy the MMU notifier * * @work: previously sheduled work item * @@ -98,7 +136,7 @@ static void amdgpu_mn_destroy(struct work_struct *work) * amdgpu_mn_release - callback to notify about mm destruction * * @mn: our notifier - * @mn: the mm this callback is about + * @mm: the mm this callback is about * * Shedule a work item to lazy destroy our notifier. */ @@ -106,13 +144,16 @@ static void amdgpu_mn_release(struct mmu_notifier *mn, struct mm_struct *mm) { struct amdgpu_mn *amn = container_of(mn, struct amdgpu_mn, mn); + INIT_WORK(&amn->work, amdgpu_mn_destroy); schedule_work(&amn->work); } /** - * amdgpu_mn_lock - take the write side lock for this mn + * amdgpu_mn_lock - take the write side lock for this notifier + * + * @mn: our notifier */ void amdgpu_mn_lock(struct amdgpu_mn *mn) { @@ -121,7 +162,9 @@ void amdgpu_mn_lock(struct amdgpu_mn *mn) } /** - * amdgpu_mn_unlock - drop the write side lock for this mn + * amdgpu_mn_unlock - drop the write side lock for this notifier + * + * @mn: our notifier */ void amdgpu_mn_unlock(struct amdgpu_mn *mn) { @@ -130,11 +173,9 @@ void amdgpu_mn_unlock(struct amdgpu_mn *mn) } /** - * amdgpu_mn_read_lock - take the amn read lock + * amdgpu_mn_read_lock - take the read side lock for this notifier * * @amn: our notifier - * - * Take the amn read side lock. */ static void amdgpu_mn_read_lock(struct amdgpu_mn *amn) { @@ -145,11 +186,9 @@ static void amdgpu_mn_read_lock(struct amdgpu_mn *amn) } /** - * amdgpu_mn_read_unlock - drop the amn read lock + * amdgpu_mn_read_unlock - drop the read side lock for this notifier * * @amn: our notifier - * - * Drop the amn read side lock. */ static void amdgpu_mn_read_unlock(struct amdgpu_mn *amn) { @@ -161,9 +200,11 @@ static void amdgpu_mn_read_unlock(struct amdgpu_mn *amn) * amdgpu_mn_invalidate_node - unmap all BOs of a node * * @node: the node with the BOs to unmap + * @start: start of address range affected + * @end: end of address range affected * - * We block for all BOs and unmap them by move them - * into system domain again. + * Block for operations on BOs to finish and mark pages as accessed and + * potentially dirty. */ static void amdgpu_mn_invalidate_node(struct amdgpu_mn_node *node, unsigned long start, @@ -190,12 +231,12 @@ static void amdgpu_mn_invalidate_node(struct amdgpu_mn_node *node, * amdgpu_mn_invalidate_range_start_gfx - callback to notify about mm change * * @mn: our notifier - * @mn: the mm this callback is about + * @mm: the mm this callback is about * @start: start of updated range * @end: end of updated range * - * We block for all BOs between start and end to be idle and - * unmap them by move them into system domain again. + * Block for operations on BOs to finish and mark pages as accessed and + * potentially dirty. */ static void amdgpu_mn_invalidate_range_start_gfx(struct mmu_notifier *mn, struct mm_struct *mm, @@ -268,7 +309,7 @@ static void amdgpu_mn_invalidate_range_start_hsa(struct mmu_notifier *mn, * amdgpu_mn_invalidate_range_end - callback to notify about mm change * * @mn: our notifier - * @mn: the mm this callback is about + * @mm: the mm this callback is about * @start: start of updated range * @end: end of updated range * @@ -456,6 +497,7 @@ void amdgpu_mn_unregister(struct amdgpu_bo *bo) if (list_empty(head)) { struct amdgpu_mn_node *node; + node = container_of(head, struct amdgpu_mn_node, bos); interval_tree_remove(&node->it, &amn->objects); kfree(node); -- GitLab From f4557923b5d3bd5aaa4177ea184c4389175cc92f Mon Sep 17 00:00:00 2001 From: Slava Abramov <slava.abramov@amd.com> Date: Wed, 13 Jun 2018 10:50:31 -0400 Subject: [PATCH 0370/1506] drm/amdgpu: fix typo in amdgpu_mn.c comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In doc comments for struct amdgpu_mn: destrution -> destruction Signed-off-by: Slava Abramov <slava.abramov@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c index 40fcb2af2914f..72a3e8c688760 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c @@ -59,7 +59,7 @@ * @adev: amdgpu device pointer * @mm: process address space * @mn: MMU notifier structur - * @work: destrution work item + * @work: destruction work item * @node: hash table node to find structure by adev and mn * @lock: rw semaphore protecting the notifier nodes * @objects: interval tree containing amdgpu_mn_nodes -- GitLab From 7fc48e5912795caf78b1e2fb86d5f6ee02fbdb8c Mon Sep 17 00:00:00 2001 From: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Date: Mon, 11 Jun 2018 11:11:24 -0400 Subject: [PATCH 0371/1506] drm/amdgpu: Update function level documentation for GPUVM v3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add/update function level documentation and add reference to amdgpu_vm.c in amdgpu.rst v2: Fix reference in rst file. Fix compilation warnings. Add space between function names and params list where it's missing. v3: Fix some funtion comments. Add formatted documentation to structs. Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- Documentation/gpu/amdgpu.rst | 9 + drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 253 +++++++++++++++++++++---- 2 files changed, 224 insertions(+), 38 deletions(-) diff --git a/Documentation/gpu/amdgpu.rst b/Documentation/gpu/amdgpu.rst index a4852f9a61419..3ffb2a226faef 100644 --- a/Documentation/gpu/amdgpu.rst +++ b/Documentation/gpu/amdgpu.rst @@ -44,3 +44,12 @@ MMU Notifier .. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c :internal: + +AMDGPU Virtual Memory +--------------------- + +.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c + :doc: GPUVM + +.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c + :internal: diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index d88687b617e2f..7f03f8c387085 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -34,8 +34,9 @@ #include "amdgpu_trace.h" #include "amdgpu_amdkfd.h" -/* - * GPUVM +/** + * DOC: GPUVM + * * GPUVM is similar to the legacy gart on older asics, however * rather than there being a single global gart table * for the entire GPU, there are multiple VM page tables active @@ -63,37 +64,84 @@ INTERVAL_TREE_DEFINE(struct amdgpu_bo_va_mapping, rb, uint64_t, __subtree_last, #undef START #undef LAST -/* Local structure. Encapsulate some VM table update parameters to reduce +/** + * struct amdgpu_pte_update_params - Local structure + * + * Encapsulate some VM table update parameters to reduce * the number of function parameters + * */ struct amdgpu_pte_update_params { - /* amdgpu device we do this update for */ + + /** + * @adev: amdgpu device we do this update for + */ struct amdgpu_device *adev; - /* optional amdgpu_vm we do this update for */ + + /** + * @vm: optional amdgpu_vm we do this update for + */ struct amdgpu_vm *vm; - /* address where to copy page table entries from */ + + /** + * @src: address where to copy page table entries from + */ uint64_t src; - /* indirect buffer to fill with commands */ + + /** + * @ib: indirect buffer to fill with commands + */ struct amdgpu_ib *ib; - /* Function which actually does the update */ + + /** + * @func: Function which actually does the update + */ void (*func)(struct amdgpu_pte_update_params *params, struct amdgpu_bo *bo, uint64_t pe, uint64_t addr, unsigned count, uint32_t incr, uint64_t flags); - /* The next two are used during VM update by CPU - * DMA addresses to use for mapping - * Kernel pointer of PD/PT BO that needs to be updated + /** + * @pages_addr: + * + * DMA addresses to use for mapping, used during VM update by CPU */ dma_addr_t *pages_addr; + + /** + * @kptr: + * + * Kernel pointer of PD/PT BO that needs to be updated, + * used during VM update by CPU + */ void *kptr; }; -/* Helper to disable partial resident texture feature from a fence callback */ +/** + * struct amdgpu_prt_cb - Helper to disable partial resident texture feature from a fence callback + */ struct amdgpu_prt_cb { + + /** + * @adev: amdgpu device + */ struct amdgpu_device *adev; + + /** + * @cb: callback + */ struct dma_fence_cb cb; }; +/** + * amdgpu_vm_bo_base_init - Adds bo to the list of bos associated with the vm + * + * @base: base structure for tracking BO usage in a VM + * @vm: vm to which bo is to be added + * @bo: amdgpu buffer object + * + * Initialize a bo_va_base structure and add it to the appropriate lists + * + */ static void amdgpu_vm_bo_base_init(struct amdgpu_vm_bo_base *base, struct amdgpu_vm *vm, struct amdgpu_bo *bo) @@ -126,8 +174,10 @@ static void amdgpu_vm_bo_base_init(struct amdgpu_vm_bo_base *base, * amdgpu_vm_level_shift - return the addr shift for each level * * @adev: amdgpu_device pointer + * @level: VMPT level * - * Returns the number of bits the pfn needs to be right shifted for a level. + * Returns: + * The number of bits the pfn needs to be right shifted for a level. */ static unsigned amdgpu_vm_level_shift(struct amdgpu_device *adev, unsigned level) @@ -155,8 +205,10 @@ static unsigned amdgpu_vm_level_shift(struct amdgpu_device *adev, * amdgpu_vm_num_entries - return the number of entries in a PD/PT * * @adev: amdgpu_device pointer + * @level: VMPT level * - * Calculate the number of entries in a page directory or page table. + * Returns: + * The number of entries in a page directory or page table. */ static unsigned amdgpu_vm_num_entries(struct amdgpu_device *adev, unsigned level) @@ -179,8 +231,10 @@ static unsigned amdgpu_vm_num_entries(struct amdgpu_device *adev, * amdgpu_vm_bo_size - returns the size of the BOs in bytes * * @adev: amdgpu_device pointer + * @level: VMPT level * - * Calculate the size of the BO for a page directory or page table in bytes. + * Returns: + * The size of the BO for a page directory or page table in bytes. */ static unsigned amdgpu_vm_bo_size(struct amdgpu_device *adev, unsigned level) { @@ -218,6 +272,9 @@ void amdgpu_vm_get_pd_bo(struct amdgpu_vm *vm, * @param: parameter for the validation callback * * Validate the page table BOs on command submission if neccessary. + * + * Returns: + * Validation result. */ int amdgpu_vm_validate_pt_bos(struct amdgpu_device *adev, struct amdgpu_vm *vm, int (*validate)(void *p, struct amdgpu_bo *bo), @@ -273,6 +330,9 @@ int amdgpu_vm_validate_pt_bos(struct amdgpu_device *adev, struct amdgpu_vm *vm, * @vm: VM to check * * Check if all VM PDs/PTs are ready for updates + * + * Returns: + * True if eviction list is empty. */ bool amdgpu_vm_ready(struct amdgpu_vm *vm) { @@ -283,10 +343,14 @@ bool amdgpu_vm_ready(struct amdgpu_vm *vm) * amdgpu_vm_clear_bo - initially clear the PDs/PTs * * @adev: amdgpu_device pointer + * @vm: VM to clear BO from * @bo: BO to clear * @level: level this BO is at * * Root PD needs to be reserved when calling this. + * + * Returns: + * 0 on success, errno otherwise. */ static int amdgpu_vm_clear_bo(struct amdgpu_device *adev, struct amdgpu_vm *vm, struct amdgpu_bo *bo, @@ -382,10 +446,16 @@ static int amdgpu_vm_clear_bo(struct amdgpu_device *adev, * * @adev: amdgpu_device pointer * @vm: requested vm + * @parent: parent PT * @saddr: start of the address range * @eaddr: end of the address range + * @level: VMPT level + * @ats: indicate ATS support from PTE * * Make sure the page directories and page tables are allocated + * + * Returns: + * 0 on success, errno otherwise. */ static int amdgpu_vm_alloc_levels(struct amdgpu_device *adev, struct amdgpu_vm *vm, @@ -494,6 +564,9 @@ static int amdgpu_vm_alloc_levels(struct amdgpu_device *adev, * @size: Size from start address we need. * * Make sure the page tables are allocated. + * + * Returns: + * 0 on success, errno otherwise. */ int amdgpu_vm_alloc_pts(struct amdgpu_device *adev, struct amdgpu_vm *vm, @@ -559,6 +632,15 @@ void amdgpu_vm_check_compute_bug(struct amdgpu_device *adev) } } +/** + * amdgpu_vm_need_pipeline_sync - Check if pipe sync is needed for job. + * + * @ring: ring on which the job will be submitted + * @job: job to submit + * + * Returns: + * True if sync is needed. + */ bool amdgpu_vm_need_pipeline_sync(struct amdgpu_ring *ring, struct amdgpu_job *job) { @@ -586,6 +668,14 @@ bool amdgpu_vm_need_pipeline_sync(struct amdgpu_ring *ring, return vm_flush_needed || gds_switch_needed; } +/** + * amdgpu_vm_is_large_bar - Check if BAR is large enough + * + * @adev: amdgpu_device pointer + * + * Returns: + * True if BAR is large enough. + */ static bool amdgpu_vm_is_large_bar(struct amdgpu_device *adev) { return (adev->gmc.real_vram_size == adev->gmc.visible_vram_size); @@ -595,10 +685,12 @@ static bool amdgpu_vm_is_large_bar(struct amdgpu_device *adev) * amdgpu_vm_flush - hardware flush the vm * * @ring: ring to use for flush - * @vmid: vmid number to use - * @pd_addr: address of the page directory + * @need_pipe_sync: is pipe sync needed * * Emit a VM flush when it is necessary. + * + * Returns: + * 0 on success, errno otherwise. */ int amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job, bool need_pipe_sync) { @@ -706,6 +798,9 @@ int amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job, bool need_ * Returns the found bo_va or NULL if none is found * * Object has to be reserved! + * + * Returns: + * Found bo_va or NULL. */ struct amdgpu_bo_va *amdgpu_vm_bo_find(struct amdgpu_vm *vm, struct amdgpu_bo *bo) @@ -787,7 +882,10 @@ static void amdgpu_vm_do_copy_ptes(struct amdgpu_pte_update_params *params, * @addr: the unmapped addr * * Look up the physical address of the page that the pte resolves - * to and return the pointer for the page table entry. + * to. + * + * Returns: + * The pointer for the page table entry. */ static uint64_t amdgpu_vm_map_gart(const dma_addr_t *pages_addr, uint64_t addr) { @@ -840,6 +938,17 @@ static void amdgpu_vm_cpu_set_ptes(struct amdgpu_pte_update_params *params, } } + +/** + * amdgpu_vm_wait_pd - Wait for PT BOs to be free. + * + * @adev: amdgpu_device pointer + * @vm: related vm + * @owner: fence owner + * + * Returns: + * 0 on success, errno otherwise. + */ static int amdgpu_vm_wait_pd(struct amdgpu_device *adev, struct amdgpu_vm *vm, void *owner) { @@ -893,7 +1002,10 @@ static void amdgpu_vm_update_pde(struct amdgpu_pte_update_params *params, /* * amdgpu_vm_invalidate_level - mark all PD levels as invalid * + * @adev: amdgpu_device pointer + * @vm: related vm * @parent: parent PD + * @level: VMPT level * * Mark all PD level as invalid after an error. */ @@ -928,7 +1040,9 @@ static void amdgpu_vm_invalidate_level(struct amdgpu_device *adev, * @vm: requested vm * * Makes sure all directories are up to date. - * Returns 0 for success, error for failure. + * + * Returns: + * 0 for success, error for failure. */ int amdgpu_vm_update_directories(struct amdgpu_device *adev, struct amdgpu_vm *vm) @@ -1115,14 +1229,15 @@ static void amdgpu_vm_handle_huge_pages(struct amdgpu_pte_update_params *p, * amdgpu_vm_update_ptes - make sure that page tables are valid * * @params: see amdgpu_pte_update_params definition - * @vm: requested vm * @start: start of GPU address range * @end: end of GPU address range * @dst: destination address to map to, the next dst inside the function * @flags: mapping flags * * Update the page tables in the range @start - @end. - * Returns 0 for success, -EINVAL for failure. + * + * Returns: + * 0 for success, -EINVAL for failure. */ static int amdgpu_vm_update_ptes(struct amdgpu_pte_update_params *params, uint64_t start, uint64_t end, @@ -1176,7 +1291,9 @@ static int amdgpu_vm_update_ptes(struct amdgpu_pte_update_params *params, * @end: last PTE to handle * @dst: addr those PTEs should point to * @flags: hw mapping flags - * Returns 0 for success, -EINVAL for failure. + * + * Returns: + * 0 for success, -EINVAL for failure. */ static int amdgpu_vm_frag_ptes(struct amdgpu_pte_update_params *params, uint64_t start, uint64_t end, @@ -1248,7 +1365,9 @@ static int amdgpu_vm_frag_ptes(struct amdgpu_pte_update_params *params, * @fence: optional resulting fence * * Fill in the page table entries between @start and @last. - * Returns 0 for success, -EINVAL for failure. + * + * Returns: + * 0 for success, -EINVAL for failure. */ static int amdgpu_vm_bo_update_mapping(struct amdgpu_device *adev, struct dma_fence *exclusive, @@ -1403,7 +1522,9 @@ static int amdgpu_vm_bo_update_mapping(struct amdgpu_device *adev, * * Split the mapping into smaller chunks so that each update fits * into a SDMA IB. - * Returns 0 for success, -EINVAL for failure. + * + * Returns: + * 0 for success, -EINVAL for failure. */ static int amdgpu_vm_bo_split_mapping(struct amdgpu_device *adev, struct dma_fence *exclusive, @@ -1514,7 +1635,9 @@ static int amdgpu_vm_bo_split_mapping(struct amdgpu_device *adev, * @clear: if true clear the entries * * Fill in the page table entries for @bo_va. - * Returns 0 for success, -EINVAL for failure. + * + * Returns: + * 0 for success, -EINVAL for failure. */ int amdgpu_vm_bo_update(struct amdgpu_device *adev, struct amdgpu_bo_va *bo_va, @@ -1609,6 +1732,8 @@ int amdgpu_vm_bo_update(struct amdgpu_device *adev, /** * amdgpu_vm_update_prt_state - update the global PRT state + * + * @adev: amdgpu_device pointer */ static void amdgpu_vm_update_prt_state(struct amdgpu_device *adev) { @@ -1623,6 +1748,8 @@ static void amdgpu_vm_update_prt_state(struct amdgpu_device *adev) /** * amdgpu_vm_prt_get - add a PRT user + * + * @adev: amdgpu_device pointer */ static void amdgpu_vm_prt_get(struct amdgpu_device *adev) { @@ -1635,6 +1762,8 @@ static void amdgpu_vm_prt_get(struct amdgpu_device *adev) /** * amdgpu_vm_prt_put - drop a PRT user + * + * @adev: amdgpu_device pointer */ static void amdgpu_vm_prt_put(struct amdgpu_device *adev) { @@ -1644,6 +1773,8 @@ static void amdgpu_vm_prt_put(struct amdgpu_device *adev) /** * amdgpu_vm_prt_cb - callback for updating the PRT status + * + * @fence: fence for the callback */ static void amdgpu_vm_prt_cb(struct dma_fence *fence, struct dma_fence_cb *_cb) { @@ -1655,6 +1786,9 @@ static void amdgpu_vm_prt_cb(struct dma_fence *fence, struct dma_fence_cb *_cb) /** * amdgpu_vm_add_prt_cb - add callback for updating the PRT status + * + * @adev: amdgpu_device pointer + * @fence: fence for the callback */ static void amdgpu_vm_add_prt_cb(struct amdgpu_device *adev, struct dma_fence *fence) @@ -1746,9 +1880,11 @@ static void amdgpu_vm_prt_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm) * or if an error occurred) * * Make sure all freed BOs are cleared in the PT. - * Returns 0 for success. - * * PTs have to be reserved and mutex must be locked! + * + * Returns: + * 0 for success. + * */ int amdgpu_vm_clear_freed(struct amdgpu_device *adev, struct amdgpu_vm *vm, @@ -1793,10 +1929,11 @@ int amdgpu_vm_clear_freed(struct amdgpu_device *adev, * * @adev: amdgpu_device pointer * @vm: requested vm - * @sync: sync object to add fences to * * Make sure all BOs which are moved are updated in the PTs. - * Returns 0 for success. + * + * Returns: + * 0 for success. * * PTs have to be reserved! */ @@ -1851,7 +1988,9 @@ int amdgpu_vm_handle_moved(struct amdgpu_device *adev, * * Add @bo into the requested vm. * Add @bo to the list of bos associated with the vm - * Returns newly added bo_va or NULL for failure + * + * Returns: + * Newly added bo_va or NULL for failure * * Object has to be reserved! */ @@ -1917,7 +2056,9 @@ static void amdgpu_vm_bo_insert_map(struct amdgpu_device *adev, * @flags: attributes of pages (read/write/valid/etc.) * * Add a mapping of the BO at the specefied addr into the VM. - * Returns 0 for success, error for failure. + * + * Returns: + * 0 for success, error for failure. * * Object has to be reserved and unreserved outside! */ @@ -1979,7 +2120,9 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev, * * Add a mapping of the BO at the specefied addr into the VM. Replace existing * mappings as we do so. - * Returns 0 for success, error for failure. + * + * Returns: + * 0 for success, error for failure. * * Object has to be reserved and unreserved outside! */ @@ -2036,7 +2179,9 @@ int amdgpu_vm_bo_replace_map(struct amdgpu_device *adev, * @saddr: where to the BO is mapped * * Remove a mapping of the BO at the specefied addr from the VM. - * Returns 0 for success, error for failure. + * + * Returns: + * 0 for success, error for failure. * * Object has to be reserved and unreserved outside! */ @@ -2090,7 +2235,9 @@ int amdgpu_vm_bo_unmap(struct amdgpu_device *adev, * @size: size of the range * * Remove all mappings in a range, split them as appropriate. - * Returns 0 for success, error for failure. + * + * Returns: + * 0 for success, error for failure. */ int amdgpu_vm_bo_clear_mappings(struct amdgpu_device *adev, struct amdgpu_vm *vm, @@ -2189,6 +2336,10 @@ int amdgpu_vm_bo_clear_mappings(struct amdgpu_device *adev, * @vm: the requested VM * * Find a mapping by it's address. + * + * Returns: + * The amdgpu_bo_va_mapping matching for addr or NULL + * */ struct amdgpu_bo_va_mapping *amdgpu_vm_bo_lookup_mapping(struct amdgpu_vm *vm, uint64_t addr) @@ -2240,7 +2391,6 @@ void amdgpu_vm_bo_rmv(struct amdgpu_device *adev, * amdgpu_vm_bo_invalidate - mark the bo as invalid * * @adev: amdgpu_device pointer - * @vm: requested vm * @bo: amdgpu buffer object * * Mark @bo as invalid. @@ -2281,6 +2431,14 @@ void amdgpu_vm_bo_invalidate(struct amdgpu_device *adev, } } +/** + * amdgpu_vm_get_block_size - calculate VM page table size as power of two + * + * @vm_size: VM size + * + * Returns: + * VM page table as power of two + */ static uint32_t amdgpu_vm_get_block_size(uint64_t vm_size) { /* Total bits covered by PD + PTs */ @@ -2368,6 +2526,9 @@ void amdgpu_vm_adjust_size(struct amdgpu_device *adev, uint32_t vm_size, * @vm_context: Indicates if it GFX or Compute context * * Init @vm fields. + * + * Returns: + * 0 for success, error for failure. */ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm, int vm_context, unsigned int pasid) @@ -2488,6 +2649,9 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm, /** * amdgpu_vm_make_compute - Turn a GFX VM into a compute VM * + * @adev: amdgpu_device pointer + * @vm: requested vm + * * This only works on GFX VMs that don't have any BOs added and no * page tables allocated yet. * @@ -2500,7 +2664,8 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm, * setting. May leave behind an unused shadow BO for the page * directory when switching from SDMA updates to CPU updates. * - * Returns 0 for success, -errno for errors. + * Returns: + * 0 for success, -errno for errors. */ int amdgpu_vm_make_compute(struct amdgpu_device *adev, struct amdgpu_vm *vm) { @@ -2655,8 +2820,10 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm) * @adev: amdgpu_device pointer * @pasid: PASID do identify the VM * - * This function is expected to be called in interrupt context. Returns - * true if there was fault credit, false otherwise + * This function is expected to be called in interrupt context. + * + * Returns: + * True if there was fault credit, false otherwise */ bool amdgpu_vm_pasid_fault_credit(struct amdgpu_device *adev, unsigned int pasid) @@ -2740,6 +2907,16 @@ void amdgpu_vm_manager_fini(struct amdgpu_device *adev) amdgpu_vmid_mgr_fini(adev); } +/** + * amdgpu_vm_ioctl - Manages VMID reservation for vm hubs. + * + * @dev: drm device pointer + * @data: drm_amdgpu_vm + * @filp: drm file pointer + * + * Returns: + * 0 for success, -errno for errors. + */ int amdgpu_vm_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) { union drm_amdgpu_vm *args = data; -- GitLab From 923ff76eb035b0de3725edd7c13cda3b068ba197 Mon Sep 17 00:00:00 2001 From: Slava Abramov <slava.abramov@amd.com> Date: Thu, 7 Jun 2018 17:27:07 -0400 Subject: [PATCH 0372/1506] drm/amdgpu: update documentation for amdgpu_irq.c v3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add/update function level documentation and add reference to amdgpu_irq.c in amdgpu.rst v2: Added DOC comment Added more explanations for amdgpu_hotplug_work_func Properly formatted unused parameters Properly formatted return values Fixed usage of acronyms More consistent styling v3: Removed duplicate "not" Using '&' to refer to functions and types Signed-off-by: Slava Abramov <slava.abramov@amd.com> Acked-by: Christian König <christian.koenig@amd.com> Reviewed-by: Michel Dänzer <michel.daenzer@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- Documentation/gpu/amdgpu.rst | 8 + drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c | 202 ++++++++++++++++-------- 2 files changed, 147 insertions(+), 63 deletions(-) diff --git a/Documentation/gpu/amdgpu.rst b/Documentation/gpu/amdgpu.rst index 3ffb2a226faef..abf87360ab154 100644 --- a/Documentation/gpu/amdgpu.rst +++ b/Documentation/gpu/amdgpu.rst @@ -52,4 +52,12 @@ AMDGPU Virtual Memory :doc: GPUVM .. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c + +Interrupt Handling +------------------ + +.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c + :doc: Interrupt Handling + +.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c :internal: diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c index 3a5ca462abf09..1abf5b5bac9e5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c @@ -25,6 +25,23 @@ * Alex Deucher * Jerome Glisse */ + +/** + * DOC: Interrupt Handling + * + * Interrupts generated within GPU hardware raise interrupt requests that are + * passed to amdgpu IRQ handler which is responsible for detecting source and + * type of the interrupt and dispatching matching handlers. If handling an + * interrupt requires calling kernel functions that may sleep processing is + * dispatched to work handlers. + * + * If MSI functionality is not disabled by module parameter then MSI + * support will be enabled. + * + * For GPU interrupt sources that may be driven by another driver, IRQ domain + * support is used (with mapping between virtual and hardware IRQs). + */ + #include <linux/irq.h> #include <drm/drmP.h> #include <drm/drm_crtc_helper.h> @@ -43,19 +60,21 @@ #define AMDGPU_WAIT_IDLE_TIMEOUT 200 -/* - * Handle hotplug events outside the interrupt handler proper. - */ /** - * amdgpu_hotplug_work_func - display hotplug work handler + * amdgpu_hotplug_work_func - work handler for display hotplug event * - * @work: work struct + * @work: work struct pointer * - * This is the hot plug event work handler (all asics). - * The work gets scheduled from the irq handler if there - * was a hot plug interrupt. It walks the connector table - * and calls the hotplug handler for each one, then sends - * a drm hotplug event to alert userspace. + * This is the hotplug event work handler (all ASICs). + * The work gets scheduled from the IRQ handler if there + * was a hotplug interrupt. It walks through the connector table + * and calls hotplug handler for each connector. After this, it sends + * a DRM hotplug event to alert userspace. + * + * This design approach is required in order to defer hotplug event handling + * from the IRQ handler to a work handler because hotplug handler has to use + * mutexes which cannot be locked in an IRQ handler (since &mutex_lock may + * sleep). */ static void amdgpu_hotplug_work_func(struct work_struct *work) { @@ -74,13 +93,12 @@ static void amdgpu_hotplug_work_func(struct work_struct *work) } /** - * amdgpu_irq_reset_work_func - execute gpu reset + * amdgpu_irq_reset_work_func - execute GPU reset * - * @work: work struct + * @work: work struct pointer * - * Execute scheduled gpu reset (cayman+). - * This function is called when the irq handler - * thinks we need a gpu reset. + * Execute scheduled GPU reset (Cayman+). + * This function is called when the IRQ handler thinks we need a GPU reset. */ static void amdgpu_irq_reset_work_func(struct work_struct *work) { @@ -91,7 +109,13 @@ static void amdgpu_irq_reset_work_func(struct work_struct *work) amdgpu_device_gpu_recover(adev, NULL, false); } -/* Disable *all* interrupts */ +/** + * amdgpu_irq_disable_all - disable *all* interrupts + * + * @adev: amdgpu device pointer + * + * Disable all types of interrupts from all sources. + */ void amdgpu_irq_disable_all(struct amdgpu_device *adev) { unsigned long irqflags; @@ -123,11 +147,15 @@ void amdgpu_irq_disable_all(struct amdgpu_device *adev) } /** - * amdgpu_irq_handler - irq handler + * amdgpu_irq_handler - IRQ handler + * + * @irq: IRQ number (unused) + * @arg: pointer to DRM device * - * @int irq, void *arg: args + * IRQ handler for amdgpu driver (all ASICs). * - * This is the irq handler for the amdgpu driver (all asics). + * Returns: + * result of handling the IRQ, as defined by &irqreturn_t */ irqreturn_t amdgpu_irq_handler(int irq, void *arg) { @@ -142,18 +170,18 @@ irqreturn_t amdgpu_irq_handler(int irq, void *arg) } /** - * amdgpu_msi_ok - asic specific msi checks + * amdgpu_msi_ok - check whether MSI functionality is enabled * - * @adev: amdgpu device pointer + * @adev: amdgpu device pointer (unused) + * + * Checks whether MSI functionality has been disabled via module parameter + * (all ASICs). * - * Handles asic specific MSI checks to determine if - * MSIs should be enabled on a particular chip (all asics). - * Returns true if MSIs should be enabled, false if MSIs - * should not be enabled. + * Returns: + * *true* if MSIs are allowed to be enabled or *false* otherwise */ static bool amdgpu_msi_ok(struct amdgpu_device *adev) { - /* force MSI on */ if (amdgpu_msi == 1) return true; else if (amdgpu_msi == 0) @@ -163,12 +191,15 @@ static bool amdgpu_msi_ok(struct amdgpu_device *adev) } /** - * amdgpu_irq_init - init driver interrupt info + * amdgpu_irq_init - initialize interrupt handling * * @adev: amdgpu device pointer * - * Sets up the work irq handlers, vblank init, MSIs, etc. (all asics). - * Returns 0 for success, error for failure. + * Sets up work functions for hotplug and reset interrupts, enables MSI + * functionality, initializes vblank, hotplug and reset interrupt handling. + * + * Returns: + * 0 on success or error code on failure */ int amdgpu_irq_init(struct amdgpu_device *adev) { @@ -176,7 +207,7 @@ int amdgpu_irq_init(struct amdgpu_device *adev) spin_lock_init(&adev->irq.lock); - /* enable msi */ + /* Enable MSI if not disabled by module parameter */ adev->irq.msi_enabled = false; if (amdgpu_msi_ok(adev)) { @@ -189,7 +220,7 @@ int amdgpu_irq_init(struct amdgpu_device *adev) if (!amdgpu_device_has_dc_support(adev)) { if (!adev->enable_virtual_display) - /* Disable vblank irqs aggressively for power-saving */ + /* Disable vblank IRQs aggressively for power-saving */ /* XXX: can this be enabled for DC? */ adev->ddev->vblank_disable_immediate = true; @@ -197,7 +228,7 @@ int amdgpu_irq_init(struct amdgpu_device *adev) if (r) return r; - /* pre DCE11 */ + /* Pre-DCE11 */ INIT_WORK(&adev->hotplug_work, amdgpu_hotplug_work_func); } @@ -220,11 +251,13 @@ int amdgpu_irq_init(struct amdgpu_device *adev) } /** - * amdgpu_irq_fini - tear down driver interrupt info + * amdgpu_irq_fini - shut down interrupt handling * * @adev: amdgpu device pointer * - * Tears down the work irq handlers, vblank handlers, MSIs, etc. (all asics). + * Tears down work functions for hotplug and reset interrupts, disables MSI + * functionality, shuts down vblank, hotplug and reset interrupt handling, + * turns off interrupts from all sources (all ASICs). */ void amdgpu_irq_fini(struct amdgpu_device *adev) { @@ -264,12 +297,17 @@ void amdgpu_irq_fini(struct amdgpu_device *adev) } /** - * amdgpu_irq_add_id - register irq source + * amdgpu_irq_add_id - register IRQ source * * @adev: amdgpu device pointer - * @src_id: source id for this source - * @source: irq source + * @client_id: client id + * @src_id: source id + * @source: IRQ source pointer + * + * Registers IRQ source on a client. * + * Returns: + * 0 on success or error code otherwise */ int amdgpu_irq_add_id(struct amdgpu_device *adev, unsigned client_id, unsigned src_id, @@ -312,12 +350,12 @@ int amdgpu_irq_add_id(struct amdgpu_device *adev, } /** - * amdgpu_irq_dispatch - dispatch irq to IP blocks + * amdgpu_irq_dispatch - dispatch IRQ to IP blocks * * @adev: amdgpu device pointer - * @entry: interrupt vector + * @entry: interrupt vector pointer * - * Dispatches the irq to the different IP blocks + * Dispatches IRQ to IP blocks. */ void amdgpu_irq_dispatch(struct amdgpu_device *adev, struct amdgpu_iv_entry *entry) @@ -361,13 +399,13 @@ void amdgpu_irq_dispatch(struct amdgpu_device *adev, } /** - * amdgpu_irq_update - update hw interrupt state + * amdgpu_irq_update - update hardware interrupt state * * @adev: amdgpu device pointer - * @src: interrupt src you want to enable - * @type: type of interrupt you want to update + * @src: interrupt source pointer + * @type: type of interrupt * - * Updates the interrupt state for a specific src (all asics). + * Updates interrupt state for the specific source (all ASICs). */ int amdgpu_irq_update(struct amdgpu_device *adev, struct amdgpu_irq_src *src, unsigned type) @@ -378,7 +416,7 @@ int amdgpu_irq_update(struct amdgpu_device *adev, spin_lock_irqsave(&adev->irq.lock, irqflags); - /* we need to determine after taking the lock, otherwise + /* We need to determine after taking the lock, otherwise we might disable just enabled interrupts again */ if (amdgpu_irq_enabled(adev, src, type)) state = AMDGPU_IRQ_STATE_ENABLE; @@ -390,6 +428,14 @@ int amdgpu_irq_update(struct amdgpu_device *adev, return r; } +/** + * amdgpu_irq_gpu_reset_resume_helper - update interrupt states on all sources + * + * @adev: amdgpu device pointer + * + * Updates state of all types of interrupts on all sources on resume after + * reset. + */ void amdgpu_irq_gpu_reset_resume_helper(struct amdgpu_device *adev) { int i, j, k; @@ -413,10 +459,13 @@ void amdgpu_irq_gpu_reset_resume_helper(struct amdgpu_device *adev) * amdgpu_irq_get - enable interrupt * * @adev: amdgpu device pointer - * @src: interrupt src you want to enable - * @type: type of interrupt you want to enable + * @src: interrupt source pointer + * @type: type of interrupt * - * Enables the interrupt type for a specific src (all asics). + * Enables specified type of interrupt on the specified source (all ASICs). + * + * Returns: + * 0 on success or error code otherwise */ int amdgpu_irq_get(struct amdgpu_device *adev, struct amdgpu_irq_src *src, unsigned type) @@ -440,10 +489,13 @@ int amdgpu_irq_get(struct amdgpu_device *adev, struct amdgpu_irq_src *src, * amdgpu_irq_put - disable interrupt * * @adev: amdgpu device pointer - * @src: interrupt src you want to disable - * @type: type of interrupt you want to disable + * @src: interrupt source pointer + * @type: type of interrupt + * + * Enables specified type of interrupt on the specified source (all ASICs). * - * Disables the interrupt type for a specific src (all asics). + * Returns: + * 0 on success or error code otherwise */ int amdgpu_irq_put(struct amdgpu_device *adev, struct amdgpu_irq_src *src, unsigned type) @@ -464,12 +516,17 @@ int amdgpu_irq_put(struct amdgpu_device *adev, struct amdgpu_irq_src *src, } /** - * amdgpu_irq_enabled - test if irq is enabled or not + * amdgpu_irq_enabled - check whether interrupt is enabled or not * * @adev: amdgpu device pointer - * @idx: interrupt src you want to test + * @src: interrupt source pointer + * @type: type of interrupt * - * Tests if the given interrupt source is enabled or not + * Checks whether the given type of interrupt is enabled on the given source. + * + * Returns: + * *true* if interrupt is enabled, *false* if interrupt is disabled or on + * invalid parameters */ bool amdgpu_irq_enabled(struct amdgpu_device *adev, struct amdgpu_irq_src *src, unsigned type) @@ -486,7 +543,7 @@ bool amdgpu_irq_enabled(struct amdgpu_device *adev, struct amdgpu_irq_src *src, return !!atomic_read(&src->enabled_types[type]); } -/* gen irq */ +/* XXX: Generic IRQ handling */ static void amdgpu_irq_mask(struct irq_data *irqd) { /* XXX */ @@ -497,12 +554,26 @@ static void amdgpu_irq_unmask(struct irq_data *irqd) /* XXX */ } +/* amdgpu hardware interrupt chip descriptor */ static struct irq_chip amdgpu_irq_chip = { .name = "amdgpu-ih", .irq_mask = amdgpu_irq_mask, .irq_unmask = amdgpu_irq_unmask, }; +/** + * amdgpu_irqdomain_map - create mapping between virtual and hardware IRQ numbers + * + * @d: amdgpu IRQ domain pointer (unused) + * @irq: virtual IRQ number + * @hwirq: hardware irq number + * + * Current implementation assigns simple interrupt handler to the given virtual + * IRQ. + * + * Returns: + * 0 on success or error code otherwise + */ static int amdgpu_irqdomain_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hwirq) { @@ -514,17 +585,21 @@ static int amdgpu_irqdomain_map(struct irq_domain *d, return 0; } +/* Implementation of methods for amdgpu IRQ domain */ static const struct irq_domain_ops amdgpu_hw_irqdomain_ops = { .map = amdgpu_irqdomain_map, }; /** - * amdgpu_irq_add_domain - create a linear irq domain + * amdgpu_irq_add_domain - create a linear IRQ domain * * @adev: amdgpu device pointer * - * Create an irq domain for GPU interrupt sources + * Creates an IRQ domain for GPU interrupt sources * that may be driven by another driver (e.g., ACP). + * + * Returns: + * 0 on success or error code otherwise */ int amdgpu_irq_add_domain(struct amdgpu_device *adev) { @@ -539,11 +614,11 @@ int amdgpu_irq_add_domain(struct amdgpu_device *adev) } /** - * amdgpu_irq_remove_domain - remove the irq domain + * amdgpu_irq_remove_domain - remove the IRQ domain * * @adev: amdgpu device pointer * - * Remove the irq domain for GPU interrupt sources + * Removes the IRQ domain for GPU interrupt sources * that may be driven by another driver (e.g., ACP). */ void amdgpu_irq_remove_domain(struct amdgpu_device *adev) @@ -555,16 +630,17 @@ void amdgpu_irq_remove_domain(struct amdgpu_device *adev) } /** - * amdgpu_irq_create_mapping - create a mapping between a domain irq and a - * Linux irq + * amdgpu_irq_create_mapping - create mapping between domain Linux IRQs * * @adev: amdgpu device pointer * @src_id: IH source id * - * Create a mapping between a domain irq (GPU IH src id) and a Linux irq + * Creates mapping between a domain IRQ (GPU IH src id) and a Linux IRQ * Use this for components that generate a GPU interrupt, but are driven * by a different driver (e.g., ACP). - * Returns the Linux irq. + * + * Returns: + * Linux IRQ */ unsigned amdgpu_irq_create_mapping(struct amdgpu_device *adev, unsigned src_id) { -- GitLab From c8c5e569c5b0c9ad523c35497af2ae5788a29581 Mon Sep 17 00:00:00 2001 From: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Date: Tue, 12 Jun 2018 14:28:20 -0400 Subject: [PATCH 0373/1506] drm/amdgpu: Consolidate visible vs. real vram check v2. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move all instnaces of this check into a function in amdgpu_gmc.h Rename the original function to a more proper name. v2: Add more places to cleanup. Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 11 ++++++----- drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h | 15 +++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 20 ++++---------------- 5 files changed, 27 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 82312a7bc6ad5..7a625f3989a00 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -31,6 +31,7 @@ #include <drm/drm_syncobj.h> #include "amdgpu.h" #include "amdgpu_trace.h" +#include "amdgpu_gmc.h" static int amdgpu_cs_user_fence_chunk(struct amdgpu_cs_parser *p, struct drm_amdgpu_cs_chunk_fence *data, @@ -302,7 +303,7 @@ static void amdgpu_cs_get_threshold_for_moves(struct amdgpu_device *adev, *max_bytes = us_to_bytes(adev, adev->mm_stats.accum_us); /* Do the same for visible VRAM if half of it is free */ - if (adev->gmc.visible_vram_size < adev->gmc.real_vram_size) { + if (!amdgpu_gmc_vram_full_visible(&adev->gmc)) { u64 total_vis_vram = adev->gmc.visible_vram_size; u64 used_vis_vram = amdgpu_vram_mgr_vis_usage(&adev->mman.bdev.man[TTM_PL_VRAM]); @@ -359,7 +360,7 @@ static int amdgpu_cs_bo_validate(struct amdgpu_cs_parser *p, * to move it. Don't move anything if the threshold is zero. */ if (p->bytes_moved < p->bytes_moved_threshold) { - if (adev->gmc.visible_vram_size < adev->gmc.real_vram_size && + if (!amdgpu_gmc_vram_full_visible(&adev->gmc) && (bo->flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED)) { /* And don't move a CPU_ACCESS_REQUIRED BO to limited * visible VRAM if we've depleted our allowance to do @@ -381,7 +382,7 @@ static int amdgpu_cs_bo_validate(struct amdgpu_cs_parser *p, r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); p->bytes_moved += ctx.bytes_moved; - if (adev->gmc.visible_vram_size < adev->gmc.real_vram_size && + if (!amdgpu_gmc_vram_full_visible(&adev->gmc) && amdgpu_bo_in_cpu_visible_vram(bo)) p->bytes_moved_vis += ctx.bytes_moved; @@ -434,8 +435,8 @@ static bool amdgpu_cs_try_evict(struct amdgpu_cs_parser *p, /* Good we can try to move this BO somewhere else */ update_bytes_moved_vis = - adev->gmc.visible_vram_size < adev->gmc.real_vram_size && - amdgpu_bo_in_cpu_visible_vram(bo); + !amdgpu_gmc_vram_full_visible(&adev->gmc) && + amdgpu_bo_in_cpu_visible_vram(bo); amdgpu_ttm_placement_from_domain(bo, other); r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); p->bytes_moved += ctx.bytes_moved; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h index 893c2490b7836..6cb4948233cbe 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h @@ -109,4 +109,19 @@ struct amdgpu_gmc { const struct amdgpu_gmc_funcs *gmc_funcs; }; +/** + * amdgpu_gmc_vram_full_visible - Check if full VRAM is visible through the BAR + * + * @adev: amdgpu_device pointer + * + * Returns: + * True if full VRAM is visible through the BAR + */ +static inline bool amdgpu_gmc_vram_full_visible(struct amdgpu_gmc *gmc) +{ + WARN_ON(gmc->real_vram_size < gmc->visible_vram_size); + + return (gmc->real_vram_size == gmc->visible_vram_size); +} + #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 987a9fa33d359..f5b0b180a6ccd 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -463,7 +463,7 @@ static int amdgpu_bo_do_create(struct amdgpu_device *adev, if (unlikely(r != 0)) return r; - if (adev->gmc.visible_vram_size < adev->gmc.real_vram_size && + if (!amdgpu_gmc_vram_full_visible(&adev->gmc) && bo->tbo.mem.mem_type == TTM_PL_VRAM && bo->tbo.mem.start < adev->gmc.visible_vram_size >> PAGE_SHIFT) amdgpu_cs_report_moved_bytes(adev, ctx.bytes_moved, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index e93a0a237dc3e..0c084d3d08652 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -277,7 +277,7 @@ static void amdgpu_evict_flags(struct ttm_buffer_object *bo, if (!adev->mman.buffer_funcs_enabled) { /* Move to system memory */ amdgpu_ttm_placement_from_domain(abo, AMDGPU_GEM_DOMAIN_CPU); - } else if (adev->gmc.visible_vram_size < adev->gmc.real_vram_size && + } else if (!amdgpu_gmc_vram_full_visible(&adev->gmc) && !(abo->flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED) && amdgpu_bo_in_cpu_visible_vram(abo)) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 7f03f8c387085..6d2294203bd7b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -33,6 +33,7 @@ #include "amdgpu.h" #include "amdgpu_trace.h" #include "amdgpu_amdkfd.h" +#include "amdgpu_gmc.h" /** * DOC: GPUVM @@ -668,19 +669,6 @@ bool amdgpu_vm_need_pipeline_sync(struct amdgpu_ring *ring, return vm_flush_needed || gds_switch_needed; } -/** - * amdgpu_vm_is_large_bar - Check if BAR is large enough - * - * @adev: amdgpu_device pointer - * - * Returns: - * True if BAR is large enough. - */ -static bool amdgpu_vm_is_large_bar(struct amdgpu_device *adev) -{ - return (adev->gmc.real_vram_size == adev->gmc.visible_vram_size); -} - /** * amdgpu_vm_flush - hardware flush the vm * @@ -2579,7 +2567,7 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm, } DRM_DEBUG_DRIVER("VM update mode is %s\n", vm->use_cpu_for_update ? "CPU" : "SDMA"); - WARN_ONCE((vm->use_cpu_for_update & !amdgpu_vm_is_large_bar(adev)), + WARN_ONCE((vm->use_cpu_for_update & !amdgpu_gmc_vram_full_visible(&adev->gmc)), "CPU update of VM recommended only for large BAR system\n"); vm->last_update = NULL; @@ -2699,7 +2687,7 @@ int amdgpu_vm_make_compute(struct amdgpu_device *adev, struct amdgpu_vm *vm) vm->pte_support_ats = pte_support_ats; DRM_DEBUG_DRIVER("VM update mode is %s\n", vm->use_cpu_for_update ? "CPU" : "SDMA"); - WARN_ONCE((vm->use_cpu_for_update & !amdgpu_vm_is_large_bar(adev)), + WARN_ONCE((vm->use_cpu_for_update & !amdgpu_gmc_vram_full_visible(&adev->gmc)), "CPU update of VM recommended only for large BAR system\n"); if (vm->pasid) { @@ -2877,7 +2865,7 @@ void amdgpu_vm_manager_init(struct amdgpu_device *adev) */ #ifdef CONFIG_X86_64 if (amdgpu_vm_update_mode == -1) { - if (amdgpu_vm_is_large_bar(adev)) + if (amdgpu_gmc_vram_full_visible(&adev->gmc)) adev->vm_manager.vm_update_mode = AMDGPU_VM_USE_CPU_FOR_COMPUTE; else -- GitLab From dc85db256d47062955145264df5923f03b85b0c6 Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexander.deucher@amd.com> Date: Fri, 1 Jun 2018 12:28:14 -0500 Subject: [PATCH 0374/1506] drm/doc: Add amdgpu hwmon/power documentation (v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document the hwmon and power control interfaces exposed by the amdgpu driver. v2: use section rather than chapter for now Reviewed-by: Michel Dänzer <michel.daenzer@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- Documentation/gpu/amdgpu.rst | 53 ++++++++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | 45 ++++++++++++++++++---- 2 files changed, 90 insertions(+), 8 deletions(-) diff --git a/Documentation/gpu/amdgpu.rst b/Documentation/gpu/amdgpu.rst index abf87360ab154..e1656fe8f2474 100644 --- a/Documentation/gpu/amdgpu.rst +++ b/Documentation/gpu/amdgpu.rst @@ -61,3 +61,56 @@ Interrupt Handling .. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c :internal: + +GPU Power/Thermal Controls and Monitoring +========================================= + +This section covers hwmon and power/thermal controls. + +HWMON Interfaces +---------------- + +.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c + :doc: hwmon + +GPU sysfs Power State Interfaces +-------------------------------- + +GPU power controls are exposed via sysfs files. + +power_dpm_state +~~~~~~~~~~~~~~~ + +.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c + :doc: power_dpm_state + +power_dpm_force_performance_level +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c + :doc: power_dpm_force_performance_level + +pp_table +~~~~~~~~ + +.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c + :doc: pp_table + +pp_od_clk_voltage +~~~~~~~~~~~~~~~~~ + +.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c + :doc: pp_od_clk_voltage + +pp_dpm_sclk pp_dpm_mclk pp_dpm_pcie +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c + :doc: pp_dpm_sclk pp_dpm_mclk pp_dpm_pcie + +pp_power_profile_mode +~~~~~~~~~~~~~~~~~~~~~ + +.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c + :doc: pp_power_profile_mode + diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c index b455da4877829..f667cb9eb614c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c @@ -80,12 +80,15 @@ void amdgpu_pm_acpi_event_handler(struct amdgpu_device *adev) /** * DOC: power_dpm_state * - * This is a legacy interface and is only provided for backwards compatibility. - * The amdgpu driver provides a sysfs API for adjusting certain power - * related parameters. The file power_dpm_state is used for this. + * The power_dpm_state file is a legacy interface and is only provided for + * backwards compatibility. The amdgpu driver provides a sysfs API for adjusting + * certain power related parameters. The file power_dpm_state is used for this. * It accepts the following arguments: + * * - battery + * * - balanced + * * - performance * * battery @@ -169,14 +172,21 @@ static ssize_t amdgpu_set_dpm_state(struct device *dev, * The amdgpu driver provides a sysfs API for adjusting certain power * related parameters. The file power_dpm_force_performance_level is * used for this. It accepts the following arguments: + * * - auto + * * - low + * * - high + * * - manual - * - GPU fan + * * - profile_standard + * * - profile_min_sclk + * * - profile_min_mclk + * * - profile_peak * * auto @@ -463,8 +473,11 @@ static ssize_t amdgpu_set_pp_table(struct device *dev, * this. * * Reading the file will display: + * * - a list of engine clock levels and voltages labeled OD_SCLK + * * - a list of memory clock levels and voltages labeled OD_MCLK + * * - a list of valid ranges for sclk, mclk, and voltage labeled OD_RANGE * * To manually adjust these settings, first select manual using @@ -1285,35 +1298,51 @@ static ssize_t amdgpu_hwmon_set_power_cap(struct device *dev, * DOC: hwmon * * The amdgpu driver exposes the following sensor interfaces: + * * - GPU temperature (via the on-die sensor) + * * - GPU voltage + * * - Northbridge voltage (APUs only) + * * - GPU power + * * - GPU fan * * hwmon interfaces for GPU temperature: + * * - temp1_input: the on die GPU temperature in millidegrees Celsius + * * - temp1_crit: temperature critical max value in millidegrees Celsius + * * - temp1_crit_hyst: temperature hysteresis for critical limit in millidegrees Celsius * * hwmon interfaces for GPU voltage: + * * - in0_input: the voltage on the GPU in millivolts + * * - in1_input: the voltage on the Northbridge in millivolts * * hwmon interfaces for GPU power: + * * - power1_average: average power used by the GPU in microWatts + * * - power1_cap_min: minimum cap supported in microWatts + * * - power1_cap_max: maximum cap supported in microWatts + * * - power1_cap: selected power cap in microWatts * * hwmon interfaces for GPU fan: + * * - pwm1: pulse width modulation fan level (0-255) - * - pwm1_enable: pulse width modulation fan control method - * 0: no fan speed control - * 1: manual fan speed control using pwm interface - * 2: automatic fan speed control + * + * - pwm1_enable: pulse width modulation fan control method (0: no fan speed control, 1: manual fan speed control using pwm interface, 2: automatic fan speed control) + * * - pwm1_min: pulse width modulation fan control minimum level (0) + * * - pwm1_max: pulse width modulation fan control maximum level (255) + * * - fan1_input: fan speed in RPM * * You can use hwmon tools like sensors to view this information on your system. -- GitLab From c5792d7776e61737af200bf6f0d15354b5a3d205 Mon Sep 17 00:00:00 2001 From: Rex Zhu <Rex.Zhu@amd.com> Date: Mon, 4 Jun 2018 13:33:14 +0800 Subject: [PATCH 0375/1506] drm/amd/pp: Remove SAMU support in powerplay As the SAMU ip was not supported in linux, so delete the SAMU support in powerplay on asics Bonarire/Hawwii/Tonga/Fiji/Polaris/vegam. Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../powerplay/hwmgr/smu7_clockpowergating.c | 54 ------------ .../powerplay/hwmgr/smu7_clockpowergating.h | 1 - .../gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c | 1 - .../gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.h | 1 - .../drm/amd/powerplay/hwmgr/vega10_hwmgr.h | 1 - drivers/gpu/drm/amd/powerplay/inc/smumgr.h | 2 - .../gpu/drm/amd/powerplay/smumgr/ci_smumgr.c | 35 -------- .../drm/amd/powerplay/smumgr/fiji_smumgr.c | 74 ---------------- .../drm/amd/powerplay/smumgr/iceland_smumgr.c | 10 --- .../amd/powerplay/smumgr/polaris10_smumgr.c | 86 ------------------- .../drm/amd/powerplay/smumgr/tonga_smumgr.c | 80 ----------------- .../drm/amd/powerplay/smumgr/vegam_smumgr.c | 85 ------------------ 12 files changed, 430 deletions(-) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.c index 6d72a5600917c..41495621d94a0 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.c @@ -39,13 +39,6 @@ static int smu7_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable) PPSMC_MSG_VCEDPM_Disable); } -static int smu7_enable_disable_samu_dpm(struct pp_hwmgr *hwmgr, bool enable) -{ - return smum_send_msg_to_smc(hwmgr, enable ? - PPSMC_MSG_SAMUDPM_Enable : - PPSMC_MSG_SAMUDPM_Disable); -} - static int smu7_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate) { if (!bgate) @@ -60,13 +53,6 @@ static int smu7_update_vce_dpm(struct pp_hwmgr *hwmgr, bool bgate) return smu7_enable_disable_vce_dpm(hwmgr, !bgate); } -static int smu7_update_samu_dpm(struct pp_hwmgr *hwmgr, bool bgate) -{ - if (!bgate) - smum_update_smc_table(hwmgr, SMU_SAMU_TABLE); - return smu7_enable_disable_samu_dpm(hwmgr, !bgate); -} - int smu7_powerdown_uvd(struct pp_hwmgr *hwmgr) { if (phm_cf_want_uvd_power_gating(hwmgr)) @@ -107,35 +93,15 @@ static int smu7_powerup_vce(struct pp_hwmgr *hwmgr) return 0; } -static int smu7_powerdown_samu(struct pp_hwmgr *hwmgr) -{ - if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, - PHM_PlatformCaps_SamuPowerGating)) - return smum_send_msg_to_smc(hwmgr, - PPSMC_MSG_SAMPowerOFF); - return 0; -} - -static int smu7_powerup_samu(struct pp_hwmgr *hwmgr) -{ - if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, - PHM_PlatformCaps_SamuPowerGating)) - return smum_send_msg_to_smc(hwmgr, - PPSMC_MSG_SAMPowerON); - return 0; -} - int smu7_disable_clock_power_gating(struct pp_hwmgr *hwmgr) { struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); data->uvd_power_gated = false; data->vce_power_gated = false; - data->samu_power_gated = false; smu7_powerup_uvd(hwmgr); smu7_powerup_vce(hwmgr); - smu7_powerup_samu(hwmgr); return 0; } @@ -195,26 +161,6 @@ void smu7_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate) } } -int smu7_powergate_samu(struct pp_hwmgr *hwmgr, bool bgate) -{ - struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); - - if (data->samu_power_gated == bgate) - return 0; - - data->samu_power_gated = bgate; - - if (bgate) { - smu7_update_samu_dpm(hwmgr, true); - smu7_powerdown_samu(hwmgr); - } else { - smu7_powerup_samu(hwmgr); - smu7_update_samu_dpm(hwmgr, false); - } - - return 0; -} - int smu7_update_clock_gatings(struct pp_hwmgr *hwmgr, const uint32_t *msg_id) { diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.h b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.h index 1ddce023218ac..be7f66d2b234a 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.h +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.h @@ -29,7 +29,6 @@ void smu7_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate); void smu7_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate); int smu7_powerdown_uvd(struct pp_hwmgr *hwmgr); -int smu7_powergate_samu(struct pp_hwmgr *hwmgr, bool bgate); int smu7_powergate_acp(struct pp_hwmgr *hwmgr, bool bgate); int smu7_disable_clock_power_gating(struct pp_hwmgr *hwmgr); int smu7_update_clock_gatings(struct pp_hwmgr *hwmgr, diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c index fdb20db9c147f..24d20d9c74b4a 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c @@ -4300,7 +4300,6 @@ static int smu7_init_power_gate_state(struct pp_hwmgr *hwmgr) data->uvd_power_gated = false; data->vce_power_gated = false; - data->samu_power_gated = false; return 0; } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.h b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.h index c91e75db6a8e5..3784ce6e50ab4 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.h @@ -310,7 +310,6 @@ struct smu7_hwmgr { /* ---- Power Gating States ---- */ bool uvd_power_gated; bool vce_power_gated; - bool samu_power_gated; bool need_long_memory_training; /* Application power optimization parameters */ diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.h b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.h index aadd6cbc7e85d..339820da9e6a8 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.h @@ -370,7 +370,6 @@ struct vega10_hwmgr { /* ---- Power Gating States ---- */ bool uvd_power_gated; bool vce_power_gated; - bool samu_power_gated; bool need_long_memory_training; /* Internal settings to apply the application power optimization parameters */ diff --git a/drivers/gpu/drm/amd/powerplay/inc/smumgr.h b/drivers/gpu/drm/amd/powerplay/inc/smumgr.h index 6c22ed9249bfa..89dfbf53c7e6a 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smumgr.h +++ b/drivers/gpu/drm/amd/powerplay/inc/smumgr.h @@ -29,7 +29,6 @@ enum SMU_TABLE { SMU_UVD_TABLE = 0, SMU_VCE_TABLE, - SMU_SAMU_TABLE, SMU_BIF_TABLE, }; @@ -47,7 +46,6 @@ enum SMU_MEMBER { UcodeLoadStatus, UvdBootLevel, VceBootLevel, - SamuBootLevel, LowSclkInterruptThreshold, DRAM_LOG_ADDR_H, DRAM_LOG_ADDR_L, diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c index 2d4ec8ac3a088..8cd21ac6cedac 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c @@ -1614,37 +1614,6 @@ static int ci_populate_smc_acp_level(struct pp_hwmgr *hwmgr, return result; } -static int ci_populate_smc_samu_level(struct pp_hwmgr *hwmgr, - SMU7_Discrete_DpmTable *table) -{ - int result = -EINVAL; - uint8_t count; - struct pp_atomctrl_clock_dividers_vi dividers; - struct phm_samu_clock_voltage_dependency_table *samu_table = - hwmgr->dyn_state.samu_clock_voltage_dependency_table; - - table->SamuBootLevel = 0; - table->SamuLevelCount = (uint8_t)(samu_table->count); - - for (count = 0; count < table->SamuLevelCount; count++) { - table->SamuLevel[count].Frequency = samu_table->entries[count].samclk; - table->SamuLevel[count].MinVoltage = samu_table->entries[count].v * VOLTAGE_SCALE; - table->SamuLevel[count].MinPhases = 1; - - /* retrieve divider value for VBIOS */ - result = atomctrl_get_dfs_pll_dividers_vi(hwmgr, - table->SamuLevel[count].Frequency, ÷rs); - PP_ASSERT_WITH_CODE((0 == result), - "can not find divide id for samu clock", return result); - - table->SamuLevel[count].Divider = (uint8_t)dividers.pll_post_divider; - - CONVERT_FROM_HOST_TO_SMC_UL(table->SamuLevel[count].Frequency); - CONVERT_FROM_HOST_TO_SMC_US(table->SamuLevel[count].MinVoltage); - } - return result; -} - static int ci_populate_memory_timing_parameters( struct pp_hwmgr *hwmgr, uint32_t engine_clock, @@ -2026,10 +1995,6 @@ static int ci_init_smc_table(struct pp_hwmgr *hwmgr) PP_ASSERT_WITH_CODE(0 == result, "Failed to initialize ACP Level!", return result); - result = ci_populate_smc_samu_level(hwmgr, table); - PP_ASSERT_WITH_CODE(0 == result, - "Failed to initialize SAMU Level!", return result); - /* Since only the initial state is completely set up at this point (the other states are just copies of the boot state) we only */ /* need to populate the ARB settings for the initial state. */ result = ci_program_memory_timing_parameters(hwmgr); diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c index 53df9405f43a3..18048f8e2f130 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c @@ -1503,44 +1503,6 @@ static int fiji_populate_smc_acp_level(struct pp_hwmgr *hwmgr, return result; } -static int fiji_populate_smc_samu_level(struct pp_hwmgr *hwmgr, - SMU73_Discrete_DpmTable *table) -{ - int result = -EINVAL; - uint8_t count; - struct pp_atomctrl_clock_dividers_vi dividers; - struct phm_ppt_v1_information *table_info = - (struct phm_ppt_v1_information *)(hwmgr->pptable); - struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table = - table_info->mm_dep_table; - - table->SamuBootLevel = 0; - table->SamuLevelCount = (uint8_t)(mm_table->count); - - for (count = 0; count < table->SamuLevelCount; count++) { - /* not sure whether we need evclk or not */ - table->SamuLevel[count].MinVoltage = 0; - table->SamuLevel[count].Frequency = mm_table->entries[count].samclock; - table->SamuLevel[count].MinVoltage |= (mm_table->entries[count].vddc * - VOLTAGE_SCALE) << VDDC_SHIFT; - table->SamuLevel[count].MinVoltage |= ((mm_table->entries[count].vddc - - VDDC_VDDCI_DELTA) * VOLTAGE_SCALE) << VDDCI_SHIFT; - table->SamuLevel[count].MinVoltage |= 1 << PHASES_SHIFT; - - /* retrieve divider value for VBIOS */ - result = atomctrl_get_dfs_pll_dividers_vi(hwmgr, - table->SamuLevel[count].Frequency, ÷rs); - PP_ASSERT_WITH_CODE((0 == result), - "can not find divide id for samu clock", return result); - - table->SamuLevel[count].Divider = (uint8_t)dividers.pll_post_divider; - - CONVERT_FROM_HOST_TO_SMC_UL(table->SamuLevel[count].Frequency); - CONVERT_FROM_HOST_TO_SMC_UL(table->SamuLevel[count].MinVoltage); - } - return result; -} - static int fiji_populate_memory_timing_parameters(struct pp_hwmgr *hwmgr, int32_t eng_clock, int32_t mem_clock, struct SMU73_Discrete_MCArbDramTimingTableEntry *arb_regs) @@ -2028,10 +1990,6 @@ static int fiji_init_smc_table(struct pp_hwmgr *hwmgr) PP_ASSERT_WITH_CODE(0 == result, "Failed to initialize ACP Level!", return result); - result = fiji_populate_smc_samu_level(hwmgr, table); - PP_ASSERT_WITH_CODE(0 == result, - "Failed to initialize SAMU Level!", return result); - /* Since only the initial state is completely set up at this point * (the other states are just copies of the boot state) we only * need to populate the ARB settings for the initial state. @@ -2378,8 +2336,6 @@ static uint32_t fiji_get_offsetof(uint32_t type, uint32_t member) return offsetof(SMU73_Discrete_DpmTable, UvdBootLevel); case VceBootLevel: return offsetof(SMU73_Discrete_DpmTable, VceBootLevel); - case SamuBootLevel: - return offsetof(SMU73_Discrete_DpmTable, SamuBootLevel); case LowSclkInterruptThreshold: return offsetof(SMU73_Discrete_DpmTable, LowSclkInterruptThreshold); } @@ -2478,33 +2434,6 @@ static int fiji_update_vce_smc_table(struct pp_hwmgr *hwmgr) return 0; } -static int fiji_update_samu_smc_table(struct pp_hwmgr *hwmgr) -{ - struct fiji_smumgr *smu_data = (struct fiji_smumgr *)(hwmgr->smu_backend); - uint32_t mm_boot_level_offset, mm_boot_level_value; - - - smu_data->smc_state_table.SamuBootLevel = 0; - mm_boot_level_offset = smu_data->smu7_data.dpm_table_start + - offsetof(SMU73_Discrete_DpmTable, SamuBootLevel); - - mm_boot_level_offset /= 4; - mm_boot_level_offset *= 4; - mm_boot_level_value = cgs_read_ind_register(hwmgr->device, - CGS_IND_REG__SMC, mm_boot_level_offset); - mm_boot_level_value &= 0xFFFFFF00; - mm_boot_level_value |= smu_data->smc_state_table.SamuBootLevel << 0; - cgs_write_ind_register(hwmgr->device, - CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value); - - if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, - PHM_PlatformCaps_StablePState)) - smum_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_SAMUDPM_SetEnabledMask, - (uint32_t)(1 << smu_data->smc_state_table.SamuBootLevel)); - return 0; -} - static int fiji_update_smc_table(struct pp_hwmgr *hwmgr, uint32_t type) { switch (type) { @@ -2514,9 +2443,6 @@ static int fiji_update_smc_table(struct pp_hwmgr *hwmgr, uint32_t type) case SMU_VCE_TABLE: fiji_update_vce_smc_table(hwmgr); break; - case SMU_SAMU_TABLE: - fiji_update_samu_smc_table(hwmgr); - break; default: break; } diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.c index 415f691c3fa90..9299b93aa09af 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.c @@ -1578,12 +1578,6 @@ static int iceland_populate_smc_acp_level(struct pp_hwmgr *hwmgr, return 0; } -static int iceland_populate_smc_samu_level(struct pp_hwmgr *hwmgr, - SMU71_Discrete_DpmTable *table) -{ - return 0; -} - static int iceland_populate_memory_timing_parameters( struct pp_hwmgr *hwmgr, uint32_t engine_clock, @@ -1992,10 +1986,6 @@ static int iceland_init_smc_table(struct pp_hwmgr *hwmgr) PP_ASSERT_WITH_CODE(0 == result, "Failed to initialize ACP Level!", return result;); - result = iceland_populate_smc_samu_level(hwmgr, table); - PP_ASSERT_WITH_CODE(0 == result, - "Failed to initialize SAMU Level!", return result;); - /* Since only the initial state is completely set up at this point (the other states are just copies of the boot state) we only */ /* need to populate the ARB settings for the initial state. */ result = iceland_program_memory_timing_parameters(hwmgr); diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c index a8c6524f07e40..a4ce199af4758 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c @@ -1337,55 +1337,6 @@ static int polaris10_populate_smc_vce_level(struct pp_hwmgr *hwmgr, return result; } - -static int polaris10_populate_smc_samu_level(struct pp_hwmgr *hwmgr, - SMU74_Discrete_DpmTable *table) -{ - int result = -EINVAL; - uint8_t count; - struct pp_atomctrl_clock_dividers_vi dividers; - struct phm_ppt_v1_information *table_info = - (struct phm_ppt_v1_information *)(hwmgr->pptable); - struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table = - table_info->mm_dep_table; - struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); - uint32_t vddci; - - table->SamuBootLevel = 0; - table->SamuLevelCount = (uint8_t)(mm_table->count); - - for (count = 0; count < table->SamuLevelCount; count++) { - /* not sure whether we need evclk or not */ - table->SamuLevel[count].MinVoltage = 0; - table->SamuLevel[count].Frequency = mm_table->entries[count].samclock; - table->SamuLevel[count].MinVoltage |= (mm_table->entries[count].vddc * - VOLTAGE_SCALE) << VDDC_SHIFT; - - if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control) - vddci = (uint32_t)phm_find_closest_vddci(&(data->vddci_voltage_table), - mm_table->entries[count].vddc - VDDC_VDDCI_DELTA); - else if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->vddci_control) - vddci = mm_table->entries[count].vddc - VDDC_VDDCI_DELTA; - else - vddci = (data->vbios_boot_state.vddci_bootup_value * VOLTAGE_SCALE) << VDDCI_SHIFT; - - table->SamuLevel[count].MinVoltage |= (vddci * VOLTAGE_SCALE) << VDDCI_SHIFT; - table->SamuLevel[count].MinVoltage |= 1 << PHASES_SHIFT; - - /* retrieve divider value for VBIOS */ - result = atomctrl_get_dfs_pll_dividers_vi(hwmgr, - table->SamuLevel[count].Frequency, ÷rs); - PP_ASSERT_WITH_CODE((0 == result), - "can not find divide id for samu clock", return result); - - table->SamuLevel[count].Divider = (uint8_t)dividers.pll_post_divider; - - CONVERT_FROM_HOST_TO_SMC_UL(table->SamuLevel[count].Frequency); - CONVERT_FROM_HOST_TO_SMC_UL(table->SamuLevel[count].MinVoltage); - } - return result; -} - static int polaris10_populate_memory_timing_parameters(struct pp_hwmgr *hwmgr, int32_t eng_clock, int32_t mem_clock, SMU74_Discrete_MCArbDramTimingTableEntry *arb_regs) @@ -1865,10 +1816,6 @@ static int polaris10_init_smc_table(struct pp_hwmgr *hwmgr) PP_ASSERT_WITH_CODE(0 == result, "Failed to initialize VCE Level!", return result); - result = polaris10_populate_smc_samu_level(hwmgr, table); - PP_ASSERT_WITH_CODE(0 == result, - "Failed to initialize SAMU Level!", return result); - /* Since only the initial state is completely set up at this point * (the other states are just copies of the boot state) we only * need to populate the ARB settings for the initial state. @@ -2222,34 +2169,6 @@ static int polaris10_update_vce_smc_table(struct pp_hwmgr *hwmgr) return 0; } -static int polaris10_update_samu_smc_table(struct pp_hwmgr *hwmgr) -{ - struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(hwmgr->smu_backend); - uint32_t mm_boot_level_offset, mm_boot_level_value; - - - smu_data->smc_state_table.SamuBootLevel = 0; - mm_boot_level_offset = smu_data->smu7_data.dpm_table_start + - offsetof(SMU74_Discrete_DpmTable, SamuBootLevel); - - mm_boot_level_offset /= 4; - mm_boot_level_offset *= 4; - mm_boot_level_value = cgs_read_ind_register(hwmgr->device, - CGS_IND_REG__SMC, mm_boot_level_offset); - mm_boot_level_value &= 0xFFFFFF00; - mm_boot_level_value |= smu_data->smc_state_table.SamuBootLevel << 0; - cgs_write_ind_register(hwmgr->device, - CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value); - - if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, - PHM_PlatformCaps_StablePState)) - smum_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_SAMUDPM_SetEnabledMask, - (uint32_t)(1 << smu_data->smc_state_table.SamuBootLevel)); - return 0; -} - - static int polaris10_update_bif_smc_table(struct pp_hwmgr *hwmgr) { struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(hwmgr->smu_backend); @@ -2276,9 +2195,6 @@ static int polaris10_update_smc_table(struct pp_hwmgr *hwmgr, uint32_t type) case SMU_VCE_TABLE: polaris10_update_vce_smc_table(hwmgr); break; - case SMU_SAMU_TABLE: - polaris10_update_samu_smc_table(hwmgr); - break; case SMU_BIF_TABLE: polaris10_update_bif_smc_table(hwmgr); default: @@ -2357,8 +2273,6 @@ static uint32_t polaris10_get_offsetof(uint32_t type, uint32_t member) return offsetof(SMU74_Discrete_DpmTable, UvdBootLevel); case VceBootLevel: return offsetof(SMU74_Discrete_DpmTable, VceBootLevel); - case SamuBootLevel: - return offsetof(SMU74_Discrete_DpmTable, SamuBootLevel); case LowSclkInterruptThreshold: return offsetof(SMU74_Discrete_DpmTable, LowSclkInterruptThreshold); } diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c index 782b19fc2e701..7dabc6c456e12 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c @@ -1443,51 +1443,6 @@ static int tonga_populate_smc_acp_level(struct pp_hwmgr *hwmgr, return result; } -static int tonga_populate_smc_samu_level(struct pp_hwmgr *hwmgr, - SMU72_Discrete_DpmTable *table) -{ - int result = 0; - uint8_t count; - pp_atomctrl_clock_dividers_vi dividers; - struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); - struct phm_ppt_v1_information *pptable_info = - (struct phm_ppt_v1_information *)(hwmgr->pptable); - phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table = - pptable_info->mm_dep_table; - - table->SamuBootLevel = 0; - table->SamuLevelCount = (uint8_t) (mm_table->count); - - for (count = 0; count < table->SamuLevelCount; count++) { - /* not sure whether we need evclk or not */ - table->SamuLevel[count].Frequency = - pptable_info->mm_dep_table->entries[count].samclock; - table->SamuLevel[count].MinVoltage.Vddc = - phm_get_voltage_index(pptable_info->vddc_lookup_table, - mm_table->entries[count].vddc); - table->SamuLevel[count].MinVoltage.VddGfx = - (data->vdd_gfx_control == SMU7_VOLTAGE_CONTROL_BY_SVID2) ? - phm_get_voltage_index(pptable_info->vddgfx_lookup_table, - mm_table->entries[count].vddgfx) : 0; - table->SamuLevel[count].MinVoltage.Vddci = - phm_get_voltage_id(&data->vddci_voltage_table, - mm_table->entries[count].vddc - VDDC_VDDCI_DELTA); - table->SamuLevel[count].MinVoltage.Phases = 1; - - /* retrieve divider value for VBIOS */ - result = atomctrl_get_dfs_pll_dividers_vi(hwmgr, - table->SamuLevel[count].Frequency, ÷rs); - PP_ASSERT_WITH_CODE((!result), - "can not find divide id for samu clock", return result); - - table->SamuLevel[count].Divider = (uint8_t)dividers.pll_post_divider; - - CONVERT_FROM_HOST_TO_SMC_UL(table->SamuLevel[count].Frequency); - } - - return result; -} - static int tonga_populate_memory_timing_parameters( struct pp_hwmgr *hwmgr, uint32_t engine_clock, @@ -2323,10 +2278,6 @@ static int tonga_init_smc_table(struct pp_hwmgr *hwmgr) PP_ASSERT_WITH_CODE(!result, "Failed to initialize ACP Level !", return result); - result = tonga_populate_smc_samu_level(hwmgr, table); - PP_ASSERT_WITH_CODE(!result, - "Failed to initialize SAMU Level !", return result); - /* Since only the initial state is completely set up at this * point (the other states are just copies of the boot state) we only * need to populate the ARB settings for the initial state. @@ -2673,8 +2624,6 @@ static uint32_t tonga_get_offsetof(uint32_t type, uint32_t member) return offsetof(SMU72_Discrete_DpmTable, UvdBootLevel); case VceBootLevel: return offsetof(SMU72_Discrete_DpmTable, VceBootLevel); - case SamuBootLevel: - return offsetof(SMU72_Discrete_DpmTable, SamuBootLevel); case LowSclkInterruptThreshold: return offsetof(SMU72_Discrete_DpmTable, LowSclkInterruptThreshold); } @@ -2773,32 +2722,6 @@ static int tonga_update_vce_smc_table(struct pp_hwmgr *hwmgr) return 0; } -static int tonga_update_samu_smc_table(struct pp_hwmgr *hwmgr) -{ - struct tonga_smumgr *smu_data = (struct tonga_smumgr *)(hwmgr->smu_backend); - uint32_t mm_boot_level_offset, mm_boot_level_value; - - smu_data->smc_state_table.SamuBootLevel = 0; - mm_boot_level_offset = smu_data->smu7_data.dpm_table_start + - offsetof(SMU72_Discrete_DpmTable, SamuBootLevel); - - mm_boot_level_offset /= 4; - mm_boot_level_offset *= 4; - mm_boot_level_value = cgs_read_ind_register(hwmgr->device, - CGS_IND_REG__SMC, mm_boot_level_offset); - mm_boot_level_value &= 0xFFFFFF00; - mm_boot_level_value |= smu_data->smc_state_table.SamuBootLevel << 0; - cgs_write_ind_register(hwmgr->device, - CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value); - - if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, - PHM_PlatformCaps_StablePState)) - smum_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_SAMUDPM_SetEnabledMask, - (uint32_t)(1 << smu_data->smc_state_table.SamuBootLevel)); - return 0; -} - static int tonga_update_smc_table(struct pp_hwmgr *hwmgr, uint32_t type) { switch (type) { @@ -2808,9 +2731,6 @@ static int tonga_update_smc_table(struct pp_hwmgr *hwmgr, uint32_t type) case SMU_VCE_TABLE: tonga_update_vce_smc_table(hwmgr); break; - case SMU_SAMU_TABLE: - tonga_update_samu_smc_table(hwmgr); - break; default: break; } diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/vegam_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/vegam_smumgr.c index 2de48959ac935..57420d7caa4e9 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/vegam_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/vegam_smumgr.c @@ -393,34 +393,6 @@ static int vegam_update_vce_smc_table(struct pp_hwmgr *hwmgr) return 0; } -static int vegam_update_samu_smc_table(struct pp_hwmgr *hwmgr) -{ - struct vegam_smumgr *smu_data = (struct vegam_smumgr *)(hwmgr->smu_backend); - uint32_t mm_boot_level_offset, mm_boot_level_value; - - - smu_data->smc_state_table.SamuBootLevel = 0; - mm_boot_level_offset = smu_data->smu7_data.dpm_table_start + - offsetof(SMU75_Discrete_DpmTable, SamuBootLevel); - - mm_boot_level_offset /= 4; - mm_boot_level_offset *= 4; - mm_boot_level_value = cgs_read_ind_register(hwmgr->device, - CGS_IND_REG__SMC, mm_boot_level_offset); - mm_boot_level_value &= 0xFFFFFF00; - mm_boot_level_value |= smu_data->smc_state_table.SamuBootLevel << 0; - cgs_write_ind_register(hwmgr->device, - CGS_IND_REG__SMC, mm_boot_level_offset, mm_boot_level_value); - - if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, - PHM_PlatformCaps_StablePState)) - smum_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_SAMUDPM_SetEnabledMask, - (uint32_t)(1 << smu_data->smc_state_table.SamuBootLevel)); - return 0; -} - - static int vegam_update_bif_smc_table(struct pp_hwmgr *hwmgr) { struct vegam_smumgr *smu_data = (struct vegam_smumgr *)(hwmgr->smu_backend); @@ -447,9 +419,6 @@ static int vegam_update_smc_table(struct pp_hwmgr *hwmgr, uint32_t type) case SMU_VCE_TABLE: vegam_update_vce_smc_table(hwmgr); break; - case SMU_SAMU_TABLE: - vegam_update_samu_smc_table(hwmgr); - break; case SMU_BIF_TABLE: vegam_update_bif_smc_table(hwmgr); break; @@ -1281,54 +1250,6 @@ static int vegam_populate_smc_vce_level(struct pp_hwmgr *hwmgr, return result; } -static int vegam_populate_smc_samu_level(struct pp_hwmgr *hwmgr, - SMU75_Discrete_DpmTable *table) -{ - int result = -EINVAL; - uint8_t count; - struct pp_atomctrl_clock_dividers_vi dividers; - struct phm_ppt_v1_information *table_info = - (struct phm_ppt_v1_information *)(hwmgr->pptable); - struct phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table = - table_info->mm_dep_table; - struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); - uint32_t vddci; - - table->SamuBootLevel = 0; - table->SamuLevelCount = (uint8_t)(mm_table->count); - - for (count = 0; count < table->SamuLevelCount; count++) { - /* not sure whether we need evclk or not */ - table->SamuLevel[count].MinVoltage = 0; - table->SamuLevel[count].Frequency = mm_table->entries[count].samclock; - table->SamuLevel[count].MinVoltage |= (mm_table->entries[count].vddc * - VOLTAGE_SCALE) << VDDC_SHIFT; - - if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control) - vddci = (uint32_t)phm_find_closest_vddci(&(data->vddci_voltage_table), - mm_table->entries[count].vddc - VDDC_VDDCI_DELTA); - else if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->vddci_control) - vddci = mm_table->entries[count].vddc - VDDC_VDDCI_DELTA; - else - vddci = (data->vbios_boot_state.vddci_bootup_value * VOLTAGE_SCALE) << VDDCI_SHIFT; - - table->SamuLevel[count].MinVoltage |= (vddci * VOLTAGE_SCALE) << VDDCI_SHIFT; - table->SamuLevel[count].MinVoltage |= 1 << PHASES_SHIFT; - - /* retrieve divider value for VBIOS */ - result = atomctrl_get_dfs_pll_dividers_vi(hwmgr, - table->SamuLevel[count].Frequency, ÷rs); - PP_ASSERT_WITH_CODE((0 == result), - "can not find divide id for samu clock", return result); - - table->SamuLevel[count].Divider = (uint8_t)dividers.pll_post_divider; - - CONVERT_FROM_HOST_TO_SMC_UL(table->SamuLevel[count].Frequency); - CONVERT_FROM_HOST_TO_SMC_UL(table->SamuLevel[count].MinVoltage); - } - return result; -} - static int vegam_populate_memory_timing_parameters(struct pp_hwmgr *hwmgr, int32_t eng_clock, int32_t mem_clock, SMU75_Discrete_MCArbDramTimingTableEntry *arb_regs) @@ -2062,10 +1983,6 @@ static int vegam_init_smc_table(struct pp_hwmgr *hwmgr) PP_ASSERT_WITH_CODE(!result, "Failed to initialize VCE Level!", return result); - result = vegam_populate_smc_samu_level(hwmgr, table); - PP_ASSERT_WITH_CODE(!result, - "Failed to initialize SAMU Level!", return result); - /* Since only the initial state is completely set up at this point * (the other states are just copies of the boot state) we only * need to populate the ARB settings for the initial state. @@ -2273,8 +2190,6 @@ static uint32_t vegam_get_offsetof(uint32_t type, uint32_t member) return offsetof(SMU75_Discrete_DpmTable, UvdBootLevel); case VceBootLevel: return offsetof(SMU75_Discrete_DpmTable, VceBootLevel); - case SamuBootLevel: - return offsetof(SMU75_Discrete_DpmTable, SamuBootLevel); case LowSclkInterruptThreshold: return offsetof(SMU75_Discrete_DpmTable, LowSclkInterruptThreshold); } -- GitLab From 600ae890be59910e65b75fe25a1b900d83c0329c Mon Sep 17 00:00:00 2001 From: Rex Zhu <Rex.Zhu@amd.com> Date: Mon, 4 Jun 2018 16:39:38 +0800 Subject: [PATCH 0376/1506] drm/amdgpu: Use real power source in powerplay instand of hardcode 1. move ac_power to struct pm from dpm, so can be shared with powerplay 2. remove power_source in powerplay, use adev->pm.ac_power instand. 3. update ac_power before dispatch power task. Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | 21 +++++------ drivers/gpu/drm/amd/amdgpu/ci_dpm.c | 12 +++---- drivers/gpu/drm/amd/amdgpu/kv_dpm.c | 2 +- drivers/gpu/drm/amd/amdgpu/si_dpm.c | 4 +-- drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c | 1 - .../gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c | 6 ++-- .../drm/amd/powerplay/hwmgr/vega10_hwmgr.c | 5 +-- drivers/gpu/drm/amd/powerplay/inc/hwmgr.h | 2 -- .../drm/amd/powerplay/inc/pp_power_source.h | 36 ------------------- 10 files changed, 27 insertions(+), 64 deletions(-) delete mode 100644 drivers/gpu/drm/amd/powerplay/inc/pp_power_source.h diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h index dd6203a0a6b77..9acfbee91c40a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h @@ -402,7 +402,6 @@ struct amdgpu_dpm { u32 tdp_adjustment; u16 load_line_slope; bool power_control; - bool ac_power; /* special states active */ bool thermal_active; bool uvd_active; @@ -439,6 +438,7 @@ struct amdgpu_pm { struct amd_pp_display_configuration pm_display_cfg;/* set by dc */ uint32_t smu_prv_buffer_size; struct amdgpu_bo *smu_prv_buffer; + bool ac_power; }; #define R600_SSTU_DFLT 0 diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c index f667cb9eb614c..113edffb59601 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c @@ -68,11 +68,11 @@ void amdgpu_pm_acpi_event_handler(struct amdgpu_device *adev) if (adev->pm.dpm_enabled) { mutex_lock(&adev->pm.mutex); if (power_supply_is_system_supplied() > 0) - adev->pm.dpm.ac_power = true; + adev->pm.ac_power = true; else - adev->pm.dpm.ac_power = false; + adev->pm.ac_power = false; if (adev->powerplay.pp_funcs->enable_bapm) - amdgpu_dpm_enable_bapm(adev, adev->pm.dpm.ac_power); + amdgpu_dpm_enable_bapm(adev, adev->pm.ac_power); mutex_unlock(&adev->pm.mutex); } } @@ -1907,6 +1907,14 @@ void amdgpu_pm_compute_clocks(struct amdgpu_device *adev) amdgpu_fence_wait_empty(ring); } + mutex_lock(&adev->pm.mutex); + /* update battery/ac status */ + if (power_supply_is_system_supplied() > 0) + adev->pm.ac_power = true; + else + adev->pm.ac_power = false; + mutex_unlock(&adev->pm.mutex); + if (adev->powerplay.pp_funcs->dispatch_tasks) { if (!amdgpu_device_has_dc_support(adev)) { mutex_lock(&adev->pm.mutex); @@ -1927,14 +1935,7 @@ void amdgpu_pm_compute_clocks(struct amdgpu_device *adev) } else { mutex_lock(&adev->pm.mutex); amdgpu_dpm_get_active_displays(adev); - /* update battery/ac status */ - if (power_supply_is_system_supplied() > 0) - adev->pm.dpm.ac_power = true; - else - adev->pm.dpm.ac_power = false; - amdgpu_dpm_change_power_state_locked(adev); - mutex_unlock(&adev->pm.mutex); } } diff --git a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c index a266dcf5daed2..b6248c0578a16 100644 --- a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c @@ -951,12 +951,12 @@ static void ci_apply_state_adjust_rules(struct amdgpu_device *adev, else pi->battery_state = false; - if (adev->pm.dpm.ac_power) + if (adev->pm.ac_power) max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac; else max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc; - if (adev->pm.dpm.ac_power == false) { + if (adev->pm.ac_power == false) { for (i = 0; i < ps->performance_level_count; i++) { if (ps->performance_levels[i].mclk > max_limits->mclk) ps->performance_levels[i].mclk = max_limits->mclk; @@ -4078,7 +4078,7 @@ static int ci_enable_uvd_dpm(struct amdgpu_device *adev, bool enable) const struct amdgpu_clock_and_voltage_limits *max_limits; int i; - if (adev->pm.dpm.ac_power) + if (adev->pm.ac_power) max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac; else max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc; @@ -4127,7 +4127,7 @@ static int ci_enable_vce_dpm(struct amdgpu_device *adev, bool enable) const struct amdgpu_clock_and_voltage_limits *max_limits; int i; - if (adev->pm.dpm.ac_power) + if (adev->pm.ac_power) max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac; else max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc; @@ -4160,7 +4160,7 @@ static int ci_enable_samu_dpm(struct amdgpu_device *adev, bool enable) const struct amdgpu_clock_and_voltage_limits *max_limits; int i; - if (adev->pm.dpm.ac_power) + if (adev->pm.ac_power) max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac; else max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc; @@ -4191,7 +4191,7 @@ static int ci_enable_acp_dpm(struct amdgpu_device *adev, bool enable) const struct amdgpu_clock_and_voltage_limits *max_limits; int i; - if (adev->pm.dpm.ac_power) + if (adev->pm.ac_power) max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac; else max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc; diff --git a/drivers/gpu/drm/amd/amdgpu/kv_dpm.c b/drivers/gpu/drm/amd/amdgpu/kv_dpm.c index 17f7f074cedcc..d79e6f5234dad 100644 --- a/drivers/gpu/drm/amd/amdgpu/kv_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/kv_dpm.c @@ -1921,7 +1921,7 @@ static int kv_dpm_set_power_state(void *handle) int ret; if (pi->bapm_enable) { - ret = amdgpu_kv_smc_bapm_enable(adev, adev->pm.dpm.ac_power); + ret = amdgpu_kv_smc_bapm_enable(adev, adev->pm.ac_power); if (ret) { DRM_ERROR("amdgpu_kv_smc_bapm_enable failed\n"); return ret; diff --git a/drivers/gpu/drm/amd/amdgpu/si_dpm.c b/drivers/gpu/drm/amd/amdgpu/si_dpm.c index b12d7c9d42a05..9567dd0a01bc9 100644 --- a/drivers/gpu/drm/amd/amdgpu/si_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/si_dpm.c @@ -3480,7 +3480,7 @@ static void si_apply_state_adjust_rules(struct amdgpu_device *adev, disable_sclk_switching = true; } - if (adev->pm.dpm.ac_power) + if (adev->pm.ac_power) max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac; else max_limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc; @@ -3489,7 +3489,7 @@ static void si_apply_state_adjust_rules(struct amdgpu_device *adev, if (ps->performance_levels[i].vddc > ps->performance_levels[i+1].vddc) ps->performance_levels[i].vddc = ps->performance_levels[i+1].vddc; } - if (adev->pm.dpm.ac_power == false) { + if (adev->pm.ac_power == false) { for (i = 0; i < ps->performance_level_count; i++) { if (ps->performance_levels[i].mclk > max_limits->mclk) ps->performance_levels[i].mclk = max_limits->mclk; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c index 4ef77cebc6284..9b675d9bd162d 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c @@ -81,7 +81,6 @@ int hwmgr_early_init(struct pp_hwmgr *hwmgr) return -EINVAL; hwmgr->usec_timeout = AMD_MAX_USEC_TIMEOUT; - hwmgr->power_source = PP_PowerSource_AC; hwmgr->pp_table_version = PP_TABLE_V1; hwmgr->dpm_level = AMD_DPM_FORCED_LEVEL_AUTO; hwmgr->request_dpm_level = AMD_DPM_FORCED_LEVEL_AUTO; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c index 24d20d9c74b4a..b89d6fb8559b8 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c @@ -2877,7 +2877,7 @@ static int smu7_apply_state_adjust_rules(struct pp_hwmgr *hwmgr, struct pp_power_state *request_ps, const struct pp_power_state *current_ps) { - + struct amdgpu_device *adev = hwmgr->adev; struct smu7_power_state *smu7_ps = cast_phw_smu7_power_state(&request_ps->hardware); uint32_t sclk; @@ -2900,12 +2900,12 @@ static int smu7_apply_state_adjust_rules(struct pp_hwmgr *hwmgr, "VI should always have 2 performance levels", ); - max_limits = (PP_PowerSource_AC == hwmgr->power_source) ? + max_limits = adev->pm.ac_power ? &(hwmgr->dyn_state.max_clock_voltage_on_ac) : &(hwmgr->dyn_state.max_clock_voltage_on_dc); /* Cap clock DPM tables at DC MAX if it is in DC. */ - if (PP_PowerSource_DC == hwmgr->power_source) { + if (!adev->pm.ac_power) { for (i = 0; i < smu7_ps->performance_level_count; i++) { if (smu7_ps->performance_levels[i].memory_clock > max_limits->mclk) smu7_ps->performance_levels[i].memory_clock = max_limits->mclk; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c index 66fd1a43e346b..3b8d36df52e99 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c @@ -3102,6 +3102,7 @@ static int vega10_apply_state_adjust_rules(struct pp_hwmgr *hwmgr, struct pp_power_state *request_ps, const struct pp_power_state *current_ps) { + struct amdgpu_device *adev = hwmgr->adev; struct vega10_power_state *vega10_ps = cast_phw_vega10_power_state(&request_ps->hardware); uint32_t sclk; @@ -3127,12 +3128,12 @@ static int vega10_apply_state_adjust_rules(struct pp_hwmgr *hwmgr, if (vega10_ps->performance_level_count != 2) pr_info("VI should always have 2 performance levels"); - max_limits = (PP_PowerSource_AC == hwmgr->power_source) ? + max_limits = adev->pm.ac_power ? &(hwmgr->dyn_state.max_clock_voltage_on_ac) : &(hwmgr->dyn_state.max_clock_voltage_on_dc); /* Cap clock DPM tables at DC MAX if it is in DC. */ - if (PP_PowerSource_DC == hwmgr->power_source) { + if (!adev->pm.ac_power) { for (i = 0; i < vega10_ps->performance_level_count; i++) { if (vega10_ps->performance_levels[i].mem_clock > max_limits->mclk) diff --git a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h index b99fb8ac822c8..40c98ca5feb74 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h @@ -26,7 +26,6 @@ #include <linux/seq_file.h> #include "amd_powerplay.h" #include "hardwaremanager.h" -#include "pp_power_source.h" #include "hwmgr_ppt.h" #include "ppatomctrl.h" #include "hwmgr_ppt.h" @@ -741,7 +740,6 @@ struct pp_hwmgr { const struct pp_table_func *pptable_func; struct pp_power_state *ps; - enum pp_power_source power_source; uint32_t num_ps; struct pp_thermal_controller_info thermal_controller; bool fan_ctrl_is_in_default_mode; diff --git a/drivers/gpu/drm/amd/powerplay/inc/pp_power_source.h b/drivers/gpu/drm/amd/powerplay/inc/pp_power_source.h deleted file mode 100644 index b43315cc5d58e..0000000000000 --- a/drivers/gpu/drm/amd/powerplay/inc/pp_power_source.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2015 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#ifndef PP_POWERSOURCE_H -#define PP_POWERSOURCE_H - -enum pp_power_source { - PP_PowerSource_AC = 0, - PP_PowerSource_DC, - PP_PowerSource_LimitedPower, - PP_PowerSource_LimitedPower_2, - PP_PowerSource_Max -}; - - -#endif -- GitLab From e1e36485e9f398be7207630d866810df485fbf34 Mon Sep 17 00:00:00 2001 From: Rex Zhu <Rex.Zhu@amd.com> Date: Mon, 4 Jun 2018 18:12:31 +0800 Subject: [PATCH 0377/1506] drm/amd/pp: Implement update_smc_table for CI. driver need to update uvd/vce smc table before enable uvd/vce dpm. Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/powerplay/smumgr/ci_smumgr.c | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c index 8cd21ac6cedac..fbe3ef4ee45c6 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c @@ -2846,6 +2846,89 @@ static int ci_update_dpm_settings(struct pp_hwmgr *hwmgr, return 0; } +static int ci_update_uvd_smc_table(struct pp_hwmgr *hwmgr) +{ + struct amdgpu_device *adev = hwmgr->adev; + struct smu7_hwmgr *data = hwmgr->backend; + struct ci_smumgr *smu_data = hwmgr->smu_backend; + struct phm_uvd_clock_voltage_dependency_table *uvd_table = + hwmgr->dyn_state.uvd_clock_voltage_dependency_table; + uint32_t profile_mode_mask = AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD | + AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK | + AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK | + AMD_DPM_FORCED_LEVEL_PROFILE_PEAK; + uint32_t max_vddc = adev->pm.ac_power ? hwmgr->dyn_state.max_clock_voltage_on_ac.vddc : + hwmgr->dyn_state.max_clock_voltage_on_dc.vddc; + int32_t i; + + if (PP_CAP(PHM_PlatformCaps_UVDDPM) || uvd_table->count <= 0) + smu_data->smc_state_table.UvdBootLevel = 0; + else + smu_data->smc_state_table.UvdBootLevel = uvd_table->count - 1; + + PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, DPM_TABLE_475, + UvdBootLevel, smu_data->smc_state_table.UvdBootLevel); + + data->dpm_level_enable_mask.uvd_dpm_enable_mask = 0; + + for (i = uvd_table->count - 1; i >= 0; i--) { + if (uvd_table->entries[i].v <= max_vddc) + data->dpm_level_enable_mask.uvd_dpm_enable_mask |= 1 << i; + if (hwmgr->dpm_level & profile_mode_mask || !PP_CAP(PHM_PlatformCaps_UVDDPM)) + break; + } + ci_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_UVDDPM_SetEnabledMask, + data->dpm_level_enable_mask.uvd_dpm_enable_mask); + + return 0; +} + +static int ci_update_vce_smc_table(struct pp_hwmgr *hwmgr) +{ + struct amdgpu_device *adev = hwmgr->adev; + struct smu7_hwmgr *data = hwmgr->backend; + struct phm_vce_clock_voltage_dependency_table *vce_table = + hwmgr->dyn_state.vce_clock_voltage_dependency_table; + uint32_t profile_mode_mask = AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD | + AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK | + AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK | + AMD_DPM_FORCED_LEVEL_PROFILE_PEAK; + uint32_t max_vddc = adev->pm.ac_power ? hwmgr->dyn_state.max_clock_voltage_on_ac.vddc : + hwmgr->dyn_state.max_clock_voltage_on_dc.vddc; + int32_t i; + + PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, DPM_TABLE_475, + VceBootLevel, 0); /* temp hard code to level 0, vce can set min evclk*/ + + data->dpm_level_enable_mask.vce_dpm_enable_mask = 0; + + for (i = vce_table->count - 1; i >= 0; i--) { + if (vce_table->entries[i].v <= max_vddc) + data->dpm_level_enable_mask.vce_dpm_enable_mask |= 1 << i; + if (hwmgr->dpm_level & profile_mode_mask || !PP_CAP(PHM_PlatformCaps_VCEDPM)) + break; + } + ci_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_VCEDPM_SetEnabledMask, + data->dpm_level_enable_mask.vce_dpm_enable_mask); + + return 0; +} + +static int ci_update_smc_table(struct pp_hwmgr *hwmgr, uint32_t type) +{ + switch (type) { + case SMU_UVD_TABLE: + ci_update_uvd_smc_table(hwmgr); + break; + case SMU_VCE_TABLE: + ci_update_vce_smc_table(hwmgr); + break; + default: + break; + } + return 0; +} + const struct pp_smumgr_func ci_smu_funcs = { .smu_init = ci_smu_init, .smu_fini = ci_smu_fini, @@ -2868,4 +2951,5 @@ const struct pp_smumgr_func ci_smu_funcs = { .initialize_mc_reg_table = ci_initialize_mc_reg_table, .is_dpm_running = ci_is_dpm_running, .update_dpm_settings = ci_update_dpm_settings, + .update_smc_table = ci_update_smc_table, }; -- GitLab From b1ddf5484727296f8812118a6042c76ebd1faff4 Mon Sep 17 00:00:00 2001 From: Rex Zhu <Rex.Zhu@amd.com> Date: Mon, 4 Jun 2018 18:26:18 +0800 Subject: [PATCH 0378/1506] drm/amdgpu: Get real power source to initizlize ac_power driver need to know the real power source to do some power related configuration when initialize. Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 3317d1536f4fc..fe76ec1f97374 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -25,6 +25,7 @@ * Alex Deucher * Jerome Glisse */ +#include <linux/power_supply.h> #include <linux/kthread.h> #include <linux/console.h> #include <linux/slab.h> @@ -2293,6 +2294,8 @@ int amdgpu_device_init(struct amdgpu_device *adev, INIT_DELAYED_WORK(&adev->late_init_work, amdgpu_device_ip_late_init_func_handler); + adev->pm.ac_power = power_supply_is_system_supplied() > 0 ? true : false; + /* Registers mapping */ /* TODO: block userspace mapping of io register */ if (adev->asic_type >= CHIP_BONAIRE) { -- GitLab From ab3ec8a1a9f1c785103f395e9502ab5804705134 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= <michel.daenzer@amd.com> Date: Thu, 14 Jun 2018 11:59:20 +0200 Subject: [PATCH 0379/1506] drm/amdgpu: Restore :internal: for amdgpu_vm.c documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This was accidentally dropped by the "drm/amdgpu: update documentation for amdgpu_irq.c v3" change, resulting in the GPUVM documentation body being included twice in the generated documentation. Trivial. Signed-off-by: Michel Dänzer <michel.daenzer@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- Documentation/gpu/amdgpu.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/gpu/amdgpu.rst b/Documentation/gpu/amdgpu.rst index e1656fe8f2474..e52d0ce186fe4 100644 --- a/Documentation/gpu/amdgpu.rst +++ b/Documentation/gpu/amdgpu.rst @@ -52,6 +52,7 @@ AMDGPU Virtual Memory :doc: GPUVM .. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c + :internal: Interrupt Handling ------------------ -- GitLab From 00553cf8116e041c75c6c201bdf6d4e006fcf956 Mon Sep 17 00:00:00 2001 From: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Date: Wed, 13 Jun 2018 16:01:38 -0400 Subject: [PATCH 0380/1506] drm/amdgpu: Update function level documentation for GPUVM. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add documentation for missed parameters. Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 6d2294203bd7b..8199494184952 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -347,6 +347,7 @@ bool amdgpu_vm_ready(struct amdgpu_vm *vm) * @vm: VM to clear BO from * @bo: BO to clear * @level: level this BO is at + * @pte_support_ats: indicate ATS support from PTE * * Root PD needs to be reserved when calling this. * @@ -673,6 +674,7 @@ bool amdgpu_vm_need_pipeline_sync(struct amdgpu_ring *ring, * amdgpu_vm_flush - hardware flush the vm * * @ring: ring to use for flush + * @job: related job * @need_pipe_sync: is pipe sync needed * * Emit a VM flush when it is necessary. @@ -1763,6 +1765,7 @@ static void amdgpu_vm_prt_put(struct amdgpu_device *adev) * amdgpu_vm_prt_cb - callback for updating the PRT status * * @fence: fence for the callback + * @_cb: the callback function */ static void amdgpu_vm_prt_cb(struct dma_fence *fence, struct dma_fence_cb *_cb) { @@ -2041,6 +2044,7 @@ static void amdgpu_vm_bo_insert_map(struct amdgpu_device *adev, * @bo_va: bo_va to store the address * @saddr: where to map the BO * @offset: requested offset in the BO + * @size: BO size in bytes * @flags: attributes of pages (read/write/valid/etc.) * * Add a mapping of the BO at the specefied addr into the VM. @@ -2104,6 +2108,7 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev, * @bo_va: bo_va to store the address * @saddr: where to map the BO * @offset: requested offset in the BO + * @size: BO size in bytes * @flags: attributes of pages (read/write/valid/etc.) * * Add a mapping of the BO at the specefied addr into the VM. Replace existing @@ -2322,6 +2327,7 @@ int amdgpu_vm_bo_clear_mappings(struct amdgpu_device *adev, * amdgpu_vm_bo_lookup_mapping - find mapping by address * * @vm: the requested VM + * @addr: the address * * Find a mapping by it's address. * @@ -2380,6 +2386,7 @@ void amdgpu_vm_bo_rmv(struct amdgpu_device *adev, * * @adev: amdgpu_device pointer * @bo: amdgpu buffer object + * @evicted: is the BO evicted * * Mark @bo as invalid. */ @@ -2445,6 +2452,10 @@ static uint32_t amdgpu_vm_get_block_size(uint64_t vm_size) * * @adev: amdgpu_device pointer * @vm_size: the default vm size if it's set auto + * @fragment_size_default: Default PTE fragment size + * @max_level: max VMPT level + * @max_bits: max address space size in bits + * */ void amdgpu_vm_adjust_size(struct amdgpu_device *adev, uint32_t vm_size, uint32_t fragment_size_default, unsigned max_level, @@ -2512,6 +2523,7 @@ void amdgpu_vm_adjust_size(struct amdgpu_device *adev, uint32_t vm_size, * @adev: amdgpu_device pointer * @vm: requested vm * @vm_context: Indicates if it GFX or Compute context + * @pasid: Process address space identifier * * Init @vm fields. * -- GitLab From 3b070c60ea511a0d103b39de3122d3bad0de45ab Mon Sep 17 00:00:00 2001 From: Mikita Lipski <mikita.lipski@amd.com> Date: Tue, 22 May 2018 15:55:43 -0400 Subject: [PATCH 0381/1506] drm/amd/display: Drop to fail-safe mode if edid is bad Provide the connector with a single fail-safe mode of 640x480 for CTS tests instead of providing a list of possible base modes. Signed-off-by: Mikita Lipski <mikita.lipski@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 4 ++++ 1 file changed, 4 insertions(+) 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 adeb795d80f65..b1b8d1914b315 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -3424,6 +3424,10 @@ static int amdgpu_dm_connector_get_modes(struct drm_connector *connector) struct edid *edid = amdgpu_dm_connector->edid; encoder = helper->best_encoder(connector); + + if (!edid || !drm_edid_is_valid(edid)) + return drm_add_modes_noedid(connector, 640, 480); + amdgpu_dm_connector_ddc_get_modes(connector, edid); amdgpu_dm_connector_add_common_modes(encoder, connector); -- GitLab From 6e0ef9d85b99baeeea4b9c4a9777809cb0c6040a Mon Sep 17 00:00:00 2001 From: Mikita Lipski <mikita.lipski@amd.com> Date: Thu, 17 May 2018 15:44:20 -0400 Subject: [PATCH 0382/1506] drm/amd/display: Write TEST_EDID_CHECKSUM_WRITE for EDID tests Extract edid's checksum and send it back for verification if EDID_TEST is requested. Also added a flag for EDID checksum write in TEST_RESPONSE structure, and simple spelling fix. Signed-off-by: Mikita Lipski <mikita.lipski@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 28 +++++++++++++++++++ drivers/gpu/drm/amd/display/dc/dc_dp_types.h | 5 ++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c index bd449351803fb..dea49dc9b518f 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c @@ -497,6 +497,34 @@ enum dc_edid_status dm_helpers_read_local_edid( DRM_ERROR("EDID err: %d, on connector: %s", edid_status, aconnector->base.name); + if (link->aux_mode) { + union test_request test_request = {0}; + union test_response test_response = {0}; + + dm_helpers_dp_read_dpcd(ctx, + link, + DP_TEST_REQUEST, + &test_request.raw, + sizeof(union test_request)); + + if (!test_request.bits.EDID_READ) + return edid_status; + + test_response.bits.EDID_CHECKSUM_WRITE = 1; + + dm_helpers_dp_write_dpcd(ctx, + link, + DP_TEST_EDID_CHECKSUM, + &sink->dc_edid.raw_edid[sink->dc_edid.length-1], + 1); + + dm_helpers_dp_write_dpcd(ctx, + link, + DP_TEST_RESPONSE, + &test_response.raw, + sizeof(test_response)); + + } return edid_status; } diff --git a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h index 90bccd5ccaa2b..da93ab43f2d8a 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h @@ -430,7 +430,7 @@ union test_request { struct { uint8_t LINK_TRAINING :1; uint8_t LINK_TEST_PATTRN :1; - uint8_t EDID_REAT :1; + uint8_t EDID_READ :1; uint8_t PHY_TEST_PATTERN :1; uint8_t AUDIO_TEST_PATTERN :1; uint8_t RESERVED :1; @@ -443,7 +443,8 @@ union test_response { struct { uint8_t ACK :1; uint8_t NO_ACK :1; - uint8_t RESERVED :6; + uint8_t EDID_CHECKSUM_WRITE:1; + uint8_t RESERVED :5; } bits; uint8_t raw; }; -- GitLab From b4f84bdf579eb654add9a4c257b97af499c23e03 Mon Sep 17 00:00:00 2001 From: Eric Bernstein <eric.bernstein@amd.com> Date: Tue, 22 May 2018 15:16:33 -0400 Subject: [PATCH 0383/1506] drm/amd/display: Stream encoder update Update stream encoder based on feedback from HW team. Signed-off-by: Eric Bernstein <eric.bernstein@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../display/dc/dcn10/dcn10_stream_encoder.c | 30 +------------------ 1 file changed, 1 insertion(+), 29 deletions(-) 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 147f61416fa5c..32a4997714c1a 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 @@ -1097,27 +1097,6 @@ static union audio_cea_channels speakers_to_channels( return cea_channels; } -static uint32_t calc_max_audio_packets_per_line( - const struct audio_crtc_info *crtc_info) -{ - uint32_t max_packets_per_line; - - max_packets_per_line = - crtc_info->h_total - crtc_info->h_active; - - if (crtc_info->pixel_repetition) - max_packets_per_line *= crtc_info->pixel_repetition; - - /* for other hdmi features */ - max_packets_per_line -= 58; - /* for Control Period */ - max_packets_per_line -= 16; - /* Number of Audio Packets per Line */ - max_packets_per_line /= 32; - - return max_packets_per_line; -} - static void get_audio_clock_info( enum dc_color_depth color_depth, uint32_t crtc_pixel_clock_in_khz, @@ -1211,16 +1190,9 @@ static void enc1_se_setup_hdmi_audio( struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc); struct audio_clock_info audio_clock_info = {0}; - uint32_t max_packets_per_line; - - /* For now still do calculation, although this field is ignored when - * above HDMI_PACKET_GEN_VERSION set to 1 - */ - max_packets_per_line = calc_max_audio_packets_per_line(crtc_info); /* HDMI_AUDIO_PACKET_CONTROL */ - REG_UPDATE_2(HDMI_AUDIO_PACKET_CONTROL, - HDMI_AUDIO_PACKETS_PER_LINE, max_packets_per_line, + REG_UPDATE(HDMI_AUDIO_PACKET_CONTROL, HDMI_AUDIO_DELAY_EN, 1); /* AFMT_AUDIO_PACKET_CONTROL */ -- GitLab From 973d42c79e99aedd767071407ce286bb7eefe202 Mon Sep 17 00:00:00 2001 From: Harry Wentland <harry.wentland@amd.com> Date: Wed, 9 May 2018 11:35:21 -0400 Subject: [PATCH 0384/1506] drm/amd/display: Move i2c and aux structs into dc_ddc_types.h We'd like to use some of them in dc_link_ddc and amdgpu_dm and should have them available in dc_ddc_types.h. Signed-off-by: Harry Wentland <harry.wentland@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dc_ddc_types.h | 59 +++++++++++++++++++ .../drm/amd/display/dc/i2caux/aux_engine.h | 44 +------------- .../gpu/drm/amd/display/dc/i2caux/engine.h | 15 +---- 3 files changed, 62 insertions(+), 56 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc_ddc_types.h b/drivers/gpu/drm/amd/display/dc/dc_ddc_types.h index ee04812b44926..05c8c31d8b310 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_ddc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_ddc_types.h @@ -25,6 +25,65 @@ #ifndef DC_DDC_TYPES_H_ #define DC_DDC_TYPES_H_ +enum aux_transaction_type { + AUX_TRANSACTION_TYPE_DP, + AUX_TRANSACTION_TYPE_I2C +}; + + +enum i2caux_transaction_action { + I2CAUX_TRANSACTION_ACTION_I2C_WRITE = 0x00, + I2CAUX_TRANSACTION_ACTION_I2C_READ = 0x10, + I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST = 0x20, + + I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT = 0x40, + I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT = 0x50, + I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT = 0x60, + + I2CAUX_TRANSACTION_ACTION_DP_WRITE = 0x80, + I2CAUX_TRANSACTION_ACTION_DP_READ = 0x90 +}; + +enum aux_channel_operation_result { + AUX_CHANNEL_OPERATION_SUCCEEDED, + AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN, + AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY, + AUX_CHANNEL_OPERATION_FAILED_TIMEOUT, + AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON +}; + + +struct aux_request_transaction_data { + enum aux_transaction_type type; + enum i2caux_transaction_action action; + /* 20-bit AUX channel transaction address */ + uint32_t address; + /* delay, in 100-microsecond units */ + uint8_t delay; + uint32_t length; + uint8_t *data; +}; + +enum aux_transaction_reply { + AUX_TRANSACTION_REPLY_AUX_ACK = 0x00, + AUX_TRANSACTION_REPLY_AUX_NACK = 0x01, + AUX_TRANSACTION_REPLY_AUX_DEFER = 0x02, + + AUX_TRANSACTION_REPLY_I2C_ACK = 0x00, + AUX_TRANSACTION_REPLY_I2C_NACK = 0x10, + AUX_TRANSACTION_REPLY_I2C_DEFER = 0x20, + + AUX_TRANSACTION_REPLY_HPD_DISCON = 0x40, + + AUX_TRANSACTION_REPLY_INVALID = 0xFF +}; + +struct aux_reply_transaction_data { + enum aux_transaction_reply status; + uint32_t length; + uint8_t *data; +}; + struct i2c_payload { bool write; uint8_t address; diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.h b/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.h index b9e35d0474c6a..b01488f710d51 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.h +++ b/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.h @@ -26,49 +26,7 @@ #ifndef __DAL_AUX_ENGINE_H__ #define __DAL_AUX_ENGINE_H__ -enum aux_transaction_type { - AUX_TRANSACTION_TYPE_DP, - AUX_TRANSACTION_TYPE_I2C -}; - -struct aux_request_transaction_data { - enum aux_transaction_type type; - enum i2caux_transaction_action action; - /* 20-bit AUX channel transaction address */ - uint32_t address; - /* delay, in 100-microsecond units */ - uint8_t delay; - uint32_t length; - uint8_t *data; -}; - -enum aux_transaction_reply { - AUX_TRANSACTION_REPLY_AUX_ACK = 0x00, - AUX_TRANSACTION_REPLY_AUX_NACK = 0x01, - AUX_TRANSACTION_REPLY_AUX_DEFER = 0x02, - - AUX_TRANSACTION_REPLY_I2C_ACK = 0x00, - AUX_TRANSACTION_REPLY_I2C_NACK = 0x10, - AUX_TRANSACTION_REPLY_I2C_DEFER = 0x20, - - AUX_TRANSACTION_REPLY_HPD_DISCON = 0x40, - - AUX_TRANSACTION_REPLY_INVALID = 0xFF -}; - -struct aux_reply_transaction_data { - enum aux_transaction_reply status; - uint32_t length; - uint8_t *data; -}; - -enum aux_channel_operation_result { - AUX_CHANNEL_OPERATION_SUCCEEDED, - AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN, - AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY, - AUX_CHANNEL_OPERATION_FAILED_TIMEOUT, - AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON -}; +#include "dc_ddc_types.h" struct aux_engine; diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/engine.h b/drivers/gpu/drm/amd/display/dc/i2caux/engine.h index c1109706a8808..1e8a1585e4012 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/engine.h +++ b/drivers/gpu/drm/amd/display/dc/i2caux/engine.h @@ -26,6 +26,8 @@ #ifndef __DAL_ENGINE_H__ #define __DAL_ENGINE_H__ +#include "dc_ddc_types.h" + enum i2caux_transaction_operation { I2CAUX_TRANSACTION_READ, I2CAUX_TRANSACTION_WRITE @@ -76,19 +78,6 @@ enum i2c_default_speed { I2CAUX_DEFAULT_I2C_SW_SPEED = 50 }; -enum i2caux_transaction_action { - I2CAUX_TRANSACTION_ACTION_I2C_WRITE = 0x00, - I2CAUX_TRANSACTION_ACTION_I2C_READ = 0x10, - I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST = 0x20, - - I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT = 0x40, - I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT = 0x50, - I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT = 0x60, - - I2CAUX_TRANSACTION_ACTION_DP_WRITE = 0x80, - I2CAUX_TRANSACTION_ACTION_DP_READ = 0x90 -}; - struct engine; struct engine_funcs { -- GitLab From a10dc97ab8e9b5560fc47d57d2048c7455774472 Mon Sep 17 00:00:00 2001 From: Krunoslav Kovac <Krunoslav.Kovac@amd.com> Date: Thu, 17 May 2018 14:50:12 -0400 Subject: [PATCH 0385/1506] drm/amd/display: Add use_dynamic_meta flag to stream_state Signed-off-by: Krunoslav Kovac <Krunoslav.Kovac@amd.com> Reviewed-by: Anthony Koo <Anthony.Koo@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 3 ++- drivers/gpu/drm/amd/display/dc/dc_stream.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) 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 1d716171e581b..fca22550417a9 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -2506,7 +2506,8 @@ static void set_hdr_static_info_packet( { /* HDR Static Metadata info packet for HDR10 */ - if (!stream->hdr_static_metadata.valid) + if (!stream->hdr_static_metadata.valid || + stream->use_dynamic_meta) return; *info_packet = stream->hdr_static_metadata; diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index e6e944423b3c1..065450c445c58 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -60,6 +60,7 @@ struct dc_stream_state { struct dc_info_packet hdr_static_metadata; PHYSICAL_ADDRESS_LOC dmdata_address; + bool use_dynamic_meta; struct dc_transfer_func *out_transfer_func; struct colorspace_transform gamut_remap_matrix; -- GitLab From 2cbe6d9be5a4ea5a6aff064a3bcca2ef92921993 Mon Sep 17 00:00:00 2001 From: Krunoslav Kovac <Krunoslav.Kovac@amd.com> Date: Wed, 30 May 2018 10:56:32 -0400 Subject: [PATCH 0386/1506] drm/amd/display: Drop duplicate dc_stream_set_static_screen_events definition Signed-off-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Krunoslav Kovac <Krunoslav.Kovac@amd.com> Reviewed-by: Anthony Koo <Anthony.Koo@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dc_stream.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index 065450c445c58..af503e0286a75 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -302,9 +302,4 @@ bool dc_stream_get_crtc_position(struct dc *dc, unsigned int *v_pos, unsigned int *nom_v_pos); -void dc_stream_set_static_screen_events(struct dc *dc, - struct dc_stream_state **stream, - int num_streams, - const struct dc_static_screen_events *events); - #endif /* DC_STREAM_H_ */ -- GitLab From 6f0db2dc02def18ee6fb93f408a847077addb4fc Mon Sep 17 00:00:00 2001 From: Krunoslav Kovac <Krunoslav.Kovac@amd.com> Date: Wed, 30 May 2018 10:57:32 -0400 Subject: [PATCH 0387/1506] drm/amd/display: Make it more clear when info frames affect DP or HDMI Signed-off-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Krunoslav Kovac <Krunoslav.Kovac@amd.com> Reviewed-by: Anthony Koo <Anthony.Koo@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../drm/amd/display/dc/dce110/dce110_hw_sequencer.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) 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 1dd2ae46d505c..353ffcbdf5ba6 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 @@ -665,16 +665,25 @@ static enum dc_status bios_parser_crtc_source_select( void dce110_update_info_frame(struct pipe_ctx *pipe_ctx) { + bool is_hdmi; + bool is_dp; + ASSERT(pipe_ctx->stream); if (pipe_ctx->stream_res.stream_enc == NULL) return; /* this is not root pipe */ - if (dc_is_hdmi_signal(pipe_ctx->stream->signal)) + is_hdmi = dc_is_hdmi_signal(pipe_ctx->stream->signal); + is_dp = dc_is_dp_signal(pipe_ctx->stream->signal); + + if (!is_hdmi && !is_dp) + return; + + if (is_hdmi) pipe_ctx->stream_res.stream_enc->funcs->update_hdmi_info_packets( pipe_ctx->stream_res.stream_enc, &pipe_ctx->stream_res.encoder_info_frame); - else if (dc_is_dp_signal(pipe_ctx->stream->signal)) + else pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets( pipe_ctx->stream_res.stream_enc, &pipe_ctx->stream_res.encoder_info_frame); -- GitLab From b73552323a5d089ab29342803f04fb32b0a0a2a5 Mon Sep 17 00:00:00 2001 From: Krunoslav Kovac <Krunoslav.Kovac@amd.com> Date: Wed, 30 May 2018 10:59:11 -0400 Subject: [PATCH 0388/1506] drm/amd/display: Convert quotes to Ascii quotes Signed-off-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Krunoslav Kovac <Krunoslav.Kovac@amd.com> Reviewed-by: Anthony Koo <Anthony.Koo@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 32a4997714c1a..c6a13d0486bb2 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 @@ -301,7 +301,7 @@ void enc1_stream_encoder_dp_set_stream_attribute( /* For YCbCr420 and BT2020 Colorimetry Formats, VSC SDP shall be used. * When MISC1, bit 6, is Set to 1, a Source device uses a VSC SDP to indicate the * Pixel Encoding/Colorimetry Format and that a Sink device shall ignore MISC1, bit 7, - * and MISC0, bits 7:1 (MISC1, bit 7, and MISC0, bits 7:1, become “don’t careâ€). + * and MISC0, bits 7:1 (MISC1, bit 7, and MISC0, bits 7:1, become "don't care"). */ if ((crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) || (output_color_space == COLOR_SPACE_2020_YCBCR) || -- GitLab From 6aa57bb8e4d47b442c01f5cf361d7b0efe619f6c Mon Sep 17 00:00:00 2001 From: Anthony Koo <Anthony.Koo@amd.com> Date: Thu, 24 May 2018 11:25:00 -0400 Subject: [PATCH 0389/1506] drm/amd/display: Disable stats by default Signed-off-by: Anthony Koo <Anthony.Koo@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/modules/stats/stats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/modules/stats/stats.c b/drivers/gpu/drm/amd/display/modules/stats/stats.c index fa0665d09075e..480eb2cdd55d7 100644 --- a/drivers/gpu/drm/amd/display/modules/stats/stats.c +++ b/drivers/gpu/drm/amd/display/modules/stats/stats.c @@ -29,7 +29,7 @@ #include "core_types.h" #define DAL_STATS_ENABLE_REGKEY "DalStatsEnable" -#define DAL_STATS_ENABLE_REGKEY_DEFAULT 0x00000001 +#define DAL_STATS_ENABLE_REGKEY_DEFAULT 0x00000000 #define DAL_STATS_ENABLE_REGKEY_ENABLED 0x00000001 #define DAL_STATS_ENTRIES_REGKEY "DalStatsEntries" -- GitLab From 74167ad60c04c45e991af59ee5c7f62aff5c4c38 Mon Sep 17 00:00:00 2001 From: Vitaly Prosyak <vitaly.prosyak@amd.com> Date: Fri, 25 May 2018 08:37:36 -0500 Subject: [PATCH 0390/1506] drm/amd/display: Add new transfer type HWPWL It is used when curve register settings are generated by 'matlab', i.e. bypass color module calculation. Signed-off-by: Vitaly Prosyak <vitaly.prosyak@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dc.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index f09fa4722fc98..9954d0eadfbca 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -357,6 +357,7 @@ enum dc_transfer_func_type { TF_TYPE_PREDEFINED, TF_TYPE_DISTRIBUTED_POINTS, TF_TYPE_BYPASS, + TF_TYPE_HWPWL }; struct dc_transfer_func_distributed_points { @@ -382,12 +383,15 @@ enum dc_transfer_func_predefined { struct dc_transfer_func { struct kref refcount; - struct dc_transfer_func_distributed_points tf_pts; enum dc_transfer_func_type type; enum dc_transfer_func_predefined tf; /* FP16 1.0 reference level in nits, default is 80 nits, only for PQ*/ uint32_t sdr_ref_white_level; struct dc_context *ctx; + union { + struct pwl_params pwl; + struct dc_transfer_func_distributed_points tf_pts; + }; }; /* -- GitLab From ce3f6e82249cccbbfd919ad30d256ec62d06b4af Mon Sep 17 00:00:00 2001 From: Alvin lee <alvin.lee3@amd.com> Date: Fri, 18 May 2018 14:14:38 -0400 Subject: [PATCH 0391/1506] drm/amd/display: create sink_id in dc_sink structure to idenitify all sinks Signed-off-by: Alvin lee <alvin.lee3@amd.com> Reviewed-by: Jun Lei <Jun.Lei@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/core/dc.c | 1 + drivers/gpu/drm/amd/display/dc/core/dc_sink.c | 4 ++++ drivers/gpu/drm/amd/display/dc/dc.h | 6 +++++- drivers/gpu/drm/amd/display/dc/dc_types.h | 1 + 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 2c05630e78fb5..53ce7fa864b4f 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -481,6 +481,7 @@ static bool construct(struct dc *dc, dc_ctx->driver_context = init_params->driver; dc_ctx->dc = dc; dc_ctx->asic_id = init_params->asic_id; + dc_ctx->dc_sink_id_count = 0; dc->ctx = dc_ctx; dc->current_state = dc_create_state(); diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_sink.c b/drivers/gpu/drm/amd/display/dc/core/dc_sink.c index 25fae38409aba..9971b515c3eb3 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_sink.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_sink.c @@ -53,6 +53,10 @@ static bool construct(struct dc_sink *sink, const struct dc_sink_init_data *init sink->dongle_max_pix_clk = init_params->dongle_max_pix_clk; sink->converter_disable_audio = init_params->converter_disable_audio; sink->dc_container_id = NULL; + sink->sink_id = init_params->link->ctx->dc_sink_id_count; + // increment dc_sink_id_count because we don't want two sinks with same ID + // unless they are actually the same + init_params->link->ctx->dc_sink_id_count++; return true; } diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 9954d0eadfbca..7ebce7669eea5 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -666,9 +666,13 @@ struct dc_sink { struct dc_link *link; struct dc_context *ctx; + uint32_t sink_id; + /* private to dc_sink.c */ + // refcount must be the last member in dc_sink, since we want the + // sink structure to be logically cloneable up to (but not including) + // refcount struct kref refcount; - }; void dc_sink_retain(struct dc_sink *sink); diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index e026ce5ac78fd..c96e526d07bb6 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -92,6 +92,7 @@ struct dc_context { bool created_bios; struct gpio_service *gpio_service; struct i2caux *i2caux; + uint32_t dc_sink_id_count; uint64_t fbc_gpu_addr; }; -- GitLab From 12036586a368b8c949d4e6e57ae3b40c41daf17a Mon Sep 17 00:00:00 2001 From: Eric Bernstein <eric.bernstein@amd.com> Date: Fri, 25 May 2018 11:57:26 -0400 Subject: [PATCH 0392/1506] drm/amd/display: Allow DP register double buffer Remove setting DP_DB_DISABLE to avoid issues when changing bit depth after vbios take over. Refactor code to perform single register update for both pixel encoding and component depth fields. Signed-off-by: Eric Bernstein <eric.bernstein@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../amd/display/dc/dce/dce_stream_encoder.c | 5 --- .../display/dc/dcn10/dcn10_stream_encoder.c | 44 ++++++++----------- 2 files changed, 19 insertions(+), 30 deletions(-) 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 c0e813c7ddd41..91642e6848587 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 @@ -289,11 +289,6 @@ static void dce110_stream_encoder_dp_set_stream_attribute( struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc); -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) - if (REG(DP_DB_CNTL)) - REG_UPDATE(DP_DB_CNTL, DP_DB_DISABLE, 1); -#endif - /* set pixel encoding */ switch (crtc_timing->pixel_encoding) { case PIXEL_ENCODING_YCBCR422: 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 c6a13d0486bb2..6f9078f3c4d39 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 @@ -257,20 +257,18 @@ void enc1_stream_encoder_dp_set_stream_attribute( uint8_t colorimetry_bpc; uint8_t dynamic_range_rgb = 0; /*full range*/ uint8_t dynamic_range_ycbcr = 1; /*bt709*/ + uint8_t dp_pixel_encoding = 0; + uint8_t dp_component_depth = 0; struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc); - REG_UPDATE(DP_DB_CNTL, DP_DB_DISABLE, 1); - /* set pixel encoding */ switch (crtc_timing->pixel_encoding) { case PIXEL_ENCODING_YCBCR422: - REG_UPDATE(DP_PIXEL_FORMAT, DP_PIXEL_ENCODING, - DP_PIXEL_ENCODING_TYPE_YCBCR422); + dp_pixel_encoding = DP_PIXEL_ENCODING_TYPE_YCBCR422; break; case PIXEL_ENCODING_YCBCR444: - REG_UPDATE(DP_PIXEL_FORMAT, DP_PIXEL_ENCODING, - DP_PIXEL_ENCODING_TYPE_YCBCR444); + dp_pixel_encoding = DP_PIXEL_ENCODING_TYPE_YCBCR444; if (crtc_timing->flags.Y_ONLY) if (crtc_timing->display_color_depth != COLOR_DEPTH_666) @@ -278,8 +276,8 @@ void enc1_stream_encoder_dp_set_stream_attribute( * Color depth of Y-only could be * 8, 10, 12, 16 bits */ - REG_UPDATE(DP_PIXEL_FORMAT, DP_PIXEL_ENCODING, - DP_PIXEL_ENCODING_TYPE_Y_ONLY); + dp_pixel_encoding = DP_PIXEL_ENCODING_TYPE_Y_ONLY; + /* Note: DP_MSA_MISC1 bit 7 is the indicator * of Y-only mode. * This bit is set in HW if register @@ -287,13 +285,11 @@ void enc1_stream_encoder_dp_set_stream_attribute( */ break; case PIXEL_ENCODING_YCBCR420: - REG_UPDATE(DP_PIXEL_FORMAT, DP_PIXEL_ENCODING, - DP_PIXEL_ENCODING_TYPE_YCBCR420); + dp_pixel_encoding = DP_PIXEL_ENCODING_TYPE_YCBCR420; REG_UPDATE(DP_VID_TIMING, DP_VID_N_MUL, 1); break; default: - REG_UPDATE(DP_PIXEL_FORMAT, DP_PIXEL_ENCODING, - DP_PIXEL_ENCODING_TYPE_RGB444); + dp_pixel_encoding = DP_PIXEL_ENCODING_TYPE_RGB444; break; } @@ -314,32 +310,30 @@ void enc1_stream_encoder_dp_set_stream_attribute( /* set color depth */ switch (crtc_timing->display_color_depth) { case COLOR_DEPTH_666: - REG_UPDATE(DP_PIXEL_FORMAT, DP_COMPONENT_DEPTH, - 0); + dp_component_depth = DP_COMPONENT_PIXEL_DEPTH_6BPC; break; case COLOR_DEPTH_888: - REG_UPDATE(DP_PIXEL_FORMAT, DP_COMPONENT_DEPTH, - DP_COMPONENT_PIXEL_DEPTH_8BPC); + dp_component_depth = DP_COMPONENT_PIXEL_DEPTH_8BPC; break; case COLOR_DEPTH_101010: - REG_UPDATE(DP_PIXEL_FORMAT, DP_COMPONENT_DEPTH, - DP_COMPONENT_PIXEL_DEPTH_10BPC); - + dp_component_depth = DP_COMPONENT_PIXEL_DEPTH_10BPC; break; case COLOR_DEPTH_121212: - REG_UPDATE(DP_PIXEL_FORMAT, DP_COMPONENT_DEPTH, - DP_COMPONENT_PIXEL_DEPTH_12BPC); + dp_component_depth = DP_COMPONENT_PIXEL_DEPTH_12BPC; break; case COLOR_DEPTH_161616: - REG_UPDATE(DP_PIXEL_FORMAT, DP_COMPONENT_DEPTH, - DP_COMPONENT_PIXEL_DEPTH_16BPC); + dp_component_depth = DP_COMPONENT_PIXEL_DEPTH_16BPC; break; default: - REG_UPDATE(DP_PIXEL_FORMAT, DP_COMPONENT_DEPTH, - DP_COMPONENT_PIXEL_DEPTH_6BPC); + dp_component_depth = DP_COMPONENT_PIXEL_DEPTH_6BPC; break; } + /* Set DP pixel encoding and component depth */ + REG_UPDATE_2(DP_PIXEL_FORMAT, + DP_PIXEL_ENCODING, dp_pixel_encoding, + DP_COMPONENT_DEPTH, dp_component_depth); + /* set dynamic range and YCbCr range */ switch (crtc_timing->display_color_depth) { -- GitLab From e9522309efb31423a450c32f433dd95bfb8b5787 Mon Sep 17 00:00:00 2001 From: Eric Bernstein <eric.bernstein@amd.com> Date: Fri, 18 May 2018 10:49:33 -0400 Subject: [PATCH 0393/1506] drm/amd/display: Add num_opp to resource_caps Number of OPPs to be instantiated is based on number of timing generators, not number of pipes. Signed-off-by: Eric Bernstein <eric.bernstein@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c | 1 + drivers/gpu/drm/amd/display/dc/inc/resource.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c index 99c223bcad71f..2da325ce781bc 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c @@ -417,6 +417,7 @@ static const struct dce110_clk_src_mask cs_mask = { static const struct resource_caps res_cap = { .num_timing_generator = 4, + .num_opp = 4, .num_video_plane = 4, .num_audio = 4, .num_stream_encoder = 4, diff --git a/drivers/gpu/drm/amd/display/dc/inc/resource.h b/drivers/gpu/drm/amd/display/dc/inc/resource.h index 640a647f4611f..e92facbd038f0 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/resource.h +++ b/drivers/gpu/drm/amd/display/dc/inc/resource.h @@ -38,6 +38,7 @@ enum dce_version resource_parse_asic_id( struct resource_caps { int num_timing_generator; + int num_opp; int num_video_plane; int num_audio; int num_stream_encoder; -- GitLab From 85ee15d6a3d3c55e3e653426cc32e138ee515585 Mon Sep 17 00:00:00 2001 From: Mikita Lipski <mikita.lipski@amd.com> Date: Mon, 28 May 2018 10:08:30 -0400 Subject: [PATCH 0394/1506] drm/amd/display: Do not skip FBC init in failsafe mode Initially FBC would be initialized if display's edid was correct and all the modes acquired from it, but n case when edid is corrupted or non-existant we must still initialize FBC. Signed-off-by: Mikita Lipski <mikita.lipski@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) 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 b1b8d1914b315..a1c912bc959af 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -3425,12 +3425,12 @@ static int amdgpu_dm_connector_get_modes(struct drm_connector *connector) encoder = helper->best_encoder(connector); - if (!edid || !drm_edid_is_valid(edid)) - return drm_add_modes_noedid(connector, 640, 480); - - amdgpu_dm_connector_ddc_get_modes(connector, edid); - amdgpu_dm_connector_add_common_modes(encoder, connector); - + if (!edid || !drm_edid_is_valid(edid)) { + drm_add_modes_noedid(connector, 640, 480); + } else { + amdgpu_dm_connector_ddc_get_modes(connector, edid); + amdgpu_dm_connector_add_common_modes(encoder, connector); + } amdgpu_dm_fbc_init(connector); return amdgpu_dm_connector->num_modes; -- GitLab From 042ed2dbe5b294e6c225e12d380062ee6adb3ac0 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 15 Jun 2018 10:31:36 +0100 Subject: [PATCH 0395/1506] drm/i915: Be irqsafe inside reset As we want to be able to call i915_reset_engine and co from a softirq or timer context, we need to be irqsafe at all times. So we have to forgo the simple spin_lock_irq for the full spin_lock_irqsave. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180615093137.14270-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 977982a987c8f..5155e458b11ea 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3166,15 +3166,17 @@ i915_gem_reset_request(struct intel_engine_cs *engine, */ request = i915_gem_find_active_request(engine); if (request) { + unsigned long flags; + i915_gem_context_mark_innocent(request->gem_context); dma_fence_set_error(&request->fence, -EAGAIN); /* Rewind the engine to replay the incomplete rq */ - spin_lock_irq(&engine->timeline.lock); + spin_lock_irqsave(&engine->timeline.lock, flags); request = list_prev_entry(request, link); if (&request->link == &engine->timeline.requests) request = NULL; - spin_unlock_irq(&engine->timeline.lock); + spin_unlock_irqrestore(&engine->timeline.lock, flags); } } -- GitLab From b2209e62a4507f6649233eaf0675de3ad86bd868 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 15 Jun 2018 10:31:37 +0100 Subject: [PATCH 0396/1506] drm/i915/execlists: Reset the CSB head tracking on reset/sanitization We can avoid the mmio read of the CSB pointers after reset based on the knowledge that the HW always start writing at entry 0 in the CSB buffer. We need to reset our CSB head tracking after GPU reset (and on sanitization after resume) so that we are expecting to read from entry 0, hence we reset our head tracking back to the entry before (the last entry in the ring). Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180615093137.14270-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_lrc.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 8d56bcb009798..50e141ca1f7a0 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -971,22 +971,19 @@ static void process_csb(struct intel_engine_cs *engine) &engine->status_page.page_addr[I915_HWS_CSB_BUF0_INDEX]; unsigned int head, tail; - if (unlikely(execlists->csb_use_mmio)) { - buf = (u32 * __force) - (i915->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_BUF_LO(engine, 0))); - execlists->csb_head = -1; /* force mmio read of CSB */ - } - /* Clear before reading to catch new interrupts */ clear_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted); smp_mb__after_atomic(); - if (unlikely(execlists->csb_head == -1)) { /* after a reset */ + if (unlikely(execlists->csb_use_mmio)) { if (!fw) { intel_uncore_forcewake_get(i915, execlists->fw_domains); fw = true; } + buf = (u32 * __force) + (i915->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_BUF_LO(engine, 0))); + head = readl(i915->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_PTR(engine))); tail = GEN8_CSB_WRITE_PTR(head); head = GEN8_CSB_READ_PTR(head); @@ -1961,7 +1958,7 @@ static void execlists_reset(struct intel_engine_cs *engine, spin_unlock(&engine->timeline.lock); /* Following the reset, we need to reload the CSB read/write pointers */ - engine->execlists.csb_head = -1; + engine->execlists.csb_head = GEN8_CSB_ENTRIES - 1; local_irq_restore(flags); @@ -2469,7 +2466,7 @@ static int logical_ring_init(struct intel_engine_cs *engine) upper_32_bits(ce->lrc_desc); } - engine->execlists.csb_head = -1; + engine->execlists.csb_head = GEN8_CSB_ENTRIES - 1; return 0; -- GitLab From 1c0f1b3db7a647ef8962fb4186105e91710a3ade Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Thu, 14 Jun 2018 21:05:00 +0300 Subject: [PATCH 0397/1506] drm/i915: s/IS_G4X && !IS_GM45/IS_G45/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have IS_G45 these days. Let's use it instead of the 'IS_G4X && !IS_GM45' construct. Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180614180500.2565-1-ville.syrjala@linux.intel.com Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> --- drivers/gpu/drm/i915/intel_crt.c | 2 +- drivers/gpu/drm/i915/intel_dp.c | 2 +- drivers/gpu/drm/i915/intel_hdmi.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 87c72c39f409c..a1ddd9f62bb8f 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -517,7 +517,7 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector) * to get a reliable result. */ - if (IS_G4X(dev_priv) && !IS_GM45(dev_priv)) + if (IS_G45(dev_priv)) tries = 2; else tries = 1; diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index afa0574c1908a..6ac6c8787dcf6 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -6421,7 +6421,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, * 0xd. Failure to do so will result in spurious interrupts being * generated on the port when a cable is not attached. */ - if (IS_G4X(dev_priv) && !IS_GM45(dev_priv)) { + if (IS_G45(dev_priv)) { u32 temp = I915_READ(PEG_BAND_GAP_DATA); I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd); } diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 9a33432c1f6b2..3dd3ee259e7fb 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -2341,7 +2341,7 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, * 0xd. Failure to do so will result in spurious interrupts being * generated on the port when a cable is not attached. */ - if (IS_G4X(dev_priv) && !IS_GM45(dev_priv)) { + if (IS_G45(dev_priv)) { u32 temp = I915_READ(PEG_BAND_GAP_DATA); I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd); } -- GitLab From b6f690ab237d801cbf881be4bc164062727053fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Mon, 11 Jun 2018 22:34:01 +0300 Subject: [PATCH 0398/1506] drm/atomic: Improve debug messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Print the id/name of the object we're dealing with. Makes it easier to figure out what's going on. Also toss in a few extra debug prints that might be useful. Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180611193403.16118-1-ville.syrjala@linux.intel.com Reviewed-by: Harry Wentland <harry.wentland@amd.com> --- drivers/gpu/drm/drm_atomic.c | 88 +++++++++++++++++++++++++----------- 1 file changed, 61 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 11059d556dbd0..0ae280aaa1247 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -331,6 +331,7 @@ static s32 __user *get_out_fence_for_crtc(struct drm_atomic_state *state, int drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state, const struct drm_display_mode *mode) { + struct drm_crtc *crtc = state->crtc; struct drm_mode_modeinfo umode; /* Early return for no change. */ @@ -351,13 +352,13 @@ int drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state, drm_mode_copy(&state->mode, mode); state->enable = true; - DRM_DEBUG_ATOMIC("Set [MODE:%s] for CRTC state %p\n", - mode->name, state); + DRM_DEBUG_ATOMIC("Set [MODE:%s] for [CRTC:%d:%s] state %p\n", + mode->name, crtc->base.id, crtc->name, state); } else { memset(&state->mode, 0, sizeof(state->mode)); state->enable = false; - DRM_DEBUG_ATOMIC("Set [NOMODE] for CRTC state %p\n", - state); + DRM_DEBUG_ATOMIC("Set [NOMODE] for [CRTC:%d:%s] state %p\n", + crtc->base.id, crtc->name, state); } return 0; @@ -380,6 +381,8 @@ EXPORT_SYMBOL(drm_atomic_set_mode_for_crtc); int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state, struct drm_property_blob *blob) { + struct drm_crtc *crtc = state->crtc; + if (blob == state->mode_blob) return 0; @@ -396,12 +399,13 @@ int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state, state->mode_blob = drm_property_blob_get(blob); state->enable = true; - DRM_DEBUG_ATOMIC("Set [MODE:%s] for CRTC state %p\n", - state->mode.name, state); + DRM_DEBUG_ATOMIC("Set [MODE:%s] for [CRTC:%d:%s] state %p\n", + state->mode.name, crtc->base.id, crtc->name, + state); } else { state->enable = false; - DRM_DEBUG_ATOMIC("Set [NOMODE] for CRTC state %p\n", - state); + DRM_DEBUG_ATOMIC("Set [NOMODE] for [CRTC:%d:%s] state %p\n", + crtc->base.id, crtc->name, state); } return 0; @@ -531,10 +535,14 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc, return -EFAULT; set_out_fence_for_crtc(state->state, crtc, fence_ptr); - } else if (crtc->funcs->atomic_set_property) + } else if (crtc->funcs->atomic_set_property) { return crtc->funcs->atomic_set_property(crtc, state, property, val); - else + } else { + DRM_DEBUG_ATOMIC("[CRTC:%d:%s] unknown property [PROP:%d:%s]]\n", + crtc->base.id, crtc->name, + property->base.id, property->name); return -EINVAL; + } return 0; } @@ -791,8 +799,11 @@ static int drm_atomic_plane_set_property(struct drm_plane *plane, } else if (property == plane->alpha_property) { state->alpha = val; } else if (property == plane->rotation_property) { - if (!is_power_of_2(val & DRM_MODE_ROTATE_MASK)) + if (!is_power_of_2(val & DRM_MODE_ROTATE_MASK)) { + DRM_DEBUG_ATOMIC("[PLANE:%d:%s] bad rotation bitmask: 0x%llx\n", + plane->base.id, plane->name, val); return -EINVAL; + } state->rotation = val; } else if (property == plane->zpos_property) { state->zpos = val; @@ -804,6 +815,9 @@ static int drm_atomic_plane_set_property(struct drm_plane *plane, return plane->funcs->atomic_set_property(plane, state, property, val); } else { + DRM_DEBUG_ATOMIC("[PLANE:%d:%s] unknown property [PROP:%d:%s]]\n", + plane->base.id, plane->name, + property->base.id, property->name); return -EINVAL; } @@ -911,10 +925,12 @@ static int drm_atomic_plane_check(struct drm_plane *plane, /* either *both* CRTC and FB must be set, or neither */ if (state->crtc && !state->fb) { - DRM_DEBUG_ATOMIC("CRTC set but no FB\n"); + 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) { - DRM_DEBUG_ATOMIC("FB set but no CRTC\n"); + DRM_DEBUG_ATOMIC("[PLANE:%d:%s] FB set but no CRTC\n", + plane->base.id, plane->name); return -EINVAL; } @@ -924,7 +940,9 @@ static int drm_atomic_plane_check(struct drm_plane *plane, /* Check whether this plane is usable on this CRTC */ if (!(plane->possible_crtcs & drm_crtc_mask(state->crtc))) { - DRM_DEBUG_ATOMIC("Invalid crtc for plane\n"); + DRM_DEBUG_ATOMIC("Invalid [CRTC:%d:%s] for [PLANE:%d:%s]\n", + state->crtc->base.id, state->crtc->name, + plane->base.id, plane->name); return -EINVAL; } @@ -933,7 +951,8 @@ static int drm_atomic_plane_check(struct drm_plane *plane, state->fb->modifier); if (ret) { struct drm_format_name_buf format_name; - DRM_DEBUG_ATOMIC("Invalid pixel format %s, modifier 0x%llx\n", + 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, &format_name), state->fb->modifier); @@ -945,7 +964,8 @@ static int drm_atomic_plane_check(struct drm_plane *plane, 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) { - DRM_DEBUG_ATOMIC("Invalid CRTC coordinates %ux%u+%d+%d\n", + 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); return -ERANGE; @@ -959,8 +979,9 @@ static int drm_atomic_plane_check(struct drm_plane *plane, state->src_x > fb_width - state->src_w || state->src_h > fb_height || state->src_y > fb_height - state->src_h) { - DRM_DEBUG_ATOMIC("Invalid source coordinates " + 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, @@ -1289,6 +1310,9 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector, return connector->funcs->atomic_set_property(connector, state, property, val); } else { + DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] unknown property [PROP:%d:%s]]\n", + connector->base.id, connector->name, + property->base.id, property->name); return -EINVAL; } @@ -1457,11 +1481,12 @@ drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state, } if (crtc) - DRM_DEBUG_ATOMIC("Link plane state %p to [CRTC:%d:%s]\n", - plane_state, crtc->base.id, crtc->name); + DRM_DEBUG_ATOMIC("Link [PLANE:%d:%s] state %p to [CRTC:%d:%s]\n", + plane->base.id, plane->name, plane_state, + crtc->base.id, crtc->name); else - DRM_DEBUG_ATOMIC("Link plane state %p to [NOCRTC]\n", - plane_state); + DRM_DEBUG_ATOMIC("Link [PLANE:%d:%s] state %p to [NOCRTC]\n", + plane->base.id, plane->name, plane_state); return 0; } @@ -1481,12 +1506,15 @@ void drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state, struct drm_framebuffer *fb) { + struct drm_plane *plane = plane_state->plane; + if (fb) - DRM_DEBUG_ATOMIC("Set [FB:%d] for plane state %p\n", - fb->base.id, plane_state); - else - DRM_DEBUG_ATOMIC("Set [NOFB] for plane state %p\n", + DRM_DEBUG_ATOMIC("Set [FB:%d] for [PLANE:%d:%s] state %p\n", + fb->base.id, plane->base.id, plane->name, plane_state); + else + DRM_DEBUG_ATOMIC("Set [NOFB] for [PLANE:%d:%s] state %p\n", + plane->base.id, plane->name, plane_state); drm_framebuffer_assign(&plane_state->fb, fb); } @@ -1547,6 +1575,7 @@ int drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state, struct drm_crtc *crtc) { + struct drm_connector *connector = conn_state->connector; struct drm_crtc_state *crtc_state; if (conn_state->crtc == crtc) @@ -1574,10 +1603,12 @@ drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state, drm_connector_get(conn_state->connector); conn_state->crtc = crtc; - DRM_DEBUG_ATOMIC("Link connector state %p to [CRTC:%d:%s]\n", + DRM_DEBUG_ATOMIC("Link [CONNECTOR:%d:%s] state %p to [CRTC:%d:%s]\n", + connector->base.id, connector->name, conn_state, crtc->base.id, crtc->name); } else { - DRM_DEBUG_ATOMIC("Link connector state %p to [NOCRTC]\n", + DRM_DEBUG_ATOMIC("Link [CONNECTOR:%d:%s] state %p to [NOCRTC]\n", + connector->base.id, connector->name, conn_state); } @@ -1673,6 +1704,9 @@ drm_atomic_add_affected_planes(struct drm_atomic_state *state, WARN_ON(!drm_atomic_get_new_crtc_state(state, crtc)); + 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) { struct drm_plane_state *plane_state = drm_atomic_get_plane_state(state, plane); -- GitLab From 6ab0edf4e79c42e3dc9c47e060a68d337af51be0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Mon, 11 Jun 2018 22:34:02 +0300 Subject: [PATCH 0399/1506] drm: Print bad user modes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Print out the modeline when we reject a bad user mode. Avoids having to guess why it was rejected. Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180611193403.16118-2-ville.syrjala@linux.intel.com Reviewed-by: Harry Wentland <harry.wentland@amd.com> --- drivers/gpu/drm/drm_atomic.c | 20 +++++++++++++++++--- drivers/gpu/drm/drm_crtc.c | 4 +++- drivers/gpu/drm/drm_crtc_internal.h | 3 +++ drivers/gpu/drm/drm_modes.c | 2 +- 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 0ae280aaa1247..0fb25bfe381d3 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -392,10 +392,24 @@ int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state, memset(&state->mode, 0, sizeof(state->mode)); if (blob) { - if (blob->length != sizeof(struct drm_mode_modeinfo) || - drm_mode_convert_umode(state->crtc->dev, &state->mode, - blob->data)) + int ret; + + if (blob->length != sizeof(struct drm_mode_modeinfo)) { + DRM_DEBUG_ATOMIC("[CRTC:%d:%s] bad mode blob length: %zu\n", + crtc->base.id, crtc->name, + blob->length); + return -EINVAL; + } + + ret = drm_mode_convert_umode(crtc->dev, + &state->mode, blob->data); + if (ret) { + DRM_DEBUG_ATOMIC("[CRTC:%d:%s] invalid mode (ret=%d, status=%s):\n", + crtc->base.id, crtc->name, + ret, drm_get_mode_status_name(state->mode.status)); + drm_mode_debug_printmodeline(&state->mode); return -EINVAL; + } state->mode_blob = drm_property_blob_get(blob); state->enable = true; diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 53828fc8d9115..163d82ac7d763 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -649,7 +649,9 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, ret = drm_mode_convert_umode(dev, mode, &crtc_req->mode); if (ret) { - DRM_DEBUG_KMS("Invalid mode\n"); + DRM_DEBUG_KMS("Invalid mode (ret=%d, status=%s)\n", + ret, drm_get_mode_status_name(mode->status)); + drm_mode_debug_printmodeline(mode); goto out; } diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index 5d307b23a4e66..34499800932a2 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -56,6 +56,9 @@ int drm_mode_setcrtc(struct drm_device *dev, int drm_modeset_register_all(struct drm_device *dev); void drm_modeset_unregister_all(struct drm_device *dev); +/* drm_modes.c */ +const char *drm_get_mode_status_name(enum drm_mode_status status); + /* IOCTLs */ int drm_mode_getresources(struct drm_device *dev, void *data, struct drm_file *file_priv); diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index c78ca0e84ffdc..7f552d5fa88ee 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -1257,7 +1257,7 @@ static const char * const drm_mode_status_names[] = { #undef MODE_STATUS -static const char *drm_get_mode_status_name(enum drm_mode_status status) +const char *drm_get_mode_status_name(enum drm_mode_status status) { int index = status + 3; -- GitLab From e89ea355966182007712c396a3b8e78255f17c32 Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe <alexandru-cosmin.gheorghe@arm.com> Date: Wed, 30 May 2018 18:30:52 +0100 Subject: [PATCH 0400/1506] drm/atomic: Set current atomic state in drm_private_state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drm_private_state has a back pointer to the drm_atomic_state, however that was not initialized in drm_atomic_get_private_obj_state after duplication, as it is the case for other drm atomic getters Signed-off-by: Alexandru Gheorghe <alexandru-cosmin.gheorghe@arm.com> Link: https://patchwork.freedesktop.org/patch/msgid/1527701452-1934-1-git-send-email-alexandru-cosmin.gheorghe@arm.com Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> --- drivers/gpu/drm/drm_atomic.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 0fb25bfe381d3..9ec5c865a043c 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1152,6 +1152,7 @@ drm_atomic_get_private_obj_state(struct drm_atomic_state *state, state->private_objs[index].old_state = obj->state; state->private_objs[index].new_state = obj_state; state->private_objs[index].ptr = obj; + obj_state->state = state; state->num_private_objs = num_objs; -- GitLab From 9378985eb05c486b32a61b69945df3297c6e854d Mon Sep 17 00:00:00 2001 From: Paulo Zanoni <paulo.r.zanoni@intel.com> Date: Thu, 14 Jun 2018 15:10:17 -0700 Subject: [PATCH 0401/1506] drm/i915/icl: implement DVFS for ICL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ICL DVFS is almost the same as CNL, except for the CDCLK/DDICLK table. Implement it just like CNL does. References: commit 48469eced282 ("drm/i915: Use cdclk_state->voltage on CNL") References: commit 53e9bf5e8159 ("drm/i915: Adjust system agent voltage on CNL if required by DDI ports") Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180614221018.19044-1-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/intel_cdclk.c | 46 ++++++++++++++++++++++++++++-- drivers/gpu/drm/i915/intel_ddi.c | 2 ++ 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_cdclk.c b/drivers/gpu/drm/i915/intel_cdclk.c index 8ed7bd052e462..bf9433d7964dc 100644 --- a/drivers/gpu/drm/i915/intel_cdclk.c +++ b/drivers/gpu/drm/i915/intel_cdclk.c @@ -1871,11 +1871,35 @@ static void icl_set_cdclk(struct drm_i915_private *dev_priv, skl_cdclk_decimal(cdclk)); mutex_lock(&dev_priv->pcu_lock); - /* TODO: add proper DVFS support. */ - sandybridge_pcode_write(dev_priv, SKL_PCODE_CDCLK_CONTROL, 2); + sandybridge_pcode_write(dev_priv, SKL_PCODE_CDCLK_CONTROL, + cdclk_state->voltage_level); mutex_unlock(&dev_priv->pcu_lock); intel_update_cdclk(dev_priv); + + /* + * Can't read out the voltage level :( + * Let's just assume everything is as expected. + */ + dev_priv->cdclk.hw.voltage_level = cdclk_state->voltage_level; +} + +static u8 icl_calc_voltage_level(int cdclk) +{ + switch (cdclk) { + case 50000: + case 307200: + case 312000: + return 0; + case 556800: + case 552000: + return 1; + default: + MISSING_CASE(cdclk); + case 652800: + case 648000: + return 2; + } } static void icl_get_cdclk(struct drm_i915_private *dev_priv, @@ -1909,7 +1933,7 @@ static void icl_get_cdclk(struct drm_i915_private *dev_priv, */ cdclk_state->vco = 0; cdclk_state->cdclk = cdclk_state->bypass; - return; + goto out; } cdclk_state->vco = (val & BXT_DE_PLL_RATIO_MASK) * cdclk_state->ref; @@ -1918,6 +1942,14 @@ static void icl_get_cdclk(struct drm_i915_private *dev_priv, WARN_ON((val & BXT_CDCLK_CD2X_DIV_SEL_MASK) != 0); cdclk_state->cdclk = cdclk_state->vco / 2; + +out: + /* + * Can't read this out :( Let's assume it's + * at least what the CDCLK frequency requires. + */ + cdclk_state->voltage_level = + icl_calc_voltage_level(cdclk_state->cdclk); } /** @@ -1960,6 +1992,8 @@ void icl_init_cdclk(struct drm_i915_private *dev_priv) sanitized_state.cdclk = icl_calc_cdclk(0, sanitized_state.ref); sanitized_state.vco = icl_calc_cdclk_pll_vco(dev_priv, sanitized_state.cdclk); + sanitized_state.voltage_level = + icl_calc_voltage_level(sanitized_state.cdclk); icl_set_cdclk(dev_priv, &sanitized_state); } @@ -1977,6 +2011,7 @@ void icl_uninit_cdclk(struct drm_i915_private *dev_priv) cdclk_state.cdclk = cdclk_state.bypass; cdclk_state.vco = 0; + cdclk_state.voltage_level = icl_calc_voltage_level(cdclk_state.cdclk); icl_set_cdclk(dev_priv, &cdclk_state); } @@ -2480,6 +2515,9 @@ static int icl_modeset_calc_cdclk(struct drm_atomic_state *state) intel_state->cdclk.logical.vco = vco; intel_state->cdclk.logical.cdclk = cdclk; + intel_state->cdclk.logical.voltage_level = + max(icl_calc_voltage_level(cdclk), + cnl_compute_min_voltage_level(intel_state)); if (!intel_state->active_crtcs) { cdclk = icl_calc_cdclk(0, ref); @@ -2487,6 +2525,8 @@ static int icl_modeset_calc_cdclk(struct drm_atomic_state *state) intel_state->cdclk.actual.vco = vco; intel_state->cdclk.actual.cdclk = cdclk; + intel_state->cdclk.actual.voltage_level = + icl_calc_voltage_level(cdclk); } else { intel_state->cdclk.actual = intel_state->cdclk.logical; } diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index ce153b11c7656..044fe1fb98727 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -3078,6 +3078,8 @@ void intel_ddi_compute_min_voltage_level(struct drm_i915_private *dev_priv, { if (IS_CANNONLAKE(dev_priv) && crtc_state->port_clock > 594000) crtc_state->min_voltage_level = 2; + else if (IS_ICELAKE(dev_priv) && crtc_state->port_clock > 594000) + crtc_state->min_voltage_level = 1; } void intel_ddi_get_config(struct intel_encoder *encoder, -- GitLab From f677bd558de2e98b70b7f8c522024b26d2d1120d Mon Sep 17 00:00:00 2001 From: Paulo Zanoni <paulo.r.zanoni@intel.com> Date: Thu, 14 Jun 2018 15:10:18 -0700 Subject: [PATCH 0402/1506] drm/i915/icl: update VBT's child_device_config flags2 field Some bits from the flags2 field are going to be used in the next patches, so replace the whole-byte definition with the actual bits and document their versions. This patch is based on a patch by Animesh Manna. Cc: Animesh Manna <animesh.manna@intel.com> Credits-to: Animesh Manna <animesh.manna@intel.com> Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180614221018.19044-2-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/intel_vbt_defs.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_vbt_defs.h b/drivers/gpu/drm/i915/intel_vbt_defs.h index c132d0c3a500c..c614c9f3f28bc 100644 --- a/drivers/gpu/drm/i915/intel_vbt_defs.h +++ b/drivers/gpu/drm/i915/intel_vbt_defs.h @@ -420,7 +420,9 @@ struct child_device_config { u16 extended_type; u8 dvo_function; u8 dp_usb_type_c:1; /* 195 */ - u8 flags2_reserved:7; /* 195 */ + u8 tbt:1; /* 209 */ + u8 flags2_reserved:2; /* 195 */ + u8 dp_port_trace_length:4; /* 209 */ u8 dp_gpio_index; /* 195 */ u16 dp_gpio_pin_num; /* 195 */ u8 dp_iboost_level:4; /* 196 */ -- GitLab From ebfb081edc8afd250a6d290c37481bfb2262e7cb Mon Sep 17 00:00:00 2001 From: Julia Lawall <Julia.Lawall@lip6.fr> Date: Wed, 23 May 2018 21:07:16 +0200 Subject: [PATCH 0403/1506] drm/rockchip: lvds: add missing of_node_put The device node iterators perform an of_node_get on each iteration, so a jump out of the loop requires an of_node_put. The semantic patch that fixes this problem is as follows (http://coccinelle.lip6.fr): // <smpl> @@ expression root,e; local idexpression child; iterator name for_each_child_of_node; @@ for_each_child_of_node(root, child) { ... when != of_node_put(child) when != e = child + of_node_put(child); ? break; ... } ... when != child // </smpl> Fixes: 34cc0aa25456 ("drm/rockchip: Add support for Rockchip Soc LVDS") Cc: stable@vger.kernel.org Signed-off-by: Julia Lawall <Julia.Lawall@lip6.fr> Signed-off-by: Heiko Stuebner <heiko@sntech.de> Link: https://patchwork.freedesktop.org/patch/msgid/1527102436-13447-6-git-send-email-Julia.Lawall@lip6.fr --- drivers/gpu/drm/rockchip/rockchip_lvds.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c index 4bd94b167d2cd..b3f6f524b4020 100644 --- a/drivers/gpu/drm/rockchip/rockchip_lvds.c +++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c @@ -363,8 +363,10 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master, of_property_read_u32(endpoint, "reg", &endpoint_id); ret = drm_of_find_panel_or_bridge(dev->of_node, 1, endpoint_id, &lvds->panel, &lvds->bridge); - if (!ret) + if (!ret) { + of_node_put(endpoint); break; + } } if (!child_count) { DRM_DEV_ERROR(dev, "lvds port does not have any children\n"); -- GitLab From 0baf5cc971fc21ff55d75183dd1fe3afb505bff8 Mon Sep 17 00:00:00 2001 From: Lin Huang <hl@rock-chips.com> Date: Tue, 22 May 2018 16:53:41 +0800 Subject: [PATCH 0404/1506] drm/rockchip: cnd-dp: adjust spdif register setting We use jitter bypass mode for spdif, so do not need to set jitter mode related bit in SPDIF_CTRL_ADDR register. But of course we need to keep the SPDIF_ENABLE bit. Signed-off-by: Chris Zhong <zyw@rock-chips.com> Signed-off-by: Lin Huang <hl@rock-chips.com> Signed-off-by: Heiko Stuebner <heiko@sntech.de> Link: https://patchwork.freedesktop.org/patch/msgid/1526979222-32478-1-git-send-email-hl@rock-chips.com --- drivers/gpu/drm/rockchip/cdn-dp-reg.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c index eb3042c6d1b20..3105965fc2603 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-reg.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c @@ -792,7 +792,6 @@ int cdn_dp_config_video(struct cdn_dp_device *dp) int cdn_dp_audio_stop(struct cdn_dp_device *dp, struct audio_info *audio) { - u32 val; int ret; ret = cdn_dp_reg_write(dp, AUDIO_PACK_CONTROL, 0); @@ -801,11 +800,7 @@ int cdn_dp_audio_stop(struct cdn_dp_device *dp, struct audio_info *audio) return ret; } - val = SPDIF_AVG_SEL | SPDIF_JITTER_BYPASS; - val |= SPDIF_FIFO_MID_RANGE(0xe0); - val |= SPDIF_JITTER_THRSH(0xe0); - val |= SPDIF_JITTER_AVG_WIN(7); - writel(val, dp->regs + SPDIF_CTRL_ADDR); + writel(0, dp->regs + SPDIF_CTRL_ADDR); /* clearn the audio config and reset */ writel(0, dp->regs + AUDIO_SRC_CNTL); @@ -929,12 +924,6 @@ static void cdn_dp_audio_config_spdif(struct cdn_dp_device *dp) { u32 val; - val = SPDIF_AVG_SEL | SPDIF_JITTER_BYPASS; - val |= SPDIF_FIFO_MID_RANGE(0xe0); - val |= SPDIF_JITTER_THRSH(0xe0); - val |= SPDIF_JITTER_AVG_WIN(7); - writel(val, dp->regs + SPDIF_CTRL_ADDR); - writel(SYNC_WR_TO_CH_ZERO, dp->regs + FIFO_CNTL); val = MAX_NUM_CH(2) | AUDIO_TYPE_LPCM | CFG_SUB_PCKT_NUM(4); @@ -942,9 +931,6 @@ static void cdn_dp_audio_config_spdif(struct cdn_dp_device *dp) writel(SMPL2PKT_EN, dp->regs + SMPL2PKT_CNTL); val = SPDIF_ENABLE | SPDIF_AVG_SEL | SPDIF_JITTER_BYPASS; - val |= SPDIF_FIFO_MID_RANGE(0xe0); - val |= SPDIF_JITTER_THRSH(0xe0); - val |= SPDIF_JITTER_AVG_WIN(7); writel(val, dp->regs + SPDIF_CTRL_ADDR); clk_prepare_enable(dp->spdif_clk); -- GitLab From ba1f665f161ce112a2703649317bfdc9b6521613 Mon Sep 17 00:00:00 2001 From: Haneen Mohammed <hamohammed.sa@gmail.com> Date: Fri, 25 May 2018 04:25:55 +0300 Subject: [PATCH 0405/1506] drm: Add checks for atomic_[duplicate/destroy]_state with atomic drivers This patch add checks for atomic_[duplicate/destroy]_state of drm_[connector/crtc/plane]_funcs for atomic drivers in the relevant drm_*_init functions since these callback are mandatory for atomic drivers. Update the kerneldoc comments for those callbacks. Signed-off-by: Haneen Mohammed <hamohammed.sa@gmail.com> Reviewed-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180525012555.GA8448@haneen-vb --- drivers/gpu/drm/drm_connector.c | 4 ++++ drivers/gpu/drm/drm_crtc.c | 4 ++++ drivers/gpu/drm/drm_plane.c | 4 ++++ include/drm/drm_connector.h | 4 ++++ include/drm/drm_crtc.h | 4 ++++ include/drm/drm_plane.h | 4 ++++ 6 files changed, 24 insertions(+) diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index 002b244391f9f..549b89501e01f 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -195,6 +195,10 @@ int drm_connector_init(struct drm_device *dev, struct ida *connector_ida = &drm_connector_enum_list[connector_type].ida; + WARN_ON(drm_drv_uses_atomic_modeset(dev) && + (!funcs->atomic_destroy_state || + !funcs->atomic_duplicate_state)); + ret = __drm_mode_object_add(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR, false, drm_connector_free); diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 163d82ac7d763..f45e7a8d4acd6 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -286,6 +286,10 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, if (WARN_ON(config->num_crtc >= 32)) return -EINVAL; + WARN_ON(drm_drv_uses_atomic_modeset(dev) && + (!funcs->atomic_destroy_state || + !funcs->atomic_duplicate_state)); + crtc->dev = dev; crtc->funcs = funcs; diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index 534b579335765..df0b4ebbedbf4 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -177,6 +177,10 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, if (WARN_ON(config->num_total_plane >= 32)) return -EINVAL; + WARN_ON(drm_drv_uses_atomic_modeset(dev) && + (!funcs->atomic_destroy_state || + !funcs->atomic_duplicate_state)); + ret = drm_mode_object_add(dev, &plane->base, DRM_MODE_OBJECT_PLANE); if (ret) return ret; diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index ee4c48218c85b..c5797c24edd3d 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -616,6 +616,8 @@ struct drm_connector_funcs { * cleaned up by calling the @atomic_destroy_state hook in this * structure. * + * This callback is mandatory for atomic drivers. + * * Atomic drivers which don't subclass &struct drm_connector_state should use * drm_atomic_helper_connector_duplicate_state(). Drivers that subclass the * state structure to extend it with driver-private state should use @@ -642,6 +644,8 @@ struct drm_connector_funcs { * * Destroy a state duplicated with @atomic_duplicate_state and release * or unreference all resources it references + * + * This callback is mandatory for atomic drivers. */ void (*atomic_destroy_state)(struct drm_connector *connector, struct drm_connector_state *state); diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 5cf7adeae6a57..23eddbccab10f 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -506,6 +506,8 @@ struct drm_crtc_funcs { * cleaned up by calling the @atomic_destroy_state hook in this * structure. * + * This callback is mandatory for atomic drivers. + * * Atomic drivers which don't subclass &struct drm_crtc_state should use * drm_atomic_helper_crtc_duplicate_state(). Drivers that subclass the * state structure to extend it with driver-private state should use @@ -532,6 +534,8 @@ struct drm_crtc_funcs { * * Destroy a state duplicated with @atomic_duplicate_state and release * or unreference all resources it references + * + * This callback is mandatory for atomic drivers. */ void (*atomic_destroy_state)(struct drm_crtc *crtc, struct drm_crtc_state *state); diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index 14b1607aba4bb..7d4d6c7f0afdb 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -288,6 +288,8 @@ struct drm_plane_funcs { * cleaned up by calling the @atomic_destroy_state hook in this * structure. * + * This callback is mandatory for atomic drivers. + * * Atomic drivers which don't subclass &struct drm_plane_state should use * drm_atomic_helper_plane_duplicate_state(). Drivers that subclass the * state structure to extend it with driver-private state should use @@ -314,6 +316,8 @@ struct drm_plane_funcs { * * Destroy a state duplicated with @atomic_duplicate_state and release * or unreference all resources it references + * + * This callback is mandatory for atomic drivers. */ void (*atomic_destroy_state)(struct drm_plane *plane, struct drm_plane_state *state); -- GitLab From b77422f80337d363eed60c8c48db9cb6e33085c9 Mon Sep 17 00:00:00 2001 From: Kenneth Graunke <kenneth@whitecape.org> Date: Fri, 15 Jun 2018 20:06:05 +0100 Subject: [PATCH 0406/1506] drm/i915: Enable provoking vertex fix on Gen9 systems. The SF and clipper units mishandle the provoking vertex in some cases, which can cause misrendering with shaders that use flat shaded inputs. There are chicken bits in 3D_CHICKEN3 (for SF) and FF_SLICE_CHICKEN (for the clipper) that work around the issue. These registers are unfortunately not part of the logical context (even the power context), and so we must reload them every time we start executing in a context. Bugzilla: https://bugs.freedesktop.org/103047 Signed-off-by: Kenneth Graunke <kenneth@whitecape.org> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20180615190605.16238-1-chris@chris-wilson.co.uk Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: stable@vger.kernel.org --- drivers/gpu/drm/i915/i915_reg.h | 5 +++++ drivers/gpu/drm/i915/intel_lrc.c | 12 +++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index b8c0ebd508896..54ec7ab57ce83 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2432,12 +2432,17 @@ enum i915_power_well_id { #define _3D_CHICKEN _MMIO(0x2084) #define _3D_CHICKEN_HIZ_PLANE_DISABLE_MSAA_4X_SNB (1 << 10) #define _3D_CHICKEN2 _MMIO(0x208c) + +#define FF_SLICE_CHICKEN _MMIO(0x2088) +#define FF_SLICE_CHICKEN_CL_PROVOKING_VERTEX_FIX (1 << 1) + /* Disables pipelining of read flushes past the SF-WIZ interface. * Required on all Ironlake steppings according to the B-Spec, but the * particular danger of not doing so is not specified. */ # define _3D_CHICKEN2_WM_READ_PIPELINED (1 << 14) #define _3D_CHICKEN3 _MMIO(0x2090) +#define _3D_CHICKEN_SF_PROVOKING_VERTEX_FIX (1 << 12) #define _3D_CHICKEN_SF_DISABLE_OBJEND_CULL (1 << 10) #define _3D_CHICKEN3_AA_LINE_QUALITY_FIX_ENABLE (1 << 5) #define _3D_CHICKEN3_SF_DISABLE_FASTCLIP_CULL (1 << 5) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 50e141ca1f7a0..b6c230bd7d6ee 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1573,11 +1573,21 @@ static u32 *gen9_init_indirectctx_bb(struct intel_engine_cs *engine, u32 *batch) /* WaFlushCoherentL3CacheLinesAtContextSwitch:skl,bxt,glk */ batch = gen8_emit_flush_coherentl3_wa(engine, batch); + *batch++ = MI_LOAD_REGISTER_IMM(3); + /* WaDisableGatherAtSetShaderCommonSlice:skl,bxt,kbl,glk */ - *batch++ = MI_LOAD_REGISTER_IMM(1); *batch++ = i915_mmio_reg_offset(COMMON_SLICE_CHICKEN2); *batch++ = _MASKED_BIT_DISABLE( GEN9_DISABLE_GATHER_AT_SET_SHADER_COMMON_SLICE); + + /* BSpec: 11391 */ + *batch++ = i915_mmio_reg_offset(FF_SLICE_CHICKEN); + *batch++ = _MASKED_BIT_ENABLE(FF_SLICE_CHICKEN_CL_PROVOKING_VERTEX_FIX); + + /* BSpec: 11299 */ + *batch++ = i915_mmio_reg_offset(_3D_CHICKEN3); + *batch++ = _MASKED_BIT_ENABLE(_3D_CHICKEN_SF_PROVOKING_VERTEX_FIX); + *batch++ = MI_NOOP; /* WaClearSlmSpaceAtContextSwitch:kbl */ -- GitLab From 4fdd5b4e9aba5fbbc6d3072a5a87fa1d3f3fc030 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Sat, 16 Jun 2018 21:25:34 +0100 Subject: [PATCH 0407/1506] drm/i915: Fix fallout of fake reset along resume commit b2209e62a450 ("drm/i915/execlists: Reset the CSB head tracking on reset/sanitization") and commit 1288786b18f7 ("drm/i915: Move GEM sanitize from resume_early to resume") show the conflicting requirements on the code. We must reset the GPU before trashing live state on a fast resume (hibernation debug, or error paths), but we must only reset our state tracking iff the GPU is reset (or power cycled). This is tricky if we are disabling GPU reset to simulate broken hardware; we reset our state tracking but the GPU is left intact and recovers from its stale state. v2: Again without the assertion for forcewake, no longer required since commit b3ee09a4de33 ("drm/i915/ringbuffer: Fix context restore upon reset") as the contexts are reset from the CS ensuring everything is powered up. Fixes: b2209e62a450 ("drm/i915/execlists: Reset the CSB head tracking on reset/sanitization") Fixes: 1288786b18f7 ("drm/i915: Move GEM sanitize from resume_early to resume") Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180616202534.18767-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_drv.c | 2 ++ drivers/gpu/drm/i915/i915_gem.c | 14 +++++--------- drivers/gpu/drm/i915/intel_engine_cs.c | 22 ++++++++++++++++++++++ drivers/gpu/drm/i915/intel_ringbuffer.c | 8 -------- drivers/gpu/drm/i915/intel_ringbuffer.h | 2 ++ 5 files changed, 31 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index a9c8c66bb5258..33453d56c3865 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1841,6 +1841,8 @@ static int i915_drm_resume_early(struct drm_device *dev) else intel_display_set_init_power(dev_priv, true); + intel_engines_sanitize(dev_priv); + enable_rpm_wakeref_asserts(dev_priv); out: diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 5155e458b11ea..822abf444378f 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4990,8 +4990,7 @@ void __i915_gem_object_release_unless_active(struct drm_i915_gem_object *obj) void i915_gem_sanitize(struct drm_i915_private *i915) { - struct intel_engine_cs *engine; - enum intel_engine_id id; + int err; GEM_TRACE("\n"); @@ -5017,14 +5016,11 @@ void i915_gem_sanitize(struct drm_i915_private *i915) * it may impact the display and we are uncertain about the stability * of the reset, so this could be applied to even earlier gen. */ + err = -ENODEV; if (INTEL_GEN(i915) >= 5 && intel_has_gpu_reset(i915)) - WARN_ON(intel_gpu_reset(i915, ALL_ENGINES)); - - /* Reset the submission backend after resume as well as the GPU reset */ - for_each_engine(engine, i915, id) { - if (engine->reset.reset) - engine->reset.reset(engine, NULL); - } + err = WARN_ON(intel_gpu_reset(i915, ALL_ENGINES)); + if (!err) + intel_engines_sanitize(i915); intel_uncore_forcewake_put(i915, FORCEWAKE_ALL); intel_runtime_pm_put(i915); diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index 13bb8c7d2621b..32bf3a408d464 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -1077,6 +1077,28 @@ void intel_engines_reset_default_submission(struct drm_i915_private *i915) engine->set_default_submission(engine); } +/** + * intel_engines_sanitize: called after the GPU has lost power + * @i915: the i915 device + * + * Anytime we reset the GPU, either with an explicit GPU reset or through a + * PCI power cycle, the GPU loses state and we must reset our state tracking + * to match. Note that calling intel_engines_sanitize() if the GPU has not + * been reset results in much confusion! + */ +void intel_engines_sanitize(struct drm_i915_private *i915) +{ + struct intel_engine_cs *engine; + enum intel_engine_id id; + + GEM_TRACE("\n"); + + for_each_engine(engine, i915, id) { + if (engine->reset.reset) + engine->reset.reset(engine, NULL); + } +} + /** * intel_engines_park: called when the GT is transitioning from busy->idle * @i915: the i915 device diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 6a937a8966519..4dae23885006b 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -563,14 +563,6 @@ static void reset_ring(struct intel_engine_cs *engine, struct i915_request *rq) { GEM_TRACE("%s seqno=%x\n", engine->name, rq ? rq->global_seqno : 0); - /* - * RC6 must be prevented until the reset is complete and the engine - * reinitialised. If it occurs in the middle of this sequence, the - * state written to/loaded from the power context is ill-defined (e.g. - * the PP_BASE_DIR may be lost). - */ - assert_forcewakes_active(engine->i915, FORCEWAKE_ALL); - /* * Try to restore the logical GPU state to match the continuation * of the request queue. If we skip the context/PD restore, then diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 4003f3ebe3d1b..a0bc7a8222b40 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -1052,6 +1052,8 @@ gen8_emit_ggtt_write(u32 *cs, u32 value, u32 gtt_offset) return cs; } +void intel_engines_sanitize(struct drm_i915_private *i915); + bool intel_engine_is_idle(struct intel_engine_cs *engine); bool intel_engines_are_idle(struct drm_i915_private *dev_priv); -- GitLab From 0ede01418854664526541eed7164c2e77df1646c Mon Sep 17 00:00:00 2001 From: Jani Nikula <jani.nikula@intel.com> Date: Tue, 12 Jun 2018 12:19:29 +0300 Subject: [PATCH 0408/1506] drm/i915/vbt: switch to kernel unsigned int types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have fairly mixed uintN_t vs. uN usage throughout the driver, but try to stick to kernel types at least where it's more prevalent. Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/ed5de29c280797b20eb625d52592dcbba8326684.1528794959.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_bios.c | 4 ++-- drivers/gpu/drm/i915/intel_vbt_defs.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 18b9e04441169..62a53eb89b6bd 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -652,7 +652,7 @@ parse_edp(struct drm_i915_private *dev_priv, const struct bdb_header *bdb) } if (bdb->version >= 173) { - uint8_t vswing; + u8 vswing; /* Don't read from VBT if module parameter has valid value*/ if (i915_modparams.edp_vswing) { @@ -964,7 +964,7 @@ static int goto_next_sequence_v3(const u8 *data, int index, int total) * includes MIPI_SEQ_ELEM_END byte, excludes the final MIPI_SEQ_END * byte. */ - size_of_sequence = *((const uint32_t *)(data + index)); + size_of_sequence = *((const u32 *)(data + index)); index += 4; seq_end = index + size_of_sequence; diff --git a/drivers/gpu/drm/i915/intel_vbt_defs.h b/drivers/gpu/drm/i915/intel_vbt_defs.h index c614c9f3f28bc..bba98cf83cbd9 100644 --- a/drivers/gpu/drm/i915/intel_vbt_defs.h +++ b/drivers/gpu/drm/i915/intel_vbt_defs.h @@ -456,7 +456,7 @@ struct bdb_general_definitions { * number = (block_size - sizeof(bdb_general_definitions))/ * defs->child_dev_size; */ - uint8_t devices[0]; + u8 devices[0]; } __packed; /* Mask for DRRS / Panel Channel / SSC / BLT control bits extraction */ -- GitLab From faa087c476a3bc6bbbb8600043eb53733233e7c5 Mon Sep 17 00:00:00 2001 From: Jani Nikula <jani.nikula@intel.com> Date: Tue, 12 Jun 2018 12:19:30 +0300 Subject: [PATCH 0409/1506] drm/i915/hdmi: switch to kernel unsigned int types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have fairly mixed uintN_t vs. uN usage throughout the driver, but try to stick to kernel types at least where it's more prevalent. Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/d8b79de3d52e1fcaeabf3abfbb2ed99c4397ff2b.1528794959.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_hdmi.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 3dd3ee259e7fb..8398d4b317128 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -51,7 +51,7 @@ assert_hdmi_port_disabled(struct intel_hdmi *intel_hdmi) { struct drm_device *dev = intel_hdmi_to_dev(intel_hdmi); struct drm_i915_private *dev_priv = to_i915(dev); - uint32_t enabled_bits; + u32 enabled_bits; enabled_bits = HAS_DDI(dev_priv) ? DDI_BUF_CTL_ENABLE : SDVO_ENABLE; @@ -153,7 +153,7 @@ static void g4x_write_infoframe(struct drm_encoder *encoder, unsigned int type, const void *frame, ssize_t len) { - const uint32_t *data = frame; + const u32 *data = frame; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = to_i915(dev); u32 val = I915_READ(VIDEO_DIP_CTL); @@ -208,7 +208,7 @@ static void ibx_write_infoframe(struct drm_encoder *encoder, unsigned int type, const void *frame, ssize_t len) { - const uint32_t *data = frame; + const u32 *data = frame; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = to_i915(dev); struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc); @@ -268,7 +268,7 @@ static void cpt_write_infoframe(struct drm_encoder *encoder, unsigned int type, const void *frame, ssize_t len) { - const uint32_t *data = frame; + const u32 *data = frame; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = to_i915(dev); struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc); @@ -326,7 +326,7 @@ static void vlv_write_infoframe(struct drm_encoder *encoder, unsigned int type, const void *frame, ssize_t len) { - const uint32_t *data = frame; + const u32 *data = frame; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = to_i915(dev); struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc); @@ -385,7 +385,7 @@ static void hsw_write_infoframe(struct drm_encoder *encoder, unsigned int type, const void *frame, ssize_t len) { - const uint32_t *data = frame; + const u32 *data = frame; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = to_i915(dev); enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; @@ -448,7 +448,7 @@ static void intel_write_infoframe(struct drm_encoder *encoder, union hdmi_infoframe *frame) { struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); - uint8_t buffer[VIDEO_DIP_DATA_SIZE]; + u8 buffer[VIDEO_DIP_DATA_SIZE]; ssize_t len; /* see comment above for the reason for this offset */ -- GitLab From 93383b5705e689451fff99f2a6048750104982a3 Mon Sep 17 00:00:00 2001 From: Jani Nikula <jani.nikula@intel.com> Date: Tue, 12 Jun 2018 12:19:31 +0300 Subject: [PATCH 0410/1506] drm/i915/uncore: switch to kernel unsigned int types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have fairly mixed uintN_t vs. uN usage throughout the driver, but try to stick to kernel types at least where it's more prevalent. Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/4af5f30fc9665d1bed1eed09e7f749737749d739.1528794959.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_uncore.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_uncore.h b/drivers/gpu/drm/i915/intel_uncore.h index 47478d6096308..2fbe93178fb2a 100644 --- a/drivers/gpu/drm/i915/intel_uncore.h +++ b/drivers/gpu/drm/i915/intel_uncore.h @@ -67,21 +67,21 @@ struct intel_uncore_funcs { void (*force_wake_put)(struct drm_i915_private *dev_priv, enum forcewake_domains domains); - uint8_t (*mmio_readb)(struct drm_i915_private *dev_priv, - i915_reg_t r, bool trace); - uint16_t (*mmio_readw)(struct drm_i915_private *dev_priv, - i915_reg_t r, bool trace); - uint32_t (*mmio_readl)(struct drm_i915_private *dev_priv, - i915_reg_t r, bool trace); - uint64_t (*mmio_readq)(struct drm_i915_private *dev_priv, - i915_reg_t r, bool trace); + u8 (*mmio_readb)(struct drm_i915_private *dev_priv, + i915_reg_t r, bool trace); + u16 (*mmio_readw)(struct drm_i915_private *dev_priv, + i915_reg_t r, bool trace); + u32 (*mmio_readl)(struct drm_i915_private *dev_priv, + i915_reg_t r, bool trace); + u64 (*mmio_readq)(struct drm_i915_private *dev_priv, + i915_reg_t r, bool trace); void (*mmio_writeb)(struct drm_i915_private *dev_priv, - i915_reg_t r, uint8_t val, bool trace); + i915_reg_t r, u8 val, bool trace); void (*mmio_writew)(struct drm_i915_private *dev_priv, - i915_reg_t r, uint16_t val, bool trace); + i915_reg_t r, u16 val, bool trace); void (*mmio_writel)(struct drm_i915_private *dev_priv, - i915_reg_t r, uint32_t val, bool trace); + i915_reg_t r, u32 val, bool trace); }; struct intel_forcewake_range { -- GitLab From accb1eb57196adcdd47efc7ded32f356ed396b6c Mon Sep 17 00:00:00 2001 From: Jani Nikula <jani.nikula@intel.com> Date: Tue, 12 Jun 2018 12:56:21 +0300 Subject: [PATCH 0411/1506] drm/i915/dvo: switch to kernel unsigned int types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have fairly mixed uintN_t vs. uN usage throughout the driver, but try to stick to kernel types at least where it's more prevalent. v2: fix checkpatch warning on indentation Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180612095621.21101-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/dvo_ch7017.c | 20 +++++++------- drivers/gpu/drm/i915/dvo_ch7xxx.c | 22 ++++++++-------- drivers/gpu/drm/i915/dvo_ivch.c | 26 +++++++++--------- drivers/gpu/drm/i915/dvo_ns2501.c | 44 +++++++++++++++---------------- drivers/gpu/drm/i915/dvo_sil164.c | 10 +++---- drivers/gpu/drm/i915/dvo_tfp410.c | 16 +++++------ drivers/gpu/drm/i915/intel_dvo.c | 2 +- 7 files changed, 70 insertions(+), 70 deletions(-) diff --git a/drivers/gpu/drm/i915/dvo_ch7017.c b/drivers/gpu/drm/i915/dvo_ch7017.c index 80b3e16cf48c0..caac9942e1e3a 100644 --- a/drivers/gpu/drm/i915/dvo_ch7017.c +++ b/drivers/gpu/drm/i915/dvo_ch7017.c @@ -159,7 +159,7 @@ #define CH7017_BANG_LIMIT_CONTROL 0x7f struct ch7017_priv { - uint8_t dummy; + u8 dummy; }; static void ch7017_dump_regs(struct intel_dvo_device *dvo); @@ -186,7 +186,7 @@ static bool ch7017_read(struct intel_dvo_device *dvo, u8 addr, u8 *val) static bool ch7017_write(struct intel_dvo_device *dvo, u8 addr, u8 val) { - uint8_t buf[2] = { addr, val }; + u8 buf[2] = { addr, val }; struct i2c_msg msg = { .addr = dvo->slave_addr, .flags = 0, @@ -258,11 +258,11 @@ static void ch7017_mode_set(struct intel_dvo_device *dvo, const struct drm_display_mode *mode, const struct drm_display_mode *adjusted_mode) { - uint8_t lvds_pll_feedback_div, lvds_pll_vco_control; - uint8_t outputs_enable, lvds_control_2, lvds_power_down; - uint8_t horizontal_active_pixel_input; - uint8_t horizontal_active_pixel_output, vertical_active_line_output; - uint8_t active_input_line_output; + u8 lvds_pll_feedback_div, lvds_pll_vco_control; + u8 outputs_enable, lvds_control_2, lvds_power_down; + u8 horizontal_active_pixel_input; + u8 horizontal_active_pixel_output, vertical_active_line_output; + u8 active_input_line_output; DRM_DEBUG_KMS("Registers before mode setting\n"); ch7017_dump_regs(dvo); @@ -333,7 +333,7 @@ static void ch7017_mode_set(struct intel_dvo_device *dvo, /* set the CH7017 power state */ static void ch7017_dpms(struct intel_dvo_device *dvo, bool enable) { - uint8_t val; + u8 val; ch7017_read(dvo, CH7017_LVDS_POWER_DOWN, &val); @@ -361,7 +361,7 @@ static void ch7017_dpms(struct intel_dvo_device *dvo, bool enable) static bool ch7017_get_hw_state(struct intel_dvo_device *dvo) { - uint8_t val; + u8 val; ch7017_read(dvo, CH7017_LVDS_POWER_DOWN, &val); @@ -373,7 +373,7 @@ static bool ch7017_get_hw_state(struct intel_dvo_device *dvo) static void ch7017_dump_regs(struct intel_dvo_device *dvo) { - uint8_t val; + u8 val; #define DUMP(reg) \ do { \ diff --git a/drivers/gpu/drm/i915/dvo_ch7xxx.c b/drivers/gpu/drm/i915/dvo_ch7xxx.c index 7aeeffd2428b6..397ac52337267 100644 --- a/drivers/gpu/drm/i915/dvo_ch7xxx.c +++ b/drivers/gpu/drm/i915/dvo_ch7xxx.c @@ -85,7 +85,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ static struct ch7xxx_id_struct { - uint8_t vid; + u8 vid; char *name; } ch7xxx_ids[] = { { CH7011_VID, "CH7011" }, @@ -96,7 +96,7 @@ static struct ch7xxx_id_struct { }; static struct ch7xxx_did_struct { - uint8_t did; + u8 did; char *name; } ch7xxx_dids[] = { { CH7xxx_DID, "CH7XXX" }, @@ -107,7 +107,7 @@ struct ch7xxx_priv { bool quiet; }; -static char *ch7xxx_get_id(uint8_t vid) +static char *ch7xxx_get_id(u8 vid) { int i; @@ -119,7 +119,7 @@ static char *ch7xxx_get_id(uint8_t vid) return NULL; } -static char *ch7xxx_get_did(uint8_t did) +static char *ch7xxx_get_did(u8 did) { int i; @@ -132,7 +132,7 @@ static char *ch7xxx_get_did(uint8_t did) } /** Reads an 8 bit register */ -static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch) +static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, u8 *ch) { struct ch7xxx_priv *ch7xxx = dvo->dev_priv; struct i2c_adapter *adapter = dvo->i2c_bus; @@ -170,11 +170,11 @@ static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch) } /** Writes an 8 bit register */ -static bool ch7xxx_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch) +static bool ch7xxx_writeb(struct intel_dvo_device *dvo, int addr, u8 ch) { struct ch7xxx_priv *ch7xxx = dvo->dev_priv; struct i2c_adapter *adapter = dvo->i2c_bus; - uint8_t out_buf[2]; + u8 out_buf[2]; struct i2c_msg msg = { .addr = dvo->slave_addr, .flags = 0, @@ -201,7 +201,7 @@ static bool ch7xxx_init(struct intel_dvo_device *dvo, { /* this will detect the CH7xxx chip on the specified i2c bus */ struct ch7xxx_priv *ch7xxx; - uint8_t vendor, device; + u8 vendor, device; char *name, *devid; ch7xxx = kzalloc(sizeof(struct ch7xxx_priv), GFP_KERNEL); @@ -244,7 +244,7 @@ static bool ch7xxx_init(struct intel_dvo_device *dvo, static enum drm_connector_status ch7xxx_detect(struct intel_dvo_device *dvo) { - uint8_t cdet, orig_pm, pm; + u8 cdet, orig_pm, pm; ch7xxx_readb(dvo, CH7xxx_PM, &orig_pm); @@ -276,7 +276,7 @@ static void ch7xxx_mode_set(struct intel_dvo_device *dvo, const struct drm_display_mode *mode, const struct drm_display_mode *adjusted_mode) { - uint8_t tvco, tpcp, tpd, tlpf, idf; + u8 tvco, tpcp, tpd, tlpf, idf; if (mode->clock <= 65000) { tvco = 0x23; @@ -336,7 +336,7 @@ static void ch7xxx_dump_regs(struct intel_dvo_device *dvo) int i; for (i = 0; i < CH7xxx_NUM_REGS; i++) { - uint8_t val; + u8 val; if ((i % 8) == 0) DRM_DEBUG_KMS("\n %02X: ", i); ch7xxx_readb(dvo, i, &val); diff --git a/drivers/gpu/drm/i915/dvo_ivch.c b/drivers/gpu/drm/i915/dvo_ivch.c index c73aff163908a..24278cc490905 100644 --- a/drivers/gpu/drm/i915/dvo_ivch.c +++ b/drivers/gpu/drm/i915/dvo_ivch.c @@ -161,7 +161,7 @@ * instead. The following list contains all registers that * require saving. */ -static const uint16_t backup_addresses[] = { +static const u16 backup_addresses[] = { 0x11, 0x12, 0x18, 0x19, 0x1a, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, @@ -174,11 +174,11 @@ static const uint16_t backup_addresses[] = { struct ivch_priv { bool quiet; - uint16_t width, height; + u16 width, height; /* Register backup */ - uint16_t reg_backup[ARRAY_SIZE(backup_addresses)]; + u16 reg_backup[ARRAY_SIZE(backup_addresses)]; }; @@ -188,7 +188,7 @@ static void ivch_dump_regs(struct intel_dvo_device *dvo); * * Each of the 256 registers are 16 bits long. */ -static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data) +static bool ivch_read(struct intel_dvo_device *dvo, int addr, u16 *data) { struct ivch_priv *priv = dvo->dev_priv; struct i2c_adapter *adapter = dvo->i2c_bus; @@ -231,7 +231,7 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data) } /* Writes a 16-bit register on the ivch */ -static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data) +static bool ivch_write(struct intel_dvo_device *dvo, int addr, u16 data) { struct ivch_priv *priv = dvo->dev_priv; struct i2c_adapter *adapter = dvo->i2c_bus; @@ -263,7 +263,7 @@ static bool ivch_init(struct intel_dvo_device *dvo, struct i2c_adapter *adapter) { struct ivch_priv *priv; - uint16_t temp; + u16 temp; int i; priv = kzalloc(sizeof(struct ivch_priv), GFP_KERNEL); @@ -342,7 +342,7 @@ static void ivch_reset(struct intel_dvo_device *dvo) static void ivch_dpms(struct intel_dvo_device *dvo, bool enable) { int i; - uint16_t vr01, vr30, backlight; + u16 vr01, vr30, backlight; ivch_reset(dvo); @@ -379,7 +379,7 @@ static void ivch_dpms(struct intel_dvo_device *dvo, bool enable) static bool ivch_get_hw_state(struct intel_dvo_device *dvo) { - uint16_t vr01; + u16 vr01; ivch_reset(dvo); @@ -398,9 +398,9 @@ static void ivch_mode_set(struct intel_dvo_device *dvo, const struct drm_display_mode *adjusted_mode) { struct ivch_priv *priv = dvo->dev_priv; - uint16_t vr40 = 0; - uint16_t vr01 = 0; - uint16_t vr10; + u16 vr40 = 0; + u16 vr01 = 0; + u16 vr10; ivch_reset(dvo); @@ -416,7 +416,7 @@ static void ivch_mode_set(struct intel_dvo_device *dvo, if (mode->hdisplay != adjusted_mode->crtc_hdisplay || mode->vdisplay != adjusted_mode->crtc_vdisplay) { - uint16_t x_ratio, y_ratio; + u16 x_ratio, y_ratio; vr01 |= VR01_PANEL_FIT_ENABLE; vr40 |= VR40_CLOCK_GATING_ENABLE; @@ -438,7 +438,7 @@ static void ivch_mode_set(struct intel_dvo_device *dvo, static void ivch_dump_regs(struct intel_dvo_device *dvo) { - uint16_t val; + u16 val; ivch_read(dvo, VR00, &val); DRM_DEBUG_KMS("VR00: 0x%04x\n", val); diff --git a/drivers/gpu/drm/i915/dvo_ns2501.c b/drivers/gpu/drm/i915/dvo_ns2501.c index 2379c33cfe51e..c584e01dc8dc3 100644 --- a/drivers/gpu/drm/i915/dvo_ns2501.c +++ b/drivers/gpu/drm/i915/dvo_ns2501.c @@ -191,8 +191,8 @@ enum { }; struct ns2501_reg { - uint8_t offset; - uint8_t value; + u8 offset; + u8 value; }; /* @@ -202,23 +202,23 @@ struct ns2501_reg { * read all this with a grain of salt. */ struct ns2501_configuration { - uint8_t sync; /* configuration of the C0 register */ - uint8_t conf; /* configuration register 8 */ - uint8_t syncb; /* configuration register 41 */ - uint8_t dither; /* configuration of the dithering */ - uint8_t pll_a; /* PLL configuration, register A, 1B */ - uint16_t pll_b; /* PLL configuration, register B, 1C/1D */ - uint16_t hstart; /* horizontal start, registers C1/C2 */ - uint16_t hstop; /* horizontal total, registers C3/C4 */ - uint16_t vstart; /* vertical start, registers C5/C6 */ - uint16_t vstop; /* vertical total, registers C7/C8 */ - uint16_t vsync; /* manual vertical sync start, 80/81 */ - uint16_t vtotal; /* number of lines generated, 82/83 */ - uint16_t hpos; /* horizontal position + 256, 98/99 */ - uint16_t vpos; /* vertical position, 8e/8f */ - uint16_t voffs; /* vertical output offset, 9c/9d */ - uint16_t hscale; /* horizontal scaling factor, b8/b9 */ - uint16_t vscale; /* vertical scaling factor, 10/11 */ + u8 sync; /* configuration of the C0 register */ + u8 conf; /* configuration register 8 */ + u8 syncb; /* configuration register 41 */ + u8 dither; /* configuration of the dithering */ + u8 pll_a; /* PLL configuration, register A, 1B */ + u16 pll_b; /* PLL configuration, register B, 1C/1D */ + u16 hstart; /* horizontal start, registers C1/C2 */ + u16 hstop; /* horizontal total, registers C3/C4 */ + u16 vstart; /* vertical start, registers C5/C6 */ + u16 vstop; /* vertical total, registers C7/C8 */ + u16 vsync; /* manual vertical sync start, 80/81 */ + u16 vtotal; /* number of lines generated, 82/83 */ + u16 hpos; /* horizontal position + 256, 98/99 */ + u16 vpos; /* vertical position, 8e/8f */ + u16 voffs; /* vertical output offset, 9c/9d */ + u16 hscale; /* horizontal scaling factor, b8/b9 */ + u16 vscale; /* vertical scaling factor, 10/11 */ }; /* @@ -389,7 +389,7 @@ struct ns2501_priv { ** If it returns false, it might be wise to enable the ** DVO with the above function. */ -static bool ns2501_readb(struct intel_dvo_device *dvo, int addr, uint8_t * ch) +static bool ns2501_readb(struct intel_dvo_device *dvo, int addr, u8 *ch) { struct ns2501_priv *ns = dvo->dev_priv; struct i2c_adapter *adapter = dvo->i2c_bus; @@ -434,11 +434,11 @@ static bool ns2501_readb(struct intel_dvo_device *dvo, int addr, uint8_t * ch) ** If it returns false, it might be wise to enable the ** DVO with the above function. */ -static bool ns2501_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch) +static bool ns2501_writeb(struct intel_dvo_device *dvo, int addr, u8 ch) { struct ns2501_priv *ns = dvo->dev_priv; struct i2c_adapter *adapter = dvo->i2c_bus; - uint8_t out_buf[2]; + u8 out_buf[2]; struct i2c_msg msg = { .addr = dvo->slave_addr, diff --git a/drivers/gpu/drm/i915/dvo_sil164.c b/drivers/gpu/drm/i915/dvo_sil164.c index 1c1a0674dbab9..4ae5d8fd9ff0f 100644 --- a/drivers/gpu/drm/i915/dvo_sil164.c +++ b/drivers/gpu/drm/i915/dvo_sil164.c @@ -65,7 +65,7 @@ struct sil164_priv { #define SILPTR(d) ((SIL164Ptr)(d->DriverPrivate.ptr)) -static bool sil164_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch) +static bool sil164_readb(struct intel_dvo_device *dvo, int addr, u8 *ch) { struct sil164_priv *sil = dvo->dev_priv; struct i2c_adapter *adapter = dvo->i2c_bus; @@ -102,11 +102,11 @@ static bool sil164_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch) return false; } -static bool sil164_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch) +static bool sil164_writeb(struct intel_dvo_device *dvo, int addr, u8 ch) { struct sil164_priv *sil = dvo->dev_priv; struct i2c_adapter *adapter = dvo->i2c_bus; - uint8_t out_buf[2]; + u8 out_buf[2]; struct i2c_msg msg = { .addr = dvo->slave_addr, .flags = 0, @@ -173,7 +173,7 @@ static bool sil164_init(struct intel_dvo_device *dvo, static enum drm_connector_status sil164_detect(struct intel_dvo_device *dvo) { - uint8_t reg9; + u8 reg9; sil164_readb(dvo, SIL164_REG9, ®9); @@ -243,7 +243,7 @@ static bool sil164_get_hw_state(struct intel_dvo_device *dvo) static void sil164_dump_regs(struct intel_dvo_device *dvo) { - uint8_t val; + u8 val; sil164_readb(dvo, SIL164_FREQ_LO, &val); DRM_DEBUG_KMS("SIL164_FREQ_LO: 0x%02x\n", val); diff --git a/drivers/gpu/drm/i915/dvo_tfp410.c b/drivers/gpu/drm/i915/dvo_tfp410.c index 31e181da93db7..d603bc2f2506c 100644 --- a/drivers/gpu/drm/i915/dvo_tfp410.c +++ b/drivers/gpu/drm/i915/dvo_tfp410.c @@ -90,7 +90,7 @@ struct tfp410_priv { bool quiet; }; -static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch) +static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, u8 *ch) { struct tfp410_priv *tfp = dvo->dev_priv; struct i2c_adapter *adapter = dvo->i2c_bus; @@ -127,11 +127,11 @@ static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch) return false; } -static bool tfp410_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch) +static bool tfp410_writeb(struct intel_dvo_device *dvo, int addr, u8 ch) { struct tfp410_priv *tfp = dvo->dev_priv; struct i2c_adapter *adapter = dvo->i2c_bus; - uint8_t out_buf[2]; + u8 out_buf[2]; struct i2c_msg msg = { .addr = dvo->slave_addr, .flags = 0, @@ -155,7 +155,7 @@ static bool tfp410_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch) static int tfp410_getid(struct intel_dvo_device *dvo, int addr) { - uint8_t ch1, ch2; + u8 ch1, ch2; if (tfp410_readb(dvo, addr+0, &ch1) && tfp410_readb(dvo, addr+1, &ch2)) @@ -203,7 +203,7 @@ static bool tfp410_init(struct intel_dvo_device *dvo, static enum drm_connector_status tfp410_detect(struct intel_dvo_device *dvo) { enum drm_connector_status ret = connector_status_disconnected; - uint8_t ctl2; + u8 ctl2; if (tfp410_readb(dvo, TFP410_CTL_2, &ctl2)) { if (ctl2 & TFP410_CTL_2_RSEN) @@ -236,7 +236,7 @@ static void tfp410_mode_set(struct intel_dvo_device *dvo, /* set the tfp410 power state */ static void tfp410_dpms(struct intel_dvo_device *dvo, bool enable) { - uint8_t ctl1; + u8 ctl1; if (!tfp410_readb(dvo, TFP410_CTL_1, &ctl1)) return; @@ -251,7 +251,7 @@ static void tfp410_dpms(struct intel_dvo_device *dvo, bool enable) static bool tfp410_get_hw_state(struct intel_dvo_device *dvo) { - uint8_t ctl1; + u8 ctl1; if (!tfp410_readb(dvo, TFP410_CTL_1, &ctl1)) return false; @@ -264,7 +264,7 @@ static bool tfp410_get_hw_state(struct intel_dvo_device *dvo) static void tfp410_dump_regs(struct intel_dvo_device *dvo) { - uint8_t val, val2; + u8 val, val2; tfp410_readb(dvo, TFP410_REV, &val); DRM_DEBUG_KMS("TFP410_REV: 0x%02X\n", val); diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index 27f16db8953a5..4e142ff497085 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -438,7 +438,7 @@ void intel_dvo_init(struct drm_i915_private *dev_priv) int gpio; bool dvoinit; enum pipe pipe; - uint32_t dpll[I915_MAX_PIPES]; + u32 dpll[I915_MAX_PIPES]; enum port port; /* -- GitLab From fd620bf92a609315241fa5440d336ef17ea76550 Mon Sep 17 00:00:00 2001 From: Jani Nikula <jani.nikula@intel.com> Date: Tue, 12 Jun 2018 12:19:33 +0300 Subject: [PATCH 0412/1506] drm/i915/backlight: switch to kernel unsigned int types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have fairly mixed uintN_t vs. uN usage throughout the driver, but try to stick to kernel types at least where it's more prevalent. Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/e68c3f16738eb3ab9f276d797f20326ed6d15848.1528794959.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_dp_aux_backlight.c | 12 ++++++------ drivers/gpu/drm/i915/intel_panel.c | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp_aux_backlight.c b/drivers/gpu/drm/i915/intel_dp_aux_backlight.c index 2bb2ceb9d463d..357136f17f853 100644 --- a/drivers/gpu/drm/i915/intel_dp_aux_backlight.c +++ b/drivers/gpu/drm/i915/intel_dp_aux_backlight.c @@ -26,7 +26,7 @@ static void set_aux_backlight_enable(struct intel_dp *intel_dp, bool enable) { - uint8_t reg_val = 0; + u8 reg_val = 0; /* Early return when display use other mechanism to enable backlight. */ if (!(intel_dp->edp_dpcd[1] & DP_EDP_BACKLIGHT_AUX_ENABLE_CAP)) @@ -54,11 +54,11 @@ static void set_aux_backlight_enable(struct intel_dp *intel_dp, bool enable) * Read the current backlight value from DPCD register(s) based * on if 8-bit(MSB) or 16-bit(MSB and LSB) values are supported */ -static uint32_t intel_dp_aux_get_backlight(struct intel_connector *connector) +static u32 intel_dp_aux_get_backlight(struct intel_connector *connector) { struct intel_dp *intel_dp = enc_to_intel_dp(&connector->encoder->base); - uint8_t read_val[2] = { 0x0 }; - uint16_t level = 0; + u8 read_val[2] = { 0x0 }; + u16 level = 0; if (drm_dp_dpcd_read(&intel_dp->aux, DP_EDP_BACKLIGHT_BRIGHTNESS_MSB, &read_val, sizeof(read_val)) < 0) { @@ -82,7 +82,7 @@ intel_dp_aux_set_backlight(const struct drm_connector_state *conn_state, u32 lev { struct intel_connector *connector = to_intel_connector(conn_state->connector); struct intel_dp *intel_dp = enc_to_intel_dp(&connector->encoder->base); - uint8_t vals[2] = { 0x0 }; + u8 vals[2] = { 0x0 }; vals[0] = level; @@ -178,7 +178,7 @@ static void intel_dp_aux_enable_backlight(const struct intel_crtc_state *crtc_st { struct intel_connector *connector = to_intel_connector(conn_state->connector); struct intel_dp *intel_dp = enc_to_intel_dp(&connector->encoder->base); - uint8_t dpcd_buf, new_dpcd_buf, edp_backlight_mode; + u8 dpcd_buf, new_dpcd_buf, edp_backlight_mode; if (drm_dp_dpcd_readb(&intel_dp->aux, DP_EDP_BACKLIGHT_MODE_SET_REGISTER, &dpcd_buf) != 1) { diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index b443278e569ce..14b827ec54273 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -406,11 +406,11 @@ intel_panel_detect(struct drm_i915_private *dev_priv) * Return @source_val in range [@source_min..@source_max] scaled to range * [@target_min..@target_max]. */ -static uint32_t scale(uint32_t source_val, - uint32_t source_min, uint32_t source_max, - uint32_t target_min, uint32_t target_max) +static u32 scale(u32 source_val, + u32 source_min, u32 source_max, + u32 target_min, u32 target_max) { - uint64_t target_val; + u64 target_val; WARN_ON(source_min > source_max); WARN_ON(target_min > target_max); -- GitLab From c25004964c5a8a0ee7b749bf969b3621dcaf2597 Mon Sep 17 00:00:00 2001 From: Jani Nikula <jani.nikula@intel.com> Date: Tue, 12 Jun 2018 12:19:34 +0300 Subject: [PATCH 0413/1506] drm/i915/audio: switch to kernel unsigned int types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have fairly mixed uintN_t vs. uN usage throughout the driver, but try to stick to kernel types at least where it's more prevalent. Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/808b06e1f0a95a4ee892553abf11fdbc30025571.1528794959.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_audio.c | 36 +++++++++++++++--------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index 3ea566f99450e..4e4c0ec44f356 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -198,13 +198,13 @@ static int audio_config_hdmi_get_n(const struct intel_crtc_state *crtc_state, } static bool intel_eld_uptodate(struct drm_connector *connector, - i915_reg_t reg_eldv, uint32_t bits_eldv, - i915_reg_t reg_elda, uint32_t bits_elda, + i915_reg_t reg_eldv, u32 bits_eldv, + i915_reg_t reg_elda, u32 bits_elda, i915_reg_t reg_edid) { struct drm_i915_private *dev_priv = to_i915(connector->dev); - uint8_t *eld = connector->eld; - uint32_t tmp; + u8 *eld = connector->eld; + u32 tmp; int i; tmp = I915_READ(reg_eldv); @@ -218,7 +218,7 @@ static bool intel_eld_uptodate(struct drm_connector *connector, I915_WRITE(reg_elda, tmp); for (i = 0; i < drm_eld_size(eld) / 4; i++) - if (I915_READ(reg_edid) != *((uint32_t *)eld + i)) + if (I915_READ(reg_edid) != *((u32 *)eld + i)) return false; return true; @@ -229,7 +229,7 @@ static void g4x_audio_codec_disable(struct intel_encoder *encoder, const struct drm_connector_state *old_conn_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - uint32_t eldv, tmp; + u32 eldv, tmp; DRM_DEBUG_KMS("Disable audio codec\n"); @@ -251,9 +251,9 @@ static void g4x_audio_codec_enable(struct intel_encoder *encoder, { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct drm_connector *connector = conn_state->connector; - uint8_t *eld = connector->eld; - uint32_t eldv; - uint32_t tmp; + u8 *eld = connector->eld; + u32 eldv; + u32 tmp; int len, i; DRM_DEBUG_KMS("Enable audio codec, %u bytes ELD\n", eld[2]); @@ -278,7 +278,7 @@ static void g4x_audio_codec_enable(struct intel_encoder *encoder, len = min(drm_eld_size(eld) / 4, len); DRM_DEBUG_DRIVER("ELD size %d\n", len); for (i = 0; i < len; i++) - I915_WRITE(G4X_HDMIW_HDMIEDID, *((uint32_t *)eld + i)); + I915_WRITE(G4X_HDMIW_HDMIEDID, *((u32 *)eld + i)); tmp = I915_READ(G4X_AUD_CNTL_ST); tmp |= eldv; @@ -393,7 +393,7 @@ static void hsw_audio_codec_disable(struct intel_encoder *encoder, struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc); enum pipe pipe = crtc->pipe; - uint32_t tmp; + u32 tmp; DRM_DEBUG_KMS("Disable audio codec on pipe %c\n", pipe_name(pipe)); @@ -426,8 +426,8 @@ static void hsw_audio_codec_enable(struct intel_encoder *encoder, struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); struct drm_connector *connector = conn_state->connector; enum pipe pipe = crtc->pipe; - const uint8_t *eld = connector->eld; - uint32_t tmp; + const u8 *eld = connector->eld; + u32 tmp; int len, i; DRM_DEBUG_KMS("Enable audio codec on pipe %c, %u bytes ELD\n", @@ -456,7 +456,7 @@ static void hsw_audio_codec_enable(struct intel_encoder *encoder, /* Up to 84 bytes of hw ELD buffer */ len = min(drm_eld_size(eld), 84); for (i = 0; i < len / 4; i++) - I915_WRITE(HSW_AUD_EDID_DATA(pipe), *((uint32_t *)eld + i)); + I915_WRITE(HSW_AUD_EDID_DATA(pipe), *((u32 *)eld + i)); /* ELD valid */ tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD); @@ -477,7 +477,7 @@ static void ilk_audio_codec_disable(struct intel_encoder *encoder, struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc); enum pipe pipe = crtc->pipe; enum port port = encoder->port; - uint32_t tmp, eldv; + u32 tmp, eldv; i915_reg_t aud_config, aud_cntrl_st2; DRM_DEBUG_KMS("Disable audio codec on port %c, pipe %c\n", @@ -524,8 +524,8 @@ static void ilk_audio_codec_enable(struct intel_encoder *encoder, struct drm_connector *connector = conn_state->connector; enum pipe pipe = crtc->pipe; enum port port = encoder->port; - uint8_t *eld = connector->eld; - uint32_t tmp, eldv; + u8 *eld = connector->eld; + u32 tmp, eldv; int len, i; i915_reg_t hdmiw_hdmiedid, aud_config, aud_cntl_st, aud_cntrl_st2; @@ -575,7 +575,7 @@ static void ilk_audio_codec_enable(struct intel_encoder *encoder, /* Up to 84 bytes of hw ELD buffer */ len = min(drm_eld_size(eld), 84); for (i = 0; i < len / 4; i++) - I915_WRITE(hdmiw_hdmiedid, *((uint32_t *)eld + i)); + I915_WRITE(hdmiw_hdmiedid, *((u32 *)eld + i)); /* ELD valid */ tmp = I915_READ(aud_cntrl_st2); -- GitLab From 02f361f5fdfb7bc24fcd686ae581114038eacbdd Mon Sep 17 00:00:00 2001 From: Jani Nikula <jani.nikula@intel.com> Date: Tue, 12 Jun 2018 12:19:35 +0300 Subject: [PATCH 0414/1506] drm/i915/lspcon: switch to kernel unsigned int types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have fairly mixed uintN_t vs. uN usage throughout the driver, but try to stick to kernel types at least where it's more prevalent. Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/1e132575785d9b615208eb60ee5e388df5991172.1528794959.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_lspcon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_lspcon.c b/drivers/gpu/drm/i915/intel_lspcon.c index 8ae8f42f430a1..5dae16ccd9f10 100644 --- a/drivers/gpu/drm/i915/intel_lspcon.c +++ b/drivers/gpu/drm/i915/intel_lspcon.c @@ -116,7 +116,7 @@ static int lspcon_change_mode(struct intel_lspcon *lspcon, static bool lspcon_wake_native_aux_ch(struct intel_lspcon *lspcon) { - uint8_t rev; + u8 rev; if (drm_dp_dpcd_readb(&lspcon_to_intel_dp(lspcon)->aux, DP_DPCD_REV, &rev) != 1) { -- GitLab From e2810a7167df14c762e085fae5aade38425b71bf Mon Sep 17 00:00:00 2001 From: Heiko Stuebner <heiko@sntech.de> Date: Tue, 12 Jun 2018 15:20:27 +0200 Subject: [PATCH 0415/1506] drm/rockchip: vop: split out core clock enablement into separate functions Judging from the iommu code, both the hclk and aclk are necessary for register access. Split them off into separate functions from the regular vop enablement, so that we can use them elsewhere as well. Fixes: d0b912bd4c23 ("iommu/rockchip: Request irqs in rk_iommu_probe()") [prerequisite change for the actual fix] Cc: stable@vger.kernel.org Signed-off-by: Heiko Stuebner <heiko@sntech.de> Tested-by: Ezequiel Garcia <ezequiel@collabora.com> Reviewed-by: Tomasz Figa <tfiga@chromium.org> Link: https://patchwork.freedesktop.org/patch/msgid/20180612132028.27490-2-heiko@sntech.de --- drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 44 +++++++++++++++------ 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 45847d4a2e142..b55156b8ba3b8 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -486,6 +486,31 @@ static void vop_line_flag_irq_disable(struct vop *vop) spin_unlock_irqrestore(&vop->irq_lock, flags); } +static int vop_core_clks_enable(struct vop *vop) +{ + int ret; + + ret = clk_enable(vop->hclk); + if (ret < 0) + return ret; + + ret = clk_enable(vop->aclk); + if (ret < 0) + goto err_disable_hclk; + + return 0; + +err_disable_hclk: + clk_disable(vop->hclk); + return ret; +} + +static void vop_core_clks_disable(struct vop *vop) +{ + clk_disable(vop->aclk); + clk_disable(vop->hclk); +} + static int vop_enable(struct drm_crtc *crtc) { struct vop *vop = to_vop(crtc); @@ -497,17 +522,13 @@ static int vop_enable(struct drm_crtc *crtc) return ret; } - ret = clk_enable(vop->hclk); + ret = vop_core_clks_enable(vop); if (WARN_ON(ret < 0)) goto err_put_pm_runtime; ret = clk_enable(vop->dclk); if (WARN_ON(ret < 0)) - goto err_disable_hclk; - - ret = clk_enable(vop->aclk); - if (WARN_ON(ret < 0)) - goto err_disable_dclk; + goto err_disable_core; /* * Slave iommu shares power, irq and clock with vop. It was associated @@ -519,7 +540,7 @@ static int vop_enable(struct drm_crtc *crtc) if (ret) { DRM_DEV_ERROR(vop->dev, "failed to attach dma mapping, %d\n", ret); - goto err_disable_aclk; + goto err_disable_dclk; } spin_lock(&vop->reg_lock); @@ -558,12 +579,10 @@ static int vop_enable(struct drm_crtc *crtc) return 0; -err_disable_aclk: - clk_disable(vop->aclk); err_disable_dclk: clk_disable(vop->dclk); -err_disable_hclk: - clk_disable(vop->hclk); +err_disable_core: + vop_core_clks_disable(vop); err_put_pm_runtime: pm_runtime_put_sync(vop->dev); return ret; @@ -609,8 +628,7 @@ static void vop_crtc_atomic_disable(struct drm_crtc *crtc, rockchip_drm_dma_detach_device(vop->drm_dev, vop->dev); clk_disable(vop->dclk); - clk_disable(vop->aclk); - clk_disable(vop->hclk); + vop_core_clks_disable(vop); pm_runtime_put(vop->dev); mutex_unlock(&vop->vop_lock); -- GitLab From 6456314ff1de246414a43e3132075b70b3e050ac Mon Sep 17 00:00:00 2001 From: Sandy Huang <hjc@rock-chips.com> Date: Tue, 12 Jun 2018 15:20:28 +0200 Subject: [PATCH 0416/1506] drm/rockchip: vop: fix irq disabled after vop driver probed The vop irq is shared between vop and iommu and irq probing in the iommu driver moved to the probe function recently. This can in some cases lead to a stall if the irq is triggered while the vop driver still has it disabled, but the vop irq handler gets called. But there is no real need to disable the irq, as the vop can simply also track its enabled state and ignore irqs in that case. For this we can simply check the power-domain state of the vop, similar to how the iommu driver does it. So remove the enable/disable handling and add appropriate condition to the irq handler. changes in v2: - move to just check the power-domain state - add clock handling changes in v3: - clarify comment to speak of runtime-pm not power-domain changes in v4: - address Marc's comments (clk-enable WARN_ON and style improvement) Fixes: d0b912bd4c23 ("iommu/rockchip: Request irqs in rk_iommu_probe()") Cc: stable@vger.kernel.org Signed-off-by: Sandy Huang <hjc@rock-chips.com> Signed-off-by: Heiko Stuebner <heiko@sntech.de> Tested-by: Ezequiel Garcia <ezequiel@collabora.com> Reviewed-by: Tomasz Figa <tfiga@chromium.org> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180612132028.27490-3-heiko@sntech.de --- drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 25 ++++++++++++++------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index b55156b8ba3b8..c9222119767d8 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -573,8 +573,6 @@ static int vop_enable(struct drm_crtc *crtc) spin_unlock(&vop->reg_lock); - enable_irq(vop->irq); - drm_crtc_vblank_on(crtc); return 0; @@ -618,8 +616,6 @@ static void vop_crtc_atomic_disable(struct drm_crtc *crtc, vop_dsp_hold_valid_irq_disable(vop); - disable_irq(vop->irq); - vop->is_enabled = false; /* @@ -1195,6 +1191,18 @@ static irqreturn_t vop_isr(int irq, void *data) uint32_t active_irqs; int ret = IRQ_NONE; + /* + * The irq is shared with the iommu. If the runtime-pm state of the + * vop-device is disabled the irq has to be targeted at the iommu. + */ + if (!pm_runtime_get_if_in_use(vop->dev)) + return IRQ_NONE; + + if (vop_core_clks_enable(vop)) { + DRM_DEV_ERROR_RATELIMITED(vop->dev, "couldn't enable clocks\n"); + goto out; + } + /* * interrupt register has interrupt status, enable and clear bits, we * must hold irq_lock to avoid a race with enable/disable_vblank(). @@ -1210,7 +1218,7 @@ static irqreturn_t vop_isr(int irq, void *data) /* This is expected for vop iommu irqs, since the irq is shared */ if (!active_irqs) - return IRQ_NONE; + goto out_disable; if (active_irqs & DSP_HOLD_VALID_INTR) { complete(&vop->dsp_hold_completion); @@ -1236,6 +1244,10 @@ static irqreturn_t vop_isr(int irq, void *data) DRM_DEV_ERROR(vop->dev, "Unknown VOP IRQs: %#02x\n", active_irqs); +out_disable: + vop_core_clks_disable(vop); +out: + pm_runtime_put(vop->dev); return ret; } @@ -1614,9 +1626,6 @@ static int vop_bind(struct device *dev, struct device *master, void *data) if (ret) goto err_disable_pm_runtime; - /* IRQ is initially disabled; it gets enabled in power_on */ - disable_irq(vop->irq); - return 0; err_disable_pm_runtime: -- GitLab From bcc2661e3243fe75b91ec682de01e7cbedfbe7f9 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Mon, 18 Jun 2018 08:31:35 +0100 Subject: [PATCH 0417/1506] drm/i915: Only show debug for state changes when banning Since we trigger 10,000s of hangs and resets during selftesting, we emit many, many thousands of lines of useless debug messages. Reduce the frequency by only logging a change in state of a guilty context. Fixes: 14921f3cef85 ("drm/i915: Fix context ban and hang accounting for client") Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180618073135.10849-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 822abf444378f..858d188dd33bc 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2976,16 +2976,16 @@ static void i915_gem_context_mark_guilty(struct i915_gem_context *ctx) score = atomic_add_return(CONTEXT_SCORE_GUILTY, &ctx->ban_score); banned = score >= CONTEXT_SCORE_BAN_THRESHOLD; - DRM_DEBUG_DRIVER("context %s: guilty %d, score %u, ban %s\n", - ctx->name, atomic_read(&ctx->guilty_count), - score, yesno(banned && bannable)); - /* Cool contexts don't accumulate client ban score */ if (!bannable) return; - if (banned) + if (banned) { + DRM_DEBUG_DRIVER("context %s: guilty %d, score %u, banned\n", + ctx->name, atomic_read(&ctx->guilty_count), + score); i915_gem_context_set_banned(ctx); + } if (!IS_ERR_OR_NULL(ctx->file_priv)) i915_gem_client_mark_guilty(ctx->file_priv, ctx); -- GitLab From 5ee4a7a6db8eb46aafdfea1f26cbdbbb4cef76b3 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Mon, 18 Jun 2018 10:41:50 +0100 Subject: [PATCH 0418/1506] drm/i915/execlists: Pull the w/a LRI emission into a helper Having the w/a registers as an open-coded table leaves a trap for the unwary; it would be easy to miss incrementing the LRI counter when adding a new register to the list. Instead, pull the list of registers into a table, so that we only need add new registers to that table rather than try and remember important side-effects of earlier chunks of GPU instructions. Suggested-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180618094150.30895-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_reg.h | 3 +- drivers/gpu/drm/i915/intel_lrc.c | 59 +++++++++++++++++++++++--------- 2 files changed, 45 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 54ec7ab57ce83..1f928bac2532e 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -156,6 +156,7 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define _PHY3(phy, ...) _PICK(phy, __VA_ARGS__) #define _MMIO_PHY3(phy, a, b, c) _MMIO(_PHY3(phy, a, b, c)) +#define __MASKED_FIELD(mask, value) ((mask) << 16 | (value)) #define _MASKED_FIELD(mask, value) ({ \ if (__builtin_constant_p(mask)) \ BUILD_BUG_ON_MSG(((mask) & 0xffff0000), "Incorrect mask"); \ @@ -164,7 +165,7 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) if (__builtin_constant_p(mask) && __builtin_constant_p(value)) \ BUILD_BUG_ON_MSG((value) & ~(mask), \ "Incorrect value for mask"); \ - (mask) << 16 | (value); }) + __MASKED_FIELD(mask, value); }) #define _MASKED_BIT_ENABLE(a) ({ typeof(a) _a = (a); _MASKED_FIELD(_a, _a); }) #define _MASKED_BIT_DISABLE(a) (_MASKED_FIELD((a), 0)) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index b6c230bd7d6ee..10deebe49543b 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1566,29 +1566,56 @@ static u32 *gen8_init_indirectctx_bb(struct intel_engine_cs *engine, u32 *batch) return batch; } -static u32 *gen9_init_indirectctx_bb(struct intel_engine_cs *engine, u32 *batch) +struct lri { + i915_reg_t reg; + u32 value; +}; + +static u32 *emit_lri(u32 *batch, const struct lri *lri, unsigned int count) { - *batch++ = MI_ARB_ON_OFF | MI_ARB_DISABLE; + GEM_BUG_ON(!count || count > 63); - /* WaFlushCoherentL3CacheLinesAtContextSwitch:skl,bxt,glk */ - batch = gen8_emit_flush_coherentl3_wa(engine, batch); + *batch++ = MI_LOAD_REGISTER_IMM(count); + do { + *batch++ = i915_mmio_reg_offset(lri->reg); + *batch++ = lri->value; + } while (lri++, --count); + *batch++ = MI_NOOP; - *batch++ = MI_LOAD_REGISTER_IMM(3); + return batch; +} - /* WaDisableGatherAtSetShaderCommonSlice:skl,bxt,kbl,glk */ - *batch++ = i915_mmio_reg_offset(COMMON_SLICE_CHICKEN2); - *batch++ = _MASKED_BIT_DISABLE( - GEN9_DISABLE_GATHER_AT_SET_SHADER_COMMON_SLICE); +static u32 *gen9_init_indirectctx_bb(struct intel_engine_cs *engine, u32 *batch) +{ + static const struct lri lri[] = { + /* WaDisableGatherAtSetShaderCommonSlice:skl,bxt,kbl,glk */ + { + COMMON_SLICE_CHICKEN2, + __MASKED_FIELD(GEN9_DISABLE_GATHER_AT_SET_SHADER_COMMON_SLICE, + 0), + }, + + /* BSpec: 11391 */ + { + FF_SLICE_CHICKEN, + __MASKED_FIELD(FF_SLICE_CHICKEN_CL_PROVOKING_VERTEX_FIX, + FF_SLICE_CHICKEN_CL_PROVOKING_VERTEX_FIX), + }, + + /* BSpec: 11299 */ + { + _3D_CHICKEN3, + __MASKED_FIELD(_3D_CHICKEN_SF_PROVOKING_VERTEX_FIX, + _3D_CHICKEN_SF_PROVOKING_VERTEX_FIX), + } + }; - /* BSpec: 11391 */ - *batch++ = i915_mmio_reg_offset(FF_SLICE_CHICKEN); - *batch++ = _MASKED_BIT_ENABLE(FF_SLICE_CHICKEN_CL_PROVOKING_VERTEX_FIX); + *batch++ = MI_ARB_ON_OFF | MI_ARB_DISABLE; - /* BSpec: 11299 */ - *batch++ = i915_mmio_reg_offset(_3D_CHICKEN3); - *batch++ = _MASKED_BIT_ENABLE(_3D_CHICKEN_SF_PROVOKING_VERTEX_FIX); + /* WaFlushCoherentL3CacheLinesAtContextSwitch:skl,bxt,glk */ + batch = gen8_emit_flush_coherentl3_wa(engine, batch); - *batch++ = MI_NOOP; + batch = emit_lri(batch, lri, ARRAY_SIZE(lri)); /* WaClearSlmSpaceAtContextSwitch:kbl */ /* Actual scratch location is at 128 bytes offset */ -- GitLab From b9be78531d2710f4302545aa80e0678ed0a3dd09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= <jose.souza@intel.com> Date: Thu, 14 Jun 2018 16:37:19 -0700 Subject: [PATCH 0419/1506] drm/i915/whl: Introducing Whiskey Lake platform MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Whiskey Lake uses the same gen graphics as Coffe Lake, including some ids that were previously marked as reserved on Coffe Lake, but that now are moved to WHL page. So, let's just move them to WHL macros that will feed into CFL macro just to keep it better organized to make easier future code review but it will be handled as a CFL. v2: Fixing GT level of some ids Cc: Rodrigo Vivi <rodrigo.vivi@intel.com> Signed-off-by: José Roberto de Souza <jose.souza@intel.com> Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180614233720.30517-1-jose.souza@intel.com --- drivers/gpu/drm/i915/i915_pci.c | 4 +++- include/drm/i915_pciids.h | 28 ++++++++++++++++++---------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c index 97a91e6af7e3c..92e98773e53d4 100644 --- a/drivers/gpu/drm/i915/i915_pci.c +++ b/drivers/gpu/drm/i915/i915_pci.c @@ -660,9 +660,11 @@ static const struct pci_device_id pciidlist[] = { INTEL_CFL_S_GT1_IDS(&intel_coffeelake_gt1_info), INTEL_CFL_S_GT2_IDS(&intel_coffeelake_gt2_info), INTEL_CFL_H_GT2_IDS(&intel_coffeelake_gt2_info), - INTEL_CFL_U_GT1_IDS(&intel_coffeelake_gt1_info), INTEL_CFL_U_GT2_IDS(&intel_coffeelake_gt2_info), INTEL_CFL_U_GT3_IDS(&intel_coffeelake_gt3_info), + INTEL_WHL_U_GT1_IDS(&intel_coffeelake_gt1_info), + INTEL_WHL_U_GT2_IDS(&intel_coffeelake_gt2_info), + INTEL_WHL_U_GT3_IDS(&intel_coffeelake_gt3_info), INTEL_CNL_IDS(&intel_cannonlake_info), INTEL_ICL_11_IDS(&intel_icelake_11_info), {0, 0, 0} diff --git a/include/drm/i915_pciids.h b/include/drm/i915_pciids.h index bab70ff6e78bd..d03350a380250 100644 --- a/include/drm/i915_pciids.h +++ b/include/drm/i915_pciids.h @@ -388,32 +388,40 @@ INTEL_VGA_DEVICE(0x3E9B, info), /* Halo GT2 */ \ INTEL_VGA_DEVICE(0x3E94, info) /* Halo GT2 */ -/* CFL U GT1 */ -#define INTEL_CFL_U_GT1_IDS(info) \ - INTEL_VGA_DEVICE(0x3EA1, info), \ - INTEL_VGA_DEVICE(0x3EA4, info) - /* CFL U GT2 */ #define INTEL_CFL_U_GT2_IDS(info) \ - INTEL_VGA_DEVICE(0x3EA0, info), \ - INTEL_VGA_DEVICE(0x3EA3, info), \ INTEL_VGA_DEVICE(0x3EA9, info) /* CFL U GT3 */ #define INTEL_CFL_U_GT3_IDS(info) \ - INTEL_VGA_DEVICE(0x3EA2, info), /* ULT GT3 */ \ INTEL_VGA_DEVICE(0x3EA5, info), /* ULT GT3 */ \ INTEL_VGA_DEVICE(0x3EA6, info), /* ULT GT3 */ \ INTEL_VGA_DEVICE(0x3EA7, info), /* ULT GT3 */ \ INTEL_VGA_DEVICE(0x3EA8, info) /* ULT GT3 */ +/* WHL/CFL U GT1 */ +#define INTEL_WHL_U_GT1_IDS(info) \ + INTEL_VGA_DEVICE(0x3EA1, info) + +/* WHL/CFL U GT2 */ +#define INTEL_WHL_U_GT2_IDS(info) \ + INTEL_VGA_DEVICE(0x3EA0, info) + +/* WHL/CFL U GT3 */ +#define INTEL_WHL_U_GT3_IDS(info) \ + INTEL_VGA_DEVICE(0x3EA2, info), \ + INTEL_VGA_DEVICE(0x3EA3, info), \ + INTEL_VGA_DEVICE(0x3EA4, info) + #define INTEL_CFL_IDS(info) \ INTEL_CFL_S_GT1_IDS(info), \ INTEL_CFL_S_GT2_IDS(info), \ INTEL_CFL_H_GT2_IDS(info), \ - INTEL_CFL_U_GT1_IDS(info), \ INTEL_CFL_U_GT2_IDS(info), \ - INTEL_CFL_U_GT3_IDS(info) + INTEL_CFL_U_GT3_IDS(info), \ + INTEL_WHL_U_GT1_IDS(info), \ + INTEL_WHL_U_GT2_IDS(info), \ + INTEL_WHL_U_GT3_IDS(info) /* CNL */ #define INTEL_CNL_IDS(info) \ -- GitLab From e364672477a105029346f0888bfa797b1ec3eee4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= <jose.souza@intel.com> Date: Thu, 14 Jun 2018 16:37:20 -0700 Subject: [PATCH 0420/1506] drm/i915/aml: Introducing Amber Lake platform MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Amber Lake uses the same gen graphics as Kaby Lake, including a id that were previously marked as reserved on Kaby Lake, but that now is moved to AML page. So, let's just move it to AML macro that will feed into KBL macro just to keep it better organized to make easier future code review but it will be handled as a KBL. Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Signed-off-by: José Roberto de Souza <jose.souza@intel.com> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180614233720.30517-2-jose.souza@intel.com --- drivers/gpu/drm/i915/i915_pci.c | 1 + include/drm/i915_pciids.h | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c index 92e98773e53d4..55543f1b0236a 100644 --- a/drivers/gpu/drm/i915/i915_pci.c +++ b/drivers/gpu/drm/i915/i915_pci.c @@ -657,6 +657,7 @@ static const struct pci_device_id pciidlist[] = { INTEL_KBL_GT2_IDS(&intel_kabylake_gt2_info), INTEL_KBL_GT3_IDS(&intel_kabylake_gt3_info), INTEL_KBL_GT4_IDS(&intel_kabylake_gt3_info), + INTEL_AML_GT2_IDS(&intel_kabylake_gt2_info), INTEL_CFL_S_GT1_IDS(&intel_coffeelake_gt1_info), INTEL_CFL_S_GT2_IDS(&intel_coffeelake_gt2_info), INTEL_CFL_H_GT2_IDS(&intel_coffeelake_gt2_info), diff --git a/include/drm/i915_pciids.h b/include/drm/i915_pciids.h index d03350a380250..fbf5cfc9b352f 100644 --- a/include/drm/i915_pciids.h +++ b/include/drm/i915_pciids.h @@ -349,7 +349,6 @@ #define INTEL_KBL_GT2_IDS(info) \ INTEL_VGA_DEVICE(0x5916, info), /* ULT GT2 */ \ INTEL_VGA_DEVICE(0x5917, info), /* Mobile GT2 */ \ - INTEL_VGA_DEVICE(0x591C, info), /* ULX GT2 */ \ INTEL_VGA_DEVICE(0x5921, info), /* ULT GT2F */ \ INTEL_VGA_DEVICE(0x591E, info), /* ULX GT2 */ \ INTEL_VGA_DEVICE(0x5912, info), /* DT GT2 */ \ @@ -365,11 +364,17 @@ #define INTEL_KBL_GT4_IDS(info) \ INTEL_VGA_DEVICE(0x593B, info) /* Halo GT4 */ +/* AML/KBL Y GT2 */ +#define INTEL_AML_GT2_IDS(info) \ + INTEL_VGA_DEVICE(0x591C, info), /* ULX GT2 */ \ + INTEL_VGA_DEVICE(0x87C0, info) /* ULX GT2 */ + #define INTEL_KBL_IDS(info) \ INTEL_KBL_GT1_IDS(info), \ INTEL_KBL_GT2_IDS(info), \ INTEL_KBL_GT3_IDS(info), \ - INTEL_KBL_GT4_IDS(info) + INTEL_KBL_GT4_IDS(info), \ + INTEL_AML_GT2_IDS(info) /* CFL S */ #define INTEL_CFL_S_GT1_IDS(info) \ -- GitLab From 58884bbc7c9d8dd2623510ecf8ba3ddf1af9ce96 Mon Sep 17 00:00:00 2001 From: Radhakrishna Sripada <radhakrishna.sripada@intel.com> Date: Thu, 7 Jun 2018 12:20:13 -0700 Subject: [PATCH 0421/1506] drm/i915/audio: Add 810 MHz clock entries to dp_aud_n_m table Expand the Maud/Naud table according to DP 1.4 spec to include entries for 810 MHz clock. This is required for audio to work with HBR3. Cc: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Cc: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Radhakrishna Sripada <radhakrishna.sripada@intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180607192013.25872-1-radhakrishna.sripada@intel.com --- drivers/gpu/drm/i915/intel_audio.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index 4e4c0ec44f356..a34aa66f28f8e 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -59,6 +59,7 @@ */ /* DP N/M table */ +#define LC_810M 810000 #define LC_540M 540000 #define LC_270M 270000 #define LC_162M 162000 @@ -99,6 +100,15 @@ static const struct dp_aud_n_m dp_aud_n_m[] = { { 128000, LC_540M, 4096, 33750 }, { 176400, LC_540M, 3136, 18750 }, { 192000, LC_540M, 2048, 11250 }, + { 32000, LC_810M, 1024, 50625 }, + { 44100, LC_810M, 784, 28125 }, + { 48000, LC_810M, 512, 16875 }, + { 64000, LC_810M, 2048, 50625 }, + { 88200, LC_810M, 1568, 28125 }, + { 96000, LC_810M, 1024, 16875 }, + { 128000, LC_810M, 4096, 50625 }, + { 176400, LC_810M, 3136, 28125 }, + { 192000, LC_810M, 2048, 16875 }, }; static const struct dp_aud_n_m * -- GitLab From 5ee8ee86c86f30950a6e53eb5a340e929353e855 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni <paulo.r.zanoni@intel.com> Date: Mon, 18 Jun 2018 11:09:43 -0700 Subject: [PATCH 0422/1506] drm/i915/i915_reg.h: fix the checkpatch SPACING issues Because OCD. Now seriously, commit 1aa920ea0e85 ("drm/i915: add register macro definition style guide") has finally established a coding standard to be followed by the rest of the file, and I've been trying to request everybody to adhere to that since then. The problem is that when someone adds a new line to a register that has the wrong style, these people generally propagate the wrong style and I have to keep asking them to drive-by fix the whole register, which is not something I like to do and also creates extra work for them. Or I can ignore the propagation of the wrong coding style and feel anxious about it. On top of that, we now have our CI happily reminding us about these problems, which makes everything worse. So IMHO the best way to proceed is to fix the spacing issues in the file once and for all. Contributors will stop propagating the bad style when adding new bits to registers that already have bad style, we will stop asking them to redo their patches and the CI emails will become more relevant by having less semi-false errors. Yes, there will be some pain involved for backporters, but at least spacing issues like that are easy to spot and fix in the patch files. This patch was generated by: ../../../../scripts/checkpatch.pl -f --strict --types SPACING \ --fix-inplace i915_reg.h I manually checked the output and everything seems sane. v2: Single conflict around the addition of DP_TP_CTL_LINK_TRAIN_PAT4. Cc: Jani Nikula <jani.nikula@intel.com> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Acked-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Reviewed-by: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180618180943.894-1-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 3184 +++++++++++++++---------------- 1 file changed, 1592 insertions(+), 1592 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 1f928bac2532e..b0dd26fc1ee3e 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -141,17 +141,17 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define _PICK(__index, ...) (((const u32 []){ __VA_ARGS__ })[__index]) -#define _PIPE(pipe, a, b) ((a) + (pipe)*((b)-(a))) +#define _PIPE(pipe, a, b) ((a) + (pipe) * ((b) - (a))) #define _MMIO_PIPE(pipe, a, b) _MMIO(_PIPE(pipe, a, b)) #define _PLANE(plane, a, b) _PIPE(plane, a, b) #define _MMIO_PLANE(plane, a, b) _MMIO_PIPE(plane, a, b) -#define _TRANS(tran, a, b) ((a) + (tran)*((b)-(a))) +#define _TRANS(tran, a, b) ((a) + (tran) * ((b) - (a))) #define _MMIO_TRANS(tran, a, b) _MMIO(_TRANS(tran, a, b)) -#define _PORT(port, a, b) ((a) + (port)*((b)-(a))) +#define _PORT(port, a, b) ((a) + (port) * ((b) - (a))) #define _MMIO_PORT(port, a, b) _MMIO(_PORT(port, a, b)) #define _MMIO_PIPE3(pipe, a, b, c) _MMIO(_PICK(pipe, a, b, c)) #define _MMIO_PORT3(pipe, a, b, c) _MMIO(_PICK(pipe, a, b, c)) -#define _PLL(pll, a, b) ((a) + (pll)*((b)-(a))) +#define _PLL(pll, a, b) ((a) + (pll) * ((b) - (a))) #define _MMIO_PLL(pll, a, b) _MMIO(_PLL(pll, a, b)) #define _PHY3(phy, ...) _PICK(phy, __VA_ARGS__) #define _MMIO_PHY3(phy, a, b, c) _MMIO(_PHY3(phy, a, b, c)) @@ -271,19 +271,19 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define ILK_GDSR _MMIO(MCHBAR_MIRROR_BASE + 0x2ca4) -#define ILK_GRDOM_FULL (0<<1) -#define ILK_GRDOM_RENDER (1<<1) -#define ILK_GRDOM_MEDIA (3<<1) -#define ILK_GRDOM_MASK (3<<1) -#define ILK_GRDOM_RESET_ENABLE (1<<0) +#define ILK_GRDOM_FULL (0 << 1) +#define ILK_GRDOM_RENDER (1 << 1) +#define ILK_GRDOM_MEDIA (3 << 1) +#define ILK_GRDOM_MASK (3 << 1) +#define ILK_GRDOM_RESET_ENABLE (1 << 0) #define GEN6_MBCUNIT_SNPCR _MMIO(0x900c) /* for LLC config */ #define GEN6_MBC_SNPCR_SHIFT 21 -#define GEN6_MBC_SNPCR_MASK (3<<21) -#define GEN6_MBC_SNPCR_MAX (0<<21) -#define GEN6_MBC_SNPCR_MED (1<<21) -#define GEN6_MBC_SNPCR_LOW (2<<21) -#define GEN6_MBC_SNPCR_MIN (3<<21) /* only 1/16th of the cache is shared */ +#define GEN6_MBC_SNPCR_MASK (3 << 21) +#define GEN6_MBC_SNPCR_MAX (0 << 21) +#define GEN6_MBC_SNPCR_MED (1 << 21) +#define GEN6_MBC_SNPCR_LOW (2 << 21) +#define GEN6_MBC_SNPCR_MIN (3 << 21) /* only 1/16th of the cache is shared */ #define VLV_G3DCTL _MMIO(0x9024) #define VLV_GSCKGCTL _MMIO(0x9028) @@ -315,13 +315,13 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define GEN11_GRDOM_VECS (1 << 13) #define GEN11_GRDOM_VECS2 (1 << 14) -#define RING_PP_DIR_BASE(engine) _MMIO((engine)->mmio_base+0x228) -#define RING_PP_DIR_BASE_READ(engine) _MMIO((engine)->mmio_base+0x518) -#define RING_PP_DIR_DCLV(engine) _MMIO((engine)->mmio_base+0x220) +#define RING_PP_DIR_BASE(engine) _MMIO((engine)->mmio_base + 0x228) +#define RING_PP_DIR_BASE_READ(engine) _MMIO((engine)->mmio_base + 0x518) +#define RING_PP_DIR_DCLV(engine) _MMIO((engine)->mmio_base + 0x220) #define PP_DIR_DCLV_2G 0xffffffff -#define GEN8_RING_PDP_UDW(engine, n) _MMIO((engine)->mmio_base+0x270 + (n) * 8 + 4) -#define GEN8_RING_PDP_LDW(engine, n) _MMIO((engine)->mmio_base+0x270 + (n) * 8) +#define GEN8_RING_PDP_UDW(engine, n) _MMIO((engine)->mmio_base + 0x270 + (n) * 8 + 4) +#define GEN8_RING_PDP_LDW(engine, n) _MMIO((engine)->mmio_base + 0x270 + (n) * 8) #define GEN8_R_PWR_CLK_STATE _MMIO(0x20C8) #define GEN8_RPCS_ENABLE (1 << 31) @@ -359,25 +359,25 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define GEN8_SELECTIVE_READ_ADDRESSING_ENABLE (1 << 13) #define GAM_ECOCHK _MMIO(0x4090) -#define BDW_DISABLE_HDC_INVALIDATION (1<<25) -#define ECOCHK_SNB_BIT (1<<10) -#define ECOCHK_DIS_TLB (1<<8) -#define HSW_ECOCHK_ARB_PRIO_SOL (1<<6) -#define ECOCHK_PPGTT_CACHE64B (0x3<<3) -#define ECOCHK_PPGTT_CACHE4B (0x0<<3) -#define ECOCHK_PPGTT_GFDT_IVB (0x1<<4) -#define ECOCHK_PPGTT_LLC_IVB (0x1<<3) -#define ECOCHK_PPGTT_UC_HSW (0x1<<3) -#define ECOCHK_PPGTT_WT_HSW (0x2<<3) -#define ECOCHK_PPGTT_WB_HSW (0x3<<3) +#define BDW_DISABLE_HDC_INVALIDATION (1 << 25) +#define ECOCHK_SNB_BIT (1 << 10) +#define ECOCHK_DIS_TLB (1 << 8) +#define HSW_ECOCHK_ARB_PRIO_SOL (1 << 6) +#define ECOCHK_PPGTT_CACHE64B (0x3 << 3) +#define ECOCHK_PPGTT_CACHE4B (0x0 << 3) +#define ECOCHK_PPGTT_GFDT_IVB (0x1 << 4) +#define ECOCHK_PPGTT_LLC_IVB (0x1 << 3) +#define ECOCHK_PPGTT_UC_HSW (0x1 << 3) +#define ECOCHK_PPGTT_WT_HSW (0x2 << 3) +#define ECOCHK_PPGTT_WB_HSW (0x3 << 3) #define GAC_ECO_BITS _MMIO(0x14090) -#define ECOBITS_SNB_BIT (1<<13) -#define ECOBITS_PPGTT_CACHE64B (3<<8) -#define ECOBITS_PPGTT_CACHE4B (0<<8) +#define ECOBITS_SNB_BIT (1 << 13) +#define ECOBITS_PPGTT_CACHE64B (3 << 8) +#define ECOBITS_PPGTT_CACHE4B (0 << 8) #define GAB_CTL _MMIO(0x24000) -#define GAB_CTL_CONT_AFTER_PAGEFAULT (1<<8) +#define GAB_CTL_CONT_AFTER_PAGEFAULT (1 << 8) #define GEN6_STOLEN_RESERVED _MMIO(0x1082C0) #define GEN6_STOLEN_RESERVED_ADDR_MASK (0xFFF << 20) @@ -405,15 +405,15 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define _VGA_MSR_WRITE _MMIO(0x3c2) #define VGA_MSR_WRITE 0x3c2 #define VGA_MSR_READ 0x3cc -#define VGA_MSR_MEM_EN (1<<1) -#define VGA_MSR_CGA_MODE (1<<0) +#define VGA_MSR_MEM_EN (1 << 1) +#define VGA_MSR_CGA_MODE (1 << 0) #define VGA_SR_INDEX 0x3c4 #define SR01 1 #define VGA_SR_DATA 0x3c5 #define VGA_AR_INDEX 0x3c0 -#define VGA_AR_VID_EN (1<<5) +#define VGA_AR_VID_EN (1 << 5) #define VGA_AR_DATA_WRITE 0x3c0 #define VGA_AR_DATA_READ 0x3c1 @@ -446,8 +446,8 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define MI_PREDICATE_SRC1_UDW _MMIO(0x2408 + 4) #define MI_PREDICATE_RESULT_2 _MMIO(0x2214) -#define LOWER_SLICE_ENABLED (1<<0) -#define LOWER_SLICE_DISABLED (0<<0) +#define LOWER_SLICE_ENABLED (1 << 0) +#define LOWER_SLICE_DISABLED (0 << 0) /* * Registers used only by the command parser @@ -505,47 +505,47 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define GEN7_OACONTROL_CTX_MASK 0xFFFFF000 #define GEN7_OACONTROL_TIMER_PERIOD_MASK 0x3F #define GEN7_OACONTROL_TIMER_PERIOD_SHIFT 6 -#define GEN7_OACONTROL_TIMER_ENABLE (1<<5) -#define GEN7_OACONTROL_FORMAT_A13 (0<<2) -#define GEN7_OACONTROL_FORMAT_A29 (1<<2) -#define GEN7_OACONTROL_FORMAT_A13_B8_C8 (2<<2) -#define GEN7_OACONTROL_FORMAT_A29_B8_C8 (3<<2) -#define GEN7_OACONTROL_FORMAT_B4_C8 (4<<2) -#define GEN7_OACONTROL_FORMAT_A45_B8_C8 (5<<2) -#define GEN7_OACONTROL_FORMAT_B4_C8_A16 (6<<2) -#define GEN7_OACONTROL_FORMAT_C4_B8 (7<<2) +#define GEN7_OACONTROL_TIMER_ENABLE (1 << 5) +#define GEN7_OACONTROL_FORMAT_A13 (0 << 2) +#define GEN7_OACONTROL_FORMAT_A29 (1 << 2) +#define GEN7_OACONTROL_FORMAT_A13_B8_C8 (2 << 2) +#define GEN7_OACONTROL_FORMAT_A29_B8_C8 (3 << 2) +#define GEN7_OACONTROL_FORMAT_B4_C8 (4 << 2) +#define GEN7_OACONTROL_FORMAT_A45_B8_C8 (5 << 2) +#define GEN7_OACONTROL_FORMAT_B4_C8_A16 (6 << 2) +#define GEN7_OACONTROL_FORMAT_C4_B8 (7 << 2) #define GEN7_OACONTROL_FORMAT_SHIFT 2 -#define GEN7_OACONTROL_PER_CTX_ENABLE (1<<1) -#define GEN7_OACONTROL_ENABLE (1<<0) +#define GEN7_OACONTROL_PER_CTX_ENABLE (1 << 1) +#define GEN7_OACONTROL_ENABLE (1 << 0) #define GEN8_OACTXID _MMIO(0x2364) #define GEN8_OA_DEBUG _MMIO(0x2B04) -#define GEN9_OA_DEBUG_DISABLE_CLK_RATIO_REPORTS (1<<5) -#define GEN9_OA_DEBUG_INCLUDE_CLK_RATIO (1<<6) -#define GEN9_OA_DEBUG_DISABLE_GO_1_0_REPORTS (1<<2) -#define GEN9_OA_DEBUG_DISABLE_CTX_SWITCH_REPORTS (1<<1) +#define GEN9_OA_DEBUG_DISABLE_CLK_RATIO_REPORTS (1 << 5) +#define GEN9_OA_DEBUG_INCLUDE_CLK_RATIO (1 << 6) +#define GEN9_OA_DEBUG_DISABLE_GO_1_0_REPORTS (1 << 2) +#define GEN9_OA_DEBUG_DISABLE_CTX_SWITCH_REPORTS (1 << 1) #define GEN8_OACONTROL _MMIO(0x2B00) -#define GEN8_OA_REPORT_FORMAT_A12 (0<<2) -#define GEN8_OA_REPORT_FORMAT_A12_B8_C8 (2<<2) -#define GEN8_OA_REPORT_FORMAT_A36_B8_C8 (5<<2) -#define GEN8_OA_REPORT_FORMAT_C4_B8 (7<<2) +#define GEN8_OA_REPORT_FORMAT_A12 (0 << 2) +#define GEN8_OA_REPORT_FORMAT_A12_B8_C8 (2 << 2) +#define GEN8_OA_REPORT_FORMAT_A36_B8_C8 (5 << 2) +#define GEN8_OA_REPORT_FORMAT_C4_B8 (7 << 2) #define GEN8_OA_REPORT_FORMAT_SHIFT 2 -#define GEN8_OA_SPECIFIC_CONTEXT_ENABLE (1<<1) -#define GEN8_OA_COUNTER_ENABLE (1<<0) +#define GEN8_OA_SPECIFIC_CONTEXT_ENABLE (1 << 1) +#define GEN8_OA_COUNTER_ENABLE (1 << 0) #define GEN8_OACTXCONTROL _MMIO(0x2360) #define GEN8_OA_TIMER_PERIOD_MASK 0x3F #define GEN8_OA_TIMER_PERIOD_SHIFT 2 -#define GEN8_OA_TIMER_ENABLE (1<<1) -#define GEN8_OA_COUNTER_RESUME (1<<0) +#define GEN8_OA_TIMER_ENABLE (1 << 1) +#define GEN8_OA_COUNTER_RESUME (1 << 0) #define GEN7_OABUFFER _MMIO(0x23B0) /* R/W */ -#define GEN7_OABUFFER_OVERRUN_DISABLE (1<<3) -#define GEN7_OABUFFER_EDGE_TRIGGER (1<<2) -#define GEN7_OABUFFER_STOP_RESUME_ENABLE (1<<1) -#define GEN7_OABUFFER_RESUME (1<<0) +#define GEN7_OABUFFER_OVERRUN_DISABLE (1 << 3) +#define GEN7_OABUFFER_EDGE_TRIGGER (1 << 2) +#define GEN7_OABUFFER_STOP_RESUME_ENABLE (1 << 1) +#define GEN7_OABUFFER_RESUME (1 << 0) #define GEN8_OABUFFER_UDW _MMIO(0x23b4) #define GEN8_OABUFFER _MMIO(0x2b14) @@ -553,33 +553,33 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define GEN7_OASTATUS1 _MMIO(0x2364) #define GEN7_OASTATUS1_TAIL_MASK 0xffffffc0 -#define GEN7_OASTATUS1_COUNTER_OVERFLOW (1<<2) -#define GEN7_OASTATUS1_OABUFFER_OVERFLOW (1<<1) -#define GEN7_OASTATUS1_REPORT_LOST (1<<0) +#define GEN7_OASTATUS1_COUNTER_OVERFLOW (1 << 2) +#define GEN7_OASTATUS1_OABUFFER_OVERFLOW (1 << 1) +#define GEN7_OASTATUS1_REPORT_LOST (1 << 0) #define GEN7_OASTATUS2 _MMIO(0x2368) #define GEN7_OASTATUS2_HEAD_MASK 0xffffffc0 #define GEN7_OASTATUS2_MEM_SELECT_GGTT (1 << 0) /* 0: PPGTT, 1: GGTT */ #define GEN8_OASTATUS _MMIO(0x2b08) -#define GEN8_OASTATUS_OVERRUN_STATUS (1<<3) -#define GEN8_OASTATUS_COUNTER_OVERFLOW (1<<2) -#define GEN8_OASTATUS_OABUFFER_OVERFLOW (1<<1) -#define GEN8_OASTATUS_REPORT_LOST (1<<0) +#define GEN8_OASTATUS_OVERRUN_STATUS (1 << 3) +#define GEN8_OASTATUS_COUNTER_OVERFLOW (1 << 2) +#define GEN8_OASTATUS_OABUFFER_OVERFLOW (1 << 1) +#define GEN8_OASTATUS_REPORT_LOST (1 << 0) #define GEN8_OAHEADPTR _MMIO(0x2B0C) #define GEN8_OAHEADPTR_MASK 0xffffffc0 #define GEN8_OATAILPTR _MMIO(0x2B10) #define GEN8_OATAILPTR_MASK 0xffffffc0 -#define OABUFFER_SIZE_128K (0<<3) -#define OABUFFER_SIZE_256K (1<<3) -#define OABUFFER_SIZE_512K (2<<3) -#define OABUFFER_SIZE_1M (3<<3) -#define OABUFFER_SIZE_2M (4<<3) -#define OABUFFER_SIZE_4M (5<<3) -#define OABUFFER_SIZE_8M (6<<3) -#define OABUFFER_SIZE_16M (7<<3) +#define OABUFFER_SIZE_128K (0 << 3) +#define OABUFFER_SIZE_256K (1 << 3) +#define OABUFFER_SIZE_512K (2 << 3) +#define OABUFFER_SIZE_1M (3 << 3) +#define OABUFFER_SIZE_2M (4 << 3) +#define OABUFFER_SIZE_4M (5 << 3) +#define OABUFFER_SIZE_8M (6 << 3) +#define OABUFFER_SIZE_16M (7 << 3) /* * Flexible, Aggregate EU Counter Registers. @@ -602,35 +602,35 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define OASTARTTRIG1_THRESHOLD_MASK 0xffff #define OASTARTTRIG2 _MMIO(0x2714) -#define OASTARTTRIG2_INVERT_A_0 (1<<0) -#define OASTARTTRIG2_INVERT_A_1 (1<<1) -#define OASTARTTRIG2_INVERT_A_2 (1<<2) -#define OASTARTTRIG2_INVERT_A_3 (1<<3) -#define OASTARTTRIG2_INVERT_A_4 (1<<4) -#define OASTARTTRIG2_INVERT_A_5 (1<<5) -#define OASTARTTRIG2_INVERT_A_6 (1<<6) -#define OASTARTTRIG2_INVERT_A_7 (1<<7) -#define OASTARTTRIG2_INVERT_A_8 (1<<8) -#define OASTARTTRIG2_INVERT_A_9 (1<<9) -#define OASTARTTRIG2_INVERT_A_10 (1<<10) -#define OASTARTTRIG2_INVERT_A_11 (1<<11) -#define OASTARTTRIG2_INVERT_A_12 (1<<12) -#define OASTARTTRIG2_INVERT_A_13 (1<<13) -#define OASTARTTRIG2_INVERT_A_14 (1<<14) -#define OASTARTTRIG2_INVERT_A_15 (1<<15) -#define OASTARTTRIG2_INVERT_B_0 (1<<16) -#define OASTARTTRIG2_INVERT_B_1 (1<<17) -#define OASTARTTRIG2_INVERT_B_2 (1<<18) -#define OASTARTTRIG2_INVERT_B_3 (1<<19) -#define OASTARTTRIG2_INVERT_C_0 (1<<20) -#define OASTARTTRIG2_INVERT_C_1 (1<<21) -#define OASTARTTRIG2_INVERT_D_0 (1<<22) -#define OASTARTTRIG2_THRESHOLD_ENABLE (1<<23) -#define OASTARTTRIG2_START_TRIG_FLAG_MBZ (1<<24) -#define OASTARTTRIG2_EVENT_SELECT_0 (1<<28) -#define OASTARTTRIG2_EVENT_SELECT_1 (1<<29) -#define OASTARTTRIG2_EVENT_SELECT_2 (1<<30) -#define OASTARTTRIG2_EVENT_SELECT_3 (1<<31) +#define OASTARTTRIG2_INVERT_A_0 (1 << 0) +#define OASTARTTRIG2_INVERT_A_1 (1 << 1) +#define OASTARTTRIG2_INVERT_A_2 (1 << 2) +#define OASTARTTRIG2_INVERT_A_3 (1 << 3) +#define OASTARTTRIG2_INVERT_A_4 (1 << 4) +#define OASTARTTRIG2_INVERT_A_5 (1 << 5) +#define OASTARTTRIG2_INVERT_A_6 (1 << 6) +#define OASTARTTRIG2_INVERT_A_7 (1 << 7) +#define OASTARTTRIG2_INVERT_A_8 (1 << 8) +#define OASTARTTRIG2_INVERT_A_9 (1 << 9) +#define OASTARTTRIG2_INVERT_A_10 (1 << 10) +#define OASTARTTRIG2_INVERT_A_11 (1 << 11) +#define OASTARTTRIG2_INVERT_A_12 (1 << 12) +#define OASTARTTRIG2_INVERT_A_13 (1 << 13) +#define OASTARTTRIG2_INVERT_A_14 (1 << 14) +#define OASTARTTRIG2_INVERT_A_15 (1 << 15) +#define OASTARTTRIG2_INVERT_B_0 (1 << 16) +#define OASTARTTRIG2_INVERT_B_1 (1 << 17) +#define OASTARTTRIG2_INVERT_B_2 (1 << 18) +#define OASTARTTRIG2_INVERT_B_3 (1 << 19) +#define OASTARTTRIG2_INVERT_C_0 (1 << 20) +#define OASTARTTRIG2_INVERT_C_1 (1 << 21) +#define OASTARTTRIG2_INVERT_D_0 (1 << 22) +#define OASTARTTRIG2_THRESHOLD_ENABLE (1 << 23) +#define OASTARTTRIG2_START_TRIG_FLAG_MBZ (1 << 24) +#define OASTARTTRIG2_EVENT_SELECT_0 (1 << 28) +#define OASTARTTRIG2_EVENT_SELECT_1 (1 << 29) +#define OASTARTTRIG2_EVENT_SELECT_2 (1 << 30) +#define OASTARTTRIG2_EVENT_SELECT_3 (1 << 31) #define OASTARTTRIG3 _MMIO(0x2718) #define OASTARTTRIG3_NOA_SELECT_MASK 0xf @@ -659,35 +659,35 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define OASTARTTRIG5_THRESHOLD_MASK 0xffff #define OASTARTTRIG6 _MMIO(0x2724) -#define OASTARTTRIG6_INVERT_A_0 (1<<0) -#define OASTARTTRIG6_INVERT_A_1 (1<<1) -#define OASTARTTRIG6_INVERT_A_2 (1<<2) -#define OASTARTTRIG6_INVERT_A_3 (1<<3) -#define OASTARTTRIG6_INVERT_A_4 (1<<4) -#define OASTARTTRIG6_INVERT_A_5 (1<<5) -#define OASTARTTRIG6_INVERT_A_6 (1<<6) -#define OASTARTTRIG6_INVERT_A_7 (1<<7) -#define OASTARTTRIG6_INVERT_A_8 (1<<8) -#define OASTARTTRIG6_INVERT_A_9 (1<<9) -#define OASTARTTRIG6_INVERT_A_10 (1<<10) -#define OASTARTTRIG6_INVERT_A_11 (1<<11) -#define OASTARTTRIG6_INVERT_A_12 (1<<12) -#define OASTARTTRIG6_INVERT_A_13 (1<<13) -#define OASTARTTRIG6_INVERT_A_14 (1<<14) -#define OASTARTTRIG6_INVERT_A_15 (1<<15) -#define OASTARTTRIG6_INVERT_B_0 (1<<16) -#define OASTARTTRIG6_INVERT_B_1 (1<<17) -#define OASTARTTRIG6_INVERT_B_2 (1<<18) -#define OASTARTTRIG6_INVERT_B_3 (1<<19) -#define OASTARTTRIG6_INVERT_C_0 (1<<20) -#define OASTARTTRIG6_INVERT_C_1 (1<<21) -#define OASTARTTRIG6_INVERT_D_0 (1<<22) -#define OASTARTTRIG6_THRESHOLD_ENABLE (1<<23) -#define OASTARTTRIG6_START_TRIG_FLAG_MBZ (1<<24) -#define OASTARTTRIG6_EVENT_SELECT_4 (1<<28) -#define OASTARTTRIG6_EVENT_SELECT_5 (1<<29) -#define OASTARTTRIG6_EVENT_SELECT_6 (1<<30) -#define OASTARTTRIG6_EVENT_SELECT_7 (1<<31) +#define OASTARTTRIG6_INVERT_A_0 (1 << 0) +#define OASTARTTRIG6_INVERT_A_1 (1 << 1) +#define OASTARTTRIG6_INVERT_A_2 (1 << 2) +#define OASTARTTRIG6_INVERT_A_3 (1 << 3) +#define OASTARTTRIG6_INVERT_A_4 (1 << 4) +#define OASTARTTRIG6_INVERT_A_5 (1 << 5) +#define OASTARTTRIG6_INVERT_A_6 (1 << 6) +#define OASTARTTRIG6_INVERT_A_7 (1 << 7) +#define OASTARTTRIG6_INVERT_A_8 (1 << 8) +#define OASTARTTRIG6_INVERT_A_9 (1 << 9) +#define OASTARTTRIG6_INVERT_A_10 (1 << 10) +#define OASTARTTRIG6_INVERT_A_11 (1 << 11) +#define OASTARTTRIG6_INVERT_A_12 (1 << 12) +#define OASTARTTRIG6_INVERT_A_13 (1 << 13) +#define OASTARTTRIG6_INVERT_A_14 (1 << 14) +#define OASTARTTRIG6_INVERT_A_15 (1 << 15) +#define OASTARTTRIG6_INVERT_B_0 (1 << 16) +#define OASTARTTRIG6_INVERT_B_1 (1 << 17) +#define OASTARTTRIG6_INVERT_B_2 (1 << 18) +#define OASTARTTRIG6_INVERT_B_3 (1 << 19) +#define OASTARTTRIG6_INVERT_C_0 (1 << 20) +#define OASTARTTRIG6_INVERT_C_1 (1 << 21) +#define OASTARTTRIG6_INVERT_D_0 (1 << 22) +#define OASTARTTRIG6_THRESHOLD_ENABLE (1 << 23) +#define OASTARTTRIG6_START_TRIG_FLAG_MBZ (1 << 24) +#define OASTARTTRIG6_EVENT_SELECT_4 (1 << 28) +#define OASTARTTRIG6_EVENT_SELECT_5 (1 << 29) +#define OASTARTTRIG6_EVENT_SELECT_6 (1 << 30) +#define OASTARTTRIG6_EVENT_SELECT_7 (1 << 31) #define OASTARTTRIG7 _MMIO(0x2728) #define OASTARTTRIG7_NOA_SELECT_MASK 0xf @@ -716,31 +716,31 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define OAREPORTTRIG1_EDGE_LEVEL_TRIGER_SELECT_MASK 0xffff0000 /* 0=level */ #define OAREPORTTRIG2 _MMIO(0x2744) -#define OAREPORTTRIG2_INVERT_A_0 (1<<0) -#define OAREPORTTRIG2_INVERT_A_1 (1<<1) -#define OAREPORTTRIG2_INVERT_A_2 (1<<2) -#define OAREPORTTRIG2_INVERT_A_3 (1<<3) -#define OAREPORTTRIG2_INVERT_A_4 (1<<4) -#define OAREPORTTRIG2_INVERT_A_5 (1<<5) -#define OAREPORTTRIG2_INVERT_A_6 (1<<6) -#define OAREPORTTRIG2_INVERT_A_7 (1<<7) -#define OAREPORTTRIG2_INVERT_A_8 (1<<8) -#define OAREPORTTRIG2_INVERT_A_9 (1<<9) -#define OAREPORTTRIG2_INVERT_A_10 (1<<10) -#define OAREPORTTRIG2_INVERT_A_11 (1<<11) -#define OAREPORTTRIG2_INVERT_A_12 (1<<12) -#define OAREPORTTRIG2_INVERT_A_13 (1<<13) -#define OAREPORTTRIG2_INVERT_A_14 (1<<14) -#define OAREPORTTRIG2_INVERT_A_15 (1<<15) -#define OAREPORTTRIG2_INVERT_B_0 (1<<16) -#define OAREPORTTRIG2_INVERT_B_1 (1<<17) -#define OAREPORTTRIG2_INVERT_B_2 (1<<18) -#define OAREPORTTRIG2_INVERT_B_3 (1<<19) -#define OAREPORTTRIG2_INVERT_C_0 (1<<20) -#define OAREPORTTRIG2_INVERT_C_1 (1<<21) -#define OAREPORTTRIG2_INVERT_D_0 (1<<22) -#define OAREPORTTRIG2_THRESHOLD_ENABLE (1<<23) -#define OAREPORTTRIG2_REPORT_TRIGGER_ENABLE (1<<31) +#define OAREPORTTRIG2_INVERT_A_0 (1 << 0) +#define OAREPORTTRIG2_INVERT_A_1 (1 << 1) +#define OAREPORTTRIG2_INVERT_A_2 (1 << 2) +#define OAREPORTTRIG2_INVERT_A_3 (1 << 3) +#define OAREPORTTRIG2_INVERT_A_4 (1 << 4) +#define OAREPORTTRIG2_INVERT_A_5 (1 << 5) +#define OAREPORTTRIG2_INVERT_A_6 (1 << 6) +#define OAREPORTTRIG2_INVERT_A_7 (1 << 7) +#define OAREPORTTRIG2_INVERT_A_8 (1 << 8) +#define OAREPORTTRIG2_INVERT_A_9 (1 << 9) +#define OAREPORTTRIG2_INVERT_A_10 (1 << 10) +#define OAREPORTTRIG2_INVERT_A_11 (1 << 11) +#define OAREPORTTRIG2_INVERT_A_12 (1 << 12) +#define OAREPORTTRIG2_INVERT_A_13 (1 << 13) +#define OAREPORTTRIG2_INVERT_A_14 (1 << 14) +#define OAREPORTTRIG2_INVERT_A_15 (1 << 15) +#define OAREPORTTRIG2_INVERT_B_0 (1 << 16) +#define OAREPORTTRIG2_INVERT_B_1 (1 << 17) +#define OAREPORTTRIG2_INVERT_B_2 (1 << 18) +#define OAREPORTTRIG2_INVERT_B_3 (1 << 19) +#define OAREPORTTRIG2_INVERT_C_0 (1 << 20) +#define OAREPORTTRIG2_INVERT_C_1 (1 << 21) +#define OAREPORTTRIG2_INVERT_D_0 (1 << 22) +#define OAREPORTTRIG2_THRESHOLD_ENABLE (1 << 23) +#define OAREPORTTRIG2_REPORT_TRIGGER_ENABLE (1 << 31) #define OAREPORTTRIG3 _MMIO(0x2748) #define OAREPORTTRIG3_NOA_SELECT_MASK 0xf @@ -769,31 +769,31 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define OAREPORTTRIG5_EDGE_LEVEL_TRIGER_SELECT_MASK 0xffff0000 /* 0=level */ #define OAREPORTTRIG6 _MMIO(0x2754) -#define OAREPORTTRIG6_INVERT_A_0 (1<<0) -#define OAREPORTTRIG6_INVERT_A_1 (1<<1) -#define OAREPORTTRIG6_INVERT_A_2 (1<<2) -#define OAREPORTTRIG6_INVERT_A_3 (1<<3) -#define OAREPORTTRIG6_INVERT_A_4 (1<<4) -#define OAREPORTTRIG6_INVERT_A_5 (1<<5) -#define OAREPORTTRIG6_INVERT_A_6 (1<<6) -#define OAREPORTTRIG6_INVERT_A_7 (1<<7) -#define OAREPORTTRIG6_INVERT_A_8 (1<<8) -#define OAREPORTTRIG6_INVERT_A_9 (1<<9) -#define OAREPORTTRIG6_INVERT_A_10 (1<<10) -#define OAREPORTTRIG6_INVERT_A_11 (1<<11) -#define OAREPORTTRIG6_INVERT_A_12 (1<<12) -#define OAREPORTTRIG6_INVERT_A_13 (1<<13) -#define OAREPORTTRIG6_INVERT_A_14 (1<<14) -#define OAREPORTTRIG6_INVERT_A_15 (1<<15) -#define OAREPORTTRIG6_INVERT_B_0 (1<<16) -#define OAREPORTTRIG6_INVERT_B_1 (1<<17) -#define OAREPORTTRIG6_INVERT_B_2 (1<<18) -#define OAREPORTTRIG6_INVERT_B_3 (1<<19) -#define OAREPORTTRIG6_INVERT_C_0 (1<<20) -#define OAREPORTTRIG6_INVERT_C_1 (1<<21) -#define OAREPORTTRIG6_INVERT_D_0 (1<<22) -#define OAREPORTTRIG6_THRESHOLD_ENABLE (1<<23) -#define OAREPORTTRIG6_REPORT_TRIGGER_ENABLE (1<<31) +#define OAREPORTTRIG6_INVERT_A_0 (1 << 0) +#define OAREPORTTRIG6_INVERT_A_1 (1 << 1) +#define OAREPORTTRIG6_INVERT_A_2 (1 << 2) +#define OAREPORTTRIG6_INVERT_A_3 (1 << 3) +#define OAREPORTTRIG6_INVERT_A_4 (1 << 4) +#define OAREPORTTRIG6_INVERT_A_5 (1 << 5) +#define OAREPORTTRIG6_INVERT_A_6 (1 << 6) +#define OAREPORTTRIG6_INVERT_A_7 (1 << 7) +#define OAREPORTTRIG6_INVERT_A_8 (1 << 8) +#define OAREPORTTRIG6_INVERT_A_9 (1 << 9) +#define OAREPORTTRIG6_INVERT_A_10 (1 << 10) +#define OAREPORTTRIG6_INVERT_A_11 (1 << 11) +#define OAREPORTTRIG6_INVERT_A_12 (1 << 12) +#define OAREPORTTRIG6_INVERT_A_13 (1 << 13) +#define OAREPORTTRIG6_INVERT_A_14 (1 << 14) +#define OAREPORTTRIG6_INVERT_A_15 (1 << 15) +#define OAREPORTTRIG6_INVERT_B_0 (1 << 16) +#define OAREPORTTRIG6_INVERT_B_1 (1 << 17) +#define OAREPORTTRIG6_INVERT_B_2 (1 << 18) +#define OAREPORTTRIG6_INVERT_B_3 (1 << 19) +#define OAREPORTTRIG6_INVERT_C_0 (1 << 20) +#define OAREPORTTRIG6_INVERT_C_1 (1 << 21) +#define OAREPORTTRIG6_INVERT_D_0 (1 << 22) +#define OAREPORTTRIG6_THRESHOLD_ENABLE (1 << 23) +#define OAREPORTTRIG6_REPORT_TRIGGER_ENABLE (1 << 31) #define OAREPORTTRIG7 _MMIO(0x2758) #define OAREPORTTRIG7_NOA_SELECT_MASK 0xf @@ -829,9 +829,9 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define OACEC_COMPARE_VALUE_MASK 0xffff #define OACEC_COMPARE_VALUE_SHIFT 3 -#define OACEC_SELECT_NOA (0<<19) -#define OACEC_SELECT_PREV (1<<19) -#define OACEC_SELECT_BOOLEAN (2<<19) +#define OACEC_SELECT_NOA (0 << 19) +#define OACEC_SELECT_PREV (1 << 19) +#define OACEC_SELECT_BOOLEAN (2 << 19) /* CECX_1 */ #define OACEC_MASK_MASK 0xffff @@ -949,9 +949,9 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) * Reset registers */ #define DEBUG_RESET_I830 _MMIO(0x6070) -#define DEBUG_RESET_FULL (1<<7) -#define DEBUG_RESET_RENDER (1<<8) -#define DEBUG_RESET_DISPLAY (1<<9) +#define DEBUG_RESET_FULL (1 << 7) +#define DEBUG_RESET_RENDER (1 << 8) +#define DEBUG_RESET_DISPLAY (1 << 9) /* * IOSF sideband @@ -962,7 +962,7 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define IOSF_PORT_SHIFT 8 #define IOSF_BYTE_ENABLES_SHIFT 4 #define IOSF_BAR_SHIFT 1 -#define IOSF_SB_BUSY (1<<0) +#define IOSF_SB_BUSY (1 << 0) #define IOSF_PORT_BUNIT 0x03 #define IOSF_PORT_PUNIT 0x04 #define IOSF_PORT_NC 0x11 @@ -1099,8 +1099,8 @@ enum i915_power_well_id { #define PUNIT_REG_GPU_LFM 0xd3 #define PUNIT_REG_GPU_FREQ_REQ 0xd4 #define PUNIT_REG_GPU_FREQ_STS 0xd8 -#define GPLLENABLE (1<<4) -#define GENFREQSTATUS (1<<0) +#define GPLLENABLE (1 << 4) +#define GENFREQSTATUS (1 << 0) #define PUNIT_REG_MEDIA_TURBO_FREQ_REQ 0xdc #define PUNIT_REG_CZ_TIMESTAMP 0xce @@ -1195,10 +1195,10 @@ enum i915_power_well_id { #define DPIO_DEVFN 0 #define DPIO_CTL _MMIO(VLV_DISPLAY_BASE + 0x2110) -#define DPIO_MODSEL1 (1<<3) /* if ref clk b == 27 */ -#define DPIO_MODSEL0 (1<<2) /* if ref clk a == 27 */ -#define DPIO_SFR_BYPASS (1<<1) -#define DPIO_CMNRST (1<<0) +#define DPIO_MODSEL1 (1 << 3) /* if ref clk b == 27 */ +#define DPIO_MODSEL0 (1 << 2) /* if ref clk a == 27 */ +#define DPIO_SFR_BYPASS (1 << 1) +#define DPIO_CMNRST (1 << 0) #define DPIO_PHY(pipe) ((pipe) >> 1) #define DPIO_PHY_IOSF_PORT(phy) (dev_priv->dpio_phy_iosf_port[phy]) @@ -1216,7 +1216,7 @@ enum i915_power_well_id { #define DPIO_P1_SHIFT (21) /* 3 bits */ #define DPIO_P2_SHIFT (16) /* 5 bits */ #define DPIO_N_SHIFT (12) /* 4 bits */ -#define DPIO_ENABLE_CALIBRATION (1<<11) +#define DPIO_ENABLE_CALIBRATION (1 << 11) #define DPIO_M1DIV_SHIFT (8) /* 3 bits */ #define DPIO_M2DIV_MASK 0xff #define _VLV_PLL_DW3_CH1 0x802c @@ -1265,10 +1265,10 @@ enum i915_power_well_id { #define _VLV_PCS_DW0_CH0 0x8200 #define _VLV_PCS_DW0_CH1 0x8400 -#define DPIO_PCS_TX_LANE2_RESET (1<<16) -#define DPIO_PCS_TX_LANE1_RESET (1<<7) -#define DPIO_LEFT_TXFIFO_RST_MASTER2 (1<<4) -#define DPIO_RIGHT_TXFIFO_RST_MASTER2 (1<<3) +#define DPIO_PCS_TX_LANE2_RESET (1 << 16) +#define DPIO_PCS_TX_LANE1_RESET (1 << 7) +#define DPIO_LEFT_TXFIFO_RST_MASTER2 (1 << 4) +#define DPIO_RIGHT_TXFIFO_RST_MASTER2 (1 << 3) #define VLV_PCS_DW0(ch) _PORT(ch, _VLV_PCS_DW0_CH0, _VLV_PCS_DW0_CH1) #define _VLV_PCS01_DW0_CH0 0x200 @@ -1280,11 +1280,11 @@ enum i915_power_well_id { #define _VLV_PCS_DW1_CH0 0x8204 #define _VLV_PCS_DW1_CH1 0x8404 -#define CHV_PCS_REQ_SOFTRESET_EN (1<<23) -#define DPIO_PCS_CLK_CRI_RXEB_EIOS_EN (1<<22) -#define DPIO_PCS_CLK_CRI_RXDIGFILTSG_EN (1<<21) +#define CHV_PCS_REQ_SOFTRESET_EN (1 << 23) +#define DPIO_PCS_CLK_CRI_RXEB_EIOS_EN (1 << 22) +#define DPIO_PCS_CLK_CRI_RXDIGFILTSG_EN (1 << 21) #define DPIO_PCS_CLK_DATAWIDTH_SHIFT (6) -#define DPIO_PCS_CLK_SOFT_RESET (1<<5) +#define DPIO_PCS_CLK_SOFT_RESET (1 << 5) #define VLV_PCS_DW1(ch) _PORT(ch, _VLV_PCS_DW1_CH0, _VLV_PCS_DW1_CH1) #define _VLV_PCS01_DW1_CH0 0x204 @@ -1309,12 +1309,12 @@ enum i915_power_well_id { #define _VLV_PCS_DW9_CH0 0x8224 #define _VLV_PCS_DW9_CH1 0x8424 -#define DPIO_PCS_TX2MARGIN_MASK (0x7<<13) -#define DPIO_PCS_TX2MARGIN_000 (0<<13) -#define DPIO_PCS_TX2MARGIN_101 (1<<13) -#define DPIO_PCS_TX1MARGIN_MASK (0x7<<10) -#define DPIO_PCS_TX1MARGIN_000 (0<<10) -#define DPIO_PCS_TX1MARGIN_101 (1<<10) +#define DPIO_PCS_TX2MARGIN_MASK (0x7 << 13) +#define DPIO_PCS_TX2MARGIN_000 (0 << 13) +#define DPIO_PCS_TX2MARGIN_101 (1 << 13) +#define DPIO_PCS_TX1MARGIN_MASK (0x7 << 10) +#define DPIO_PCS_TX1MARGIN_000 (0 << 10) +#define DPIO_PCS_TX1MARGIN_101 (1 << 10) #define VLV_PCS_DW9(ch) _PORT(ch, _VLV_PCS_DW9_CH0, _VLV_PCS_DW9_CH1) #define _VLV_PCS01_DW9_CH0 0x224 @@ -1326,14 +1326,14 @@ enum i915_power_well_id { #define _CHV_PCS_DW10_CH0 0x8228 #define _CHV_PCS_DW10_CH1 0x8428 -#define DPIO_PCS_SWING_CALC_TX0_TX2 (1<<30) -#define DPIO_PCS_SWING_CALC_TX1_TX3 (1<<31) -#define DPIO_PCS_TX2DEEMP_MASK (0xf<<24) -#define DPIO_PCS_TX2DEEMP_9P5 (0<<24) -#define DPIO_PCS_TX2DEEMP_6P0 (2<<24) -#define DPIO_PCS_TX1DEEMP_MASK (0xf<<16) -#define DPIO_PCS_TX1DEEMP_9P5 (0<<16) -#define DPIO_PCS_TX1DEEMP_6P0 (2<<16) +#define DPIO_PCS_SWING_CALC_TX0_TX2 (1 << 30) +#define DPIO_PCS_SWING_CALC_TX1_TX3 (1 << 31) +#define DPIO_PCS_TX2DEEMP_MASK (0xf << 24) +#define DPIO_PCS_TX2DEEMP_9P5 (0 << 24) +#define DPIO_PCS_TX2DEEMP_6P0 (2 << 24) +#define DPIO_PCS_TX1DEEMP_MASK (0xf << 16) +#define DPIO_PCS_TX1DEEMP_9P5 (0 << 16) +#define DPIO_PCS_TX1DEEMP_6P0 (2 << 16) #define CHV_PCS_DW10(ch) _PORT(ch, _CHV_PCS_DW10_CH0, _CHV_PCS_DW10_CH1) #define _VLV_PCS01_DW10_CH0 0x0228 @@ -1345,10 +1345,10 @@ enum i915_power_well_id { #define _VLV_PCS_DW11_CH0 0x822c #define _VLV_PCS_DW11_CH1 0x842c -#define DPIO_TX2_STAGGER_MASK(x) ((x)<<24) -#define DPIO_LANEDESKEW_STRAP_OVRD (1<<3) -#define DPIO_LEFT_TXFIFO_RST_MASTER (1<<1) -#define DPIO_RIGHT_TXFIFO_RST_MASTER (1<<0) +#define DPIO_TX2_STAGGER_MASK(x) ((x) << 24) +#define DPIO_LANEDESKEW_STRAP_OVRD (1 << 3) +#define DPIO_LEFT_TXFIFO_RST_MASTER (1 << 1) +#define DPIO_RIGHT_TXFIFO_RST_MASTER (1 << 0) #define VLV_PCS_DW11(ch) _PORT(ch, _VLV_PCS_DW11_CH0, _VLV_PCS_DW11_CH1) #define _VLV_PCS01_DW11_CH0 0x022c @@ -1367,11 +1367,11 @@ enum i915_power_well_id { #define _VLV_PCS_DW12_CH0 0x8230 #define _VLV_PCS_DW12_CH1 0x8430 -#define DPIO_TX2_STAGGER_MULT(x) ((x)<<20) -#define DPIO_TX1_STAGGER_MULT(x) ((x)<<16) -#define DPIO_TX1_STAGGER_MASK(x) ((x)<<8) -#define DPIO_LANESTAGGER_STRAP_OVRD (1<<6) -#define DPIO_LANESTAGGER_STRAP(x) ((x)<<0) +#define DPIO_TX2_STAGGER_MULT(x) ((x) << 20) +#define DPIO_TX1_STAGGER_MULT(x) ((x) << 16) +#define DPIO_TX1_STAGGER_MASK(x) ((x) << 8) +#define DPIO_LANESTAGGER_STRAP_OVRD (1 << 6) +#define DPIO_LANESTAGGER_STRAP(x) ((x) << 0) #define VLV_PCS_DW12(ch) _PORT(ch, _VLV_PCS_DW12_CH0, _VLV_PCS_DW12_CH1) #define _VLV_PCS_DW14_CH0 0x8238 @@ -1392,7 +1392,7 @@ enum i915_power_well_id { #define _VLV_TX_DW3_CH0 0x828c #define _VLV_TX_DW3_CH1 0x848c /* The following bit for CHV phy */ -#define DPIO_TX_UNIQ_TRANS_SCALE_EN (1<<27) +#define DPIO_TX_UNIQ_TRANS_SCALE_EN (1 << 27) #define DPIO_SWING_MARGIN101_SHIFT 16 #define DPIO_SWING_MARGIN101_MASK (0xff << DPIO_SWING_MARGIN101_SHIFT) #define VLV_TX_DW3(ch) _PORT(ch, _VLV_TX_DW3_CH0, _VLV_TX_DW3_CH1) @@ -1411,7 +1411,7 @@ enum i915_power_well_id { #define _VLV_TX_DW5_CH0 0x8294 #define _VLV_TX_DW5_CH1 0x8494 -#define DPIO_TX_OCALINIT_EN (1<<31) +#define DPIO_TX_OCALINIT_EN (1 << 31) #define VLV_TX_DW5(ch) _PORT(ch, _VLV_TX_DW5_CH0, _VLV_TX_DW5_CH1) #define _VLV_TX_DW11_CH0 0x82ac @@ -1641,10 +1641,10 @@ enum i915_power_well_id { #define PORT_PLL_LOCK_THRESHOLD_SHIFT 1 #define PORT_PLL_LOCK_THRESHOLD_MASK (0x7 << PORT_PLL_LOCK_THRESHOLD_SHIFT) /* PORT_PLL_10_A */ -#define PORT_PLL_DCO_AMP_OVR_EN_H (1<<27) +#define PORT_PLL_DCO_AMP_OVR_EN_H (1 << 27) #define PORT_PLL_DCO_AMP_DEFAULT 15 #define PORT_PLL_DCO_AMP_MASK 0x3c00 -#define PORT_PLL_DCO_AMP(x) ((x)<<10) +#define PORT_PLL_DCO_AMP(x) ((x) << 10) #define _PORT_PLL_BASE(phy, ch) _BXT_PHY_CH(phy, ch, \ _PORT_PLL_0_B, \ _PORT_PLL_0_C) @@ -1746,7 +1746,7 @@ enum i915_power_well_id { _CNL_PORT_TX_D_GRP_OFFSET, \ _CNL_PORT_TX_AE_GRP_OFFSET, \ _CNL_PORT_TX_F_GRP_OFFSET) + \ - 4*(dw)) + 4 * (dw)) #define _CNL_PORT_TX_DW_LN0(port, dw) (_PICK((port), \ _CNL_PORT_TX_AE_LN0_OFFSET, \ _CNL_PORT_TX_B_LN0_OFFSET, \ @@ -1754,7 +1754,7 @@ enum i915_power_well_id { _CNL_PORT_TX_D_LN0_OFFSET, \ _CNL_PORT_TX_AE_LN0_OFFSET, \ _CNL_PORT_TX_F_LN0_OFFSET) + \ - 4*(dw)) + 4 * (dw)) #define CNL_PORT_TX_DW2_GRP(port) _MMIO(_CNL_PORT_TX_DW_GRP((port), 2)) #define CNL_PORT_TX_DW2_LN0(port) _MMIO(_CNL_PORT_TX_DW_LN0((port), 2)) @@ -2140,8 +2140,8 @@ enum i915_power_well_id { /* SKL balance leg register */ #define DISPIO_CR_TX_BMU_CR0 _MMIO(0x6C00C) /* I_boost values */ -#define BALANCE_LEG_SHIFT(port) (8+3*(port)) -#define BALANCE_LEG_MASK(port) (7<<(8+3*(port))) +#define BALANCE_LEG_SHIFT(port) (8 + 3 * (port)) +#define BALANCE_LEG_MASK(port) (7 << (8 + 3 * (port))) /* Balance leg disable bits */ #define BALANCE_LEG_DISABLE_SHIFT 23 #define BALANCE_LEG_DISABLE(port) (1 << (23 + (port))) @@ -2161,10 +2161,10 @@ enum i915_power_well_id { #define I830_FENCE_TILING_Y_SHIFT 12 #define I830_FENCE_SIZE_BITS(size) ((ffs((size) >> 19) - 1) << 8) #define I830_FENCE_PITCH_SHIFT 4 -#define I830_FENCE_REG_VALID (1<<0) +#define I830_FENCE_REG_VALID (1 << 0) #define I915_FENCE_MAX_PITCH_VAL 4 #define I830_FENCE_MAX_PITCH_VAL 6 -#define I830_FENCE_MAX_SIZE_VAL (1<<8) +#define I830_FENCE_MAX_SIZE_VAL (1 << 8) #define I915_FENCE_START_MASK 0x0ff00000 #define I915_FENCE_SIZE_BITS(size) ((ffs((size) >> 20) - 1) << 8) @@ -2173,7 +2173,7 @@ enum i915_power_well_id { #define FENCE_REG_965_HI(i) _MMIO(0x03000 + (i) * 8 + 4) #define I965_FENCE_PITCH_SHIFT 2 #define I965_FENCE_TILING_Y_SHIFT 1 -#define I965_FENCE_REG_VALID (1<<0) +#define I965_FENCE_REG_VALID (1 << 0) #define I965_FENCE_MAX_PITCH_VAL 0x0400 #define FENCE_REG_GEN6_LO(i) _MMIO(0x100000 + (i) * 8) @@ -2196,13 +2196,13 @@ enum i915_power_well_id { #define PGTBL_ADDRESS_LO_MASK 0xfffff000 /* bits [31:12] */ #define PGTBL_ADDRESS_HI_MASK 0x000000f0 /* bits [35:32] (gen4) */ #define PGTBL_ER _MMIO(0x02024) -#define PRB0_BASE (0x2030-0x30) -#define PRB1_BASE (0x2040-0x30) /* 830,gen3 */ -#define PRB2_BASE (0x2050-0x30) /* gen3 */ -#define SRB0_BASE (0x2100-0x30) /* gen2 */ -#define SRB1_BASE (0x2110-0x30) /* gen2 */ -#define SRB2_BASE (0x2120-0x30) /* 830 */ -#define SRB3_BASE (0x2130-0x30) /* 830 */ +#define PRB0_BASE (0x2030 - 0x30) +#define PRB1_BASE (0x2040 - 0x30) /* 830,gen3 */ +#define PRB2_BASE (0x2050 - 0x30) /* gen3 */ +#define SRB0_BASE (0x2100 - 0x30) /* gen2 */ +#define SRB1_BASE (0x2110 - 0x30) /* gen2 */ +#define SRB2_BASE (0x2120 - 0x30) /* 830 */ +#define SRB3_BASE (0x2130 - 0x30) /* 830 */ #define RENDER_RING_BASE 0x02000 #define BSD_RING_BASE 0x04000 #define GEN6_BSD_RING_BASE 0x12000 @@ -2215,14 +2215,14 @@ enum i915_power_well_id { #define GEN11_VEBOX_RING_BASE 0x1c8000 #define GEN11_VEBOX2_RING_BASE 0x1d8000 #define BLT_RING_BASE 0x22000 -#define RING_TAIL(base) _MMIO((base)+0x30) -#define RING_HEAD(base) _MMIO((base)+0x34) -#define RING_START(base) _MMIO((base)+0x38) -#define RING_CTL(base) _MMIO((base)+0x3c) +#define RING_TAIL(base) _MMIO((base) + 0x30) +#define RING_HEAD(base) _MMIO((base) + 0x34) +#define RING_START(base) _MMIO((base) + 0x38) +#define RING_CTL(base) _MMIO((base) + 0x3c) #define RING_CTL_SIZE(size) ((size) - PAGE_SIZE) /* in bytes -> pages */ -#define RING_SYNC_0(base) _MMIO((base)+0x40) -#define RING_SYNC_1(base) _MMIO((base)+0x44) -#define RING_SYNC_2(base) _MMIO((base)+0x48) +#define RING_SYNC_0(base) _MMIO((base) + 0x40) +#define RING_SYNC_1(base) _MMIO((base) + 0x44) +#define RING_SYNC_2(base) _MMIO((base) + 0x48) #define GEN6_RVSYNC (RING_SYNC_0(RENDER_RING_BASE)) #define GEN6_RBSYNC (RING_SYNC_1(RENDER_RING_BASE)) #define GEN6_RVESYNC (RING_SYNC_2(RENDER_RING_BASE)) @@ -2236,11 +2236,11 @@ enum i915_power_well_id { #define GEN6_VERSYNC (RING_SYNC_1(VEBOX_RING_BASE)) #define GEN6_VEVSYNC (RING_SYNC_2(VEBOX_RING_BASE)) #define GEN6_NOSYNC INVALID_MMIO_REG -#define RING_PSMI_CTL(base) _MMIO((base)+0x50) -#define RING_MAX_IDLE(base) _MMIO((base)+0x54) -#define RING_HWS_PGA(base) _MMIO((base)+0x80) -#define RING_HWS_PGA_GEN6(base) _MMIO((base)+0x2080) -#define RING_RESET_CTL(base) _MMIO((base)+0xd0) +#define RING_PSMI_CTL(base) _MMIO((base) + 0x50) +#define RING_MAX_IDLE(base) _MMIO((base) + 0x54) +#define RING_HWS_PGA(base) _MMIO((base) + 0x80) +#define RING_HWS_PGA_GEN6(base) _MMIO((base) + 0x2080) +#define RING_RESET_CTL(base) _MMIO((base) + 0xd0) #define RESET_CTL_REQUEST_RESET (1 << 0) #define RESET_CTL_READY_TO_RESET (1 << 1) #define RING_SEMA_WAIT_POLL(base) _MMIO((base) + 0x24c) @@ -2250,8 +2250,8 @@ enum i915_power_well_id { #define GEN7_WR_WATERMARK _MMIO(0x4028) #define GEN7_GFX_PRIO_CTRL _MMIO(0x402C) #define ARB_MODE _MMIO(0x4030) -#define ARB_MODE_SWIZZLE_SNB (1<<4) -#define ARB_MODE_SWIZZLE_IVB (1<<5) +#define ARB_MODE_SWIZZLE_SNB (1 << 4) +#define ARB_MODE_SWIZZLE_IVB (1 << 5) #define GEN7_GFX_PEND_TLB0 _MMIO(0x4034) #define GEN7_GFX_PEND_TLB1 _MMIO(0x4038) /* L3, CVS, ZTLB, RCC, CASC LRA min, max values */ @@ -2261,30 +2261,30 @@ enum i915_power_well_id { #define GEN7_GFX_MAX_REQ_COUNT _MMIO(0x4074) #define GAMTARBMODE _MMIO(0x04a08) -#define ARB_MODE_BWGTLB_DISABLE (1<<9) -#define ARB_MODE_SWIZZLE_BDW (1<<1) +#define ARB_MODE_BWGTLB_DISABLE (1 << 9) +#define ARB_MODE_SWIZZLE_BDW (1 << 1) #define RENDER_HWS_PGA_GEN7 _MMIO(0x04080) -#define RING_FAULT_REG(engine) _MMIO(0x4094 + 0x100*(engine)->hw_id) +#define RING_FAULT_REG(engine) _MMIO(0x4094 + 0x100 * (engine)->hw_id) #define GEN8_RING_FAULT_REG _MMIO(0x4094) #define GEN8_RING_FAULT_ENGINE_ID(x) (((x) >> 12) & 0x7) -#define RING_FAULT_GTTSEL_MASK (1<<11) +#define RING_FAULT_GTTSEL_MASK (1 << 11) #define RING_FAULT_SRCID(x) (((x) >> 3) & 0xff) #define RING_FAULT_FAULT_TYPE(x) (((x) >> 1) & 0x3) -#define RING_FAULT_VALID (1<<0) +#define RING_FAULT_VALID (1 << 0) #define DONE_REG _MMIO(0x40b0) #define GEN8_PRIVATE_PAT_LO _MMIO(0x40e0) #define GEN8_PRIVATE_PAT_HI _MMIO(0x40e0 + 4) -#define GEN10_PAT_INDEX(index) _MMIO(0x40e0 + (index)*4) +#define GEN10_PAT_INDEX(index) _MMIO(0x40e0 + (index) * 4) #define BSD_HWS_PGA_GEN7 _MMIO(0x04180) #define BLT_HWS_PGA_GEN7 _MMIO(0x04280) #define VEBOX_HWS_PGA_GEN7 _MMIO(0x04380) -#define RING_ACTHD(base) _MMIO((base)+0x74) -#define RING_ACTHD_UDW(base) _MMIO((base)+0x5c) -#define RING_NOPID(base) _MMIO((base)+0x94) -#define RING_IMR(base) _MMIO((base)+0xa8) -#define RING_HWSTAM(base) _MMIO((base)+0x98) -#define RING_TIMESTAMP(base) _MMIO((base)+0x358) -#define RING_TIMESTAMP_UDW(base) _MMIO((base)+0x358 + 4) +#define RING_ACTHD(base) _MMIO((base) + 0x74) +#define RING_ACTHD_UDW(base) _MMIO((base) + 0x5c) +#define RING_NOPID(base) _MMIO((base) + 0x94) +#define RING_IMR(base) _MMIO((base) + 0xa8) +#define RING_HWSTAM(base) _MMIO((base) + 0x98) +#define RING_TIMESTAMP(base) _MMIO((base) + 0x358) +#define RING_TIMESTAMP_UDW(base) _MMIO((base) + 0x358 + 4) #define TAIL_ADDR 0x001FFFF8 #define HEAD_WRAP_COUNT 0xFFE00000 #define HEAD_WRAP_ONE 0x00200000 @@ -2297,17 +2297,17 @@ enum i915_power_well_id { #define RING_VALID_MASK 0x00000001 #define RING_VALID 0x00000001 #define RING_INVALID 0x00000000 -#define RING_WAIT_I8XX (1<<0) /* gen2, PRBx_HEAD */ -#define RING_WAIT (1<<11) /* gen3+, PRBx_CTL */ -#define RING_WAIT_SEMAPHORE (1<<10) /* gen6+ */ +#define RING_WAIT_I8XX (1 << 0) /* gen2, PRBx_HEAD */ +#define RING_WAIT (1 << 11) /* gen3+, PRBx_CTL */ +#define RING_WAIT_SEMAPHORE (1 << 10) /* gen6+ */ -#define RING_FORCE_TO_NONPRIV(base, i) _MMIO(((base)+0x4D0) + (i)*4) +#define RING_FORCE_TO_NONPRIV(base, i) _MMIO(((base) + 0x4D0) + (i) * 4) #define RING_MAX_NONPRIV_SLOTS 12 #define GEN7_TLB_RD_ADDR _MMIO(0x4700) #define GEN9_GAMT_ECO_REG_RW_IA _MMIO(0x4ab0) -#define GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS (1<<18) +#define GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS (1 << 18) #define GEN8_GAMW_ECO_DEV_RW_IA _MMIO(0x4080) #define GAMW_ECO_ENABLE_64K_IPS_FIELD 0xF @@ -2341,19 +2341,19 @@ enum i915_power_well_id { #define GEN11_MCR_SLICE_MASK GEN11_MCR_SLICE(0xf) #define GEN11_MCR_SUBSLICE(subslice) (((subslice) & 0x7) << 24) #define GEN11_MCR_SUBSLICE_MASK GEN11_MCR_SUBSLICE(0x7) -#define RING_IPEIR(base) _MMIO((base)+0x64) -#define RING_IPEHR(base) _MMIO((base)+0x68) +#define RING_IPEIR(base) _MMIO((base) + 0x64) +#define RING_IPEHR(base) _MMIO((base) + 0x68) /* * On GEN4, only the render ring INSTDONE exists and has a different * layout than the GEN7+ version. * The GEN2 counterpart of this register is GEN2_INSTDONE. */ -#define RING_INSTDONE(base) _MMIO((base)+0x6c) -#define RING_INSTPS(base) _MMIO((base)+0x70) -#define RING_DMA_FADD(base) _MMIO((base)+0x78) -#define RING_DMA_FADD_UDW(base) _MMIO((base)+0x60) /* gen8+ */ -#define RING_INSTPM(base) _MMIO((base)+0xc0) -#define RING_MI_MODE(base) _MMIO((base)+0x9c) +#define RING_INSTDONE(base) _MMIO((base) + 0x6c) +#define RING_INSTPS(base) _MMIO((base) + 0x70) +#define RING_DMA_FADD(base) _MMIO((base) + 0x78) +#define RING_DMA_FADD_UDW(base) _MMIO((base) + 0x60) /* gen8+ */ +#define RING_INSTPM(base) _MMIO((base) + 0xc0) +#define RING_MI_MODE(base) _MMIO((base) + 0x9c) #define INSTPS _MMIO(0x2070) /* 965+ only */ #define GEN4_INSTDONE1 _MMIO(0x207c) /* 965+ only, aka INSTDONE_2 on SNB */ #define ACTHD_I965 _MMIO(0x2074) @@ -2361,37 +2361,37 @@ enum i915_power_well_id { #define HWS_ADDRESS_MASK 0xfffff000 #define HWS_START_ADDRESS_SHIFT 4 #define PWRCTXA _MMIO(0x2088) /* 965GM+ only */ -#define PWRCTX_EN (1<<0) +#define PWRCTX_EN (1 << 0) #define IPEIR _MMIO(0x2088) #define IPEHR _MMIO(0x208c) #define GEN2_INSTDONE _MMIO(0x2090) #define NOPID _MMIO(0x2094) #define HWSTAM _MMIO(0x2098) #define DMA_FADD_I8XX _MMIO(0x20d0) -#define RING_BBSTATE(base) _MMIO((base)+0x110) +#define RING_BBSTATE(base) _MMIO((base) + 0x110) #define RING_BB_PPGTT (1 << 5) -#define RING_SBBADDR(base) _MMIO((base)+0x114) /* hsw+ */ -#define RING_SBBSTATE(base) _MMIO((base)+0x118) /* hsw+ */ -#define RING_SBBADDR_UDW(base) _MMIO((base)+0x11c) /* gen8+ */ -#define RING_BBADDR(base) _MMIO((base)+0x140) -#define RING_BBADDR_UDW(base) _MMIO((base)+0x168) /* gen8+ */ -#define RING_BB_PER_CTX_PTR(base) _MMIO((base)+0x1c0) /* gen8+ */ -#define RING_INDIRECT_CTX(base) _MMIO((base)+0x1c4) /* gen8+ */ -#define RING_INDIRECT_CTX_OFFSET(base) _MMIO((base)+0x1c8) /* gen8+ */ -#define RING_CTX_TIMESTAMP(base) _MMIO((base)+0x3a8) /* gen8+ */ +#define RING_SBBADDR(base) _MMIO((base) + 0x114) /* hsw+ */ +#define RING_SBBSTATE(base) _MMIO((base) + 0x118) /* hsw+ */ +#define RING_SBBADDR_UDW(base) _MMIO((base) + 0x11c) /* gen8+ */ +#define RING_BBADDR(base) _MMIO((base) + 0x140) +#define RING_BBADDR_UDW(base) _MMIO((base) + 0x168) /* gen8+ */ +#define RING_BB_PER_CTX_PTR(base) _MMIO((base) + 0x1c0) /* gen8+ */ +#define RING_INDIRECT_CTX(base) _MMIO((base) + 0x1c4) /* gen8+ */ +#define RING_INDIRECT_CTX_OFFSET(base) _MMIO((base) + 0x1c8) /* gen8+ */ +#define RING_CTX_TIMESTAMP(base) _MMIO((base) + 0x3a8) /* gen8+ */ #define ERROR_GEN6 _MMIO(0x40a0) #define GEN7_ERR_INT _MMIO(0x44040) -#define ERR_INT_POISON (1<<31) -#define ERR_INT_MMIO_UNCLAIMED (1<<13) -#define ERR_INT_PIPE_CRC_DONE_C (1<<8) -#define ERR_INT_FIFO_UNDERRUN_C (1<<6) -#define ERR_INT_PIPE_CRC_DONE_B (1<<5) -#define ERR_INT_FIFO_UNDERRUN_B (1<<3) -#define ERR_INT_PIPE_CRC_DONE_A (1<<2) -#define ERR_INT_PIPE_CRC_DONE(pipe) (1<<(2 + (pipe)*3)) -#define ERR_INT_FIFO_UNDERRUN_A (1<<0) -#define ERR_INT_FIFO_UNDERRUN(pipe) (1<<((pipe)*3)) +#define ERR_INT_POISON (1 << 31) +#define ERR_INT_MMIO_UNCLAIMED (1 << 13) +#define ERR_INT_PIPE_CRC_DONE_C (1 << 8) +#define ERR_INT_FIFO_UNDERRUN_C (1 << 6) +#define ERR_INT_PIPE_CRC_DONE_B (1 << 5) +#define ERR_INT_FIFO_UNDERRUN_B (1 << 3) +#define ERR_INT_PIPE_CRC_DONE_A (1 << 2) +#define ERR_INT_PIPE_CRC_DONE(pipe) (1 << (2 + (pipe) * 3)) +#define ERR_INT_FIFO_UNDERRUN_A (1 << 0) +#define ERR_INT_FIFO_UNDERRUN(pipe) (1 << ((pipe) * 3)) #define GEN8_FAULT_TLB_DATA0 _MMIO(0x4b10) #define GEN8_FAULT_TLB_DATA1 _MMIO(0x4b14) @@ -2399,7 +2399,7 @@ enum i915_power_well_id { #define FAULT_GTT_SEL (1 << 4) #define FPGA_DBG _MMIO(0x42300) -#define FPGA_DBG_RM_NOCLAIM (1<<31) +#define FPGA_DBG_RM_NOCLAIM (1 << 31) #define CLAIM_ER _MMIO(VLV_DISPLAY_BASE + 0x2028) #define CLAIM_ER_CLR (1 << 31) @@ -2408,22 +2408,22 @@ enum i915_power_well_id { #define DERRMR _MMIO(0x44050) /* Note that HBLANK events are reserved on bdw+ */ -#define DERRMR_PIPEA_SCANLINE (1<<0) -#define DERRMR_PIPEA_PRI_FLIP_DONE (1<<1) -#define DERRMR_PIPEA_SPR_FLIP_DONE (1<<2) -#define DERRMR_PIPEA_VBLANK (1<<3) -#define DERRMR_PIPEA_HBLANK (1<<5) -#define DERRMR_PIPEB_SCANLINE (1<<8) -#define DERRMR_PIPEB_PRI_FLIP_DONE (1<<9) -#define DERRMR_PIPEB_SPR_FLIP_DONE (1<<10) -#define DERRMR_PIPEB_VBLANK (1<<11) -#define DERRMR_PIPEB_HBLANK (1<<13) +#define DERRMR_PIPEA_SCANLINE (1 << 0) +#define DERRMR_PIPEA_PRI_FLIP_DONE (1 << 1) +#define DERRMR_PIPEA_SPR_FLIP_DONE (1 << 2) +#define DERRMR_PIPEA_VBLANK (1 << 3) +#define DERRMR_PIPEA_HBLANK (1 << 5) +#define DERRMR_PIPEB_SCANLINE (1 << 8) +#define DERRMR_PIPEB_PRI_FLIP_DONE (1 << 9) +#define DERRMR_PIPEB_SPR_FLIP_DONE (1 << 10) +#define DERRMR_PIPEB_VBLANK (1 << 11) +#define DERRMR_PIPEB_HBLANK (1 << 13) /* Note that PIPEC is not a simple translation of PIPEA/PIPEB */ -#define DERRMR_PIPEC_SCANLINE (1<<14) -#define DERRMR_PIPEC_PRI_FLIP_DONE (1<<15) -#define DERRMR_PIPEC_SPR_FLIP_DONE (1<<20) -#define DERRMR_PIPEC_VBLANK (1<<21) -#define DERRMR_PIPEC_HBLANK (1<<22) +#define DERRMR_PIPEC_SCANLINE (1 << 14) +#define DERRMR_PIPEC_PRI_FLIP_DONE (1 << 15) +#define DERRMR_PIPEC_SPR_FLIP_DONE (1 << 20) +#define DERRMR_PIPEC_VBLANK (1 << 21) +#define DERRMR_PIPEC_HBLANK (1 << 22) /* GM45+ chicken bits -- debug workaround bits that may be required @@ -2447,7 +2447,7 @@ enum i915_power_well_id { #define _3D_CHICKEN_SF_DISABLE_OBJEND_CULL (1 << 10) #define _3D_CHICKEN3_AA_LINE_QUALITY_FIX_ENABLE (1 << 5) #define _3D_CHICKEN3_SF_DISABLE_FASTCLIP_CULL (1 << 5) -#define _3D_CHICKEN_SDE_LIMIT_FIFO_POLY_DEPTH(x) ((x)<<1) /* gen8+ */ +#define _3D_CHICKEN_SDE_LIMIT_FIFO_POLY_DEPTH(x) ((x) << 1) /* gen8+ */ #define _3D_CHICKEN3_SF_DISABLE_PIPELINED_ATTR_FETCH (1 << 1) /* gen6 */ #define MI_MODE _MMIO(0x209c) @@ -2486,22 +2486,22 @@ enum i915_power_well_id { #define GFX_MODE _MMIO(0x2520) #define GFX_MODE_GEN7 _MMIO(0x229c) -#define RING_MODE_GEN7(engine) _MMIO((engine)->mmio_base+0x29c) -#define GFX_RUN_LIST_ENABLE (1<<15) -#define GFX_INTERRUPT_STEERING (1<<14) -#define GFX_TLB_INVALIDATE_EXPLICIT (1<<13) -#define GFX_SURFACE_FAULT_ENABLE (1<<12) -#define GFX_REPLAY_MODE (1<<11) -#define GFX_PSMI_GRANULARITY (1<<10) -#define GFX_PPGTT_ENABLE (1<<9) -#define GEN8_GFX_PPGTT_48B (1<<7) - -#define GFX_FORWARD_VBLANK_MASK (3<<5) -#define GFX_FORWARD_VBLANK_NEVER (0<<5) -#define GFX_FORWARD_VBLANK_ALWAYS (1<<5) -#define GFX_FORWARD_VBLANK_COND (2<<5) - -#define GEN11_GFX_DISABLE_LEGACY_MODE (1<<3) +#define RING_MODE_GEN7(engine) _MMIO((engine)->mmio_base + 0x29c) +#define GFX_RUN_LIST_ENABLE (1 << 15) +#define GFX_INTERRUPT_STEERING (1 << 14) +#define GFX_TLB_INVALIDATE_EXPLICIT (1 << 13) +#define GFX_SURFACE_FAULT_ENABLE (1 << 12) +#define GFX_REPLAY_MODE (1 << 11) +#define GFX_PSMI_GRANULARITY (1 << 10) +#define GFX_PPGTT_ENABLE (1 << 9) +#define GEN8_GFX_PPGTT_48B (1 << 7) + +#define GFX_FORWARD_VBLANK_MASK (3 << 5) +#define GFX_FORWARD_VBLANK_NEVER (0 << 5) +#define GFX_FORWARD_VBLANK_ALWAYS (1 << 5) +#define GFX_FORWARD_VBLANK_COND (2 << 5) + +#define GEN11_GFX_DISABLE_LEGACY_MODE (1 << 3) #define VLV_DISPLAY_BASE 0x180000 #define VLV_MIPI_BASE VLV_DISPLAY_BASE @@ -2515,8 +2515,8 @@ enum i915_power_well_id { #define IMR _MMIO(0x20a8) #define ISR _MMIO(0x20ac) #define VLV_GUNIT_CLOCK_GATE _MMIO(VLV_DISPLAY_BASE + 0x2060) -#define GINT_DIS (1<<22) -#define GCFG_DIS (1<<8) +#define GINT_DIS (1 << 22) +#define GCFG_DIS (1 << 8) #define VLV_GUNIT_CLOCK_GATE2 _MMIO(VLV_DISPLAY_BASE + 0x2064) #define VLV_IIR_RW _MMIO(VLV_DISPLAY_BASE + 0x2084) #define VLV_IER _MMIO(VLV_DISPLAY_BASE + 0x20a0) @@ -2526,35 +2526,35 @@ enum i915_power_well_id { #define VLV_PCBR _MMIO(VLV_DISPLAY_BASE + 0x2120) #define VLV_PCBR_ADDR_SHIFT 12 -#define DISPLAY_PLANE_FLIP_PENDING(plane) (1<<(11-(plane))) /* A and B only */ +#define DISPLAY_PLANE_FLIP_PENDING(plane) (1 << (11 - (plane))) /* A and B only */ #define EIR _MMIO(0x20b0) #define EMR _MMIO(0x20b4) #define ESR _MMIO(0x20b8) -#define GM45_ERROR_PAGE_TABLE (1<<5) -#define GM45_ERROR_MEM_PRIV (1<<4) -#define I915_ERROR_PAGE_TABLE (1<<4) -#define GM45_ERROR_CP_PRIV (1<<3) -#define I915_ERROR_MEMORY_REFRESH (1<<1) -#define I915_ERROR_INSTRUCTION (1<<0) +#define GM45_ERROR_PAGE_TABLE (1 << 5) +#define GM45_ERROR_MEM_PRIV (1 << 4) +#define I915_ERROR_PAGE_TABLE (1 << 4) +#define GM45_ERROR_CP_PRIV (1 << 3) +#define I915_ERROR_MEMORY_REFRESH (1 << 1) +#define I915_ERROR_INSTRUCTION (1 << 0) #define INSTPM _MMIO(0x20c0) -#define INSTPM_SELF_EN (1<<12) /* 915GM only */ -#define INSTPM_AGPBUSY_INT_EN (1<<11) /* gen3: when disabled, pending interrupts +#define INSTPM_SELF_EN (1 << 12) /* 915GM only */ +#define INSTPM_AGPBUSY_INT_EN (1 << 11) /* gen3: when disabled, pending interrupts will not assert AGPBUSY# and will only be delivered when out of C3. */ -#define INSTPM_FORCE_ORDERING (1<<7) /* GEN6+ */ -#define INSTPM_TLB_INVALIDATE (1<<9) -#define INSTPM_SYNC_FLUSH (1<<5) +#define INSTPM_FORCE_ORDERING (1 << 7) /* GEN6+ */ +#define INSTPM_TLB_INVALIDATE (1 << 9) +#define INSTPM_SYNC_FLUSH (1 << 5) #define ACTHD _MMIO(0x20c8) #define MEM_MODE _MMIO(0x20cc) -#define MEM_DISPLAY_B_TRICKLE_FEED_DISABLE (1<<3) /* 830 only */ -#define MEM_DISPLAY_A_TRICKLE_FEED_DISABLE (1<<2) /* 830/845 only */ -#define MEM_DISPLAY_TRICKLE_FEED_DISABLE (1<<2) /* 85x only */ +#define MEM_DISPLAY_B_TRICKLE_FEED_DISABLE (1 << 3) /* 830 only */ +#define MEM_DISPLAY_A_TRICKLE_FEED_DISABLE (1 << 2) /* 830/845 only */ +#define MEM_DISPLAY_TRICKLE_FEED_DISABLE (1 << 2) /* 85x only */ #define FW_BLC _MMIO(0x20d8) #define FW_BLC2 _MMIO(0x20dc) #define FW_BLC_SELF _MMIO(0x20e0) /* 915+ only */ -#define FW_BLC_SELF_EN_MASK (1<<31) -#define FW_BLC_SELF_FIFO_MASK (1<<16) /* 945 only */ -#define FW_BLC_SELF_EN (1<<15) /* 945 only */ +#define FW_BLC_SELF_EN_MASK (1 << 31) +#define FW_BLC_SELF_FIFO_MASK (1 << 16) /* 945 only */ +#define FW_BLC_SELF_EN (1 << 15) /* 945 only */ #define MM_BURST_LENGTH 0x00700000 #define MM_FIFO_WATERMARK 0x0001F000 #define LM_BURST_LENGTH 0x00000700 @@ -2653,40 +2653,40 @@ enum i915_power_well_id { #define MI_AGPBUSY_830_MODE (1 << 0) /* 85x only */ #define CACHE_MODE_0 _MMIO(0x2120) /* 915+ only */ -#define CM0_PIPELINED_RENDER_FLUSH_DISABLE (1<<8) -#define CM0_IZ_OPT_DISABLE (1<<6) -#define CM0_ZR_OPT_DISABLE (1<<5) -#define CM0_STC_EVICT_DISABLE_LRA_SNB (1<<5) -#define CM0_DEPTH_EVICT_DISABLE (1<<4) -#define CM0_COLOR_EVICT_DISABLE (1<<3) -#define CM0_DEPTH_WRITE_DISABLE (1<<1) -#define CM0_RC_OP_FLUSH_DISABLE (1<<0) +#define CM0_PIPELINED_RENDER_FLUSH_DISABLE (1 << 8) +#define CM0_IZ_OPT_DISABLE (1 << 6) +#define CM0_ZR_OPT_DISABLE (1 << 5) +#define CM0_STC_EVICT_DISABLE_LRA_SNB (1 << 5) +#define CM0_DEPTH_EVICT_DISABLE (1 << 4) +#define CM0_COLOR_EVICT_DISABLE (1 << 3) +#define CM0_DEPTH_WRITE_DISABLE (1 << 1) +#define CM0_RC_OP_FLUSH_DISABLE (1 << 0) #define GFX_FLSH_CNTL _MMIO(0x2170) /* 915+ only */ #define GFX_FLSH_CNTL_GEN6 _MMIO(0x101008) -#define GFX_FLSH_CNTL_EN (1<<0) +#define GFX_FLSH_CNTL_EN (1 << 0) #define ECOSKPD _MMIO(0x21d0) -#define ECO_GATING_CX_ONLY (1<<3) -#define ECO_FLIP_DONE (1<<0) +#define ECO_GATING_CX_ONLY (1 << 3) +#define ECO_FLIP_DONE (1 << 0) #define CACHE_MODE_0_GEN7 _MMIO(0x7000) /* IVB+ */ -#define RC_OP_FLUSH_ENABLE (1<<0) -#define HIZ_RAW_STALL_OPT_DISABLE (1<<2) +#define RC_OP_FLUSH_ENABLE (1 << 0) +#define HIZ_RAW_STALL_OPT_DISABLE (1 << 2) #define CACHE_MODE_1 _MMIO(0x7004) /* IVB+ */ -#define PIXEL_SUBSPAN_COLLECT_OPT_DISABLE (1<<6) -#define GEN8_4x4_STC_OPTIMIZATION_DISABLE (1<<6) -#define GEN9_PARTIAL_RESOLVE_IN_VC_DISABLE (1<<1) +#define PIXEL_SUBSPAN_COLLECT_OPT_DISABLE (1 << 6) +#define GEN8_4x4_STC_OPTIMIZATION_DISABLE (1 << 6) +#define GEN9_PARTIAL_RESOLVE_IN_VC_DISABLE (1 << 1) #define GEN10_CACHE_MODE_SS _MMIO(0xe420) #define FLOAT_BLEND_OPTIMIZATION_ENABLE (1 << 4) #define GEN6_BLITTER_ECOSKPD _MMIO(0x221d0) #define GEN6_BLITTER_LOCK_SHIFT 16 -#define GEN6_BLITTER_FBC_NOTIFY (1<<3) +#define GEN6_BLITTER_FBC_NOTIFY (1 << 3) #define GEN6_RC_SLEEP_PSMI_CONTROL _MMIO(0x2050) #define GEN6_PSMI_SLEEP_MSG_DISABLE (1 << 0) #define GEN8_RC_SEMA_IDLE_MSG_DISABLE (1 << 12) -#define GEN8_FF_DOP_CLOCK_GATE_DISABLE (1<<10) +#define GEN8_FF_DOP_CLOCK_GATE_DISABLE (1 << 10) #define GEN6_RCS_PWR_FSM _MMIO(0x22ac) #define GEN9_RCS_FE_FSM2 _MMIO(0x22a4) @@ -2742,7 +2742,7 @@ enum i915_power_well_id { #define GEN8_EU_DISABLE2 _MMIO(0x913c) #define GEN8_EU_DIS2_S2_MASK 0xff -#define GEN9_EU_DISABLE(slice) _MMIO(0x9134 + (slice)*0x4) +#define GEN9_EU_DISABLE(slice) _MMIO(0x9134 + (slice) * 0x4) #define GEN10_EU_DISABLE3 _MMIO(0x9140) #define GEN10_EU_DIS_SS_MASK 0xff @@ -2799,44 +2799,44 @@ enum i915_power_well_id { (IS_HASWELL(dev_priv) ? GT_RENDER_L3_PARITY_ERROR_INTERRUPT_S1 : 0)) /* These are all the "old" interrupts */ -#define ILK_BSD_USER_INTERRUPT (1<<5) - -#define I915_PM_INTERRUPT (1<<31) -#define I915_ISP_INTERRUPT (1<<22) -#define I915_LPE_PIPE_B_INTERRUPT (1<<21) -#define I915_LPE_PIPE_A_INTERRUPT (1<<20) -#define I915_MIPIC_INTERRUPT (1<<19) -#define I915_MIPIA_INTERRUPT (1<<18) -#define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1<<18) -#define I915_DISPLAY_PORT_INTERRUPT (1<<17) -#define I915_DISPLAY_PIPE_C_HBLANK_INTERRUPT (1<<16) -#define I915_MASTER_ERROR_INTERRUPT (1<<15) -#define I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT (1<<15) -#define I915_DISPLAY_PIPE_B_HBLANK_INTERRUPT (1<<14) -#define I915_GMCH_THERMAL_SENSOR_EVENT_INTERRUPT (1<<14) /* p-state */ -#define I915_DISPLAY_PIPE_A_HBLANK_INTERRUPT (1<<13) -#define I915_HWB_OOM_INTERRUPT (1<<13) -#define I915_LPE_PIPE_C_INTERRUPT (1<<12) -#define I915_SYNC_STATUS_INTERRUPT (1<<12) -#define I915_MISC_INTERRUPT (1<<11) -#define I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT (1<<11) -#define I915_DISPLAY_PIPE_C_VBLANK_INTERRUPT (1<<10) -#define I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT (1<<10) -#define I915_DISPLAY_PIPE_C_EVENT_INTERRUPT (1<<9) -#define I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT (1<<9) -#define I915_DISPLAY_PIPE_C_DPBM_INTERRUPT (1<<8) -#define I915_DISPLAY_PLANE_C_FLIP_PENDING_INTERRUPT (1<<8) -#define I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT (1<<7) -#define I915_DISPLAY_PIPE_A_EVENT_INTERRUPT (1<<6) -#define I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT (1<<5) -#define I915_DISPLAY_PIPE_B_EVENT_INTERRUPT (1<<4) -#define I915_DISPLAY_PIPE_A_DPBM_INTERRUPT (1<<3) -#define I915_DISPLAY_PIPE_B_DPBM_INTERRUPT (1<<2) -#define I915_DEBUG_INTERRUPT (1<<2) -#define I915_WINVALID_INTERRUPT (1<<1) -#define I915_USER_INTERRUPT (1<<1) -#define I915_ASLE_INTERRUPT (1<<0) -#define I915_BSD_USER_INTERRUPT (1<<25) +#define ILK_BSD_USER_INTERRUPT (1 << 5) + +#define I915_PM_INTERRUPT (1 << 31) +#define I915_ISP_INTERRUPT (1 << 22) +#define I915_LPE_PIPE_B_INTERRUPT (1 << 21) +#define I915_LPE_PIPE_A_INTERRUPT (1 << 20) +#define I915_MIPIC_INTERRUPT (1 << 19) +#define I915_MIPIA_INTERRUPT (1 << 18) +#define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1 << 18) +#define I915_DISPLAY_PORT_INTERRUPT (1 << 17) +#define I915_DISPLAY_PIPE_C_HBLANK_INTERRUPT (1 << 16) +#define I915_MASTER_ERROR_INTERRUPT (1 << 15) +#define I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT (1 << 15) +#define I915_DISPLAY_PIPE_B_HBLANK_INTERRUPT (1 << 14) +#define I915_GMCH_THERMAL_SENSOR_EVENT_INTERRUPT (1 << 14) /* p-state */ +#define I915_DISPLAY_PIPE_A_HBLANK_INTERRUPT (1 << 13) +#define I915_HWB_OOM_INTERRUPT (1 << 13) +#define I915_LPE_PIPE_C_INTERRUPT (1 << 12) +#define I915_SYNC_STATUS_INTERRUPT (1 << 12) +#define I915_MISC_INTERRUPT (1 << 11) +#define I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT (1 << 11) +#define I915_DISPLAY_PIPE_C_VBLANK_INTERRUPT (1 << 10) +#define I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT (1 << 10) +#define I915_DISPLAY_PIPE_C_EVENT_INTERRUPT (1 << 9) +#define I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT (1 << 9) +#define I915_DISPLAY_PIPE_C_DPBM_INTERRUPT (1 << 8) +#define I915_DISPLAY_PLANE_C_FLIP_PENDING_INTERRUPT (1 << 8) +#define I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT (1 << 7) +#define I915_DISPLAY_PIPE_A_EVENT_INTERRUPT (1 << 6) +#define I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT (1 << 5) +#define I915_DISPLAY_PIPE_B_EVENT_INTERRUPT (1 << 4) +#define I915_DISPLAY_PIPE_A_DPBM_INTERRUPT (1 << 3) +#define I915_DISPLAY_PIPE_B_DPBM_INTERRUPT (1 << 2) +#define I915_DEBUG_INTERRUPT (1 << 2) +#define I915_WINVALID_INTERRUPT (1 << 1) +#define I915_USER_INTERRUPT (1 << 1) +#define I915_ASLE_INTERRUPT (1 << 0) +#define I915_BSD_USER_INTERRUPT (1 << 25) #define I915_HDMI_LPE_AUDIO_BASE (VLV_DISPLAY_BASE + 0x65000) #define I915_HDMI_LPE_AUDIO_SIZE 0x1000 @@ -2859,19 +2859,19 @@ enum i915_power_well_id { #define GEN7_FF_THREAD_MODE _MMIO(0x20a0) #define GEN7_FF_SCHED_MASK 0x0077070 #define GEN8_FF_DS_REF_CNT_FFME (1 << 19) -#define GEN7_FF_TS_SCHED_HS1 (0x5<<16) -#define GEN7_FF_TS_SCHED_HS0 (0x3<<16) -#define GEN7_FF_TS_SCHED_LOAD_BALANCE (0x1<<16) -#define GEN7_FF_TS_SCHED_HW (0x0<<16) /* Default */ +#define GEN7_FF_TS_SCHED_HS1 (0x5 << 16) +#define GEN7_FF_TS_SCHED_HS0 (0x3 << 16) +#define GEN7_FF_TS_SCHED_LOAD_BALANCE (0x1 << 16) +#define GEN7_FF_TS_SCHED_HW (0x0 << 16) /* Default */ #define GEN7_FF_VS_REF_CNT_FFME (1 << 15) -#define GEN7_FF_VS_SCHED_HS1 (0x5<<12) -#define GEN7_FF_VS_SCHED_HS0 (0x3<<12) -#define GEN7_FF_VS_SCHED_LOAD_BALANCE (0x1<<12) /* Default */ -#define GEN7_FF_VS_SCHED_HW (0x0<<12) -#define GEN7_FF_DS_SCHED_HS1 (0x5<<4) -#define GEN7_FF_DS_SCHED_HS0 (0x3<<4) -#define GEN7_FF_DS_SCHED_LOAD_BALANCE (0x1<<4) /* Default */ -#define GEN7_FF_DS_SCHED_HW (0x0<<4) +#define GEN7_FF_VS_SCHED_HS1 (0x5 << 12) +#define GEN7_FF_VS_SCHED_HS0 (0x3 << 12) +#define GEN7_FF_VS_SCHED_LOAD_BALANCE (0x1 << 12) /* Default */ +#define GEN7_FF_VS_SCHED_HW (0x0 << 12) +#define GEN7_FF_DS_SCHED_HS1 (0x5 << 4) +#define GEN7_FF_DS_SCHED_HS0 (0x3 << 4) +#define GEN7_FF_DS_SCHED_LOAD_BALANCE (0x1 << 4) /* Default */ +#define GEN7_FF_DS_SCHED_HW (0x0 << 4) /* * Framebuffer compression (915+ only) @@ -2880,51 +2880,51 @@ enum i915_power_well_id { #define FBC_CFB_BASE _MMIO(0x3200) /* 4k page aligned */ #define FBC_LL_BASE _MMIO(0x3204) /* 4k page aligned */ #define FBC_CONTROL _MMIO(0x3208) -#define FBC_CTL_EN (1<<31) -#define FBC_CTL_PERIODIC (1<<30) +#define FBC_CTL_EN (1 << 31) +#define FBC_CTL_PERIODIC (1 << 30) #define FBC_CTL_INTERVAL_SHIFT (16) -#define FBC_CTL_UNCOMPRESSIBLE (1<<14) -#define FBC_CTL_C3_IDLE (1<<13) +#define FBC_CTL_UNCOMPRESSIBLE (1 << 14) +#define FBC_CTL_C3_IDLE (1 << 13) #define FBC_CTL_STRIDE_SHIFT (5) #define FBC_CTL_FENCENO_SHIFT (0) #define FBC_COMMAND _MMIO(0x320c) -#define FBC_CMD_COMPRESS (1<<0) +#define FBC_CMD_COMPRESS (1 << 0) #define FBC_STATUS _MMIO(0x3210) -#define FBC_STAT_COMPRESSING (1<<31) -#define FBC_STAT_COMPRESSED (1<<30) -#define FBC_STAT_MODIFIED (1<<29) +#define FBC_STAT_COMPRESSING (1 << 31) +#define FBC_STAT_COMPRESSED (1 << 30) +#define FBC_STAT_MODIFIED (1 << 29) #define FBC_STAT_CURRENT_LINE_SHIFT (0) #define FBC_CONTROL2 _MMIO(0x3214) -#define FBC_CTL_FENCE_DBL (0<<4) -#define FBC_CTL_IDLE_IMM (0<<2) -#define FBC_CTL_IDLE_FULL (1<<2) -#define FBC_CTL_IDLE_LINE (2<<2) -#define FBC_CTL_IDLE_DEBUG (3<<2) -#define FBC_CTL_CPU_FENCE (1<<1) -#define FBC_CTL_PLANE(plane) ((plane)<<0) +#define FBC_CTL_FENCE_DBL (0 << 4) +#define FBC_CTL_IDLE_IMM (0 << 2) +#define FBC_CTL_IDLE_FULL (1 << 2) +#define FBC_CTL_IDLE_LINE (2 << 2) +#define FBC_CTL_IDLE_DEBUG (3 << 2) +#define FBC_CTL_CPU_FENCE (1 << 1) +#define FBC_CTL_PLANE(plane) ((plane) << 0) #define FBC_FENCE_OFF _MMIO(0x3218) /* BSpec typo has 321Bh */ #define FBC_TAG(i) _MMIO(0x3300 + (i) * 4) #define FBC_LL_SIZE (1536) #define FBC_LLC_READ_CTRL _MMIO(0x9044) -#define FBC_LLC_FULLY_OPEN (1<<30) +#define FBC_LLC_FULLY_OPEN (1 << 30) /* Framebuffer compression for GM45+ */ #define DPFC_CB_BASE _MMIO(0x3200) #define DPFC_CONTROL _MMIO(0x3208) -#define DPFC_CTL_EN (1<<31) -#define DPFC_CTL_PLANE(plane) ((plane)<<30) -#define IVB_DPFC_CTL_PLANE(plane) ((plane)<<29) -#define DPFC_CTL_FENCE_EN (1<<29) -#define IVB_DPFC_CTL_FENCE_EN (1<<28) -#define DPFC_CTL_PERSISTENT_MODE (1<<25) -#define DPFC_SR_EN (1<<10) -#define DPFC_CTL_LIMIT_1X (0<<6) -#define DPFC_CTL_LIMIT_2X (1<<6) -#define DPFC_CTL_LIMIT_4X (2<<6) +#define DPFC_CTL_EN (1 << 31) +#define DPFC_CTL_PLANE(plane) ((plane) << 30) +#define IVB_DPFC_CTL_PLANE(plane) ((plane) << 29) +#define DPFC_CTL_FENCE_EN (1 << 29) +#define IVB_DPFC_CTL_FENCE_EN (1 << 28) +#define DPFC_CTL_PERSISTENT_MODE (1 << 25) +#define DPFC_SR_EN (1 << 10) +#define DPFC_CTL_LIMIT_1X (0 << 6) +#define DPFC_CTL_LIMIT_2X (1 << 6) +#define DPFC_CTL_LIMIT_4X (2 << 6) #define DPFC_RECOMP_CTL _MMIO(0x320c) -#define DPFC_RECOMP_STALL_EN (1<<27) +#define DPFC_RECOMP_STALL_EN (1 << 27) #define DPFC_RECOMP_STALL_WM_SHIFT (16) #define DPFC_RECOMP_STALL_WM_MASK (0x07ff0000) #define DPFC_RECOMP_TIMER_COUNT_SHIFT (0) @@ -2937,12 +2937,12 @@ enum i915_power_well_id { #define DPFC_STATUS2 _MMIO(0x3214) #define DPFC_FENCE_YOFF _MMIO(0x3218) #define DPFC_CHICKEN _MMIO(0x3224) -#define DPFC_HT_MODIFY (1<<31) +#define DPFC_HT_MODIFY (1 << 31) /* Framebuffer compression for Ironlake */ #define ILK_DPFC_CB_BASE _MMIO(0x43200) #define ILK_DPFC_CONTROL _MMIO(0x43208) -#define FBC_CTL_FALSE_COLOR (1<<10) +#define FBC_CTL_FALSE_COLOR (1 << 10) /* The bit 28-8 is reserved */ #define DPFC_RESERVED (0x1FFFFF00) #define ILK_DPFC_RECOMP_CTL _MMIO(0x4320c) @@ -2953,15 +2953,15 @@ enum i915_power_well_id { #define BDW_FBC_COMP_SEG_MASK 0xfff #define ILK_DPFC_FENCE_YOFF _MMIO(0x43218) #define ILK_DPFC_CHICKEN _MMIO(0x43224) -#define ILK_DPFC_DISABLE_DUMMY0 (1<<8) -#define ILK_DPFC_NUKE_ON_ANY_MODIFICATION (1<<23) +#define ILK_DPFC_DISABLE_DUMMY0 (1 << 8) +#define ILK_DPFC_NUKE_ON_ANY_MODIFICATION (1 << 23) #define ILK_FBC_RT_BASE _MMIO(0x2128) -#define ILK_FBC_RT_VALID (1<<0) -#define SNB_FBC_FRONT_BUFFER (1<<1) +#define ILK_FBC_RT_VALID (1 << 0) +#define SNB_FBC_FRONT_BUFFER (1 << 1) #define ILK_DISPLAY_CHICKEN1 _MMIO(0x42000) -#define ILK_FBCQ_DIS (1<<22) -#define ILK_PABSTRETCH_DIS (1<<21) +#define ILK_FBCQ_DIS (1 << 22) +#define ILK_PABSTRETCH_DIS (1 << 21) /* @@ -2970,7 +2970,7 @@ enum i915_power_well_id { * The following two registers are of type GTTMMADR */ #define SNB_DPFC_CTL_SA _MMIO(0x100100) -#define SNB_CPU_FENCE_ENABLE (1<<29) +#define SNB_CPU_FENCE_ENABLE (1 << 29) #define DPFC_CPU_FENCE_OFFSET _MMIO(0x100104) /* Framebuffer compression for Ivybridge */ @@ -2980,8 +2980,8 @@ enum i915_power_well_id { #define IPS_ENABLE (1 << 31) #define MSG_FBC_REND_STATE _MMIO(0x50380) -#define FBC_REND_NUKE (1<<2) -#define FBC_REND_CACHE_CLEAN (1<<1) +#define FBC_REND_NUKE (1 << 2) +#define FBC_REND_CACHE_CLEAN (1 << 1) /* * GPIO regs @@ -3014,12 +3014,12 @@ enum i915_power_well_id { # define GPIO_DATA_PULLUP_DISABLE (1 << 13) #define GMBUS0 _MMIO(dev_priv->gpio_mmio_base + 0x5100) /* clock/port select */ -#define GMBUS_AKSV_SELECT (1<<11) -#define GMBUS_RATE_100KHZ (0<<8) -#define GMBUS_RATE_50KHZ (1<<8) -#define GMBUS_RATE_400KHZ (2<<8) /* reserved on Pineview */ -#define GMBUS_RATE_1MHZ (3<<8) /* reserved on Pineview */ -#define GMBUS_HOLD_EXT (1<<7) /* 300ns hold time, rsvd on Pineview */ +#define GMBUS_AKSV_SELECT (1 << 11) +#define GMBUS_RATE_100KHZ (0 << 8) +#define GMBUS_RATE_50KHZ (1 << 8) +#define GMBUS_RATE_400KHZ (2 << 8) /* reserved on Pineview */ +#define GMBUS_RATE_1MHZ (3 << 8) /* reserved on Pineview */ +#define GMBUS_HOLD_EXT (1 << 7) /* 300ns hold time, rsvd on Pineview */ #define GMBUS_PIN_DISABLED 0 #define GMBUS_PIN_SSC 1 #define GMBUS_PIN_VGADDC 2 @@ -3040,36 +3040,36 @@ enum i915_power_well_id { #define GMBUS_NUM_PINS 13 /* including 0 */ #define GMBUS1 _MMIO(dev_priv->gpio_mmio_base + 0x5104) /* command/status */ -#define GMBUS_SW_CLR_INT (1<<31) -#define GMBUS_SW_RDY (1<<30) -#define GMBUS_ENT (1<<29) /* enable timeout */ -#define GMBUS_CYCLE_NONE (0<<25) -#define GMBUS_CYCLE_WAIT (1<<25) -#define GMBUS_CYCLE_INDEX (2<<25) -#define GMBUS_CYCLE_STOP (4<<25) +#define GMBUS_SW_CLR_INT (1 << 31) +#define GMBUS_SW_RDY (1 << 30) +#define GMBUS_ENT (1 << 29) /* enable timeout */ +#define GMBUS_CYCLE_NONE (0 << 25) +#define GMBUS_CYCLE_WAIT (1 << 25) +#define GMBUS_CYCLE_INDEX (2 << 25) +#define GMBUS_CYCLE_STOP (4 << 25) #define GMBUS_BYTE_COUNT_SHIFT 16 #define GMBUS_BYTE_COUNT_MAX 256U #define GMBUS_SLAVE_INDEX_SHIFT 8 #define GMBUS_SLAVE_ADDR_SHIFT 1 -#define GMBUS_SLAVE_READ (1<<0) -#define GMBUS_SLAVE_WRITE (0<<0) +#define GMBUS_SLAVE_READ (1 << 0) +#define GMBUS_SLAVE_WRITE (0 << 0) #define GMBUS2 _MMIO(dev_priv->gpio_mmio_base + 0x5108) /* status */ -#define GMBUS_INUSE (1<<15) -#define GMBUS_HW_WAIT_PHASE (1<<14) -#define GMBUS_STALL_TIMEOUT (1<<13) -#define GMBUS_INT (1<<12) -#define GMBUS_HW_RDY (1<<11) -#define GMBUS_SATOER (1<<10) -#define GMBUS_ACTIVE (1<<9) +#define GMBUS_INUSE (1 << 15) +#define GMBUS_HW_WAIT_PHASE (1 << 14) +#define GMBUS_STALL_TIMEOUT (1 << 13) +#define GMBUS_INT (1 << 12) +#define GMBUS_HW_RDY (1 << 11) +#define GMBUS_SATOER (1 << 10) +#define GMBUS_ACTIVE (1 << 9) #define GMBUS3 _MMIO(dev_priv->gpio_mmio_base + 0x510c) /* data buffer bytes 3-0 */ #define GMBUS4 _MMIO(dev_priv->gpio_mmio_base + 0x5110) /* interrupt mask (Pineview+) */ -#define GMBUS_SLAVE_TIMEOUT_EN (1<<4) -#define GMBUS_NAK_EN (1<<3) -#define GMBUS_IDLE_EN (1<<2) -#define GMBUS_HW_WAIT_EN (1<<1) -#define GMBUS_HW_RDY_EN (1<<0) +#define GMBUS_SLAVE_TIMEOUT_EN (1 << 4) +#define GMBUS_NAK_EN (1 << 3) +#define GMBUS_IDLE_EN (1 << 2) +#define GMBUS_HW_WAIT_EN (1 << 1) +#define GMBUS_HW_RDY_EN (1 << 0) #define GMBUS5 _MMIO(dev_priv->gpio_mmio_base + 0x5120) /* byte index */ -#define GMBUS_2BYTE_INDEX_EN (1<<31) +#define GMBUS_2BYTE_INDEX_EN (1 << 31) /* * Clock control & power management @@ -3107,10 +3107,10 @@ enum i915_power_well_id { #define DPLL_P2_CLOCK_DIV_MASK 0x03000000 /* i915 */ #define DPLL_FPA01_P1_POST_DIV_MASK 0x00ff0000 /* i915 */ #define DPLL_FPA01_P1_POST_DIV_MASK_PINEVIEW 0x00ff8000 /* Pineview */ -#define DPLL_LOCK_VLV (1<<15) -#define DPLL_INTEGRATED_CRI_CLK_VLV (1<<14) -#define DPLL_INTEGRATED_REF_CLK_VLV (1<<13) -#define DPLL_SSC_REF_CLK_CHV (1<<13) +#define DPLL_LOCK_VLV (1 << 15) +#define DPLL_INTEGRATED_CRI_CLK_VLV (1 << 14) +#define DPLL_INTEGRATED_REF_CLK_VLV (1 << 13) +#define DPLL_SSC_REF_CLK_CHV (1 << 13) #define DPLL_PORTC_READY_MASK (0xf << 4) #define DPLL_PORTB_READY_MASK (0xf) @@ -3120,20 +3120,20 @@ enum i915_power_well_id { #define DPIO_PHY_STATUS _MMIO(VLV_DISPLAY_BASE + 0x6240) #define DPLL_PORTD_READY_MASK (0xf) #define DISPLAY_PHY_CONTROL _MMIO(VLV_DISPLAY_BASE + 0x60100) -#define PHY_CH_POWER_DOWN_OVRD_EN(phy, ch) (1 << (2*(phy)+(ch)+27)) +#define PHY_CH_POWER_DOWN_OVRD_EN(phy, ch) (1 << (2 * (phy) + (ch) + 27)) #define PHY_LDO_DELAY_0NS 0x0 #define PHY_LDO_DELAY_200NS 0x1 #define PHY_LDO_DELAY_600NS 0x2 -#define PHY_LDO_SEQ_DELAY(delay, phy) ((delay) << (2*(phy)+23)) -#define PHY_CH_POWER_DOWN_OVRD(mask, phy, ch) ((mask) << (8*(phy)+4*(ch)+11)) +#define PHY_LDO_SEQ_DELAY(delay, phy) ((delay) << (2 * (phy) + 23)) +#define PHY_CH_POWER_DOWN_OVRD(mask, phy, ch) ((mask) << (8 * (phy) + 4 * (ch) + 11)) #define PHY_CH_SU_PSR 0x1 #define PHY_CH_DEEP_PSR 0x7 -#define PHY_CH_POWER_MODE(mode, phy, ch) ((mode) << (6*(phy)+3*(ch)+2)) +#define PHY_CH_POWER_MODE(mode, phy, ch) ((mode) << (6 * (phy) + 3 * (ch) + 2)) #define PHY_COM_LANE_RESET_DEASSERT(phy) (1 << (phy)) #define DISPLAY_PHY_STATUS _MMIO(VLV_DISPLAY_BASE + 0x60104) -#define PHY_POWERGOOD(phy) (((phy) == DPIO_PHY0) ? (1<<31) : (1<<30)) -#define PHY_STATUS_CMN_LDO(phy, ch) (1 << (6-(6*(phy)+3*(ch)))) -#define PHY_STATUS_SPLINE_LDO(phy, ch, spline) (1 << (8-(6*(phy)+3*(ch)+(spline)))) +#define PHY_POWERGOOD(phy) (((phy) == DPIO_PHY0) ? (1 << 31) : (1 << 30)) +#define PHY_STATUS_CMN_LDO(phy, ch) (1 << (6 - (6 * (phy) + 3 * (ch)))) +#define PHY_STATUS_SPLINE_LDO(phy, ch, spline) (1 << (8 - (6 * (phy) + 3 * (ch) + (spline)))) /* * The i830 generation, in LVDS mode, defines P1 as the bit number set within @@ -3154,7 +3154,7 @@ enum i915_power_well_id { /* Ironlake */ # define PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT 9 # define PLL_REF_SDVO_HDMI_MULTIPLIER_MASK (7 << 9) -# define PLL_REF_SDVO_HDMI_MULTIPLIER(x) (((x)-1) << 9) +# define PLL_REF_SDVO_HDMI_MULTIPLIER(x) (((x) - 1) << 9) # define DPLL_FPA1_P1_POST_DIV_SHIFT 0 # define DPLL_FPA1_P1_POST_DIV_MASK 0xff @@ -3243,10 +3243,10 @@ enum i915_power_well_id { #define DPLLA_TEST_M_BYPASS (1 << 2) #define DPLLA_INPUT_BUFFER_ENABLE (1 << 0) #define D_STATE _MMIO(0x6104) -#define DSTATE_GFX_RESET_I830 (1<<6) -#define DSTATE_PLL_D3_OFF (1<<3) -#define DSTATE_GFX_CLOCK_GATING (1<<1) -#define DSTATE_DOT_CLOCK_GATING (1<<0) +#define DSTATE_GFX_RESET_I830 (1 << 6) +#define DSTATE_PLL_D3_OFF (1 << 3) +#define DSTATE_GFX_CLOCK_GATING (1 << 1) +#define DSTATE_DOT_CLOCK_GATING (1 << 0) #define DSPCLK_GATE_D _MMIO(dev_priv->info.display_mmio_offset + 0x6200) # define DPUNIT_B_CLOCK_GATE_DISABLE (1 << 30) /* 965 */ # define VSUNIT_CLOCK_GATE_DISABLE (1 << 29) /* 965 */ @@ -3363,7 +3363,7 @@ enum i915_power_well_id { #define DEUC _MMIO(0x6214) /* CRL only */ #define FW_BLC_SELF_VLV _MMIO(VLV_DISPLAY_BASE + 0x6500) -#define FW_CSPWRDWNEN (1<<15) +#define FW_CSPWRDWNEN (1 << 15) #define MI_ARB_VLV _MMIO(VLV_DISPLAY_BASE + 0x6504) @@ -3488,7 +3488,7 @@ enum i915_power_well_id { #define HPLLVCO_MOBILE _MMIO(MCHBAR_MIRROR_BASE + 0xc0f) #define TSC1 _MMIO(0x11001) -#define TSE (1<<0) +#define TSE (1 << 0) #define TR1 _MMIO(0x11006) #define TSFS _MMIO(0x11020) #define TSFS_SLOPE_MASK 0x0000ff00 @@ -3534,23 +3534,23 @@ enum i915_power_well_id { #define MEMCTL_CMD_CHVID 3 #define MEMCTL_CMD_VMMOFF 4 #define MEMCTL_CMD_VMMON 5 -#define MEMCTL_CMD_STS (1<<12) /* write 1 triggers command, clears +#define MEMCTL_CMD_STS (1 << 12) /* write 1 triggers command, clears when command complete */ #define MEMCTL_FREQ_MASK 0x0f00 /* jitter, from 0-15 */ #define MEMCTL_FREQ_SHIFT 8 -#define MEMCTL_SFCAVM (1<<7) +#define MEMCTL_SFCAVM (1 << 7) #define MEMCTL_TGT_VID_MASK 0x007f #define MEMIHYST _MMIO(0x1117c) #define MEMINTREN _MMIO(0x11180) /* 16 bits */ -#define MEMINT_RSEXIT_EN (1<<8) -#define MEMINT_CX_SUPR_EN (1<<7) -#define MEMINT_CONT_BUSY_EN (1<<6) -#define MEMINT_AVG_BUSY_EN (1<<5) -#define MEMINT_EVAL_CHG_EN (1<<4) -#define MEMINT_MON_IDLE_EN (1<<3) -#define MEMINT_UP_EVAL_EN (1<<2) -#define MEMINT_DOWN_EVAL_EN (1<<1) -#define MEMINT_SW_CMD_EN (1<<0) +#define MEMINT_RSEXIT_EN (1 << 8) +#define MEMINT_CX_SUPR_EN (1 << 7) +#define MEMINT_CONT_BUSY_EN (1 << 6) +#define MEMINT_AVG_BUSY_EN (1 << 5) +#define MEMINT_EVAL_CHG_EN (1 << 4) +#define MEMINT_MON_IDLE_EN (1 << 3) +#define MEMINT_UP_EVAL_EN (1 << 2) +#define MEMINT_DOWN_EVAL_EN (1 << 1) +#define MEMINT_SW_CMD_EN (1 << 0) #define MEMINTRSTR _MMIO(0x11182) /* 16 bits */ #define MEM_RSEXIT_MASK 0xc000 #define MEM_RSEXIT_SHIFT 14 @@ -3572,26 +3572,26 @@ enum i915_power_well_id { #define MEM_INT_STEER_SMI 2 #define MEM_INT_STEER_SCI 3 #define MEMINTRSTS _MMIO(0x11184) -#define MEMINT_RSEXIT (1<<7) -#define MEMINT_CONT_BUSY (1<<6) -#define MEMINT_AVG_BUSY (1<<5) -#define MEMINT_EVAL_CHG (1<<4) -#define MEMINT_MON_IDLE (1<<3) -#define MEMINT_UP_EVAL (1<<2) -#define MEMINT_DOWN_EVAL (1<<1) -#define MEMINT_SW_CMD (1<<0) +#define MEMINT_RSEXIT (1 << 7) +#define MEMINT_CONT_BUSY (1 << 6) +#define MEMINT_AVG_BUSY (1 << 5) +#define MEMINT_EVAL_CHG (1 << 4) +#define MEMINT_MON_IDLE (1 << 3) +#define MEMINT_UP_EVAL (1 << 2) +#define MEMINT_DOWN_EVAL (1 << 1) +#define MEMINT_SW_CMD (1 << 0) #define MEMMODECTL _MMIO(0x11190) -#define MEMMODE_BOOST_EN (1<<31) +#define MEMMODE_BOOST_EN (1 << 31) #define MEMMODE_BOOST_FREQ_MASK 0x0f000000 /* jitter for boost, 0-15 */ #define MEMMODE_BOOST_FREQ_SHIFT 24 #define MEMMODE_IDLE_MODE_MASK 0x00030000 #define MEMMODE_IDLE_MODE_SHIFT 16 #define MEMMODE_IDLE_MODE_EVAL 0 #define MEMMODE_IDLE_MODE_CONT 1 -#define MEMMODE_HWIDLE_EN (1<<15) -#define MEMMODE_SWMODE_EN (1<<14) -#define MEMMODE_RCLK_GATE (1<<13) -#define MEMMODE_HW_UPDATE (1<<12) +#define MEMMODE_HWIDLE_EN (1 << 15) +#define MEMMODE_SWMODE_EN (1 << 14) +#define MEMMODE_RCLK_GATE (1 << 13) +#define MEMMODE_HW_UPDATE (1 << 12) #define MEMMODE_FSTART_MASK 0x00000f00 /* starting jitter, 0-15 */ #define MEMMODE_FSTART_SHIFT 8 #define MEMMODE_FMAX_MASK 0x000000f0 /* max jitter, 0-15 */ @@ -3605,8 +3605,8 @@ enum i915_power_well_id { #define SWMEMCMD_TARVID (3 << 13) #define SWMEMCMD_VRM_OFF (4 << 13) #define SWMEMCMD_VRM_ON (5 << 13) -#define CMDSTS (1<<12) -#define SFCAVM (1<<11) +#define CMDSTS (1 << 12) +#define SFCAVM (1 << 11) #define SWFREQ_MASK 0x0380 /* P0-7 */ #define SWFREQ_SHIFT 7 #define TARVID_MASK 0x001f @@ -3615,49 +3615,49 @@ enum i915_power_well_id { #define RCUPEI _MMIO(0x111b0) #define RCDNEI _MMIO(0x111b4) #define RSTDBYCTL _MMIO(0x111b8) -#define RS1EN (1<<31) -#define RS2EN (1<<30) -#define RS3EN (1<<29) -#define D3RS3EN (1<<28) /* Display D3 imlies RS3 */ -#define SWPROMORSX (1<<27) /* RSx promotion timers ignored */ -#define RCWAKERW (1<<26) /* Resetwarn from PCH causes wakeup */ -#define DPRSLPVREN (1<<25) /* Fast voltage ramp enable */ -#define GFXTGHYST (1<<24) /* Hysteresis to allow trunk gating */ -#define RCX_SW_EXIT (1<<23) /* Leave RSx and prevent re-entry */ -#define RSX_STATUS_MASK (7<<20) -#define RSX_STATUS_ON (0<<20) -#define RSX_STATUS_RC1 (1<<20) -#define RSX_STATUS_RC1E (2<<20) -#define RSX_STATUS_RS1 (3<<20) -#define RSX_STATUS_RS2 (4<<20) /* aka rc6 */ -#define RSX_STATUS_RSVD (5<<20) /* deep rc6 unsupported on ilk */ -#define RSX_STATUS_RS3 (6<<20) /* rs3 unsupported on ilk */ -#define RSX_STATUS_RSVD2 (7<<20) -#define UWRCRSXE (1<<19) /* wake counter limit prevents rsx */ -#define RSCRP (1<<18) /* rs requests control on rs1/2 reqs */ -#define JRSC (1<<17) /* rsx coupled to cpu c-state */ -#define RS2INC0 (1<<16) /* allow rs2 in cpu c0 */ -#define RS1CONTSAV_MASK (3<<14) -#define RS1CONTSAV_NO_RS1 (0<<14) /* rs1 doesn't save/restore context */ -#define RS1CONTSAV_RSVD (1<<14) -#define RS1CONTSAV_SAVE_RS1 (2<<14) /* rs1 saves context */ -#define RS1CONTSAV_FULL_RS1 (3<<14) /* rs1 saves and restores context */ -#define NORMSLEXLAT_MASK (3<<12) -#define SLOW_RS123 (0<<12) -#define SLOW_RS23 (1<<12) -#define SLOW_RS3 (2<<12) -#define NORMAL_RS123 (3<<12) -#define RCMODE_TIMEOUT (1<<11) /* 0 is eval interval method */ -#define IMPROMOEN (1<<10) /* promo is immediate or delayed until next idle interval (only for timeout method above) */ -#define RCENTSYNC (1<<9) /* rs coupled to cpu c-state (3/6/7) */ -#define STATELOCK (1<<7) /* locked to rs_cstate if 0 */ -#define RS_CSTATE_MASK (3<<4) -#define RS_CSTATE_C367_RS1 (0<<4) -#define RS_CSTATE_C36_RS1_C7_RS2 (1<<4) -#define RS_CSTATE_RSVD (2<<4) -#define RS_CSTATE_C367_RS2 (3<<4) -#define REDSAVES (1<<3) /* no context save if was idle during rs0 */ -#define REDRESTORES (1<<2) /* no restore if was idle during rs0 */ +#define RS1EN (1 << 31) +#define RS2EN (1 << 30) +#define RS3EN (1 << 29) +#define D3RS3EN (1 << 28) /* Display D3 imlies RS3 */ +#define SWPROMORSX (1 << 27) /* RSx promotion timers ignored */ +#define RCWAKERW (1 << 26) /* Resetwarn from PCH causes wakeup */ +#define DPRSLPVREN (1 << 25) /* Fast voltage ramp enable */ +#define GFXTGHYST (1 << 24) /* Hysteresis to allow trunk gating */ +#define RCX_SW_EXIT (1 << 23) /* Leave RSx and prevent re-entry */ +#define RSX_STATUS_MASK (7 << 20) +#define RSX_STATUS_ON (0 << 20) +#define RSX_STATUS_RC1 (1 << 20) +#define RSX_STATUS_RC1E (2 << 20) +#define RSX_STATUS_RS1 (3 << 20) +#define RSX_STATUS_RS2 (4 << 20) /* aka rc6 */ +#define RSX_STATUS_RSVD (5 << 20) /* deep rc6 unsupported on ilk */ +#define RSX_STATUS_RS3 (6 << 20) /* rs3 unsupported on ilk */ +#define RSX_STATUS_RSVD2 (7 << 20) +#define UWRCRSXE (1 << 19) /* wake counter limit prevents rsx */ +#define RSCRP (1 << 18) /* rs requests control on rs1/2 reqs */ +#define JRSC (1 << 17) /* rsx coupled to cpu c-state */ +#define RS2INC0 (1 << 16) /* allow rs2 in cpu c0 */ +#define RS1CONTSAV_MASK (3 << 14) +#define RS1CONTSAV_NO_RS1 (0 << 14) /* rs1 doesn't save/restore context */ +#define RS1CONTSAV_RSVD (1 << 14) +#define RS1CONTSAV_SAVE_RS1 (2 << 14) /* rs1 saves context */ +#define RS1CONTSAV_FULL_RS1 (3 << 14) /* rs1 saves and restores context */ +#define NORMSLEXLAT_MASK (3 << 12) +#define SLOW_RS123 (0 << 12) +#define SLOW_RS23 (1 << 12) +#define SLOW_RS3 (2 << 12) +#define NORMAL_RS123 (3 << 12) +#define RCMODE_TIMEOUT (1 << 11) /* 0 is eval interval method */ +#define IMPROMOEN (1 << 10) /* promo is immediate or delayed until next idle interval (only for timeout method above) */ +#define RCENTSYNC (1 << 9) /* rs coupled to cpu c-state (3/6/7) */ +#define STATELOCK (1 << 7) /* locked to rs_cstate if 0 */ +#define RS_CSTATE_MASK (3 << 4) +#define RS_CSTATE_C367_RS1 (0 << 4) +#define RS_CSTATE_C36_RS1_C7_RS2 (1 << 4) +#define RS_CSTATE_RSVD (2 << 4) +#define RS_CSTATE_C367_RS2 (3 << 4) +#define REDSAVES (1 << 3) /* no context save if was idle during rs0 */ +#define REDRESTORES (1 << 2) /* no restore if was idle during rs0 */ #define VIDCTL _MMIO(0x111c0) #define VIDSTS _MMIO(0x111c8) #define VIDSTART _MMIO(0x111cc) /* 8 bits */ @@ -3666,7 +3666,7 @@ enum i915_power_well_id { #define MEMSTAT_VID_SHIFT 8 #define MEMSTAT_PSTATE_MASK 0x00f8 #define MEMSTAT_PSTATE_SHIFT 3 -#define MEMSTAT_MON_ACTV (1<<2) +#define MEMSTAT_MON_ACTV (1 << 2) #define MEMSTAT_SRC_CTL_MASK 0x0003 #define MEMSTAT_SRC_CTL_CORE 0 #define MEMSTAT_SRC_CTL_TRB 1 @@ -3675,7 +3675,7 @@ enum i915_power_well_id { #define RCPREVBSYTUPAVG _MMIO(0x113b8) #define RCPREVBSYTDNAVG _MMIO(0x113bc) #define PMMISC _MMIO(0x11214) -#define MCPPCE_EN (1<<0) /* enable PM_MSG from PCH->MPC */ +#define MCPPCE_EN (1 << 0) /* enable PM_MSG from PCH->MPC */ #define SDEW _MMIO(0x1124c) #define CSIEW0 _MMIO(0x11250) #define CSIEW1 _MMIO(0x11254) @@ -3692,8 +3692,8 @@ enum i915_power_well_id { #define RPPREVBSYTUPAVG _MMIO(0x113b8) #define RPPREVBSYTDNAVG _MMIO(0x113bc) #define ECR _MMIO(0x11600) -#define ECR_GPFE (1<<31) -#define ECR_IMONE (1<<30) +#define ECR_GPFE (1 << 31) +#define ECR_IMONE (1 << 30) #define ECR_CAP_MASK 0x0000001f /* Event range, 0-31 */ #define OGW0 _MMIO(0x11608) #define OGW1 _MMIO(0x1160c) @@ -3800,11 +3800,11 @@ enum { FAULT_AND_CONTINUE /* Unsupported */ }; -#define GEN8_CTX_VALID (1<<0) -#define GEN8_CTX_FORCE_PD_RESTORE (1<<1) -#define GEN8_CTX_FORCE_RESTORE (1<<2) -#define GEN8_CTX_L3LLC_COHERENT (1<<5) -#define GEN8_CTX_PRIVILEGE (1<<8) +#define GEN8_CTX_VALID (1 << 0) +#define GEN8_CTX_FORCE_PD_RESTORE (1 << 1) +#define GEN8_CTX_FORCE_RESTORE (1 << 2) +#define GEN8_CTX_L3LLC_COHERENT (1 << 5) +#define GEN8_CTX_PRIVILEGE (1 << 8) #define GEN8_CTX_ADDRESSING_MODE_SHIFT 3 #define GEN8_CTX_ID_SHIFT 32 @@ -3826,7 +3826,7 @@ enum { #define OVADD _MMIO(0x30000) #define DOVSTA _MMIO(0x30008) -#define OC_BUF (0x3<<20) +#define OC_BUF (0x3 << 20) #define OGAMC5 _MMIO(0x30010) #define OGAMC4 _MMIO(0x30014) #define OGAMC3 _MMIO(0x30018) @@ -3994,64 +3994,64 @@ enum { /* VLV eDP PSR registers */ #define _PSRCTLA (VLV_DISPLAY_BASE + 0x60090) #define _PSRCTLB (VLV_DISPLAY_BASE + 0x61090) -#define VLV_EDP_PSR_ENABLE (1<<0) -#define VLV_EDP_PSR_RESET (1<<1) -#define VLV_EDP_PSR_MODE_MASK (7<<2) -#define VLV_EDP_PSR_MODE_HW_TIMER (1<<3) -#define VLV_EDP_PSR_MODE_SW_TIMER (1<<2) -#define VLV_EDP_PSR_SINGLE_FRAME_UPDATE (1<<7) -#define VLV_EDP_PSR_ACTIVE_ENTRY (1<<8) -#define VLV_EDP_PSR_SRC_TRANSMITTER_STATE (1<<9) -#define VLV_EDP_PSR_DBL_FRAME (1<<10) -#define VLV_EDP_PSR_FRAME_COUNT_MASK (0xff<<16) +#define VLV_EDP_PSR_ENABLE (1 << 0) +#define VLV_EDP_PSR_RESET (1 << 1) +#define VLV_EDP_PSR_MODE_MASK (7 << 2) +#define VLV_EDP_PSR_MODE_HW_TIMER (1 << 3) +#define VLV_EDP_PSR_MODE_SW_TIMER (1 << 2) +#define VLV_EDP_PSR_SINGLE_FRAME_UPDATE (1 << 7) +#define VLV_EDP_PSR_ACTIVE_ENTRY (1 << 8) +#define VLV_EDP_PSR_SRC_TRANSMITTER_STATE (1 << 9) +#define VLV_EDP_PSR_DBL_FRAME (1 << 10) +#define VLV_EDP_PSR_FRAME_COUNT_MASK (0xff << 16) #define VLV_EDP_PSR_IDLE_FRAME_SHIFT 16 #define VLV_PSRCTL(pipe) _MMIO_PIPE(pipe, _PSRCTLA, _PSRCTLB) #define _VSCSDPA (VLV_DISPLAY_BASE + 0x600a0) #define _VSCSDPB (VLV_DISPLAY_BASE + 0x610a0) -#define VLV_EDP_PSR_SDP_FREQ_MASK (3<<30) -#define VLV_EDP_PSR_SDP_FREQ_ONCE (1<<31) -#define VLV_EDP_PSR_SDP_FREQ_EVFRAME (1<<30) +#define VLV_EDP_PSR_SDP_FREQ_MASK (3 << 30) +#define VLV_EDP_PSR_SDP_FREQ_ONCE (1 << 31) +#define VLV_EDP_PSR_SDP_FREQ_EVFRAME (1 << 30) #define VLV_VSCSDP(pipe) _MMIO_PIPE(pipe, _VSCSDPA, _VSCSDPB) #define _PSRSTATA (VLV_DISPLAY_BASE + 0x60094) #define _PSRSTATB (VLV_DISPLAY_BASE + 0x61094) -#define VLV_EDP_PSR_LAST_STATE_MASK (7<<3) +#define VLV_EDP_PSR_LAST_STATE_MASK (7 << 3) #define VLV_EDP_PSR_CURR_STATE_MASK 7 -#define VLV_EDP_PSR_DISABLED (0<<0) -#define VLV_EDP_PSR_INACTIVE (1<<0) -#define VLV_EDP_PSR_IN_TRANS_TO_ACTIVE (2<<0) -#define VLV_EDP_PSR_ACTIVE_NORFB_UP (3<<0) -#define VLV_EDP_PSR_ACTIVE_SF_UPDATE (4<<0) -#define VLV_EDP_PSR_EXIT (5<<0) -#define VLV_EDP_PSR_IN_TRANS (1<<7) +#define VLV_EDP_PSR_DISABLED (0 << 0) +#define VLV_EDP_PSR_INACTIVE (1 << 0) +#define VLV_EDP_PSR_IN_TRANS_TO_ACTIVE (2 << 0) +#define VLV_EDP_PSR_ACTIVE_NORFB_UP (3 << 0) +#define VLV_EDP_PSR_ACTIVE_SF_UPDATE (4 << 0) +#define VLV_EDP_PSR_EXIT (5 << 0) +#define VLV_EDP_PSR_IN_TRANS (1 << 7) #define VLV_PSRSTAT(pipe) _MMIO_PIPE(pipe, _PSRSTATA, _PSRSTATB) /* HSW+ eDP PSR registers */ #define HSW_EDP_PSR_BASE 0x64800 #define BDW_EDP_PSR_BASE 0x6f800 #define EDP_PSR_CTL _MMIO(dev_priv->psr_mmio_base + 0) -#define EDP_PSR_ENABLE (1<<31) -#define BDW_PSR_SINGLE_FRAME (1<<30) -#define EDP_PSR_RESTORE_PSR_ACTIVE_CTX_MASK (1<<29) /* SW can't modify */ -#define EDP_PSR_LINK_STANDBY (1<<27) -#define EDP_PSR_MIN_LINK_ENTRY_TIME_MASK (3<<25) -#define EDP_PSR_MIN_LINK_ENTRY_TIME_8_LINES (0<<25) -#define EDP_PSR_MIN_LINK_ENTRY_TIME_4_LINES (1<<25) -#define EDP_PSR_MIN_LINK_ENTRY_TIME_2_LINES (2<<25) -#define EDP_PSR_MIN_LINK_ENTRY_TIME_0_LINES (3<<25) +#define EDP_PSR_ENABLE (1 << 31) +#define BDW_PSR_SINGLE_FRAME (1 << 30) +#define EDP_PSR_RESTORE_PSR_ACTIVE_CTX_MASK (1 << 29) /* SW can't modify */ +#define EDP_PSR_LINK_STANDBY (1 << 27) +#define EDP_PSR_MIN_LINK_ENTRY_TIME_MASK (3 << 25) +#define EDP_PSR_MIN_LINK_ENTRY_TIME_8_LINES (0 << 25) +#define EDP_PSR_MIN_LINK_ENTRY_TIME_4_LINES (1 << 25) +#define EDP_PSR_MIN_LINK_ENTRY_TIME_2_LINES (2 << 25) +#define EDP_PSR_MIN_LINK_ENTRY_TIME_0_LINES (3 << 25) #define EDP_PSR_MAX_SLEEP_TIME_SHIFT 20 -#define EDP_PSR_SKIP_AUX_EXIT (1<<12) -#define EDP_PSR_TP1_TP2_SEL (0<<11) -#define EDP_PSR_TP1_TP3_SEL (1<<11) -#define EDP_PSR_TP2_TP3_TIME_500us (0<<8) -#define EDP_PSR_TP2_TP3_TIME_100us (1<<8) -#define EDP_PSR_TP2_TP3_TIME_2500us (2<<8) -#define EDP_PSR_TP2_TP3_TIME_0us (3<<8) -#define EDP_PSR_TP1_TIME_500us (0<<4) -#define EDP_PSR_TP1_TIME_100us (1<<4) -#define EDP_PSR_TP1_TIME_2500us (2<<4) -#define EDP_PSR_TP1_TIME_0us (3<<4) +#define EDP_PSR_SKIP_AUX_EXIT (1 << 12) +#define EDP_PSR_TP1_TP2_SEL (0 << 11) +#define EDP_PSR_TP1_TP3_SEL (1 << 11) +#define EDP_PSR_TP2_TP3_TIME_500us (0 << 8) +#define EDP_PSR_TP2_TP3_TIME_100us (1 << 8) +#define EDP_PSR_TP2_TP3_TIME_2500us (2 << 8) +#define EDP_PSR_TP2_TP3_TIME_0us (3 << 8) +#define EDP_PSR_TP1_TIME_500us (0 << 4) +#define EDP_PSR_TP1_TIME_100us (1 << 4) +#define EDP_PSR_TP1_TIME_2500us (2 << 4) +#define EDP_PSR_TP1_TIME_0us (3 << 4) #define EDP_PSR_IDLE_FRAME_SHIFT 0 /* Bspec claims those aren't shifted but stay at 0x64800 */ @@ -4071,55 +4071,55 @@ enum { #define EDP_PSR_AUX_DATA(i) _MMIO(dev_priv->psr_mmio_base + 0x14 + (i) * 4) /* 5 registers */ #define EDP_PSR_STATUS _MMIO(dev_priv->psr_mmio_base + 0x40) -#define EDP_PSR_STATUS_STATE_MASK (7<<29) -#define EDP_PSR_STATUS_STATE_IDLE (0<<29) -#define EDP_PSR_STATUS_STATE_SRDONACK (1<<29) -#define EDP_PSR_STATUS_STATE_SRDENT (2<<29) -#define EDP_PSR_STATUS_STATE_BUFOFF (3<<29) -#define EDP_PSR_STATUS_STATE_BUFON (4<<29) -#define EDP_PSR_STATUS_STATE_AUXACK (5<<29) -#define EDP_PSR_STATUS_STATE_SRDOFFACK (6<<29) -#define EDP_PSR_STATUS_LINK_MASK (3<<26) -#define EDP_PSR_STATUS_LINK_FULL_OFF (0<<26) -#define EDP_PSR_STATUS_LINK_FULL_ON (1<<26) -#define EDP_PSR_STATUS_LINK_STANDBY (2<<26) +#define EDP_PSR_STATUS_STATE_MASK (7 << 29) +#define EDP_PSR_STATUS_STATE_IDLE (0 << 29) +#define EDP_PSR_STATUS_STATE_SRDONACK (1 << 29) +#define EDP_PSR_STATUS_STATE_SRDENT (2 << 29) +#define EDP_PSR_STATUS_STATE_BUFOFF (3 << 29) +#define EDP_PSR_STATUS_STATE_BUFON (4 << 29) +#define EDP_PSR_STATUS_STATE_AUXACK (5 << 29) +#define EDP_PSR_STATUS_STATE_SRDOFFACK (6 << 29) +#define EDP_PSR_STATUS_LINK_MASK (3 << 26) +#define EDP_PSR_STATUS_LINK_FULL_OFF (0 << 26) +#define EDP_PSR_STATUS_LINK_FULL_ON (1 << 26) +#define EDP_PSR_STATUS_LINK_STANDBY (2 << 26) #define EDP_PSR_STATUS_MAX_SLEEP_TIMER_SHIFT 20 #define EDP_PSR_STATUS_MAX_SLEEP_TIMER_MASK 0x1f #define EDP_PSR_STATUS_COUNT_SHIFT 16 #define EDP_PSR_STATUS_COUNT_MASK 0xf -#define EDP_PSR_STATUS_AUX_ERROR (1<<15) -#define EDP_PSR_STATUS_AUX_SENDING (1<<12) -#define EDP_PSR_STATUS_SENDING_IDLE (1<<9) -#define EDP_PSR_STATUS_SENDING_TP2_TP3 (1<<8) -#define EDP_PSR_STATUS_SENDING_TP1 (1<<4) +#define EDP_PSR_STATUS_AUX_ERROR (1 << 15) +#define EDP_PSR_STATUS_AUX_SENDING (1 << 12) +#define EDP_PSR_STATUS_SENDING_IDLE (1 << 9) +#define EDP_PSR_STATUS_SENDING_TP2_TP3 (1 << 8) +#define EDP_PSR_STATUS_SENDING_TP1 (1 << 4) #define EDP_PSR_STATUS_IDLE_MASK 0xf #define EDP_PSR_PERF_CNT _MMIO(dev_priv->psr_mmio_base + 0x44) #define EDP_PSR_PERF_CNT_MASK 0xffffff #define EDP_PSR_DEBUG _MMIO(dev_priv->psr_mmio_base + 0x60) /* PSR_MASK on SKL+ */ -#define EDP_PSR_DEBUG_MASK_MAX_SLEEP (1<<28) -#define EDP_PSR_DEBUG_MASK_LPSP (1<<27) -#define EDP_PSR_DEBUG_MASK_MEMUP (1<<26) -#define EDP_PSR_DEBUG_MASK_HPD (1<<25) -#define EDP_PSR_DEBUG_MASK_DISP_REG_WRITE (1<<16) -#define EDP_PSR_DEBUG_EXIT_ON_PIXEL_UNDERRUN (1<<15) /* SKL+ */ +#define EDP_PSR_DEBUG_MASK_MAX_SLEEP (1 << 28) +#define EDP_PSR_DEBUG_MASK_LPSP (1 << 27) +#define EDP_PSR_DEBUG_MASK_MEMUP (1 << 26) +#define EDP_PSR_DEBUG_MASK_HPD (1 << 25) +#define EDP_PSR_DEBUG_MASK_DISP_REG_WRITE (1 << 16) +#define EDP_PSR_DEBUG_EXIT_ON_PIXEL_UNDERRUN (1 << 15) /* SKL+ */ #define EDP_PSR2_CTL _MMIO(0x6f900) -#define EDP_PSR2_ENABLE (1<<31) -#define EDP_SU_TRACK_ENABLE (1<<30) -#define EDP_Y_COORDINATE_VALID (1<<26) /* GLK and CNL+ */ -#define EDP_Y_COORDINATE_ENABLE (1<<25) /* GLK and CNL+ */ -#define EDP_MAX_SU_DISABLE_TIME(t) ((t)<<20) -#define EDP_MAX_SU_DISABLE_TIME_MASK (0x1f<<20) -#define EDP_PSR2_TP2_TIME_500us (0<<8) -#define EDP_PSR2_TP2_TIME_100us (1<<8) -#define EDP_PSR2_TP2_TIME_2500us (2<<8) -#define EDP_PSR2_TP2_TIME_50us (3<<8) -#define EDP_PSR2_TP2_TIME_MASK (3<<8) +#define EDP_PSR2_ENABLE (1 << 31) +#define EDP_SU_TRACK_ENABLE (1 << 30) +#define EDP_Y_COORDINATE_VALID (1 << 26) /* GLK and CNL+ */ +#define EDP_Y_COORDINATE_ENABLE (1 << 25) /* GLK and CNL+ */ +#define EDP_MAX_SU_DISABLE_TIME(t) ((t) << 20) +#define EDP_MAX_SU_DISABLE_TIME_MASK (0x1f << 20) +#define EDP_PSR2_TP2_TIME_500us (0 << 8) +#define EDP_PSR2_TP2_TIME_100us (1 << 8) +#define EDP_PSR2_TP2_TIME_2500us (2 << 8) +#define EDP_PSR2_TP2_TIME_50us (3 << 8) +#define EDP_PSR2_TP2_TIME_MASK (3 << 8) #define EDP_PSR2_FRAME_BEFORE_SU_SHIFT 4 -#define EDP_PSR2_FRAME_BEFORE_SU_MASK (0xf<<4) -#define EDP_PSR2_FRAME_BEFORE_SU(a) ((a)<<4) +#define EDP_PSR2_FRAME_BEFORE_SU_MASK (0xf << 4) +#define EDP_PSR2_FRAME_BEFORE_SU(a) ((a) << 4) #define EDP_PSR2_IDLE_FRAME_MASK 0xf #define EDP_PSR2_IDLE_FRAME_SHIFT 0 @@ -4147,7 +4147,7 @@ enum { #define PSR_EVENT_PSR_DISABLE (1 << 0) #define EDP_PSR2_STATUS _MMIO(0x6f940) -#define EDP_PSR2_STATUS_STATE_MASK (0xf<<28) +#define EDP_PSR2_STATUS_STATE_MASK (0xf << 28) #define EDP_PSR2_STATUS_STATE_SHIFT 28 /* VGA port control */ @@ -4155,48 +4155,48 @@ enum { #define PCH_ADPA _MMIO(0xe1100) #define VLV_ADPA _MMIO(VLV_DISPLAY_BASE + 0x61100) -#define ADPA_DAC_ENABLE (1<<31) +#define ADPA_DAC_ENABLE (1 << 31) #define ADPA_DAC_DISABLE 0 #define ADPA_PIPE_SEL_SHIFT 30 -#define ADPA_PIPE_SEL_MASK (1<<30) +#define ADPA_PIPE_SEL_MASK (1 << 30) #define ADPA_PIPE_SEL(pipe) ((pipe) << 30) #define ADPA_PIPE_SEL_SHIFT_CPT 29 -#define ADPA_PIPE_SEL_MASK_CPT (3<<29) +#define ADPA_PIPE_SEL_MASK_CPT (3 << 29) #define ADPA_PIPE_SEL_CPT(pipe) ((pipe) << 29) #define ADPA_CRT_HOTPLUG_MASK 0x03ff0000 /* bit 25-16 */ -#define ADPA_CRT_HOTPLUG_MONITOR_NONE (0<<24) -#define ADPA_CRT_HOTPLUG_MONITOR_MASK (3<<24) -#define ADPA_CRT_HOTPLUG_MONITOR_COLOR (3<<24) -#define ADPA_CRT_HOTPLUG_MONITOR_MONO (2<<24) -#define ADPA_CRT_HOTPLUG_ENABLE (1<<23) -#define ADPA_CRT_HOTPLUG_PERIOD_64 (0<<22) -#define ADPA_CRT_HOTPLUG_PERIOD_128 (1<<22) -#define ADPA_CRT_HOTPLUG_WARMUP_5MS (0<<21) -#define ADPA_CRT_HOTPLUG_WARMUP_10MS (1<<21) -#define ADPA_CRT_HOTPLUG_SAMPLE_2S (0<<20) -#define ADPA_CRT_HOTPLUG_SAMPLE_4S (1<<20) -#define ADPA_CRT_HOTPLUG_VOLTAGE_40 (0<<18) -#define ADPA_CRT_HOTPLUG_VOLTAGE_50 (1<<18) -#define ADPA_CRT_HOTPLUG_VOLTAGE_60 (2<<18) -#define ADPA_CRT_HOTPLUG_VOLTAGE_70 (3<<18) -#define ADPA_CRT_HOTPLUG_VOLREF_325MV (0<<17) -#define ADPA_CRT_HOTPLUG_VOLREF_475MV (1<<17) -#define ADPA_CRT_HOTPLUG_FORCE_TRIGGER (1<<16) -#define ADPA_USE_VGA_HVPOLARITY (1<<15) +#define ADPA_CRT_HOTPLUG_MONITOR_NONE (0 << 24) +#define ADPA_CRT_HOTPLUG_MONITOR_MASK (3 << 24) +#define ADPA_CRT_HOTPLUG_MONITOR_COLOR (3 << 24) +#define ADPA_CRT_HOTPLUG_MONITOR_MONO (2 << 24) +#define ADPA_CRT_HOTPLUG_ENABLE (1 << 23) +#define ADPA_CRT_HOTPLUG_PERIOD_64 (0 << 22) +#define ADPA_CRT_HOTPLUG_PERIOD_128 (1 << 22) +#define ADPA_CRT_HOTPLUG_WARMUP_5MS (0 << 21) +#define ADPA_CRT_HOTPLUG_WARMUP_10MS (1 << 21) +#define ADPA_CRT_HOTPLUG_SAMPLE_2S (0 << 20) +#define ADPA_CRT_HOTPLUG_SAMPLE_4S (1 << 20) +#define ADPA_CRT_HOTPLUG_VOLTAGE_40 (0 << 18) +#define ADPA_CRT_HOTPLUG_VOLTAGE_50 (1 << 18) +#define ADPA_CRT_HOTPLUG_VOLTAGE_60 (2 << 18) +#define ADPA_CRT_HOTPLUG_VOLTAGE_70 (3 << 18) +#define ADPA_CRT_HOTPLUG_VOLREF_325MV (0 << 17) +#define ADPA_CRT_HOTPLUG_VOLREF_475MV (1 << 17) +#define ADPA_CRT_HOTPLUG_FORCE_TRIGGER (1 << 16) +#define ADPA_USE_VGA_HVPOLARITY (1 << 15) #define ADPA_SETS_HVPOLARITY 0 -#define ADPA_VSYNC_CNTL_DISABLE (1<<10) +#define ADPA_VSYNC_CNTL_DISABLE (1 << 10) #define ADPA_VSYNC_CNTL_ENABLE 0 -#define ADPA_HSYNC_CNTL_DISABLE (1<<11) +#define ADPA_HSYNC_CNTL_DISABLE (1 << 11) #define ADPA_HSYNC_CNTL_ENABLE 0 -#define ADPA_VSYNC_ACTIVE_HIGH (1<<4) +#define ADPA_VSYNC_ACTIVE_HIGH (1 << 4) #define ADPA_VSYNC_ACTIVE_LOW 0 -#define ADPA_HSYNC_ACTIVE_HIGH (1<<3) +#define ADPA_HSYNC_ACTIVE_HIGH (1 << 3) #define ADPA_HSYNC_ACTIVE_LOW 0 -#define ADPA_DPMS_MASK (~(3<<10)) -#define ADPA_DPMS_ON (0<<10) -#define ADPA_DPMS_SUSPEND (1<<10) -#define ADPA_DPMS_STANDBY (2<<10) -#define ADPA_DPMS_OFF (3<<10) +#define ADPA_DPMS_MASK (~(3 << 10)) +#define ADPA_DPMS_ON (0 << 10) +#define ADPA_DPMS_SUSPEND (1 << 10) +#define ADPA_DPMS_STANDBY (2 << 10) +#define ADPA_DPMS_OFF (3 << 10) /* Hotplug control (945+ only) */ @@ -4405,7 +4405,7 @@ enum { #define DVO_BLANK_ACTIVE_HIGH (1 << 2) #define DVO_OUTPUT_CSTATE_PIXELS (1 << 1) /* SDG only */ #define DVO_OUTPUT_SOURCE_SIZE_PIXELS (1 << 0) /* SDG only */ -#define DVO_PRESERVE_MASK (0x7<<24) +#define DVO_PRESERVE_MASK (0x7 << 24) #define DVOA_SRCDIM _MMIO(0x61124) #define DVOB_SRCDIM _MMIO(0x61144) #define DVOC_SRCDIM _MMIO(0x61164) @@ -5383,7 +5383,7 @@ enum { #define _PIPEB_DATA_M_G4X 0x71050 /* Transfer unit size for display port - 1, default is 0x3f (for TU size 64) */ -#define TU_SIZE(x) (((x)-1) << 25) /* default size 64 */ +#define TU_SIZE(x) (((x) - 1) << 25) /* default size 64 */ #define TU_SIZE_SHIFT 25 #define TU_SIZE_MASK (0x3f << 25) @@ -5425,18 +5425,18 @@ enum { #define DSL_LINEMASK_GEN2 0x00000fff #define DSL_LINEMASK_GEN3 0x00001fff #define _PIPEACONF 0x70008 -#define PIPECONF_ENABLE (1<<31) +#define PIPECONF_ENABLE (1 << 31) #define PIPECONF_DISABLE 0 -#define PIPECONF_DOUBLE_WIDE (1<<30) -#define I965_PIPECONF_ACTIVE (1<<30) -#define PIPECONF_DSI_PLL_LOCKED (1<<29) /* vlv & pipe A only */ -#define PIPECONF_FRAME_START_DELAY_MASK (3<<27) +#define PIPECONF_DOUBLE_WIDE (1 << 30) +#define I965_PIPECONF_ACTIVE (1 << 30) +#define PIPECONF_DSI_PLL_LOCKED (1 << 29) /* vlv & pipe A only */ +#define PIPECONF_FRAME_START_DELAY_MASK (3 << 27) #define PIPECONF_SINGLE_WIDE 0 #define PIPECONF_PIPE_UNLOCKED 0 -#define PIPECONF_PIPE_LOCKED (1<<25) +#define PIPECONF_PIPE_LOCKED (1 << 25) #define PIPECONF_PALETTE 0 -#define PIPECONF_GAMMA (1<<24) -#define PIPECONF_FORCE_BORDER (1<<25) +#define PIPECONF_GAMMA (1 << 24) +#define PIPECONF_FORCE_BORDER (1 << 25) #define PIPECONF_INTERLACE_MASK (7 << 21) #define PIPECONF_INTERLACE_MASK_HSW (3 << 21) /* Note that pre-gen3 does not support interlaced display directly. Panel @@ -5455,67 +5455,67 @@ enum { #define PIPECONF_PFIT_PF_INTERLACED_DBL_ILK (5 << 21) /* ilk/snb only */ #define PIPECONF_INTERLACE_MODE_MASK (7 << 21) #define PIPECONF_EDP_RR_MODE_SWITCH (1 << 20) -#define PIPECONF_CXSR_DOWNCLOCK (1<<16) +#define PIPECONF_CXSR_DOWNCLOCK (1 << 16) #define PIPECONF_EDP_RR_MODE_SWITCH_VLV (1 << 14) #define PIPECONF_COLOR_RANGE_SELECT (1 << 13) #define PIPECONF_BPC_MASK (0x7 << 5) -#define PIPECONF_8BPC (0<<5) -#define PIPECONF_10BPC (1<<5) -#define PIPECONF_6BPC (2<<5) -#define PIPECONF_12BPC (3<<5) -#define PIPECONF_DITHER_EN (1<<4) +#define PIPECONF_8BPC (0 << 5) +#define PIPECONF_10BPC (1 << 5) +#define PIPECONF_6BPC (2 << 5) +#define PIPECONF_12BPC (3 << 5) +#define PIPECONF_DITHER_EN (1 << 4) #define PIPECONF_DITHER_TYPE_MASK (0x0000000c) -#define PIPECONF_DITHER_TYPE_SP (0<<2) -#define PIPECONF_DITHER_TYPE_ST1 (1<<2) -#define PIPECONF_DITHER_TYPE_ST2 (2<<2) -#define PIPECONF_DITHER_TYPE_TEMP (3<<2) +#define PIPECONF_DITHER_TYPE_SP (0 << 2) +#define PIPECONF_DITHER_TYPE_ST1 (1 << 2) +#define PIPECONF_DITHER_TYPE_ST2 (2 << 2) +#define PIPECONF_DITHER_TYPE_TEMP (3 << 2) #define _PIPEASTAT 0x70024 -#define PIPE_FIFO_UNDERRUN_STATUS (1UL<<31) -#define SPRITE1_FLIP_DONE_INT_EN_VLV (1UL<<30) -#define PIPE_CRC_ERROR_ENABLE (1UL<<29) -#define PIPE_CRC_DONE_ENABLE (1UL<<28) -#define PERF_COUNTER2_INTERRUPT_EN (1UL<<27) -#define PIPE_GMBUS_EVENT_ENABLE (1UL<<27) -#define PLANE_FLIP_DONE_INT_EN_VLV (1UL<<26) -#define PIPE_HOTPLUG_INTERRUPT_ENABLE (1UL<<26) -#define PIPE_VSYNC_INTERRUPT_ENABLE (1UL<<25) -#define PIPE_DISPLAY_LINE_COMPARE_ENABLE (1UL<<24) -#define PIPE_DPST_EVENT_ENABLE (1UL<<23) -#define SPRITE0_FLIP_DONE_INT_EN_VLV (1UL<<22) -#define PIPE_LEGACY_BLC_EVENT_ENABLE (1UL<<22) -#define PIPE_ODD_FIELD_INTERRUPT_ENABLE (1UL<<21) -#define PIPE_EVEN_FIELD_INTERRUPT_ENABLE (1UL<<20) -#define PIPE_B_PSR_INTERRUPT_ENABLE_VLV (1UL<<19) -#define PERF_COUNTER_INTERRUPT_EN (1UL<<19) -#define PIPE_HOTPLUG_TV_INTERRUPT_ENABLE (1UL<<18) /* pre-965 */ -#define PIPE_START_VBLANK_INTERRUPT_ENABLE (1UL<<18) /* 965 or later */ -#define PIPE_FRAMESTART_INTERRUPT_ENABLE (1UL<<17) -#define PIPE_VBLANK_INTERRUPT_ENABLE (1UL<<17) -#define PIPEA_HBLANK_INT_EN_VLV (1UL<<16) -#define PIPE_OVERLAY_UPDATED_ENABLE (1UL<<16) -#define SPRITE1_FLIP_DONE_INT_STATUS_VLV (1UL<<15) -#define SPRITE0_FLIP_DONE_INT_STATUS_VLV (1UL<<14) -#define PIPE_CRC_ERROR_INTERRUPT_STATUS (1UL<<13) -#define PIPE_CRC_DONE_INTERRUPT_STATUS (1UL<<12) -#define PERF_COUNTER2_INTERRUPT_STATUS (1UL<<11) -#define PIPE_GMBUS_INTERRUPT_STATUS (1UL<<11) -#define PLANE_FLIP_DONE_INT_STATUS_VLV (1UL<<10) -#define PIPE_HOTPLUG_INTERRUPT_STATUS (1UL<<10) -#define PIPE_VSYNC_INTERRUPT_STATUS (1UL<<9) -#define PIPE_DISPLAY_LINE_COMPARE_STATUS (1UL<<8) -#define PIPE_DPST_EVENT_STATUS (1UL<<7) -#define PIPE_A_PSR_STATUS_VLV (1UL<<6) -#define PIPE_LEGACY_BLC_EVENT_STATUS (1UL<<6) -#define PIPE_ODD_FIELD_INTERRUPT_STATUS (1UL<<5) -#define PIPE_EVEN_FIELD_INTERRUPT_STATUS (1UL<<4) -#define PIPE_B_PSR_STATUS_VLV (1UL<<3) -#define PERF_COUNTER_INTERRUPT_STATUS (1UL<<3) -#define PIPE_HOTPLUG_TV_INTERRUPT_STATUS (1UL<<2) /* pre-965 */ -#define PIPE_START_VBLANK_INTERRUPT_STATUS (1UL<<2) /* 965 or later */ -#define PIPE_FRAMESTART_INTERRUPT_STATUS (1UL<<1) -#define PIPE_VBLANK_INTERRUPT_STATUS (1UL<<1) -#define PIPE_HBLANK_INT_STATUS (1UL<<0) -#define PIPE_OVERLAY_UPDATED_STATUS (1UL<<0) +#define PIPE_FIFO_UNDERRUN_STATUS (1UL << 31) +#define SPRITE1_FLIP_DONE_INT_EN_VLV (1UL << 30) +#define PIPE_CRC_ERROR_ENABLE (1UL << 29) +#define PIPE_CRC_DONE_ENABLE (1UL << 28) +#define PERF_COUNTER2_INTERRUPT_EN (1UL << 27) +#define PIPE_GMBUS_EVENT_ENABLE (1UL << 27) +#define PLANE_FLIP_DONE_INT_EN_VLV (1UL << 26) +#define PIPE_HOTPLUG_INTERRUPT_ENABLE (1UL << 26) +#define PIPE_VSYNC_INTERRUPT_ENABLE (1UL << 25) +#define PIPE_DISPLAY_LINE_COMPARE_ENABLE (1UL << 24) +#define PIPE_DPST_EVENT_ENABLE (1UL << 23) +#define SPRITE0_FLIP_DONE_INT_EN_VLV (1UL << 22) +#define PIPE_LEGACY_BLC_EVENT_ENABLE (1UL << 22) +#define PIPE_ODD_FIELD_INTERRUPT_ENABLE (1UL << 21) +#define PIPE_EVEN_FIELD_INTERRUPT_ENABLE (1UL << 20) +#define PIPE_B_PSR_INTERRUPT_ENABLE_VLV (1UL << 19) +#define PERF_COUNTER_INTERRUPT_EN (1UL << 19) +#define PIPE_HOTPLUG_TV_INTERRUPT_ENABLE (1UL << 18) /* pre-965 */ +#define PIPE_START_VBLANK_INTERRUPT_ENABLE (1UL << 18) /* 965 or later */ +#define PIPE_FRAMESTART_INTERRUPT_ENABLE (1UL << 17) +#define PIPE_VBLANK_INTERRUPT_ENABLE (1UL << 17) +#define PIPEA_HBLANK_INT_EN_VLV (1UL << 16) +#define PIPE_OVERLAY_UPDATED_ENABLE (1UL << 16) +#define SPRITE1_FLIP_DONE_INT_STATUS_VLV (1UL << 15) +#define SPRITE0_FLIP_DONE_INT_STATUS_VLV (1UL << 14) +#define PIPE_CRC_ERROR_INTERRUPT_STATUS (1UL << 13) +#define PIPE_CRC_DONE_INTERRUPT_STATUS (1UL << 12) +#define PERF_COUNTER2_INTERRUPT_STATUS (1UL << 11) +#define PIPE_GMBUS_INTERRUPT_STATUS (1UL << 11) +#define PLANE_FLIP_DONE_INT_STATUS_VLV (1UL << 10) +#define PIPE_HOTPLUG_INTERRUPT_STATUS (1UL << 10) +#define PIPE_VSYNC_INTERRUPT_STATUS (1UL << 9) +#define PIPE_DISPLAY_LINE_COMPARE_STATUS (1UL << 8) +#define PIPE_DPST_EVENT_STATUS (1UL << 7) +#define PIPE_A_PSR_STATUS_VLV (1UL << 6) +#define PIPE_LEGACY_BLC_EVENT_STATUS (1UL << 6) +#define PIPE_ODD_FIELD_INTERRUPT_STATUS (1UL << 5) +#define PIPE_EVEN_FIELD_INTERRUPT_STATUS (1UL << 4) +#define PIPE_B_PSR_STATUS_VLV (1UL << 3) +#define PERF_COUNTER_INTERRUPT_STATUS (1UL << 3) +#define PIPE_HOTPLUG_TV_INTERRUPT_STATUS (1UL << 2) /* pre-965 */ +#define PIPE_START_VBLANK_INTERRUPT_STATUS (1UL << 2) /* 965 or later */ +#define PIPE_FRAMESTART_INTERRUPT_STATUS (1UL << 1) +#define PIPE_VBLANK_INTERRUPT_STATUS (1UL << 1) +#define PIPE_HBLANK_INT_STATUS (1UL << 0) +#define PIPE_OVERLAY_UPDATED_STATUS (1UL << 0) #define PIPESTAT_INT_ENABLE_MASK 0x7fff0000 #define PIPESTAT_INT_STATUS_MASK 0x0000ffff @@ -5544,67 +5544,67 @@ enum { #define _PIPE_MISC_A 0x70030 #define _PIPE_MISC_B 0x71030 -#define PIPEMISC_YUV420_ENABLE (1<<27) -#define PIPEMISC_YUV420_MODE_FULL_BLEND (1<<26) -#define PIPEMISC_OUTPUT_COLORSPACE_YUV (1<<11) -#define PIPEMISC_DITHER_BPC_MASK (7<<5) -#define PIPEMISC_DITHER_8_BPC (0<<5) -#define PIPEMISC_DITHER_10_BPC (1<<5) -#define PIPEMISC_DITHER_6_BPC (2<<5) -#define PIPEMISC_DITHER_12_BPC (3<<5) -#define PIPEMISC_DITHER_ENABLE (1<<4) -#define PIPEMISC_DITHER_TYPE_MASK (3<<2) -#define PIPEMISC_DITHER_TYPE_SP (0<<2) +#define PIPEMISC_YUV420_ENABLE (1 << 27) +#define PIPEMISC_YUV420_MODE_FULL_BLEND (1 << 26) +#define PIPEMISC_OUTPUT_COLORSPACE_YUV (1 << 11) +#define PIPEMISC_DITHER_BPC_MASK (7 << 5) +#define PIPEMISC_DITHER_8_BPC (0 << 5) +#define PIPEMISC_DITHER_10_BPC (1 << 5) +#define PIPEMISC_DITHER_6_BPC (2 << 5) +#define PIPEMISC_DITHER_12_BPC (3 << 5) +#define PIPEMISC_DITHER_ENABLE (1 << 4) +#define PIPEMISC_DITHER_TYPE_MASK (3 << 2) +#define PIPEMISC_DITHER_TYPE_SP (0 << 2) #define PIPEMISC(pipe) _MMIO_PIPE2(pipe, _PIPE_MISC_A) #define VLV_DPFLIPSTAT _MMIO(VLV_DISPLAY_BASE + 0x70028) -#define PIPEB_LINE_COMPARE_INT_EN (1<<29) -#define PIPEB_HLINE_INT_EN (1<<28) -#define PIPEB_VBLANK_INT_EN (1<<27) -#define SPRITED_FLIP_DONE_INT_EN (1<<26) -#define SPRITEC_FLIP_DONE_INT_EN (1<<25) -#define PLANEB_FLIP_DONE_INT_EN (1<<24) -#define PIPE_PSR_INT_EN (1<<22) -#define PIPEA_LINE_COMPARE_INT_EN (1<<21) -#define PIPEA_HLINE_INT_EN (1<<20) -#define PIPEA_VBLANK_INT_EN (1<<19) -#define SPRITEB_FLIP_DONE_INT_EN (1<<18) -#define SPRITEA_FLIP_DONE_INT_EN (1<<17) -#define PLANEA_FLIPDONE_INT_EN (1<<16) -#define PIPEC_LINE_COMPARE_INT_EN (1<<13) -#define PIPEC_HLINE_INT_EN (1<<12) -#define PIPEC_VBLANK_INT_EN (1<<11) -#define SPRITEF_FLIPDONE_INT_EN (1<<10) -#define SPRITEE_FLIPDONE_INT_EN (1<<9) -#define PLANEC_FLIPDONE_INT_EN (1<<8) +#define PIPEB_LINE_COMPARE_INT_EN (1 << 29) +#define PIPEB_HLINE_INT_EN (1 << 28) +#define PIPEB_VBLANK_INT_EN (1 << 27) +#define SPRITED_FLIP_DONE_INT_EN (1 << 26) +#define SPRITEC_FLIP_DONE_INT_EN (1 << 25) +#define PLANEB_FLIP_DONE_INT_EN (1 << 24) +#define PIPE_PSR_INT_EN (1 << 22) +#define PIPEA_LINE_COMPARE_INT_EN (1 << 21) +#define PIPEA_HLINE_INT_EN (1 << 20) +#define PIPEA_VBLANK_INT_EN (1 << 19) +#define SPRITEB_FLIP_DONE_INT_EN (1 << 18) +#define SPRITEA_FLIP_DONE_INT_EN (1 << 17) +#define PLANEA_FLIPDONE_INT_EN (1 << 16) +#define PIPEC_LINE_COMPARE_INT_EN (1 << 13) +#define PIPEC_HLINE_INT_EN (1 << 12) +#define PIPEC_VBLANK_INT_EN (1 << 11) +#define SPRITEF_FLIPDONE_INT_EN (1 << 10) +#define SPRITEE_FLIPDONE_INT_EN (1 << 9) +#define PLANEC_FLIPDONE_INT_EN (1 << 8) #define DPINVGTT _MMIO(VLV_DISPLAY_BASE + 0x7002c) /* VLV/CHV only */ -#define SPRITEF_INVALID_GTT_INT_EN (1<<27) -#define SPRITEE_INVALID_GTT_INT_EN (1<<26) -#define PLANEC_INVALID_GTT_INT_EN (1<<25) -#define CURSORC_INVALID_GTT_INT_EN (1<<24) -#define CURSORB_INVALID_GTT_INT_EN (1<<23) -#define CURSORA_INVALID_GTT_INT_EN (1<<22) -#define SPRITED_INVALID_GTT_INT_EN (1<<21) -#define SPRITEC_INVALID_GTT_INT_EN (1<<20) -#define PLANEB_INVALID_GTT_INT_EN (1<<19) -#define SPRITEB_INVALID_GTT_INT_EN (1<<18) -#define SPRITEA_INVALID_GTT_INT_EN (1<<17) -#define PLANEA_INVALID_GTT_INT_EN (1<<16) +#define SPRITEF_INVALID_GTT_INT_EN (1 << 27) +#define SPRITEE_INVALID_GTT_INT_EN (1 << 26) +#define PLANEC_INVALID_GTT_INT_EN (1 << 25) +#define CURSORC_INVALID_GTT_INT_EN (1 << 24) +#define CURSORB_INVALID_GTT_INT_EN (1 << 23) +#define CURSORA_INVALID_GTT_INT_EN (1 << 22) +#define SPRITED_INVALID_GTT_INT_EN (1 << 21) +#define SPRITEC_INVALID_GTT_INT_EN (1 << 20) +#define PLANEB_INVALID_GTT_INT_EN (1 << 19) +#define SPRITEB_INVALID_GTT_INT_EN (1 << 18) +#define SPRITEA_INVALID_GTT_INT_EN (1 << 17) +#define PLANEA_INVALID_GTT_INT_EN (1 << 16) #define DPINVGTT_EN_MASK 0xff0000 #define DPINVGTT_EN_MASK_CHV 0xfff0000 -#define SPRITEF_INVALID_GTT_STATUS (1<<11) -#define SPRITEE_INVALID_GTT_STATUS (1<<10) -#define PLANEC_INVALID_GTT_STATUS (1<<9) -#define CURSORC_INVALID_GTT_STATUS (1<<8) -#define CURSORB_INVALID_GTT_STATUS (1<<7) -#define CURSORA_INVALID_GTT_STATUS (1<<6) -#define SPRITED_INVALID_GTT_STATUS (1<<5) -#define SPRITEC_INVALID_GTT_STATUS (1<<4) -#define PLANEB_INVALID_GTT_STATUS (1<<3) -#define SPRITEB_INVALID_GTT_STATUS (1<<2) -#define SPRITEA_INVALID_GTT_STATUS (1<<1) -#define PLANEA_INVALID_GTT_STATUS (1<<0) +#define SPRITEF_INVALID_GTT_STATUS (1 << 11) +#define SPRITEE_INVALID_GTT_STATUS (1 << 10) +#define PLANEC_INVALID_GTT_STATUS (1 << 9) +#define CURSORC_INVALID_GTT_STATUS (1 << 8) +#define CURSORB_INVALID_GTT_STATUS (1 << 7) +#define CURSORA_INVALID_GTT_STATUS (1 << 6) +#define SPRITED_INVALID_GTT_STATUS (1 << 5) +#define SPRITEC_INVALID_GTT_STATUS (1 << 4) +#define PLANEB_INVALID_GTT_STATUS (1 << 3) +#define SPRITEB_INVALID_GTT_STATUS (1 << 2) +#define SPRITEA_INVALID_GTT_STATUS (1 << 1) +#define PLANEA_INVALID_GTT_STATUS (1 << 0) #define DPINVGTT_STATUS_MASK 0xff #define DPINVGTT_STATUS_MASK_CHV 0xfff @@ -5645,149 +5645,149 @@ enum { /* pnv/gen4/g4x/vlv/chv */ #define DSPFW1 _MMIO(dev_priv->info.display_mmio_offset + 0x70034) #define DSPFW_SR_SHIFT 23 -#define DSPFW_SR_MASK (0x1ff<<23) +#define DSPFW_SR_MASK (0x1ff << 23) #define DSPFW_CURSORB_SHIFT 16 -#define DSPFW_CURSORB_MASK (0x3f<<16) +#define DSPFW_CURSORB_MASK (0x3f << 16) #define DSPFW_PLANEB_SHIFT 8 -#define DSPFW_PLANEB_MASK (0x7f<<8) -#define DSPFW_PLANEB_MASK_VLV (0xff<<8) /* vlv/chv */ +#define DSPFW_PLANEB_MASK (0x7f << 8) +#define DSPFW_PLANEB_MASK_VLV (0xff << 8) /* vlv/chv */ #define DSPFW_PLANEA_SHIFT 0 -#define DSPFW_PLANEA_MASK (0x7f<<0) -#define DSPFW_PLANEA_MASK_VLV (0xff<<0) /* vlv/chv */ +#define DSPFW_PLANEA_MASK (0x7f << 0) +#define DSPFW_PLANEA_MASK_VLV (0xff << 0) /* vlv/chv */ #define DSPFW2 _MMIO(dev_priv->info.display_mmio_offset + 0x70038) -#define DSPFW_FBC_SR_EN (1<<31) /* g4x */ +#define DSPFW_FBC_SR_EN (1 << 31) /* g4x */ #define DSPFW_FBC_SR_SHIFT 28 -#define DSPFW_FBC_SR_MASK (0x7<<28) /* g4x */ +#define DSPFW_FBC_SR_MASK (0x7 << 28) /* g4x */ #define DSPFW_FBC_HPLL_SR_SHIFT 24 -#define DSPFW_FBC_HPLL_SR_MASK (0xf<<24) /* g4x */ +#define DSPFW_FBC_HPLL_SR_MASK (0xf << 24) /* g4x */ #define DSPFW_SPRITEB_SHIFT (16) -#define DSPFW_SPRITEB_MASK (0x7f<<16) /* g4x */ -#define DSPFW_SPRITEB_MASK_VLV (0xff<<16) /* vlv/chv */ +#define DSPFW_SPRITEB_MASK (0x7f << 16) /* g4x */ +#define DSPFW_SPRITEB_MASK_VLV (0xff << 16) /* vlv/chv */ #define DSPFW_CURSORA_SHIFT 8 -#define DSPFW_CURSORA_MASK (0x3f<<8) +#define DSPFW_CURSORA_MASK (0x3f << 8) #define DSPFW_PLANEC_OLD_SHIFT 0 -#define DSPFW_PLANEC_OLD_MASK (0x7f<<0) /* pre-gen4 sprite C */ +#define DSPFW_PLANEC_OLD_MASK (0x7f << 0) /* pre-gen4 sprite C */ #define DSPFW_SPRITEA_SHIFT 0 -#define DSPFW_SPRITEA_MASK (0x7f<<0) /* g4x */ -#define DSPFW_SPRITEA_MASK_VLV (0xff<<0) /* vlv/chv */ +#define DSPFW_SPRITEA_MASK (0x7f << 0) /* g4x */ +#define DSPFW_SPRITEA_MASK_VLV (0xff << 0) /* vlv/chv */ #define DSPFW3 _MMIO(dev_priv->info.display_mmio_offset + 0x7003c) -#define DSPFW_HPLL_SR_EN (1<<31) -#define PINEVIEW_SELF_REFRESH_EN (1<<30) +#define DSPFW_HPLL_SR_EN (1 << 31) +#define PINEVIEW_SELF_REFRESH_EN (1 << 30) #define DSPFW_CURSOR_SR_SHIFT 24 -#define DSPFW_CURSOR_SR_MASK (0x3f<<24) +#define DSPFW_CURSOR_SR_MASK (0x3f << 24) #define DSPFW_HPLL_CURSOR_SHIFT 16 -#define DSPFW_HPLL_CURSOR_MASK (0x3f<<16) +#define DSPFW_HPLL_CURSOR_MASK (0x3f << 16) #define DSPFW_HPLL_SR_SHIFT 0 -#define DSPFW_HPLL_SR_MASK (0x1ff<<0) +#define DSPFW_HPLL_SR_MASK (0x1ff << 0) /* vlv/chv */ #define DSPFW4 _MMIO(VLV_DISPLAY_BASE + 0x70070) #define DSPFW_SPRITEB_WM1_SHIFT 16 -#define DSPFW_SPRITEB_WM1_MASK (0xff<<16) +#define DSPFW_SPRITEB_WM1_MASK (0xff << 16) #define DSPFW_CURSORA_WM1_SHIFT 8 -#define DSPFW_CURSORA_WM1_MASK (0x3f<<8) +#define DSPFW_CURSORA_WM1_MASK (0x3f << 8) #define DSPFW_SPRITEA_WM1_SHIFT 0 -#define DSPFW_SPRITEA_WM1_MASK (0xff<<0) +#define DSPFW_SPRITEA_WM1_MASK (0xff << 0) #define DSPFW5 _MMIO(VLV_DISPLAY_BASE + 0x70074) #define DSPFW_PLANEB_WM1_SHIFT 24 -#define DSPFW_PLANEB_WM1_MASK (0xff<<24) +#define DSPFW_PLANEB_WM1_MASK (0xff << 24) #define DSPFW_PLANEA_WM1_SHIFT 16 -#define DSPFW_PLANEA_WM1_MASK (0xff<<16) +#define DSPFW_PLANEA_WM1_MASK (0xff << 16) #define DSPFW_CURSORB_WM1_SHIFT 8 -#define DSPFW_CURSORB_WM1_MASK (0x3f<<8) +#define DSPFW_CURSORB_WM1_MASK (0x3f << 8) #define DSPFW_CURSOR_SR_WM1_SHIFT 0 -#define DSPFW_CURSOR_SR_WM1_MASK (0x3f<<0) +#define DSPFW_CURSOR_SR_WM1_MASK (0x3f << 0) #define DSPFW6 _MMIO(VLV_DISPLAY_BASE + 0x70078) #define DSPFW_SR_WM1_SHIFT 0 -#define DSPFW_SR_WM1_MASK (0x1ff<<0) +#define DSPFW_SR_WM1_MASK (0x1ff << 0) #define DSPFW7 _MMIO(VLV_DISPLAY_BASE + 0x7007c) #define DSPFW7_CHV _MMIO(VLV_DISPLAY_BASE + 0x700b4) /* wtf #1? */ #define DSPFW_SPRITED_WM1_SHIFT 24 -#define DSPFW_SPRITED_WM1_MASK (0xff<<24) +#define DSPFW_SPRITED_WM1_MASK (0xff << 24) #define DSPFW_SPRITED_SHIFT 16 -#define DSPFW_SPRITED_MASK_VLV (0xff<<16) +#define DSPFW_SPRITED_MASK_VLV (0xff << 16) #define DSPFW_SPRITEC_WM1_SHIFT 8 -#define DSPFW_SPRITEC_WM1_MASK (0xff<<8) +#define DSPFW_SPRITEC_WM1_MASK (0xff << 8) #define DSPFW_SPRITEC_SHIFT 0 -#define DSPFW_SPRITEC_MASK_VLV (0xff<<0) +#define DSPFW_SPRITEC_MASK_VLV (0xff << 0) #define DSPFW8_CHV _MMIO(VLV_DISPLAY_BASE + 0x700b8) #define DSPFW_SPRITEF_WM1_SHIFT 24 -#define DSPFW_SPRITEF_WM1_MASK (0xff<<24) +#define DSPFW_SPRITEF_WM1_MASK (0xff << 24) #define DSPFW_SPRITEF_SHIFT 16 -#define DSPFW_SPRITEF_MASK_VLV (0xff<<16) +#define DSPFW_SPRITEF_MASK_VLV (0xff << 16) #define DSPFW_SPRITEE_WM1_SHIFT 8 -#define DSPFW_SPRITEE_WM1_MASK (0xff<<8) +#define DSPFW_SPRITEE_WM1_MASK (0xff << 8) #define DSPFW_SPRITEE_SHIFT 0 -#define DSPFW_SPRITEE_MASK_VLV (0xff<<0) +#define DSPFW_SPRITEE_MASK_VLV (0xff << 0) #define DSPFW9_CHV _MMIO(VLV_DISPLAY_BASE + 0x7007c) /* wtf #2? */ #define DSPFW_PLANEC_WM1_SHIFT 24 -#define DSPFW_PLANEC_WM1_MASK (0xff<<24) +#define DSPFW_PLANEC_WM1_MASK (0xff << 24) #define DSPFW_PLANEC_SHIFT 16 -#define DSPFW_PLANEC_MASK_VLV (0xff<<16) +#define DSPFW_PLANEC_MASK_VLV (0xff << 16) #define DSPFW_CURSORC_WM1_SHIFT 8 -#define DSPFW_CURSORC_WM1_MASK (0x3f<<16) +#define DSPFW_CURSORC_WM1_MASK (0x3f << 16) #define DSPFW_CURSORC_SHIFT 0 -#define DSPFW_CURSORC_MASK (0x3f<<0) +#define DSPFW_CURSORC_MASK (0x3f << 0) /* vlv/chv high order bits */ #define DSPHOWM _MMIO(VLV_DISPLAY_BASE + 0x70064) #define DSPFW_SR_HI_SHIFT 24 -#define DSPFW_SR_HI_MASK (3<<24) /* 2 bits for chv, 1 for vlv */ +#define DSPFW_SR_HI_MASK (3 << 24) /* 2 bits for chv, 1 for vlv */ #define DSPFW_SPRITEF_HI_SHIFT 23 -#define DSPFW_SPRITEF_HI_MASK (1<<23) +#define DSPFW_SPRITEF_HI_MASK (1 << 23) #define DSPFW_SPRITEE_HI_SHIFT 22 -#define DSPFW_SPRITEE_HI_MASK (1<<22) +#define DSPFW_SPRITEE_HI_MASK (1 << 22) #define DSPFW_PLANEC_HI_SHIFT 21 -#define DSPFW_PLANEC_HI_MASK (1<<21) +#define DSPFW_PLANEC_HI_MASK (1 << 21) #define DSPFW_SPRITED_HI_SHIFT 20 -#define DSPFW_SPRITED_HI_MASK (1<<20) +#define DSPFW_SPRITED_HI_MASK (1 << 20) #define DSPFW_SPRITEC_HI_SHIFT 16 -#define DSPFW_SPRITEC_HI_MASK (1<<16) +#define DSPFW_SPRITEC_HI_MASK (1 << 16) #define DSPFW_PLANEB_HI_SHIFT 12 -#define DSPFW_PLANEB_HI_MASK (1<<12) +#define DSPFW_PLANEB_HI_MASK (1 << 12) #define DSPFW_SPRITEB_HI_SHIFT 8 -#define DSPFW_SPRITEB_HI_MASK (1<<8) +#define DSPFW_SPRITEB_HI_MASK (1 << 8) #define DSPFW_SPRITEA_HI_SHIFT 4 -#define DSPFW_SPRITEA_HI_MASK (1<<4) +#define DSPFW_SPRITEA_HI_MASK (1 << 4) #define DSPFW_PLANEA_HI_SHIFT 0 -#define DSPFW_PLANEA_HI_MASK (1<<0) +#define DSPFW_PLANEA_HI_MASK (1 << 0) #define DSPHOWM1 _MMIO(VLV_DISPLAY_BASE + 0x70068) #define DSPFW_SR_WM1_HI_SHIFT 24 -#define DSPFW_SR_WM1_HI_MASK (3<<24) /* 2 bits for chv, 1 for vlv */ +#define DSPFW_SR_WM1_HI_MASK (3 << 24) /* 2 bits for chv, 1 for vlv */ #define DSPFW_SPRITEF_WM1_HI_SHIFT 23 -#define DSPFW_SPRITEF_WM1_HI_MASK (1<<23) +#define DSPFW_SPRITEF_WM1_HI_MASK (1 << 23) #define DSPFW_SPRITEE_WM1_HI_SHIFT 22 -#define DSPFW_SPRITEE_WM1_HI_MASK (1<<22) +#define DSPFW_SPRITEE_WM1_HI_MASK (1 << 22) #define DSPFW_PLANEC_WM1_HI_SHIFT 21 -#define DSPFW_PLANEC_WM1_HI_MASK (1<<21) +#define DSPFW_PLANEC_WM1_HI_MASK (1 << 21) #define DSPFW_SPRITED_WM1_HI_SHIFT 20 -#define DSPFW_SPRITED_WM1_HI_MASK (1<<20) +#define DSPFW_SPRITED_WM1_HI_MASK (1 << 20) #define DSPFW_SPRITEC_WM1_HI_SHIFT 16 -#define DSPFW_SPRITEC_WM1_HI_MASK (1<<16) +#define DSPFW_SPRITEC_WM1_HI_MASK (1 << 16) #define DSPFW_PLANEB_WM1_HI_SHIFT 12 -#define DSPFW_PLANEB_WM1_HI_MASK (1<<12) +#define DSPFW_PLANEB_WM1_HI_MASK (1 << 12) #define DSPFW_SPRITEB_WM1_HI_SHIFT 8 -#define DSPFW_SPRITEB_WM1_HI_MASK (1<<8) +#define DSPFW_SPRITEB_WM1_HI_MASK (1 << 8) #define DSPFW_SPRITEA_WM1_HI_SHIFT 4 -#define DSPFW_SPRITEA_WM1_HI_MASK (1<<4) +#define DSPFW_SPRITEA_WM1_HI_MASK (1 << 4) #define DSPFW_PLANEA_WM1_HI_SHIFT 0 -#define DSPFW_PLANEA_WM1_HI_MASK (1<<0) +#define DSPFW_PLANEA_WM1_HI_MASK (1 << 0) /* drain latency register values*/ #define VLV_DDL(pipe) _MMIO(VLV_DISPLAY_BASE + 0x70050 + 4 * (pipe)) #define DDL_CURSOR_SHIFT 24 -#define DDL_SPRITE_SHIFT(sprite) (8+8*(sprite)) +#define DDL_SPRITE_SHIFT(sprite) (8 + 8 * (sprite)) #define DDL_PLANE_SHIFT 0 -#define DDL_PRECISION_HIGH (1<<7) -#define DDL_PRECISION_LOW (0<<7) +#define DDL_PRECISION_HIGH (1 << 7) +#define DDL_PRECISION_LOW (0 << 7) #define DRAIN_LATENCY_MASK 0x7f #define CBR1_VLV _MMIO(VLV_DISPLAY_BASE + 0x70400) -#define CBR_PND_DEADLINE_DISABLE (1<<31) -#define CBR_PWM_CLOCK_MUX_SELECT (1<<30) +#define CBR_PND_DEADLINE_DISABLE (1 << 31) +#define CBR_PWM_CLOCK_MUX_SELECT (1 << 30) #define CBR4_VLV _MMIO(VLV_DISPLAY_BASE + 0x70450) -#define CBR_DPLLBMD_PIPE(pipe) (1<<(7+(pipe)*11)) /* pipes B and C */ +#define CBR_DPLLBMD_PIPE(pipe) (1 << (7 + (pipe) * 11)) /* pipes B and C */ /* FIFO watermark sizes etc */ #define G4X_FIFO_LINE_SIZE 64 @@ -5859,32 +5859,32 @@ enum { /* define the Watermark register on Ironlake */ #define WM0_PIPEA_ILK _MMIO(0x45100) -#define WM0_PIPE_PLANE_MASK (0xffff<<16) +#define WM0_PIPE_PLANE_MASK (0xffff << 16) #define WM0_PIPE_PLANE_SHIFT 16 -#define WM0_PIPE_SPRITE_MASK (0xff<<8) +#define WM0_PIPE_SPRITE_MASK (0xff << 8) #define WM0_PIPE_SPRITE_SHIFT 8 #define WM0_PIPE_CURSOR_MASK (0xff) #define WM0_PIPEB_ILK _MMIO(0x45104) #define WM0_PIPEC_IVB _MMIO(0x45200) #define WM1_LP_ILK _MMIO(0x45108) -#define WM1_LP_SR_EN (1<<31) +#define WM1_LP_SR_EN (1 << 31) #define WM1_LP_LATENCY_SHIFT 24 -#define WM1_LP_LATENCY_MASK (0x7f<<24) -#define WM1_LP_FBC_MASK (0xf<<20) +#define WM1_LP_LATENCY_MASK (0x7f << 24) +#define WM1_LP_FBC_MASK (0xf << 20) #define WM1_LP_FBC_SHIFT 20 #define WM1_LP_FBC_SHIFT_BDW 19 -#define WM1_LP_SR_MASK (0x7ff<<8) +#define WM1_LP_SR_MASK (0x7ff << 8) #define WM1_LP_SR_SHIFT 8 #define WM1_LP_CURSOR_MASK (0xff) #define WM2_LP_ILK _MMIO(0x4510c) -#define WM2_LP_EN (1<<31) +#define WM2_LP_EN (1 << 31) #define WM3_LP_ILK _MMIO(0x45110) -#define WM3_LP_EN (1<<31) +#define WM3_LP_EN (1 << 31) #define WM1S_LP_ILK _MMIO(0x45120) #define WM2S_LP_IVB _MMIO(0x45124) #define WM3S_LP_IVB _MMIO(0x45128) -#define WM1S_LP_EN (1<<31) +#define WM1S_LP_EN (1 << 31) #define HSW_WM_LP_VAL(lat, fbc, pri, cur) \ (WM3_LP_EN | ((lat) << WM1_LP_LATENCY_SHIFT) | \ @@ -5941,7 +5941,7 @@ enum { #define CURSOR_ENABLE 0x80000000 #define CURSOR_GAMMA_ENABLE 0x40000000 #define CURSOR_STRIDE_SHIFT 28 -#define CURSOR_STRIDE(x) ((ffs(x)-9) << CURSOR_STRIDE_SHIFT) /* 256,512,1k,2k */ +#define CURSOR_STRIDE(x) ((ffs(x) - 9) << CURSOR_STRIDE_SHIFT) /* 256,512,1k,2k */ #define CURSOR_FORMAT_SHIFT 24 #define CURSOR_FORMAT_MASK (0x07 << CURSOR_FORMAT_SHIFT) #define CURSOR_FORMAT_2C (0x00 << CURSOR_FORMAT_SHIFT) @@ -5962,8 +5962,8 @@ enum { #define MCURSOR_PIPE_SELECT_SHIFT 28 #define MCURSOR_PIPE_SELECT(pipe) ((pipe) << 28) #define MCURSOR_GAMMA_ENABLE (1 << 26) -#define MCURSOR_PIPE_CSC_ENABLE (1<<24) -#define MCURSOR_ROTATE_180 (1<<15) +#define MCURSOR_PIPE_CSC_ENABLE (1 << 24) +#define MCURSOR_ROTATE_180 (1 << 15) #define MCURSOR_TRICKLE_FEED_DISABLE (1 << 14) #define _CURABASE 0x70084 #define _CURAPOS 0x70088 @@ -6001,41 +6001,41 @@ enum { /* Display A control */ #define _DSPACNTR 0x70180 -#define DISPLAY_PLANE_ENABLE (1<<31) +#define DISPLAY_PLANE_ENABLE (1 << 31) #define DISPLAY_PLANE_DISABLE 0 -#define DISPPLANE_GAMMA_ENABLE (1<<30) +#define DISPPLANE_GAMMA_ENABLE (1 << 30) #define DISPPLANE_GAMMA_DISABLE 0 -#define DISPPLANE_PIXFORMAT_MASK (0xf<<26) -#define DISPPLANE_YUV422 (0x0<<26) -#define DISPPLANE_8BPP (0x2<<26) -#define DISPPLANE_BGRA555 (0x3<<26) -#define DISPPLANE_BGRX555 (0x4<<26) -#define DISPPLANE_BGRX565 (0x5<<26) -#define DISPPLANE_BGRX888 (0x6<<26) -#define DISPPLANE_BGRA888 (0x7<<26) -#define DISPPLANE_RGBX101010 (0x8<<26) -#define DISPPLANE_RGBA101010 (0x9<<26) -#define DISPPLANE_BGRX101010 (0xa<<26) -#define DISPPLANE_RGBX161616 (0xc<<26) -#define DISPPLANE_RGBX888 (0xe<<26) -#define DISPPLANE_RGBA888 (0xf<<26) -#define DISPPLANE_STEREO_ENABLE (1<<25) +#define DISPPLANE_PIXFORMAT_MASK (0xf << 26) +#define DISPPLANE_YUV422 (0x0 << 26) +#define DISPPLANE_8BPP (0x2 << 26) +#define DISPPLANE_BGRA555 (0x3 << 26) +#define DISPPLANE_BGRX555 (0x4 << 26) +#define DISPPLANE_BGRX565 (0x5 << 26) +#define DISPPLANE_BGRX888 (0x6 << 26) +#define DISPPLANE_BGRA888 (0x7 << 26) +#define DISPPLANE_RGBX101010 (0x8 << 26) +#define DISPPLANE_RGBA101010 (0x9 << 26) +#define DISPPLANE_BGRX101010 (0xa << 26) +#define DISPPLANE_RGBX161616 (0xc << 26) +#define DISPPLANE_RGBX888 (0xe << 26) +#define DISPPLANE_RGBA888 (0xf << 26) +#define DISPPLANE_STEREO_ENABLE (1 << 25) #define DISPPLANE_STEREO_DISABLE 0 -#define DISPPLANE_PIPE_CSC_ENABLE (1<<24) +#define DISPPLANE_PIPE_CSC_ENABLE (1 << 24) #define DISPPLANE_SEL_PIPE_SHIFT 24 -#define DISPPLANE_SEL_PIPE_MASK (3<<DISPPLANE_SEL_PIPE_SHIFT) -#define DISPPLANE_SEL_PIPE(pipe) ((pipe)<<DISPPLANE_SEL_PIPE_SHIFT) -#define DISPPLANE_SRC_KEY_ENABLE (1<<22) +#define DISPPLANE_SEL_PIPE_MASK (3 << DISPPLANE_SEL_PIPE_SHIFT) +#define DISPPLANE_SEL_PIPE(pipe) ((pipe) << DISPPLANE_SEL_PIPE_SHIFT) +#define DISPPLANE_SRC_KEY_ENABLE (1 << 22) #define DISPPLANE_SRC_KEY_DISABLE 0 -#define DISPPLANE_LINE_DOUBLE (1<<20) +#define DISPPLANE_LINE_DOUBLE (1 << 20) #define DISPPLANE_NO_LINE_DOUBLE 0 #define DISPPLANE_STEREO_POLARITY_FIRST 0 -#define DISPPLANE_STEREO_POLARITY_SECOND (1<<18) -#define DISPPLANE_ALPHA_PREMULTIPLY (1<<16) /* CHV pipe B */ -#define DISPPLANE_ROTATE_180 (1<<15) -#define DISPPLANE_TRICKLE_FEED_DISABLE (1<<14) /* Ironlake */ -#define DISPPLANE_TILED (1<<10) -#define DISPPLANE_MIRROR (1<<8) /* CHV pipe B */ +#define DISPPLANE_STEREO_POLARITY_SECOND (1 << 18) +#define DISPPLANE_ALPHA_PREMULTIPLY (1 << 16) /* CHV pipe B */ +#define DISPPLANE_ROTATE_180 (1 << 15) +#define DISPPLANE_TRICKLE_FEED_DISABLE (1 << 14) /* Ironlake */ +#define DISPPLANE_TILED (1 << 10) +#define DISPPLANE_MIRROR (1 << 8) /* CHV pipe B */ #define _DSPAADDR 0x70184 #define _DSPASTRIDE 0x70188 #define _DSPAPOS 0x7018C /* reserved */ @@ -6058,15 +6058,15 @@ enum { /* CHV pipe B blender and primary plane */ #define _CHV_BLEND_A 0x60a00 -#define CHV_BLEND_LEGACY (0<<30) -#define CHV_BLEND_ANDROID (1<<30) -#define CHV_BLEND_MPO (2<<30) -#define CHV_BLEND_MASK (3<<30) +#define CHV_BLEND_LEGACY (0 << 30) +#define CHV_BLEND_ANDROID (1 << 30) +#define CHV_BLEND_MPO (2 << 30) +#define CHV_BLEND_MASK (3 << 30) #define _CHV_CANVAS_A 0x60a04 #define _PRIMPOS_A 0x60a08 #define _PRIMSIZE_A 0x60a0c #define _PRIMCNSTALPHA_A 0x60a10 -#define PRIM_CONST_ALPHA_ENABLE (1<<31) +#define PRIM_CONST_ALPHA_ENABLE (1 << 31) #define CHV_BLEND(pipe) _MMIO_TRANS2(pipe, _CHV_BLEND_A) #define CHV_CANVAS(pipe) _MMIO_TRANS2(pipe, _CHV_CANVAS_A) @@ -6107,7 +6107,7 @@ enum { /* Display B control */ #define _DSPBCNTR (dev_priv->info.display_mmio_offset + 0x71180) -#define DISPPLANE_ALPHA_TRANS_ENABLE (1<<15) +#define DISPPLANE_ALPHA_TRANS_ENABLE (1 << 15) #define DISPPLANE_ALPHA_TRANS_DISABLE 0 #define DISPPLANE_SPRITE_ABOVE_DISPLAY 0 #define DISPPLANE_SPRITE_ABOVE_OVERLAY (1) @@ -6122,27 +6122,27 @@ enum { /* Sprite A control */ #define _DVSACNTR 0x72180 -#define DVS_ENABLE (1<<31) -#define DVS_GAMMA_ENABLE (1<<30) -#define DVS_YUV_RANGE_CORRECTION_DISABLE (1<<27) -#define DVS_PIXFORMAT_MASK (3<<25) -#define DVS_FORMAT_YUV422 (0<<25) -#define DVS_FORMAT_RGBX101010 (1<<25) -#define DVS_FORMAT_RGBX888 (2<<25) -#define DVS_FORMAT_RGBX161616 (3<<25) -#define DVS_PIPE_CSC_ENABLE (1<<24) -#define DVS_SOURCE_KEY (1<<22) -#define DVS_RGB_ORDER_XBGR (1<<20) -#define DVS_YUV_FORMAT_BT709 (1<<18) -#define DVS_YUV_BYTE_ORDER_MASK (3<<16) -#define DVS_YUV_ORDER_YUYV (0<<16) -#define DVS_YUV_ORDER_UYVY (1<<16) -#define DVS_YUV_ORDER_YVYU (2<<16) -#define DVS_YUV_ORDER_VYUY (3<<16) -#define DVS_ROTATE_180 (1<<15) -#define DVS_DEST_KEY (1<<2) -#define DVS_TRICKLE_FEED_DISABLE (1<<14) -#define DVS_TILED (1<<10) +#define DVS_ENABLE (1 << 31) +#define DVS_GAMMA_ENABLE (1 << 30) +#define DVS_YUV_RANGE_CORRECTION_DISABLE (1 << 27) +#define DVS_PIXFORMAT_MASK (3 << 25) +#define DVS_FORMAT_YUV422 (0 << 25) +#define DVS_FORMAT_RGBX101010 (1 << 25) +#define DVS_FORMAT_RGBX888 (2 << 25) +#define DVS_FORMAT_RGBX161616 (3 << 25) +#define DVS_PIPE_CSC_ENABLE (1 << 24) +#define DVS_SOURCE_KEY (1 << 22) +#define DVS_RGB_ORDER_XBGR (1 << 20) +#define DVS_YUV_FORMAT_BT709 (1 << 18) +#define DVS_YUV_BYTE_ORDER_MASK (3 << 16) +#define DVS_YUV_ORDER_YUYV (0 << 16) +#define DVS_YUV_ORDER_UYVY (1 << 16) +#define DVS_YUV_ORDER_YVYU (2 << 16) +#define DVS_YUV_ORDER_VYUY (3 << 16) +#define DVS_ROTATE_180 (1 << 15) +#define DVS_DEST_KEY (1 << 2) +#define DVS_TRICKLE_FEED_DISABLE (1 << 14) +#define DVS_TILED (1 << 10) #define _DVSALINOFF 0x72184 #define _DVSASTRIDE 0x72188 #define _DVSAPOS 0x7218c @@ -6154,13 +6154,13 @@ enum { #define _DVSATILEOFF 0x721a4 #define _DVSASURFLIVE 0x721ac #define _DVSASCALE 0x72204 -#define DVS_SCALE_ENABLE (1<<31) -#define DVS_FILTER_MASK (3<<29) -#define DVS_FILTER_MEDIUM (0<<29) -#define DVS_FILTER_ENHANCING (1<<29) -#define DVS_FILTER_SOFTENING (2<<29) -#define DVS_VERTICAL_OFFSET_HALF (1<<28) /* must be enabled below */ -#define DVS_VERTICAL_OFFSET_ENABLE (1<<27) +#define DVS_SCALE_ENABLE (1 << 31) +#define DVS_FILTER_MASK (3 << 29) +#define DVS_FILTER_MEDIUM (0 << 29) +#define DVS_FILTER_ENHANCING (1 << 29) +#define DVS_FILTER_SOFTENING (2 << 29) +#define DVS_VERTICAL_OFFSET_HALF (1 << 28) /* must be enabled below */ +#define DVS_VERTICAL_OFFSET_ENABLE (1 << 27) #define _DVSAGAMC 0x72300 #define _DVSBCNTR 0x73180 @@ -6191,31 +6191,31 @@ enum { #define DVSSURFLIVE(pipe) _MMIO_PIPE(pipe, _DVSASURFLIVE, _DVSBSURFLIVE) #define _SPRA_CTL 0x70280 -#define SPRITE_ENABLE (1<<31) -#define SPRITE_GAMMA_ENABLE (1<<30) -#define SPRITE_YUV_RANGE_CORRECTION_DISABLE (1<<28) -#define SPRITE_PIXFORMAT_MASK (7<<25) -#define SPRITE_FORMAT_YUV422 (0<<25) -#define SPRITE_FORMAT_RGBX101010 (1<<25) -#define SPRITE_FORMAT_RGBX888 (2<<25) -#define SPRITE_FORMAT_RGBX161616 (3<<25) -#define SPRITE_FORMAT_YUV444 (4<<25) -#define SPRITE_FORMAT_XR_BGR101010 (5<<25) /* Extended range */ -#define SPRITE_PIPE_CSC_ENABLE (1<<24) -#define SPRITE_SOURCE_KEY (1<<22) -#define SPRITE_RGB_ORDER_RGBX (1<<20) /* only for 888 and 161616 */ -#define SPRITE_YUV_TO_RGB_CSC_DISABLE (1<<19) -#define SPRITE_YUV_TO_RGB_CSC_FORMAT_BT709 (1<<18) /* 0 is BT601 */ -#define SPRITE_YUV_BYTE_ORDER_MASK (3<<16) -#define SPRITE_YUV_ORDER_YUYV (0<<16) -#define SPRITE_YUV_ORDER_UYVY (1<<16) -#define SPRITE_YUV_ORDER_YVYU (2<<16) -#define SPRITE_YUV_ORDER_VYUY (3<<16) -#define SPRITE_ROTATE_180 (1<<15) -#define SPRITE_TRICKLE_FEED_DISABLE (1<<14) -#define SPRITE_INT_GAMMA_ENABLE (1<<13) -#define SPRITE_TILED (1<<10) -#define SPRITE_DEST_KEY (1<<2) +#define SPRITE_ENABLE (1 << 31) +#define SPRITE_GAMMA_ENABLE (1 << 30) +#define SPRITE_YUV_RANGE_CORRECTION_DISABLE (1 << 28) +#define SPRITE_PIXFORMAT_MASK (7 << 25) +#define SPRITE_FORMAT_YUV422 (0 << 25) +#define SPRITE_FORMAT_RGBX101010 (1 << 25) +#define SPRITE_FORMAT_RGBX888 (2 << 25) +#define SPRITE_FORMAT_RGBX161616 (3 << 25) +#define SPRITE_FORMAT_YUV444 (4 << 25) +#define SPRITE_FORMAT_XR_BGR101010 (5 << 25) /* Extended range */ +#define SPRITE_PIPE_CSC_ENABLE (1 << 24) +#define SPRITE_SOURCE_KEY (1 << 22) +#define SPRITE_RGB_ORDER_RGBX (1 << 20) /* only for 888 and 161616 */ +#define SPRITE_YUV_TO_RGB_CSC_DISABLE (1 << 19) +#define SPRITE_YUV_TO_RGB_CSC_FORMAT_BT709 (1 << 18) /* 0 is BT601 */ +#define SPRITE_YUV_BYTE_ORDER_MASK (3 << 16) +#define SPRITE_YUV_ORDER_YUYV (0 << 16) +#define SPRITE_YUV_ORDER_UYVY (1 << 16) +#define SPRITE_YUV_ORDER_YVYU (2 << 16) +#define SPRITE_YUV_ORDER_VYUY (3 << 16) +#define SPRITE_ROTATE_180 (1 << 15) +#define SPRITE_TRICKLE_FEED_DISABLE (1 << 14) +#define SPRITE_INT_GAMMA_ENABLE (1 << 13) +#define SPRITE_TILED (1 << 10) +#define SPRITE_DEST_KEY (1 << 2) #define _SPRA_LINOFF 0x70284 #define _SPRA_STRIDE 0x70288 #define _SPRA_POS 0x7028c @@ -6228,13 +6228,13 @@ enum { #define _SPRA_OFFSET 0x702a4 #define _SPRA_SURFLIVE 0x702ac #define _SPRA_SCALE 0x70304 -#define SPRITE_SCALE_ENABLE (1<<31) -#define SPRITE_FILTER_MASK (3<<29) -#define SPRITE_FILTER_MEDIUM (0<<29) -#define SPRITE_FILTER_ENHANCING (1<<29) -#define SPRITE_FILTER_SOFTENING (2<<29) -#define SPRITE_VERTICAL_OFFSET_HALF (1<<28) /* must be enabled below */ -#define SPRITE_VERTICAL_OFFSET_ENABLE (1<<27) +#define SPRITE_SCALE_ENABLE (1 << 31) +#define SPRITE_FILTER_MASK (3 << 29) +#define SPRITE_FILTER_MEDIUM (0 << 29) +#define SPRITE_FILTER_ENHANCING (1 << 29) +#define SPRITE_FILTER_SOFTENING (2 << 29) +#define SPRITE_VERTICAL_OFFSET_HALF (1 << 28) /* must be enabled below */ +#define SPRITE_VERTICAL_OFFSET_ENABLE (1 << 27) #define _SPRA_GAMC 0x70400 #define _SPRB_CTL 0x71280 @@ -6268,28 +6268,28 @@ enum { #define SPRSURFLIVE(pipe) _MMIO_PIPE(pipe, _SPRA_SURFLIVE, _SPRB_SURFLIVE) #define _SPACNTR (VLV_DISPLAY_BASE + 0x72180) -#define SP_ENABLE (1<<31) -#define SP_GAMMA_ENABLE (1<<30) -#define SP_PIXFORMAT_MASK (0xf<<26) -#define SP_FORMAT_YUV422 (0<<26) -#define SP_FORMAT_BGR565 (5<<26) -#define SP_FORMAT_BGRX8888 (6<<26) -#define SP_FORMAT_BGRA8888 (7<<26) -#define SP_FORMAT_RGBX1010102 (8<<26) -#define SP_FORMAT_RGBA1010102 (9<<26) -#define SP_FORMAT_RGBX8888 (0xe<<26) -#define SP_FORMAT_RGBA8888 (0xf<<26) -#define SP_ALPHA_PREMULTIPLY (1<<23) /* CHV pipe B */ -#define SP_SOURCE_KEY (1<<22) -#define SP_YUV_FORMAT_BT709 (1<<18) -#define SP_YUV_BYTE_ORDER_MASK (3<<16) -#define SP_YUV_ORDER_YUYV (0<<16) -#define SP_YUV_ORDER_UYVY (1<<16) -#define SP_YUV_ORDER_YVYU (2<<16) -#define SP_YUV_ORDER_VYUY (3<<16) -#define SP_ROTATE_180 (1<<15) -#define SP_TILED (1<<10) -#define SP_MIRROR (1<<8) /* CHV pipe B */ +#define SP_ENABLE (1 << 31) +#define SP_GAMMA_ENABLE (1 << 30) +#define SP_PIXFORMAT_MASK (0xf << 26) +#define SP_FORMAT_YUV422 (0 << 26) +#define SP_FORMAT_BGR565 (5 << 26) +#define SP_FORMAT_BGRX8888 (6 << 26) +#define SP_FORMAT_BGRA8888 (7 << 26) +#define SP_FORMAT_RGBX1010102 (8 << 26) +#define SP_FORMAT_RGBA1010102 (9 << 26) +#define SP_FORMAT_RGBX8888 (0xe << 26) +#define SP_FORMAT_RGBA8888 (0xf << 26) +#define SP_ALPHA_PREMULTIPLY (1 << 23) /* CHV pipe B */ +#define SP_SOURCE_KEY (1 << 22) +#define SP_YUV_FORMAT_BT709 (1 << 18) +#define SP_YUV_BYTE_ORDER_MASK (3 << 16) +#define SP_YUV_ORDER_YUYV (0 << 16) +#define SP_YUV_ORDER_UYVY (1 << 16) +#define SP_YUV_ORDER_YVYU (2 << 16) +#define SP_YUV_ORDER_VYUY (3 << 16) +#define SP_ROTATE_180 (1 << 15) +#define SP_TILED (1 << 10) +#define SP_MIRROR (1 << 8) /* CHV pipe B */ #define _SPALINOFF (VLV_DISPLAY_BASE + 0x72184) #define _SPASTRIDE (VLV_DISPLAY_BASE + 0x72188) #define _SPAPOS (VLV_DISPLAY_BASE + 0x7218c) @@ -6300,7 +6300,7 @@ enum { #define _SPAKEYMAXVAL (VLV_DISPLAY_BASE + 0x721a0) #define _SPATILEOFF (VLV_DISPLAY_BASE + 0x721a4) #define _SPACONSTALPHA (VLV_DISPLAY_BASE + 0x721a8) -#define SP_CONST_ALPHA_ENABLE (1<<31) +#define SP_CONST_ALPHA_ENABLE (1 << 31) #define _SPACLRC0 (VLV_DISPLAY_BASE + 0x721d0) #define SP_CONTRAST(x) ((x) << 18) /* u3.6 */ #define SP_BRIGHTNESS(x) ((x) & 0xff) /* s8 */ @@ -6392,40 +6392,40 @@ enum { * correctly map to the same formats in ICL, as long as bit 23 is set to 0 */ #define PLANE_CTL_FORMAT_MASK (0xf << 24) -#define PLANE_CTL_FORMAT_YUV422 ( 0 << 24) -#define PLANE_CTL_FORMAT_NV12 ( 1 << 24) -#define PLANE_CTL_FORMAT_XRGB_2101010 ( 2 << 24) -#define PLANE_CTL_FORMAT_XRGB_8888 ( 4 << 24) -#define PLANE_CTL_FORMAT_XRGB_16161616F ( 6 << 24) -#define PLANE_CTL_FORMAT_AYUV ( 8 << 24) -#define PLANE_CTL_FORMAT_INDEXED ( 12 << 24) -#define PLANE_CTL_FORMAT_RGB_565 ( 14 << 24) +#define PLANE_CTL_FORMAT_YUV422 (0 << 24) +#define PLANE_CTL_FORMAT_NV12 (1 << 24) +#define PLANE_CTL_FORMAT_XRGB_2101010 (2 << 24) +#define PLANE_CTL_FORMAT_XRGB_8888 (4 << 24) +#define PLANE_CTL_FORMAT_XRGB_16161616F (6 << 24) +#define PLANE_CTL_FORMAT_AYUV (8 << 24) +#define PLANE_CTL_FORMAT_INDEXED (12 << 24) +#define PLANE_CTL_FORMAT_RGB_565 (14 << 24) #define ICL_PLANE_CTL_FORMAT_MASK (0x1f << 23) #define PLANE_CTL_PIPE_CSC_ENABLE (1 << 23) /* Pre-GLK */ #define PLANE_CTL_KEY_ENABLE_MASK (0x3 << 21) -#define PLANE_CTL_KEY_ENABLE_SOURCE ( 1 << 21) -#define PLANE_CTL_KEY_ENABLE_DESTINATION ( 2 << 21) +#define PLANE_CTL_KEY_ENABLE_SOURCE (1 << 21) +#define PLANE_CTL_KEY_ENABLE_DESTINATION (2 << 21) #define PLANE_CTL_ORDER_BGRX (0 << 20) #define PLANE_CTL_ORDER_RGBX (1 << 20) #define PLANE_CTL_YUV_TO_RGB_CSC_FORMAT_BT709 (1 << 18) #define PLANE_CTL_YUV422_ORDER_MASK (0x3 << 16) -#define PLANE_CTL_YUV422_YUYV ( 0 << 16) -#define PLANE_CTL_YUV422_UYVY ( 1 << 16) -#define PLANE_CTL_YUV422_YVYU ( 2 << 16) -#define PLANE_CTL_YUV422_VYUY ( 3 << 16) +#define PLANE_CTL_YUV422_YUYV (0 << 16) +#define PLANE_CTL_YUV422_UYVY (1 << 16) +#define PLANE_CTL_YUV422_YVYU (2 << 16) +#define PLANE_CTL_YUV422_VYUY (3 << 16) #define PLANE_CTL_DECOMPRESSION_ENABLE (1 << 15) #define PLANE_CTL_TRICKLE_FEED_DISABLE (1 << 14) #define PLANE_CTL_PLANE_GAMMA_DISABLE (1 << 13) /* Pre-GLK */ #define PLANE_CTL_TILED_MASK (0x7 << 10) -#define PLANE_CTL_TILED_LINEAR ( 0 << 10) -#define PLANE_CTL_TILED_X ( 1 << 10) -#define PLANE_CTL_TILED_Y ( 4 << 10) -#define PLANE_CTL_TILED_YF ( 5 << 10) -#define PLANE_CTL_FLIP_HORIZONTAL ( 1 << 8) +#define PLANE_CTL_TILED_LINEAR (0 << 10) +#define PLANE_CTL_TILED_X (1 << 10) +#define PLANE_CTL_TILED_Y (4 << 10) +#define PLANE_CTL_TILED_YF (5 << 10) +#define PLANE_CTL_FLIP_HORIZONTAL (1 << 8) #define PLANE_CTL_ALPHA_MASK (0x3 << 4) /* Pre-GLK */ -#define PLANE_CTL_ALPHA_DISABLE ( 0 << 4) -#define PLANE_CTL_ALPHA_SW_PREMULTIPLY ( 2 << 4) -#define PLANE_CTL_ALPHA_HW_PREMULTIPLY ( 3 << 4) +#define PLANE_CTL_ALPHA_DISABLE (0 << 4) +#define PLANE_CTL_ALPHA_SW_PREMULTIPLY (2 << 4) +#define PLANE_CTL_ALPHA_HW_PREMULTIPLY (3 << 4) #define PLANE_CTL_ROTATE_MASK 0x3 #define PLANE_CTL_ROTATE_0 0x0 #define PLANE_CTL_ROTATE_90 0x1 @@ -6653,7 +6653,7 @@ enum { # define VFMUNIT_CLOCK_GATE_DISABLE (1 << 11) #define FDI_PLL_FREQ_CTL _MMIO(0x46030) -#define FDI_PLL_FREQ_CHANGE_REQUEST (1<<24) +#define FDI_PLL_FREQ_CHANGE_REQUEST (1 << 24) #define FDI_PLL_FREQ_LOCK_LIMIT_MASK 0xfff00 #define FDI_PLL_FREQ_DISABLE_COUNT_LIMIT_MASK 0xff @@ -6702,14 +6702,14 @@ enum { /* IVB+ has 3 fitters, 0 is 7x5 capable, the other two only 3x3 */ #define _PFA_CTL_1 0x68080 #define _PFB_CTL_1 0x68880 -#define PF_ENABLE (1<<31) -#define PF_PIPE_SEL_MASK_IVB (3<<29) -#define PF_PIPE_SEL_IVB(pipe) ((pipe)<<29) -#define PF_FILTER_MASK (3<<23) -#define PF_FILTER_PROGRAMMED (0<<23) -#define PF_FILTER_MED_3x3 (1<<23) -#define PF_FILTER_EDGE_ENHANCE (2<<23) -#define PF_FILTER_EDGE_SOFTEN (3<<23) +#define PF_ENABLE (1 << 31) +#define PF_PIPE_SEL_MASK_IVB (3 << 29) +#define PF_PIPE_SEL_IVB(pipe) ((pipe) << 29) +#define PF_FILTER_MASK (3 << 23) +#define PF_FILTER_PROGRAMMED (0 << 23) +#define PF_FILTER_MED_3x3 (1 << 23) +#define PF_FILTER_EDGE_ENHANCE (2 << 23) +#define PF_FILTER_EDGE_SOFTEN (3 << 23) #define _PFA_WIN_SZ 0x68074 #define _PFB_WIN_SZ 0x68874 #define _PFA_WIN_POS 0x68070 @@ -6727,7 +6727,7 @@ enum { #define _PSA_CTL 0x68180 #define _PSB_CTL 0x68980 -#define PS_ENABLE (1<<31) +#define PS_ENABLE (1 << 31) #define _PSA_WIN_SZ 0x68174 #define _PSB_WIN_SZ 0x68974 #define _PSA_WIN_POS 0x68170 @@ -6829,7 +6829,7 @@ enum { #define _PS_ECC_STAT_2B 0x68AD0 #define _PS_ECC_STAT_1C 0x691D0 -#define _ID(id, a, b) ((a) + (id)*((b)-(a))) +#define _ID(id, a, b) ((a) + (id) * ((b) - (a))) #define SKL_PS_CTRL(pipe, id) _MMIO_PIPE(pipe, \ _ID(id, _PS_1A_CTRL, _PS_2A_CTRL), \ _ID(id, _PS_1B_CTRL, _PS_2B_CTRL)) @@ -6910,37 +6910,37 @@ enum { #define DE_PIPEB_CRC_DONE (1 << 10) #define DE_PIPEB_FIFO_UNDERRUN (1 << 8) #define DE_PIPEA_VBLANK (1 << 7) -#define DE_PIPE_VBLANK(pipe) (1 << (7 + 8*(pipe))) +#define DE_PIPE_VBLANK(pipe) (1 << (7 + 8 * (pipe))) #define DE_PIPEA_EVEN_FIELD (1 << 6) #define DE_PIPEA_ODD_FIELD (1 << 5) #define DE_PIPEA_LINE_COMPARE (1 << 4) #define DE_PIPEA_VSYNC (1 << 3) #define DE_PIPEA_CRC_DONE (1 << 2) -#define DE_PIPE_CRC_DONE(pipe) (1 << (2 + 8*(pipe))) +#define DE_PIPE_CRC_DONE(pipe) (1 << (2 + 8 * (pipe))) #define DE_PIPEA_FIFO_UNDERRUN (1 << 0) -#define DE_PIPE_FIFO_UNDERRUN(pipe) (1 << (8*(pipe))) +#define DE_PIPE_FIFO_UNDERRUN(pipe) (1 << (8 * (pipe))) /* More Ivybridge lolz */ -#define DE_ERR_INT_IVB (1<<30) -#define DE_GSE_IVB (1<<29) -#define DE_PCH_EVENT_IVB (1<<28) -#define DE_DP_A_HOTPLUG_IVB (1<<27) -#define DE_AUX_CHANNEL_A_IVB (1<<26) -#define DE_EDP_PSR_INT_HSW (1<<19) -#define DE_SPRITEC_FLIP_DONE_IVB (1<<14) -#define DE_PLANEC_FLIP_DONE_IVB (1<<13) -#define DE_PIPEC_VBLANK_IVB (1<<10) -#define DE_SPRITEB_FLIP_DONE_IVB (1<<9) -#define DE_PLANEB_FLIP_DONE_IVB (1<<8) -#define DE_PIPEB_VBLANK_IVB (1<<5) -#define DE_SPRITEA_FLIP_DONE_IVB (1<<4) -#define DE_PLANEA_FLIP_DONE_IVB (1<<3) -#define DE_PLANE_FLIP_DONE_IVB(plane) (1<< (3 + 5*(plane))) -#define DE_PIPEA_VBLANK_IVB (1<<0) +#define DE_ERR_INT_IVB (1 << 30) +#define DE_GSE_IVB (1 << 29) +#define DE_PCH_EVENT_IVB (1 << 28) +#define DE_DP_A_HOTPLUG_IVB (1 << 27) +#define DE_AUX_CHANNEL_A_IVB (1 << 26) +#define DE_EDP_PSR_INT_HSW (1 << 19) +#define DE_SPRITEC_FLIP_DONE_IVB (1 << 14) +#define DE_PLANEC_FLIP_DONE_IVB (1 << 13) +#define DE_PIPEC_VBLANK_IVB (1 << 10) +#define DE_SPRITEB_FLIP_DONE_IVB (1 << 9) +#define DE_PLANEB_FLIP_DONE_IVB (1 << 8) +#define DE_PIPEB_VBLANK_IVB (1 << 5) +#define DE_SPRITEA_FLIP_DONE_IVB (1 << 4) +#define DE_PLANEA_FLIP_DONE_IVB (1 << 3) +#define DE_PLANE_FLIP_DONE_IVB(plane) (1 << (3 + 5 * (plane))) +#define DE_PIPEA_VBLANK_IVB (1 << 0) #define DE_PIPE_VBLANK_IVB(pipe) (1 << ((pipe) * 5)) #define VLV_MASTER_IER _MMIO(0x4400c) /* Gunit master IER */ -#define MASTER_INTERRUPT_ENABLE (1<<31) +#define MASTER_INTERRUPT_ENABLE (1 << 31) #define DEISR _MMIO(0x44000) #define DEIMR _MMIO(0x44004) @@ -6953,37 +6953,37 @@ enum { #define GTIER _MMIO(0x4401c) #define GEN8_MASTER_IRQ _MMIO(0x44200) -#define GEN8_MASTER_IRQ_CONTROL (1<<31) -#define GEN8_PCU_IRQ (1<<30) -#define GEN8_DE_PCH_IRQ (1<<23) -#define GEN8_DE_MISC_IRQ (1<<22) -#define GEN8_DE_PORT_IRQ (1<<20) -#define GEN8_DE_PIPE_C_IRQ (1<<18) -#define GEN8_DE_PIPE_B_IRQ (1<<17) -#define GEN8_DE_PIPE_A_IRQ (1<<16) -#define GEN8_DE_PIPE_IRQ(pipe) (1<<(16+(pipe))) -#define GEN8_GT_VECS_IRQ (1<<6) -#define GEN8_GT_GUC_IRQ (1<<5) -#define GEN8_GT_PM_IRQ (1<<4) -#define GEN8_GT_VCS2_IRQ (1<<3) -#define GEN8_GT_VCS1_IRQ (1<<2) -#define GEN8_GT_BCS_IRQ (1<<1) -#define GEN8_GT_RCS_IRQ (1<<0) +#define GEN8_MASTER_IRQ_CONTROL (1 << 31) +#define GEN8_PCU_IRQ (1 << 30) +#define GEN8_DE_PCH_IRQ (1 << 23) +#define GEN8_DE_MISC_IRQ (1 << 22) +#define GEN8_DE_PORT_IRQ (1 << 20) +#define GEN8_DE_PIPE_C_IRQ (1 << 18) +#define GEN8_DE_PIPE_B_IRQ (1 << 17) +#define GEN8_DE_PIPE_A_IRQ (1 << 16) +#define GEN8_DE_PIPE_IRQ(pipe) (1 << (16 + (pipe))) +#define GEN8_GT_VECS_IRQ (1 << 6) +#define GEN8_GT_GUC_IRQ (1 << 5) +#define GEN8_GT_PM_IRQ (1 << 4) +#define GEN8_GT_VCS2_IRQ (1 << 3) +#define GEN8_GT_VCS1_IRQ (1 << 2) +#define GEN8_GT_BCS_IRQ (1 << 1) +#define GEN8_GT_RCS_IRQ (1 << 0) #define GEN8_GT_ISR(which) _MMIO(0x44300 + (0x10 * (which))) #define GEN8_GT_IMR(which) _MMIO(0x44304 + (0x10 * (which))) #define GEN8_GT_IIR(which) _MMIO(0x44308 + (0x10 * (which))) #define GEN8_GT_IER(which) _MMIO(0x4430c + (0x10 * (which))) -#define GEN9_GUC_TO_HOST_INT_EVENT (1<<31) -#define GEN9_GUC_EXEC_ERROR_EVENT (1<<30) -#define GEN9_GUC_DISPLAY_EVENT (1<<29) -#define GEN9_GUC_SEMA_SIGNAL_EVENT (1<<28) -#define GEN9_GUC_IOMMU_MSG_EVENT (1<<27) -#define GEN9_GUC_DB_RING_EVENT (1<<26) -#define GEN9_GUC_DMA_DONE_EVENT (1<<25) -#define GEN9_GUC_FATAL_ERROR_EVENT (1<<24) -#define GEN9_GUC_NOTIFICATION_EVENT (1<<23) +#define GEN9_GUC_TO_HOST_INT_EVENT (1 << 31) +#define GEN9_GUC_EXEC_ERROR_EVENT (1 << 30) +#define GEN9_GUC_DISPLAY_EVENT (1 << 29) +#define GEN9_GUC_SEMA_SIGNAL_EVENT (1 << 28) +#define GEN9_GUC_IOMMU_MSG_EVENT (1 << 27) +#define GEN9_GUC_DB_RING_EVENT (1 << 26) +#define GEN9_GUC_DMA_DONE_EVENT (1 << 25) +#define GEN9_GUC_FATAL_ERROR_EVENT (1 << 24) +#define GEN9_GUC_NOTIFICATION_EVENT (1 << 23) #define GEN8_RCS_IRQ_SHIFT 0 #define GEN8_BCS_IRQ_SHIFT 16 @@ -7127,8 +7127,8 @@ enum { #define ILK_DISPLAY_CHICKEN2 _MMIO(0x42004) /* Required on all Ironlake and Sandybridge according to the B-Spec. */ #define ILK_ELPIN_409_SELECT (1 << 25) -#define ILK_DPARB_GATE (1<<22) -#define ILK_VSDPFD_FULL (1<<21) +#define ILK_DPARB_GATE (1 << 22) +#define ILK_VSDPFD_FULL (1 << 21) #define FUSE_STRAP _MMIO(0x42014) #define ILK_INTERNAL_GRAPHICS_DISABLE (1 << 31) #define ILK_INTERNAL_DISPLAY_DISABLE (1 << 30) @@ -7178,31 +7178,31 @@ enum { #define CHICKEN_TRANS_A 0x420c0 #define CHICKEN_TRANS_B 0x420c4 #define CHICKEN_TRANS(trans) _MMIO_TRANS(trans, CHICKEN_TRANS_A, CHICKEN_TRANS_B) -#define VSC_DATA_SEL_SOFTWARE_CONTROL (1<<25) /* GLK and CNL+ */ -#define DDI_TRAINING_OVERRIDE_ENABLE (1<<19) -#define DDI_TRAINING_OVERRIDE_VALUE (1<<18) -#define DDIE_TRAINING_OVERRIDE_ENABLE (1<<17) /* CHICKEN_TRANS_A only */ -#define DDIE_TRAINING_OVERRIDE_VALUE (1<<16) /* CHICKEN_TRANS_A only */ -#define PSR2_ADD_VERTICAL_LINE_COUNT (1<<15) -#define PSR2_VSC_ENABLE_PROG_HEADER (1<<12) +#define VSC_DATA_SEL_SOFTWARE_CONTROL (1 << 25) /* GLK and CNL+ */ +#define DDI_TRAINING_OVERRIDE_ENABLE (1 << 19) +#define DDI_TRAINING_OVERRIDE_VALUE (1 << 18) +#define DDIE_TRAINING_OVERRIDE_ENABLE (1 << 17) /* CHICKEN_TRANS_A only */ +#define DDIE_TRAINING_OVERRIDE_VALUE (1 << 16) /* CHICKEN_TRANS_A only */ +#define PSR2_ADD_VERTICAL_LINE_COUNT (1 << 15) +#define PSR2_VSC_ENABLE_PROG_HEADER (1 << 12) #define DISP_ARB_CTL _MMIO(0x45000) -#define DISP_FBC_MEMORY_WAKE (1<<31) -#define DISP_TILE_SURFACE_SWIZZLING (1<<13) -#define DISP_FBC_WM_DIS (1<<15) +#define DISP_FBC_MEMORY_WAKE (1 << 31) +#define DISP_TILE_SURFACE_SWIZZLING (1 << 13) +#define DISP_FBC_WM_DIS (1 << 15) #define DISP_ARB_CTL2 _MMIO(0x45004) -#define DISP_DATA_PARTITION_5_6 (1<<6) -#define DISP_IPC_ENABLE (1<<3) +#define DISP_DATA_PARTITION_5_6 (1 << 6) +#define DISP_IPC_ENABLE (1 << 3) #define DBUF_CTL _MMIO(0x45008) #define DBUF_CTL_S1 _MMIO(0x45008) #define DBUF_CTL_S2 _MMIO(0x44FE8) -#define DBUF_POWER_REQUEST (1<<31) -#define DBUF_POWER_STATE (1<<30) +#define DBUF_POWER_REQUEST (1 << 31) +#define DBUF_POWER_STATE (1 << 30) #define GEN7_MSG_CTL _MMIO(0x45010) -#define WAIT_FOR_PCH_RESET_ACK (1<<1) -#define WAIT_FOR_PCH_FLR_ACK (1<<0) +#define WAIT_FOR_PCH_RESET_ACK (1 << 1) +#define WAIT_FOR_PCH_FLR_ACK (1 << 0) #define HSW_NDE_RSTWRN_OPT _MMIO(0x46408) -#define RESET_PCH_HANDSHAKE_ENABLE (1<<4) +#define RESET_PCH_HANDSHAKE_ENABLE (1 << 4) #define GEN8_CHICKEN_DCPR_1 _MMIO(0x46430) #define SKL_SELECT_ALTERNATE_DC_EXIT (1 << 30) @@ -7227,16 +7227,16 @@ enum { #define ICL_DSSM_CDCLK_PLL_REFCLK_38_4MHz (2 << 29) #define GEN7_FF_SLICE_CS_CHICKEN1 _MMIO(0x20e0) -#define GEN9_FFSC_PERCTX_PREEMPT_CTRL (1<<14) +#define GEN9_FFSC_PERCTX_PREEMPT_CTRL (1 << 14) #define FF_SLICE_CS_CHICKEN2 _MMIO(0x20e4) -#define GEN9_TSG_BARRIER_ACK_DISABLE (1<<8) -#define GEN9_POOLED_EU_LOAD_BALANCING_FIX_DISABLE (1<<10) +#define GEN9_TSG_BARRIER_ACK_DISABLE (1 << 8) +#define GEN9_POOLED_EU_LOAD_BALANCING_FIX_DISABLE (1 << 10) #define GEN9_CS_DEBUG_MODE1 _MMIO(0x20ec) #define GEN9_CTX_PREEMPT_REG _MMIO(0x2248) #define GEN8_CS_CHICKEN1 _MMIO(0x2580) -#define GEN9_PREEMPT_3D_OBJECT_LEVEL (1<<0) +#define GEN9_PREEMPT_3D_OBJECT_LEVEL (1 << 0) #define GEN9_PREEMPT_GPGPU_LEVEL(hi, lo) (((hi) << 2) | ((lo) << 1)) #define GEN9_PREEMPT_GPGPU_MID_THREAD_LEVEL GEN9_PREEMPT_GPGPU_LEVEL(0, 0) #define GEN9_PREEMPT_GPGPU_THREAD_GROUP_LEVEL GEN9_PREEMPT_GPGPU_LEVEL(0, 1) @@ -7258,11 +7258,11 @@ enum { #define GEN11_BLEND_EMB_FIX_DISABLE_IN_RCC (1 << 11) #define HIZ_CHICKEN _MMIO(0x7018) -# define CHV_HZ_8X8_MODE_IN_1X (1<<15) -# define BDW_HIZ_POWER_COMPILER_CLOCK_GATING_DISABLE (1<<3) +# define CHV_HZ_8X8_MODE_IN_1X (1 << 15) +# define BDW_HIZ_POWER_COMPILER_CLOCK_GATING_DISABLE (1 << 3) #define GEN9_SLICE_COMMON_ECO_CHICKEN0 _MMIO(0x7308) -#define DISABLE_PIXEL_MASK_CAMMING (1<<14) +#define DISABLE_PIXEL_MASK_CAMMING (1 << 14) #define GEN9_SLICE_COMMON_ECO_CHICKEN1 _MMIO(0x731c) #define GEN11_STATE_CACHE_REDIRECT_TO_CS (1 << 11) @@ -7283,7 +7283,7 @@ enum { #define GEN7_L3CNTLREG1 _MMIO(0xB01C) #define GEN7_WA_FOR_GEN7_L3_CONTROL 0x3C47FF8C -#define GEN7_L3AGDIS (1<<19) +#define GEN7_L3AGDIS (1 << 19) #define GEN7_L3CNTLREG2 _MMIO(0xB020) #define GEN7_L3CNTLREG3 _MMIO(0xB024) @@ -7293,7 +7293,7 @@ enum { #define GEN11_I2M_WRITE_DISABLE (1 << 28) #define GEN7_L3SQCREG4 _MMIO(0xb034) -#define L3SQ_URB_READ_CAM_MATCH_DISABLE (1<<27) +#define L3SQ_URB_READ_CAM_MATCH_DISABLE (1 << 27) #define GEN8_L3SQCREG4 _MMIO(0xb118) #define GEN11_LQSC_CLEAN_EVICT_DISABLE (1 << 6) @@ -7304,12 +7304,12 @@ enum { #define HDC_CHICKEN0 _MMIO(0x7300) #define CNL_HDC_CHICKEN0 _MMIO(0xE5F0) #define ICL_HDC_MODE _MMIO(0xE5F4) -#define HDC_FORCE_CSR_NON_COHERENT_OVR_DISABLE (1<<15) -#define HDC_FENCE_DEST_SLM_DISABLE (1<<14) -#define HDC_DONOT_FETCH_MEM_WHEN_MASKED (1<<11) -#define HDC_FORCE_CONTEXT_SAVE_RESTORE_NON_COHERENT (1<<5) -#define HDC_FORCE_NON_COHERENT (1<<4) -#define HDC_BARRIER_PERFORMANCE_DISABLE (1<<10) +#define HDC_FORCE_CSR_NON_COHERENT_OVR_DISABLE (1 << 15) +#define HDC_FENCE_DEST_SLM_DISABLE (1 << 14) +#define HDC_DONOT_FETCH_MEM_WHEN_MASKED (1 << 11) +#define HDC_FORCE_CONTEXT_SAVE_RESTORE_NON_COHERENT (1 << 5) +#define HDC_FORCE_NON_COHERENT (1 << 4) +#define HDC_BARRIER_PERFORMANCE_DISABLE (1 << 10) #define GEN8_HDC_CHICKEN1 _MMIO(0x7304) @@ -7322,13 +7322,13 @@ enum { /* WaCatErrorRejectionIssue */ #define GEN7_SQ_CHICKEN_MBCUNIT_CONFIG _MMIO(0x9030) -#define GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB (1<<11) +#define GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB (1 << 11) #define HSW_SCRATCH1 _MMIO(0xb038) -#define HSW_SCRATCH1_L3_DATA_ATOMICS_DISABLE (1<<27) +#define HSW_SCRATCH1_L3_DATA_ATOMICS_DISABLE (1 << 27) #define BDW_SCRATCH1 _MMIO(0xb11c) -#define GEN9_LBS_SLA_RETRY_TIMER_DECREMENT_ENABLE (1<<2) +#define GEN9_LBS_SLA_RETRY_TIMER_DECREMENT_ENABLE (1 << 2) /* PCH */ @@ -7427,8 +7427,8 @@ enum { #define SDEIER _MMIO(0xc400c) #define SERR_INT _MMIO(0xc4040) -#define SERR_INT_POISON (1<<31) -#define SERR_INT_TRANS_FIFO_UNDERRUN(pipe) (1<<((pipe)*3)) +#define SERR_INT_POISON (1 << 31) +#define SERR_INT_TRANS_FIFO_UNDERRUN(pipe) (1 << ((pipe) * 3)) /* digital port hotplug */ #define PCH_PORT_HOTPLUG _MMIO(0xc4030) /* SHOTPLUG_CTL */ @@ -7500,7 +7500,7 @@ enum { #define PCH_DPLL(pll) _MMIO(pll == 0 ? _PCH_DPLL_A : _PCH_DPLL_B) #define _PCH_FPA0 0xc6040 -#define FP_CB_TUNE (0x3<<22) +#define FP_CB_TUNE (0x3 << 22) #define _PCH_FPA1 0xc6044 #define _PCH_FPB0 0xc6048 #define _PCH_FPB1 0xc604c @@ -7511,32 +7511,32 @@ enum { #define PCH_DREF_CONTROL _MMIO(0xC6200) #define DREF_CONTROL_MASK 0x7fc3 -#define DREF_CPU_SOURCE_OUTPUT_DISABLE (0<<13) -#define DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD (2<<13) -#define DREF_CPU_SOURCE_OUTPUT_NONSPREAD (3<<13) -#define DREF_CPU_SOURCE_OUTPUT_MASK (3<<13) -#define DREF_SSC_SOURCE_DISABLE (0<<11) -#define DREF_SSC_SOURCE_ENABLE (2<<11) -#define DREF_SSC_SOURCE_MASK (3<<11) -#define DREF_NONSPREAD_SOURCE_DISABLE (0<<9) -#define DREF_NONSPREAD_CK505_ENABLE (1<<9) -#define DREF_NONSPREAD_SOURCE_ENABLE (2<<9) -#define DREF_NONSPREAD_SOURCE_MASK (3<<9) -#define DREF_SUPERSPREAD_SOURCE_DISABLE (0<<7) -#define DREF_SUPERSPREAD_SOURCE_ENABLE (2<<7) -#define DREF_SUPERSPREAD_SOURCE_MASK (3<<7) -#define DREF_SSC4_DOWNSPREAD (0<<6) -#define DREF_SSC4_CENTERSPREAD (1<<6) -#define DREF_SSC1_DISABLE (0<<1) -#define DREF_SSC1_ENABLE (1<<1) +#define DREF_CPU_SOURCE_OUTPUT_DISABLE (0 << 13) +#define DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD (2 << 13) +#define DREF_CPU_SOURCE_OUTPUT_NONSPREAD (3 << 13) +#define DREF_CPU_SOURCE_OUTPUT_MASK (3 << 13) +#define DREF_SSC_SOURCE_DISABLE (0 << 11) +#define DREF_SSC_SOURCE_ENABLE (2 << 11) +#define DREF_SSC_SOURCE_MASK (3 << 11) +#define DREF_NONSPREAD_SOURCE_DISABLE (0 << 9) +#define DREF_NONSPREAD_CK505_ENABLE (1 << 9) +#define DREF_NONSPREAD_SOURCE_ENABLE (2 << 9) +#define DREF_NONSPREAD_SOURCE_MASK (3 << 9) +#define DREF_SUPERSPREAD_SOURCE_DISABLE (0 << 7) +#define DREF_SUPERSPREAD_SOURCE_ENABLE (2 << 7) +#define DREF_SUPERSPREAD_SOURCE_MASK (3 << 7) +#define DREF_SSC4_DOWNSPREAD (0 << 6) +#define DREF_SSC4_CENTERSPREAD (1 << 6) +#define DREF_SSC1_DISABLE (0 << 1) +#define DREF_SSC1_ENABLE (1 << 1) #define DREF_SSC4_DISABLE (0) #define DREF_SSC4_ENABLE (1) #define PCH_RAWCLK_FREQ _MMIO(0xc6204) #define FDL_TP1_TIMER_SHIFT 12 -#define FDL_TP1_TIMER_MASK (3<<12) +#define FDL_TP1_TIMER_MASK (3 << 12) #define FDL_TP2_TIMER_SHIFT 10 -#define FDL_TP2_TIMER_MASK (3<<10) +#define FDL_TP2_TIMER_MASK (3 << 10) #define RAWCLK_FREQ_MASK 0x3ff #define CNP_RAWCLK_DIV_MASK (0x3ff << 16) #define CNP_RAWCLK_DIV(div) ((div) << 16) @@ -7661,7 +7661,7 @@ enum { #define HSW_TVIDEO_DIP_VSC_DATA(trans, i) _MMIO_TRANS2(trans, _HSW_VIDEO_DIP_VSC_DATA_A + (i) * 4) #define _HSW_STEREO_3D_CTL_A 0x70020 -#define S3D_ENABLE (1<<31) +#define S3D_ENABLE (1 << 31) #define _HSW_STEREO_3D_CTL_B 0x71020 #define HSW_STEREO_3D_CTL(trans) _MMIO_PIPE2(trans, _HSW_STEREO_3D_CTL_A) @@ -7704,156 +7704,156 @@ enum { #define _PCH_TRANSBCONF 0xf1008 #define PCH_TRANSCONF(pipe) _MMIO_PIPE(pipe, _PCH_TRANSACONF, _PCH_TRANSBCONF) #define LPT_TRANSCONF PCH_TRANSCONF(PIPE_A) /* lpt has only one transcoder */ -#define TRANS_DISABLE (0<<31) -#define TRANS_ENABLE (1<<31) -#define TRANS_STATE_MASK (1<<30) -#define TRANS_STATE_DISABLE (0<<30) -#define TRANS_STATE_ENABLE (1<<30) -#define TRANS_FSYNC_DELAY_HB1 (0<<27) -#define TRANS_FSYNC_DELAY_HB2 (1<<27) -#define TRANS_FSYNC_DELAY_HB3 (2<<27) -#define TRANS_FSYNC_DELAY_HB4 (3<<27) -#define TRANS_INTERLACE_MASK (7<<21) -#define TRANS_PROGRESSIVE (0<<21) -#define TRANS_INTERLACED (3<<21) -#define TRANS_LEGACY_INTERLACED_ILK (2<<21) -#define TRANS_8BPC (0<<5) -#define TRANS_10BPC (1<<5) -#define TRANS_6BPC (2<<5) -#define TRANS_12BPC (3<<5) +#define TRANS_DISABLE (0 << 31) +#define TRANS_ENABLE (1 << 31) +#define TRANS_STATE_MASK (1 << 30) +#define TRANS_STATE_DISABLE (0 << 30) +#define TRANS_STATE_ENABLE (1 << 30) +#define TRANS_FSYNC_DELAY_HB1 (0 << 27) +#define TRANS_FSYNC_DELAY_HB2 (1 << 27) +#define TRANS_FSYNC_DELAY_HB3 (2 << 27) +#define TRANS_FSYNC_DELAY_HB4 (3 << 27) +#define TRANS_INTERLACE_MASK (7 << 21) +#define TRANS_PROGRESSIVE (0 << 21) +#define TRANS_INTERLACED (3 << 21) +#define TRANS_LEGACY_INTERLACED_ILK (2 << 21) +#define TRANS_8BPC (0 << 5) +#define TRANS_10BPC (1 << 5) +#define TRANS_6BPC (2 << 5) +#define TRANS_12BPC (3 << 5) #define _TRANSA_CHICKEN1 0xf0060 #define _TRANSB_CHICKEN1 0xf1060 #define TRANS_CHICKEN1(pipe) _MMIO_PIPE(pipe, _TRANSA_CHICKEN1, _TRANSB_CHICKEN1) -#define TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE (1<<10) -#define TRANS_CHICKEN1_DP0UNIT_GC_DISABLE (1<<4) +#define TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE (1 << 10) +#define TRANS_CHICKEN1_DP0UNIT_GC_DISABLE (1 << 4) #define _TRANSA_CHICKEN2 0xf0064 #define _TRANSB_CHICKEN2 0xf1064 #define TRANS_CHICKEN2(pipe) _MMIO_PIPE(pipe, _TRANSA_CHICKEN2, _TRANSB_CHICKEN2) -#define TRANS_CHICKEN2_TIMING_OVERRIDE (1<<31) -#define TRANS_CHICKEN2_FDI_POLARITY_REVERSED (1<<29) -#define TRANS_CHICKEN2_FRAME_START_DELAY_MASK (3<<27) -#define TRANS_CHICKEN2_DISABLE_DEEP_COLOR_COUNTER (1<<26) -#define TRANS_CHICKEN2_DISABLE_DEEP_COLOR_MODESWITCH (1<<25) +#define TRANS_CHICKEN2_TIMING_OVERRIDE (1 << 31) +#define TRANS_CHICKEN2_FDI_POLARITY_REVERSED (1 << 29) +#define TRANS_CHICKEN2_FRAME_START_DELAY_MASK (3 << 27) +#define TRANS_CHICKEN2_DISABLE_DEEP_COLOR_COUNTER (1 << 26) +#define TRANS_CHICKEN2_DISABLE_DEEP_COLOR_MODESWITCH (1 << 25) #define SOUTH_CHICKEN1 _MMIO(0xc2000) #define FDIA_PHASE_SYNC_SHIFT_OVR 19 #define FDIA_PHASE_SYNC_SHIFT_EN 18 -#define FDI_PHASE_SYNC_OVR(pipe) (1<<(FDIA_PHASE_SYNC_SHIFT_OVR - ((pipe) * 2))) -#define FDI_PHASE_SYNC_EN(pipe) (1<<(FDIA_PHASE_SYNC_SHIFT_EN - ((pipe) * 2))) +#define FDI_PHASE_SYNC_OVR(pipe) (1 << (FDIA_PHASE_SYNC_SHIFT_OVR - ((pipe) * 2))) +#define FDI_PHASE_SYNC_EN(pipe) (1 << (FDIA_PHASE_SYNC_SHIFT_EN - ((pipe) * 2))) #define FDI_BC_BIFURCATION_SELECT (1 << 12) #define CHASSIS_CLK_REQ_DURATION_MASK (0xf << 8) #define CHASSIS_CLK_REQ_DURATION(x) ((x) << 8) -#define SPT_PWM_GRANULARITY (1<<0) +#define SPT_PWM_GRANULARITY (1 << 0) #define SOUTH_CHICKEN2 _MMIO(0xc2004) -#define FDI_MPHY_IOSFSB_RESET_STATUS (1<<13) -#define FDI_MPHY_IOSFSB_RESET_CTL (1<<12) -#define LPT_PWM_GRANULARITY (1<<5) -#define DPLS_EDP_PPS_FIX_DIS (1<<0) +#define FDI_MPHY_IOSFSB_RESET_STATUS (1 << 13) +#define FDI_MPHY_IOSFSB_RESET_CTL (1 << 12) +#define LPT_PWM_GRANULARITY (1 << 5) +#define DPLS_EDP_PPS_FIX_DIS (1 << 0) #define _FDI_RXA_CHICKEN 0xc200c #define _FDI_RXB_CHICKEN 0xc2010 -#define FDI_RX_PHASE_SYNC_POINTER_OVR (1<<1) -#define FDI_RX_PHASE_SYNC_POINTER_EN (1<<0) +#define FDI_RX_PHASE_SYNC_POINTER_OVR (1 << 1) +#define FDI_RX_PHASE_SYNC_POINTER_EN (1 << 0) #define FDI_RX_CHICKEN(pipe) _MMIO_PIPE(pipe, _FDI_RXA_CHICKEN, _FDI_RXB_CHICKEN) #define SOUTH_DSPCLK_GATE_D _MMIO(0xc2020) -#define PCH_GMBUSUNIT_CLOCK_GATE_DISABLE (1<<31) -#define PCH_DPLUNIT_CLOCK_GATE_DISABLE (1<<30) -#define PCH_DPLSUNIT_CLOCK_GATE_DISABLE (1<<29) -#define PCH_CPUNIT_CLOCK_GATE_DISABLE (1<<14) -#define CNP_PWM_CGE_GATING_DISABLE (1<<13) -#define PCH_LP_PARTITION_LEVEL_DISABLE (1<<12) +#define PCH_GMBUSUNIT_CLOCK_GATE_DISABLE (1 << 31) +#define PCH_DPLUNIT_CLOCK_GATE_DISABLE (1 << 30) +#define PCH_DPLSUNIT_CLOCK_GATE_DISABLE (1 << 29) +#define PCH_CPUNIT_CLOCK_GATE_DISABLE (1 << 14) +#define CNP_PWM_CGE_GATING_DISABLE (1 << 13) +#define PCH_LP_PARTITION_LEVEL_DISABLE (1 << 12) /* CPU: FDI_TX */ #define _FDI_TXA_CTL 0x60100 #define _FDI_TXB_CTL 0x61100 #define FDI_TX_CTL(pipe) _MMIO_PIPE(pipe, _FDI_TXA_CTL, _FDI_TXB_CTL) -#define FDI_TX_DISABLE (0<<31) -#define FDI_TX_ENABLE (1<<31) -#define FDI_LINK_TRAIN_PATTERN_1 (0<<28) -#define FDI_LINK_TRAIN_PATTERN_2 (1<<28) -#define FDI_LINK_TRAIN_PATTERN_IDLE (2<<28) -#define FDI_LINK_TRAIN_NONE (3<<28) -#define FDI_LINK_TRAIN_VOLTAGE_0_4V (0<<25) -#define FDI_LINK_TRAIN_VOLTAGE_0_6V (1<<25) -#define FDI_LINK_TRAIN_VOLTAGE_0_8V (2<<25) -#define FDI_LINK_TRAIN_VOLTAGE_1_2V (3<<25) -#define FDI_LINK_TRAIN_PRE_EMPHASIS_NONE (0<<22) -#define FDI_LINK_TRAIN_PRE_EMPHASIS_1_5X (1<<22) -#define FDI_LINK_TRAIN_PRE_EMPHASIS_2X (2<<22) -#define FDI_LINK_TRAIN_PRE_EMPHASIS_3X (3<<22) +#define FDI_TX_DISABLE (0 << 31) +#define FDI_TX_ENABLE (1 << 31) +#define FDI_LINK_TRAIN_PATTERN_1 (0 << 28) +#define FDI_LINK_TRAIN_PATTERN_2 (1 << 28) +#define FDI_LINK_TRAIN_PATTERN_IDLE (2 << 28) +#define FDI_LINK_TRAIN_NONE (3 << 28) +#define FDI_LINK_TRAIN_VOLTAGE_0_4V (0 << 25) +#define FDI_LINK_TRAIN_VOLTAGE_0_6V (1 << 25) +#define FDI_LINK_TRAIN_VOLTAGE_0_8V (2 << 25) +#define FDI_LINK_TRAIN_VOLTAGE_1_2V (3 << 25) +#define FDI_LINK_TRAIN_PRE_EMPHASIS_NONE (0 << 22) +#define FDI_LINK_TRAIN_PRE_EMPHASIS_1_5X (1 << 22) +#define FDI_LINK_TRAIN_PRE_EMPHASIS_2X (2 << 22) +#define FDI_LINK_TRAIN_PRE_EMPHASIS_3X (3 << 22) /* ILK always use 400mV 0dB for voltage swing and pre-emphasis level. SNB has different settings. */ /* SNB A-stepping */ -#define FDI_LINK_TRAIN_400MV_0DB_SNB_A (0x38<<22) -#define FDI_LINK_TRAIN_400MV_6DB_SNB_A (0x02<<22) -#define FDI_LINK_TRAIN_600MV_3_5DB_SNB_A (0x01<<22) -#define FDI_LINK_TRAIN_800MV_0DB_SNB_A (0x0<<22) +#define FDI_LINK_TRAIN_400MV_0DB_SNB_A (0x38 << 22) +#define FDI_LINK_TRAIN_400MV_6DB_SNB_A (0x02 << 22) +#define FDI_LINK_TRAIN_600MV_3_5DB_SNB_A (0x01 << 22) +#define FDI_LINK_TRAIN_800MV_0DB_SNB_A (0x0 << 22) /* SNB B-stepping */ -#define FDI_LINK_TRAIN_400MV_0DB_SNB_B (0x0<<22) -#define FDI_LINK_TRAIN_400MV_6DB_SNB_B (0x3a<<22) -#define FDI_LINK_TRAIN_600MV_3_5DB_SNB_B (0x39<<22) -#define FDI_LINK_TRAIN_800MV_0DB_SNB_B (0x38<<22) -#define FDI_LINK_TRAIN_VOL_EMP_MASK (0x3f<<22) +#define FDI_LINK_TRAIN_400MV_0DB_SNB_B (0x0 << 22) +#define FDI_LINK_TRAIN_400MV_6DB_SNB_B (0x3a << 22) +#define FDI_LINK_TRAIN_600MV_3_5DB_SNB_B (0x39 << 22) +#define FDI_LINK_TRAIN_800MV_0DB_SNB_B (0x38 << 22) +#define FDI_LINK_TRAIN_VOL_EMP_MASK (0x3f << 22) #define FDI_DP_PORT_WIDTH_SHIFT 19 #define FDI_DP_PORT_WIDTH_MASK (7 << FDI_DP_PORT_WIDTH_SHIFT) #define FDI_DP_PORT_WIDTH(width) (((width) - 1) << FDI_DP_PORT_WIDTH_SHIFT) -#define FDI_TX_ENHANCE_FRAME_ENABLE (1<<18) +#define FDI_TX_ENHANCE_FRAME_ENABLE (1 << 18) /* Ironlake: hardwired to 1 */ -#define FDI_TX_PLL_ENABLE (1<<14) +#define FDI_TX_PLL_ENABLE (1 << 14) /* Ivybridge has different bits for lolz */ -#define FDI_LINK_TRAIN_PATTERN_1_IVB (0<<8) -#define FDI_LINK_TRAIN_PATTERN_2_IVB (1<<8) -#define FDI_LINK_TRAIN_PATTERN_IDLE_IVB (2<<8) -#define FDI_LINK_TRAIN_NONE_IVB (3<<8) +#define FDI_LINK_TRAIN_PATTERN_1_IVB (0 << 8) +#define FDI_LINK_TRAIN_PATTERN_2_IVB (1 << 8) +#define FDI_LINK_TRAIN_PATTERN_IDLE_IVB (2 << 8) +#define FDI_LINK_TRAIN_NONE_IVB (3 << 8) /* both Tx and Rx */ -#define FDI_COMPOSITE_SYNC (1<<11) -#define FDI_LINK_TRAIN_AUTO (1<<10) -#define FDI_SCRAMBLING_ENABLE (0<<7) -#define FDI_SCRAMBLING_DISABLE (1<<7) +#define FDI_COMPOSITE_SYNC (1 << 11) +#define FDI_LINK_TRAIN_AUTO (1 << 10) +#define FDI_SCRAMBLING_ENABLE (0 << 7) +#define FDI_SCRAMBLING_DISABLE (1 << 7) /* FDI_RX, FDI_X is hard-wired to Transcoder_X */ #define _FDI_RXA_CTL 0xf000c #define _FDI_RXB_CTL 0xf100c #define FDI_RX_CTL(pipe) _MMIO_PIPE(pipe, _FDI_RXA_CTL, _FDI_RXB_CTL) -#define FDI_RX_ENABLE (1<<31) +#define FDI_RX_ENABLE (1 << 31) /* train, dp width same as FDI_TX */ -#define FDI_FS_ERRC_ENABLE (1<<27) -#define FDI_FE_ERRC_ENABLE (1<<26) -#define FDI_RX_POLARITY_REVERSED_LPT (1<<16) -#define FDI_8BPC (0<<16) -#define FDI_10BPC (1<<16) -#define FDI_6BPC (2<<16) -#define FDI_12BPC (3<<16) -#define FDI_RX_LINK_REVERSAL_OVERRIDE (1<<15) -#define FDI_DMI_LINK_REVERSE_MASK (1<<14) -#define FDI_RX_PLL_ENABLE (1<<13) -#define FDI_FS_ERR_CORRECT_ENABLE (1<<11) -#define FDI_FE_ERR_CORRECT_ENABLE (1<<10) -#define FDI_FS_ERR_REPORT_ENABLE (1<<9) -#define FDI_FE_ERR_REPORT_ENABLE (1<<8) -#define FDI_RX_ENHANCE_FRAME_ENABLE (1<<6) -#define FDI_PCDCLK (1<<4) +#define FDI_FS_ERRC_ENABLE (1 << 27) +#define FDI_FE_ERRC_ENABLE (1 << 26) +#define FDI_RX_POLARITY_REVERSED_LPT (1 << 16) +#define FDI_8BPC (0 << 16) +#define FDI_10BPC (1 << 16) +#define FDI_6BPC (2 << 16) +#define FDI_12BPC (3 << 16) +#define FDI_RX_LINK_REVERSAL_OVERRIDE (1 << 15) +#define FDI_DMI_LINK_REVERSE_MASK (1 << 14) +#define FDI_RX_PLL_ENABLE (1 << 13) +#define FDI_FS_ERR_CORRECT_ENABLE (1 << 11) +#define FDI_FE_ERR_CORRECT_ENABLE (1 << 10) +#define FDI_FS_ERR_REPORT_ENABLE (1 << 9) +#define FDI_FE_ERR_REPORT_ENABLE (1 << 8) +#define FDI_RX_ENHANCE_FRAME_ENABLE (1 << 6) +#define FDI_PCDCLK (1 << 4) /* CPT */ -#define FDI_AUTO_TRAINING (1<<10) -#define FDI_LINK_TRAIN_PATTERN_1_CPT (0<<8) -#define FDI_LINK_TRAIN_PATTERN_2_CPT (1<<8) -#define FDI_LINK_TRAIN_PATTERN_IDLE_CPT (2<<8) -#define FDI_LINK_TRAIN_NORMAL_CPT (3<<8) -#define FDI_LINK_TRAIN_PATTERN_MASK_CPT (3<<8) +#define FDI_AUTO_TRAINING (1 << 10) +#define FDI_LINK_TRAIN_PATTERN_1_CPT (0 << 8) +#define FDI_LINK_TRAIN_PATTERN_2_CPT (1 << 8) +#define FDI_LINK_TRAIN_PATTERN_IDLE_CPT (2 << 8) +#define FDI_LINK_TRAIN_NORMAL_CPT (3 << 8) +#define FDI_LINK_TRAIN_PATTERN_MASK_CPT (3 << 8) #define _FDI_RXA_MISC 0xf0010 #define _FDI_RXB_MISC 0xf1010 -#define FDI_RX_PWRDN_LANE1_MASK (3<<26) -#define FDI_RX_PWRDN_LANE1_VAL(x) ((x)<<26) -#define FDI_RX_PWRDN_LANE0_MASK (3<<24) -#define FDI_RX_PWRDN_LANE0_VAL(x) ((x)<<24) -#define FDI_RX_TP1_TO_TP2_48 (2<<20) -#define FDI_RX_TP1_TO_TP2_64 (3<<20) -#define FDI_RX_FDI_DELAY_90 (0x90<<0) +#define FDI_RX_PWRDN_LANE1_MASK (3 << 26) +#define FDI_RX_PWRDN_LANE1_VAL(x) ((x) << 26) +#define FDI_RX_PWRDN_LANE0_MASK (3 << 24) +#define FDI_RX_PWRDN_LANE0_VAL(x) ((x) << 24) +#define FDI_RX_TP1_TO_TP2_48 (2 << 20) +#define FDI_RX_TP1_TO_TP2_64 (3 << 20) +#define FDI_RX_FDI_DELAY_90 (0x90 << 0) #define FDI_RX_MISC(pipe) _MMIO_PIPE(pipe, _FDI_RXA_MISC, _FDI_RXB_MISC) #define _FDI_RXA_TUSIZE1 0xf0030 @@ -7864,17 +7864,17 @@ enum { #define FDI_RX_TUSIZE2(pipe) _MMIO_PIPE(pipe, _FDI_RXA_TUSIZE2, _FDI_RXB_TUSIZE2) /* FDI_RX interrupt register format */ -#define FDI_RX_INTER_LANE_ALIGN (1<<10) -#define FDI_RX_SYMBOL_LOCK (1<<9) /* train 2 */ -#define FDI_RX_BIT_LOCK (1<<8) /* train 1 */ -#define FDI_RX_TRAIN_PATTERN_2_FAIL (1<<7) -#define FDI_RX_FS_CODE_ERR (1<<6) -#define FDI_RX_FE_CODE_ERR (1<<5) -#define FDI_RX_SYMBOL_ERR_RATE_ABOVE (1<<4) -#define FDI_RX_HDCP_LINK_FAIL (1<<3) -#define FDI_RX_PIXEL_FIFO_OVERFLOW (1<<2) -#define FDI_RX_CROSS_CLOCK_OVERFLOW (1<<1) -#define FDI_RX_SYMBOL_QUEUE_OVERFLOW (1<<0) +#define FDI_RX_INTER_LANE_ALIGN (1 << 10) +#define FDI_RX_SYMBOL_LOCK (1 << 9) /* train 2 */ +#define FDI_RX_BIT_LOCK (1 << 8) /* train 1 */ +#define FDI_RX_TRAIN_PATTERN_2_FAIL (1 << 7) +#define FDI_RX_FS_CODE_ERR (1 << 6) +#define FDI_RX_FE_CODE_ERR (1 << 5) +#define FDI_RX_SYMBOL_ERR_RATE_ABOVE (1 << 4) +#define FDI_RX_HDCP_LINK_FAIL (1 << 3) +#define FDI_RX_PIXEL_FIFO_OVERFLOW (1 << 2) +#define FDI_RX_CROSS_CLOCK_OVERFLOW (1 << 1) +#define FDI_RX_SYMBOL_QUEUE_OVERFLOW (1 << 0) #define _FDI_RXA_IIR 0xf0014 #define _FDI_RXA_IMR 0xf0018 @@ -7924,54 +7924,54 @@ enum { #define _TRANS_DP_CTL_B 0xe1300 #define _TRANS_DP_CTL_C 0xe2300 #define TRANS_DP_CTL(pipe) _MMIO_PIPE(pipe, _TRANS_DP_CTL_A, _TRANS_DP_CTL_B) -#define TRANS_DP_OUTPUT_ENABLE (1<<31) +#define TRANS_DP_OUTPUT_ENABLE (1 << 31) #define TRANS_DP_PORT_SEL_MASK (3 << 29) #define TRANS_DP_PORT_SEL_NONE (3 << 29) #define TRANS_DP_PORT_SEL(port) (((port) - PORT_B) << 29) -#define TRANS_DP_AUDIO_ONLY (1<<26) -#define TRANS_DP_ENH_FRAMING (1<<18) -#define TRANS_DP_8BPC (0<<9) -#define TRANS_DP_10BPC (1<<9) -#define TRANS_DP_6BPC (2<<9) -#define TRANS_DP_12BPC (3<<9) -#define TRANS_DP_BPC_MASK (3<<9) -#define TRANS_DP_VSYNC_ACTIVE_HIGH (1<<4) +#define TRANS_DP_AUDIO_ONLY (1 << 26) +#define TRANS_DP_ENH_FRAMING (1 << 18) +#define TRANS_DP_8BPC (0 << 9) +#define TRANS_DP_10BPC (1 << 9) +#define TRANS_DP_6BPC (2 << 9) +#define TRANS_DP_12BPC (3 << 9) +#define TRANS_DP_BPC_MASK (3 << 9) +#define TRANS_DP_VSYNC_ACTIVE_HIGH (1 << 4) #define TRANS_DP_VSYNC_ACTIVE_LOW 0 -#define TRANS_DP_HSYNC_ACTIVE_HIGH (1<<3) +#define TRANS_DP_HSYNC_ACTIVE_HIGH (1 << 3) #define TRANS_DP_HSYNC_ACTIVE_LOW 0 -#define TRANS_DP_SYNC_MASK (3<<3) +#define TRANS_DP_SYNC_MASK (3 << 3) /* SNB eDP training params */ /* SNB A-stepping */ -#define EDP_LINK_TRAIN_400MV_0DB_SNB_A (0x38<<22) -#define EDP_LINK_TRAIN_400MV_6DB_SNB_A (0x02<<22) -#define EDP_LINK_TRAIN_600MV_3_5DB_SNB_A (0x01<<22) -#define EDP_LINK_TRAIN_800MV_0DB_SNB_A (0x0<<22) +#define EDP_LINK_TRAIN_400MV_0DB_SNB_A (0x38 << 22) +#define EDP_LINK_TRAIN_400MV_6DB_SNB_A (0x02 << 22) +#define EDP_LINK_TRAIN_600MV_3_5DB_SNB_A (0x01 << 22) +#define EDP_LINK_TRAIN_800MV_0DB_SNB_A (0x0 << 22) /* SNB B-stepping */ -#define EDP_LINK_TRAIN_400_600MV_0DB_SNB_B (0x0<<22) -#define EDP_LINK_TRAIN_400MV_3_5DB_SNB_B (0x1<<22) -#define EDP_LINK_TRAIN_400_600MV_6DB_SNB_B (0x3a<<22) -#define EDP_LINK_TRAIN_600_800MV_3_5DB_SNB_B (0x39<<22) -#define EDP_LINK_TRAIN_800_1200MV_0DB_SNB_B (0x38<<22) -#define EDP_LINK_TRAIN_VOL_EMP_MASK_SNB (0x3f<<22) +#define EDP_LINK_TRAIN_400_600MV_0DB_SNB_B (0x0 << 22) +#define EDP_LINK_TRAIN_400MV_3_5DB_SNB_B (0x1 << 22) +#define EDP_LINK_TRAIN_400_600MV_6DB_SNB_B (0x3a << 22) +#define EDP_LINK_TRAIN_600_800MV_3_5DB_SNB_B (0x39 << 22) +#define EDP_LINK_TRAIN_800_1200MV_0DB_SNB_B (0x38 << 22) +#define EDP_LINK_TRAIN_VOL_EMP_MASK_SNB (0x3f << 22) /* IVB */ -#define EDP_LINK_TRAIN_400MV_0DB_IVB (0x24 <<22) -#define EDP_LINK_TRAIN_400MV_3_5DB_IVB (0x2a <<22) -#define EDP_LINK_TRAIN_400MV_6DB_IVB (0x2f <<22) -#define EDP_LINK_TRAIN_600MV_0DB_IVB (0x30 <<22) -#define EDP_LINK_TRAIN_600MV_3_5DB_IVB (0x36 <<22) -#define EDP_LINK_TRAIN_800MV_0DB_IVB (0x38 <<22) -#define EDP_LINK_TRAIN_800MV_3_5DB_IVB (0x3e <<22) +#define EDP_LINK_TRAIN_400MV_0DB_IVB (0x24 << 22) +#define EDP_LINK_TRAIN_400MV_3_5DB_IVB (0x2a << 22) +#define EDP_LINK_TRAIN_400MV_6DB_IVB (0x2f << 22) +#define EDP_LINK_TRAIN_600MV_0DB_IVB (0x30 << 22) +#define EDP_LINK_TRAIN_600MV_3_5DB_IVB (0x36 << 22) +#define EDP_LINK_TRAIN_800MV_0DB_IVB (0x38 << 22) +#define EDP_LINK_TRAIN_800MV_3_5DB_IVB (0x3e << 22) /* legacy values */ -#define EDP_LINK_TRAIN_500MV_0DB_IVB (0x00 <<22) -#define EDP_LINK_TRAIN_1000MV_0DB_IVB (0x20 <<22) -#define EDP_LINK_TRAIN_500MV_3_5DB_IVB (0x02 <<22) -#define EDP_LINK_TRAIN_1000MV_3_5DB_IVB (0x22 <<22) -#define EDP_LINK_TRAIN_1000MV_6DB_IVB (0x23 <<22) +#define EDP_LINK_TRAIN_500MV_0DB_IVB (0x00 << 22) +#define EDP_LINK_TRAIN_1000MV_0DB_IVB (0x20 << 22) +#define EDP_LINK_TRAIN_500MV_3_5DB_IVB (0x02 << 22) +#define EDP_LINK_TRAIN_1000MV_3_5DB_IVB (0x22 << 22) +#define EDP_LINK_TRAIN_1000MV_6DB_IVB (0x23 << 22) -#define EDP_LINK_TRAIN_VOL_EMP_MASK_IVB (0x3f<<22) +#define EDP_LINK_TRAIN_VOL_EMP_MASK_IVB (0x3f << 22) #define VLV_PMWGICZ _MMIO(0x1300a4) @@ -8018,7 +8018,7 @@ enum { #define FORCEWAKE_KERNEL_FALLBACK BIT(15) #define FORCEWAKE_MT_ACK _MMIO(0x130040) #define ECOBUS _MMIO(0xa180) -#define FORCEWAKE_MT_ENABLE (1<<5) +#define FORCEWAKE_MT_ENABLE (1 << 5) #define VLV_SPAREG2H _MMIO(0xA194) #define GEN9_PWRGT_DOMAIN_STATUS _MMIO(0xA2A0) #define GEN9_PWRGT_MEDIA_STATUS_MASK (1 << 0) @@ -8027,13 +8027,13 @@ enum { #define GTFIFODBG _MMIO(0x120000) #define GT_FIFO_SBDEDICATE_FREE_ENTRY_CHV (0x1f << 20) #define GT_FIFO_FREE_ENTRIES_CHV (0x7f << 13) -#define GT_FIFO_SBDROPERR (1<<6) -#define GT_FIFO_BLOBDROPERR (1<<5) -#define GT_FIFO_SB_READ_ABORTERR (1<<4) -#define GT_FIFO_DROPERR (1<<3) -#define GT_FIFO_OVFERR (1<<2) -#define GT_FIFO_IAWRERR (1<<1) -#define GT_FIFO_IARDERR (1<<0) +#define GT_FIFO_SBDROPERR (1 << 6) +#define GT_FIFO_BLOBDROPERR (1 << 5) +#define GT_FIFO_SB_READ_ABORTERR (1 << 4) +#define GT_FIFO_DROPERR (1 << 3) +#define GT_FIFO_OVFERR (1 << 2) +#define GT_FIFO_IAWRERR (1 << 1) +#define GT_FIFO_IARDERR (1 << 0) #define GTFIFOCTL _MMIO(0x120008) #define GT_FIFO_FREE_ENTRIES_MASK 0x7f @@ -8067,37 +8067,37 @@ enum { # define GEN6_OACSUNIT_CLOCK_GATE_DISABLE (1 << 20) #define GEN7_UCGCTL4 _MMIO(0x940c) -#define GEN7_L3BANK2X_CLOCK_GATE_DISABLE (1<<25) -#define GEN8_EU_GAUNIT_CLOCK_GATE_DISABLE (1<<14) +#define GEN7_L3BANK2X_CLOCK_GATE_DISABLE (1 << 25) +#define GEN8_EU_GAUNIT_CLOCK_GATE_DISABLE (1 << 14) #define GEN6_RCGCTL1 _MMIO(0x9410) #define GEN6_RCGCTL2 _MMIO(0x9414) #define GEN6_RSTCTL _MMIO(0x9420) #define GEN8_UCGCTL6 _MMIO(0x9430) -#define GEN8_GAPSUNIT_CLOCK_GATE_DISABLE (1<<24) -#define GEN8_SDEUNIT_CLOCK_GATE_DISABLE (1<<14) -#define GEN8_HDCUNIT_CLOCK_GATE_DISABLE_HDCREQ (1<<28) +#define GEN8_GAPSUNIT_CLOCK_GATE_DISABLE (1 << 24) +#define GEN8_SDEUNIT_CLOCK_GATE_DISABLE (1 << 14) +#define GEN8_HDCUNIT_CLOCK_GATE_DISABLE_HDCREQ (1 << 28) #define GEN6_GFXPAUSE _MMIO(0xA000) #define GEN6_RPNSWREQ _MMIO(0xA008) -#define GEN6_TURBO_DISABLE (1<<31) -#define GEN6_FREQUENCY(x) ((x)<<25) -#define HSW_FREQUENCY(x) ((x)<<24) -#define GEN9_FREQUENCY(x) ((x)<<23) -#define GEN6_OFFSET(x) ((x)<<19) -#define GEN6_AGGRESSIVE_TURBO (0<<15) +#define GEN6_TURBO_DISABLE (1 << 31) +#define GEN6_FREQUENCY(x) ((x) << 25) +#define HSW_FREQUENCY(x) ((x) << 24) +#define GEN9_FREQUENCY(x) ((x) << 23) +#define GEN6_OFFSET(x) ((x) << 19) +#define GEN6_AGGRESSIVE_TURBO (0 << 15) #define GEN6_RC_VIDEO_FREQ _MMIO(0xA00C) #define GEN6_RC_CONTROL _MMIO(0xA090) -#define GEN6_RC_CTL_RC6pp_ENABLE (1<<16) -#define GEN6_RC_CTL_RC6p_ENABLE (1<<17) -#define GEN6_RC_CTL_RC6_ENABLE (1<<18) -#define GEN6_RC_CTL_RC1e_ENABLE (1<<20) -#define GEN6_RC_CTL_RC7_ENABLE (1<<22) -#define VLV_RC_CTL_CTX_RST_PARALLEL (1<<24) -#define GEN7_RC_CTL_TO_MODE (1<<28) -#define GEN6_RC_CTL_EI_MODE(x) ((x)<<27) -#define GEN6_RC_CTL_HW_ENABLE (1<<31) +#define GEN6_RC_CTL_RC6pp_ENABLE (1 << 16) +#define GEN6_RC_CTL_RC6p_ENABLE (1 << 17) +#define GEN6_RC_CTL_RC6_ENABLE (1 << 18) +#define GEN6_RC_CTL_RC1e_ENABLE (1 << 20) +#define GEN6_RC_CTL_RC7_ENABLE (1 << 22) +#define VLV_RC_CTL_CTX_RST_PARALLEL (1 << 24) +#define GEN7_RC_CTL_TO_MODE (1 << 28) +#define GEN6_RC_CTL_EI_MODE(x) ((x) << 27) +#define GEN6_RC_CTL_HW_ENABLE (1 << 31) #define GEN6_RP_DOWN_TIMEOUT _MMIO(0xA010) #define GEN6_RP_INTERRUPT_LIMITS _MMIO(0xA014) #define GEN6_RPSTAT1 _MMIO(0xA01C) @@ -8108,19 +8108,19 @@ enum { #define HSW_CAGF_MASK (0x7f << HSW_CAGF_SHIFT) #define GEN9_CAGF_MASK (0x1ff << GEN9_CAGF_SHIFT) #define GEN6_RP_CONTROL _MMIO(0xA024) -#define GEN6_RP_MEDIA_TURBO (1<<11) -#define GEN6_RP_MEDIA_MODE_MASK (3<<9) -#define GEN6_RP_MEDIA_HW_TURBO_MODE (3<<9) -#define GEN6_RP_MEDIA_HW_NORMAL_MODE (2<<9) -#define GEN6_RP_MEDIA_HW_MODE (1<<9) -#define GEN6_RP_MEDIA_SW_MODE (0<<9) -#define GEN6_RP_MEDIA_IS_GFX (1<<8) -#define GEN6_RP_ENABLE (1<<7) -#define GEN6_RP_UP_IDLE_MIN (0x1<<3) -#define GEN6_RP_UP_BUSY_AVG (0x2<<3) -#define GEN6_RP_UP_BUSY_CONT (0x4<<3) -#define GEN6_RP_DOWN_IDLE_AVG (0x2<<0) -#define GEN6_RP_DOWN_IDLE_CONT (0x1<<0) +#define GEN6_RP_MEDIA_TURBO (1 << 11) +#define GEN6_RP_MEDIA_MODE_MASK (3 << 9) +#define GEN6_RP_MEDIA_HW_TURBO_MODE (3 << 9) +#define GEN6_RP_MEDIA_HW_NORMAL_MODE (2 << 9) +#define GEN6_RP_MEDIA_HW_MODE (1 << 9) +#define GEN6_RP_MEDIA_SW_MODE (0 << 9) +#define GEN6_RP_MEDIA_IS_GFX (1 << 8) +#define GEN6_RP_ENABLE (1 << 7) +#define GEN6_RP_UP_IDLE_MIN (0x1 << 3) +#define GEN6_RP_UP_BUSY_AVG (0x2 << 3) +#define GEN6_RP_UP_BUSY_CONT (0x4 << 3) +#define GEN6_RP_DOWN_IDLE_AVG (0x2 << 0) +#define GEN6_RP_DOWN_IDLE_CONT (0x1 << 0) #define GEN6_RP_UP_THRESHOLD _MMIO(0xA02C) #define GEN6_RP_DOWN_THRESHOLD _MMIO(0xA030) #define GEN6_RP_CUR_UP_EI _MMIO(0xA050) @@ -8156,15 +8156,15 @@ enum { #define VLV_RCEDATA _MMIO(0xA0BC) #define GEN6_RC6pp_THRESHOLD _MMIO(0xA0C0) #define GEN6_PMINTRMSK _MMIO(0xA168) -#define GEN8_PMINTR_DISABLE_REDIRECT_TO_GUC (1<<31) -#define ARAT_EXPIRED_INTRMSK (1<<9) +#define GEN8_PMINTR_DISABLE_REDIRECT_TO_GUC (1 << 31) +#define ARAT_EXPIRED_INTRMSK (1 << 9) #define GEN8_MISC_CTRL0 _MMIO(0xA180) #define VLV_PWRDWNUPCTL _MMIO(0xA294) #define GEN9_MEDIA_PG_IDLE_HYSTERESIS _MMIO(0xA0C4) #define GEN9_RENDER_PG_IDLE_HYSTERESIS _MMIO(0xA0C8) #define GEN9_PG_ENABLE _MMIO(0xA210) -#define GEN9_RENDER_PG_ENABLE (1<<0) -#define GEN9_MEDIA_PG_ENABLE (1<<1) +#define GEN9_RENDER_PG_ENABLE (1 << 0) +#define GEN9_MEDIA_PG_ENABLE (1 << 1) #define GEN8_PUSHBUS_CONTROL _MMIO(0xA248) #define GEN8_PUSHBUS_ENABLE _MMIO(0xA250) #define GEN8_PUSHBUS_SHIFT _MMIO(0xA25C) @@ -8177,13 +8177,13 @@ enum { #define GEN6_PMIMR _MMIO(0x44024) /* rps_lock */ #define GEN6_PMIIR _MMIO(0x44028) #define GEN6_PMIER _MMIO(0x4402C) -#define GEN6_PM_MBOX_EVENT (1<<25) -#define GEN6_PM_THERMAL_EVENT (1<<24) -#define GEN6_PM_RP_DOWN_TIMEOUT (1<<6) -#define GEN6_PM_RP_UP_THRESHOLD (1<<5) -#define GEN6_PM_RP_DOWN_THRESHOLD (1<<4) -#define GEN6_PM_RP_UP_EI_EXPIRED (1<<2) -#define GEN6_PM_RP_DOWN_EI_EXPIRED (1<<1) +#define GEN6_PM_MBOX_EVENT (1 << 25) +#define GEN6_PM_THERMAL_EVENT (1 << 24) +#define GEN6_PM_RP_DOWN_TIMEOUT (1 << 6) +#define GEN6_PM_RP_UP_THRESHOLD (1 << 5) +#define GEN6_PM_RP_DOWN_THRESHOLD (1 << 4) +#define GEN6_PM_RP_UP_EI_EXPIRED (1 << 2) +#define GEN6_PM_RP_DOWN_EI_EXPIRED (1 << 1) #define GEN6_PM_RPS_EVENTS (GEN6_PM_RP_UP_THRESHOLD | \ GEN6_PM_RP_DOWN_THRESHOLD | \ GEN6_PM_RP_DOWN_TIMEOUT) @@ -8192,16 +8192,16 @@ enum { #define GEN7_GT_SCRATCH_REG_NUM 8 #define VLV_GTLC_SURVIVABILITY_REG _MMIO(0x130098) -#define VLV_GFX_CLK_STATUS_BIT (1<<3) -#define VLV_GFX_CLK_FORCE_ON_BIT (1<<2) +#define VLV_GFX_CLK_STATUS_BIT (1 << 3) +#define VLV_GFX_CLK_FORCE_ON_BIT (1 << 2) #define GEN6_GT_GFX_RC6_LOCKED _MMIO(0x138104) #define VLV_COUNTER_CONTROL _MMIO(0x138104) -#define VLV_COUNT_RANGE_HIGH (1<<15) -#define VLV_MEDIA_RC0_COUNT_EN (1<<5) -#define VLV_RENDER_RC0_COUNT_EN (1<<4) -#define VLV_MEDIA_RC6_COUNT_EN (1<<1) -#define VLV_RENDER_RC6_COUNT_EN (1<<0) +#define VLV_COUNT_RANGE_HIGH (1 << 15) +#define VLV_MEDIA_RC0_COUNT_EN (1 << 5) +#define VLV_RENDER_RC0_COUNT_EN (1 << 4) +#define VLV_MEDIA_RC6_COUNT_EN (1 << 1) +#define VLV_RENDER_RC6_COUNT_EN (1 << 0) #define GEN6_GT_GFX_RC6 _MMIO(0x138108) #define VLV_GT_RENDER_RC6 _MMIO(0x138108) #define VLV_GT_MEDIA_RC6 _MMIO(0x13810C) @@ -8212,7 +8212,7 @@ enum { #define VLV_MEDIA_C0_COUNT _MMIO(0x13811C) #define GEN6_PCODE_MAILBOX _MMIO(0x138124) -#define GEN6_PCODE_READY (1<<31) +#define GEN6_PCODE_READY (1 << 31) #define GEN6_PCODE_ERROR_MASK 0xFF #define GEN6_PCODE_SUCCESS 0x0 #define GEN6_PCODE_ILLEGAL_CMD 0x1 @@ -8256,7 +8256,7 @@ enum { #define GEN6_PCODE_DATA1 _MMIO(0x13812C) #define GEN6_GT_CORE_STATUS _MMIO(0x138060) -#define GEN6_CORE_CPD_STATE_MASK (7<<4) +#define GEN6_CORE_CPD_STATE_MASK (7 << 4) #define GEN6_RCn_MASK 7 #define GEN6_RC0 0 #define GEN6_RC3 2 @@ -8268,26 +8268,26 @@ enum { #define CHV_POWER_SS0_SIG1 _MMIO(0xa720) #define CHV_POWER_SS1_SIG1 _MMIO(0xa728) -#define CHV_SS_PG_ENABLE (1<<1) -#define CHV_EU08_PG_ENABLE (1<<9) -#define CHV_EU19_PG_ENABLE (1<<17) -#define CHV_EU210_PG_ENABLE (1<<25) +#define CHV_SS_PG_ENABLE (1 << 1) +#define CHV_EU08_PG_ENABLE (1 << 9) +#define CHV_EU19_PG_ENABLE (1 << 17) +#define CHV_EU210_PG_ENABLE (1 << 25) #define CHV_POWER_SS0_SIG2 _MMIO(0xa724) #define CHV_POWER_SS1_SIG2 _MMIO(0xa72c) -#define CHV_EU311_PG_ENABLE (1<<1) +#define CHV_EU311_PG_ENABLE (1 << 1) -#define GEN9_SLICE_PGCTL_ACK(slice) _MMIO(0x804c + (slice)*0x4) +#define GEN9_SLICE_PGCTL_ACK(slice) _MMIO(0x804c + (slice) * 0x4) #define GEN10_SLICE_PGCTL_ACK(slice) _MMIO(0x804c + ((slice) / 3) * 0x34 + \ ((slice) % 3) * 0x4) #define GEN9_PGCTL_SLICE_ACK (1 << 0) -#define GEN9_PGCTL_SS_ACK(subslice) (1 << (2 + (subslice)*2)) +#define GEN9_PGCTL_SS_ACK(subslice) (1 << (2 + (subslice) * 2)) #define GEN10_PGCTL_VALID_SS_MASK(slice) ((slice) == 0 ? 0x7F : 0x1F) -#define GEN9_SS01_EU_PGCTL_ACK(slice) _MMIO(0x805c + (slice)*0x8) +#define GEN9_SS01_EU_PGCTL_ACK(slice) _MMIO(0x805c + (slice) * 0x8) #define GEN10_SS01_EU_PGCTL_ACK(slice) _MMIO(0x805c + ((slice) / 3) * 0x30 + \ ((slice) % 3) * 0x8) -#define GEN9_SS23_EU_PGCTL_ACK(slice) _MMIO(0x8060 + (slice)*0x8) +#define GEN9_SS23_EU_PGCTL_ACK(slice) _MMIO(0x8060 + (slice) * 0x8) #define GEN10_SS23_EU_PGCTL_ACK(slice) _MMIO(0x8060 + ((slice) / 3) * 0x30 + \ ((slice) % 3) * 0x8) #define GEN9_PGCTL_SSA_EU08_ACK (1 << 0) @@ -8300,10 +8300,10 @@ enum { #define GEN9_PGCTL_SSB_EU311_ACK (1 << 14) #define GEN7_MISCCPCTL _MMIO(0x9424) -#define GEN7_DOP_CLOCK_GATE_ENABLE (1<<0) -#define GEN8_DOP_CLOCK_GATE_CFCLK_ENABLE (1<<2) -#define GEN8_DOP_CLOCK_GATE_GUC_ENABLE (1<<4) -#define GEN8_DOP_CLOCK_GATE_MEDIA_ENABLE (1<<6) +#define GEN7_DOP_CLOCK_GATE_ENABLE (1 << 0) +#define GEN8_DOP_CLOCK_GATE_CFCLK_ENABLE (1 << 2) +#define GEN8_DOP_CLOCK_GATE_GUC_ENABLE (1 << 4) +#define GEN8_DOP_CLOCK_GATE_MEDIA_ENABLE (1 << 6) #define GEN8_GARBCNTL _MMIO(0xB004) #define GEN9_GAPS_TSV_CREDIT_DISABLE (1 << 7) @@ -8332,38 +8332,38 @@ enum { /* IVYBRIDGE DPF */ #define GEN7_L3CDERRST1(slice) _MMIO(0xB008 + (slice) * 0x200) /* L3CD Error Status 1 */ -#define GEN7_L3CDERRST1_ROW_MASK (0x7ff<<14) -#define GEN7_PARITY_ERROR_VALID (1<<13) -#define GEN7_L3CDERRST1_BANK_MASK (3<<11) -#define GEN7_L3CDERRST1_SUBBANK_MASK (7<<8) +#define GEN7_L3CDERRST1_ROW_MASK (0x7ff << 14) +#define GEN7_PARITY_ERROR_VALID (1 << 13) +#define GEN7_L3CDERRST1_BANK_MASK (3 << 11) +#define GEN7_L3CDERRST1_SUBBANK_MASK (7 << 8) #define GEN7_PARITY_ERROR_ROW(reg) \ ((reg & GEN7_L3CDERRST1_ROW_MASK) >> 14) #define GEN7_PARITY_ERROR_BANK(reg) \ ((reg & GEN7_L3CDERRST1_BANK_MASK) >> 11) #define GEN7_PARITY_ERROR_SUBBANK(reg) \ ((reg & GEN7_L3CDERRST1_SUBBANK_MASK) >> 8) -#define GEN7_L3CDERRST1_ENABLE (1<<7) +#define GEN7_L3CDERRST1_ENABLE (1 << 7) #define GEN7_L3LOG(slice, i) _MMIO(0xB070 + (slice) * 0x200 + (i) * 4) #define GEN7_L3LOG_SIZE 0x80 #define GEN7_HALF_SLICE_CHICKEN1 _MMIO(0xe100) /* IVB GT1 + VLV */ #define GEN7_HALF_SLICE_CHICKEN1_GT2 _MMIO(0xf100) -#define GEN7_MAX_PS_THREAD_DEP (8<<12) -#define GEN7_SINGLE_SUBSCAN_DISPATCH_ENABLE (1<<10) -#define GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE (1<<4) -#define GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE (1<<3) +#define GEN7_MAX_PS_THREAD_DEP (8 << 12) +#define GEN7_SINGLE_SUBSCAN_DISPATCH_ENABLE (1 << 10) +#define GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE (1 << 4) +#define GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE (1 << 3) #define GEN9_HALF_SLICE_CHICKEN5 _MMIO(0xe188) -#define GEN9_DG_MIRROR_FIX_ENABLE (1<<5) -#define GEN9_CCS_TLB_PREFETCH_ENABLE (1<<3) +#define GEN9_DG_MIRROR_FIX_ENABLE (1 << 5) +#define GEN9_CCS_TLB_PREFETCH_ENABLE (1 << 3) #define GEN8_ROW_CHICKEN _MMIO(0xe4f0) -#define FLOW_CONTROL_ENABLE (1<<15) -#define PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE (1<<8) -#define STALL_DOP_GATING_DISABLE (1<<5) -#define THROTTLE_12_5 (7<<2) -#define DISABLE_EARLY_EOT (1<<1) +#define FLOW_CONTROL_ENABLE (1 << 15) +#define PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE (1 << 8) +#define STALL_DOP_GATING_DISABLE (1 << 5) +#define THROTTLE_12_5 (7 << 2) +#define DISABLE_EARLY_EOT (1 << 1) #define GEN7_ROW_CHICKEN2 _MMIO(0xe4f4) #define GEN7_ROW_CHICKEN2_GT2 _MMIO(0xf4f4) @@ -8375,19 +8375,19 @@ enum { #define HSW_ROW_CHICKEN3_L3_GLOBAL_ATOMICS_DISABLE (1 << 6) #define HALF_SLICE_CHICKEN2 _MMIO(0xe180) -#define GEN8_ST_PO_DISABLE (1<<13) +#define GEN8_ST_PO_DISABLE (1 << 13) #define HALF_SLICE_CHICKEN3 _MMIO(0xe184) -#define HSW_SAMPLE_C_PERFORMANCE (1<<9) -#define GEN8_CENTROID_PIXEL_OPT_DIS (1<<8) -#define GEN9_DISABLE_OCL_OOB_SUPPRESS_LOGIC (1<<5) -#define CNL_FAST_ANISO_L1_BANKING_FIX (1<<4) -#define GEN8_SAMPLER_POWER_BYPASS_DIS (1<<1) +#define HSW_SAMPLE_C_PERFORMANCE (1 << 9) +#define GEN8_CENTROID_PIXEL_OPT_DIS (1 << 8) +#define GEN9_DISABLE_OCL_OOB_SUPPRESS_LOGIC (1 << 5) +#define CNL_FAST_ANISO_L1_BANKING_FIX (1 << 4) +#define GEN8_SAMPLER_POWER_BYPASS_DIS (1 << 1) #define GEN9_HALF_SLICE_CHICKEN7 _MMIO(0xe194) -#define GEN9_SAMPLER_HASH_COMPRESSED_READ_ADDR (1<<8) -#define GEN9_ENABLE_YV12_BUGFIX (1<<4) -#define GEN9_ENABLE_GPGPU_PREEMPTION (1<<2) +#define GEN9_SAMPLER_HASH_COMPRESSED_READ_ADDR (1 << 8) +#define GEN9_ENABLE_YV12_BUGFIX (1 << 4) +#define GEN9_ENABLE_GPGPU_PREEMPTION (1 << 2) /* Audio */ #define G4X_AUD_VID_DID _MMIO(dev_priv->info.display_mmio_offset + 0x62020) @@ -8540,9 +8540,9 @@ enum { #define HSW_PWR_WELL_CTL_REQ(pw) (1 << (_HSW_PW_SHIFT(pw) + 1)) #define HSW_PWR_WELL_CTL_STATE(pw) (1 << _HSW_PW_SHIFT(pw)) #define HSW_PWR_WELL_CTL5 _MMIO(0x45410) -#define HSW_PWR_WELL_ENABLE_SINGLE_STEP (1<<31) -#define HSW_PWR_WELL_PWR_GATE_OVERRIDE (1<<20) -#define HSW_PWR_WELL_FORCE_ON (1<<19) +#define HSW_PWR_WELL_ENABLE_SINGLE_STEP (1 << 31) +#define HSW_PWR_WELL_PWR_GATE_OVERRIDE (1 << 20) +#define HSW_PWR_WELL_FORCE_ON (1 << 19) #define HSW_PWR_WELL_CTL6 _MMIO(0x45414) /* SKL Fuse Status */ @@ -8553,7 +8553,7 @@ enum skl_power_gate { }; #define SKL_FUSE_STATUS _MMIO(0x42000) -#define SKL_FUSE_DOWNLOAD_STATUS (1<<31) +#define SKL_FUSE_DOWNLOAD_STATUS (1 << 31) /* PG0 (HW control->no power well ID), PG1..PG2 (SKL_DISP_PW1..SKL_DISP_PW2) */ #define SKL_PW_TO_PG(pw) ((pw) - SKL_DISP_PW_1 + SKL_PG1) #define SKL_FUSE_PG_DIST_STATUS(pg) (1 << (27 - (pg))) @@ -8568,8 +8568,8 @@ enum skl_power_gate { _CNL_AUX_ANAOVRD1_C, \ _CNL_AUX_ANAOVRD1_D, \ _CNL_AUX_ANAOVRD1_F)) -#define CNL_AUX_ANAOVRD1_ENABLE (1<<16) -#define CNL_AUX_ANAOVRD1_LDO_BYPASS (1<<23) +#define CNL_AUX_ANAOVRD1_ENABLE (1 << 16) +#define CNL_AUX_ANAOVRD1_LDO_BYPASS (1 << 23) /* HDCP Key Registers */ #define HDCP_KEY_CONF _MMIO(0x66c00) @@ -8660,37 +8660,37 @@ enum skl_power_gate { #define _TRANS_DDI_FUNC_CTL_EDP 0x6F400 #define TRANS_DDI_FUNC_CTL(tran) _MMIO_TRANS2(tran, _TRANS_DDI_FUNC_CTL_A) -#define TRANS_DDI_FUNC_ENABLE (1<<31) +#define TRANS_DDI_FUNC_ENABLE (1 << 31) /* Those bits are ignored by pipe EDP since it can only connect to DDI A */ -#define TRANS_DDI_PORT_MASK (7<<28) +#define TRANS_DDI_PORT_MASK (7 << 28) #define TRANS_DDI_PORT_SHIFT 28 -#define TRANS_DDI_SELECT_PORT(x) ((x)<<28) -#define TRANS_DDI_PORT_NONE (0<<28) -#define TRANS_DDI_MODE_SELECT_MASK (7<<24) -#define TRANS_DDI_MODE_SELECT_HDMI (0<<24) -#define TRANS_DDI_MODE_SELECT_DVI (1<<24) -#define TRANS_DDI_MODE_SELECT_DP_SST (2<<24) -#define TRANS_DDI_MODE_SELECT_DP_MST (3<<24) -#define TRANS_DDI_MODE_SELECT_FDI (4<<24) -#define TRANS_DDI_BPC_MASK (7<<20) -#define TRANS_DDI_BPC_8 (0<<20) -#define TRANS_DDI_BPC_10 (1<<20) -#define TRANS_DDI_BPC_6 (2<<20) -#define TRANS_DDI_BPC_12 (3<<20) -#define TRANS_DDI_PVSYNC (1<<17) -#define TRANS_DDI_PHSYNC (1<<16) -#define TRANS_DDI_EDP_INPUT_MASK (7<<12) -#define TRANS_DDI_EDP_INPUT_A_ON (0<<12) -#define TRANS_DDI_EDP_INPUT_A_ONOFF (4<<12) -#define TRANS_DDI_EDP_INPUT_B_ONOFF (5<<12) -#define TRANS_DDI_EDP_INPUT_C_ONOFF (6<<12) -#define TRANS_DDI_HDCP_SIGNALLING (1<<9) -#define TRANS_DDI_DP_VC_PAYLOAD_ALLOC (1<<8) -#define TRANS_DDI_HDMI_SCRAMBLER_CTS_ENABLE (1<<7) -#define TRANS_DDI_HDMI_SCRAMBLER_RESET_FREQ (1<<6) -#define TRANS_DDI_BFI_ENABLE (1<<4) -#define TRANS_DDI_HIGH_TMDS_CHAR_RATE (1<<4) -#define TRANS_DDI_HDMI_SCRAMBLING (1<<0) +#define TRANS_DDI_SELECT_PORT(x) ((x) << 28) +#define TRANS_DDI_PORT_NONE (0 << 28) +#define TRANS_DDI_MODE_SELECT_MASK (7 << 24) +#define TRANS_DDI_MODE_SELECT_HDMI (0 << 24) +#define TRANS_DDI_MODE_SELECT_DVI (1 << 24) +#define TRANS_DDI_MODE_SELECT_DP_SST (2 << 24) +#define TRANS_DDI_MODE_SELECT_DP_MST (3 << 24) +#define TRANS_DDI_MODE_SELECT_FDI (4 << 24) +#define TRANS_DDI_BPC_MASK (7 << 20) +#define TRANS_DDI_BPC_8 (0 << 20) +#define TRANS_DDI_BPC_10 (1 << 20) +#define TRANS_DDI_BPC_6 (2 << 20) +#define TRANS_DDI_BPC_12 (3 << 20) +#define TRANS_DDI_PVSYNC (1 << 17) +#define TRANS_DDI_PHSYNC (1 << 16) +#define TRANS_DDI_EDP_INPUT_MASK (7 << 12) +#define TRANS_DDI_EDP_INPUT_A_ON (0 << 12) +#define TRANS_DDI_EDP_INPUT_A_ONOFF (4 << 12) +#define TRANS_DDI_EDP_INPUT_B_ONOFF (5 << 12) +#define TRANS_DDI_EDP_INPUT_C_ONOFF (6 << 12) +#define TRANS_DDI_HDCP_SIGNALLING (1 << 9) +#define TRANS_DDI_DP_VC_PAYLOAD_ALLOC (1 << 8) +#define TRANS_DDI_HDMI_SCRAMBLER_CTS_ENABLE (1 << 7) +#define TRANS_DDI_HDMI_SCRAMBLER_RESET_FREQ (1 << 6) +#define TRANS_DDI_BFI_ENABLE (1 << 4) +#define TRANS_DDI_HIGH_TMDS_CHAR_RATE (1 << 4) +#define TRANS_DDI_HDMI_SCRAMBLING (1 << 0) #define TRANS_DDI_HDMI_SCRAMBLING_MASK (TRANS_DDI_HDMI_SCRAMBLER_CTS_ENABLE \ | TRANS_DDI_HDMI_SCRAMBLER_RESET_FREQ \ | TRANS_DDI_HDMI_SCRAMBLING) @@ -8699,29 +8699,29 @@ enum skl_power_gate { #define _DP_TP_CTL_A 0x64040 #define _DP_TP_CTL_B 0x64140 #define DP_TP_CTL(port) _MMIO_PORT(port, _DP_TP_CTL_A, _DP_TP_CTL_B) -#define DP_TP_CTL_ENABLE (1<<31) -#define DP_TP_CTL_MODE_SST (0<<27) -#define DP_TP_CTL_MODE_MST (1<<27) -#define DP_TP_CTL_FORCE_ACT (1<<25) -#define DP_TP_CTL_ENHANCED_FRAME_ENABLE (1<<18) -#define DP_TP_CTL_FDI_AUTOTRAIN (1<<15) -#define DP_TP_CTL_LINK_TRAIN_MASK (7<<8) -#define DP_TP_CTL_LINK_TRAIN_PAT1 (0<<8) -#define DP_TP_CTL_LINK_TRAIN_PAT2 (1<<8) -#define DP_TP_CTL_LINK_TRAIN_PAT3 (4<<8) -#define DP_TP_CTL_LINK_TRAIN_PAT4 (5<<8) -#define DP_TP_CTL_LINK_TRAIN_IDLE (2<<8) -#define DP_TP_CTL_LINK_TRAIN_NORMAL (3<<8) -#define DP_TP_CTL_SCRAMBLE_DISABLE (1<<7) +#define DP_TP_CTL_ENABLE (1 << 31) +#define DP_TP_CTL_MODE_SST (0 << 27) +#define DP_TP_CTL_MODE_MST (1 << 27) +#define DP_TP_CTL_FORCE_ACT (1 << 25) +#define DP_TP_CTL_ENHANCED_FRAME_ENABLE (1 << 18) +#define DP_TP_CTL_FDI_AUTOTRAIN (1 << 15) +#define DP_TP_CTL_LINK_TRAIN_MASK (7 << 8) +#define DP_TP_CTL_LINK_TRAIN_PAT1 (0 << 8) +#define DP_TP_CTL_LINK_TRAIN_PAT2 (1 << 8) +#define DP_TP_CTL_LINK_TRAIN_PAT3 (4 << 8) +#define DP_TP_CTL_LINK_TRAIN_PAT4 (5 << 8) +#define DP_TP_CTL_LINK_TRAIN_IDLE (2 << 8) +#define DP_TP_CTL_LINK_TRAIN_NORMAL (3 << 8) +#define DP_TP_CTL_SCRAMBLE_DISABLE (1 << 7) /* DisplayPort Transport Status */ #define _DP_TP_STATUS_A 0x64044 #define _DP_TP_STATUS_B 0x64144 #define DP_TP_STATUS(port) _MMIO_PORT(port, _DP_TP_STATUS_A, _DP_TP_STATUS_B) -#define DP_TP_STATUS_IDLE_DONE (1<<25) -#define DP_TP_STATUS_ACT_SENT (1<<24) -#define DP_TP_STATUS_MODE_STATUS_MST (1<<23) -#define DP_TP_STATUS_AUTOTRAIN_DONE (1<<12) +#define DP_TP_STATUS_IDLE_DONE (1 << 25) +#define DP_TP_STATUS_ACT_SENT (1 << 24) +#define DP_TP_STATUS_MODE_STATUS_MST (1 << 23) +#define DP_TP_STATUS_AUTOTRAIN_DONE (1 << 12) #define DP_TP_STATUS_PAYLOAD_MAPPING_VC2 (3 << 8) #define DP_TP_STATUS_PAYLOAD_MAPPING_VC1 (3 << 4) #define DP_TP_STATUS_PAYLOAD_MAPPING_VC0 (3 << 0) @@ -8730,16 +8730,16 @@ enum skl_power_gate { #define _DDI_BUF_CTL_A 0x64000 #define _DDI_BUF_CTL_B 0x64100 #define DDI_BUF_CTL(port) _MMIO_PORT(port, _DDI_BUF_CTL_A, _DDI_BUF_CTL_B) -#define DDI_BUF_CTL_ENABLE (1<<31) +#define DDI_BUF_CTL_ENABLE (1 << 31) #define DDI_BUF_TRANS_SELECT(n) ((n) << 24) -#define DDI_BUF_EMP_MASK (0xf<<24) -#define DDI_BUF_PORT_REVERSAL (1<<16) -#define DDI_BUF_IS_IDLE (1<<7) -#define DDI_A_4_LANES (1<<4) +#define DDI_BUF_EMP_MASK (0xf << 24) +#define DDI_BUF_PORT_REVERSAL (1 << 16) +#define DDI_BUF_IS_IDLE (1 << 7) +#define DDI_A_4_LANES (1 << 4) #define DDI_PORT_WIDTH(width) (((width) - 1) << 1) #define DDI_PORT_WIDTH_MASK (7 << 1) #define DDI_PORT_WIDTH_SHIFT 1 -#define DDI_INIT_DISPLAY_DETECTED (1<<0) +#define DDI_INIT_DISPLAY_DETECTED (1 << 0) /* DDI Buffer Translations */ #define _DDI_BUF_TRANS_A 0x64E00 @@ -8754,90 +8754,90 @@ enum skl_power_gate { #define SBI_ADDR _MMIO(0xC6000) #define SBI_DATA _MMIO(0xC6004) #define SBI_CTL_STAT _MMIO(0xC6008) -#define SBI_CTL_DEST_ICLK (0x0<<16) -#define SBI_CTL_DEST_MPHY (0x1<<16) -#define SBI_CTL_OP_IORD (0x2<<8) -#define SBI_CTL_OP_IOWR (0x3<<8) -#define SBI_CTL_OP_CRRD (0x6<<8) -#define SBI_CTL_OP_CRWR (0x7<<8) -#define SBI_RESPONSE_FAIL (0x1<<1) -#define SBI_RESPONSE_SUCCESS (0x0<<1) -#define SBI_BUSY (0x1<<0) -#define SBI_READY (0x0<<0) +#define SBI_CTL_DEST_ICLK (0x0 << 16) +#define SBI_CTL_DEST_MPHY (0x1 << 16) +#define SBI_CTL_OP_IORD (0x2 << 8) +#define SBI_CTL_OP_IOWR (0x3 << 8) +#define SBI_CTL_OP_CRRD (0x6 << 8) +#define SBI_CTL_OP_CRWR (0x7 << 8) +#define SBI_RESPONSE_FAIL (0x1 << 1) +#define SBI_RESPONSE_SUCCESS (0x0 << 1) +#define SBI_BUSY (0x1 << 0) +#define SBI_READY (0x0 << 0) /* SBI offsets */ #define SBI_SSCDIVINTPHASE 0x0200 #define SBI_SSCDIVINTPHASE6 0x0600 #define SBI_SSCDIVINTPHASE_DIVSEL_SHIFT 1 -#define SBI_SSCDIVINTPHASE_DIVSEL_MASK (0x7f<<1) -#define SBI_SSCDIVINTPHASE_DIVSEL(x) ((x)<<1) +#define SBI_SSCDIVINTPHASE_DIVSEL_MASK (0x7f << 1) +#define SBI_SSCDIVINTPHASE_DIVSEL(x) ((x) << 1) #define SBI_SSCDIVINTPHASE_INCVAL_SHIFT 8 -#define SBI_SSCDIVINTPHASE_INCVAL_MASK (0x7f<<8) -#define SBI_SSCDIVINTPHASE_INCVAL(x) ((x)<<8) -#define SBI_SSCDIVINTPHASE_DIR(x) ((x)<<15) -#define SBI_SSCDIVINTPHASE_PROPAGATE (1<<0) +#define SBI_SSCDIVINTPHASE_INCVAL_MASK (0x7f << 8) +#define SBI_SSCDIVINTPHASE_INCVAL(x) ((x) << 8) +#define SBI_SSCDIVINTPHASE_DIR(x) ((x) << 15) +#define SBI_SSCDIVINTPHASE_PROPAGATE (1 << 0) #define SBI_SSCDITHPHASE 0x0204 #define SBI_SSCCTL 0x020c #define SBI_SSCCTL6 0x060C -#define SBI_SSCCTL_PATHALT (1<<3) -#define SBI_SSCCTL_DISABLE (1<<0) +#define SBI_SSCCTL_PATHALT (1 << 3) +#define SBI_SSCCTL_DISABLE (1 << 0) #define SBI_SSCAUXDIV6 0x0610 #define SBI_SSCAUXDIV_FINALDIV2SEL_SHIFT 4 -#define SBI_SSCAUXDIV_FINALDIV2SEL_MASK (1<<4) -#define SBI_SSCAUXDIV_FINALDIV2SEL(x) ((x)<<4) +#define SBI_SSCAUXDIV_FINALDIV2SEL_MASK (1 << 4) +#define SBI_SSCAUXDIV_FINALDIV2SEL(x) ((x) << 4) #define SBI_DBUFF0 0x2a00 #define SBI_GEN0 0x1f00 -#define SBI_GEN0_CFG_BUFFENABLE_DISABLE (1<<0) +#define SBI_GEN0_CFG_BUFFENABLE_DISABLE (1 << 0) /* LPT PIXCLK_GATE */ #define PIXCLK_GATE _MMIO(0xC6020) -#define PIXCLK_GATE_UNGATE (1<<0) -#define PIXCLK_GATE_GATE (0<<0) +#define PIXCLK_GATE_UNGATE (1 << 0) +#define PIXCLK_GATE_GATE (0 << 0) /* SPLL */ #define SPLL_CTL _MMIO(0x46020) -#define SPLL_PLL_ENABLE (1<<31) -#define SPLL_PLL_SSC (1<<28) -#define SPLL_PLL_NON_SSC (2<<28) -#define SPLL_PLL_LCPLL (3<<28) -#define SPLL_PLL_REF_MASK (3<<28) -#define SPLL_PLL_FREQ_810MHz (0<<26) -#define SPLL_PLL_FREQ_1350MHz (1<<26) -#define SPLL_PLL_FREQ_2700MHz (2<<26) -#define SPLL_PLL_FREQ_MASK (3<<26) +#define SPLL_PLL_ENABLE (1 << 31) +#define SPLL_PLL_SSC (1 << 28) +#define SPLL_PLL_NON_SSC (2 << 28) +#define SPLL_PLL_LCPLL (3 << 28) +#define SPLL_PLL_REF_MASK (3 << 28) +#define SPLL_PLL_FREQ_810MHz (0 << 26) +#define SPLL_PLL_FREQ_1350MHz (1 << 26) +#define SPLL_PLL_FREQ_2700MHz (2 << 26) +#define SPLL_PLL_FREQ_MASK (3 << 26) /* WRPLL */ #define _WRPLL_CTL1 0x46040 #define _WRPLL_CTL2 0x46060 #define WRPLL_CTL(pll) _MMIO_PIPE(pll, _WRPLL_CTL1, _WRPLL_CTL2) -#define WRPLL_PLL_ENABLE (1<<31) -#define WRPLL_PLL_SSC (1<<28) -#define WRPLL_PLL_NON_SSC (2<<28) -#define WRPLL_PLL_LCPLL (3<<28) -#define WRPLL_PLL_REF_MASK (3<<28) +#define WRPLL_PLL_ENABLE (1 << 31) +#define WRPLL_PLL_SSC (1 << 28) +#define WRPLL_PLL_NON_SSC (2 << 28) +#define WRPLL_PLL_LCPLL (3 << 28) +#define WRPLL_PLL_REF_MASK (3 << 28) /* WRPLL divider programming */ -#define WRPLL_DIVIDER_REFERENCE(x) ((x)<<0) +#define WRPLL_DIVIDER_REFERENCE(x) ((x) << 0) #define WRPLL_DIVIDER_REF_MASK (0xff) -#define WRPLL_DIVIDER_POST(x) ((x)<<8) -#define WRPLL_DIVIDER_POST_MASK (0x3f<<8) +#define WRPLL_DIVIDER_POST(x) ((x) << 8) +#define WRPLL_DIVIDER_POST_MASK (0x3f << 8) #define WRPLL_DIVIDER_POST_SHIFT 8 -#define WRPLL_DIVIDER_FEEDBACK(x) ((x)<<16) +#define WRPLL_DIVIDER_FEEDBACK(x) ((x) << 16) #define WRPLL_DIVIDER_FB_SHIFT 16 -#define WRPLL_DIVIDER_FB_MASK (0xff<<16) +#define WRPLL_DIVIDER_FB_MASK (0xff << 16) /* Port clock selection */ #define _PORT_CLK_SEL_A 0x46100 #define _PORT_CLK_SEL_B 0x46104 #define PORT_CLK_SEL(port) _MMIO_PORT(port, _PORT_CLK_SEL_A, _PORT_CLK_SEL_B) -#define PORT_CLK_SEL_LCPLL_2700 (0<<29) -#define PORT_CLK_SEL_LCPLL_1350 (1<<29) -#define PORT_CLK_SEL_LCPLL_810 (2<<29) -#define PORT_CLK_SEL_SPLL (3<<29) -#define PORT_CLK_SEL_WRPLL(pll) (((pll)+4)<<29) -#define PORT_CLK_SEL_WRPLL1 (4<<29) -#define PORT_CLK_SEL_WRPLL2 (5<<29) -#define PORT_CLK_SEL_NONE (7<<29) -#define PORT_CLK_SEL_MASK (7<<29) +#define PORT_CLK_SEL_LCPLL_2700 (0 << 29) +#define PORT_CLK_SEL_LCPLL_1350 (1 << 29) +#define PORT_CLK_SEL_LCPLL_810 (2 << 29) +#define PORT_CLK_SEL_SPLL (3 << 29) +#define PORT_CLK_SEL_WRPLL(pll) (((pll) + 4) << 29) +#define PORT_CLK_SEL_WRPLL1 (4 << 29) +#define PORT_CLK_SEL_WRPLL2 (5 << 29) +#define PORT_CLK_SEL_NONE (7 << 29) +#define PORT_CLK_SEL_MASK (7 << 29) /* On ICL+ this is the same as PORT_CLK_SEL, but all bits change. */ #define DDI_CLK_SEL(port) PORT_CLK_SEL(port) @@ -8854,8 +8854,8 @@ enum skl_power_gate { #define _TRANS_CLK_SEL_B 0x46144 #define TRANS_CLK_SEL(tran) _MMIO_TRANS(tran, _TRANS_CLK_SEL_A, _TRANS_CLK_SEL_B) /* For each transcoder, we need to select the corresponding port clock */ -#define TRANS_CLK_SEL_DISABLED (0x0<<29) -#define TRANS_CLK_SEL_PORT(x) (((x)+1)<<29) +#define TRANS_CLK_SEL_DISABLED (0x0 << 29) +#define TRANS_CLK_SEL_PORT(x) (((x) + 1) << 29) #define CDCLK_FREQ _MMIO(0x46200) @@ -8865,28 +8865,28 @@ enum skl_power_gate { #define _TRANS_EDP_MSA_MISC 0x6f410 #define TRANS_MSA_MISC(tran) _MMIO_TRANS2(tran, _TRANSA_MSA_MISC) -#define TRANS_MSA_SYNC_CLK (1<<0) -#define TRANS_MSA_6_BPC (0<<5) -#define TRANS_MSA_8_BPC (1<<5) -#define TRANS_MSA_10_BPC (2<<5) -#define TRANS_MSA_12_BPC (3<<5) -#define TRANS_MSA_16_BPC (4<<5) +#define TRANS_MSA_SYNC_CLK (1 << 0) +#define TRANS_MSA_6_BPC (0 << 5) +#define TRANS_MSA_8_BPC (1 << 5) +#define TRANS_MSA_10_BPC (2 << 5) +#define TRANS_MSA_12_BPC (3 << 5) +#define TRANS_MSA_16_BPC (4 << 5) /* LCPLL Control */ #define LCPLL_CTL _MMIO(0x130040) -#define LCPLL_PLL_DISABLE (1<<31) -#define LCPLL_PLL_LOCK (1<<30) -#define LCPLL_CLK_FREQ_MASK (3<<26) -#define LCPLL_CLK_FREQ_450 (0<<26) -#define LCPLL_CLK_FREQ_54O_BDW (1<<26) -#define LCPLL_CLK_FREQ_337_5_BDW (2<<26) -#define LCPLL_CLK_FREQ_675_BDW (3<<26) -#define LCPLL_CD_CLOCK_DISABLE (1<<25) -#define LCPLL_ROOT_CD_CLOCK_DISABLE (1<<24) -#define LCPLL_CD2X_CLOCK_DISABLE (1<<23) -#define LCPLL_POWER_DOWN_ALLOW (1<<22) -#define LCPLL_CD_SOURCE_FCLK (1<<21) -#define LCPLL_CD_SOURCE_FCLK_DONE (1<<19) +#define LCPLL_PLL_DISABLE (1 << 31) +#define LCPLL_PLL_LOCK (1 << 30) +#define LCPLL_CLK_FREQ_MASK (3 << 26) +#define LCPLL_CLK_FREQ_450 (0 << 26) +#define LCPLL_CLK_FREQ_54O_BDW (1 << 26) +#define LCPLL_CLK_FREQ_337_5_BDW (2 << 26) +#define LCPLL_CLK_FREQ_675_BDW (3 << 26) +#define LCPLL_CD_CLOCK_DISABLE (1 << 25) +#define LCPLL_ROOT_CD_CLOCK_DISABLE (1 << 24) +#define LCPLL_CD2X_CLOCK_DISABLE (1 << 23) +#define LCPLL_POWER_DOWN_ALLOW (1 << 22) +#define LCPLL_CD_SOURCE_FCLK (1 << 21) +#define LCPLL_CD_SOURCE_FCLK_DONE (1 << 19) /* * SKL Clocks @@ -8914,16 +8914,16 @@ enum skl_power_gate { /* LCPLL_CTL */ #define LCPLL1_CTL _MMIO(0x46010) #define LCPLL2_CTL _MMIO(0x46014) -#define LCPLL_PLL_ENABLE (1<<31) +#define LCPLL_PLL_ENABLE (1 << 31) /* DPLL control1 */ #define DPLL_CTRL1 _MMIO(0x6C058) -#define DPLL_CTRL1_HDMI_MODE(id) (1<<((id)*6+5)) -#define DPLL_CTRL1_SSC(id) (1<<((id)*6+4)) -#define DPLL_CTRL1_LINK_RATE_MASK(id) (7<<((id)*6+1)) -#define DPLL_CTRL1_LINK_RATE_SHIFT(id) ((id)*6+1) -#define DPLL_CTRL1_LINK_RATE(linkrate, id) ((linkrate)<<((id)*6+1)) -#define DPLL_CTRL1_OVERRIDE(id) (1<<((id)*6)) +#define DPLL_CTRL1_HDMI_MODE(id) (1 << ((id) * 6 + 5)) +#define DPLL_CTRL1_SSC(id) (1 << ((id) * 6 + 4)) +#define DPLL_CTRL1_LINK_RATE_MASK(id) (7 << ((id) * 6 + 1)) +#define DPLL_CTRL1_LINK_RATE_SHIFT(id) ((id) * 6 + 1) +#define DPLL_CTRL1_LINK_RATE(linkrate, id) ((linkrate) << ((id) * 6 + 1)) +#define DPLL_CTRL1_OVERRIDE(id) (1 << ((id) * 6)) #define DPLL_CTRL1_LINK_RATE_2700 0 #define DPLL_CTRL1_LINK_RATE_1350 1 #define DPLL_CTRL1_LINK_RATE_810 2 @@ -8933,43 +8933,43 @@ enum skl_power_gate { /* DPLL control2 */ #define DPLL_CTRL2 _MMIO(0x6C05C) -#define DPLL_CTRL2_DDI_CLK_OFF(port) (1<<((port)+15)) -#define DPLL_CTRL2_DDI_CLK_SEL_MASK(port) (3<<((port)*3+1)) -#define DPLL_CTRL2_DDI_CLK_SEL_SHIFT(port) ((port)*3+1) -#define DPLL_CTRL2_DDI_CLK_SEL(clk, port) ((clk)<<((port)*3+1)) -#define DPLL_CTRL2_DDI_SEL_OVERRIDE(port) (1<<((port)*3)) +#define DPLL_CTRL2_DDI_CLK_OFF(port) (1 << ((port) + 15)) +#define DPLL_CTRL2_DDI_CLK_SEL_MASK(port) (3 << ((port) * 3 + 1)) +#define DPLL_CTRL2_DDI_CLK_SEL_SHIFT(port) ((port) * 3 + 1) +#define DPLL_CTRL2_DDI_CLK_SEL(clk, port) ((clk) << ((port) * 3 + 1)) +#define DPLL_CTRL2_DDI_SEL_OVERRIDE(port) (1 << ((port) * 3)) /* DPLL Status */ #define DPLL_STATUS _MMIO(0x6C060) -#define DPLL_LOCK(id) (1<<((id)*8)) +#define DPLL_LOCK(id) (1 << ((id) * 8)) /* DPLL cfg */ #define _DPLL1_CFGCR1 0x6C040 #define _DPLL2_CFGCR1 0x6C048 #define _DPLL3_CFGCR1 0x6C050 -#define DPLL_CFGCR1_FREQ_ENABLE (1<<31) -#define DPLL_CFGCR1_DCO_FRACTION_MASK (0x7fff<<9) -#define DPLL_CFGCR1_DCO_FRACTION(x) ((x)<<9) +#define DPLL_CFGCR1_FREQ_ENABLE (1 << 31) +#define DPLL_CFGCR1_DCO_FRACTION_MASK (0x7fff << 9) +#define DPLL_CFGCR1_DCO_FRACTION(x) ((x) << 9) #define DPLL_CFGCR1_DCO_INTEGER_MASK (0x1ff) #define _DPLL1_CFGCR2 0x6C044 #define _DPLL2_CFGCR2 0x6C04C #define _DPLL3_CFGCR2 0x6C054 -#define DPLL_CFGCR2_QDIV_RATIO_MASK (0xff<<8) -#define DPLL_CFGCR2_QDIV_RATIO(x) ((x)<<8) -#define DPLL_CFGCR2_QDIV_MODE(x) ((x)<<7) -#define DPLL_CFGCR2_KDIV_MASK (3<<5) -#define DPLL_CFGCR2_KDIV(x) ((x)<<5) -#define DPLL_CFGCR2_KDIV_5 (0<<5) -#define DPLL_CFGCR2_KDIV_2 (1<<5) -#define DPLL_CFGCR2_KDIV_3 (2<<5) -#define DPLL_CFGCR2_KDIV_1 (3<<5) -#define DPLL_CFGCR2_PDIV_MASK (7<<2) -#define DPLL_CFGCR2_PDIV(x) ((x)<<2) -#define DPLL_CFGCR2_PDIV_1 (0<<2) -#define DPLL_CFGCR2_PDIV_2 (1<<2) -#define DPLL_CFGCR2_PDIV_3 (2<<2) -#define DPLL_CFGCR2_PDIV_7 (4<<2) +#define DPLL_CFGCR2_QDIV_RATIO_MASK (0xff << 8) +#define DPLL_CFGCR2_QDIV_RATIO(x) ((x) << 8) +#define DPLL_CFGCR2_QDIV_MODE(x) ((x) << 7) +#define DPLL_CFGCR2_KDIV_MASK (3 << 5) +#define DPLL_CFGCR2_KDIV(x) ((x) << 5) +#define DPLL_CFGCR2_KDIV_5 (0 << 5) +#define DPLL_CFGCR2_KDIV_2 (1 << 5) +#define DPLL_CFGCR2_KDIV_3 (2 << 5) +#define DPLL_CFGCR2_KDIV_1 (3 << 5) +#define DPLL_CFGCR2_PDIV_MASK (7 << 2) +#define DPLL_CFGCR2_PDIV(x) ((x) << 2) +#define DPLL_CFGCR2_PDIV_1 (0 << 2) +#define DPLL_CFGCR2_PDIV_2 (1 << 2) +#define DPLL_CFGCR2_PDIV_3 (2 << 2) +#define DPLL_CFGCR2_PDIV_7 (4 << 2) #define DPLL_CFGCR2_CENTRAL_FREQ_MASK (3) #define DPLL_CFGCR1(id) _MMIO_PIPE((id) - SKL_DPLL1, _DPLL1_CFGCR1, _DPLL2_CFGCR1) @@ -8981,9 +8981,9 @@ enum skl_power_gate { #define DPCLKA_CFGCR0 _MMIO(0x6C200) #define DPCLKA_CFGCR0_ICL _MMIO(0x164280) #define DPCLKA_CFGCR0_DDI_CLK_OFF(port) (1 << ((port) == PORT_F ? 23 : \ - (port)+10)) + (port) + 10)) #define DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(port) ((port) == PORT_F ? 21 : \ - (port)*2) + (port) * 2) #define DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port) (3 << DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(port)) #define DPCLKA_CFGCR0_DDI_CLK_SEL(pll, port) ((pll) << DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(port)) @@ -9196,22 +9196,22 @@ enum skl_power_gate { /* GEN9 DC */ #define DC_STATE_EN _MMIO(0x45504) #define DC_STATE_DISABLE 0 -#define DC_STATE_EN_UPTO_DC5 (1<<0) -#define DC_STATE_EN_DC9 (1<<3) -#define DC_STATE_EN_UPTO_DC6 (2<<0) +#define DC_STATE_EN_UPTO_DC5 (1 << 0) +#define DC_STATE_EN_DC9 (1 << 3) +#define DC_STATE_EN_UPTO_DC6 (2 << 0) #define DC_STATE_EN_UPTO_DC5_DC6_MASK 0x3 #define DC_STATE_DEBUG _MMIO(0x45520) -#define DC_STATE_DEBUG_MASK_CORES (1<<0) -#define DC_STATE_DEBUG_MASK_MEMORY_UP (1<<1) +#define DC_STATE_DEBUG_MASK_CORES (1 << 0) +#define DC_STATE_DEBUG_MASK_MEMORY_UP (1 << 1) /* Please see hsw_read_dcomp() and hsw_write_dcomp() before using this register, * since on HSW we can't write to it using I915_WRITE. */ #define D_COMP_HSW _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5F0C) #define D_COMP_BDW _MMIO(0x138144) -#define D_COMP_RCOMP_IN_PROGRESS (1<<9) -#define D_COMP_COMP_FORCE (1<<8) -#define D_COMP_COMP_DISABLE (1<<0) +#define D_COMP_RCOMP_IN_PROGRESS (1 << 9) +#define D_COMP_COMP_FORCE (1 << 8) +#define D_COMP_COMP_DISABLE (1 << 0) /* Pipe WM_LINETIME - watermark line time */ #define _PIPE_WM_LINETIME_A 0x45270 @@ -9219,27 +9219,27 @@ enum skl_power_gate { #define PIPE_WM_LINETIME(pipe) _MMIO_PIPE(pipe, _PIPE_WM_LINETIME_A, _PIPE_WM_LINETIME_B) #define PIPE_WM_LINETIME_MASK (0x1ff) #define PIPE_WM_LINETIME_TIME(x) ((x)) -#define PIPE_WM_LINETIME_IPS_LINETIME_MASK (0x1ff<<16) -#define PIPE_WM_LINETIME_IPS_LINETIME(x) ((x)<<16) +#define PIPE_WM_LINETIME_IPS_LINETIME_MASK (0x1ff << 16) +#define PIPE_WM_LINETIME_IPS_LINETIME(x) ((x) << 16) /* SFUSE_STRAP */ #define SFUSE_STRAP _MMIO(0xc2014) -#define SFUSE_STRAP_FUSE_LOCK (1<<13) -#define SFUSE_STRAP_RAW_FREQUENCY (1<<8) -#define SFUSE_STRAP_DISPLAY_DISABLED (1<<7) -#define SFUSE_STRAP_CRT_DISABLED (1<<6) -#define SFUSE_STRAP_DDIF_DETECTED (1<<3) -#define SFUSE_STRAP_DDIB_DETECTED (1<<2) -#define SFUSE_STRAP_DDIC_DETECTED (1<<1) -#define SFUSE_STRAP_DDID_DETECTED (1<<0) +#define SFUSE_STRAP_FUSE_LOCK (1 << 13) +#define SFUSE_STRAP_RAW_FREQUENCY (1 << 8) +#define SFUSE_STRAP_DISPLAY_DISABLED (1 << 7) +#define SFUSE_STRAP_CRT_DISABLED (1 << 6) +#define SFUSE_STRAP_DDIF_DETECTED (1 << 3) +#define SFUSE_STRAP_DDIB_DETECTED (1 << 2) +#define SFUSE_STRAP_DDIC_DETECTED (1 << 1) +#define SFUSE_STRAP_DDID_DETECTED (1 << 0) #define WM_MISC _MMIO(0x45260) #define WM_MISC_DATA_PARTITION_5_6 (1 << 0) #define WM_DBG _MMIO(0x45280) -#define WM_DBG_DISALLOW_MULTIPLE_LP (1<<0) -#define WM_DBG_DISALLOW_MAXFIFO (1<<1) -#define WM_DBG_DISALLOW_SPRITE (1<<2) +#define WM_DBG_DISALLOW_MULTIPLE_LP (1 << 0) +#define WM_DBG_DISALLOW_MAXFIFO (1 << 1) +#define WM_DBG_DISALLOW_SPRITE (1 << 2) /* pipe CSC */ #define _PIPE_A_CSC_COEFF_RY_GY 0x49010 -- GitLab From af7187b784432d62cb2059d65ef91b7e0aa77a4f Mon Sep 17 00:00:00 2001 From: Paulo Zanoni <paulo.r.zanoni@intel.com> Date: Tue, 12 Jun 2018 16:56:53 -0700 Subject: [PATCH 0423/1506] drm/i915/i915_reg.h: fix the checkpatch SPACE_BEFORE_TAB issues Since I'm touching the file I might as well fix this class of errors since they are just a few. Also drive-by fix the styling of the VLV_TURBO_SOC_OVERRIDE definitions instead of just the spaces before the tabs. Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180612235654.7914-3-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index b0dd26fc1ee3e..1bf3bdc61e455 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1142,11 +1142,11 @@ enum i915_power_well_id { #define FB_FMAX_VMIN_FREQ_LO_SHIFT 27 #define FB_FMAX_VMIN_FREQ_LO_MASK 0xf8000000 -#define VLV_TURBO_SOC_OVERRIDE 0x04 -#define VLV_OVERRIDE_EN 1 -#define VLV_SOC_TDP_EN (1 << 1) -#define VLV_BIAS_CPU_125_SOC_875 (6 << 2) -#define CHV_BIAS_CPU_50_SOC_50 (3 << 2) +#define VLV_TURBO_SOC_OVERRIDE 0x04 +#define VLV_OVERRIDE_EN 1 +#define VLV_SOC_TDP_EN (1 << 1) +#define VLV_BIAS_CPU_125_SOC_875 (6 << 2) +#define CHV_BIAS_CPU_50_SOC_50 (3 << 2) /* vlv2 north clock has */ #define CCK_FUSE_REG 0x8 @@ -2413,7 +2413,7 @@ enum i915_power_well_id { #define DERRMR_PIPEA_SPR_FLIP_DONE (1 << 2) #define DERRMR_PIPEA_VBLANK (1 << 3) #define DERRMR_PIPEA_HBLANK (1 << 5) -#define DERRMR_PIPEB_SCANLINE (1 << 8) +#define DERRMR_PIPEB_SCANLINE (1 << 8) #define DERRMR_PIPEB_PRI_FLIP_DONE (1 << 9) #define DERRMR_PIPEB_SPR_FLIP_DONE (1 << 10) #define DERRMR_PIPEB_VBLANK (1 << 11) @@ -7573,7 +7573,7 @@ enum { #define TRANS_VBLANK_END_SHIFT 16 #define TRANS_VBLANK_START_SHIFT 0 #define _PCH_TRANS_VSYNC_A 0xe0014 -#define TRANS_VSYNC_END_SHIFT 16 +#define TRANS_VSYNC_END_SHIFT 16 #define TRANS_VSYNC_START_SHIFT 0 #define _PCH_TRANS_VSYNCSHIFT_A 0xe0028 -- GitLab From 9e8789ec967a2d524bcfc79c47a85d08dfbe626a Mon Sep 17 00:00:00 2001 From: Paulo Zanoni <paulo.r.zanoni@intel.com> Date: Tue, 12 Jun 2018 16:56:54 -0700 Subject: [PATCH 0424/1506] drm/i915/i915_reg.h: fix the checkpatch MACRO_ARG_PRECEDENCE issues While I don't see any issue with the way these macros are being called today, let's protect them against operator precedence issues before they happen. Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180612235654.7914-4-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 42 ++++++++++++++++----------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 1bf3bdc61e455..50fe3b27ec941 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1780,7 +1780,7 @@ enum i915_power_well_id { #define CNL_PORT_TX_DW4_GRP(port) _MMIO(_CNL_PORT_TX_DW_GRP((port), 4)) #define CNL_PORT_TX_DW4_LN0(port) _MMIO(_CNL_PORT_TX_DW_LN0((port), 4)) #define CNL_PORT_TX_DW4_LN(port, ln) _MMIO(_CNL_PORT_TX_DW_LN0((port), 4) + \ - (ln * (_CNL_PORT_TX_DW4_LN1_AE - \ + ((ln) * (_CNL_PORT_TX_DW4_LN1_AE - \ _CNL_PORT_TX_DW4_LN0_AE))) #define _ICL_PORT_TX_DW4_GRP_A 0x162690 #define _ICL_PORT_TX_DW4_GRP_B 0x6C690 @@ -1793,8 +1793,8 @@ enum i915_power_well_id { #define ICL_PORT_TX_DW4_LN(port, ln) _MMIO(_PORT(port, \ _ICL_PORT_TX_DW4_LN0_A, \ _ICL_PORT_TX_DW4_LN0_B) + \ - (ln * (_ICL_PORT_TX_DW4_LN1_A - \ - _ICL_PORT_TX_DW4_LN0_A))) + ((ln) * (_ICL_PORT_TX_DW4_LN1_A - \ + _ICL_PORT_TX_DW4_LN0_A))) #define LOADGEN_SELECT (1 << 31) #define POST_CURSOR_1(x) ((x) << 12) #define POST_CURSOR_1_MASK (0x3F << 12) @@ -6076,8 +6076,8 @@ enum { /* Display/Sprite base address macros */ #define DISP_BASEADDR_MASK (0xfffff000) -#define I915_LO_DISPBASE(val) (val & ~DISP_BASEADDR_MASK) -#define I915_HI_DISPBASE(val) (val & DISP_BASEADDR_MASK) +#define I915_LO_DISPBASE(val) ((val) & ~DISP_BASEADDR_MASK) +#define I915_HI_DISPBASE(val) ((val) & DISP_BASEADDR_MASK) /* * VBIOS flags @@ -7091,7 +7091,7 @@ enum { #define GEN11_VECS(x) (31 - (x)) #define GEN11_VCS(x) (x) -#define GEN11_GT_INTR_DW(x) _MMIO(0x190018 + (x * 4)) +#define GEN11_GT_INTR_DW(x) _MMIO(0x190018 + ((x) * 4)) #define GEN11_INTR_IDENTITY_REG0 _MMIO(0x190060) #define GEN11_INTR_IDENTITY_REG1 _MMIO(0x190064) @@ -7100,12 +7100,12 @@ enum { #define GEN11_INTR_ENGINE_INSTANCE(x) (((x) & GENMASK(25, 20)) >> 20) #define GEN11_INTR_ENGINE_INTR(x) ((x) & 0xffff) -#define GEN11_INTR_IDENTITY_REG(x) _MMIO(0x190060 + (x * 4)) +#define GEN11_INTR_IDENTITY_REG(x) _MMIO(0x190060 + ((x) * 4)) #define GEN11_IIR_REG0_SELECTOR _MMIO(0x190070) #define GEN11_IIR_REG1_SELECTOR _MMIO(0x190074) -#define GEN11_IIR_REG_SELECTOR(x) _MMIO(0x190070 + (x * 4)) +#define GEN11_IIR_REG_SELECTOR(x) _MMIO(0x190070 + ((x) * 4)) #define GEN11_RENDER_COPY_INTR_ENABLE _MMIO(0x190030) #define GEN11_VCS_VECS_INTR_ENABLE _MMIO(0x190034) @@ -7497,15 +7497,15 @@ enum { #define _PCH_DPLL_A 0xc6014 #define _PCH_DPLL_B 0xc6018 -#define PCH_DPLL(pll) _MMIO(pll == 0 ? _PCH_DPLL_A : _PCH_DPLL_B) +#define PCH_DPLL(pll) _MMIO((pll) == 0 ? _PCH_DPLL_A : _PCH_DPLL_B) #define _PCH_FPA0 0xc6040 #define FP_CB_TUNE (0x3 << 22) #define _PCH_FPA1 0xc6044 #define _PCH_FPB0 0xc6048 #define _PCH_FPB1 0xc604c -#define PCH_FP0(pll) _MMIO(pll == 0 ? _PCH_FPA0 : _PCH_FPB0) -#define PCH_FP1(pll) _MMIO(pll == 0 ? _PCH_FPA1 : _PCH_FPB1) +#define PCH_FP0(pll) _MMIO((pll) == 0 ? _PCH_FPA0 : _PCH_FPB0) +#define PCH_FP1(pll) _MMIO((pll) == 0 ? _PCH_FPA1 : _PCH_FPB1) #define PCH_DPLL_TEST _MMIO(0xc606c) @@ -8337,11 +8337,11 @@ enum { #define GEN7_L3CDERRST1_BANK_MASK (3 << 11) #define GEN7_L3CDERRST1_SUBBANK_MASK (7 << 8) #define GEN7_PARITY_ERROR_ROW(reg) \ - ((reg & GEN7_L3CDERRST1_ROW_MASK) >> 14) + (((reg) & GEN7_L3CDERRST1_ROW_MASK) >> 14) #define GEN7_PARITY_ERROR_BANK(reg) \ - ((reg & GEN7_L3CDERRST1_BANK_MASK) >> 11) + (((reg) & GEN7_L3CDERRST1_BANK_MASK) >> 11) #define GEN7_PARITY_ERROR_SUBBANK(reg) \ - ((reg & GEN7_L3CDERRST1_SUBBANK_MASK) >> 8) + (((reg) & GEN7_L3CDERRST1_SUBBANK_MASK) >> 8) #define GEN7_L3CDERRST1_ENABLE (1 << 7) #define GEN7_L3LOG(slice, i) _MMIO(0xB070 + (slice) * 0x200 + (i) * 4) @@ -8614,7 +8614,7 @@ enum skl_power_gate { #define HDCP_SHA_V_PRIME_H2 _MMIO(0x66d0C) #define HDCP_SHA_V_PRIME_H3 _MMIO(0x66d10) #define HDCP_SHA_V_PRIME_H4 _MMIO(0x66d14) -#define HDCP_SHA_V_PRIME(h) _MMIO((0x66d04 + h * 4)) +#define HDCP_SHA_V_PRIME(h) _MMIO((0x66d04 + (h) * 4)) #define HDCP_SHA_TEXT _MMIO(0x66d18) /* HDCP Auth Registers */ @@ -8630,7 +8630,7 @@ enum skl_power_gate { _PORTC_HDCP_AUTHENC, \ _PORTD_HDCP_AUTHENC, \ _PORTE_HDCP_AUTHENC, \ - _PORTF_HDCP_AUTHENC) + x) + _PORTF_HDCP_AUTHENC) + (x)) #define PORT_HDCP_CONF(port) _PORT_HDCP_AUTHENC(port, 0x0) #define HDCP_CONF_CAPTURE_AN BIT(0) #define HDCP_CONF_AUTH_AND_ENC (BIT(1) | BIT(0)) @@ -8651,7 +8651,7 @@ enum skl_power_gate { #define HDCP_STATUS_R0_READY BIT(18) #define HDCP_STATUS_AN_READY BIT(17) #define HDCP_STATUS_CIPHER BIT(16) -#define HDCP_STATUS_FRAME_CNT(x) ((x >> 8) & 0xff) +#define HDCP_STATUS_FRAME_CNT(x) (((x) >> 8) & 0xff) /* Per-pipe DDI Function Control */ #define _TRANS_DDI_FUNC_CTL_A 0x60400 @@ -9402,7 +9402,7 @@ enum skl_power_gate { _MIPI_PORT(port, BXT_MIPI1_TX_ESCLK_FIXDIV_MASK, \ BXT_MIPI2_TX_ESCLK_FIXDIV_MASK) #define BXT_MIPI_TX_ESCLK_DIVIDER(port, val) \ - ((val & 0x3F) << BXT_MIPI_TX_ESCLK_SHIFT(port)) + (((val) & 0x3F) << BXT_MIPI_TX_ESCLK_SHIFT(port)) /* RX upper control divider to select actual RX clock output from 8x */ #define BXT_MIPI1_RX_ESCLK_UPPER_SHIFT 21 #define BXT_MIPI2_RX_ESCLK_UPPER_SHIFT 5 @@ -9415,7 +9415,7 @@ enum skl_power_gate { _MIPI_PORT(port, BXT_MIPI1_RX_ESCLK_UPPER_FIXDIV_MASK, \ BXT_MIPI2_RX_ESCLK_UPPER_FIXDIV_MASK) #define BXT_MIPI_RX_ESCLK_UPPER_DIVIDER(port, val) \ - ((val & 3) << BXT_MIPI_RX_ESCLK_UPPER_SHIFT(port)) + (((val) & 3) << BXT_MIPI_RX_ESCLK_UPPER_SHIFT(port)) /* 8/3X divider to select the actual 8/3X clock output from 8x */ #define BXT_MIPI1_8X_BY3_SHIFT 19 #define BXT_MIPI2_8X_BY3_SHIFT 3 @@ -9428,7 +9428,7 @@ enum skl_power_gate { _MIPI_PORT(port, BXT_MIPI1_8X_BY3_DIVIDER_MASK, \ BXT_MIPI2_8X_BY3_DIVIDER_MASK) #define BXT_MIPI_8X_BY3_DIVIDER(port, val) \ - ((val & 3) << BXT_MIPI_8X_BY3_SHIFT(port)) + (((val) & 3) << BXT_MIPI_8X_BY3_SHIFT(port)) /* RX lower control divider to select actual RX clock output from 8x */ #define BXT_MIPI1_RX_ESCLK_LOWER_SHIFT 16 #define BXT_MIPI2_RX_ESCLK_LOWER_SHIFT 0 @@ -9441,7 +9441,7 @@ enum skl_power_gate { _MIPI_PORT(port, BXT_MIPI1_RX_ESCLK_LOWER_FIXDIV_MASK, \ BXT_MIPI2_RX_ESCLK_LOWER_FIXDIV_MASK) #define BXT_MIPI_RX_ESCLK_LOWER_DIVIDER(port, val) \ - ((val & 3) << BXT_MIPI_RX_ESCLK_LOWER_SHIFT(port)) + (((val) & 3) << BXT_MIPI_RX_ESCLK_LOWER_SHIFT(port)) #define RX_DIVIDER_BIT_1_2 0x3 #define RX_DIVIDER_BIT_3_4 0xC -- GitLab From df0d28c185ad29d539826a8eb8b651ea9c46051d Mon Sep 17 00:00:00 2001 From: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Date: Fri, 15 Jun 2018 17:05:28 -0700 Subject: [PATCH 0425/1506] drm/i915/icl: GSE interrupt moves from DE_MISC to GU_MISC The Graphics System Event(GSE) interrupt bit has a new location in the GU_MISC_INTERRUPT_{IIR, ISR, IMR, IER} registers. Since GSE was the only DE_MISC interrupt that was enabled, with this change we don't enable/handle any of DE_MISC interrupts for gen11. Credits to Paulo for pointing out the register change. v2: from DK raw_reg_[read/write], branch prediction hint and drop platform check (Mika) v3: From DK Early re-enable of master interrupt (Chris) Cc: Chris Wilson <chris@chris-wilson.co.uk> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> [Paulo: bikesheds and rebases] Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180616000530.5357-1-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/i915_irq.c | 46 ++++++++++++++++++++++++++++++++- drivers/gpu/drm/i915/i915_reg.h | 7 +++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index d5aee0b74f4b4..64d5e10a4de88 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2954,11 +2954,44 @@ gen11_gt_irq_handler(struct drm_i915_private * const i915, spin_unlock(&i915->irq_lock); } +static void +gen11_gu_misc_irq_ack(struct drm_i915_private *dev_priv, const u32 master_ctl, + u32 *iir) +{ + void __iomem * const regs = dev_priv->regs; + + if (!(master_ctl & GEN11_GU_MISC_IRQ)) + return; + + *iir = raw_reg_read(regs, GEN11_GU_MISC_IIR); + if (likely(*iir)) + raw_reg_write(regs, GEN11_GU_MISC_IIR, *iir); +} + +static void +gen11_gu_misc_irq_handler(struct drm_i915_private *dev_priv, + const u32 master_ctl, const u32 iir) +{ + if (!(master_ctl & GEN11_GU_MISC_IRQ)) + return; + + if (unlikely(!iir)) { + DRM_ERROR("GU_MISC iir blank!\n"); + return; + } + + if (iir & GEN11_GU_MISC_GSE) + intel_opregion_asle_intr(dev_priv); + else + DRM_ERROR("Unexpected GU_MISC interrupt 0x%x\n", iir); +} + static irqreturn_t gen11_irq_handler(int irq, void *arg) { struct drm_i915_private * const i915 = to_i915(arg); void __iomem * const regs = i915->regs; u32 master_ctl; + u32 gu_misc_iir; if (!intel_irqs_enabled(i915)) return IRQ_NONE; @@ -2987,9 +3020,13 @@ static irqreturn_t gen11_irq_handler(int irq, void *arg) enable_rpm_wakeref_asserts(i915); } + gen11_gu_misc_irq_ack(i915, master_ctl, &gu_misc_iir); + /* Acknowledge and enable interrupts. */ raw_reg_write(regs, GEN11_GFX_MSTR_IRQ, GEN11_MASTER_IRQ | master_ctl); + gen11_gu_misc_irq_handler(i915, master_ctl, gu_misc_iir); + return IRQ_HANDLED; } @@ -3476,6 +3513,7 @@ static void gen11_irq_reset(struct drm_device *dev) GEN3_IRQ_RESET(GEN8_DE_PORT_); GEN3_IRQ_RESET(GEN8_DE_MISC_); + GEN3_IRQ_RESET(GEN11_GU_MISC_); GEN3_IRQ_RESET(GEN8_PCU_); } @@ -3919,9 +3957,12 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv) uint32_t de_pipe_enables; u32 de_port_masked = GEN8_AUX_CHANNEL_A; u32 de_port_enables; - u32 de_misc_masked = GEN8_DE_MISC_GSE | GEN8_DE_EDP_PSR; + u32 de_misc_masked = GEN8_DE_EDP_PSR; enum pipe pipe; + if (INTEL_GEN(dev_priv) <= 10) + de_misc_masked |= GEN8_DE_MISC_GSE; + if (INTEL_GEN(dev_priv) >= 9) { de_pipe_masked |= GEN9_DE_PIPE_IRQ_FAULT_ERRORS; de_port_masked |= GEN9_AUX_CHANNEL_B | GEN9_AUX_CHANNEL_C | @@ -4018,10 +4059,13 @@ static void gen11_gt_irq_postinstall(struct drm_i915_private *dev_priv) static int gen11_irq_postinstall(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + u32 gu_misc_masked = GEN11_GU_MISC_GSE; gen11_gt_irq_postinstall(dev_priv); gen8_de_irq_postinstall(dev_priv); + GEN3_IRQ_INIT(GEN11_GU_MISC_, ~gu_misc_masked, gu_misc_masked); + I915_WRITE(GEN11_DISPLAY_INT_CTL, GEN11_DISPLAY_IRQ_ENABLE); I915_WRITE(GEN11_GFX_MSTR_IRQ, GEN11_MASTER_IRQ); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 50fe3b27ec941..aed5ef9a95cb4 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -7059,9 +7059,16 @@ enum { #define GEN8_PCU_IIR _MMIO(0x444e8) #define GEN8_PCU_IER _MMIO(0x444ec) +#define GEN11_GU_MISC_ISR _MMIO(0x444f0) +#define GEN11_GU_MISC_IMR _MMIO(0x444f4) +#define GEN11_GU_MISC_IIR _MMIO(0x444f8) +#define GEN11_GU_MISC_IER _MMIO(0x444fc) +#define GEN11_GU_MISC_GSE (1 << 27) + #define GEN11_GFX_MSTR_IRQ _MMIO(0x190010) #define GEN11_MASTER_IRQ (1 << 31) #define GEN11_PCU_IRQ (1 << 30) +#define GEN11_GU_MISC_IRQ (1 << 29) #define GEN11_DISPLAY_IRQ (1 << 16) #define GEN11_GT_DW_IRQ(x) (1 << (x)) #define GEN11_GT_DW1_IRQ (1 << 1) -- GitLab From 121e758ee5782b31fa5ecf23a3828f86167d36cc Mon Sep 17 00:00:00 2001 From: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Date: Fri, 15 Jun 2018 17:05:29 -0700 Subject: [PATCH 0426/1506] drm/i915/icl: Support for TC North Display interrupts The hotplug interrupts for the ports can be routed to either North Display or South Display depending on the output mode. DP Alternate or DP over TBT outputs will have hotplug interrupts routed to the North Display while interrupts for legacy modes will be routed to the South Display in PCH. This patch adds hotplug interrupt handling support for DP Alternate mode. Cc: Jani Nikula <jani.nikula@intel.com> Cc: Anusha Srivatsa <anusha.srivatsa@intel.com> Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> [Paulo: coding style changes] Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180616000530.5357-2-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/i915_irq.c | 95 +++++++++++++++++++++++++++++++-- drivers/gpu/drm/i915/i915_reg.h | 20 +++++++ 2 files changed, 112 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 64d5e10a4de88..40e563eb3a1f2 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -115,6 +115,13 @@ static const u32 hpd_bxt[HPD_NUM_PINS] = { [HPD_PORT_C] = BXT_DE_PORT_HP_DDIC }; +static const u32 hpd_tc_gen11[HPD_NUM_PINS] = { + [HPD_PORT_C] = GEN11_TC1_HOTPLUG, + [HPD_PORT_D] = GEN11_TC2_HOTPLUG, + [HPD_PORT_E] = GEN11_TC3_HOTPLUG, + [HPD_PORT_F] = GEN11_TC4_HOTPLUG +}; + /* IIR can theoretically queue up two events. Be paranoid. */ #define GEN8_IRQ_RESET_NDX(type, which) do { \ I915_WRITE(GEN8_##type##_IMR(which), 0xffffffff); \ @@ -1549,6 +1556,22 @@ static void gen8_gt_irq_handler(struct drm_i915_private *i915, } } +static bool gen11_port_hotplug_long_detect(enum port port, u32 val) +{ + switch (port) { + case PORT_C: + return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC1); + case PORT_D: + return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC2); + case PORT_E: + return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC3); + case PORT_F: + return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC4); + default: + return false; + } +} + static bool bxt_port_hotplug_long_detect(enum port port, u32 val) { switch (port) { @@ -2598,6 +2621,25 @@ static void bxt_hpd_irq_handler(struct drm_i915_private *dev_priv, intel_hpd_irq_handler(dev_priv, pin_mask, long_mask); } +static void gen11_hpd_irq_handler(struct drm_i915_private *dev_priv, u32 iir) +{ + u32 pin_mask = 0, long_mask = 0; + u32 trigger_tc, dig_hotplug_reg; + + trigger_tc = iir & GEN11_DE_TC_HOTPLUG_MASK; + if (trigger_tc) { + dig_hotplug_reg = I915_READ(GEN11_TC_HOTPLUG_CTL); + I915_WRITE(GEN11_TC_HOTPLUG_CTL, dig_hotplug_reg); + + intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, trigger_tc, + dig_hotplug_reg, hpd_tc_gen11, + gen11_port_hotplug_long_detect); + intel_hpd_irq_handler(dev_priv, pin_mask, long_mask); + } else { + DRM_ERROR("Unexpected DE HPD interrupt 0x%08x\n", iir); + } +} + static irqreturn_t gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl) { @@ -2633,6 +2675,17 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl) DRM_ERROR("The master control interrupt lied (DE MISC)!\n"); } + if (INTEL_GEN(dev_priv) >= 11 && (master_ctl & GEN11_DE_HPD_IRQ)) { + iir = I915_READ(GEN11_DE_HPD_IIR); + if (iir) { + I915_WRITE(GEN11_DE_HPD_IIR, iir); + ret = IRQ_HANDLED; + gen11_hpd_irq_handler(dev_priv, iir); + } else { + DRM_ERROR("The master control interrupt lied, (DE HPD)!\n"); + } + } + if (master_ctl & GEN8_DE_PORT_IRQ) { iir = I915_READ(GEN8_DE_PORT_IIR); if (iir) { @@ -3513,6 +3566,7 @@ static void gen11_irq_reset(struct drm_device *dev) GEN3_IRQ_RESET(GEN8_DE_PORT_); GEN3_IRQ_RESET(GEN8_DE_MISC_); + GEN3_IRQ_RESET(GEN11_DE_HPD_); GEN3_IRQ_RESET(GEN11_GU_MISC_); GEN3_IRQ_RESET(GEN8_PCU_); } @@ -3631,6 +3685,34 @@ static void ibx_hpd_irq_setup(struct drm_i915_private *dev_priv) ibx_hpd_detection_setup(dev_priv); } +static void gen11_hpd_detection_setup(struct drm_i915_private *dev_priv) +{ + u32 hotplug; + + hotplug = I915_READ(GEN11_TC_HOTPLUG_CTL); + hotplug |= GEN11_HOTPLUG_CTL_ENABLE(PORT_TC1) | + GEN11_HOTPLUG_CTL_ENABLE(PORT_TC2) | + GEN11_HOTPLUG_CTL_ENABLE(PORT_TC3) | + GEN11_HOTPLUG_CTL_ENABLE(PORT_TC4); + I915_WRITE(GEN11_TC_HOTPLUG_CTL, hotplug); +} + +static void gen11_hpd_irq_setup(struct drm_i915_private *dev_priv) +{ + u32 hotplug_irqs, enabled_irqs; + u32 val; + + enabled_irqs = intel_hpd_enabled_irqs(dev_priv, hpd_tc_gen11); + hotplug_irqs = GEN11_DE_TC_HOTPLUG_MASK; + + val = I915_READ(GEN11_DE_HPD_IMR); + val &= ~hotplug_irqs; + I915_WRITE(GEN11_DE_HPD_IMR, val); + POSTING_READ(GEN11_DE_HPD_IMR); + + gen11_hpd_detection_setup(dev_priv); +} + static void spt_hpd_detection_setup(struct drm_i915_private *dev_priv) { u32 val, hotplug; @@ -4004,10 +4086,17 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv) GEN3_IRQ_INIT(GEN8_DE_PORT_, ~de_port_masked, de_port_enables); GEN3_IRQ_INIT(GEN8_DE_MISC_, ~de_misc_masked, de_misc_masked); - if (IS_GEN9_LP(dev_priv)) + if (INTEL_GEN(dev_priv) >= 11) { + u32 de_hpd_masked = 0; + u32 de_hpd_enables = GEN11_DE_TC_HOTPLUG_MASK; + + GEN3_IRQ_INIT(GEN11_DE_HPD_, ~de_hpd_masked, de_hpd_enables); + gen11_hpd_detection_setup(dev_priv); + } else if (IS_GEN9_LP(dev_priv)) { bxt_hpd_detection_setup(dev_priv); - else if (IS_BROADWELL(dev_priv)) + } else if (IS_BROADWELL(dev_priv)) { ilk_hpd_detection_setup(dev_priv); + } } static int gen8_irq_postinstall(struct drm_device *dev) @@ -4529,7 +4618,7 @@ void intel_irq_init(struct drm_i915_private *dev_priv) dev->driver->irq_uninstall = gen11_irq_reset; dev->driver->enable_vblank = gen8_enable_vblank; dev->driver->disable_vblank = gen8_disable_vblank; - dev_priv->display.hpd_irq_setup = spt_hpd_irq_setup; + dev_priv->display.hpd_irq_setup = gen11_hpd_irq_setup; } else if (INTEL_GEN(dev_priv) >= 8) { dev->driver->irq_handler = gen8_irq_handler; dev->driver->irq_preinstall = gen8_irq_reset; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index aed5ef9a95cb4..21692228cb814 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -7079,11 +7079,31 @@ enum { #define GEN11_AUDIO_CODEC_IRQ (1 << 24) #define GEN11_DE_PCH_IRQ (1 << 23) #define GEN11_DE_MISC_IRQ (1 << 22) +#define GEN11_DE_HPD_IRQ (1 << 21) #define GEN11_DE_PORT_IRQ (1 << 20) #define GEN11_DE_PIPE_C (1 << 18) #define GEN11_DE_PIPE_B (1 << 17) #define GEN11_DE_PIPE_A (1 << 16) +#define GEN11_DE_HPD_ISR _MMIO(0x44470) +#define GEN11_DE_HPD_IMR _MMIO(0x44474) +#define GEN11_DE_HPD_IIR _MMIO(0x44478) +#define GEN11_DE_HPD_IER _MMIO(0x4447c) +#define GEN11_TC4_HOTPLUG (1 << 19) +#define GEN11_TC3_HOTPLUG (1 << 18) +#define GEN11_TC2_HOTPLUG (1 << 17) +#define GEN11_TC1_HOTPLUG (1 << 16) +#define GEN11_DE_TC_HOTPLUG_MASK (GEN11_TC4_HOTPLUG | \ + GEN11_TC3_HOTPLUG | \ + GEN11_TC2_HOTPLUG | \ + GEN11_TC1_HOTPLUG) + +#define GEN11_TC_HOTPLUG_CTL _MMIO(0x44038) +#define GEN11_HOTPLUG_CTL_ENABLE(tc_port) (8 << (tc_port) * 4) +#define GEN11_HOTPLUG_CTL_LONG_DETECT(tc_port) (2 << (tc_port) * 4) +#define GEN11_HOTPLUG_CTL_SHORT_DETECT(tc_port) (1 << (tc_port) * 4) +#define GEN11_HOTPLUG_CTL_NO_DETECT(tc_port) (0 << (tc_port) * 4) + #define GEN11_GT_INTR_DW0 _MMIO(0x190018) #define GEN11_CSME (31) #define GEN11_GUNIT (28) -- GitLab From b796b9710fd52d7f406f606697322fb5c7f562f3 Mon Sep 17 00:00:00 2001 From: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Date: Fri, 15 Jun 2018 17:05:30 -0700 Subject: [PATCH 0427/1506] drm/i915/icl: Handle hotplug interrupts for DP over TBT This patch enables hotplug interrupts for DP over TBT output on TC ports. The TBT interrupts are enabled and handled irrespective of the actual output type which could be DP Alternate, DP over TBT, native DP or native HDMI. Cc: Animesh Manna <animesh.manna@intel.com> Cc: Paulo Zanoni <paulo.r.zanoni@intel.com> Cc: Anusha Srivatsa <anusha.srivatsa@intel.com> Cc: Manasi Navare <manasi.d.navare@intel.com> Reviewed-by: Lucas De Marchi <lucas.demarchi@intel.com> Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180616000530.5357-3-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/i915_irq.c | 49 ++++++++++++++++++++++++--------- drivers/gpu/drm/i915/i915_reg.h | 11 +++++++- 2 files changed, 46 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 40e563eb3a1f2..46aaef5c1851e 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -115,11 +115,11 @@ static const u32 hpd_bxt[HPD_NUM_PINS] = { [HPD_PORT_C] = BXT_DE_PORT_HP_DDIC }; -static const u32 hpd_tc_gen11[HPD_NUM_PINS] = { - [HPD_PORT_C] = GEN11_TC1_HOTPLUG, - [HPD_PORT_D] = GEN11_TC2_HOTPLUG, - [HPD_PORT_E] = GEN11_TC3_HOTPLUG, - [HPD_PORT_F] = GEN11_TC4_HOTPLUG +static const u32 hpd_gen11[HPD_NUM_PINS] = { + [HPD_PORT_C] = GEN11_TC1_HOTPLUG | GEN11_TBT1_HOTPLUG, + [HPD_PORT_D] = GEN11_TC2_HOTPLUG | GEN11_TBT2_HOTPLUG, + [HPD_PORT_E] = GEN11_TC3_HOTPLUG | GEN11_TBT3_HOTPLUG, + [HPD_PORT_F] = GEN11_TC4_HOTPLUG | GEN11_TBT4_HOTPLUG }; /* IIR can theoretically queue up two events. Be paranoid. */ @@ -2624,20 +2624,35 @@ static void bxt_hpd_irq_handler(struct drm_i915_private *dev_priv, static void gen11_hpd_irq_handler(struct drm_i915_private *dev_priv, u32 iir) { u32 pin_mask = 0, long_mask = 0; - u32 trigger_tc, dig_hotplug_reg; + u32 trigger_tc = iir & GEN11_DE_TC_HOTPLUG_MASK; + u32 trigger_tbt = iir & GEN11_DE_TBT_HOTPLUG_MASK; - trigger_tc = iir & GEN11_DE_TC_HOTPLUG_MASK; if (trigger_tc) { + u32 dig_hotplug_reg; + dig_hotplug_reg = I915_READ(GEN11_TC_HOTPLUG_CTL); I915_WRITE(GEN11_TC_HOTPLUG_CTL, dig_hotplug_reg); intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, trigger_tc, - dig_hotplug_reg, hpd_tc_gen11, + dig_hotplug_reg, hpd_gen11, + gen11_port_hotplug_long_detect); + } + + if (trigger_tbt) { + u32 dig_hotplug_reg; + + dig_hotplug_reg = I915_READ(GEN11_TBT_HOTPLUG_CTL); + I915_WRITE(GEN11_TBT_HOTPLUG_CTL, dig_hotplug_reg); + + intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, trigger_tbt, + dig_hotplug_reg, hpd_gen11, gen11_port_hotplug_long_detect); + } + + if (pin_mask) intel_hpd_irq_handler(dev_priv, pin_mask, long_mask); - } else { + else DRM_ERROR("Unexpected DE HPD interrupt 0x%08x\n", iir); - } } static irqreturn_t @@ -3695,6 +3710,13 @@ static void gen11_hpd_detection_setup(struct drm_i915_private *dev_priv) GEN11_HOTPLUG_CTL_ENABLE(PORT_TC3) | GEN11_HOTPLUG_CTL_ENABLE(PORT_TC4); I915_WRITE(GEN11_TC_HOTPLUG_CTL, hotplug); + + hotplug = I915_READ(GEN11_TBT_HOTPLUG_CTL); + hotplug |= GEN11_HOTPLUG_CTL_ENABLE(PORT_TC1) | + GEN11_HOTPLUG_CTL_ENABLE(PORT_TC2) | + GEN11_HOTPLUG_CTL_ENABLE(PORT_TC3) | + GEN11_HOTPLUG_CTL_ENABLE(PORT_TC4); + I915_WRITE(GEN11_TBT_HOTPLUG_CTL, hotplug); } static void gen11_hpd_irq_setup(struct drm_i915_private *dev_priv) @@ -3702,8 +3724,8 @@ static void gen11_hpd_irq_setup(struct drm_i915_private *dev_priv) u32 hotplug_irqs, enabled_irqs; u32 val; - enabled_irqs = intel_hpd_enabled_irqs(dev_priv, hpd_tc_gen11); - hotplug_irqs = GEN11_DE_TC_HOTPLUG_MASK; + enabled_irqs = intel_hpd_enabled_irqs(dev_priv, hpd_gen11); + hotplug_irqs = GEN11_DE_TC_HOTPLUG_MASK | GEN11_DE_TBT_HOTPLUG_MASK; val = I915_READ(GEN11_DE_HPD_IMR); val &= ~hotplug_irqs; @@ -4088,7 +4110,8 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv) if (INTEL_GEN(dev_priv) >= 11) { u32 de_hpd_masked = 0; - u32 de_hpd_enables = GEN11_DE_TC_HOTPLUG_MASK; + u32 de_hpd_enables = GEN11_DE_TC_HOTPLUG_MASK | + GEN11_DE_TBT_HOTPLUG_MASK; GEN3_IRQ_INIT(GEN11_DE_HPD_, ~de_hpd_masked, de_hpd_enables); gen11_hpd_detection_setup(dev_priv); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 21692228cb814..4bfd7a9bd75f5 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -7097,7 +7097,16 @@ enum { GEN11_TC3_HOTPLUG | \ GEN11_TC2_HOTPLUG | \ GEN11_TC1_HOTPLUG) - +#define GEN11_TBT4_HOTPLUG (1 << 3) +#define GEN11_TBT3_HOTPLUG (1 << 2) +#define GEN11_TBT2_HOTPLUG (1 << 1) +#define GEN11_TBT1_HOTPLUG (1 << 0) +#define GEN11_DE_TBT_HOTPLUG_MASK (GEN11_TBT4_HOTPLUG | \ + GEN11_TBT3_HOTPLUG | \ + GEN11_TBT2_HOTPLUG | \ + GEN11_TBT1_HOTPLUG) + +#define GEN11_TBT_HOTPLUG_CTL _MMIO(0x44030) #define GEN11_TC_HOTPLUG_CTL _MMIO(0x44038) #define GEN11_HOTPLUG_CTL_ENABLE(tc_port) (8 << (tc_port) * 4) #define GEN11_HOTPLUG_CTL_LONG_DETECT(tc_port) (2 << (tc_port) * 4) -- GitLab From d5b65efd2b2e674668d773a82d858ce161956b0a Mon Sep 17 00:00:00 2001 From: Arnd Bergmann <arnd@arndb.de> Date: Mon, 18 Jun 2018 17:38:43 +0200 Subject: [PATCH 0428/1506] i915: remove timespec_to_jiffies_timeout This function has been unused since commit 5ed0bdf21a85 ("drm: i915: Use nsec based interfaces"). Let's remove the definition as well now to help get rid of all uses of 'timespec'. Signed-off-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180618153855.2126048-1-arnd@arndb.de --- drivers/gpu/drm/i915/i915_drv.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index d00761a06f056..ebece44a807f7 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3700,14 +3700,6 @@ static inline unsigned long nsecs_to_jiffies_timeout(const u64 n) return min_t(u64, MAX_JIFFY_OFFSET, nsecs_to_jiffies64(n) + 1); } -static inline unsigned long -timespec_to_jiffies_timeout(const struct timespec *value) -{ - unsigned long j = timespec_to_jiffies(value); - - return min_t(unsigned long, MAX_JIFFY_OFFSET, j + 1); -} - /* * If you need to wait X milliseconds between events A and B, but event B * doesn't happen exactly after event A, you record the timestamp (jiffies) of -- GitLab From 0fdb3f75a358256188b88391d698349af8cb7340 Mon Sep 17 00:00:00 2001 From: Vathsala Nagaraju <vathsala.nagaraju@intel.com> Date: Mon, 18 Jun 2018 11:42:06 +0530 Subject: [PATCH 0429/1506] drm/i915/psr: Adds psrwake options for all platforms Adds new psrwake options defined in the below table. Platform PSR wake options vbt version KBL/CFL/WHL All(205+) BXT Uses old interpretation. CNL/ICL+ All(205+) GLK All(205+) SKL All PV releases (Check for 205+ might help but cannot be foolproof) We will continue with newer interpretation for SKL from 205. v2: Jani Keep the bdb version check. v3: Apply newer version for skl from 205+(DK). Add (version check && platform list) (Jani). Add bdb version for each platform in commit message(DK). Cc: Jani Nikula <jani.nikula@intel.com> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com> Cc: Puthikorn Voravootivat <puthik@chromium.org> Cc: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Cc: Ashutosh D Shukla <ashutosh.d.shukla@intel.com> Cc: Maulik V Vaghela <maulik.v.vaghela@intel.com> Signed-off-by: Vathsala Nagaraju <vathsala.nagaraju@intel.com> Reviewed-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/1529302326-3567-1-git-send-email-vathsala.nagaraju@intel.com --- drivers/gpu/drm/i915/intel_bios.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 62a53eb89b6bd..03f04b4723945 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -710,7 +710,9 @@ parse_psr(struct drm_i915_private *dev_priv, const struct bdb_header *bdb) * New psr options 0=500us, 1=100us, 2=2500us, 3=0us * Old decimal value is wake up time in multiples of 100 us. */ - if (bdb->version >= 209 && IS_GEN9_BC(dev_priv)) { + if (bdb->version >= 205 && + (IS_GEN9_BC(dev_priv) || IS_GEMINILAKE(dev_priv) || + INTEL_GEN(dev_priv) >= 10)) { switch (psr_table->tp1_wakeup_time) { case 0: dev_priv->vbt.psr.tp1_wakeup_time_us = 500; -- GitLab From 1a4b8901c5ecd321904f7eb5bd73be59c1ca062c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Mon, 11 Jun 2018 22:34:03 +0300 Subject: [PATCH 0430/1506] drm/i915: Print prop name/id when rejecting it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the '[PROP:id:name]' format I introduced for the core in the driver debug messages as well. Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180611193403.16118-3-ville.syrjala@linux.intel.com Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> --- drivers/gpu/drm/i915/intel_atomic.c | 6 ++++-- drivers/gpu/drm/i915/intel_atomic_plane.c | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 40285d1b91b7f..fee026ca449b1 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -59,7 +59,8 @@ int intel_digital_connector_atomic_get_property(struct drm_connector *connector, else if (property == dev_priv->broadcast_rgb_property) *val = intel_conn_state->broadcast_rgb; else { - DRM_DEBUG_ATOMIC("Unknown property %s\n", property->name); + DRM_DEBUG_ATOMIC("Unknown property [PROP:%d:%s]\n", + property->base.id, property->name); return -EINVAL; } @@ -95,7 +96,8 @@ int intel_digital_connector_atomic_set_property(struct drm_connector *connector, return 0; } - DRM_DEBUG_ATOMIC("Unknown property %s\n", property->name); + DRM_DEBUG_ATOMIC("Unknown property [PROP:%d:%s]\n", + property->base.id, property->name); return -EINVAL; } diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c index 6d068786eb413..69a18d4ff59dc 100644 --- a/drivers/gpu/drm/i915/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c @@ -277,7 +277,8 @@ intel_plane_atomic_get_property(struct drm_plane *plane, struct drm_property *property, uint64_t *val) { - DRM_DEBUG_KMS("Unknown plane property '%s'\n", property->name); + DRM_DEBUG_KMS("Unknown property [PROP:%d:%s]\n", + property->base.id, property->name); return -EINVAL; } @@ -299,6 +300,7 @@ intel_plane_atomic_set_property(struct drm_plane *plane, struct drm_property *property, uint64_t val) { - DRM_DEBUG_KMS("Unknown plane property '%s'\n", property->name); + DRM_DEBUG_KMS("Unknown property [PROP:%d:%s]\n", + property->base.id, property->name); return -EINVAL; } -- GitLab From 98fac1d5c5825e61721c7b73875f8b46159e6dcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Fri, 15 Jun 2018 20:44:04 +0300 Subject: [PATCH 0431/1506] drm/i915: Nuke the cursor size defines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No point in having this extra indireciton for the cursor max size. So drop the defines and just write out the raw numbers. Makes it easier to see what's going on. Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180615174406.12258-1-ville.syrjala@linux.intel.com Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com> --- drivers/gpu/drm/i915/intel_display.c | 8 ++++---- drivers/gpu/drm/i915/intel_drv.h | 6 ------ 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9939e092d9aab..aa7fed31ccda0 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -15052,11 +15052,11 @@ int intel_modeset_init(struct drm_device *dev) dev->mode_config.cursor_width = IS_I845G(dev_priv) ? 64 : 512; dev->mode_config.cursor_height = 1023; } else if (IS_GEN2(dev_priv)) { - dev->mode_config.cursor_width = GEN2_CURSOR_WIDTH; - dev->mode_config.cursor_height = GEN2_CURSOR_HEIGHT; + dev->mode_config.cursor_width = 64; + dev->mode_config.cursor_height = 64; } else { - dev->mode_config.cursor_width = MAX_CURSOR_WIDTH; - dev->mode_config.cursor_height = MAX_CURSOR_HEIGHT; + dev->mode_config.cursor_width = 256; + dev->mode_config.cursor_height = 256; } dev->mode_config.fb_base = ggtt->gmadr.start; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index fd2e4de776975..22831acc7c30f 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -158,12 +158,6 @@ #define MAX_OUTPUTS 6 /* maximum connectors per crtcs in the mode set */ -/* Maximum cursor sizes */ -#define GEN2_CURSOR_WIDTH 64 -#define GEN2_CURSOR_HEIGHT 64 -#define MAX_CURSOR_WIDTH 256 -#define MAX_CURSOR_HEIGHT 256 - #define INTEL_I2C_BUS_DVO 1 #define INTEL_I2C_BUS_SDVO 2 -- GitLab From ad77c537eab1c28732e02c03f3da82917722bef6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Fri, 15 Jun 2018 20:44:05 +0300 Subject: [PATCH 0432/1506] drm/i915: Check timings against hardware maximums MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Validate that all display timings fit within the number of bits we have in the transcoder timing registers. The limits are: hsw+: 4k: vdisplay, vblank_start 8k: everything else gen3+: 4k: h/vdisplay, h/vblank_start 8k: everything else gen2: 2k: h/vdisplay, h/vblank_start 4k: everything else Also document the fact that the mode_config.max_width/height limits refer to just the max framebuffer dimensions we support. Which may be larger than the max hdisplay/vdisplay. Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180615174406.12258-2-ville.syrjala@linux.intel.com Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com> --- drivers/gpu/drm/i915/intel_display.c | 35 ++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index aa7fed31ccda0..b2a5a9ed94040 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -14570,6 +14570,10 @@ static enum drm_mode_status intel_mode_valid(struct drm_device *dev, const struct drm_display_mode *mode) { + struct drm_i915_private *dev_priv = to_i915(dev); + int hdisplay_max, htotal_max; + int vdisplay_max, vtotal_max; + /* * Can't reject DBLSCAN here because Xorg ddxen can add piles * of DBLSCAN modes to the output's mode list when they detect @@ -14599,6 +14603,36 @@ intel_mode_valid(struct drm_device *dev, DRM_MODE_FLAG_CLKDIV2)) return MODE_BAD; + if (INTEL_GEN(dev_priv) >= 9 || + IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv)) { + hdisplay_max = 8192; /* FDI max 4096 handled elsewhere */ + vdisplay_max = 4096; + htotal_max = 8192; + vtotal_max = 8192; + } else if (INTEL_GEN(dev_priv) >= 3) { + hdisplay_max = 4096; + vdisplay_max = 4096; + htotal_max = 8192; + vtotal_max = 8192; + } else { + hdisplay_max = 2048; + vdisplay_max = 2048; + htotal_max = 4096; + vtotal_max = 4096; + } + + if (mode->hdisplay > hdisplay_max || + mode->hsync_start > htotal_max || + mode->hsync_end > htotal_max || + mode->htotal > htotal_max) + return MODE_H_ILLEGAL; + + if (mode->vdisplay > vdisplay_max || + mode->vsync_start > vtotal_max || + mode->vsync_end > vtotal_max || + mode->vtotal > vtotal_max) + return MODE_V_ILLEGAL; + return MODE_OK; } @@ -15037,6 +15071,7 @@ int intel_modeset_init(struct drm_device *dev) } } + /* maximum framebuffer dimensions */ if (IS_GEN2(dev_priv)) { dev->mode_config.max_width = 2048; dev->mode_config.max_height = 2048; -- GitLab From ad193bc6206d3ee2fc39fe29a2525333faf1afd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Fri, 15 Jun 2018 20:44:06 +0300 Subject: [PATCH 0433/1506] drm/i915: Enforce max hdisplay/hblank_start limits on HSW/BDW FDI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PCH transcoder registers are only 12 bits wide for the hdisplay and hblank_start values. On HSW/BDW the CPU side registers are 13 bits wide. intel_mode_valid() only checks against the higher limit (since we don't know where the mode is to be used), so an extra check is required against the FDI limits. Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180615174406.12258-3-ville.syrjala@linux.intel.com Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com> --- drivers/gpu/drm/i915/intel_crt.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index a1ddd9f62bb8f..0c6bf82bb059a 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -337,6 +337,10 @@ intel_crt_mode_valid(struct drm_connector *connector, (ironlake_get_lanes_required(mode->clock, 270000, 24) > 2)) return MODE_CLOCK_HIGH; + /* HSW/BDW FDI limited to 4k */ + if (mode->hdisplay > 4096) + return MODE_H_ILLEGAL; + return MODE_OK; } @@ -379,6 +383,11 @@ static bool hsw_crt_compute_config(struct intel_encoder *encoder, if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) return false; + /* HSW/BDW FDI limited to 4k */ + if (adjusted_mode->crtc_hdisplay > 4096 || + adjusted_mode->crtc_hblank_start > 4096) + return false; + pipe_config->has_pch_encoder = true; /* LPT FDI RX only supports 8bpc. */ -- GitLab From 1c3eced3d4ad7fd0a62c782205c36b96c0091813 Mon Sep 17 00:00:00 2001 From: Jani Nikula <jani.nikula@intel.com> Date: Tue, 19 Jun 2018 15:44:37 +0300 Subject: [PATCH 0434/1506] drm/i915/audio: constify ELD pointers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hooks aren't supposed to modify the ELD, so use const pointer. As a drive-by fix, use drm_eld_size() to log ELD size. Suggested-by: Ville Syrjala <ville.syrjala@linux.intel.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180619124437.10982-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_audio.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index a34aa66f28f8e..bb94172ffc074 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -213,7 +213,7 @@ static bool intel_eld_uptodate(struct drm_connector *connector, i915_reg_t reg_edid) { struct drm_i915_private *dev_priv = to_i915(connector->dev); - u8 *eld = connector->eld; + const u8 *eld = connector->eld; u32 tmp; int i; @@ -228,7 +228,7 @@ static bool intel_eld_uptodate(struct drm_connector *connector, I915_WRITE(reg_elda, tmp); for (i = 0; i < drm_eld_size(eld) / 4; i++) - if (I915_READ(reg_edid) != *((u32 *)eld + i)) + if (I915_READ(reg_edid) != *((const u32 *)eld + i)) return false; return true; @@ -261,12 +261,12 @@ static void g4x_audio_codec_enable(struct intel_encoder *encoder, { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct drm_connector *connector = conn_state->connector; - u8 *eld = connector->eld; + const u8 *eld = connector->eld; u32 eldv; u32 tmp; int len, i; - DRM_DEBUG_KMS("Enable audio codec, %u bytes ELD\n", eld[2]); + DRM_DEBUG_KMS("Enable audio codec, %u bytes ELD\n", drm_eld_size(eld)); tmp = I915_READ(G4X_AUD_VID_DID); if (tmp == INTEL_AUDIO_DEVBLC || tmp == INTEL_AUDIO_DEVCL) @@ -288,7 +288,7 @@ static void g4x_audio_codec_enable(struct intel_encoder *encoder, len = min(drm_eld_size(eld) / 4, len); DRM_DEBUG_DRIVER("ELD size %d\n", len); for (i = 0; i < len; i++) - I915_WRITE(G4X_HDMIW_HDMIEDID, *((u32 *)eld + i)); + I915_WRITE(G4X_HDMIW_HDMIEDID, *((const u32 *)eld + i)); tmp = I915_READ(G4X_AUD_CNTL_ST); tmp |= eldv; @@ -466,7 +466,7 @@ static void hsw_audio_codec_enable(struct intel_encoder *encoder, /* Up to 84 bytes of hw ELD buffer */ len = min(drm_eld_size(eld), 84); for (i = 0; i < len / 4; i++) - I915_WRITE(HSW_AUD_EDID_DATA(pipe), *((u32 *)eld + i)); + I915_WRITE(HSW_AUD_EDID_DATA(pipe), *((const u32 *)eld + i)); /* ELD valid */ tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD); @@ -534,7 +534,7 @@ static void ilk_audio_codec_enable(struct intel_encoder *encoder, struct drm_connector *connector = conn_state->connector; enum pipe pipe = crtc->pipe; enum port port = encoder->port; - u8 *eld = connector->eld; + const u8 *eld = connector->eld; u32 tmp, eldv; int len, i; i915_reg_t hdmiw_hdmiedid, aud_config, aud_cntl_st, aud_cntrl_st2; @@ -585,7 +585,7 @@ static void ilk_audio_codec_enable(struct intel_encoder *encoder, /* Up to 84 bytes of hw ELD buffer */ len = min(drm_eld_size(eld), 84); for (i = 0; i < len / 4; i++) - I915_WRITE(hdmiw_hdmiedid, *((u32 *)eld + i)); + I915_WRITE(hdmiw_hdmiedid, *((const u32 *)eld + i)); /* ELD valid */ tmp = I915_READ(aud_cntrl_st2); -- GitLab From 2bfb0b678e48dee76543bfa2079b7e42609332fb Mon Sep 17 00:00:00 2001 From: Souptick Joarder <jrdr.linux@gmail.com> Date: Mon, 16 Apr 2018 19:13:51 +0530 Subject: [PATCH 0435/1506] gpu: drm: radeon: Adding new typedef vm_fault_t MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use new return type vm_fault_t for fault handler in vm_operations_struct. Signed-off-by: Souptick Joarder <jrdr.linux@gmail.com> Reviewed-by: Matthew Wilcox <mawilcox@microsoft.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/radeon/radeon_ttm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index 8689fcca051c7..cbb67e9ffb3a5 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -947,11 +947,11 @@ void radeon_ttm_set_active_vram_size(struct radeon_device *rdev, u64 size) static struct vm_operations_struct radeon_ttm_vm_ops; static const struct vm_operations_struct *ttm_vm_ops = NULL; -static int radeon_ttm_fault(struct vm_fault *vmf) +static vm_fault_t radeon_ttm_fault(struct vm_fault *vmf) { struct ttm_buffer_object *bo; struct radeon_device *rdev; - int r; + vm_fault_t ret; bo = (struct ttm_buffer_object *)vmf->vma->vm_private_data; if (bo == NULL) { @@ -959,9 +959,9 @@ static int radeon_ttm_fault(struct vm_fault *vmf) } rdev = radeon_get_rdev(bo->bdev); down_read(&rdev->pm.mclk_lock); - r = ttm_vm_ops->fault(vmf); + ret = ttm_vm_ops->fault(vmf); up_read(&rdev->pm.mclk_lock); - return r; + return ret; } int radeon_mmap(struct file *filp, struct vm_area_struct *vma) -- GitLab From 4daa4fba3a3899a3eefff26e38cf680661a931e4 Mon Sep 17 00:00:00 2001 From: Souptick Joarder <jrdr.linux@gmail.com> Date: Sat, 2 Jun 2018 00:57:24 +0530 Subject: [PATCH 0436/1506] gpu: drm: ttm: Adding new return type vm_fault_t MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use new return type vm_fault_t for fault handler. For now, this is just documenting that the function returns a VM_FAULT value rather than an errno. Once all instances are converted, vm_fault_t will become a distinct type. Ref-> commit 1c8f422059ae ("mm: change return type to vm_fault_t") Previously vm_insert_{mixed,pfn} returns err which driver mapped into VM_FAULT_* type. The new function vmf_insert_{mixed,pfn} will replace this inefficiency by returning VM_FAULT_* type. Signed-off-by: Souptick Joarder <jrdr.linux@gmail.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/ttm/ttm_bo_vm.c | 45 ++++++++++++++++----------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c index c7ece7613a6aa..0ca0ec47334e2 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_vm.c +++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c @@ -44,10 +44,11 @@ #define TTM_BO_VM_NUM_PREFAULT 16 -static int ttm_bo_vm_fault_idle(struct ttm_buffer_object *bo, +static vm_fault_t ttm_bo_vm_fault_idle(struct ttm_buffer_object *bo, struct vm_fault *vmf) { - int ret = 0; + vm_fault_t ret = 0; + int err = 0; if (likely(!bo->moving)) goto out_unlock; @@ -78,9 +79,9 @@ static int ttm_bo_vm_fault_idle(struct ttm_buffer_object *bo, /* * Ordinary wait. */ - ret = dma_fence_wait(bo->moving, true); - if (unlikely(ret != 0)) { - ret = (ret != -ERESTARTSYS) ? VM_FAULT_SIGBUS : + err = dma_fence_wait(bo->moving, true); + if (unlikely(err != 0)) { + ret = (err != -ERESTARTSYS) ? VM_FAULT_SIGBUS : VM_FAULT_NOPAGE; goto out_unlock; } @@ -105,7 +106,7 @@ static unsigned long ttm_bo_io_mem_pfn(struct ttm_buffer_object *bo, + page_offset; } -static int ttm_bo_vm_fault(struct vm_fault *vmf) +static vm_fault_t ttm_bo_vm_fault(struct vm_fault *vmf) { struct vm_area_struct *vma = vmf->vma; struct ttm_buffer_object *bo = (struct ttm_buffer_object *) @@ -116,8 +117,9 @@ static int ttm_bo_vm_fault(struct vm_fault *vmf) unsigned long pfn; struct ttm_tt *ttm = NULL; struct page *page; - int ret; + int err; int i; + vm_fault_t ret = VM_FAULT_NOPAGE; unsigned long address = vmf->address; struct ttm_mem_type_manager *man = &bdev->man[bo->mem.mem_type]; @@ -129,9 +131,9 @@ static int ttm_bo_vm_fault(struct vm_fault *vmf) * for reserve, and if it fails, retry the fault after waiting * for the buffer to become unreserved. */ - ret = ttm_bo_reserve(bo, true, true, NULL); - if (unlikely(ret != 0)) { - if (ret != -EBUSY) + err = ttm_bo_reserve(bo, true, true, NULL); + if (unlikely(err != 0)) { + if (err != -EBUSY) return VM_FAULT_NOPAGE; if (vmf->flags & FAULT_FLAG_ALLOW_RETRY) { @@ -163,8 +165,8 @@ static int ttm_bo_vm_fault(struct vm_fault *vmf) } if (bdev->driver->fault_reserve_notify) { - ret = bdev->driver->fault_reserve_notify(bo); - switch (ret) { + err = bdev->driver->fault_reserve_notify(bo); + switch (err) { case 0: break; case -EBUSY: @@ -192,13 +194,13 @@ static int ttm_bo_vm_fault(struct vm_fault *vmf) goto out_unlock; } - ret = ttm_mem_io_lock(man, true); - if (unlikely(ret != 0)) { + err = ttm_mem_io_lock(man, true); + if (unlikely(err != 0)) { ret = VM_FAULT_NOPAGE; goto out_unlock; } - ret = ttm_mem_io_reserve_vm(bo); - if (unlikely(ret != 0)) { + err = ttm_mem_io_reserve_vm(bo); + if (unlikely(err != 0)) { ret = VM_FAULT_SIGBUS; goto out_io_unlock; } @@ -266,23 +268,20 @@ static int ttm_bo_vm_fault(struct vm_fault *vmf) } if (vma->vm_flags & VM_MIXEDMAP) - ret = vm_insert_mixed(&cvma, address, + ret = vmf_insert_mixed(&cvma, address, __pfn_to_pfn_t(pfn, PFN_DEV)); else - ret = vm_insert_pfn(&cvma, address, pfn); + ret = vmf_insert_pfn(&cvma, address, pfn); /* * Somebody beat us to this PTE or prefaulting to * an already populated PTE, or prefaulting error. */ - if (unlikely((ret == -EBUSY) || (ret != 0 && i > 0))) + if (unlikely((ret == VM_FAULT_NOPAGE && i > 0))) break; - else if (unlikely(ret != 0)) { - ret = - (ret == -ENOMEM) ? VM_FAULT_OOM : VM_FAULT_SIGBUS; + else if (unlikely(ret & VM_FAULT_ERROR)) goto out_io_unlock; - } address += PAGE_SIZE; if (unlikely(++page_offset >= page_last)) -- GitLab From eeb2c3c2a614f003cd42cc3d96d23f5c29ff6727 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann <arnd@arndb.de> Date: Mon, 18 Jun 2018 17:35:10 +0200 Subject: [PATCH 0437/1506] amdgpu: display: use modern ktime accessors getrawmonotonic64() is deprecated because of the nonstandard naming. The replacement functions ktime_get_raw_ns() also simplifies the callers. Signed-off-by: Arnd Bergmann <arnd@arndb.de> Reviewed-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c | 8 -------- drivers/gpu/drm/amd/display/dc/dm_services.h | 5 ++++- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c index 5a3346124a017..e861929dd981f 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c @@ -35,14 +35,6 @@ #include "amdgpu_dm_irq.h" #include "amdgpu_pm.h" -unsigned long long dm_get_timestamp(struct dc_context *ctx) -{ - struct timespec64 time; - - getrawmonotonic64(&time); - return timespec64_to_ns(&time); -} - unsigned long long dm_get_elapse_time_in_ns(struct dc_context *ctx, unsigned long long current_time_stamp, unsigned long long last_time_stamp) diff --git a/drivers/gpu/drm/amd/display/dc/dm_services.h b/drivers/gpu/drm/amd/display/dc/dm_services.h index 4ff9b2bba1782..eb5ab3978e840 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_services.h +++ b/drivers/gpu/drm/amd/display/dc/dm_services.h @@ -339,7 +339,10 @@ bool dm_dmcu_set_pipe(struct dc_context *ctx, unsigned int controller_id); #define dm_log_to_buffer(buffer, size, fmt, args)\ vsnprintf(buffer, size, fmt, args) -unsigned long long dm_get_timestamp(struct dc_context *ctx); +static inline unsigned long long dm_get_timestamp(struct dc_context *ctx) +{ + return ktime_get_raw_ns(); +} unsigned long long dm_get_elapse_time_in_ns(struct dc_context *ctx, unsigned long long current_time_stamp, -- GitLab From 8e2c7ad99dce3f4242fa0d0d5950ca3ba0f212c3 Mon Sep 17 00:00:00 2001 From: Chunming Zhou <david1.zhou@amd.com> Date: Fri, 15 Jun 2018 14:39:57 +0800 Subject: [PATCH 0438/1506] drm/amdgpu: update ib_start/size_alignment same as windows used MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PAGE_SIZE for start_alignment is far much than hw requirement, And now, update to expereince value from window side. Signed-off-by: Chunming Zhou <david1.zhou@amd.com> Acked-by: Marek Olšák <marek.olsak@amd.com> Acked-by: Christian König <christian.koenig@amd.com> Acked-by: Junwei Zhang <Jerry.Zhang@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 28 ++++++++++++------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index ec1060a5eab3a..2060f208e60b7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -329,35 +329,35 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file type = AMD_IP_BLOCK_TYPE_GFX; for (i = 0; i < adev->gfx.num_gfx_rings; i++) ring_mask |= ((adev->gfx.gfx_ring[i].ready ? 1 : 0) << i); - ib_start_alignment = AMDGPU_GPU_PAGE_SIZE; - ib_size_alignment = 8; + ib_start_alignment = 32; + ib_size_alignment = 32; break; case AMDGPU_HW_IP_COMPUTE: type = AMD_IP_BLOCK_TYPE_GFX; for (i = 0; i < adev->gfx.num_compute_rings; i++) ring_mask |= ((adev->gfx.compute_ring[i].ready ? 1 : 0) << i); - ib_start_alignment = AMDGPU_GPU_PAGE_SIZE; - ib_size_alignment = 8; + ib_start_alignment = 32; + ib_size_alignment = 32; break; case AMDGPU_HW_IP_DMA: type = AMD_IP_BLOCK_TYPE_SDMA; for (i = 0; i < adev->sdma.num_instances; i++) ring_mask |= ((adev->sdma.instance[i].ring.ready ? 1 : 0) << i); - ib_start_alignment = AMDGPU_GPU_PAGE_SIZE; - ib_size_alignment = 1; + ib_start_alignment = 256; + ib_size_alignment = 4; break; case AMDGPU_HW_IP_UVD: type = AMD_IP_BLOCK_TYPE_UVD; for (i = 0; i < adev->uvd.num_uvd_inst; i++) ring_mask |= ((adev->uvd.inst[i].ring.ready ? 1 : 0) << i); - ib_start_alignment = AMDGPU_GPU_PAGE_SIZE; - ib_size_alignment = 16; + ib_start_alignment = 64; + ib_size_alignment = 64; break; case AMDGPU_HW_IP_VCE: type = AMD_IP_BLOCK_TYPE_VCE; for (i = 0; i < adev->vce.num_rings; i++) ring_mask |= ((adev->vce.ring[i].ready ? 1 : 0) << i); - ib_start_alignment = AMDGPU_GPU_PAGE_SIZE; + ib_start_alignment = 4; ib_size_alignment = 1; break; case AMDGPU_HW_IP_UVD_ENC: @@ -367,26 +367,26 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file ring_mask |= ((adev->uvd.inst[i].ring_enc[j].ready ? 1 : 0) << (j + i * adev->uvd.num_enc_rings)); - ib_start_alignment = AMDGPU_GPU_PAGE_SIZE; - ib_size_alignment = 1; + ib_start_alignment = 64; + ib_size_alignment = 64; break; case AMDGPU_HW_IP_VCN_DEC: type = AMD_IP_BLOCK_TYPE_VCN; ring_mask = adev->vcn.ring_dec.ready ? 1 : 0; - ib_start_alignment = AMDGPU_GPU_PAGE_SIZE; + ib_start_alignment = 16; ib_size_alignment = 16; break; case AMDGPU_HW_IP_VCN_ENC: type = AMD_IP_BLOCK_TYPE_VCN; for (i = 0; i < adev->vcn.num_enc_rings; i++) ring_mask |= ((adev->vcn.ring_enc[i].ready ? 1 : 0) << i); - ib_start_alignment = AMDGPU_GPU_PAGE_SIZE; + ib_start_alignment = 64; ib_size_alignment = 1; break; case AMDGPU_HW_IP_VCN_JPEG: type = AMD_IP_BLOCK_TYPE_VCN; ring_mask = adev->vcn.ring_jpeg.ready ? 1 : 0; - ib_start_alignment = AMDGPU_GPU_PAGE_SIZE; + ib_start_alignment = 16; ib_size_alignment = 16; break; default: -- GitLab From 761f58e0e91334983cce60637adfbf7492aa97b3 Mon Sep 17 00:00:00 2001 From: Junwei Zhang <Jerry.Zhang@amd.com> Date: Tue, 19 Jun 2018 11:22:18 +0800 Subject: [PATCH 0439/1506] drm/amdgpu: correct GART location info MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid confusing the GART with the GTT domain. Signed-off-by: Junwei Zhang <Jerry.Zhang@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index fe76ec1f97374..f81e8d53d7081 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -676,17 +676,15 @@ void amdgpu_device_vram_location(struct amdgpu_device *adev, } /** - * amdgpu_device_gart_location - try to find GTT location + * amdgpu_device_gart_location - try to find GART location * * @adev: amdgpu device structure holding all necessary informations * @mc: memory controller structure holding memory informations * - * Function will place try to place GTT before or after VRAM. + * Function will place try to place GART before or after VRAM. * - * If GTT size is bigger than space left then we ajust GTT size. + * If GART size is bigger than space left then we ajust GART size. * Thus function will never fails. - * - * FIXME: when reducing GTT size align new size on power of 2. */ void amdgpu_device_gart_location(struct amdgpu_device *adev, struct amdgpu_gmc *mc) @@ -699,13 +697,13 @@ void amdgpu_device_gart_location(struct amdgpu_device *adev, size_bf = mc->vram_start; if (size_bf > size_af) { if (mc->gart_size > size_bf) { - dev_warn(adev->dev, "limiting GTT\n"); + dev_warn(adev->dev, "limiting GART\n"); mc->gart_size = size_bf; } mc->gart_start = 0; } else { if (mc->gart_size > size_af) { - dev_warn(adev->dev, "limiting GTT\n"); + dev_warn(adev->dev, "limiting GART\n"); mc->gart_size = size_af; } /* VCE doesn't like it when BOs cross a 4GB segment, so align @@ -714,7 +712,7 @@ void amdgpu_device_gart_location(struct amdgpu_device *adev, mc->gart_start = ALIGN(mc->vram_end + 1, 0x100000000ULL); } mc->gart_end = mc->gart_start + mc->gart_size - 1; - dev_info(adev->dev, "GTT: %lluM 0x%016llX - 0x%016llX\n", + dev_info(adev->dev, "GART: %lluM 0x%016llX - 0x%016llX\n", mc->gart_size >> 20, mc->gart_start, mc->gart_end); } -- GitLab From a21daa88d4f08c959a36ad9760df045407a080e5 Mon Sep 17 00:00:00 2001 From: Stefan Agner <stefan@agner.ch> Date: Tue, 19 Jun 2018 11:16:56 +0200 Subject: [PATCH 0440/1506] drm/amdgpu: Use correct enum to set powergating state Use enum amd_powergating_state instead of enum amd_clockgating_state. The underlying value stays the same, so there is no functional change in practise. This fixes a warning seen with clang: drivers/gpu/drm/amd/amdgpu/amdgpu_device.c:1930:14: warning: implicit conversion from enumeration type 'enum amd_clockgating_state' to different enumeration type 'enum amd_powergating_state' [-Wenum-conversion] AMD_CG_STATE_UNGATE); ^~~~~~~~~~~~~~~~~~~ Signed-off-by: Stefan Agner <stefan@agner.ch> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index f81e8d53d7081..cd8177967e67b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -1925,7 +1925,7 @@ int amdgpu_device_ip_suspend(struct amdgpu_device *adev) if (adev->powerplay.pp_feature & PP_GFXOFF_MASK) amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_SMC, - AMD_CG_STATE_UNGATE); + AMD_PG_STATE_UNGATE); /* ungate SMC block first */ r = amdgpu_device_ip_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_SMC, -- GitLab From f648661bc7de497634c474a38608a715a0af4bbd Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Wed, 20 Jun 2018 12:24:41 +0100 Subject: [PATCH 0441/1506] drm/i915/selftests: Avoid ERR_PTR dereference Along the early error path for igt_switch_to_kernel_context we may try to dereference an invalid error pointer. Instead, return early rather than dump the GEM trace since we haven't yet emitted anything of interest. Reported-by: Dan Carpenter <dan.carpenter@oracle.com> Fixes: 09a4c02e58c1 ("drm/i915: Look for an active kernel context before switching") Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Mika Kuoppala <mika.kuoppala@intel.com> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180620112441.13085-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/selftests/i915_gem_context.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_context.c b/drivers/gpu/drm/i915/selftests/i915_gem_context.c index 836f1af8b833c..90c3c36173ba1 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_context.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_context.c @@ -519,8 +519,8 @@ static int igt_switch_to_kernel_context(void *arg) mutex_lock(&i915->drm.struct_mutex); ctx = kernel_context(i915); if (IS_ERR(ctx)) { - err = PTR_ERR(ctx); - goto out_unlock; + mutex_unlock(&i915->drm.struct_mutex); + return PTR_ERR(ctx); } /* First check idling each individual engine */ -- GitLab From 9d54fcd5416d84a3ab6a0b58846cff88ce62a4d4 Mon Sep 17 00:00:00 2001 From: Daniel Vetter <daniel.vetter@ffwll.ch> Date: Thu, 5 Apr 2018 17:44:47 +0200 Subject: [PATCH 0442/1506] drm/gem-fb-helper: Always do implicit sync MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I've done a lot of history digging. The first signs of this optimization was introduced in i915: commit 25067bfc060d1a481584dcb51ef4b5680176ecb6 Author: Gustavo Padovan <gustavo.padovan@collabora.co.uk> Date: Wed Sep 10 12:03:17 2014 -0300 drm/i915: pin sprite fb only if it changed without much justification. Pinning already pinned stuff is real cheap (it's just obj->pin_count++ really), and the missing implicit sync was entirely forgotten about it seems. It's at least not mentioned anywhere it the commit message. It was also promptly removed shortly afterwards in commit ea2c67bb4affa84080c616920f3899f123786e56 Author: Matt Roper <matthew.d.roper@intel.com> Date: Tue Dec 23 10:41:52 2014 -0800 drm/i915: Move to atomic plane helpers (v9) again without really mentioning the side-effect that plane updates with the same fb now again obey implicit syncing. Note that this only ever applied to the plane_update hook, all other legacy entry points (set_base, page_flip) always obeyed implicit sync in the drm/i915 driver. The real source of this code here seems to be msm, copied to vc4, then copied to tinydrm. I've also tried to dig around in all available msm sources, but the corresponding check for fb != old_fb is present ever since the initial merge in commit cf3a7e4ce08e6876cdcb80390876647f28a7cf8f Author: Rob Clark <robdclark@gmail.com> Date: Sat Nov 8 13:21:06 2014 -0500 drm/msm: atomic core bits The only older version I've found of msm atomic code predates the atomic helpers, and so didn't even use any of this. It also does not have a corresponding check (because it simply did no implicit sync at all). I've chatted with Rob on irc, and he didn't remember the reason for this either. Note we had epic amounts of fun with too much syncing against _vblank_, especially around cursor updates. But I don't ever discussing a need for less syncing against implicit fences. Also note that explicit fencing allows you to sidetrack all of this, at least for all the drivers correctly implemented using drm_atomic_set_fence_for_plane(). Given that it seems to be an accident of history, and that big drivers like i915 (and also nouveau it seems, I didn't follow the amdgpu/radeon sync code to figure this out properly there) never have done it, let's remove this. Cc: Rob Clark <robdclark@gmail.com> Cc: Matt Roper <matthew.d.roper@intel.com> Cc: Gustavo Padovan <gustavo.padovan@collabora.co.uk> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Cc: Sean Paul <seanpaul@chromium.org> Cc: David Airlie <airlied@linux.ie> Cc: "Noralf Trønnes" <noralf@tronnes.org> Reviewed-by: Eric Anholt <eric@anholt.net> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180405154449.23038-8-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_gem_framebuffer_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c index acfbc0641a06a..2810d41314118 100644 --- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c +++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c @@ -253,7 +253,7 @@ int drm_gem_fb_prepare_fb(struct drm_plane *plane, struct dma_buf *dma_buf; struct dma_fence *fence; - if (plane->state->fb == state->fb || !state->fb) + if (!state->fb) return 0; dma_buf = drm_gem_fb_get_obj(state->fb, 0)->dma_buf; -- GitLab From 2227a7a219fdd2b925b1e861f36255efd149ff6d Mon Sep 17 00:00:00 2001 From: Daniel Vetter <daniel.vetter@ffwll.ch> Date: Thu, 5 Apr 2018 17:44:48 +0200 Subject: [PATCH 0443/1506] drm/vc4: Always obey implicit sync Same justification as for drm_gem_fb_prepare_fb. Cc: Eric Anholt <eric@anholt.net> Reviewed-by: Eric Anholt <eric@anholt.net> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180405154449.23038-9-daniel.vetter@ffwll.ch Link: https://patchwork.freedesktop.org/patch/msgid/20180409085134.27321-1-daniel.vetter@ffwll.ch --- drivers/gpu/drm/vc4/vc4_plane.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 2575bd81a0105..3922f5f5807d0 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -861,18 +861,21 @@ static int vc4_prepare_fb(struct drm_plane *plane, struct dma_fence *fence; int ret; - if ((plane->state->fb == state->fb) || !state->fb) + if (!state->fb) return 0; bo = to_vc4_bo(&drm_fb_cma_get_gem_obj(state->fb, 0)->base); + fence = reservation_object_get_excl_rcu(bo->resv); + drm_atomic_set_fence_for_plane(state, fence); + + if (plane->state->fb == state->fb) + return 0; + ret = vc4_bo_inc_usecnt(bo); if (ret) return ret; - fence = reservation_object_get_excl_rcu(bo->resv); - drm_atomic_set_fence_for_plane(state, fence); - return 0; } -- GitLab From a19741e5e5a9f1f02f8e3c037bde7d73d4bfae9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Mon, 28 May 2018 11:47:52 +0200 Subject: [PATCH 0444/1506] dma_buf: remove device parameter from attach callback v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The device parameter is completely unused because it is available in the attachment structure as well. v2: fix kerneldoc as well Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/226643/ --- drivers/dma-buf/dma-buf.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c | 3 +-- drivers/gpu/drm/drm_prime.c | 3 +-- drivers/gpu/drm/udl/udl_dmabuf.c | 1 - drivers/gpu/drm/vmwgfx/vmwgfx_prime.c | 1 - .../media/common/videobuf2/videobuf2-dma-contig.c | 2 +- drivers/media/common/videobuf2/videobuf2-dma-sg.c | 2 +- drivers/media/common/videobuf2/videobuf2-vmalloc.c | 2 +- include/drm/drm_prime.h | 2 +- include/linux/dma-buf.h | 13 ++++++------- 10 files changed, 13 insertions(+), 18 deletions(-) diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 4c45e31258f04..50771063c617a 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -568,7 +568,7 @@ struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf, mutex_lock(&dmabuf->lock); if (dmabuf->ops->attach) { - ret = dmabuf->ops->attach(dmabuf, dev, attach); + ret = dmabuf->ops->attach(dmabuf, attach); if (ret) goto err_attach; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c index 4b584cb75bf45..bbbb4f9578db7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c @@ -127,7 +127,6 @@ amdgpu_gem_prime_import_sg_table(struct drm_device *dev, } static int amdgpu_gem_map_attach(struct dma_buf *dma_buf, - struct device *target_dev, struct dma_buf_attachment *attach) { struct drm_gem_object *obj = dma_buf->priv; @@ -135,7 +134,7 @@ static int amdgpu_gem_map_attach(struct dma_buf *dma_buf, struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); long r; - r = drm_gem_map_attach(dma_buf, target_dev, attach); + r = drm_gem_map_attach(dma_buf, attach); if (r) return r; diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c index 397b46b337399..0055d919070cd 100644 --- a/drivers/gpu/drm/drm_prime.c +++ b/drivers/gpu/drm/drm_prime.c @@ -186,7 +186,6 @@ static int drm_prime_lookup_buf_handle(struct drm_prime_file_private *prime_fpri /** * drm_gem_map_attach - dma_buf attach implementation for GEM * @dma_buf: buffer to attach device to - * @target_dev: not used * @attach: buffer attachment data * * Allocates &drm_prime_attachment and calls &drm_driver.gem_prime_pin for @@ -195,7 +194,7 @@ static int drm_prime_lookup_buf_handle(struct drm_prime_file_private *prime_fpri * * Returns 0 on success, negative error code on failure. */ -int drm_gem_map_attach(struct dma_buf *dma_buf, struct device *target_dev, +int drm_gem_map_attach(struct dma_buf *dma_buf, struct dma_buf_attachment *attach) { struct drm_prime_attachment *prime_attach; diff --git a/drivers/gpu/drm/udl/udl_dmabuf.c b/drivers/gpu/drm/udl/udl_dmabuf.c index 0a20695eb120e..91ae60309d3e9 100644 --- a/drivers/gpu/drm/udl/udl_dmabuf.c +++ b/drivers/gpu/drm/udl/udl_dmabuf.c @@ -29,7 +29,6 @@ struct udl_drm_dmabuf_attachment { }; static int udl_attach_dma_buf(struct dma_buf *dmabuf, - struct device *dev, struct dma_buf_attachment *attach) { struct udl_drm_dmabuf_attachment *udl_attach; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_prime.c b/drivers/gpu/drm/vmwgfx/vmwgfx_prime.c index 0d42a46521fc1..fbffb37ccf42e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_prime.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_prime.c @@ -40,7 +40,6 @@ */ static int vmw_prime_map_attach(struct dma_buf *dma_buf, - struct device *target_dev, struct dma_buf_attachment *attach) { return -ENOSYS; diff --git a/drivers/media/common/videobuf2/videobuf2-dma-contig.c b/drivers/media/common/videobuf2/videobuf2-dma-contig.c index f1178f6f434d0..12d0072c52c28 100644 --- a/drivers/media/common/videobuf2/videobuf2-dma-contig.c +++ b/drivers/media/common/videobuf2/videobuf2-dma-contig.c @@ -222,7 +222,7 @@ struct vb2_dc_attachment { enum dma_data_direction dma_dir; }; -static int vb2_dc_dmabuf_ops_attach(struct dma_buf *dbuf, struct device *dev, +static int vb2_dc_dmabuf_ops_attach(struct dma_buf *dbuf, struct dma_buf_attachment *dbuf_attach) { struct vb2_dc_attachment *attach; diff --git a/drivers/media/common/videobuf2/videobuf2-dma-sg.c b/drivers/media/common/videobuf2/videobuf2-dma-sg.c index 753ed3138dcc8..cf94765e593fb 100644 --- a/drivers/media/common/videobuf2/videobuf2-dma-sg.c +++ b/drivers/media/common/videobuf2/videobuf2-dma-sg.c @@ -371,7 +371,7 @@ struct vb2_dma_sg_attachment { enum dma_data_direction dma_dir; }; -static int vb2_dma_sg_dmabuf_ops_attach(struct dma_buf *dbuf, struct device *dev, +static int vb2_dma_sg_dmabuf_ops_attach(struct dma_buf *dbuf, struct dma_buf_attachment *dbuf_attach) { struct vb2_dma_sg_attachment *attach; diff --git a/drivers/media/common/videobuf2/videobuf2-vmalloc.c b/drivers/media/common/videobuf2/videobuf2-vmalloc.c index 359fb9804d160..cdec023a918df 100644 --- a/drivers/media/common/videobuf2/videobuf2-vmalloc.c +++ b/drivers/media/common/videobuf2/videobuf2-vmalloc.c @@ -209,7 +209,7 @@ struct vb2_vmalloc_attachment { enum dma_data_direction dma_dir; }; -static int vb2_vmalloc_dmabuf_ops_attach(struct dma_buf *dbuf, struct device *dev, +static int vb2_vmalloc_dmabuf_ops_attach(struct dma_buf *dbuf, struct dma_buf_attachment *dbuf_attach) { struct vb2_vmalloc_attachment *attach; diff --git a/include/drm/drm_prime.h b/include/drm/drm_prime.h index 4d5f5d6cf6a68..ef338151cea8d 100644 --- a/include/drm/drm_prime.h +++ b/include/drm/drm_prime.h @@ -82,7 +82,7 @@ int drm_gem_prime_fd_to_handle(struct drm_device *dev, struct dma_buf *drm_gem_dmabuf_export(struct drm_device *dev, struct dma_buf_export_info *exp_info); void drm_gem_dmabuf_release(struct dma_buf *dma_buf); -int drm_gem_map_attach(struct dma_buf *dma_buf, struct device *target_dev, +int drm_gem_map_attach(struct dma_buf *dma_buf, struct dma_buf_attachment *attach); void drm_gem_map_detach(struct dma_buf *dma_buf, struct dma_buf_attachment *attach); diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h index 88917fa796e44..c0ad5bf61188e 100644 --- a/include/linux/dma-buf.h +++ b/include/linux/dma-buf.h @@ -55,11 +55,11 @@ struct dma_buf_ops { * @attach: * * This is called from dma_buf_attach() to make sure that a given - * &device can access the provided &dma_buf. Exporters which support - * buffer objects in special locations like VRAM or device-specific - * carveout areas should check whether the buffer could be move to - * system memory (or directly accessed by the provided device), and - * otherwise need to fail the attach operation. + * &dma_buf_attachment.dev can access the provided &dma_buf. Exporters + * which support buffer objects in special locations like VRAM or + * device-specific carveout areas should check whether the buffer could + * be move to system memory (or directly accessed by the provided + * device), and otherwise need to fail the attach operation. * * The exporter should also in general check whether the current * allocation fullfills the DMA constraints of the new device. If this @@ -77,8 +77,7 @@ struct dma_buf_ops { * to signal that backing storage is already allocated and incompatible * with the requirements of requesting device. */ - int (*attach)(struct dma_buf *, struct device *, - struct dma_buf_attachment *); + int (*attach)(struct dma_buf *, struct dma_buf_attachment *); /** * @detach: -- GitLab From f664a52695429b68afb4e130a0f69cd5fd1fec86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Mon, 28 May 2018 13:34:01 +0200 Subject: [PATCH 0445/1506] dma-buf: remove kmap_atomic interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Neither used nor correctly implemented anywhere. Just completely remove the interface. Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Acked-by: Sumit Semwal <sumit.semwal@linaro.org> Link: https://patchwork.freedesktop.org/patch/226645/ --- drivers/dma-buf/dma-buf.c | 54 +------------------ drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c | 2 - drivers/gpu/drm/armada/armada_gem.c | 2 - drivers/gpu/drm/drm_prime.c | 31 ----------- drivers/gpu/drm/i915/i915_gem_dmabuf.c | 11 ---- drivers/gpu/drm/i915/selftests/mock_dmabuf.c | 2 - drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c | 2 - drivers/gpu/drm/tegra/gem.c | 14 ----- drivers/gpu/drm/udl/udl_dmabuf.c | 17 ------ drivers/gpu/drm/vmwgfx/vmwgfx_prime.c | 13 ----- .../common/videobuf2/videobuf2-dma-contig.c | 1 - .../media/common/videobuf2/videobuf2-dma-sg.c | 1 - .../common/videobuf2/videobuf2-vmalloc.c | 1 - drivers/staging/android/ion/ion.c | 2 - drivers/tee/tee_shm.c | 6 --- include/drm/drm_prime.h | 4 -- include/linux/dma-buf.h | 4 -- 17 files changed, 2 insertions(+), 165 deletions(-) diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 50771063c617a..13884474d1588 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -405,7 +405,6 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info) || !exp_info->ops->map_dma_buf || !exp_info->ops->unmap_dma_buf || !exp_info->ops->release - || !exp_info->ops->map_atomic || !exp_info->ops->map || !exp_info->ops->mmap)) { return ERR_PTR(-EINVAL); @@ -687,26 +686,14 @@ EXPORT_SYMBOL_GPL(dma_buf_unmap_attachment); * void \*dma_buf_kmap(struct dma_buf \*, unsigned long); * void dma_buf_kunmap(struct dma_buf \*, unsigned long, void \*); * - * There are also atomic variants of these interfaces. Like for kmap they - * facilitate non-blocking fast-paths. Neither the importer nor the exporter - * (in the callback) is allowed to block when using these. - * - * Interfaces:: - * void \*dma_buf_kmap_atomic(struct dma_buf \*, unsigned long); - * void dma_buf_kunmap_atomic(struct dma_buf \*, unsigned long, void \*); - * - * For importers all the restrictions of using kmap apply, like the limited - * supply of kmap_atomic slots. Hence an importer shall only hold onto at - * max 2 atomic dma_buf kmaps at the same time (in any given process context). + * Implementing the functions is optional for exporters and for importers all + * the restrictions of using kmap apply. * * dma_buf kmap calls outside of the range specified in begin_cpu_access are * undefined. If the range is not PAGE_SIZE aligned, kmap needs to succeed on * the partial chunks at the beginning and end but may return stale or bogus * data outside of the range (in these partial chunks). * - * Note that these calls need to always succeed. The exporter needs to - * complete any preparations that might fail in begin_cpu_access. - * * For some cases the overhead of kmap can be too high, a vmap interface * is introduced. This interface should be used very carefully, as vmalloc * space is a limited resources on many architectures. @@ -859,43 +846,6 @@ int dma_buf_end_cpu_access(struct dma_buf *dmabuf, } EXPORT_SYMBOL_GPL(dma_buf_end_cpu_access); -/** - * dma_buf_kmap_atomic - Map a page of the buffer object into kernel address - * space. The same restrictions as for kmap_atomic and friends apply. - * @dmabuf: [in] buffer to map page from. - * @page_num: [in] page in PAGE_SIZE units to map. - * - * This call must always succeed, any necessary preparations that might fail - * need to be done in begin_cpu_access. - */ -void *dma_buf_kmap_atomic(struct dma_buf *dmabuf, unsigned long page_num) -{ - WARN_ON(!dmabuf); - - if (!dmabuf->ops->map_atomic) - return NULL; - return dmabuf->ops->map_atomic(dmabuf, page_num); -} -EXPORT_SYMBOL_GPL(dma_buf_kmap_atomic); - -/** - * dma_buf_kunmap_atomic - Unmap a page obtained by dma_buf_kmap_atomic. - * @dmabuf: [in] buffer to unmap page from. - * @page_num: [in] page in PAGE_SIZE units to unmap. - * @vaddr: [in] kernel space pointer obtained from dma_buf_kmap_atomic. - * - * This call must always succeed. - */ -void dma_buf_kunmap_atomic(struct dma_buf *dmabuf, unsigned long page_num, - void *vaddr) -{ - WARN_ON(!dmabuf); - - if (dmabuf->ops->unmap_atomic) - dmabuf->ops->unmap_atomic(dmabuf, page_num, vaddr); -} -EXPORT_SYMBOL_GPL(dma_buf_kunmap_atomic); - /** * dma_buf_kmap - Map a page of the buffer object into kernel address space. The * same restrictions as for kmap and friends apply. diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c index bbbb4f9578db7..0558da049827a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c @@ -238,9 +238,7 @@ static const struct dma_buf_ops amdgpu_dmabuf_ops = { .release = drm_gem_dmabuf_release, .begin_cpu_access = amdgpu_gem_begin_cpu_access, .map = drm_gem_dmabuf_kmap, - .map_atomic = drm_gem_dmabuf_kmap_atomic, .unmap = drm_gem_dmabuf_kunmap, - .unmap_atomic = drm_gem_dmabuf_kunmap_atomic, .mmap = drm_gem_dmabuf_mmap, .vmap = drm_gem_dmabuf_vmap, .vunmap = drm_gem_dmabuf_vunmap, diff --git a/drivers/gpu/drm/armada/armada_gem.c b/drivers/gpu/drm/armada/armada_gem.c index a97f509743a59..3fb37c75c065d 100644 --- a/drivers/gpu/drm/armada/armada_gem.c +++ b/drivers/gpu/drm/armada/armada_gem.c @@ -490,8 +490,6 @@ static const struct dma_buf_ops armada_gem_prime_dmabuf_ops = { .map_dma_buf = armada_gem_prime_map_dma_buf, .unmap_dma_buf = armada_gem_prime_unmap_dma_buf, .release = drm_gem_dmabuf_release, - .map_atomic = armada_gem_dmabuf_no_kmap, - .unmap_atomic = armada_gem_dmabuf_no_kunmap, .map = armada_gem_dmabuf_no_kmap, .unmap = armada_gem_dmabuf_no_kunmap, .mmap = armada_gem_dmabuf_mmap, diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c index 0055d919070cd..186db2e4c57a1 100644 --- a/drivers/gpu/drm/drm_prime.c +++ b/drivers/gpu/drm/drm_prime.c @@ -433,35 +433,6 @@ void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr) } EXPORT_SYMBOL(drm_gem_dmabuf_vunmap); -/** - * drm_gem_dmabuf_kmap_atomic - map_atomic implementation for GEM - * @dma_buf: buffer to be mapped - * @page_num: page number within the buffer - * - * Not implemented. This can be used as the &dma_buf_ops.map_atomic callback. - */ -void *drm_gem_dmabuf_kmap_atomic(struct dma_buf *dma_buf, - unsigned long page_num) -{ - return NULL; -} -EXPORT_SYMBOL(drm_gem_dmabuf_kmap_atomic); - -/** - * drm_gem_dmabuf_kunmap_atomic - unmap_atomic implementation for GEM - * @dma_buf: buffer to be unmapped - * @page_num: page number within the buffer - * @addr: virtual address of the buffer - * - * Not implemented. This can be used as the &dma_buf_ops.unmap_atomic callback. - */ -void drm_gem_dmabuf_kunmap_atomic(struct dma_buf *dma_buf, - unsigned long page_num, void *addr) -{ - -} -EXPORT_SYMBOL(drm_gem_dmabuf_kunmap_atomic); - /** * drm_gem_dmabuf_kmap - map implementation for GEM * @dma_buf: buffer to be mapped @@ -519,9 +490,7 @@ static const struct dma_buf_ops drm_gem_prime_dmabuf_ops = { .unmap_dma_buf = drm_gem_unmap_dma_buf, .release = drm_gem_dmabuf_release, .map = drm_gem_dmabuf_kmap, - .map_atomic = drm_gem_dmabuf_kmap_atomic, .unmap = drm_gem_dmabuf_kunmap, - .unmap_atomic = drm_gem_dmabuf_kunmap_atomic, .mmap = drm_gem_dmabuf_mmap, .vmap = drm_gem_dmabuf_vmap, .vunmap = drm_gem_dmabuf_vunmap, diff --git a/drivers/gpu/drm/i915/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/i915_gem_dmabuf.c index 69a7aec49e84e..82e2ca17a441e 100644 --- a/drivers/gpu/drm/i915/i915_gem_dmabuf.c +++ b/drivers/gpu/drm/i915/i915_gem_dmabuf.c @@ -111,15 +111,6 @@ static void i915_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr) i915_gem_object_unpin_map(obj); } -static void *i915_gem_dmabuf_kmap_atomic(struct dma_buf *dma_buf, unsigned long page_num) -{ - return NULL; -} - -static void i915_gem_dmabuf_kunmap_atomic(struct dma_buf *dma_buf, unsigned long page_num, void *addr) -{ - -} static void *i915_gem_dmabuf_kmap(struct dma_buf *dma_buf, unsigned long page_num) { struct drm_i915_gem_object *obj = dma_buf_to_obj(dma_buf); @@ -225,9 +216,7 @@ static const struct dma_buf_ops i915_dmabuf_ops = { .unmap_dma_buf = i915_gem_unmap_dma_buf, .release = drm_gem_dmabuf_release, .map = i915_gem_dmabuf_kmap, - .map_atomic = i915_gem_dmabuf_kmap_atomic, .unmap = i915_gem_dmabuf_kunmap, - .unmap_atomic = i915_gem_dmabuf_kunmap_atomic, .mmap = i915_gem_dmabuf_mmap, .vmap = i915_gem_dmabuf_vmap, .vunmap = i915_gem_dmabuf_vunmap, diff --git a/drivers/gpu/drm/i915/selftests/mock_dmabuf.c b/drivers/gpu/drm/i915/selftests/mock_dmabuf.c index 302f7d1036359..f81fda8ea45ed 100644 --- a/drivers/gpu/drm/i915/selftests/mock_dmabuf.c +++ b/drivers/gpu/drm/i915/selftests/mock_dmabuf.c @@ -130,9 +130,7 @@ static const struct dma_buf_ops mock_dmabuf_ops = { .unmap_dma_buf = mock_unmap_dma_buf, .release = mock_dmabuf_release, .map = mock_dmabuf_kmap, - .map_atomic = mock_dmabuf_kmap_atomic, .unmap = mock_dmabuf_kunmap, - .unmap_atomic = mock_dmabuf_kunmap_atomic, .mmap = mock_dmabuf_mmap, .vmap = mock_dmabuf_vmap, .vunmap = mock_dmabuf_vunmap, diff --git a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c index 8e41d649e248d..1a073f9b28349 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c +++ b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c @@ -148,8 +148,6 @@ static const struct dma_buf_ops omap_dmabuf_ops = { .release = drm_gem_dmabuf_release, .begin_cpu_access = omap_gem_dmabuf_begin_cpu_access, .end_cpu_access = omap_gem_dmabuf_end_cpu_access, - .map_atomic = omap_gem_dmabuf_kmap_atomic, - .unmap_atomic = omap_gem_dmabuf_kunmap_atomic, .map = omap_gem_dmabuf_kmap, .unmap = omap_gem_dmabuf_kunmap, .mmap = omap_gem_dmabuf_mmap, diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c index 8b0b4ff64bb41..d7661702c11c3 100644 --- a/drivers/gpu/drm/tegra/gem.c +++ b/drivers/gpu/drm/tegra/gem.c @@ -596,18 +596,6 @@ static int tegra_gem_prime_end_cpu_access(struct dma_buf *buf, return 0; } -static void *tegra_gem_prime_kmap_atomic(struct dma_buf *buf, - unsigned long page) -{ - return NULL; -} - -static void tegra_gem_prime_kunmap_atomic(struct dma_buf *buf, - unsigned long page, - void *addr) -{ -} - static void *tegra_gem_prime_kmap(struct dma_buf *buf, unsigned long page) { return NULL; @@ -648,8 +636,6 @@ static const struct dma_buf_ops tegra_gem_prime_dmabuf_ops = { .release = tegra_gem_prime_release, .begin_cpu_access = tegra_gem_prime_begin_cpu_access, .end_cpu_access = tegra_gem_prime_end_cpu_access, - .map_atomic = tegra_gem_prime_kmap_atomic, - .unmap_atomic = tegra_gem_prime_kunmap_atomic, .map = tegra_gem_prime_kmap, .unmap = tegra_gem_prime_kunmap, .mmap = tegra_gem_prime_mmap, diff --git a/drivers/gpu/drm/udl/udl_dmabuf.c b/drivers/gpu/drm/udl/udl_dmabuf.c index 91ae60309d3e9..556f62662aa92 100644 --- a/drivers/gpu/drm/udl/udl_dmabuf.c +++ b/drivers/gpu/drm/udl/udl_dmabuf.c @@ -157,27 +157,12 @@ static void *udl_dmabuf_kmap(struct dma_buf *dma_buf, unsigned long page_num) return NULL; } -static void *udl_dmabuf_kmap_atomic(struct dma_buf *dma_buf, - unsigned long page_num) -{ - /* TODO */ - - return NULL; -} - static void udl_dmabuf_kunmap(struct dma_buf *dma_buf, unsigned long page_num, void *addr) { /* TODO */ } -static void udl_dmabuf_kunmap_atomic(struct dma_buf *dma_buf, - unsigned long page_num, - void *addr) -{ - /* TODO */ -} - static int udl_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma) { @@ -192,9 +177,7 @@ static const struct dma_buf_ops udl_dmabuf_ops = { .map_dma_buf = udl_map_dma_buf, .unmap_dma_buf = udl_unmap_dma_buf, .map = udl_dmabuf_kmap, - .map_atomic = udl_dmabuf_kmap_atomic, .unmap = udl_dmabuf_kunmap, - .unmap_atomic = udl_dmabuf_kunmap_atomic, .mmap = udl_dmabuf_mmap, .release = drm_gem_dmabuf_release, }; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_prime.c b/drivers/gpu/drm/vmwgfx/vmwgfx_prime.c index fbffb37ccf42e..373bc6da2f843 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_prime.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_prime.c @@ -71,17 +71,6 @@ static void vmw_prime_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr) { } -static void *vmw_prime_dmabuf_kmap_atomic(struct dma_buf *dma_buf, - unsigned long page_num) -{ - return NULL; -} - -static void vmw_prime_dmabuf_kunmap_atomic(struct dma_buf *dma_buf, - unsigned long page_num, void *addr) -{ - -} static void *vmw_prime_dmabuf_kmap(struct dma_buf *dma_buf, unsigned long page_num) { @@ -108,9 +97,7 @@ const struct dma_buf_ops vmw_prime_dmabuf_ops = { .unmap_dma_buf = vmw_prime_unmap_dma_buf, .release = NULL, .map = vmw_prime_dmabuf_kmap, - .map_atomic = vmw_prime_dmabuf_kmap_atomic, .unmap = vmw_prime_dmabuf_kunmap, - .unmap_atomic = vmw_prime_dmabuf_kunmap_atomic, .mmap = vmw_prime_dmabuf_mmap, .vmap = vmw_prime_dmabuf_vmap, .vunmap = vmw_prime_dmabuf_vunmap, diff --git a/drivers/media/common/videobuf2/videobuf2-dma-contig.c b/drivers/media/common/videobuf2/videobuf2-dma-contig.c index 12d0072c52c28..aff0ab7bf83d5 100644 --- a/drivers/media/common/videobuf2/videobuf2-dma-contig.c +++ b/drivers/media/common/videobuf2/videobuf2-dma-contig.c @@ -358,7 +358,6 @@ static const struct dma_buf_ops vb2_dc_dmabuf_ops = { .map_dma_buf = vb2_dc_dmabuf_ops_map, .unmap_dma_buf = vb2_dc_dmabuf_ops_unmap, .map = vb2_dc_dmabuf_ops_kmap, - .map_atomic = vb2_dc_dmabuf_ops_kmap, .vmap = vb2_dc_dmabuf_ops_vmap, .mmap = vb2_dc_dmabuf_ops_mmap, .release = vb2_dc_dmabuf_ops_release, diff --git a/drivers/media/common/videobuf2/videobuf2-dma-sg.c b/drivers/media/common/videobuf2/videobuf2-dma-sg.c index cf94765e593fb..015e737095cdd 100644 --- a/drivers/media/common/videobuf2/videobuf2-dma-sg.c +++ b/drivers/media/common/videobuf2/videobuf2-dma-sg.c @@ -507,7 +507,6 @@ static const struct dma_buf_ops vb2_dma_sg_dmabuf_ops = { .map_dma_buf = vb2_dma_sg_dmabuf_ops_map, .unmap_dma_buf = vb2_dma_sg_dmabuf_ops_unmap, .map = vb2_dma_sg_dmabuf_ops_kmap, - .map_atomic = vb2_dma_sg_dmabuf_ops_kmap, .vmap = vb2_dma_sg_dmabuf_ops_vmap, .mmap = vb2_dma_sg_dmabuf_ops_mmap, .release = vb2_dma_sg_dmabuf_ops_release, diff --git a/drivers/media/common/videobuf2/videobuf2-vmalloc.c b/drivers/media/common/videobuf2/videobuf2-vmalloc.c index cdec023a918df..6dfbd5b059075 100644 --- a/drivers/media/common/videobuf2/videobuf2-vmalloc.c +++ b/drivers/media/common/videobuf2/videobuf2-vmalloc.c @@ -346,7 +346,6 @@ static const struct dma_buf_ops vb2_vmalloc_dmabuf_ops = { .map_dma_buf = vb2_vmalloc_dmabuf_ops_map, .unmap_dma_buf = vb2_vmalloc_dmabuf_ops_unmap, .map = vb2_vmalloc_dmabuf_ops_kmap, - .map_atomic = vb2_vmalloc_dmabuf_ops_kmap, .vmap = vb2_vmalloc_dmabuf_ops_vmap, .mmap = vb2_vmalloc_dmabuf_ops_mmap, .release = vb2_vmalloc_dmabuf_ops_release, diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index e74db79025497..a5220445b5e8f 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -369,8 +369,6 @@ static const struct dma_buf_ops dma_buf_ops = { .detach = ion_dma_buf_detatch, .begin_cpu_access = ion_dma_buf_begin_cpu_access, .end_cpu_access = ion_dma_buf_end_cpu_access, - .map_atomic = ion_dma_buf_kmap, - .unmap_atomic = ion_dma_buf_kunmap, .map = ion_dma_buf_kmap, .unmap = ion_dma_buf_kunmap, }; diff --git a/drivers/tee/tee_shm.c b/drivers/tee/tee_shm.c index 556960a1bab3b..df4a1553b78b1 100644 --- a/drivers/tee/tee_shm.c +++ b/drivers/tee/tee_shm.c @@ -80,11 +80,6 @@ static void tee_shm_op_release(struct dma_buf *dmabuf) tee_shm_release(shm); } -static void *tee_shm_op_map_atomic(struct dma_buf *dmabuf, unsigned long pgnum) -{ - return NULL; -} - static void *tee_shm_op_map(struct dma_buf *dmabuf, unsigned long pgnum) { return NULL; @@ -107,7 +102,6 @@ static const struct dma_buf_ops tee_shm_dma_buf_ops = { .map_dma_buf = tee_shm_op_map_dma_buf, .unmap_dma_buf = tee_shm_op_unmap_dma_buf, .release = tee_shm_op_release, - .map_atomic = tee_shm_op_map_atomic, .map = tee_shm_op_map, .mmap = tee_shm_op_mmap, }; diff --git a/include/drm/drm_prime.h b/include/drm/drm_prime.h index ef338151cea8d..d716d653b0964 100644 --- a/include/drm/drm_prime.h +++ b/include/drm/drm_prime.h @@ -93,10 +93,6 @@ void drm_gem_unmap_dma_buf(struct dma_buf_attachment *attach, enum dma_data_direction dir); void *drm_gem_dmabuf_vmap(struct dma_buf *dma_buf); void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr); -void *drm_gem_dmabuf_kmap_atomic(struct dma_buf *dma_buf, - unsigned long page_num); -void drm_gem_dmabuf_kunmap_atomic(struct dma_buf *dma_buf, - unsigned long page_num, void *addr); void *drm_gem_dmabuf_kmap(struct dma_buf *dma_buf, unsigned long page_num); void drm_gem_dmabuf_kunmap(struct dma_buf *dma_buf, unsigned long page_num, void *addr); diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h index c0ad5bf61188e..58725f890b5b6 100644 --- a/include/linux/dma-buf.h +++ b/include/linux/dma-buf.h @@ -205,8 +205,6 @@ struct dma_buf_ops { * to be restarted. */ int (*end_cpu_access)(struct dma_buf *, enum dma_data_direction); - void *(*map_atomic)(struct dma_buf *, unsigned long); - void (*unmap_atomic)(struct dma_buf *, unsigned long, void *); void *(*map)(struct dma_buf *, unsigned long); void (*unmap)(struct dma_buf *, unsigned long, void *); @@ -394,8 +392,6 @@ int dma_buf_begin_cpu_access(struct dma_buf *dma_buf, enum dma_data_direction dir); int dma_buf_end_cpu_access(struct dma_buf *dma_buf, enum dma_data_direction dir); -void *dma_buf_kmap_atomic(struct dma_buf *, unsigned long); -void dma_buf_kunmap_atomic(struct dma_buf *, unsigned long, void *); void *dma_buf_kmap(struct dma_buf *, unsigned long); void dma_buf_kunmap(struct dma_buf *, unsigned long, void *); -- GitLab From 935774cd71fe604cc8ed24adcb507d7784255672 Mon Sep 17 00:00:00 2001 From: Brian Starkey <brian.starkey@arm.com> Date: Wed, 29 Mar 2017 17:42:32 +0100 Subject: [PATCH 0446/1506] drm: Add writeback connector type Writeback connectors represent writeback engines which can write the CRTC output to a memory framebuffer. Add a writeback connector type and related support functions. Drivers should initialize a writeback connector with drm_writeback_connector_init() which takes care of setting up all the writeback-specific details on top of the normal functionality of drm_connector_init(). Writeback connectors have a WRITEBACK_FB_ID property, used to set the output framebuffer, and a WRITEBACK_PIXEL_FORMATS blob used to expose the supported writeback formats to userspace. When a framebuffer is attached to a writeback connector with the WRITEBACK_FB_ID property, it is used only once (for the commit in which it was included), and userspace can never read back the value of WRITEBACK_FB_ID. WRITEBACK_FB_ID can only be set if the connector is attached to a CRTC. Changes since v1: - Added drm_writeback.c + documentation - Added helper to initialize writeback connector in one go - Added core checks - Squashed into a single commit - Dropped the client cap - Writeback framebuffers are no longer persistent Changes since v2: Daniel Vetter: - Subclass drm_connector to drm_writeback_connector - Relax check to allow CRTC to be set without an FB - Add some writeback_ prefixes - Drop PIXEL_FORMATS_SIZE property, as it was unnecessary Gustavo Padovan: - Add drm_writeback_job to handle writeback signalling centrally Changes since v3: - Rebased - Rename PIXEL_FORMATS -> WRITEBACK_PIXEL_FORMATS Chances since v4: - Embed a drm_encoder inside the drm_writeback_connector to reduce the amount of boilerplate code required from the drivers that are using it. Changes since v5: - Added Rob Clark's atomic_commit() vfunc to connector helper funcs, so that writeback jobs are committed from atomic helpers - Updated create_writeback_properties() signature to return an error code rather than a boolean false for failure. - Free writeback job with the connector state rather than when doing the cleanup_work() Changes since v7: - fix extraneous use of out_fence that is only introduced in a subsequent patch. Changes since v8: - whitespace changes pull from subsequent patch Changes since v9: - Revert the v6 changes that free the writeback job in the connector state cleanup and return to doing it in the cleanup_work() function Signed-off-by: Brian Starkey <brian.starkey@arm.com> [rebased and fixed conflicts] Signed-off-by: Mihail Atanassov <mihail.atanassov@arm.com> [rebased and added atomic_commit() vfunc for writeback jobs] Signed-off-by: Rob Clark <robdclark@gmail.com> Signed-off-by: Liviu Dudau <liviu.dudau@arm.com> Reviewed-by: Eric Anholt <eric@anholt.net> Link: https://patchwork.freedesktop.org/patch/229037/ --- Documentation/gpu/drm-kms.rst | 9 + drivers/gpu/drm/Makefile | 2 +- drivers/gpu/drm/drm_atomic.c | 124 ++++++++++++ drivers/gpu/drm/drm_atomic_helper.c | 25 +++ drivers/gpu/drm/drm_connector.c | 4 +- drivers/gpu/drm/drm_writeback.c | 245 +++++++++++++++++++++++ include/drm/drm_atomic.h | 3 + include/drm/drm_connector.h | 13 ++ include/drm/drm_mode_config.h | 15 ++ include/drm/drm_modeset_helper_vtables.h | 11 + include/drm/drm_writeback.h | 91 +++++++++ include/uapi/drm/drm_mode.h | 1 + 12 files changed, 541 insertions(+), 2 deletions(-) create mode 100644 drivers/gpu/drm/drm_writeback.c create mode 100644 include/drm/drm_writeback.h diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index e233c2626bd01..4f6f113a7f5d5 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -373,6 +373,15 @@ Connector Functions Reference .. kernel-doc:: drivers/gpu/drm/drm_connector.c :export: +Writeback Connectors +-------------------- + +.. kernel-doc:: drivers/gpu/drm/drm_writeback.c + :doc: overview + +.. kernel-doc:: drivers/gpu/drm/drm_writeback.c + :export: + Encoder Abstraction =================== diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index ef9f3dab287fd..69c13517ea3a6 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -18,7 +18,7 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \ drm_encoder.o drm_mode_object.o drm_property.o \ drm_plane.o drm_color_mgmt.o drm_print.o \ drm_dumb_buffers.o drm_mode_config.o drm_vblank.o \ - drm_syncobj.o drm_lease.o + drm_syncobj.o drm_lease.o drm_writeback.o drm-$(CONFIG_DRM_LIB_RANDOM) += lib/drm_random.o drm-$(CONFIG_DRM_VM) += drm_vm.o diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 9ec5c865a043c..3e53d6e5c3407 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -30,6 +30,7 @@ #include <drm/drm_atomic.h> #include <drm/drm_mode.h> #include <drm/drm_print.h> +#include <drm/drm_writeback.h> #include <linux/sync_file.h> #include "drm_crtc_internal.h" @@ -690,6 +691,45 @@ static void drm_atomic_crtc_print_state(struct drm_printer *p, crtc->funcs->atomic_print_state(p, state); } +/** + * drm_atomic_connector_check - check connector state + * @connector: connector to check + * @state: connector state to check + * + * Provides core sanity checks for connector state. + * + * RETURNS: + * Zero on success, error code on failure + */ +static int drm_atomic_connector_check(struct drm_connector *connector, + struct drm_connector_state *state) +{ + struct drm_crtc_state *crtc_state; + struct drm_writeback_job *writeback_job = state->writeback_job; + + if ((connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) || !writeback_job) + return 0; + + if (writeback_job->fb && !state->crtc) { + DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] framebuffer without CRTC\n", + connector->base.id, connector->name); + return -EINVAL; + } + + if (state->crtc) + crtc_state = drm_atomic_get_existing_crtc_state(state->state, + state->crtc); + + if (writeback_job->fb && !crtc_state->active) { + DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] has framebuffer, but [CRTC:%d] is off\n", + connector->base.id, connector->name, + state->crtc->base.id); + return -EINVAL; + } + + return 0; +} + /** * drm_atomic_get_plane_state - get plane state * @state: global atomic state object @@ -1321,6 +1361,12 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector, return -EINVAL; } state->content_protection = val; + } else if (property == config->writeback_fb_id_property) { + struct drm_framebuffer *fb = drm_framebuffer_lookup(dev, NULL, val); + int ret = drm_atomic_set_writeback_fb_for_connector(state, fb); + if (fb) + drm_framebuffer_put(fb); + return ret; } else if (connector->funcs->atomic_set_property) { return connector->funcs->atomic_set_property(connector, state, property, val); @@ -1407,6 +1453,9 @@ drm_atomic_connector_get_property(struct drm_connector *connector, *val = state->scaling_mode; } else if (property == connector->content_protection_property) { *val = state->content_protection; + } else if (property == config->writeback_fb_id_property) { + /* Writeback framebuffer is one-shot, write and forget */ + *val = 0; } else if (connector->funcs->atomic_get_property) { return connector->funcs->atomic_get_property(connector, state, property, val); @@ -1631,6 +1680,70 @@ drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state, } EXPORT_SYMBOL(drm_atomic_set_crtc_for_connector); +/* + * drm_atomic_get_writeback_job - return or allocate a writeback job + * @conn_state: Connector state to get the job for + * + * Writeback jobs have a different lifetime to the atomic state they are + * associated with. This convenience function takes care of allocating a job + * if there isn't yet one associated with the connector state, otherwise + * it just returns the existing job. + * + * Returns: The writeback job for the given connector state + */ +static struct drm_writeback_job * +drm_atomic_get_writeback_job(struct drm_connector_state *conn_state) +{ + WARN_ON(conn_state->connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK); + + if (!conn_state->writeback_job) + conn_state->writeback_job = + kzalloc(sizeof(*conn_state->writeback_job), GFP_KERNEL); + + return conn_state->writeback_job; +} + +/** + * drm_atomic_set_writeback_fb_for_connector - set writeback framebuffer + * @conn_state: atomic state object for the connector + * @fb: fb to use for the connector + * + * This is used to set the framebuffer for a writeback connector, which outputs + * to a buffer instead of an actual physical connector. + * Changing the assigned framebuffer requires us to grab a reference to the new + * fb and drop the reference to the old fb, if there is one. This function + * takes care of all these details besides updating the pointer in the + * state object itself. + * + * Note: The only way conn_state can already have an fb set is if the commit + * sets the property more than once. + * + * See also: drm_writeback_connector_init() + * + * Returns: 0 on success + */ +int drm_atomic_set_writeback_fb_for_connector( + struct drm_connector_state *conn_state, + struct drm_framebuffer *fb) +{ + struct drm_writeback_job *job = + drm_atomic_get_writeback_job(conn_state); + if (!job) + return -ENOMEM; + + drm_framebuffer_assign(&job->fb, fb); + + if (fb) + DRM_DEBUG_ATOMIC("Set [FB:%d] for connector state %p\n", + fb->base.id, conn_state); + else + DRM_DEBUG_ATOMIC("Set [NOFB] for connector state %p\n", + conn_state); + + return 0; +} +EXPORT_SYMBOL(drm_atomic_set_writeback_fb_for_connector); + /** * drm_atomic_add_affected_connectors - add connectors for crtc * @state: atomic state @@ -1752,6 +1865,8 @@ int drm_atomic_check_only(struct drm_atomic_state *state) struct drm_plane_state *plane_state; struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; + struct drm_connector *conn; + struct drm_connector_state *conn_state; int i, ret = 0; DRM_DEBUG_ATOMIC("checking %p\n", state); @@ -1774,6 +1889,15 @@ int drm_atomic_check_only(struct drm_atomic_state *state) } } + for_each_new_connector_in_state(state, conn, conn_state, i) { + ret = drm_atomic_connector_check(conn, conn_state); + if (ret) { + DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] atomic core check failed\n", + conn->base.id, conn->name); + return ret; + } + } + if (config->funcs->atomic_check) ret = config->funcs->atomic_check(state->dev, state); diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 232fa11a5e311..17baf5057132e 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -30,6 +30,7 @@ #include <drm/drm_plane_helper.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_writeback.h> #include <linux/dma-fence.h> #include "drm_crtc_helper_internal.h" @@ -1172,6 +1173,25 @@ void drm_atomic_helper_commit_modeset_disables(struct drm_device *dev, } EXPORT_SYMBOL(drm_atomic_helper_commit_modeset_disables); +static void drm_atomic_helper_commit_writebacks(struct drm_device *dev, + struct drm_atomic_state *old_state) +{ + struct drm_connector *connector; + struct drm_connector_state *new_conn_state; + int i; + + for_each_new_connector_in_state(old_state, connector, new_conn_state, i) { + const struct drm_connector_helper_funcs *funcs; + + funcs = connector->helper_private; + + if (new_conn_state->writeback_job && new_conn_state->writeback_job->fb) { + WARN_ON(connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK); + funcs->atomic_commit(connector, new_conn_state->writeback_job); + } + } +} + /** * drm_atomic_helper_commit_modeset_enables - modeset commit to enable outputs * @dev: DRM device @@ -1251,6 +1271,8 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev, drm_bridge_enable(encoder->bridge); } + + drm_atomic_helper_commit_writebacks(dev, old_state); } EXPORT_SYMBOL(drm_atomic_helper_commit_modeset_enables); @@ -3647,6 +3669,9 @@ __drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector, if (state->crtc) drm_connector_get(connector); state->commit = NULL; + + /* Don't copy over a writeback job, they are used only once */ + state->writeback_job = NULL; } EXPORT_SYMBOL(__drm_atomic_helper_connector_duplicate_state); diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index 549b89501e01f..2f9ebddd178e1 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -87,6 +87,7 @@ static struct drm_conn_prop_enum_list drm_connector_enum_list[] = { { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" }, { DRM_MODE_CONNECTOR_DSI, "DSI" }, { DRM_MODE_CONNECTOR_DPI, "DPI" }, + { DRM_MODE_CONNECTOR_WRITEBACK, "Writeback" }, }; void drm_connector_ida_init(void) @@ -253,7 +254,8 @@ int drm_connector_init(struct drm_device *dev, config->num_connector++; spin_unlock_irq(&config->connector_list_lock); - if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL) + if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL && + connector_type != DRM_MODE_CONNECTOR_WRITEBACK) drm_object_attach_property(&connector->base, config->edid_property, 0); diff --git a/drivers/gpu/drm/drm_writeback.c b/drivers/gpu/drm/drm_writeback.c new file mode 100644 index 0000000000000..e5b8a4b79724b --- /dev/null +++ b/drivers/gpu/drm/drm_writeback.c @@ -0,0 +1,245 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * (C) COPYRIGHT 2016 ARM Limited. All rights reserved. + * Author: Brian Starkey <brian.starkey@arm.com> + * + * This program is free software and is provided to you under the terms of the + * GNU General Public License version 2 as published by the Free Software + * Foundation, and any use by you of this program is subject to the terms + * of such GNU licence. + */ + +#include <drm/drm_crtc.h> +#include <drm/drm_modeset_helper_vtables.h> +#include <drm/drm_property.h> +#include <drm/drm_writeback.h> +#include <drm/drmP.h> + +/** + * DOC: overview + * + * Writeback connectors are used to expose hardware which can write the output + * from a CRTC to a memory buffer. They are used and act similarly to other + * types of connectors, with some important differences: + * - Writeback connectors don't provide a way to output visually to the user. + * - Writeback connectors should always report as "disconnected" (so that + * clients which don't understand them will ignore them). + * - Writeback connectors don't have EDID. + * + * A framebuffer may only be attached to a writeback connector when the + * connector is attached to a CRTC. The WRITEBACK_FB_ID property which sets the + * framebuffer applies only to a single commit (see below). A framebuffer may + * not be attached while the CRTC is off. + * + * Writeback connectors have some additional properties, which userspace + * can use to query and control them: + * + * "WRITEBACK_FB_ID": + * Write-only object property storing a DRM_MODE_OBJECT_FB: it stores the + * framebuffer to be written by the writeback connector. This property is + * similar to the FB_ID property on planes, but will always read as zero + * and is not preserved across commits. + * Userspace must set this property to an output buffer every time it + * wishes the buffer to get filled. + * + * "WRITEBACK_PIXEL_FORMATS": + * Immutable blob property to store the supported pixel formats table. The + * data is an array of u32 DRM_FORMAT_* fourcc values. + * Userspace can use this blob to find out what pixel formats are supported + * by the connector's writeback engine. + */ + +static int create_writeback_properties(struct drm_device *dev) +{ + struct drm_property *prop; + + if (!dev->mode_config.writeback_fb_id_property) { + prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC, + "WRITEBACK_FB_ID", + DRM_MODE_OBJECT_FB); + if (!prop) + return -ENOMEM; + dev->mode_config.writeback_fb_id_property = prop; + } + + if (!dev->mode_config.writeback_pixel_formats_property) { + prop = drm_property_create(dev, DRM_MODE_PROP_BLOB | + DRM_MODE_PROP_ATOMIC | + DRM_MODE_PROP_IMMUTABLE, + "WRITEBACK_PIXEL_FORMATS", 0); + if (!prop) + return -ENOMEM; + dev->mode_config.writeback_pixel_formats_property = prop; + } + + return 0; +} + +static const struct drm_encoder_funcs drm_writeback_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +/** + * drm_writeback_connector_init - Initialize a writeback connector and its properties + * @dev: DRM device + * @wb_connector: Writeback connector to initialize + * @con_funcs: Connector funcs vtable + * @enc_helper_funcs: Encoder helper funcs vtable to be used by the internal encoder + * @formats: Array of supported pixel formats for the writeback engine + * @n_formats: Length of the formats array + * + * This function creates the writeback-connector-specific properties if they + * have not been already created, initializes the connector as + * type DRM_MODE_CONNECTOR_WRITEBACK, and correctly initializes the property + * values. It will also create an internal encoder associated with the + * drm_writeback_connector and set it to use the @enc_helper_funcs vtable for + * the encoder helper. + * + * Drivers should always use this function instead of drm_connector_init() to + * set up writeback connectors. + * + * Returns: 0 on success, or a negative error code + */ +int drm_writeback_connector_init(struct drm_device *dev, + struct drm_writeback_connector *wb_connector, + const struct drm_connector_funcs *con_funcs, + const struct drm_encoder_helper_funcs *enc_helper_funcs, + const u32 *formats, int n_formats) +{ + struct drm_property_blob *blob; + struct drm_connector *connector = &wb_connector->base; + struct drm_mode_config *config = &dev->mode_config; + int ret = create_writeback_properties(dev); + + if (ret != 0) + return ret; + + blob = drm_property_create_blob(dev, n_formats * sizeof(*formats), + formats); + if (IS_ERR(blob)) + return PTR_ERR(blob); + + drm_encoder_helper_add(&wb_connector->encoder, enc_helper_funcs); + ret = drm_encoder_init(dev, &wb_connector->encoder, + &drm_writeback_encoder_funcs, + DRM_MODE_ENCODER_VIRTUAL, NULL); + if (ret) + goto fail; + + connector->interlace_allowed = 0; + + ret = drm_connector_init(dev, connector, con_funcs, + DRM_MODE_CONNECTOR_WRITEBACK); + if (ret) + goto connector_fail; + + ret = drm_mode_connector_attach_encoder(connector, + &wb_connector->encoder); + if (ret) + goto attach_fail; + + INIT_LIST_HEAD(&wb_connector->job_queue); + spin_lock_init(&wb_connector->job_lock); + + drm_object_attach_property(&connector->base, + config->writeback_fb_id_property, 0); + + drm_object_attach_property(&connector->base, + config->writeback_pixel_formats_property, + blob->base.id); + wb_connector->pixel_formats_blob_ptr = blob; + + return 0; + +attach_fail: + drm_connector_cleanup(connector); +connector_fail: + drm_encoder_cleanup(&wb_connector->encoder); +fail: + drm_property_blob_put(blob); + return ret; +} +EXPORT_SYMBOL(drm_writeback_connector_init); + +/** + * drm_writeback_queue_job - Queue a writeback job for later signalling + * @wb_connector: The writeback connector to queue a job on + * @job: The job to queue + * + * This function adds a job to the job_queue for a writeback connector. It + * should be considered to take ownership of the writeback job, and so any other + * references to the job must be cleared after calling this function. + * + * Drivers must ensure that for a given writeback connector, jobs are queued in + * exactly the same order as they will be completed by the hardware (and + * signaled via drm_writeback_signal_completion). + * + * For every call to drm_writeback_queue_job() there must be exactly one call to + * drm_writeback_signal_completion() + * + * See also: drm_writeback_signal_completion() + */ +void drm_writeback_queue_job(struct drm_writeback_connector *wb_connector, + struct drm_writeback_job *job) +{ + unsigned long flags; + + spin_lock_irqsave(&wb_connector->job_lock, flags); + list_add_tail(&job->list_entry, &wb_connector->job_queue); + spin_unlock_irqrestore(&wb_connector->job_lock, flags); +} +EXPORT_SYMBOL(drm_writeback_queue_job); + +/* + * @cleanup_work: deferred cleanup of a writeback job + * + * The job cannot be cleaned up directly in drm_writeback_signal_completion, + * because it may be called in interrupt context. Dropping the framebuffer + * reference can sleep, and so the cleanup is deferred to a workqueue. + */ +static void cleanup_work(struct work_struct *work) +{ + struct drm_writeback_job *job = container_of(work, + struct drm_writeback_job, + cleanup_work); + drm_framebuffer_put(job->fb); + kfree(job); +} + + +/** + * drm_writeback_signal_completion - Signal the completion of a writeback job + * @wb_connector: The writeback connector whose job is complete + * + * Drivers should call this to signal the completion of a previously queued + * writeback job. It should be called as soon as possible after the hardware + * has finished writing, and may be called from interrupt context. + * It is the driver's responsibility to ensure that for a given connector, the + * hardware completes writeback jobs in the same order as they are queued. + * + * Unless the driver is holding its own reference to the framebuffer, it must + * not be accessed after calling this function. + * + * See also: drm_writeback_queue_job() + */ +void +drm_writeback_signal_completion(struct drm_writeback_connector *wb_connector) +{ + unsigned long flags; + struct drm_writeback_job *job; + + spin_lock_irqsave(&wb_connector->job_lock, flags); + job = list_first_entry_or_null(&wb_connector->job_queue, + struct drm_writeback_job, + list_entry); + if (job) + list_del(&job->list_entry); + spin_unlock_irqrestore(&wb_connector->job_lock, flags); + + if (WARN_ON(!job)) + return; + + INIT_WORK(&job->cleanup_work, cleanup_work); + queue_work(system_long_wq, &job->cleanup_work); +} +EXPORT_SYMBOL(drm_writeback_signal_completion); diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index ca461b6cf71f3..8254521b4583f 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -594,6 +594,9 @@ void drm_atomic_set_fence_for_plane(struct drm_plane_state *plane_state, int __must_check drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state, struct drm_crtc *crtc); +int drm_atomic_set_writeback_fb_for_connector( + struct drm_connector_state *conn_state, + struct drm_framebuffer *fb); int __must_check drm_atomic_add_affected_connectors(struct drm_atomic_state *state, struct drm_crtc *crtc); diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index c5797c24edd3d..716c3a0e0e1df 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -437,6 +437,19 @@ struct drm_connector_state { * protection. This is most commonly used for HDCP. */ unsigned int content_protection; + + /** + * @writeback_job: Writeback job for writeback connectors + * + * Holds the framebuffer for a writeback connector. As the writeback + * completion may be asynchronous to the normal commit cycle, the + * writeback job lifetime is managed separately from the normal atomic + * state by this object. + * + * See also: drm_writeback_queue_job() and + * drm_writeback_signal_completion() + */ + struct drm_writeback_job *writeback_job; }; /** diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h index fb45839179dd4..5f24329e69277 100644 --- a/include/drm/drm_mode_config.h +++ b/include/drm/drm_mode_config.h @@ -784,6 +784,21 @@ struct drm_mode_config { */ struct drm_property *panel_orientation_property; + /** + * @writeback_fb_id_property: Property for writeback connectors, storing + * the ID of the output framebuffer. + * See also: drm_writeback_connector_init() + */ + struct drm_property *writeback_fb_id_property; + + /** + * @writeback_pixel_formats_property: Property for writeback connectors, + * storing an array of the supported pixel formats for the writeback + * engine (read-only). + * See also: drm_writeback_connector_init() + */ + struct drm_property *writeback_pixel_formats_property; + /* dumb ioctl parameters */ uint32_t preferred_depth, prefer_shadow; diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h index 35e2a3a79fc56..3b289773297c2 100644 --- a/include/drm/drm_modeset_helper_vtables.h +++ b/include/drm/drm_modeset_helper_vtables.h @@ -974,6 +974,17 @@ struct drm_connector_helper_funcs { */ int (*atomic_check)(struct drm_connector *connector, struct drm_connector_state *state); + + /** + * @atomic_commit: + * + * This hook is to be used by drivers implementing writeback connectors + * that need a point when to commit the writeback job to the hardware. + * + * This callback is used by the atomic modeset helpers. + */ + void (*atomic_commit)(struct drm_connector *connector, + struct drm_writeback_job *writeback_job); }; /** diff --git a/include/drm/drm_writeback.h b/include/drm/drm_writeback.h new file mode 100644 index 0000000000000..17cd1feecd7e5 --- /dev/null +++ b/include/drm/drm_writeback.h @@ -0,0 +1,91 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * (C) COPYRIGHT 2016 ARM Limited. All rights reserved. + * Author: Brian Starkey <brian.starkey@arm.com> + * + * This program is free software and is provided to you under the terms of the + * GNU General Public License version 2 as published by the Free Software + * Foundation, and any use by you of this program is subject to the terms + * of such GNU licence. + */ + +#ifndef __DRM_WRITEBACK_H__ +#define __DRM_WRITEBACK_H__ +#include <drm/drm_connector.h> +#include <drm/drm_encoder.h> +#include <linux/workqueue.h> + +struct drm_writeback_connector { + struct drm_connector base; + + /** + * @encoder: Internal encoder used by the connector to fulfill + * the DRM framework requirements. The users of the + * @drm_writeback_connector control the behaviour of the @encoder + * by passing the @enc_funcs parameter to drm_writeback_connector_init() + * function. + */ + struct drm_encoder encoder; + + /** + * @pixel_formats_blob_ptr: + * + * DRM blob property data for the pixel formats list on writeback + * connectors + * See also drm_writeback_connector_init() + */ + struct drm_property_blob *pixel_formats_blob_ptr; + + /** @job_lock: Protects job_queue */ + spinlock_t job_lock; + + /** + * @job_queue: + * + * Holds a list of a connector's writeback jobs; the last item is the + * most recent. The first item may be either waiting for the hardware + * to begin writing, or currently being written. + * + * See also: drm_writeback_queue_job() and + * drm_writeback_signal_completion() + */ + struct list_head job_queue; +}; + +struct drm_writeback_job { + /** + * @cleanup_work: + * + * Used to allow drm_writeback_signal_completion to defer dropping the + * framebuffer reference to a workqueue + */ + struct work_struct cleanup_work; + + /** + * @list_entry: + * + * List item for the writeback connector's @job_queue + */ + struct list_head list_entry; + + /** + * @fb: + * + * Framebuffer to be written to by the writeback connector. Do not set + * directly, use drm_atomic_set_writeback_fb_for_connector() + */ + struct drm_framebuffer *fb; +}; + +int drm_writeback_connector_init(struct drm_device *dev, + struct drm_writeback_connector *wb_connector, + const struct drm_connector_funcs *con_funcs, + const struct drm_encoder_helper_funcs *enc_helper_funcs, + const u32 *formats, int n_formats); + +void drm_writeback_queue_job(struct drm_writeback_connector *wb_connector, + struct drm_writeback_job *job); + +void drm_writeback_cleanup_job(struct drm_writeback_job *job); +void drm_writeback_signal_completion(struct drm_writeback_connector *wb_connector); +#endif diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index 971c016b368cd..8d67243952f4f 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -351,6 +351,7 @@ enum drm_mode_subconnector { #define DRM_MODE_CONNECTOR_VIRTUAL 15 #define DRM_MODE_CONNECTOR_DSI 16 #define DRM_MODE_CONNECTOR_DPI 17 +#define DRM_MODE_CONNECTOR_WRITEBACK 18 struct drm_mode_get_connector { -- GitLab From b13cc8dd588434e2aec781e6d12224e4c408ac18 Mon Sep 17 00:00:00 2001 From: Brian Starkey <brian.starkey@arm.com> Date: Wed, 29 Mar 2017 17:42:33 +0100 Subject: [PATCH 0447/1506] drm: writeback: Add out-fences for writeback connectors Add the WRITEBACK_OUT_FENCE_PTR property to writeback connectors, to enable userspace to get a fence which will signal once the writeback is complete. It is not allowed to request an out-fence without a framebuffer attached to the connector. A timeline is added to drm_writeback_connector for use by the writeback out-fences. In the case of a commit failure or DRM_MODE_ATOMIC_TEST_ONLY, the fence is set to -1. Changes from v2: - Rebase onto Gustavo Padovan's v9 explicit sync series - Change out_fence_ptr type to s32 __user * - Set *out_fence_ptr to -1 in drm_atomic_connector_set_property - Store fence in drm_writeback_job Gustavo Padovan: - Move out_fence_ptr out of connector_state - Signal fence from drm_writeback_signal_completion instead of in driver directly Changes from v3: - Rebase onto commit 7e9081c5aac7 ("drm/fence: fix memory overwrite when setting out_fence fd") (change out_fence_ptr to s32 __user *, for real this time.) - Update documentation around WRITEBACK_OUT_FENCE_PTR Signed-off-by: Brian Starkey <brian.starkey@arm.com> [rebased and fixed conflicts] Signed-off-by: Mihail Atanassov <mihail.atanassov@arm.com> Signed-off-by: Liviu Dudau <liviu.dudau@arm.com> Reviewed-by: Eric Anholt <eric@anholt.net> Reviewed-by: Sean Paul <seanpaul@chromium.org> Link: https://patchwork.freedesktop.org/patch/229036/ --- drivers/gpu/drm/drm_atomic.c | 99 ++++++++++++++++++++++++++--- drivers/gpu/drm/drm_writeback.c | 109 +++++++++++++++++++++++++++++++- include/drm/drm_atomic.h | 8 +++ include/drm/drm_connector.h | 8 +-- include/drm/drm_mode_config.h | 8 +++ include/drm/drm_writeback.h | 41 +++++++++++- 6 files changed, 257 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 3e53d6e5c3407..1157190594342 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -318,6 +318,35 @@ static s32 __user *get_out_fence_for_crtc(struct drm_atomic_state *state, return fence_ptr; } +static int set_out_fence_for_connector(struct drm_atomic_state *state, + struct drm_connector *connector, + s32 __user *fence_ptr) +{ + unsigned int index = drm_connector_index(connector); + + if (!fence_ptr) + return 0; + + if (put_user(-1, fence_ptr)) + return -EFAULT; + + state->connectors[index].out_fence_ptr = fence_ptr; + + return 0; +} + +static s32 __user *get_out_fence_for_connector(struct drm_atomic_state *state, + struct drm_connector *connector) +{ + unsigned int index = drm_connector_index(connector); + s32 __user *fence_ptr; + + fence_ptr = state->connectors[index].out_fence_ptr; + state->connectors[index].out_fence_ptr = NULL; + + return fence_ptr; +} + /** * drm_atomic_set_mode_for_crtc - set mode for CRTC * @state: the CRTC whose incoming state to update @@ -727,6 +756,12 @@ static int drm_atomic_connector_check(struct drm_connector *connector, return -EINVAL; } + if (writeback_job->out_fence && !writeback_job->fb) { + DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] requesting out-fence without framebuffer\n", + connector->base.id, connector->name); + return -EINVAL; + } + return 0; } @@ -1367,6 +1402,11 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector, if (fb) drm_framebuffer_put(fb); return ret; + } else if (property == config->writeback_out_fence_ptr_property) { + s32 __user *fence_ptr = u64_to_user_ptr(val); + + return set_out_fence_for_connector(state->state, connector, + fence_ptr); } else if (connector->funcs->atomic_set_property) { return connector->funcs->atomic_set_property(connector, state, property, val); @@ -1456,6 +1496,8 @@ drm_atomic_connector_get_property(struct drm_connector *connector, } else if (property == config->writeback_fb_id_property) { /* Writeback framebuffer is one-shot, write and forget */ *val = 0; + } else if (property == config->writeback_out_fence_ptr_property) { + *val = 0; } else if (connector->funcs->atomic_get_property) { return connector->funcs->atomic_get_property(connector, state, property, val); @@ -2292,7 +2334,7 @@ static int setup_out_fence(struct drm_out_fence_state *fence_state, return 0; } -static int prepare_crtc_signaling(struct drm_device *dev, +static int prepare_signaling(struct drm_device *dev, struct drm_atomic_state *state, struct drm_mode_atomic *arg, struct drm_file *file_priv, @@ -2301,6 +2343,8 @@ static int prepare_crtc_signaling(struct drm_device *dev, { struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; + struct drm_connector *conn; + struct drm_connector_state *conn_state; int i, c = 0, ret; if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) @@ -2366,6 +2410,43 @@ static int prepare_crtc_signaling(struct drm_device *dev, c++; } + for_each_new_connector_in_state(state, conn, conn_state, i) { + struct drm_writeback_job *job; + struct drm_out_fence_state *f; + struct dma_fence *fence; + s32 __user *fence_ptr; + + fence_ptr = get_out_fence_for_connector(state, conn); + if (!fence_ptr) + continue; + + job = drm_atomic_get_writeback_job(conn_state); + if (!job) + return -ENOMEM; + + f = krealloc(*fence_state, sizeof(**fence_state) * + (*num_fences + 1), GFP_KERNEL); + if (!f) + return -ENOMEM; + + memset(&f[*num_fences], 0, sizeof(*f)); + + f[*num_fences].out_fence_ptr = fence_ptr; + *fence_state = f; + + fence = drm_writeback_get_out_fence((struct drm_writeback_connector *)conn); + if (!fence) + return -ENOMEM; + + ret = setup_out_fence(&f[(*num_fences)++], fence); + if (ret) { + dma_fence_put(fence); + return ret; + } + + job->out_fence = fence; + } + /* * Having this flag means user mode pends on event which will never * reach due to lack of at least one CRTC for signaling @@ -2376,11 +2457,11 @@ static int prepare_crtc_signaling(struct drm_device *dev, return 0; } -static void complete_crtc_signaling(struct drm_device *dev, - struct drm_atomic_state *state, - struct drm_out_fence_state *fence_state, - unsigned int num_fences, - bool install_fds) +static void complete_signaling(struct drm_device *dev, + struct drm_atomic_state *state, + struct drm_out_fence_state *fence_state, + unsigned int num_fences, + bool install_fds) { struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; @@ -2550,8 +2631,8 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, drm_mode_object_put(obj); } - ret = prepare_crtc_signaling(dev, state, arg, file_priv, &fence_state, - &num_fences); + ret = prepare_signaling(dev, state, arg, file_priv, &fence_state, + &num_fences); if (ret) goto out; @@ -2567,7 +2648,7 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, } out: - complete_crtc_signaling(dev, state, fence_state, num_fences, !ret); + complete_signaling(dev, state, fence_state, num_fences, !ret); if (ret == -EDEADLK) { drm_atomic_state_clear(state); diff --git a/drivers/gpu/drm/drm_writeback.c b/drivers/gpu/drm/drm_writeback.c index e5b8a4b79724b..827395071f0b5 100644 --- a/drivers/gpu/drm/drm_writeback.c +++ b/drivers/gpu/drm/drm_writeback.c @@ -14,6 +14,7 @@ #include <drm/drm_property.h> #include <drm/drm_writeback.h> #include <drm/drmP.h> +#include <linux/dma-fence.h> /** * DOC: overview @@ -31,6 +32,16 @@ * framebuffer applies only to a single commit (see below). A framebuffer may * not be attached while the CRTC is off. * + * Unlike with planes, when a writeback framebuffer is removed by userspace DRM + * makes no attempt to remove it from active use by the connector. This is + * because no method is provided to abort a writeback operation, and in any + * case making a new commit whilst a writeback is ongoing is undefined (see + * WRITEBACK_OUT_FENCE_PTR below). As soon as the current writeback is finished, + * the framebuffer will automatically no longer be in active use. As it will + * also have already been removed from the framebuffer list, there will be no + * way for any userspace application to retrieve a reference to it in the + * intervening period. + * * Writeback connectors have some additional properties, which userspace * can use to query and control them: * @@ -47,8 +58,54 @@ * data is an array of u32 DRM_FORMAT_* fourcc values. * Userspace can use this blob to find out what pixel formats are supported * by the connector's writeback engine. + * + * "WRITEBACK_OUT_FENCE_PTR": + * Userspace can use this property to provide a pointer for the kernel to + * fill with a sync_file file descriptor, which will signal once the + * writeback is finished. The value should be the address of a 32-bit + * signed integer, cast to a u64. + * Userspace should wait for this fence to signal before making another + * commit affecting any of the same CRTCs, Planes or Connectors. + * **Failure to do so will result in undefined behaviour.** + * For this reason it is strongly recommended that all userspace + * applications making use of writeback connectors *always* retrieve an + * out-fence for the commit and use it appropriately. + * From userspace, this property will always read as zero. */ +#define fence_to_wb_connector(x) container_of(x->lock, \ + struct drm_writeback_connector, \ + fence_lock) + +static const char *drm_writeback_fence_get_driver_name(struct dma_fence *fence) +{ + struct drm_writeback_connector *wb_connector = + fence_to_wb_connector(fence); + + return wb_connector->base.dev->driver->name; +} + +static const char * +drm_writeback_fence_get_timeline_name(struct dma_fence *fence) +{ + struct drm_writeback_connector *wb_connector = + fence_to_wb_connector(fence); + + return wb_connector->timeline_name; +} + +static bool drm_writeback_fence_enable_signaling(struct dma_fence *fence) +{ + return true; +} + +static const struct dma_fence_ops drm_writeback_fence_ops = { + .get_driver_name = drm_writeback_fence_get_driver_name, + .get_timeline_name = drm_writeback_fence_get_timeline_name, + .enable_signaling = drm_writeback_fence_enable_signaling, + .wait = dma_fence_default_wait, +}; + static int create_writeback_properties(struct drm_device *dev) { struct drm_property *prop; @@ -72,6 +129,15 @@ static int create_writeback_properties(struct drm_device *dev) dev->mode_config.writeback_pixel_formats_property = prop; } + if (!dev->mode_config.writeback_out_fence_ptr_property) { + prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, + "WRITEBACK_OUT_FENCE_PTR", 0, + U64_MAX); + if (!prop) + return -ENOMEM; + dev->mode_config.writeback_out_fence_ptr_property = prop; + } + return 0; } @@ -141,6 +207,15 @@ int drm_writeback_connector_init(struct drm_device *dev, INIT_LIST_HEAD(&wb_connector->job_queue); spin_lock_init(&wb_connector->job_lock); + wb_connector->fence_context = dma_fence_context_alloc(1); + spin_lock_init(&wb_connector->fence_lock); + snprintf(wb_connector->timeline_name, + sizeof(wb_connector->timeline_name), + "CONNECTOR:%d-%s", connector->base.id, connector->name); + + drm_object_attach_property(&connector->base, + config->writeback_out_fence_ptr_property, 0); + drm_object_attach_property(&connector->base, config->writeback_fb_id_property, 0); @@ -210,6 +285,7 @@ static void cleanup_work(struct work_struct *work) /** * drm_writeback_signal_completion - Signal the completion of a writeback job * @wb_connector: The writeback connector whose job is complete + * @status: Status code to set in the writeback out_fence (0 for success) * * Drivers should call this to signal the completion of a previously queued * writeback job. It should be called as soon as possible after the hardware @@ -223,7 +299,8 @@ static void cleanup_work(struct work_struct *work) * See also: drm_writeback_queue_job() */ void -drm_writeback_signal_completion(struct drm_writeback_connector *wb_connector) +drm_writeback_signal_completion(struct drm_writeback_connector *wb_connector, + int status) { unsigned long flags; struct drm_writeback_job *job; @@ -232,8 +309,15 @@ drm_writeback_signal_completion(struct drm_writeback_connector *wb_connector) job = list_first_entry_or_null(&wb_connector->job_queue, struct drm_writeback_job, list_entry); - if (job) + if (job) { list_del(&job->list_entry); + if (job->out_fence) { + if (status) + dma_fence_set_error(job->out_fence, status); + dma_fence_signal(job->out_fence); + dma_fence_put(job->out_fence); + } + } spin_unlock_irqrestore(&wb_connector->job_lock, flags); if (WARN_ON(!job)) @@ -243,3 +327,24 @@ drm_writeback_signal_completion(struct drm_writeback_connector *wb_connector) queue_work(system_long_wq, &job->cleanup_work); } EXPORT_SYMBOL(drm_writeback_signal_completion); + +struct dma_fence * +drm_writeback_get_out_fence(struct drm_writeback_connector *wb_connector) +{ + struct dma_fence *fence; + + if (WARN_ON(wb_connector->base.connector_type != + DRM_MODE_CONNECTOR_WRITEBACK)) + return NULL; + + fence = kzalloc(sizeof(*fence), GFP_KERNEL); + if (!fence) + return NULL; + + dma_fence_init(fence, &drm_writeback_fence_ops, + &wb_connector->fence_lock, wb_connector->fence_context, + ++wb_connector->fence_seqno); + + return fence; +} +EXPORT_SYMBOL(drm_writeback_get_out_fence); diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 8254521b4583f..da9d95a195809 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -160,6 +160,14 @@ struct __drm_crtcs_state { struct __drm_connnectors_state { struct drm_connector *ptr; struct drm_connector_state *state, *old_state, *new_state; + /** + * @out_fence_ptr: + * + * User-provided pointer which the kernel uses to return a sync_file + * file descriptor. Used by writeback connectors to signal completion of + * the writeback. + */ + s32 __user *out_fence_ptr; }; struct drm_private_obj; diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 716c3a0e0e1df..14ab58ade87f6 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -441,10 +441,10 @@ struct drm_connector_state { /** * @writeback_job: Writeback job for writeback connectors * - * Holds the framebuffer for a writeback connector. As the writeback - * completion may be asynchronous to the normal commit cycle, the - * writeback job lifetime is managed separately from the normal atomic - * state by this object. + * Holds the framebuffer and out-fence for a writeback connector. As + * the writeback completion may be asynchronous to the normal commit + * cycle, the writeback job lifetime is managed separately from the + * normal atomic state by this object. * * See also: drm_writeback_queue_job() and * drm_writeback_signal_completion() diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h index 5f24329e69277..f4a173c8d79ca 100644 --- a/include/drm/drm_mode_config.h +++ b/include/drm/drm_mode_config.h @@ -798,6 +798,14 @@ struct drm_mode_config { * See also: drm_writeback_connector_init() */ struct drm_property *writeback_pixel_formats_property; + /** + * @writeback_out_fence_ptr_property: Property for writeback connectors, + * fd pointer representing the outgoing fences for a writeback + * connector. Userspace should provide a pointer to a value of type s32, + * and then cast that pointer to u64. + * See also: drm_writeback_connector_init() + */ + struct drm_property *writeback_out_fence_ptr_property; /* dumb ioctl parameters */ uint32_t preferred_depth, prefer_shadow; diff --git a/include/drm/drm_writeback.h b/include/drm/drm_writeback.h index 17cd1feecd7e5..a10fe556dfd45 100644 --- a/include/drm/drm_writeback.h +++ b/include/drm/drm_writeback.h @@ -50,6 +50,32 @@ struct drm_writeback_connector { * drm_writeback_signal_completion() */ struct list_head job_queue; + + /** + * @fence_context: + * + * timeline context used for fence operations. + */ + unsigned int fence_context; + /** + * @fence_lock: + * + * spinlock to protect the fences in the fence_context. + */ + spinlock_t fence_lock; + /** + * @fence_seqno: + * + * Seqno variable used as monotonic counter for the fences + * created on the connector's timeline. + */ + unsigned long fence_seqno; + /** + * @timeline_name: + * + * The name of the connector's fence timeline. + */ + char timeline_name[32]; }; struct drm_writeback_job { @@ -75,6 +101,13 @@ struct drm_writeback_job { * directly, use drm_atomic_set_writeback_fb_for_connector() */ struct drm_framebuffer *fb; + + /** + * @out_fence: + * + * Fence which will signal once the writeback has completed + */ + struct dma_fence *out_fence; }; int drm_writeback_connector_init(struct drm_device *dev, @@ -87,5 +120,11 @@ void drm_writeback_queue_job(struct drm_writeback_connector *wb_connector, struct drm_writeback_job *job); void drm_writeback_cleanup_job(struct drm_writeback_job *job); -void drm_writeback_signal_completion(struct drm_writeback_connector *wb_connector); + +void +drm_writeback_signal_completion(struct drm_writeback_connector *wb_connector, + int status); + +struct dma_fence * +drm_writeback_get_out_fence(struct drm_writeback_connector *wb_connector); #endif -- GitLab From d67b6a2065076d763c7df626b8c54f16038ad862 Mon Sep 17 00:00:00 2001 From: Liviu Dudau <Liviu.Dudau@arm.com> Date: Wed, 28 Feb 2018 14:11:23 +0000 Subject: [PATCH 0448/1506] drm: writeback: Add client capability for exposing writeback connectors Due to the fact that writeback connectors behave in a special way in DRM (they always report being disconnected) we might confuse some userspace. Add a client capability for writeback connectors that will filter them out for clients that don't understand the capability. Changelog: - only accept the capability if the client has already set the DRM_CLIENT_CAP_ATOMIC one. Cc: Sean Paul <seanpaul@chromium.org> Cc: Brian Starkey <brian.starkey@arm.com> Signed-off-by: Liviu Dudau <liviu.dudau@arm.com> Reviewed-by: Eric Anholt <eric@anholt.net> Reviewed-by: Brian Starkey <brian.starkey@arm.com> Link: https://patchwork.freedesktop.org/patch/229038/ --- drivers/gpu/drm/drm_ioctl.c | 7 +++++++ drivers/gpu/drm/drm_mode_config.c | 5 +++++ include/drm/drm_file.h | 7 +++++++ include/uapi/drm/drm.h | 9 +++++++++ 4 files changed, 28 insertions(+) diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 0d4cfb232576f..fe49fb0356b5a 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -334,6 +334,13 @@ drm_setclientcap(struct drm_device *dev, void *data, struct drm_file *file_priv) return -EINVAL; file_priv->aspect_ratio_allowed = req->value; break; + case DRM_CLIENT_CAP_WRITEBACK_CONNECTORS: + if (!file_priv->atomic) + return -EINVAL; + if (req->value > 1) + return -EINVAL; + file_priv->writeback_connectors = req->value; + break; default: return -EINVAL; } diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c index e5c653357024d..21e353bd3948e 100644 --- a/drivers/gpu/drm/drm_mode_config.c +++ b/drivers/gpu/drm/drm_mode_config.c @@ -145,6 +145,11 @@ int drm_mode_getresources(struct drm_device *dev, void *data, count = 0; connector_id = u64_to_user_ptr(card_res->connector_id_ptr); drm_for_each_connector_iter(connector, &conn_iter) { + /* only expose writeback connectors if userspace understands them */ + if (!file_priv->writeback_connectors && + (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)) + continue; + if (drm_lease_held(file_priv, connector->base.id)) { if (count < card_res->count_connectors && put_user(connector->base.id, connector_id + count)) { diff --git a/include/drm/drm_file.h b/include/drm/drm_file.h index 027ac16da3d15..26485acc51d79 100644 --- a/include/drm/drm_file.h +++ b/include/drm/drm_file.h @@ -192,6 +192,13 @@ struct drm_file { */ unsigned aspect_ratio_allowed:1; + /** + * @writeback_connectors: + * + * True if client understands writeback connectors + */ + unsigned writeback_connectors:1; + /** * @is_master: * diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h index 9c660e1688abe..300f336633f28 100644 --- a/include/uapi/drm/drm.h +++ b/include/uapi/drm/drm.h @@ -687,6 +687,15 @@ struct drm_get_cap { */ #define DRM_CLIENT_CAP_ASPECT_RATIO 4 +/** + * DRM_CLIENT_CAP_WRITEBACK_CONNECTORS + * + * If set to 1, the DRM core will expose special connectors to be used for + * writing back to memory the scene setup in the commit. Depends on client + * also supporting DRM_CLIENT_CAP_ATOMIC + */ +#define DRM_CLIENT_CAP_WRITEBACK_CONNECTORS 5 + /** DRM_IOCTL_SET_CLIENT_CAP ioctl argument type */ struct drm_set_client_cap { __u64 capability; -- GitLab From f55786faa156370374c358d186eabf2f6e32e93f Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Wed, 20 Jun 2018 17:21:52 +0100 Subject: [PATCH 0449/1506] drm/i915/selftests: Remove unused dmabuf->kmap routines, fix the build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix i915's CI build after the removal of the dmabuf->kmap interface that left the mock routines intact. In file included from drivers/gpu/drm/i915/i915_gem_dmabuf.c:335:0: drivers/gpu/drm/i915/selftests/mock_dmabuf.c:104:13: error: ‘mock_dmabuf_kunmap_atomic’ defined but not used [-Werror=unused-function] static void mock_dmabuf_kunmap_atomic(struct dma_buf *dma_buf, unsigned long page_num, void *addr) drivers/gpu/drm/i915/selftests/mock_dmabuf.c:97:14: error: ‘mock_dmabuf_kmap_atomic’ defined but not used [-Werror=unused-function] static void *mock_dmabuf_kmap_atomic(struct dma_buf *dma_buf, unsigned long page_num) Fixes: f664a5269542 ("dma-buf: remove kmap_atomic interface") Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Christian König <christian.koenig@amd.com> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Cc: Sumit Semwal <sumit.semwal@linaro.org> Link: https://patchwork.freedesktop.org/patch/msgid/20180620162152.1158-1-chris@chris-wilson.co.uk Reviewed-by: Christian König <christian.koenig@amd.com> --- drivers/gpu/drm/i915/selftests/mock_dmabuf.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/drivers/gpu/drm/i915/selftests/mock_dmabuf.c b/drivers/gpu/drm/i915/selftests/mock_dmabuf.c index f81fda8ea45ed..ca682caf1062f 100644 --- a/drivers/gpu/drm/i915/selftests/mock_dmabuf.c +++ b/drivers/gpu/drm/i915/selftests/mock_dmabuf.c @@ -94,18 +94,6 @@ static void mock_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr) vm_unmap_ram(vaddr, mock->npages); } -static void *mock_dmabuf_kmap_atomic(struct dma_buf *dma_buf, unsigned long page_num) -{ - struct mock_dmabuf *mock = to_mock(dma_buf); - - return kmap_atomic(mock->pages[page_num]); -} - -static void mock_dmabuf_kunmap_atomic(struct dma_buf *dma_buf, unsigned long page_num, void *addr) -{ - kunmap_atomic(addr); -} - static void *mock_dmabuf_kmap(struct dma_buf *dma_buf, unsigned long page_num) { struct mock_dmabuf *mock = to_mock(dma_buf); -- GitLab From 98fa2aecb5096bbeb18f6509ffd181aafe4d267d Mon Sep 17 00:00:00 2001 From: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Date: Mon, 18 Jun 2018 15:02:07 -0700 Subject: [PATCH 0450/1506] drm/i915/psr: Fix warning in intel_psr_activate() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 5422b37c907e ("drm/i915/psr: Kill delays when activating psr back.") removed the call to cancel a scheduled psr_work from psr_disable() and instead added an early return in the work function. But, if the scheduled work item is executed after psr_enable(), we end up printing warnings as PSR is already enabled and active. So, put the cancel_work call back in psr_disable(). Cc: Rodrigo Vivi <rodrigo.vivi@intel.com> Cc: José Roberto de Souza <jose.souza@intel.com> Fixes: 5422b37c907e ("drm/i915/psr: Kill delays when activating psr back.") Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=106948 Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@gmail.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180618220207.2778-1-dhinakaran.pandiyan@intel.com --- drivers/gpu/drm/i915/intel_psr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index ef0f4741a95d2..d4cd19fea148f 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -754,6 +754,7 @@ void intel_psr_disable(struct intel_dp *intel_dp, dev_priv->psr.enabled = NULL; mutex_unlock(&dev_priv->psr.lock); + cancel_work_sync(&dev_priv->psr.work); } static bool psr_wait_for_idle(struct drm_i915_private *dev_priv) -- GitLab From c238ad62588981b3e83e1ba41bf5ec57b8875dd4 Mon Sep 17 00:00:00 2001 From: Colin Ian King <colin.king@canonical.com> Date: Wed, 20 Jun 2018 14:25:43 +0100 Subject: [PATCH 0451/1506] drm/i915/psr: fix copy-paste error with setting of tp2_wakeup_time_us Currently for the psr_table->tp2_tp3_wakeup_time case 3 there appears to be a copy-paste error from the previous switch statement where dev_priv->vbt.psr.tp1_wakeup_time_us is being assigned and I believe it should be dev_priv->vbt.psr.tp2_tp3_wakeup_time_us that should be assigned instead. Detected by CoverityScan, CID#1470105 ("Copy-paste error") Fixes: 77312ae8f071 ("drm/i915/psr: vbt change for psr") Signed-off-by: Colin Ian King <colin.king@canonical.com> Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180620132543.28092-1-colin.king@canonical.com --- drivers/gpu/drm/i915/intel_bios.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 03f04b4723945..1faa494e2bc91 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -740,7 +740,7 @@ parse_psr(struct drm_i915_private *dev_priv, const struct bdb_header *bdb) dev_priv->vbt.psr.tp2_tp3_wakeup_time_us = 100; break; case 3: - dev_priv->vbt.psr.tp1_wakeup_time_us = 0; + dev_priv->vbt.psr.tp2_tp3_wakeup_time_us = 0; break; default: DRM_DEBUG_KMS("VBT tp2_tp3 wakeup time value %d is outside range[0-3], defaulting to max value 2500us\n", -- GitLab From cd9e11a8bf259550577e2df7163d43a8a5655739 Mon Sep 17 00:00:00 2001 From: Radhakrishna Sripada <radhakrishna.sripada@intel.com> Date: Mon, 21 May 2018 17:25:51 -0700 Subject: [PATCH 0452/1506] drm/i915/icl: Add 10-bit support for hdmi MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Starting Icelake silicon supports 10-bpc hdmi to support certain media workloads. Currently hdmi supports 8 and 12 bpc. Plumbed in support for 10 bit hdmi. Cc: James Ausmus <james.ausmus@intel.com> Cc: Jani Nikula <jani.nikula@linux.intel.com> Cc: Paulo Zanoni <paulo.r.zanoni@intel.com> Cc: Manasi Navare <manasi.d.navare@intel.com> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Radhakrishna Sripada <radhakrishna.sripada@intel.com> Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180522002558.29262-18-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/intel_hdmi.c | 64 +++++++++++++++++++++++-------- 1 file changed, 48 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 8398d4b317128..98ad4313d9f20 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1566,14 +1566,23 @@ intel_hdmi_mode_valid(struct drm_connector *connector, /* check if we can do 8bpc */ status = hdmi_port_clock_valid(hdmi, clock, true, force_dvi); - /* if we can't do 8bpc we may still be able to do 12bpc */ - if (!HAS_GMCH_DISPLAY(dev_priv) && status != MODE_OK && hdmi->has_hdmi_sink && !force_dvi) - status = hdmi_port_clock_valid(hdmi, clock * 3 / 2, true, force_dvi); + if (hdmi->has_hdmi_sink && !force_dvi) { + /* if we can't do 8bpc we may still be able to do 12bpc */ + if (status != MODE_OK && !HAS_GMCH_DISPLAY(dev_priv)) + status = hdmi_port_clock_valid(hdmi, clock * 3 / 2, + true, force_dvi); + + /* if we can't do 8,12bpc we may still be able to do 10bpc */ + if (status != MODE_OK && INTEL_GEN(dev_priv) >= 11) + status = hdmi_port_clock_valid(hdmi, clock * 5 / 4, + true, force_dvi); + } return status; } -static bool hdmi_12bpc_possible(const struct intel_crtc_state *crtc_state) +static bool hdmi_deep_color_possible(const struct intel_crtc_state *crtc_state, + int bpc) { struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev); @@ -1585,6 +1594,9 @@ static bool hdmi_12bpc_possible(const struct intel_crtc_state *crtc_state) if (HAS_GMCH_DISPLAY(dev_priv)) return false; + if (bpc == 10 && INTEL_GEN(dev_priv) < 11) + return false; + if (crtc_state->pipe_bpp <= 8*3) return false; @@ -1592,7 +1604,7 @@ static bool hdmi_12bpc_possible(const struct intel_crtc_state *crtc_state) return false; /* - * HDMI 12bpc affects the clocks, so it's only possible + * HDMI deep color affects the clocks, so it's only possible * when not cloning with other encoder types. */ if (crtc_state->output_types != 1 << INTEL_OUTPUT_HDMI) @@ -1607,16 +1619,24 @@ static bool hdmi_12bpc_possible(const struct intel_crtc_state *crtc_state) if (crtc_state->ycbcr420) { const struct drm_hdmi_info *hdmi = &info->hdmi; - if (!(hdmi->y420_dc_modes & DRM_EDID_YCBCR420_DC_36)) + if (bpc == 12 && !(hdmi->y420_dc_modes & + DRM_EDID_YCBCR420_DC_36)) + return false; + else if (bpc == 10 && !(hdmi->y420_dc_modes & + DRM_EDID_YCBCR420_DC_30)) return false; } else { - if (!(info->edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_36)) + if (bpc == 12 && !(info->edid_hdmi_dc_modes & + DRM_EDID_HDMI_DC_36)) + return false; + else if (bpc == 10 && !(info->edid_hdmi_dc_modes & + DRM_EDID_HDMI_DC_30)) return false; } } /* Display WA #1139: glk */ - if (IS_GLK_REVID(dev_priv, 0, GLK_REVID_A1) && + if (bpc == 12 && IS_GLK_REVID(dev_priv, 0, GLK_REVID_A1) && crtc_state->base.adjusted_mode.htotal > 5460) return false; @@ -1626,7 +1646,8 @@ static bool hdmi_12bpc_possible(const struct intel_crtc_state *crtc_state) static bool intel_hdmi_ycbcr420_config(struct drm_connector *connector, struct intel_crtc_state *config, - int *clock_12bpc, int *clock_8bpc) + int *clock_12bpc, int *clock_10bpc, + int *clock_8bpc) { struct intel_crtc *intel_crtc = to_intel_crtc(config->base.crtc); @@ -1638,6 +1659,7 @@ intel_hdmi_ycbcr420_config(struct drm_connector *connector, /* YCBCR420 TMDS rate requirement is half the pixel clock */ config->port_clock /= 2; *clock_12bpc /= 2; + *clock_10bpc /= 2; *clock_8bpc /= 2; config->ycbcr420 = true; @@ -1665,6 +1687,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, struct intel_digital_connector_state *intel_conn_state = to_intel_digital_connector_state(conn_state); int clock_8bpc = pipe_config->base.adjusted_mode.crtc_clock; + int clock_10bpc = clock_8bpc * 5 / 4; int clock_12bpc = clock_8bpc * 3 / 2; int desired_bpp; bool force_dvi = intel_conn_state->force_audio == HDMI_AUDIO_OFF_DVI; @@ -1691,12 +1714,14 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) { pipe_config->pixel_multiplier = 2; clock_8bpc *= 2; + clock_10bpc *= 2; clock_12bpc *= 2; } if (drm_mode_is_420_only(&connector->display_info, adjusted_mode)) { if (!intel_hdmi_ycbcr420_config(connector, pipe_config, - &clock_12bpc, &clock_8bpc)) { + &clock_12bpc, &clock_10bpc, + &clock_8bpc)) { DRM_ERROR("Can't support YCBCR420 output\n"); return false; } @@ -1714,18 +1739,25 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, } /* - * HDMI is either 12 or 8, so if the display lets 10bpc sneak - * through, clamp it down. Note that g4x/vlv don't support 12bpc hdmi - * outputs. We also need to check that the higher clock still fits - * within limits. + * Note that g4x/vlv don't support 12bpc hdmi outputs. We also need + * to check that the higher clock still fits within limits. */ - if (hdmi_12bpc_possible(pipe_config) && - hdmi_port_clock_valid(intel_hdmi, clock_12bpc, true, force_dvi) == MODE_OK) { + if (hdmi_deep_color_possible(pipe_config, 12) && + hdmi_port_clock_valid(intel_hdmi, clock_12bpc, + true, force_dvi) == MODE_OK) { DRM_DEBUG_KMS("picking bpc to 12 for HDMI output\n"); desired_bpp = 12*3; /* Need to adjust the port link by 1.5x for 12bpc. */ pipe_config->port_clock = clock_12bpc; + } else if (hdmi_deep_color_possible(pipe_config, 10) && + hdmi_port_clock_valid(intel_hdmi, clock_10bpc, + true, force_dvi) == MODE_OK) { + DRM_DEBUG_KMS("picking bpc to 10 for HDMI output\n"); + desired_bpp = 10 * 3; + + /* Need to adjust the port link by 1.25x for 10bpc. */ + pipe_config->port_clock = clock_10bpc; } else { DRM_DEBUG_KMS("picking bpc to 8 for HDMI output\n"); desired_bpp = 8*3; -- GitLab From e1cacec9d50d7299893eeab2d895189f3db625da Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi <rodrigo.vivi@intel.com> Date: Wed, 20 Jun 2018 14:10:48 -0700 Subject: [PATCH 0453/1506] drm/i915: Update DRIVER_DATE to 20180620 Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com> --- drivers/gpu/drm/i915/i915_drv.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ebece44a807f7..735f695cb8899 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -86,8 +86,8 @@ #define DRIVER_NAME "i915" #define DRIVER_DESC "Intel Graphics" -#define DRIVER_DATE "20180606" -#define DRIVER_TIMESTAMP 1528323047 +#define DRIVER_DATE "20180620" +#define DRIVER_TIMESTAMP 1529529048 /* Use I915_STATE_WARN(x) and I915_STATE_WARN_ON() (rather than WARN() and * WARN_ON()) for hw state sanity checks to check for unexpected conditions -- GitLab From 26eb4cd6c7c7793ee76c73b66621f63daff51953 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Wed, 20 Jun 2018 14:59:29 +0100 Subject: [PATCH 0454/1506] drm/i915: Disable bh around call to tasklet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The guc submission backends expects to only be run from (at least) softirq context, but during our intel_engine_is_idle() check we would call into the tasklet to make sure it was flushed. As this could occur from process context, occasionally we would be caught out using a wait_for_atomic() not from an atomic context: [ 59.939091] WARN_ON_ONCE((1) && !(preempt_count() != 0)) [ 59.939142] WARNING: CPU: 1 PID: 2901 at drivers/gpu/drm/i915/intel_guc_submission.c:615 guc_submission_tasklet+0x784/0xa90 [i915] [ 59.939143] Modules linked in: vgem snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_codec_generic i915 x86_pkg_temp_thermal intel_powerclamp coretemp crct10dif_pclmul snd_hda_intel crc32_pclmul snd_hda_codec ghash_clmulni_intel snd_hwdep snd_hda_core e1000e snd_pcm mei_me mei prime_numbers [ 59.939164] CPU: 1 PID: 2901 Comm: gem_exec_schedu Tainted: G U W 4.18.0-rc1-g93475d62c730-drmtip_67+ #1 [ 59.939165] Hardware name: System manufacturer System Product Name/Z170M-PLUS, BIOS 3610 03/29/2018 [ 59.939188] RIP: 0010:guc_submission_tasklet+0x784/0xa90 [i915] [ 59.939189] Code: fc ff ff 80 3d 2f 87 11 00 00 0f 85 80 fb ff ff 48 c7 c6 f8 49 40 c0 48 c7 c7 80 41 3e c0 c6 05 14 87 11 00 01 e8 2c ea d6 d3 <0f> 0b e9 5f fb ff ff 8b 46 38 89 cf 31 c7 83 e7 c0 75 08 39 c1 0f [ 59.939253] RSP: 0018:ffffaafe08a03c10 EFLAGS: 00010286 [ 59.939255] RAX: 0000000000000000 RBX: ffff8f9112c246f0 RCX: 0000000000000001 [ 59.939256] RDX: 0000000080000001 RSI: ffffffff95086d8e RDI: 00000000ffffffff [ 59.939257] RBP: ffff8f9112c24680 R08: 000000009517be77 R09: 0000000000000000 [ 59.939258] R10: 0000000000000000 R11: 0000000000000000 R12: ffff8f9112c24700 [ 59.939259] R13: ffff8f9112c24700 R14: 0000000000000000 R15: ffff8f9112c242a8 [ 59.939260] FS: 00007fc2cc7e5980(0000) GS:ffff8f9136c40000(0000) knlGS:0000000000000000 [ 59.939261] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 59.939262] CR2: 00007fc2cc815040 CR3: 000000021f10e003 CR4: 00000000003606e0 [ 59.939263] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 59.939264] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 59.939265] Call Trace: [ 59.939288] ? intel_engine_is_idle+0x64/0x160 [i915] [ 59.939323] ? intel_engine_dump+0x638/0x890 [i915] [ 59.939327] ? seq_printf+0x49/0x70 [ 59.939353] ? i915_engine_info+0xc8/0x100 [i915] [ 59.939356] ? drm_get_color_range_name+0x20/0x20 [ 59.939361] ? seq_read+0xf1/0x470 [ 59.939365] ? trace_hardirqs_on_caller+0xe0/0x1b0 [ 59.939370] ? full_proxy_read+0x51/0x80 [ 59.939389] ? __vfs_read+0x31/0x170 [ 59.939395] ? do_sys_open+0x13b/0x240 [ 59.939398] ? rcu_read_lock_sched_held+0x6f/0x80 [ 59.939401] ? vfs_read+0x9e/0x140 [ 59.939404] ? ksys_read+0x50/0xc0 [ 59.939409] ? do_syscall_64+0x55/0x190 [ 59.939412] ? entry_SYSCALL_64_after_hwframe+0x49/0xbe [ 59.939420] irq event stamp: 552834 [ 59.939422] hardirqs last enabled at (552833): [<ffffffff940fc74c>] console_unlock+0x3fc/0x600 [ 59.939425] hardirqs last disabled at (552834): [<ffffffff94a0111c>] error_entry+0x7c/0x100 [ 59.939451] softirqs last enabled at (552614): [<ffffffffc02e0f53>] i915_request_add+0x2e3/0x7b0 [i915] [ 59.939470] softirqs last disabled at (552604): [<ffffffffc02e0ecb>] i915_request_add+0x25b/0x7b0 [i915] Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=106977 Fixes: dd0cf235d81f ("drm/i915: Speed up idle detection by kicking the tasklets") Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: Michal Wajdeczko <michal.wajdeczko@intel.com> Cc: MichaÅ‚ Winiarski <michal.winiarski@intel.com> Cc: Michel Thierry <michel.thierry@intel.com> Reviewed-by: Michel Thierry <michel.thierry@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180620135929.23956-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_engine_cs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index 32bf3a408d464..d3264bd6e9dcc 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -1000,10 +1000,12 @@ bool intel_engine_is_idle(struct intel_engine_cs *engine) if (READ_ONCE(engine->execlists.active)) { struct intel_engine_execlists *execlists = &engine->execlists; + local_bh_disable(); if (tasklet_trylock(&execlists->tasklet)) { execlists->tasklet.func(execlists->tasklet.data); tasklet_unlock(&execlists->tasklet); } + local_bh_enable(); if (READ_ONCE(execlists->active)) return false; -- GitLab From 827db9d8bb4a01314f214065e3f18c8345c5fc9f Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 21 Jun 2018 08:32:05 +0100 Subject: [PATCH 0455/1506] drm/i915: Ignore applying the self-relocation BIAS if no relocations We only need to apply the BIAS for self-relocations into the batchbuffer iff the execobject has any relocations. This suppresses some warnings we may get with a full gtt (so the batch object has wound up at 0 from a previous invocation), but doesn't fix the underlying problem of how we tried to move a pinned batch vma (how we have a pinned user vma outside of execbuf, I do not know, though this being on an aliasing ppgtt means it could be a spurious pinning via the global gtt). One step at a time... References: https://bugs.freedesktop.org/show_bug.cgi?id=106744#c1 Testcase: igt/gem_exec_gttfill # byt (sporadic) Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180621073205.26701-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 60dc2a865f5f9..437441f4af412 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -534,7 +534,8 @@ eb_add_vma(struct i915_execbuffer *eb, * paranoia do it everywhere. */ if (i == batch_idx) { - if (!(eb->flags[i] & EXEC_OBJECT_PINNED)) + if (entry->relocation_count && + !(eb->flags[i] & EXEC_OBJECT_PINNED)) eb->flags[i] |= __EXEC_OBJECT_NEEDS_BIAS; if (eb->reloc_cache.has_fence) eb->flags[i] |= EXEC_OBJECT_NEEDS_FENCE; -- GitLab From d20ac620f0010f9cdcbbe8408e5f22aae3c49faa Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 21 Jun 2018 09:01:50 +0100 Subject: [PATCH 0456/1506] drm/i915: Redefine EINVAL for debugging To aide debugging spurious EINVALs, include a debug message every time we emit one from execbuf. References: https://bugs.freedesktop.org/show_bug.cgi?id=106744 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180621080150.8110-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 437441f4af412..c2dd9b4cdacea 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -66,6 +66,15 @@ enum { #define __I915_EXEC_ILLEGAL_FLAGS \ (__I915_EXEC_UNKNOWN_FLAGS | I915_EXEC_CONSTANTS_MASK) +/* Catch emission of unexpected errors for CI! */ +#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM) +#undef EINVAL +#define EINVAL ({ \ + DRM_DEBUG_DRIVER("EINVAL at %s:%d\n", __func__, __LINE__); \ + 22; \ +}) +#endif + /** * DOC: User command execution * -- GitLab From c612ae0503af753c062594dcd14aecea121fa414 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Wed, 20 Jun 2018 20:48:59 +0200 Subject: [PATCH 0457/1506] staging: android: ion: fix ion_dma_buf_attach signatur MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixup for "dma_buf: remove device parameter from attach callback v2". I missed this driver, sorry for the noise. Patch is not even compile tested. Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/230641/ --- drivers/staging/android/ion/ion.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index a5220445b5e8f..3d4d35558937a 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -201,7 +201,7 @@ struct ion_dma_buf_attachment { struct list_head list; }; -static int ion_dma_buf_attach(struct dma_buf *dmabuf, struct device *dev, +static int ion_dma_buf_attach(struct dma_buf *dmabuf, struct dma_buf_attachment *attachment) { struct ion_dma_buf_attachment *a; @@ -219,7 +219,7 @@ static int ion_dma_buf_attach(struct dma_buf *dmabuf, struct device *dev, } a->table = table; - a->dev = dev; + a->dev = attachment->dev; INIT_LIST_HEAD(&a->list); attachment->priv = a; -- GitLab From 8a29c778fa1a50a25a3e66cf9589888758858d24 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi <lucas.demarchi@intel.com> Date: Wed, 23 May 2018 11:04:35 -0700 Subject: [PATCH 0458/1506] drm/i915: remove check for aux irq MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This became dead code with commit 309bd8ed464f ("drm/i915: Reinstate GMBUS and AUX interrupts on gen4/g4x"). v2: Move comment about HW behavior to where decision is made to enable MSI (Ville). Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180523180435.18042-1-lucas.demarchi@intel.com --- drivers/gpu/drm/i915/i915_drv.c | 6 ++++++ drivers/gpu/drm/i915/i915_drv.h | 10 ---------- drivers/gpu/drm/i915/intel_dp.c | 22 +++++++--------------- drivers/gpu/drm/i915/intel_drv.h | 1 - drivers/gpu/drm/i915/intel_psr.c | 2 +- 5 files changed, 14 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 33453d56c3865..2959c88a37a59 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1165,6 +1165,12 @@ static int i915_driver_init_hw(struct drm_i915_private *dev_priv) * get lost on g4x as well, and interrupt delivery seems to stay * properly dead afterwards. So we'll just disable them for all * pre-gen5 chipsets. + * + * dp aux and gmbus irq on gen4 seems to be able to generate legacy + * interrupts even when in MSI mode. This results in spurious + * interrupt warnings if the legacy irq no. is shared with another + * device. The kernel then disables that interrupt source and so + * prevents the other device from working properly. */ if (INTEL_GEN(dev_priv) >= 5) { if (pci_enable_msi(pdev) < 0) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 735f695cb8899..6f08ab310118a 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2581,16 +2581,6 @@ intel_info(const struct drm_i915_private *dev_priv) (IS_CANNONLAKE(dev_priv) || \ IS_SKL_GT3(dev_priv) || IS_SKL_GT4(dev_priv)) -/* - * dp aux and gmbus irq on gen4 seems to be able to generate legacy interrupts - * even when in MSI mode. This results in spurious interrupt warnings if the - * legacy irq no. is shared with another device. The kernel then disables that - * interrupt source and so prevents the other device from working properly. - * - * Since we don't enable MSI anymore on gen4, we can always use GMBUS/AUX - * interrupts. - */ -#define HAS_AUX_IRQ(dev_priv) true #define HAS_GMBUS_IRQ(dev_priv) (INTEL_GEN(dev_priv) >= 4) /* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 6ac6c8787dcf6..c1b2f00f324bc 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -953,7 +953,7 @@ intel_dp_check_edp(struct intel_dp *intel_dp) } static uint32_t -intel_dp_aux_wait_done(struct intel_dp *intel_dp, bool has_aux_irq) +intel_dp_aux_wait_done(struct intel_dp *intel_dp) { struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); i915_reg_t ch_ctl = intel_dp->aux_ch_ctl_reg(intel_dp); @@ -961,14 +961,10 @@ intel_dp_aux_wait_done(struct intel_dp *intel_dp, bool has_aux_irq) bool done; #define C (((status = I915_READ_NOTRACE(ch_ctl)) & DP_AUX_CH_CTL_SEND_BUSY) == 0) - if (has_aux_irq) - done = wait_event_timeout(dev_priv->gmbus_wait_queue, C, - msecs_to_jiffies_timeout(10)); - else - done = wait_for(C, 10) == 0; + done = wait_event_timeout(dev_priv->gmbus_wait_queue, C, + msecs_to_jiffies_timeout(10)); if (!done) - DRM_ERROR("dp aux hw did not signal timeout (has irq: %i)!\n", - has_aux_irq); + DRM_ERROR("dp aux hw did not signal timeout!\n"); #undef C return status; @@ -1033,7 +1029,6 @@ static uint32_t skl_get_aux_clock_divider(struct intel_dp *intel_dp, int index) } static uint32_t g4x_get_aux_send_ctl(struct intel_dp *intel_dp, - bool has_aux_irq, int send_bytes, uint32_t aux_clock_divider) { @@ -1054,7 +1049,7 @@ static uint32_t g4x_get_aux_send_ctl(struct intel_dp *intel_dp, return DP_AUX_CH_CTL_SEND_BUSY | DP_AUX_CH_CTL_DONE | - (has_aux_irq ? DP_AUX_CH_CTL_INTERRUPT : 0) | + DP_AUX_CH_CTL_INTERRUPT | DP_AUX_CH_CTL_TIME_OUT_ERROR | timeout | DP_AUX_CH_CTL_RECEIVE_ERROR | @@ -1064,13 +1059,12 @@ static uint32_t g4x_get_aux_send_ctl(struct intel_dp *intel_dp, } static uint32_t skl_get_aux_send_ctl(struct intel_dp *intel_dp, - bool has_aux_irq, int send_bytes, uint32_t unused) { return DP_AUX_CH_CTL_SEND_BUSY | DP_AUX_CH_CTL_DONE | - (has_aux_irq ? DP_AUX_CH_CTL_INTERRUPT : 0) | + DP_AUX_CH_CTL_INTERRUPT | DP_AUX_CH_CTL_TIME_OUT_ERROR | DP_AUX_CH_CTL_TIME_OUT_MAX | DP_AUX_CH_CTL_RECEIVE_ERROR | @@ -1093,7 +1087,6 @@ intel_dp_aux_xfer(struct intel_dp *intel_dp, int i, ret, recv_bytes; uint32_t status; int try, clock = 0; - bool has_aux_irq = HAS_AUX_IRQ(dev_priv); bool vdd; ch_ctl = intel_dp->aux_ch_ctl_reg(intel_dp); @@ -1148,7 +1141,6 @@ intel_dp_aux_xfer(struct intel_dp *intel_dp, while ((aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, clock++))) { u32 send_ctl = intel_dp->get_aux_send_ctl(intel_dp, - has_aux_irq, send_bytes, aux_clock_divider); @@ -1165,7 +1157,7 @@ intel_dp_aux_xfer(struct intel_dp *intel_dp, /* Send the command and wait for it to complete */ I915_WRITE(ch_ctl, send_ctl); - status = intel_dp_aux_wait_done(intel_dp, has_aux_irq); + status = intel_dp_aux_wait_done(intel_dp); /* Clear done status and any errors */ I915_WRITE(ch_ctl, diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 22831acc7c30f..9e0a8cc485211 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1132,7 +1132,6 @@ struct intel_dp { * register with to kick off an AUX transaction. */ uint32_t (*get_aux_send_ctl)(struct intel_dp *dp, - bool has_aux_irq, int send_bytes, uint32_t aux_clock_divider); diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index d4cd19fea148f..aea81ace854b3 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -336,7 +336,7 @@ static void hsw_psr_setup_aux(struct intel_dp *intel_dp) aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, 0); /* Start with bits set for DDI_AUX_CTL register */ - aux_ctl = intel_dp->get_aux_send_ctl(intel_dp, 0, sizeof(aux_msg), + aux_ctl = intel_dp->get_aux_send_ctl(intel_dp, sizeof(aux_msg), aux_clock_divider); /* Select only valid bits for SRD_AUX_CTL */ -- GitLab From 9fc59bae0f4a8ec3676a9245abed7721b4d3d8c9 Mon Sep 17 00:00:00 2001 From: Imre Deak <imre.deak@intel.com> Date: Fri, 15 Jun 2018 17:39:10 +0300 Subject: [PATCH 0459/1506] drm/i915/icl: Fix MG PLL setup when refclk is 38.4MHz Atm we're zeroing out fields in MG_PLL_BIAS and MG_PLL_TDC_COLDST_BIAS if refclk is 38.4MHz, whereas the spec tells us to preserve them. Although the calculated values mostly match the register defaults even for the 38.4MHz case, there are some differences wrt. what BIOS programs (I noticed at least differences in the MG_PLL_BIAS/IREFTRIM and MG_PLL_BIAS/BIASCAL_EN fields). In the lack of further info on how to program these fields, just do what the spec says and preserve the BIOS state. v2: - Preserve the BIOS programmed reg fields instead of programming them. Cc: Vandita Kulkarni <vandita.kulkarni@intel.com> Cc: Paulo Zanoni <paulo.r.zanoni@intel.com> Cc: James Ausmus <james.ausmus@intel.com> Signed-off-by: Imre Deak <imre.deak@intel.com> Reviewed-by: James Ausmus <james.ausmus@intel.com> (v1) Reviewed-by: Vandita Kulkarni <vandita.kulkarni@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180615143911.31082-1-imre.deak@intel.com --- drivers/gpu/drm/i915/intel_dpll_mgr.c | 67 +++++++++++++++++++-------- drivers/gpu/drm/i915/intel_dpll_mgr.h | 2 + 2 files changed, 49 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c index 132fe63e042af..d4c7bacbe83e3 100644 --- a/drivers/gpu/drm/i915/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c @@ -2812,25 +2812,31 @@ static bool icl_calc_mg_pll_state(struct intel_crtc_state *crtc_state, MG_PLL_SSC_FLLEN | MG_PLL_SSC_STEPSIZE(ssc_stepsize); - pll_state->mg_pll_tdc_coldst_bias = MG_PLL_TDC_COLDST_COLDSTART; - - if (refclk_khz != 38400) { - pll_state->mg_pll_tdc_coldst_bias |= - MG_PLL_TDC_COLDST_IREFINT_EN | - MG_PLL_TDC_COLDST_REFBIAS_START_PULSE_W(iref_pulse_w) | - MG_PLL_TDC_COLDST_COLDSTART | - MG_PLL_TDC_TDCOVCCORR_EN | - MG_PLL_TDC_TDCSEL(3); - - pll_state->mg_pll_bias = MG_PLL_BIAS_BIAS_GB_SEL(3) | - MG_PLL_BIAS_INIT_DCOAMP(0x3F) | - MG_PLL_BIAS_BIAS_BONUS(10) | - MG_PLL_BIAS_BIASCAL_EN | - MG_PLL_BIAS_CTRIM(12) | - MG_PLL_BIAS_VREF_RDAC(4) | - MG_PLL_BIAS_IREFTRIM(iref_trim); + pll_state->mg_pll_tdc_coldst_bias = MG_PLL_TDC_COLDST_COLDSTART | + MG_PLL_TDC_COLDST_IREFINT_EN | + MG_PLL_TDC_COLDST_REFBIAS_START_PULSE_W(iref_pulse_w) | + MG_PLL_TDC_TDCOVCCORR_EN | + MG_PLL_TDC_TDCSEL(3); + + pll_state->mg_pll_bias = MG_PLL_BIAS_BIAS_GB_SEL(3) | + MG_PLL_BIAS_INIT_DCOAMP(0x3F) | + MG_PLL_BIAS_BIAS_BONUS(10) | + MG_PLL_BIAS_BIASCAL_EN | + MG_PLL_BIAS_CTRIM(12) | + MG_PLL_BIAS_VREF_RDAC(4) | + MG_PLL_BIAS_IREFTRIM(iref_trim); + + if (refclk_khz == 38400) { + pll_state->mg_pll_tdc_coldst_bias_mask = MG_PLL_TDC_COLDST_COLDSTART; + pll_state->mg_pll_bias_mask = 0; + } else { + pll_state->mg_pll_tdc_coldst_bias_mask = -1U; + pll_state->mg_pll_bias_mask = -1U; } + pll_state->mg_pll_tdc_coldst_bias &= pll_state->mg_pll_tdc_coldst_bias_mask; + pll_state->mg_pll_bias &= pll_state->mg_pll_bias_mask; + return true; } @@ -2948,9 +2954,21 @@ static bool icl_pll_get_hw_state(struct drm_i915_private *dev_priv, hw_state->mg_pll_lf = I915_READ(MG_PLL_LF(port)); hw_state->mg_pll_frac_lock = I915_READ(MG_PLL_FRAC_LOCK(port)); hw_state->mg_pll_ssc = I915_READ(MG_PLL_SSC(port)); + hw_state->mg_pll_bias = I915_READ(MG_PLL_BIAS(port)); hw_state->mg_pll_tdc_coldst_bias = I915_READ(MG_PLL_TDC_COLDST_BIAS(port)); + + if (dev_priv->cdclk.hw.ref == 38400) { + hw_state->mg_pll_tdc_coldst_bias_mask = MG_PLL_TDC_COLDST_COLDSTART; + hw_state->mg_pll_bias_mask = 0; + } else { + hw_state->mg_pll_tdc_coldst_bias_mask = -1U; + hw_state->mg_pll_bias_mask = -1U; + } + + hw_state->mg_pll_tdc_coldst_bias &= hw_state->mg_pll_tdc_coldst_bias_mask; + hw_state->mg_pll_bias &= hw_state->mg_pll_bias_mask; break; default: MISSING_CASE(id); @@ -2978,6 +2996,7 @@ static void icl_mg_pll_write(struct drm_i915_private *dev_priv, { struct intel_dpll_hw_state *hw_state = &pll->state.hw_state; enum port port = icl_mg_pll_id_to_port(pll->info->id); + u32 val; I915_WRITE(MG_REFCLKIN_CTL(port), hw_state->mg_refclkin_ctl); I915_WRITE(MG_CLKTOP2_CORECLKCTL1(port), @@ -2988,9 +3007,17 @@ static void icl_mg_pll_write(struct drm_i915_private *dev_priv, I915_WRITE(MG_PLL_LF(port), hw_state->mg_pll_lf); I915_WRITE(MG_PLL_FRAC_LOCK(port), hw_state->mg_pll_frac_lock); I915_WRITE(MG_PLL_SSC(port), hw_state->mg_pll_ssc); - I915_WRITE(MG_PLL_BIAS(port), hw_state->mg_pll_bias); - I915_WRITE(MG_PLL_TDC_COLDST_BIAS(port), - hw_state->mg_pll_tdc_coldst_bias); + + val = I915_READ(MG_PLL_BIAS(port)); + val &= ~hw_state->mg_pll_bias_mask; + val |= hw_state->mg_pll_bias; + I915_WRITE(MG_PLL_BIAS(port), val); + + val = I915_READ(MG_PLL_TDC_COLDST_BIAS(port)); + val &= ~hw_state->mg_pll_tdc_coldst_bias_mask; + val |= hw_state->mg_pll_tdc_coldst_bias; + I915_WRITE(MG_PLL_TDC_COLDST_BIAS(port), val); + POSTING_READ(MG_PLL_TDC_COLDST_BIAS(port)); } diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.h b/drivers/gpu/drm/i915/intel_dpll_mgr.h index ba925c7ee4828..7e522cf4f13f3 100644 --- a/drivers/gpu/drm/i915/intel_dpll_mgr.h +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.h @@ -180,6 +180,8 @@ struct intel_dpll_hw_state { uint32_t mg_pll_ssc; uint32_t mg_pll_bias; uint32_t mg_pll_tdc_coldst_bias; + uint32_t mg_pll_bias_mask; + uint32_t mg_pll_tdc_coldst_bias_mask; }; /** -- GitLab From bd99ce085f165a07fe8b33ad04157b91c91b8668 Mon Sep 17 00:00:00 2001 From: Imre Deak <imre.deak@intel.com> Date: Tue, 19 Jun 2018 19:41:15 +0300 Subject: [PATCH 0460/1506] drm/i915/icl: Do read-modify-write as needed during MG PLL programming Some MG PLL registers have fields that need to be preserved at their HW default or BIOS programmed values. So make sure we preserve them. v2: - Add comment to icl_mg_pll_write() explaining the need for register masks. (Vandita) - Fix patchwork checkpatch warning. v3: - Rebase on drm-tip. Cc: Vandita Kulkarni <vandita.kulkarni@intel.com> Cc: Paulo Zanoni <paulo.r.zanoni@intel.com> Cc: James Ausmus <james.ausmus@intel.com> Signed-off-by: Imre Deak <imre.deak@intel.com> Reviewed-by: James Ausmus <james.ausmus@intel.com> (v1) Reviewed-by: Vandita Kulkarni <vandita.kulkarni@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180619164115.7835-1-imre.deak@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 13 +++++++++ drivers/gpu/drm/i915/intel_dpll_mgr.c | 39 ++++++++++++++++++++++++--- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 4bfd7a9bd75f5..65b222287ee4e 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -9047,6 +9047,7 @@ enum skl_power_gate { #define _MG_REFCLKIN_CTL_PORT3 0x16A92C #define _MG_REFCLKIN_CTL_PORT4 0x16B92C #define MG_REFCLKIN_CTL_OD_2_MUX(x) ((x) << 8) +#define MG_REFCLKIN_CTL_OD_2_MUX_MASK (0x7 << 8) #define MG_REFCLKIN_CTL(port) _MMIO_PORT((port) - PORT_C, \ _MG_REFCLKIN_CTL_PORT1, \ _MG_REFCLKIN_CTL_PORT2) @@ -9056,7 +9057,9 @@ enum skl_power_gate { #define _MG_CLKTOP2_CORECLKCTL1_PORT3 0x16A8D8 #define _MG_CLKTOP2_CORECLKCTL1_PORT4 0x16B8D8 #define MG_CLKTOP2_CORECLKCTL1_B_DIVRATIO(x) ((x) << 16) +#define MG_CLKTOP2_CORECLKCTL1_B_DIVRATIO_MASK (0xff << 16) #define MG_CLKTOP2_CORECLKCTL1_A_DIVRATIO(x) ((x) << 8) +#define MG_CLKTOP2_CORECLKCTL1_A_DIVRATIO_MASK (0xff << 8) #define MG_CLKTOP2_CORECLKCTL1(port) _MMIO_PORT((port) - PORT_C, \ _MG_CLKTOP2_CORECLKCTL1_PORT1, \ _MG_CLKTOP2_CORECLKCTL1_PORT2) @@ -9066,9 +9069,13 @@ enum skl_power_gate { #define _MG_CLKTOP2_HSCLKCTL_PORT3 0x16A8D4 #define _MG_CLKTOP2_HSCLKCTL_PORT4 0x16B8D4 #define MG_CLKTOP2_HSCLKCTL_CORE_INPUTSEL(x) ((x) << 16) +#define MG_CLKTOP2_HSCLKCTL_CORE_INPUTSEL_MASK (0x1 << 16) #define MG_CLKTOP2_HSCLKCTL_TLINEDRV_CLKSEL(x) ((x) << 14) +#define MG_CLKTOP2_HSCLKCTL_TLINEDRV_CLKSEL_MASK (0x3 << 14) #define MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO(x) ((x) << 12) +#define MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_MASK (0x3 << 12) #define MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO(x) ((x) << 8) +#define MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_MASK (0xf << 8) #define MG_CLKTOP2_HSCLKCTL(port) _MMIO_PORT((port) - PORT_C, \ _MG_CLKTOP2_HSCLKCTL_PORT1, \ _MG_CLKTOP2_HSCLKCTL_PORT2) @@ -9142,12 +9149,18 @@ enum skl_power_gate { #define _MG_PLL_BIAS_PORT3 0x16AA14 #define _MG_PLL_BIAS_PORT4 0x16BA14 #define MG_PLL_BIAS_BIAS_GB_SEL(x) ((x) << 30) +#define MG_PLL_BIAS_BIAS_GB_SEL_MASK (0x3 << 30) #define MG_PLL_BIAS_INIT_DCOAMP(x) ((x) << 24) +#define MG_PLL_BIAS_INIT_DCOAMP_MASK (0x3f << 24) #define MG_PLL_BIAS_BIAS_BONUS(x) ((x) << 16) +#define MG_PLL_BIAS_BIAS_BONUS_MASK (0xff << 16) #define MG_PLL_BIAS_BIASCAL_EN (1 << 15) #define MG_PLL_BIAS_CTRIM(x) ((x) << 8) +#define MG_PLL_BIAS_CTRIM_MASK (0x1f << 8) #define MG_PLL_BIAS_VREF_RDAC(x) ((x) << 5) +#define MG_PLL_BIAS_VREF_RDAC_MASK (0x7 << 5) #define MG_PLL_BIAS_IREFTRIM(x) ((x) << 0) +#define MG_PLL_BIAS_IREFTRIM_MASK (0x1f << 0) #define MG_PLL_BIAS(port) _MMIO_PORT((port) - PORT_C, _MG_PLL_BIAS_PORT1, \ _MG_PLL_BIAS_PORT2) diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c index d4c7bacbe83e3..57342364fd305 100644 --- a/drivers/gpu/drm/i915/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c @@ -2945,10 +2945,21 @@ static bool icl_pll_get_hw_state(struct drm_i915_private *dev_priv, case DPLL_ID_ICL_MGPLL4: port = icl_mg_pll_id_to_port(id); hw_state->mg_refclkin_ctl = I915_READ(MG_REFCLKIN_CTL(port)); + hw_state->mg_refclkin_ctl &= MG_REFCLKIN_CTL_OD_2_MUX_MASK; + hw_state->mg_clktop2_coreclkctl1 = I915_READ(MG_CLKTOP2_CORECLKCTL1(port)); + hw_state->mg_clktop2_coreclkctl1 &= + MG_CLKTOP2_CORECLKCTL1_A_DIVRATIO_MASK; + hw_state->mg_clktop2_hsclkctl = I915_READ(MG_CLKTOP2_HSCLKCTL(port)); + hw_state->mg_clktop2_hsclkctl &= + MG_CLKTOP2_HSCLKCTL_TLINEDRV_CLKSEL_MASK | + MG_CLKTOP2_HSCLKCTL_CORE_INPUTSEL_MASK | + MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_MASK | + MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_MASK; + hw_state->mg_pll_div0 = I915_READ(MG_PLL_DIV0(port)); hw_state->mg_pll_div1 = I915_READ(MG_PLL_DIV1(port)); hw_state->mg_pll_lf = I915_READ(MG_PLL_LF(port)); @@ -2998,10 +3009,30 @@ static void icl_mg_pll_write(struct drm_i915_private *dev_priv, enum port port = icl_mg_pll_id_to_port(pll->info->id); u32 val; - I915_WRITE(MG_REFCLKIN_CTL(port), hw_state->mg_refclkin_ctl); - I915_WRITE(MG_CLKTOP2_CORECLKCTL1(port), - hw_state->mg_clktop2_coreclkctl1); - I915_WRITE(MG_CLKTOP2_HSCLKCTL(port), hw_state->mg_clktop2_hsclkctl); + /* + * Some of the following registers have reserved fields, so program + * these with RMW based on a mask. The mask can be fixed or generated + * during the calc/readout phase if the mask depends on some other HW + * state like refclk, see icl_calc_mg_pll_state(). + */ + val = I915_READ(MG_REFCLKIN_CTL(port)); + val &= ~MG_REFCLKIN_CTL_OD_2_MUX_MASK; + val |= hw_state->mg_refclkin_ctl; + I915_WRITE(MG_REFCLKIN_CTL(port), val); + + val = I915_READ(MG_CLKTOP2_CORECLKCTL1(port)); + val &= ~MG_CLKTOP2_CORECLKCTL1_A_DIVRATIO_MASK; + val |= hw_state->mg_clktop2_coreclkctl1; + I915_WRITE(MG_CLKTOP2_CORECLKCTL1(port), val); + + val = I915_READ(MG_CLKTOP2_HSCLKCTL(port)); + val &= ~(MG_CLKTOP2_HSCLKCTL_TLINEDRV_CLKSEL_MASK | + MG_CLKTOP2_HSCLKCTL_CORE_INPUTSEL_MASK | + MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_MASK | + MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_MASK); + val |= hw_state->mg_clktop2_hsclkctl; + I915_WRITE(MG_CLKTOP2_HSCLKCTL(port), val); + I915_WRITE(MG_PLL_DIV0(port), hw_state->mg_pll_div0); I915_WRITE(MG_PLL_DIV1(port), hw_state->mg_pll_div1); I915_WRITE(MG_PLL_LF(port), hw_state->mg_pll_lf); -- GitLab From 8d4f4b82155cc6774d0fd8aaafb882566f7fd5fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Fri, 15 Jun 2018 20:39:39 +0300 Subject: [PATCH 0461/1506] drm: Document mode_config.max_width/height as the max fb dimensions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The meaning of the mode_config max_width/height fields has not been entirely clear. They are used both as the max framebuffer dimensions, and they are also used by drm_mode_getconnector() to filter out any mode whose hdisplay/vdisplay exceed those limits. Let's put it in writing that max_width/height only refrer to the max framebuffer dimensions, and should those be higher than the hardware limits for display timings the driver must validate the latter using some other means. We'll keep the max_width/height usage in drm_mode_getconnector() because setcrtc treats hdisplay/vdisplay also as the primary plane width, and having a plane bigger than the max fb size doesn't make much sense (if we ignore scaling that is). It all works out fine as long as the max fb dimensions are at least equal to the max timing limits. If the opposite were true we may want to rethink what drm_mode_getconnector() does. Maybe do the mode filtering only for non-atomic userspace? Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180615173939.11353-1-ville.syrjala@linux.intel.com Reviewed-by: Manasi Navare <manasi.d.navare@intel.com> --- include/drm/drm_mode_config.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h index f4a173c8d79ca..a0b202e1d69a0 100644 --- a/include/drm/drm_mode_config.h +++ b/include/drm/drm_mode_config.h @@ -329,10 +329,10 @@ struct drm_mode_config_funcs { /** * struct drm_mode_config - Mode configuration control structure - * @min_width: minimum pixel width on this device - * @min_height: minimum pixel height on this device - * @max_width: maximum pixel width on this device - * @max_height: maximum pixel height on this device + * @min_width: minimum fb pixel width on this device + * @min_height: minimum fb pixel height on this device + * @max_width: maximum fb pixel width on this device + * @max_height: maximum fb pixel height on this device * @funcs: core driver provided mode setting functions * @fb_base: base address of the framebuffer * @poll_enabled: track polling support for this device -- GitLab From e16a375086337af3fcf21dbd512e1573049ba6cb Mon Sep 17 00:00:00 2001 From: Vandita Kulkarni <vandita.kulkarni@intel.com> Date: Thu, 21 Jun 2018 20:43:56 +0530 Subject: [PATCH 0462/1506] drm/i915: Enable hw workaround to bypass alpha Alpha blending with alpha 0 and 0xff passes through alpha math and rounding logic causing differences compared to fully transparent or opaque plane,resulting in CRC mismatch. This WA on icl and above enables hardware to bypass alpha math and rounding for per pixel alpha values of 00 and 0xff v2: Fix patchwork checkpatch warnings. Signed-off-by: Vandita Kulkarni <vandita.kulkarni@intel.com> Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/1529594036-25036-1-git-send-email-vandita.kulkarni@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 8 ++++++++ drivers/gpu/drm/i915/intel_display.c | 12 ++++++++++++ 2 files changed, 20 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 65b222287ee4e..caad19f5f557f 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -7366,6 +7366,14 @@ enum { #define BDW_SCRATCH1 _MMIO(0xb11c) #define GEN9_LBS_SLA_RETRY_TIMER_DECREMENT_ENABLE (1 << 2) +/*GEN11 chicken */ +#define _PIPEA_CHICKEN 0x70038 +#define _PIPEB_CHICKEN 0x71038 +#define _PIPEC_CHICKEN 0x72038 +#define PER_PIXEL_ALPHA_BYPASS_EN (1 << 7) +#define PIPE_CHICKEN(pipe) _MMIO_PIPE(pipe, _PIPEA_CHICKEN,\ + _PIPEB_CHICKEN) + /* PCH */ /* south display engine interrupt: IBX */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b2a5a9ed94040..4db576c3e3649 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5633,6 +5633,7 @@ static void haswell_crtc_enable(struct intel_crtc_state *pipe_config, struct intel_atomic_state *old_intel_state = to_intel_atomic_state(old_state); bool psl_clkgate_wa; + u32 pipe_chicken; if (WARN_ON(intel_crtc->active)) return; @@ -5692,6 +5693,17 @@ static void haswell_crtc_enable(struct intel_crtc_state *pipe_config, */ intel_color_load_luts(&pipe_config->base); + /* + * Display WA #1153: enable hardware to bypass the alpha math + * and rounding for per-pixel values 00 and 0xff + */ + if (INTEL_GEN(dev_priv) >= 11) { + pipe_chicken = I915_READ(PIPE_CHICKEN(pipe)); + if (!(pipe_chicken & PER_PIXEL_ALPHA_BYPASS_EN)) + I915_WRITE_FW(PIPE_CHICKEN(pipe), + pipe_chicken | PER_PIXEL_ALPHA_BYPASS_EN); + } + intel_ddi_set_pipe_settings(pipe_config); if (!transcoder_is_dsi(cpu_transcoder)) intel_ddi_enable_transcoder_func(pipe_config); -- GitLab From abd7dbe921bb2c12933551423de23dda2980c890 Mon Sep 17 00:00:00 2001 From: Souptick Joarder <jrdr.linux@gmail.com> Date: Sat, 14 Apr 2018 21:53:21 +0530 Subject: [PATCH 0463/1506] gpu: drm: vc4: Adding new typedef vm_fault_t Use new return type vm_fault_t for fault handler. Signed-off-by: Souptick Joarder <jrdr.linux@gmail.com> Reviewed-by: Matthew Wilcox <mawilcox@microsoft.com> Signed-off-by: Eric Anholt <eric@anholt.net> Reviewed-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/vc4/vc4_bo.c | 2 +- drivers/gpu/drm/vc4/vc4_drv.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c index add9cc97a3b63..8dcce7182bb7c 100644 --- a/drivers/gpu/drm/vc4/vc4_bo.c +++ b/drivers/gpu/drm/vc4/vc4_bo.c @@ -721,7 +721,7 @@ vc4_prime_export(struct drm_device *dev, struct drm_gem_object *obj, int flags) return dmabuf; } -int vc4_fault(struct vm_fault *vmf) +vm_fault_t vc4_fault(struct vm_fault *vmf) { struct vm_area_struct *vma = vmf->vma; struct drm_gem_object *obj = vma->vm_private_data; diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index 554a4e810d5b0..eace76c621a18 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -6,6 +6,7 @@ * published by the Free Software Foundation. */ +#include <linux/mm_types.h> #include <linux/reservation.h> #include <drm/drmP.h> #include <drm/drm_encoder.h> @@ -674,7 +675,7 @@ int vc4_get_hang_state_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int vc4_label_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -int vc4_fault(struct vm_fault *vmf); +vm_fault_t vc4_fault(struct vm_fault *vmf); int vc4_mmap(struct file *filp, struct vm_area_struct *vma); struct reservation_object *vc4_prime_res_obj(struct drm_gem_object *obj); int vc4_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma); -- GitLab From 6aa13402c11035a428d8c621b334734971d5d39d Mon Sep 17 00:00:00 2001 From: Eric Anholt <eric@anholt.net> Date: Wed, 6 Jun 2018 12:04:29 -0700 Subject: [PATCH 0464/1506] drm/bridge: Move the struct drm_bridge member kerneldoc inline. This makes it more likely that the docs stay updated with the code. Signed-off-by: Eric Anholt <eric@anholt.net> Link: https://patchwork.freedesktop.org/patch/msgid/20180606190431.1833-1-eric@anholt.net Reviewed-by: Andrzej Hajda <a.hajda@samsung.com> --- include/drm/drm_bridge.h | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index 70131ab57e8f2..bd850747ce547 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -270,27 +270,29 @@ struct drm_bridge_timings { /** * struct drm_bridge - central DRM bridge control structure - * @dev: DRM device this bridge belongs to - * @encoder: encoder to which this bridge is connected - * @next: the next bridge in the encoder chain - * @of_node: device node pointer to the bridge - * @list: to keep track of all added bridges - * @timings: the timing specification for the bridge, if any (may - * be NULL) - * @funcs: control functions - * @driver_private: pointer to the bridge driver's internal context */ struct drm_bridge { + /** @dev: DRM device this bridge belongs to */ struct drm_device *dev; + /** @encoder: encoder to which this bridge is connected */ struct drm_encoder *encoder; + /** @next: the next bridge in the encoder chain */ struct drm_bridge *next; #ifdef CONFIG_OF + /** @of_node: device node pointer to the bridge */ struct device_node *of_node; #endif + /** @list: to keep track of all added bridges */ struct list_head list; + /** + * @timings: + * + * the timing specification for the bridge, if any (may be NULL) + */ const struct drm_bridge_timings *timings; - + /** @funcs: control functions */ const struct drm_bridge_funcs *funcs; + /** @driver_private: pointer to the bridge driver's internal context */ void *driver_private; }; -- GitLab From 7122b68b8a9692dcc3acf89595f04c492872115f Mon Sep 17 00:00:00 2001 From: Eric Anholt <eric@anholt.net> Date: Wed, 6 Jun 2018 10:48:51 -0700 Subject: [PATCH 0465/1506] drm/v3d: Take a lock across GPU scheduler job creation and queuing. Between creation and queueing of a job, you need to prevent any other job from being created and queued. Otherwise the scheduler's fences may be signaled out of seqno order. v2: move mutex unlock to the error label. Signed-off-by: Eric Anholt <eric@anholt.net> Fixes: 57692c94dcbe ("drm/v3d: Introduce a new DRM driver for Broadcom V3D V3.x+") Link: https://patchwork.freedesktop.org/patch/msgid/20180606174851.12433-1-eric@anholt.net Reviewed-by: Lucas Stach <l.stach@pengutronix.de> --- drivers/gpu/drm/v3d/v3d_drv.h | 5 +++++ drivers/gpu/drm/v3d/v3d_gem.c | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h index a043ac3aae982..26005abd9c5da 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.h +++ b/drivers/gpu/drm/v3d/v3d_drv.h @@ -85,6 +85,11 @@ struct v3d_dev { */ struct mutex reset_lock; + /* Lock taken when creating and pushing the GPU scheduler + * jobs, to keep the sched-fence seqnos in order. + */ + struct mutex sched_lock; + struct { u32 num_allocated; u32 pages_allocated; diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c index b513f9189cafd..269fe16379c0a 100644 --- a/drivers/gpu/drm/v3d/v3d_gem.c +++ b/drivers/gpu/drm/v3d/v3d_gem.c @@ -550,6 +550,7 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data, if (ret) goto fail; + mutex_lock(&v3d->sched_lock); if (exec->bin.start != exec->bin.end) { ret = drm_sched_job_init(&exec->bin.base, &v3d->queue[V3D_BIN].sched, @@ -576,6 +577,7 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data, kref_get(&exec->refcount); /* put by scheduler job completion */ drm_sched_entity_push_job(&exec->render.base, &v3d_priv->sched_entity[V3D_RENDER]); + mutex_unlock(&v3d->sched_lock); v3d_attach_object_fences(exec); @@ -594,6 +596,7 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data, return 0; fail_unreserve: + mutex_unlock(&v3d->sched_lock); v3d_unlock_bo_reservations(dev, exec, &acquire_ctx); fail: v3d_exec_put(exec); @@ -615,6 +618,7 @@ v3d_gem_init(struct drm_device *dev) spin_lock_init(&v3d->job_lock); mutex_init(&v3d->bo_lock); mutex_init(&v3d->reset_lock); + mutex_init(&v3d->sched_lock); /* Note: We don't allocate address 0. Various bits of HW * treat 0 as special, such as the occlusion query counters -- GitLab From 14d1d190869685d3a1e8a3f63924e20594557cb2 Mon Sep 17 00:00:00 2001 From: Eric Anholt <eric@anholt.net> Date: Tue, 5 Jun 2018 12:03:01 -0700 Subject: [PATCH 0466/1506] drm/v3d: Remove the bad signaled() implementation. Since our seqno value comes from a counter associated with the GPU ring, not the entity (aka client), they'll be completed out of order. There's actually no need for this code at all, since we don't have enable_signaling() and thus DMA_FENCE_SIGNALED_BIT will be set before we could be called. Signed-off-by: Eric Anholt <eric@anholt.net> Link: https://patchwork.freedesktop.org/patch/msgid/20180605190302.18279-2-eric@anholt.net Reviewed-by: Lucas Stach <l.stach@pengutronix.de> --- drivers/gpu/drm/v3d/v3d_drv.h | 1 - drivers/gpu/drm/v3d/v3d_fence.c | 13 ++++--------- drivers/gpu/drm/v3d/v3d_gem.c | 7 ++----- drivers/gpu/drm/v3d/v3d_irq.c | 3 --- 4 files changed, 6 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h index 26005abd9c5da..f32ac8c98f371 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.h +++ b/drivers/gpu/drm/v3d/v3d_drv.h @@ -25,7 +25,6 @@ struct v3d_queue_state { u64 fence_context; u64 emit_seqno; - u64 finished_seqno; }; struct v3d_dev { diff --git a/drivers/gpu/drm/v3d/v3d_fence.c b/drivers/gpu/drm/v3d/v3d_fence.c index 087d49c8cb12a..bfe31a89668bd 100644 --- a/drivers/gpu/drm/v3d/v3d_fence.c +++ b/drivers/gpu/drm/v3d/v3d_fence.c @@ -40,19 +40,14 @@ static bool v3d_fence_enable_signaling(struct dma_fence *fence) return true; } -static bool v3d_fence_signaled(struct dma_fence *fence) -{ - struct v3d_fence *f = to_v3d_fence(fence); - struct v3d_dev *v3d = to_v3d_dev(f->dev); - - return v3d->queue[f->queue].finished_seqno >= f->seqno; -} - const struct dma_fence_ops v3d_fence_ops = { .get_driver_name = v3d_fence_get_driver_name, .get_timeline_name = v3d_fence_get_timeline_name, .enable_signaling = v3d_fence_enable_signaling, - .signaled = v3d_fence_signaled, + /* Each of our fences gets signaled as complete by the IRQ + * handler, so we rely on the core's tracking of signaling. + */ + .signaled = NULL, .wait = dma_fence_default_wait, .release = dma_fence_free, }; diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c index 269fe16379c0a..e1fcbb4cd0aeb 100644 --- a/drivers/gpu/drm/v3d/v3d_gem.c +++ b/drivers/gpu/drm/v3d/v3d_gem.c @@ -654,17 +654,14 @@ void v3d_gem_destroy(struct drm_device *dev) { struct v3d_dev *v3d = to_v3d_dev(dev); - enum v3d_queue q; v3d_sched_fini(v3d); /* Waiting for exec to finish would need to be done before * unregistering V3D. */ - for (q = 0; q < V3D_MAX_QUEUES; q++) { - WARN_ON(v3d->queue[q].emit_seqno != - v3d->queue[q].finished_seqno); - } + WARN_ON(v3d->bin_job); + WARN_ON(v3d->render_job); drm_mm_takedown(&v3d->mm); diff --git a/drivers/gpu/drm/v3d/v3d_irq.c b/drivers/gpu/drm/v3d/v3d_irq.c index 77e1fa046c10a..e07514eb11b51 100644 --- a/drivers/gpu/drm/v3d/v3d_irq.c +++ b/drivers/gpu/drm/v3d/v3d_irq.c @@ -87,15 +87,12 @@ v3d_irq(int irq, void *arg) } if (intsts & V3D_INT_FLDONE) { - v3d->queue[V3D_BIN].finished_seqno++; dma_fence_signal(v3d->bin_job->bin.done_fence); status = IRQ_HANDLED; } if (intsts & V3D_INT_FRDONE) { - v3d->queue[V3D_RENDER].finished_seqno++; dma_fence_signal(v3d->render_job->render.done_fence); - status = IRQ_HANDLED; } -- GitLab From 4adc18371f14cf9dfd169d9b8ebdfdaee13c2639 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Fri, 22 Jun 2018 11:23:26 +0200 Subject: [PATCH 0467/1506] drm/omap: remove now unused functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some functions are unused after removal of the kmap_atomic DMA-buf interface. Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Fixes: f664a5269542 ("dma-buf: remove kmap_atomic interface") Link: https://patchwork.freedesktop.org/series/45245/ --- drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c index 1a073f9b28349..ec04a69ade46b 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c +++ b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c @@ -93,23 +93,6 @@ static int omap_gem_dmabuf_end_cpu_access(struct dma_buf *buffer, return 0; } - -static void *omap_gem_dmabuf_kmap_atomic(struct dma_buf *buffer, - unsigned long page_num) -{ - struct drm_gem_object *obj = buffer->priv; - struct page **pages; - omap_gem_get_pages(obj, &pages, false); - omap_gem_cpu_sync_page(obj, page_num); - return kmap_atomic(pages[page_num]); -} - -static void omap_gem_dmabuf_kunmap_atomic(struct dma_buf *buffer, - unsigned long page_num, void *addr) -{ - kunmap_atomic(addr); -} - static void *omap_gem_dmabuf_kmap(struct dma_buf *buffer, unsigned long page_num) { -- GitLab From aa58f58d9c6471a1087ede57e4ab6cc0817c949f Mon Sep 17 00:00:00 2001 From: Anusha Srivatsa <anusha.srivatsa@intel.com> Date: Fri, 22 Jun 2018 11:19:03 -0700 Subject: [PATCH 0468/1506] drm/i915/guc: Remove USES_GUC_SUBMISSION for ads programming In the guc_ctl_debug_flags, the ads struct is programmed only when USES_GUC_SUBMISSION is satisfied. But, this has to be programmed for all suspend/resume cases. Remove the condition and program the ads struct for both huc loading and guc submission. This issue was noticed when CI threw errors for enable_guc=2 (load huc; disable submission) v2: - Change commit title. - Correct the shifts. (Daniele) Credits to: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com> Cc: John Spotswood <john.a.spotswood@intel.com> Cc: Oscar Mateo <oscar.mateo@intel.com> Cc: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com> Signed-off-by: Anusha Srivatsa <anusha.srivatsa@intel.com> Reviewed-by: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com> Reviewed-by: John Spotswood <john.a.spotswood@intel.com> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/msgid/1529691543-28606-1-git-send-email-anusha.srivatsa@intel.com --- drivers/gpu/drm/i915/intel_guc.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c index 1aff30b0870c2..f651e57b4c619 100644 --- a/drivers/gpu/drm/i915/intel_guc.c +++ b/drivers/gpu/drm/i915/intel_guc.c @@ -206,7 +206,11 @@ void intel_guc_fini(struct intel_guc *guc) static u32 guc_ctl_debug_flags(struct intel_guc *guc) { u32 level = intel_guc_log_get_level(&guc->log); - u32 flags = 0; + u32 flags; + u32 ads; + + ads = intel_guc_ggtt_offset(guc, guc->ads_vma) >> PAGE_SHIFT; + flags = ads << GUC_ADS_ADDR_SHIFT | GUC_ADS_ENABLED; if (!GUC_LOG_LEVEL_IS_ENABLED(level)) flags |= GUC_LOG_DEFAULT_DISABLED; @@ -217,13 +221,6 @@ static u32 guc_ctl_debug_flags(struct intel_guc *guc) flags |= GUC_LOG_LEVEL_TO_VERBOSITY(level) << GUC_LOG_VERBOSITY_SHIFT; - if (USES_GUC_SUBMISSION(guc_to_i915(guc))) { - u32 ads = intel_guc_ggtt_offset(guc, guc->ads_vma) - >> PAGE_SHIFT; - - flags |= ads << GUC_ADS_ADDR_SHIFT | GUC_ADS_ENABLED; - } - return flags; } -- GitLab From 46d8f405e16cdc47962edbe7771246c8d5b8c795 Mon Sep 17 00:00:00 2001 From: Eric Anholt <eric@anholt.net> Date: Thu, 21 Jun 2018 12:54:28 -0700 Subject: [PATCH 0469/1506] drm: Consider drivers setting DRIVER_ATOMIC as atomic. Drivers such as vc4 don't initialize mode_config.funcs until later in initialization, but we know they're atomic since they've got the flag set. This avoids oopsing on dereferencing funcs in the new atomic methods sanity checks. I moved the atomic check function down below the core flag check, to avoid needing a prototype. Signed-off-by: Eric Anholt <eric@anholt.net> Fixes: ba1f665f161c ("drm: Add checks for atomic_[duplicate/destroy]_state with atomic drivers") Link: https://patchwork.freedesktop.org/patch/msgid/20180621195428.17447-1-eric@anholt.net Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> --- include/drm/drmP.h | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/include/drm/drmP.h b/include/drm/drmP.h index f5099c12c6a6d..c5dfbdb7271d7 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -97,6 +97,16 @@ struct pci_controller; #define DRM_IF_VERSION(maj, min) (maj << 16 | min) +#define DRM_SWITCH_POWER_ON 0 +#define DRM_SWITCH_POWER_OFF 1 +#define DRM_SWITCH_POWER_CHANGING 2 +#define DRM_SWITCH_POWER_DYNAMIC_OFF 3 + +static inline bool drm_core_check_feature(struct drm_device *dev, int feature) +{ + return dev->driver->driver_features & feature; +} + /** * drm_drv_uses_atomic_modeset - check if the driver implements * atomic_commit() @@ -107,17 +117,8 @@ struct pci_controller; */ static inline bool drm_drv_uses_atomic_modeset(struct drm_device *dev) { - return dev->mode_config.funcs->atomic_commit != NULL; -} - -#define DRM_SWITCH_POWER_ON 0 -#define DRM_SWITCH_POWER_OFF 1 -#define DRM_SWITCH_POWER_CHANGING 2 -#define DRM_SWITCH_POWER_DYNAMIC_OFF 3 - -static inline bool drm_core_check_feature(struct drm_device *dev, int feature) -{ - return dev->driver->driver_features & feature; + return drm_core_check_feature(dev, DRIVER_ATOMIC) || + dev->mode_config.funcs->atomic_commit != NULL; } /* returns true if currently okay to sleep */ -- GitLab From 9dd64e8f7b62e04cb34e984f637ba331d7e71829 Mon Sep 17 00:00:00 2001 From: "stu.hsieh@mediatek.com" <stu.hsieh@mediatek.com> Date: Wed, 20 Jun 2018 16:19:03 +0800 Subject: [PATCH 0470/1506] drm/mediatek: update dt-bindings for mt2712 Update device tree binding documentation for the display subsystem for Mediatek MT2712 SoCs. Signed-off-by: Stu Hsieh <stu.hsieh@mediatek.com> Acked-by: Rob Herring <robh@kernel.org> Signed-off-by: CK Hu <ck.hu@mediatek.com> --- .../devicetree/bindings/display/mediatek/mediatek,disp.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,disp.txt b/Documentation/devicetree/bindings/display/mediatek/mediatek,disp.txt index 383183a89164d..8469de510001b 100644 --- a/Documentation/devicetree/bindings/display/mediatek/mediatek,disp.txt +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,disp.txt @@ -40,7 +40,7 @@ Required properties (all function blocks): "mediatek,<chip>-dpi" - DPI controller, see mediatek,dpi.txt "mediatek,<chip>-disp-mutex" - display mutex "mediatek,<chip>-disp-od" - overdrive - the supported chips are mt2701 and mt8173. + the supported chips are mt2701, mt2712 and mt8173. - reg: Physical base address and length of the function block register space - interrupts: The interrupt signal from the function block (required, except for merge and split function blocks). -- GitLab From 8617ec2474fda604d60eefe1bd058a167f265308 Mon Sep 17 00:00:00 2001 From: "stu.hsieh@mediatek.com" <stu.hsieh@mediatek.com> Date: Wed, 20 Jun 2018 16:19:04 +0800 Subject: [PATCH 0471/1506] drm/mediatek: support maximum 64 mutex mod This patch support that if modules more than 32, add index more than 31 when using DISP_REG_MUTEX_MOD2 bit Signed-off-by: Stu Hsieh <stu.hsieh@mediatek.com> Signed-off-by: CK Hu <ck.hu@mediatek.com> --- drivers/gpu/drm/mediatek/mtk_drm_ddp.c | 75 ++++++++++++++++---------- 1 file changed, 47 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c index 8130f3dab6614..47ffa240bd257 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c @@ -41,31 +41,32 @@ #define DISP_REG_MUTEX_RST(n) (0x28 + 0x20 * (n)) #define DISP_REG_MUTEX_MOD(n) (0x2c + 0x20 * (n)) #define DISP_REG_MUTEX_SOF(n) (0x30 + 0x20 * (n)) +#define DISP_REG_MUTEX_MOD2(n) (0x34 + 0x20 * (n)) #define INT_MUTEX BIT(1) -#define MT8173_MUTEX_MOD_DISP_OVL0 BIT(11) -#define MT8173_MUTEX_MOD_DISP_OVL1 BIT(12) -#define MT8173_MUTEX_MOD_DISP_RDMA0 BIT(13) -#define MT8173_MUTEX_MOD_DISP_RDMA1 BIT(14) -#define MT8173_MUTEX_MOD_DISP_RDMA2 BIT(15) -#define MT8173_MUTEX_MOD_DISP_WDMA0 BIT(16) -#define MT8173_MUTEX_MOD_DISP_WDMA1 BIT(17) -#define MT8173_MUTEX_MOD_DISP_COLOR0 BIT(18) -#define MT8173_MUTEX_MOD_DISP_COLOR1 BIT(19) -#define MT8173_MUTEX_MOD_DISP_AAL BIT(20) -#define MT8173_MUTEX_MOD_DISP_GAMMA BIT(21) -#define MT8173_MUTEX_MOD_DISP_UFOE BIT(22) -#define MT8173_MUTEX_MOD_DISP_PWM0 BIT(23) -#define MT8173_MUTEX_MOD_DISP_PWM1 BIT(24) -#define MT8173_MUTEX_MOD_DISP_OD BIT(25) - -#define MT2701_MUTEX_MOD_DISP_OVL BIT(3) -#define MT2701_MUTEX_MOD_DISP_WDMA BIT(6) -#define MT2701_MUTEX_MOD_DISP_COLOR BIT(7) -#define MT2701_MUTEX_MOD_DISP_BLS BIT(9) -#define MT2701_MUTEX_MOD_DISP_RDMA0 BIT(10) -#define MT2701_MUTEX_MOD_DISP_RDMA1 BIT(12) +#define MT8173_MUTEX_MOD_DISP_OVL0 11 +#define MT8173_MUTEX_MOD_DISP_OVL1 12 +#define MT8173_MUTEX_MOD_DISP_RDMA0 13 +#define MT8173_MUTEX_MOD_DISP_RDMA1 14 +#define MT8173_MUTEX_MOD_DISP_RDMA2 15 +#define MT8173_MUTEX_MOD_DISP_WDMA0 16 +#define MT8173_MUTEX_MOD_DISP_WDMA1 17 +#define MT8173_MUTEX_MOD_DISP_COLOR0 18 +#define MT8173_MUTEX_MOD_DISP_COLOR1 19 +#define MT8173_MUTEX_MOD_DISP_AAL 20 +#define MT8173_MUTEX_MOD_DISP_GAMMA 21 +#define MT8173_MUTEX_MOD_DISP_UFOE 22 +#define MT8173_MUTEX_MOD_DISP_PWM0 23 +#define MT8173_MUTEX_MOD_DISP_PWM1 24 +#define MT8173_MUTEX_MOD_DISP_OD 25 + +#define MT2701_MUTEX_MOD_DISP_OVL 3 +#define MT2701_MUTEX_MOD_DISP_WDMA 6 +#define MT2701_MUTEX_MOD_DISP_COLOR 7 +#define MT2701_MUTEX_MOD_DISP_BLS 9 +#define MT2701_MUTEX_MOD_DISP_RDMA0 10 +#define MT2701_MUTEX_MOD_DISP_RDMA1 12 #define MUTEX_SOF_SINGLE_MODE 0 #define MUTEX_SOF_DSI0 1 @@ -278,6 +279,7 @@ void mtk_disp_mutex_add_comp(struct mtk_disp_mutex *mutex, struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp, mutex[mutex->id]); unsigned int reg; + unsigned int offset; WARN_ON(&ddp->mutex[mutex->id] != mutex); @@ -292,9 +294,17 @@ void mtk_disp_mutex_add_comp(struct mtk_disp_mutex *mutex, reg = MUTEX_SOF_DPI0; break; default: - reg = readl_relaxed(ddp->regs + DISP_REG_MUTEX_MOD(mutex->id)); - reg |= ddp->mutex_mod[id]; - writel_relaxed(reg, ddp->regs + DISP_REG_MUTEX_MOD(mutex->id)); + if (ddp->mutex_mod[id] < 32) { + offset = DISP_REG_MUTEX_MOD(mutex->id); + reg = readl_relaxed(ddp->regs + offset); + reg |= 1 << ddp->mutex_mod[id]; + writel_relaxed(reg, ddp->regs + offset); + } else { + offset = DISP_REG_MUTEX_MOD2(mutex->id); + reg = readl_relaxed(ddp->regs + offset); + reg |= 1 << (ddp->mutex_mod[id] - 32); + writel_relaxed(reg, ddp->regs + offset); + } return; } @@ -307,6 +317,7 @@ void mtk_disp_mutex_remove_comp(struct mtk_disp_mutex *mutex, struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp, mutex[mutex->id]); unsigned int reg; + unsigned int offset; WARN_ON(&ddp->mutex[mutex->id] != mutex); @@ -318,9 +329,17 @@ void mtk_disp_mutex_remove_comp(struct mtk_disp_mutex *mutex, ddp->regs + DISP_REG_MUTEX_SOF(mutex->id)); break; default: - reg = readl_relaxed(ddp->regs + DISP_REG_MUTEX_MOD(mutex->id)); - reg &= ~(ddp->mutex_mod[id]); - writel_relaxed(reg, ddp->regs + DISP_REG_MUTEX_MOD(mutex->id)); + if (ddp->mutex_mod[id] < 32) { + offset = DISP_REG_MUTEX_MOD(mutex->id); + reg = readl_relaxed(ddp->regs + offset); + reg &= ~(1 << ddp->mutex_mod[id]); + writel_relaxed(reg, ddp->regs + offset); + } else { + offset = DISP_REG_MUTEX_MOD2(mutex->id); + reg = readl_relaxed(ddp->regs + offset); + reg &= ~(1 << (ddp->mutex_mod[id] - 32)); + writel_relaxed(reg, ddp->regs + offset); + } break; } } -- GitLab From d480bbc47425d82d7f6cee0f370e43a1f6aff1a1 Mon Sep 17 00:00:00 2001 From: "stu.hsieh@mediatek.com" <stu.hsieh@mediatek.com> Date: Wed, 20 Jun 2018 16:19:05 +0800 Subject: [PATCH 0472/1506] drm/mediatek: add ddp component AAL1 This patch add component AAL1 and rename AAL to AAL0 Signed-off-by: Stu Hsieh <stu.hsieh@mediatek.com> Signed-off-by: CK Hu <ck.hu@mediatek.com> --- drivers/gpu/drm/mediatek/mtk_drm_ddp.c | 2 +- drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c | 3 ++- drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h | 3 ++- drivers/gpu/drm/mediatek/mtk_drm_drv.c | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c index 47ffa240bd257..7217665f4b5d1 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c @@ -110,7 +110,7 @@ static const unsigned int mt2701_mutex_mod[DDP_COMPONENT_ID_MAX] = { }; static const unsigned int mt8173_mutex_mod[DDP_COMPONENT_ID_MAX] = { - [DDP_COMPONENT_AAL] = MT8173_MUTEX_MOD_DISP_AAL, + [DDP_COMPONENT_AAL0] = MT8173_MUTEX_MOD_DISP_AAL, [DDP_COMPONENT_COLOR0] = MT8173_MUTEX_MOD_DISP_COLOR0, [DDP_COMPONENT_COLOR1] = MT8173_MUTEX_MOD_DISP_COLOR1, [DDP_COMPONENT_GAMMA] = MT8173_MUTEX_MOD_DISP_GAMMA, diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c index 4672317e3ad12..0919039805aa1 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c @@ -218,7 +218,8 @@ struct mtk_ddp_comp_match { }; static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = { - [DDP_COMPONENT_AAL] = { MTK_DISP_AAL, 0, &ddp_aal }, + [DDP_COMPONENT_AAL0] = { MTK_DISP_AAL, 0, &ddp_aal }, + [DDP_COMPONENT_AAL1] = { MTK_DISP_AAL, 1, &ddp_aal }, [DDP_COMPONENT_BLS] = { MTK_DISP_BLS, 0, NULL }, [DDP_COMPONENT_COLOR0] = { MTK_DISP_COLOR, 0, NULL }, [DDP_COMPONENT_COLOR1] = { MTK_DISP_COLOR, 1, NULL }, diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h index 0828cf8bf85ca..eee3c0cc2632b 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h @@ -41,7 +41,8 @@ enum mtk_ddp_comp_type { }; enum mtk_ddp_comp_id { - DDP_COMPONENT_AAL, + DDP_COMPONENT_AAL0, + DDP_COMPONENT_AAL1, DDP_COMPONENT_BLS, DDP_COMPONENT_COLOR0, DDP_COMPONENT_COLOR1, diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c index a2ca90fc403cb..a415260f3d5fc 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c @@ -149,7 +149,7 @@ static const enum mtk_ddp_comp_id mt2701_mtk_ddp_ext[] = { static const enum mtk_ddp_comp_id mt8173_mtk_ddp_main[] = { DDP_COMPONENT_OVL0, DDP_COMPONENT_COLOR0, - DDP_COMPONENT_AAL, + DDP_COMPONENT_AAL0, DDP_COMPONENT_OD, DDP_COMPONENT_RDMA0, DDP_COMPONENT_UFOE, -- GitLab From df2dce4e11a33fa7e3e72d3b4e4570e8f653d387 Mon Sep 17 00:00:00 2001 From: "stu.hsieh@mediatek.com" <stu.hsieh@mediatek.com> Date: Wed, 20 Jun 2018 16:19:06 +0800 Subject: [PATCH 0473/1506] drm/mediatek: add ddp component OD1 This patch add the component OD1 and rename the OD to OD0 Signed-off-by: Stu Hsieh <stu.hsieh@mediatek.com> Signed-off-by: CK Hu <ck.hu@mediatek.com> --- drivers/gpu/drm/mediatek/mtk_drm_ddp.c | 4 ++-- drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c | 3 ++- drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h | 3 ++- drivers/gpu/drm/mediatek/mtk_drm_drv.c | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c index 7217665f4b5d1..58e44349e3157 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c @@ -114,7 +114,7 @@ static const unsigned int mt8173_mutex_mod[DDP_COMPONENT_ID_MAX] = { [DDP_COMPONENT_COLOR0] = MT8173_MUTEX_MOD_DISP_COLOR0, [DDP_COMPONENT_COLOR1] = MT8173_MUTEX_MOD_DISP_COLOR1, [DDP_COMPONENT_GAMMA] = MT8173_MUTEX_MOD_DISP_GAMMA, - [DDP_COMPONENT_OD] = MT8173_MUTEX_MOD_DISP_OD, + [DDP_COMPONENT_OD0] = MT8173_MUTEX_MOD_DISP_OD, [DDP_COMPONENT_OVL0] = MT8173_MUTEX_MOD_DISP_OVL0, [DDP_COMPONENT_OVL1] = MT8173_MUTEX_MOD_DISP_OVL1, [DDP_COMPONENT_PWM0] = MT8173_MUTEX_MOD_DISP_PWM0, @@ -139,7 +139,7 @@ static unsigned int mtk_ddp_mout_en(enum mtk_ddp_comp_id cur, } else if (cur == DDP_COMPONENT_OVL0 && next == DDP_COMPONENT_RDMA0) { *addr = DISP_REG_CONFIG_DISP_OVL_MOUT_EN; value = OVL_MOUT_EN_RDMA; - } else if (cur == DDP_COMPONENT_OD && next == DDP_COMPONENT_RDMA0) { + } else if (cur == DDP_COMPONENT_OD0 && next == DDP_COMPONENT_RDMA0) { *addr = DISP_REG_CONFIG_DISP_OD_MOUT_EN; value = OD_MOUT_EN_RDMA0; } else if (cur == DDP_COMPONENT_UFOE && next == DDP_COMPONENT_DSI0) { diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c index 0919039805aa1..87acf6be87f6c 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c @@ -227,7 +227,8 @@ static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = { [DDP_COMPONENT_DSI0] = { MTK_DSI, 0, NULL }, [DDP_COMPONENT_DSI1] = { MTK_DSI, 1, NULL }, [DDP_COMPONENT_GAMMA] = { MTK_DISP_GAMMA, 0, &ddp_gamma }, - [DDP_COMPONENT_OD] = { MTK_DISP_OD, 0, &ddp_od }, + [DDP_COMPONENT_OD0] = { MTK_DISP_OD, 0, &ddp_od }, + [DDP_COMPONENT_OD1] = { MTK_DISP_OD, 1, &ddp_od }, [DDP_COMPONENT_OVL0] = { MTK_DISP_OVL, 0, NULL }, [DDP_COMPONENT_OVL1] = { MTK_DISP_OVL, 1, NULL }, [DDP_COMPONENT_PWM0] = { MTK_DISP_PWM, 0, NULL }, diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h index eee3c0cc2632b..9b19fc4423f1f 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h @@ -50,7 +50,8 @@ enum mtk_ddp_comp_id { DDP_COMPONENT_DSI0, DDP_COMPONENT_DSI1, DDP_COMPONENT_GAMMA, - DDP_COMPONENT_OD, + DDP_COMPONENT_OD0, + DDP_COMPONENT_OD1, DDP_COMPONENT_OVL0, DDP_COMPONENT_OVL1, DDP_COMPONENT_PWM0, diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c index a415260f3d5fc..08d5d0b47bfe5 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c @@ -150,7 +150,7 @@ static const enum mtk_ddp_comp_id mt8173_mtk_ddp_main[] = { DDP_COMPONENT_OVL0, DDP_COMPONENT_COLOR0, DDP_COMPONENT_AAL0, - DDP_COMPONENT_OD, + DDP_COMPONENT_OD0, DDP_COMPONENT_RDMA0, DDP_COMPONENT_UFOE, DDP_COMPONENT_DSI0, -- GitLab From 9ec3818eb37104561774c96349ec7a2b0633fbac Mon Sep 17 00:00:00 2001 From: "stu.hsieh@mediatek.com" <stu.hsieh@mediatek.com> Date: Wed, 20 Jun 2018 16:19:07 +0800 Subject: [PATCH 0474/1506] drm/mediatek: add ddp component PWM1 This patch add component PWM1 in mtk_ddp_matches Signed-off-by: Stu Hsieh <stu.hsieh@mediatek.com> Signed-off-by: CK Hu <ck.hu@mediatek.com> --- drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c index 87acf6be87f6c..a5c7ac2d162d1 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c @@ -232,6 +232,7 @@ static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = { [DDP_COMPONENT_OVL0] = { MTK_DISP_OVL, 0, NULL }, [DDP_COMPONENT_OVL1] = { MTK_DISP_OVL, 1, NULL }, [DDP_COMPONENT_PWM0] = { MTK_DISP_PWM, 0, NULL }, + [DDP_COMPONENT_PWM1] = { MTK_DISP_PWM, 1, NULL }, [DDP_COMPONENT_RDMA0] = { MTK_DISP_RDMA, 0, NULL }, [DDP_COMPONENT_RDMA1] = { MTK_DISP_RDMA, 1, NULL }, [DDP_COMPONENT_RDMA2] = { MTK_DISP_RDMA, 2, NULL }, -- GitLab From 2e2447784e568bd3469df085d51cd651e6a00993 Mon Sep 17 00:00:00 2001 From: "stu.hsieh@mediatek.com" <stu.hsieh@mediatek.com> Date: Wed, 20 Jun 2018 16:19:08 +0800 Subject: [PATCH 0475/1506] drm/mediatek: add ddp component PWM2 This patch add component PWM2 Signed-off-by: Stu Hsieh <stu.hsieh@mediatek.com> Signed-off-by: CK Hu <ck.hu@mediatek.com> --- drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c | 1 + drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c index a5c7ac2d162d1..86e8c9e5df41b 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c @@ -233,6 +233,7 @@ static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = { [DDP_COMPONENT_OVL1] = { MTK_DISP_OVL, 1, NULL }, [DDP_COMPONENT_PWM0] = { MTK_DISP_PWM, 0, NULL }, [DDP_COMPONENT_PWM1] = { MTK_DISP_PWM, 1, NULL }, + [DDP_COMPONENT_PWM2] = { MTK_DISP_PWM, 2, NULL }, [DDP_COMPONENT_RDMA0] = { MTK_DISP_RDMA, 0, NULL }, [DDP_COMPONENT_RDMA1] = { MTK_DISP_RDMA, 1, NULL }, [DDP_COMPONENT_RDMA2] = { MTK_DISP_RDMA, 2, NULL }, diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h index 9b19fc4423f1f..e00c2e798abd4 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h @@ -56,6 +56,7 @@ enum mtk_ddp_comp_id { DDP_COMPONENT_OVL1, DDP_COMPONENT_PWM0, DDP_COMPONENT_PWM1, + DDP_COMPONENT_PWM2, DDP_COMPONENT_RDMA0, DDP_COMPONENT_RDMA1, DDP_COMPONENT_RDMA2, -- GitLab From 879a91807f5af1bb02ad3b6019f9729c2b0ea4bf Mon Sep 17 00:00:00 2001 From: "stu.hsieh@mediatek.com" <stu.hsieh@mediatek.com> Date: Wed, 20 Jun 2018 16:19:09 +0800 Subject: [PATCH 0476/1506] drm/mediatek: add component DPI1 This patch add the component DPI1 Signed-off-by: Stu Hsieh <stu.hsieh@mediatek.com> Signed-off-by: CK Hu <ck.hu@mediatek.com> --- drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c | 2 ++ drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c index 86e8c9e5df41b..cc74b1a7278cd 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c @@ -224,6 +224,7 @@ static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = { [DDP_COMPONENT_COLOR0] = { MTK_DISP_COLOR, 0, NULL }, [DDP_COMPONENT_COLOR1] = { MTK_DISP_COLOR, 1, NULL }, [DDP_COMPONENT_DPI0] = { MTK_DPI, 0, NULL }, + [DDP_COMPONENT_DPI1] = { MTK_DPI, 1, NULL }, [DDP_COMPONENT_DSI0] = { MTK_DSI, 0, NULL }, [DDP_COMPONENT_DSI1] = { MTK_DSI, 1, NULL }, [DDP_COMPONENT_GAMMA] = { MTK_DISP_GAMMA, 0, &ddp_gamma }, @@ -275,6 +276,7 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node, if (comp_id == DDP_COMPONENT_BLS || comp_id == DDP_COMPONENT_DPI0 || + comp_id == DDP_COMPONENT_DPI1 || comp_id == DDP_COMPONENT_DSI0 || comp_id == DDP_COMPONENT_PWM0) { comp->regs = NULL; diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h index e00c2e798abd4..54c99c169093b 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h @@ -47,6 +47,7 @@ enum mtk_ddp_comp_id { DDP_COMPONENT_COLOR0, DDP_COMPONENT_COLOR1, DDP_COMPONENT_DPI0, + DDP_COMPONENT_DPI1, DDP_COMPONENT_DSI0, DDP_COMPONENT_DSI1, DDP_COMPONENT_GAMMA, -- GitLab From afbff52882325db7cfb65fab014dae5930dce31a Mon Sep 17 00:00:00 2001 From: "stu.hsieh@mediatek.com" <stu.hsieh@mediatek.com> Date: Wed, 20 Jun 2018 16:19:10 +0800 Subject: [PATCH 0477/1506] drm/mediatek: add component DSI2 This patch add the component DSI2 Signed-off-by: Stu Hsieh <stu.hsieh@mediatek.com> Signed-off-by: CK Hu <ck.hu@mediatek.com> --- drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c | 2 ++ drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c index cc74b1a7278cd..071f9f5aefea5 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c @@ -227,6 +227,7 @@ static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = { [DDP_COMPONENT_DPI1] = { MTK_DPI, 1, NULL }, [DDP_COMPONENT_DSI0] = { MTK_DSI, 0, NULL }, [DDP_COMPONENT_DSI1] = { MTK_DSI, 1, NULL }, + [DDP_COMPONENT_DSI2] = { MTK_DSI, 2, NULL }, [DDP_COMPONENT_GAMMA] = { MTK_DISP_GAMMA, 0, &ddp_gamma }, [DDP_COMPONENT_OD0] = { MTK_DISP_OD, 0, &ddp_od }, [DDP_COMPONENT_OD1] = { MTK_DISP_OD, 1, &ddp_od }, @@ -278,6 +279,7 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node, comp_id == DDP_COMPONENT_DPI0 || comp_id == DDP_COMPONENT_DPI1 || comp_id == DDP_COMPONENT_DSI0 || + comp_id == DDP_COMPONENT_DSI2 || comp_id == DDP_COMPONENT_PWM0) { comp->regs = NULL; comp->clk = NULL; diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h index 54c99c169093b..8d152b337f15d 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h @@ -50,6 +50,7 @@ enum mtk_ddp_comp_id { DDP_COMPONENT_DPI1, DDP_COMPONENT_DSI0, DDP_COMPONENT_DSI1, + DDP_COMPONENT_DSI2, DDP_COMPONENT_GAMMA, DDP_COMPONENT_OD0, DDP_COMPONENT_OD1, -- GitLab From b1df55d308a0489dc7f1531c83607101c3535b8e Mon Sep 17 00:00:00 2001 From: "stu.hsieh@mediatek.com" <stu.hsieh@mediatek.com> Date: Wed, 20 Jun 2018 16:19:11 +0800 Subject: [PATCH 0478/1506] drm/mediatek: add component DSI3 This patch add the component DSI3 Signed-off-by: Stu Hsieh <stu.hsieh@mediatek.com> Signed-off-by: CK Hu <ck.hu@mediatek.com> --- drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c | 2 ++ drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c index 071f9f5aefea5..17b681686471f 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c @@ -228,6 +228,7 @@ static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_ID_MAX] = { [DDP_COMPONENT_DSI0] = { MTK_DSI, 0, NULL }, [DDP_COMPONENT_DSI1] = { MTK_DSI, 1, NULL }, [DDP_COMPONENT_DSI2] = { MTK_DSI, 2, NULL }, + [DDP_COMPONENT_DSI3] = { MTK_DSI, 3, NULL }, [DDP_COMPONENT_GAMMA] = { MTK_DISP_GAMMA, 0, &ddp_gamma }, [DDP_COMPONENT_OD0] = { MTK_DISP_OD, 0, &ddp_od }, [DDP_COMPONENT_OD1] = { MTK_DISP_OD, 1, &ddp_od }, @@ -280,6 +281,7 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node, comp_id == DDP_COMPONENT_DPI1 || comp_id == DDP_COMPONENT_DSI0 || comp_id == DDP_COMPONENT_DSI2 || + comp_id == DDP_COMPONENT_DSI3 || comp_id == DDP_COMPONENT_PWM0) { comp->regs = NULL; comp->clk = NULL; diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h index 8d152b337f15d..7413ffeb3c9d8 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h @@ -51,6 +51,7 @@ enum mtk_ddp_comp_id { DDP_COMPONENT_DSI0, DDP_COMPONENT_DSI1, DDP_COMPONENT_DSI2, + DDP_COMPONENT_DSI3, DDP_COMPONENT_GAMMA, DDP_COMPONENT_OD0, DDP_COMPONENT_OD1, -- GitLab From 6de614026234f900ee55afb8dc8ea5f07b7509cd Mon Sep 17 00:00:00 2001 From: "stu.hsieh@mediatek.com" <stu.hsieh@mediatek.com> Date: Wed, 20 Jun 2018 16:19:12 +0800 Subject: [PATCH 0479/1506] drm/mediatek: add the DSI1 for component init condition This patch add the DSI1 for component init condition Signed-off-by: Stu Hsieh <stu.hsieh@mediatek.com> Signed-off-by: CK Hu <ck.hu@mediatek.com> --- drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c index 17b681686471f..ff974d82a4a67 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c @@ -280,6 +280,7 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node, comp_id == DDP_COMPONENT_DPI0 || comp_id == DDP_COMPONENT_DPI1 || comp_id == DDP_COMPONENT_DSI0 || + comp_id == DDP_COMPONENT_DSI1 || comp_id == DDP_COMPONENT_DSI2 || comp_id == DDP_COMPONENT_DSI3 || comp_id == DDP_COMPONENT_PWM0) { -- GitLab From 9b7b38de386c529d2529bb9670582cec680e239e Mon Sep 17 00:00:00 2001 From: "stu.hsieh@mediatek.com" <stu.hsieh@mediatek.com> Date: Wed, 20 Jun 2018 16:19:13 +0800 Subject: [PATCH 0480/1506] drm/mediatek: add connection from OD1 to RDMA1 This patch add the connection from OD1 to RDMA1 for ext path. Signed-off-by: Stu Hsieh <stu.hsieh@mediatek.com> Signed-off-by: CK Hu <ck.hu@mediatek.com> --- drivers/gpu/drm/mediatek/mtk_drm_ddp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c index 58e44349e3157..8bfc0debd2c2f 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c @@ -75,6 +75,7 @@ #define OVL0_MOUT_EN_COLOR0 0x1 #define OD_MOUT_EN_RDMA0 0x1 +#define OD1_MOUT_EN_RDMA1 BIT(16) #define UFOE_MOUT_EN_DSI0 0x1 #define COLOR0_SEL_IN_OVL0 0x1 #define OVL1_MOUT_EN_COLOR1 0x1 @@ -151,6 +152,9 @@ static unsigned int mtk_ddp_mout_en(enum mtk_ddp_comp_id cur, } else if (cur == DDP_COMPONENT_GAMMA && next == DDP_COMPONENT_RDMA1) { *addr = DISP_REG_CONFIG_DISP_GAMMA_MOUT_EN; value = GAMMA_MOUT_EN_RDMA1; + } else if (cur == DDP_COMPONENT_OD1 && next == DDP_COMPONENT_RDMA1) { + *addr = DISP_REG_CONFIG_DISP_OD_MOUT_EN; + value = OD1_MOUT_EN_RDMA1; } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DPI0) { *addr = DISP_REG_CONFIG_DISP_RDMA1_MOUT_EN; value = RDMA1_MOUT_DPI0; -- GitLab From 09013b1619934cb5c5b17d9a5a183c3b20ca8d6e Mon Sep 17 00:00:00 2001 From: "stu.hsieh@mediatek.com" <stu.hsieh@mediatek.com> Date: Wed, 20 Jun 2018 16:19:14 +0800 Subject: [PATCH 0481/1506] drm/mediatek: Update the definition of connection from RDMA1 to DPI0 This patch update the definition of connection from RDMA1 to DPI0. Change the term MOUT to SOUT. Because our HW datasheet use the term SOUT to match its function for RDMA. For consistency, changing the name from MOUT to SOUT is better. Signed-off-by: Stu Hsieh <stu.hsieh@mediatek.com> Signed-off-by: CK Hu <ck.hu@mediatek.com> --- drivers/gpu/drm/mediatek/mtk_drm_ddp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c index 8bfc0debd2c2f..977df8facb79b 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c @@ -29,7 +29,7 @@ #define DISP_REG_CONFIG_DISP_COLOR0_SEL_IN 0x084 #define DISP_REG_CONFIG_DISP_COLOR1_SEL_IN 0x088 #define DISP_REG_CONFIG_DPI_SEL_IN 0x0ac -#define DISP_REG_CONFIG_DISP_RDMA1_MOUT_EN 0x0c8 +#define DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN 0x0c8 #define DISP_REG_CONFIG_MMSYS_CG_CON0 0x100 #define DISP_REG_CONFIG_DISP_OVL_MOUT_EN 0x030 @@ -80,7 +80,7 @@ #define COLOR0_SEL_IN_OVL0 0x1 #define OVL1_MOUT_EN_COLOR1 0x1 #define GAMMA_MOUT_EN_RDMA1 0x1 -#define RDMA1_MOUT_DPI0 0x2 +#define RDMA1_SOUT_DPI0 0x2 #define DPI0_SEL_IN_RDMA1 0x1 #define COLOR1_SEL_IN_OVL1 0x1 @@ -156,8 +156,8 @@ static unsigned int mtk_ddp_mout_en(enum mtk_ddp_comp_id cur, *addr = DISP_REG_CONFIG_DISP_OD_MOUT_EN; value = OD1_MOUT_EN_RDMA1; } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DPI0) { - *addr = DISP_REG_CONFIG_DISP_RDMA1_MOUT_EN; - value = RDMA1_MOUT_DPI0; + *addr = DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN; + value = RDMA1_SOUT_DPI0; } else { value = 0; } -- GitLab From 7b86302401dfdee2b26d99be0d61759a5ab47f11 Mon Sep 17 00:00:00 2001 From: "stu.hsieh@mediatek.com" <stu.hsieh@mediatek.com> Date: Wed, 20 Jun 2018 16:19:15 +0800 Subject: [PATCH 0482/1506] drm/mediatek: add connection from RDMA0 to DPI0 This patch add the connection from RDMA0 to DPI0 Signed-off-by: Stu Hsieh <stu.hsieh@mediatek.com> Signed-off-by: CK Hu <ck.hu@mediatek.com> --- drivers/gpu/drm/mediatek/mtk_drm_ddp.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c index 977df8facb79b..3a3f37f523f2b 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c @@ -29,6 +29,7 @@ #define DISP_REG_CONFIG_DISP_COLOR0_SEL_IN 0x084 #define DISP_REG_CONFIG_DISP_COLOR1_SEL_IN 0x088 #define DISP_REG_CONFIG_DPI_SEL_IN 0x0ac +#define DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN 0x0c4 #define DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN 0x0c8 #define DISP_REG_CONFIG_MMSYS_CG_CON0 0x100 @@ -80,6 +81,7 @@ #define COLOR0_SEL_IN_OVL0 0x1 #define OVL1_MOUT_EN_COLOR1 0x1 #define GAMMA_MOUT_EN_RDMA1 0x1 +#define RDMA0_SOUT_DPI0 0x2 #define RDMA1_SOUT_DPI0 0x2 #define DPI0_SEL_IN_RDMA1 0x1 #define COLOR1_SEL_IN_OVL1 0x1 @@ -155,6 +157,9 @@ static unsigned int mtk_ddp_mout_en(enum mtk_ddp_comp_id cur, } else if (cur == DDP_COMPONENT_OD1 && next == DDP_COMPONENT_RDMA1) { *addr = DISP_REG_CONFIG_DISP_OD_MOUT_EN; value = OD1_MOUT_EN_RDMA1; + } else if (cur == DDP_COMPONENT_RDMA0 && next == DDP_COMPONENT_DPI0) { + *addr = DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN; + value = RDMA0_SOUT_DPI0; } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DPI0) { *addr = DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN; value = RDMA1_SOUT_DPI0; -- GitLab From 49793b767456863ccd260b61a661e74b8cd6d103 Mon Sep 17 00:00:00 2001 From: "stu.hsieh@mediatek.com" <stu.hsieh@mediatek.com> Date: Wed, 20 Jun 2018 16:19:16 +0800 Subject: [PATCH 0483/1506] drm/mediatek: add connection from RDMA0 to DSI2 This patch add the connection from RDMA0 to DSI2 Signed-off-by: Stu Hsieh <stu.hsieh@mediatek.com> Signed-off-by: CK Hu <ck.hu@mediatek.com> --- drivers/gpu/drm/mediatek/mtk_drm_ddp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c index 3a3f37f523f2b..f985bad61d83f 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c @@ -82,6 +82,7 @@ #define OVL1_MOUT_EN_COLOR1 0x1 #define GAMMA_MOUT_EN_RDMA1 0x1 #define RDMA0_SOUT_DPI0 0x2 +#define RDMA0_SOUT_DSI2 0x4 #define RDMA1_SOUT_DPI0 0x2 #define DPI0_SEL_IN_RDMA1 0x1 #define COLOR1_SEL_IN_OVL1 0x1 @@ -160,6 +161,9 @@ static unsigned int mtk_ddp_mout_en(enum mtk_ddp_comp_id cur, } else if (cur == DDP_COMPONENT_RDMA0 && next == DDP_COMPONENT_DPI0) { *addr = DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN; value = RDMA0_SOUT_DPI0; + } else if (cur == DDP_COMPONENT_RDMA0 && next == DDP_COMPONENT_DSI2) { + *addr = DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN; + value = RDMA0_SOUT_DSI2; } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DPI0) { *addr = DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN; value = RDMA1_SOUT_DPI0; -- GitLab From 89c04d65022496628dc6f9b01e51533ab26a8d18 Mon Sep 17 00:00:00 2001 From: "stu.hsieh@mediatek.com" <stu.hsieh@mediatek.com> Date: Wed, 20 Jun 2018 16:19:17 +0800 Subject: [PATCH 0484/1506] drm/mediatek: add connection from RDMA0 to DSI3 This patch add the connection from RDMA0 to DSI3 Signed-off-by: Stu Hsieh <stu.hsieh@mediatek.com> Signed-off-by: CK Hu <ck.hu@mediatek.com> --- drivers/gpu/drm/mediatek/mtk_drm_ddp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c index f985bad61d83f..463ed7830d170 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c @@ -83,6 +83,7 @@ #define GAMMA_MOUT_EN_RDMA1 0x1 #define RDMA0_SOUT_DPI0 0x2 #define RDMA0_SOUT_DSI2 0x4 +#define RDMA0_SOUT_DSI3 0x5 #define RDMA1_SOUT_DPI0 0x2 #define DPI0_SEL_IN_RDMA1 0x1 #define COLOR1_SEL_IN_OVL1 0x1 @@ -164,6 +165,9 @@ static unsigned int mtk_ddp_mout_en(enum mtk_ddp_comp_id cur, } else if (cur == DDP_COMPONENT_RDMA0 && next == DDP_COMPONENT_DSI2) { *addr = DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN; value = RDMA0_SOUT_DSI2; + } else if (cur == DDP_COMPONENT_RDMA0 && next == DDP_COMPONENT_DSI3) { + *addr = DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN; + value = RDMA0_SOUT_DSI3; } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DPI0) { *addr = DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN; value = RDMA1_SOUT_DPI0; -- GitLab From 73fabd5cebc11eccbf99dacda397c1dcb1198d73 Mon Sep 17 00:00:00 2001 From: "stu.hsieh@mediatek.com" <stu.hsieh@mediatek.com> Date: Wed, 20 Jun 2018 16:19:18 +0800 Subject: [PATCH 0485/1506] drm/mediatek: add connection from RDMA1 to DPI1 This patch add the connection from RDMA1 to DPI1 Signed-off-by: Stu Hsieh <stu.hsieh@mediatek.com> Signed-off-by: CK Hu <ck.hu@mediatek.com> --- drivers/gpu/drm/mediatek/mtk_drm_ddp.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c index 463ed7830d170..13e91903f4931 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c @@ -85,7 +85,9 @@ #define RDMA0_SOUT_DSI2 0x4 #define RDMA0_SOUT_DSI3 0x5 #define RDMA1_SOUT_DPI0 0x2 +#define RDMA1_SOUT_DPI1 0x3 #define DPI0_SEL_IN_RDMA1 0x1 +#define DPI1_SEL_IN_RDMA1 (0x1 << 8) #define COLOR1_SEL_IN_OVL1 0x1 #define OVL_MOUT_EN_RDMA 0x1 @@ -171,6 +173,9 @@ static unsigned int mtk_ddp_mout_en(enum mtk_ddp_comp_id cur, } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DPI0) { *addr = DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN; value = RDMA1_SOUT_DPI0; + } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DPI1) { + *addr = DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN; + value = RDMA1_SOUT_DPI1; } else { value = 0; } @@ -190,6 +195,9 @@ static unsigned int mtk_ddp_sel_in(enum mtk_ddp_comp_id cur, } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DPI0) { *addr = DISP_REG_CONFIG_DPI_SEL_IN; value = DPI0_SEL_IN_RDMA1; + } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DPI1) { + *addr = DISP_REG_CONFIG_DPI_SEL_IN; + value = DPI1_SEL_IN_RDMA1; } else if (cur == DDP_COMPONENT_OVL1 && next == DDP_COMPONENT_COLOR1) { *addr = DISP_REG_CONFIG_DISP_COLOR1_SEL_IN; value = COLOR1_SEL_IN_OVL1; -- GitLab From d46a8f851e880695410745a72a69abd6f05c376b Mon Sep 17 00:00:00 2001 From: "stu.hsieh@mediatek.com" <stu.hsieh@mediatek.com> Date: Wed, 20 Jun 2018 16:19:19 +0800 Subject: [PATCH 0486/1506] drm/mediatek: add connection from RDMA1 to DSI1 This patch add the connection from RDMA1 to DSI1 Signed-off-by: Stu Hsieh <stu.hsieh@mediatek.com> Signed-off-by: CK Hu <ck.hu@mediatek.com> --- drivers/gpu/drm/mediatek/mtk_drm_ddp.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c index 13e91903f4931..90228cad051aa 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c @@ -28,6 +28,7 @@ #define DISP_REG_CONFIG_DISP_UFOE_MOUT_EN 0x050 #define DISP_REG_CONFIG_DISP_COLOR0_SEL_IN 0x084 #define DISP_REG_CONFIG_DISP_COLOR1_SEL_IN 0x088 +#define DISP_REG_CONFIG_DSIO_SEL_IN 0x0a8 #define DISP_REG_CONFIG_DPI_SEL_IN 0x0ac #define DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN 0x0c4 #define DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN 0x0c8 @@ -86,8 +87,10 @@ #define RDMA0_SOUT_DSI3 0x5 #define RDMA1_SOUT_DPI0 0x2 #define RDMA1_SOUT_DPI1 0x3 +#define RDMA1_SOUT_DSI1 0x1 #define DPI0_SEL_IN_RDMA1 0x1 #define DPI1_SEL_IN_RDMA1 (0x1 << 8) +#define DSI1_SEL_IN_RDMA1 0x1 #define COLOR1_SEL_IN_OVL1 0x1 #define OVL_MOUT_EN_RDMA 0x1 @@ -170,6 +173,9 @@ static unsigned int mtk_ddp_mout_en(enum mtk_ddp_comp_id cur, } else if (cur == DDP_COMPONENT_RDMA0 && next == DDP_COMPONENT_DSI3) { *addr = DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN; value = RDMA0_SOUT_DSI3; + } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DSI1) { + *addr = DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN; + value = RDMA1_SOUT_DSI1; } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DPI0) { *addr = DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN; value = RDMA1_SOUT_DPI0; @@ -198,6 +204,9 @@ static unsigned int mtk_ddp_sel_in(enum mtk_ddp_comp_id cur, } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DPI1) { *addr = DISP_REG_CONFIG_DPI_SEL_IN; value = DPI1_SEL_IN_RDMA1; + } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DSI1) { + *addr = DISP_REG_CONFIG_DSIO_SEL_IN; + value = DSI1_SEL_IN_RDMA1; } else if (cur == DDP_COMPONENT_OVL1 && next == DDP_COMPONENT_COLOR1) { *addr = DISP_REG_CONFIG_DISP_COLOR1_SEL_IN; value = COLOR1_SEL_IN_OVL1; -- GitLab From 5346010f72226c38de987c366fdf81cb313679ef Mon Sep 17 00:00:00 2001 From: "stu.hsieh@mediatek.com" <stu.hsieh@mediatek.com> Date: Wed, 20 Jun 2018 16:19:20 +0800 Subject: [PATCH 0487/1506] drm/mediatek: add connection from RDMA1 to DSI2 This patch add the connection from RDMA1 to DSI2 Signed-off-by: Stu Hsieh <stu.hsieh@mediatek.com> Signed-off-by: CK Hu <ck.hu@mediatek.com> --- drivers/gpu/drm/mediatek/mtk_drm_ddp.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c index 90228cad051aa..9cf2fcb4932af 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c @@ -28,6 +28,7 @@ #define DISP_REG_CONFIG_DISP_UFOE_MOUT_EN 0x050 #define DISP_REG_CONFIG_DISP_COLOR0_SEL_IN 0x084 #define DISP_REG_CONFIG_DISP_COLOR1_SEL_IN 0x088 +#define DISP_REG_CONFIG_DSIE_SEL_IN 0x0a4 #define DISP_REG_CONFIG_DSIO_SEL_IN 0x0a8 #define DISP_REG_CONFIG_DPI_SEL_IN 0x0ac #define DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN 0x0c4 @@ -88,9 +89,11 @@ #define RDMA1_SOUT_DPI0 0x2 #define RDMA1_SOUT_DPI1 0x3 #define RDMA1_SOUT_DSI1 0x1 +#define RDMA1_SOUT_DSI2 0x4 #define DPI0_SEL_IN_RDMA1 0x1 #define DPI1_SEL_IN_RDMA1 (0x1 << 8) #define DSI1_SEL_IN_RDMA1 0x1 +#define DSI2_SEL_IN_RDMA1 (0x1 << 16) #define COLOR1_SEL_IN_OVL1 0x1 #define OVL_MOUT_EN_RDMA 0x1 @@ -176,6 +179,9 @@ static unsigned int mtk_ddp_mout_en(enum mtk_ddp_comp_id cur, } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DSI1) { *addr = DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN; value = RDMA1_SOUT_DSI1; + } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DSI2) { + *addr = DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN; + value = RDMA1_SOUT_DSI2; } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DPI0) { *addr = DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN; value = RDMA1_SOUT_DPI0; @@ -207,6 +213,9 @@ static unsigned int mtk_ddp_sel_in(enum mtk_ddp_comp_id cur, } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DSI1) { *addr = DISP_REG_CONFIG_DSIO_SEL_IN; value = DSI1_SEL_IN_RDMA1; + } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DSI2) { + *addr = DISP_REG_CONFIG_DSIE_SEL_IN; + value = DSI2_SEL_IN_RDMA1; } else if (cur == DDP_COMPONENT_OVL1 && next == DDP_COMPONENT_COLOR1) { *addr = DISP_REG_CONFIG_DISP_COLOR1_SEL_IN; value = COLOR1_SEL_IN_OVL1; -- GitLab From 15484ae0afa9286f166bdb64a97700f215ada956 Mon Sep 17 00:00:00 2001 From: "stu.hsieh@mediatek.com" <stu.hsieh@mediatek.com> Date: Wed, 20 Jun 2018 16:19:21 +0800 Subject: [PATCH 0488/1506] drm/mediatek: add connection from RDMA1 to DSI3 This patch add the connection from RDMA1 to DSI3 Signed-off-by: Stu Hsieh <stu.hsieh@mediatek.com> Signed-off-by: CK Hu <ck.hu@mediatek.com> --- drivers/gpu/drm/mediatek/mtk_drm_ddp.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c index 9cf2fcb4932af..d0d5f337ce149 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c @@ -90,10 +90,12 @@ #define RDMA1_SOUT_DPI1 0x3 #define RDMA1_SOUT_DSI1 0x1 #define RDMA1_SOUT_DSI2 0x4 +#define RDMA1_SOUT_DSI3 0x5 #define DPI0_SEL_IN_RDMA1 0x1 #define DPI1_SEL_IN_RDMA1 (0x1 << 8) #define DSI1_SEL_IN_RDMA1 0x1 #define DSI2_SEL_IN_RDMA1 (0x1 << 16) +#define DSI3_SEL_IN_RDMA1 (0x1 << 16) #define COLOR1_SEL_IN_OVL1 0x1 #define OVL_MOUT_EN_RDMA 0x1 @@ -182,6 +184,9 @@ static unsigned int mtk_ddp_mout_en(enum mtk_ddp_comp_id cur, } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DSI2) { *addr = DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN; value = RDMA1_SOUT_DSI2; + } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DSI3) { + *addr = DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN; + value = RDMA1_SOUT_DSI3; } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DPI0) { *addr = DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN; value = RDMA1_SOUT_DPI0; @@ -216,6 +221,9 @@ static unsigned int mtk_ddp_sel_in(enum mtk_ddp_comp_id cur, } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DSI2) { *addr = DISP_REG_CONFIG_DSIE_SEL_IN; value = DSI2_SEL_IN_RDMA1; + } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DSI3) { + *addr = DISP_REG_CONFIG_DSIO_SEL_IN; + value = DSI3_SEL_IN_RDMA1; } else if (cur == DDP_COMPONENT_OVL1 && next == DDP_COMPONENT_COLOR1) { *addr = DISP_REG_CONFIG_DISP_COLOR1_SEL_IN; value = COLOR1_SEL_IN_OVL1; -- GitLab From 01915b8588142af11a9416dcbb4e58bc0518c3ee Mon Sep 17 00:00:00 2001 From: "stu.hsieh@mediatek.com" <stu.hsieh@mediatek.com> Date: Wed, 20 Jun 2018 16:19:22 +0800 Subject: [PATCH 0489/1506] drm/mediatek: add connection from RDMA2 to DPI0 This patch add the connection from RDMA2 to DPI0 Signed-off-by: Stu Hsieh <stu.hsieh@mediatek.com> Signed-off-by: CK Hu <ck.hu@mediatek.com> --- drivers/gpu/drm/mediatek/mtk_drm_ddp.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c index d0d5f337ce149..c88742a6c2b96 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c @@ -31,6 +31,7 @@ #define DISP_REG_CONFIG_DSIE_SEL_IN 0x0a4 #define DISP_REG_CONFIG_DSIO_SEL_IN 0x0a8 #define DISP_REG_CONFIG_DPI_SEL_IN 0x0ac +#define DISP_REG_CONFIG_DISP_RDMA2_SOUT 0x0b8 #define DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN 0x0c4 #define DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN 0x0c8 #define DISP_REG_CONFIG_MMSYS_CG_CON0 0x100 @@ -91,7 +92,9 @@ #define RDMA1_SOUT_DSI1 0x1 #define RDMA1_SOUT_DSI2 0x4 #define RDMA1_SOUT_DSI3 0x5 +#define RDMA2_SOUT_DPI0 0x2 #define DPI0_SEL_IN_RDMA1 0x1 +#define DPI0_SEL_IN_RDMA2 0x3 #define DPI1_SEL_IN_RDMA1 (0x1 << 8) #define DSI1_SEL_IN_RDMA1 0x1 #define DSI2_SEL_IN_RDMA1 (0x1 << 16) @@ -193,6 +196,9 @@ static unsigned int mtk_ddp_mout_en(enum mtk_ddp_comp_id cur, } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DPI1) { *addr = DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN; value = RDMA1_SOUT_DPI1; + } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DPI0) { + *addr = DISP_REG_CONFIG_DISP_RDMA2_SOUT; + value = RDMA2_SOUT_DPI0; } else { value = 0; } @@ -224,6 +230,9 @@ static unsigned int mtk_ddp_sel_in(enum mtk_ddp_comp_id cur, } else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DSI3) { *addr = DISP_REG_CONFIG_DSIO_SEL_IN; value = DSI3_SEL_IN_RDMA1; + } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DPI0) { + *addr = DISP_REG_CONFIG_DPI_SEL_IN; + value = DPI0_SEL_IN_RDMA2; } else if (cur == DDP_COMPONENT_OVL1 && next == DDP_COMPONENT_COLOR1) { *addr = DISP_REG_CONFIG_DISP_COLOR1_SEL_IN; value = COLOR1_SEL_IN_OVL1; -- GitLab From 7ddac091673c576f010aca262bb56f5e25fc5577 Mon Sep 17 00:00:00 2001 From: "stu.hsieh@mediatek.com" <stu.hsieh@mediatek.com> Date: Wed, 20 Jun 2018 16:19:23 +0800 Subject: [PATCH 0490/1506] drm/mediatek: add connection from RDMA2 to DPI1 This patch add the connection from RDMA2 to DPI1 Signed-off-by: Stu Hsieh <stu.hsieh@mediatek.com> Signed-off-by: CK Hu <ck.hu@mediatek.com> --- drivers/gpu/drm/mediatek/mtk_drm_ddp.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c index c88742a6c2b96..a4b418302f32f 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c @@ -93,9 +93,11 @@ #define RDMA1_SOUT_DSI2 0x4 #define RDMA1_SOUT_DSI3 0x5 #define RDMA2_SOUT_DPI0 0x2 +#define RDMA2_SOUT_DPI1 0x3 #define DPI0_SEL_IN_RDMA1 0x1 #define DPI0_SEL_IN_RDMA2 0x3 #define DPI1_SEL_IN_RDMA1 (0x1 << 8) +#define DPI1_SEL_IN_RDMA2 (0x3 << 8) #define DSI1_SEL_IN_RDMA1 0x1 #define DSI2_SEL_IN_RDMA1 (0x1 << 16) #define DSI3_SEL_IN_RDMA1 (0x1 << 16) @@ -199,6 +201,9 @@ static unsigned int mtk_ddp_mout_en(enum mtk_ddp_comp_id cur, } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DPI0) { *addr = DISP_REG_CONFIG_DISP_RDMA2_SOUT; value = RDMA2_SOUT_DPI0; + } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DPI1) { + *addr = DISP_REG_CONFIG_DISP_RDMA2_SOUT; + value = RDMA2_SOUT_DPI1; } else { value = 0; } @@ -233,6 +238,9 @@ static unsigned int mtk_ddp_sel_in(enum mtk_ddp_comp_id cur, } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DPI0) { *addr = DISP_REG_CONFIG_DPI_SEL_IN; value = DPI0_SEL_IN_RDMA2; + } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DPI1) { + *addr = DISP_REG_CONFIG_DPI_SEL_IN; + value = DPI1_SEL_IN_RDMA2; } else if (cur == DDP_COMPONENT_OVL1 && next == DDP_COMPONENT_COLOR1) { *addr = DISP_REG_CONFIG_DISP_COLOR1_SEL_IN; value = COLOR1_SEL_IN_OVL1; -- GitLab From 0064be8c71fd38d9d65c18d3561d9ea48d759387 Mon Sep 17 00:00:00 2001 From: "stu.hsieh@mediatek.com" <stu.hsieh@mediatek.com> Date: Wed, 20 Jun 2018 16:19:24 +0800 Subject: [PATCH 0491/1506] drm/mediatek: add connection from RDMA2 to DSI1 This patch add the connection from RDMA2 to DSI1 Signed-off-by: Stu Hsieh <stu.hsieh@mediatek.com> Signed-off-by: CK Hu <ck.hu@mediatek.com> --- drivers/gpu/drm/mediatek/mtk_drm_ddp.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c index a4b418302f32f..db78fad785e33 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c @@ -94,11 +94,13 @@ #define RDMA1_SOUT_DSI3 0x5 #define RDMA2_SOUT_DPI0 0x2 #define RDMA2_SOUT_DPI1 0x3 +#define RDMA2_SOUT_DSI1 0x1 #define DPI0_SEL_IN_RDMA1 0x1 #define DPI0_SEL_IN_RDMA2 0x3 #define DPI1_SEL_IN_RDMA1 (0x1 << 8) #define DPI1_SEL_IN_RDMA2 (0x3 << 8) #define DSI1_SEL_IN_RDMA1 0x1 +#define DSI1_SEL_IN_RDMA2 0x4 #define DSI2_SEL_IN_RDMA1 (0x1 << 16) #define DSI3_SEL_IN_RDMA1 (0x1 << 16) #define COLOR1_SEL_IN_OVL1 0x1 @@ -204,6 +206,9 @@ static unsigned int mtk_ddp_mout_en(enum mtk_ddp_comp_id cur, } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DPI1) { *addr = DISP_REG_CONFIG_DISP_RDMA2_SOUT; value = RDMA2_SOUT_DPI1; + } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DSI1) { + *addr = DISP_REG_CONFIG_DISP_RDMA2_SOUT; + value = RDMA2_SOUT_DSI1; } else { value = 0; } @@ -241,6 +246,9 @@ static unsigned int mtk_ddp_sel_in(enum mtk_ddp_comp_id cur, } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DPI1) { *addr = DISP_REG_CONFIG_DPI_SEL_IN; value = DPI1_SEL_IN_RDMA2; + } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DSI1) { + *addr = DISP_REG_CONFIG_DSIE_SEL_IN; + value = DSI1_SEL_IN_RDMA2; } else if (cur == DDP_COMPONENT_OVL1 && next == DDP_COMPONENT_COLOR1) { *addr = DISP_REG_CONFIG_DISP_COLOR1_SEL_IN; value = COLOR1_SEL_IN_OVL1; -- GitLab From 46ce9b2dc78ca7f8e224fb74c71f3d4caf2f7dab Mon Sep 17 00:00:00 2001 From: "stu.hsieh@mediatek.com" <stu.hsieh@mediatek.com> Date: Wed, 20 Jun 2018 16:19:25 +0800 Subject: [PATCH 0492/1506] drm/mediatek: add connection from RDMA2 to DSI2 This patch add the connection from RDMA2 to DSI2 Signed-off-by: Stu Hsieh <stu.hsieh@mediatek.com> Signed-off-by: CK Hu <ck.hu@mediatek.com> --- drivers/gpu/drm/mediatek/mtk_drm_ddp.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c index db78fad785e33..e5db1ab51c9bd 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c @@ -95,6 +95,7 @@ #define RDMA2_SOUT_DPI0 0x2 #define RDMA2_SOUT_DPI1 0x3 #define RDMA2_SOUT_DSI1 0x1 +#define RDMA2_SOUT_DSI2 0x4 #define DPI0_SEL_IN_RDMA1 0x1 #define DPI0_SEL_IN_RDMA2 0x3 #define DPI1_SEL_IN_RDMA1 (0x1 << 8) @@ -102,6 +103,7 @@ #define DSI1_SEL_IN_RDMA1 0x1 #define DSI1_SEL_IN_RDMA2 0x4 #define DSI2_SEL_IN_RDMA1 (0x1 << 16) +#define DSI2_SEL_IN_RDMA2 (0x4 << 16) #define DSI3_SEL_IN_RDMA1 (0x1 << 16) #define COLOR1_SEL_IN_OVL1 0x1 @@ -209,6 +211,9 @@ static unsigned int mtk_ddp_mout_en(enum mtk_ddp_comp_id cur, } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DSI1) { *addr = DISP_REG_CONFIG_DISP_RDMA2_SOUT; value = RDMA2_SOUT_DSI1; + } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DSI2) { + *addr = DISP_REG_CONFIG_DISP_RDMA2_SOUT; + value = RDMA2_SOUT_DSI2; } else { value = 0; } @@ -249,6 +254,9 @@ static unsigned int mtk_ddp_sel_in(enum mtk_ddp_comp_id cur, } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DSI1) { *addr = DISP_REG_CONFIG_DSIE_SEL_IN; value = DSI1_SEL_IN_RDMA2; + } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DSI2) { + *addr = DISP_REG_CONFIG_DSIE_SEL_IN; + value = DSI2_SEL_IN_RDMA2; } else if (cur == DDP_COMPONENT_OVL1 && next == DDP_COMPONENT_COLOR1) { *addr = DISP_REG_CONFIG_DISP_COLOR1_SEL_IN; value = COLOR1_SEL_IN_OVL1; -- GitLab From d335369e7543fdf8f9111d8b03a8cae3e1526434 Mon Sep 17 00:00:00 2001 From: "stu.hsieh@mediatek.com" <stu.hsieh@mediatek.com> Date: Wed, 20 Jun 2018 16:19:26 +0800 Subject: [PATCH 0493/1506] drm/mediatek: add connection from RDMA2 to DSI3 This patch add the connection from RDMA2 to DSI3 Signed-off-by: Stu Hsieh <stu.hsieh@mediatek.com> Signed-off-by: CK Hu <ck.hu@mediatek.com> --- drivers/gpu/drm/mediatek/mtk_drm_ddp.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c index e5db1ab51c9bd..0a1b967cab1b2 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c @@ -96,6 +96,7 @@ #define RDMA2_SOUT_DPI1 0x3 #define RDMA2_SOUT_DSI1 0x1 #define RDMA2_SOUT_DSI2 0x4 +#define RDMA2_SOUT_DSI3 0x5 #define DPI0_SEL_IN_RDMA1 0x1 #define DPI0_SEL_IN_RDMA2 0x3 #define DPI1_SEL_IN_RDMA1 (0x1 << 8) @@ -105,6 +106,7 @@ #define DSI2_SEL_IN_RDMA1 (0x1 << 16) #define DSI2_SEL_IN_RDMA2 (0x4 << 16) #define DSI3_SEL_IN_RDMA1 (0x1 << 16) +#define DSI3_SEL_IN_RDMA2 (0x4 << 16) #define COLOR1_SEL_IN_OVL1 0x1 #define OVL_MOUT_EN_RDMA 0x1 @@ -214,6 +216,9 @@ static unsigned int mtk_ddp_mout_en(enum mtk_ddp_comp_id cur, } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DSI2) { *addr = DISP_REG_CONFIG_DISP_RDMA2_SOUT; value = RDMA2_SOUT_DSI2; + } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DSI3) { + *addr = DISP_REG_CONFIG_DISP_RDMA2_SOUT; + value = RDMA2_SOUT_DSI3; } else { value = 0; } @@ -257,6 +262,9 @@ static unsigned int mtk_ddp_sel_in(enum mtk_ddp_comp_id cur, } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DSI2) { *addr = DISP_REG_CONFIG_DSIE_SEL_IN; value = DSI2_SEL_IN_RDMA2; + } else if (cur == DDP_COMPONENT_RDMA2 && next == DDP_COMPONENT_DSI3) { + *addr = DISP_REG_CONFIG_DSIE_SEL_IN; + value = DSI3_SEL_IN_RDMA2; } else if (cur == DDP_COMPONENT_OVL1 && next == DDP_COMPONENT_COLOR1) { *addr = DISP_REG_CONFIG_DISP_COLOR1_SEL_IN; value = COLOR1_SEL_IN_OVL1; -- GitLab From f4f3ec480e82fa0c8c93a02b01e46719e4985752 Mon Sep 17 00:00:00 2001 From: "stu.hsieh@mediatek.com" <stu.hsieh@mediatek.com> Date: Wed, 20 Jun 2018 16:19:27 +0800 Subject: [PATCH 0494/1506] drm/mediatek: add DPI1 support for mutex This patch add the DPI1 support for mutex Signed-off-by: Stu Hsieh <stu.hsieh@mediatek.com> Signed-off-by: CK Hu <ck.hu@mediatek.com> --- drivers/gpu/drm/mediatek/mtk_drm_ddp.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c index 0a1b967cab1b2..4c203d013d7c6 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c @@ -76,6 +76,7 @@ #define MUTEX_SOF_DSI0 1 #define MUTEX_SOF_DSI1 2 #define MUTEX_SOF_DPI0 3 +#define MUTEX_SOF_DPI1 4 #define OVL0_MOUT_EN_COLOR0 0x1 #define OD_MOUT_EN_RDMA0 0x1 @@ -385,6 +386,9 @@ void mtk_disp_mutex_add_comp(struct mtk_disp_mutex *mutex, case DDP_COMPONENT_DPI0: reg = MUTEX_SOF_DPI0; break; + case DDP_COMPONENT_DPI1: + reg = MUTEX_SOF_DPI1; + break; default: if (ddp->mutex_mod[id] < 32) { offset = DISP_REG_MUTEX_MOD(mutex->id); @@ -417,6 +421,7 @@ void mtk_disp_mutex_remove_comp(struct mtk_disp_mutex *mutex, case DDP_COMPONENT_DSI0: case DDP_COMPONENT_DSI1: case DDP_COMPONENT_DPI0: + case DDP_COMPONENT_DPI1: writel_relaxed(MUTEX_SOF_SINGLE_MODE, ddp->regs + DISP_REG_MUTEX_SOF(mutex->id)); break; -- GitLab From dee8eb4e668d059d2cc3a92717006da50bb2d491 Mon Sep 17 00:00:00 2001 From: "stu.hsieh@mediatek.com" <stu.hsieh@mediatek.com> Date: Wed, 20 Jun 2018 16:19:28 +0800 Subject: [PATCH 0495/1506] drm/mediatek: add DSI2 support for mutex This patch add the DSI2 support for mutex Signed-off-by: Stu Hsieh <stu.hsieh@mediatek.com> Signed-off-by: CK Hu <ck.hu@mediatek.com> --- drivers/gpu/drm/mediatek/mtk_drm_ddp.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c index 4c203d013d7c6..a0b526b16da13 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c @@ -77,6 +77,7 @@ #define MUTEX_SOF_DSI1 2 #define MUTEX_SOF_DPI0 3 #define MUTEX_SOF_DPI1 4 +#define MUTEX_SOF_DSI2 5 #define OVL0_MOUT_EN_COLOR0 0x1 #define OD_MOUT_EN_RDMA0 0x1 @@ -383,6 +384,9 @@ void mtk_disp_mutex_add_comp(struct mtk_disp_mutex *mutex, case DDP_COMPONENT_DSI1: reg = MUTEX_SOF_DSI0; break; + case DDP_COMPONENT_DSI2: + reg = MUTEX_SOF_DSI2; + break; case DDP_COMPONENT_DPI0: reg = MUTEX_SOF_DPI0; break; @@ -420,6 +424,7 @@ void mtk_disp_mutex_remove_comp(struct mtk_disp_mutex *mutex, switch (id) { case DDP_COMPONENT_DSI0: case DDP_COMPONENT_DSI1: + case DDP_COMPONENT_DSI2: case DDP_COMPONENT_DPI0: case DDP_COMPONENT_DPI1: writel_relaxed(MUTEX_SOF_SINGLE_MODE, -- GitLab From 16dd757ead7a05e9cb88db9972916eef4e0a842a Mon Sep 17 00:00:00 2001 From: "stu.hsieh@mediatek.com" <stu.hsieh@mediatek.com> Date: Wed, 20 Jun 2018 16:19:29 +0800 Subject: [PATCH 0496/1506] drm/mediatek: add DSI3 support for mutex This patch add the DSI3 support for mutex Signed-off-by: Stu Hsieh <stu.hsieh@mediatek.com> Signed-off-by: CK Hu <ck.hu@mediatek.com> --- drivers/gpu/drm/mediatek/mtk_drm_ddp.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c index a0b526b16da13..15e436d4e8a07 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c @@ -78,6 +78,7 @@ #define MUTEX_SOF_DPI0 3 #define MUTEX_SOF_DPI1 4 #define MUTEX_SOF_DSI2 5 +#define MUTEX_SOF_DSI3 6 #define OVL0_MOUT_EN_COLOR0 0x1 #define OD_MOUT_EN_RDMA0 0x1 @@ -387,6 +388,9 @@ void mtk_disp_mutex_add_comp(struct mtk_disp_mutex *mutex, case DDP_COMPONENT_DSI2: reg = MUTEX_SOF_DSI2; break; + case DDP_COMPONENT_DSI3: + reg = MUTEX_SOF_DSI3; + break; case DDP_COMPONENT_DPI0: reg = MUTEX_SOF_DPI0; break; @@ -425,6 +429,7 @@ void mtk_disp_mutex_remove_comp(struct mtk_disp_mutex *mutex, case DDP_COMPONENT_DSI0: case DDP_COMPONENT_DSI1: case DDP_COMPONENT_DSI2: + case DDP_COMPONENT_DSI3: case DDP_COMPONENT_DPI0: case DDP_COMPONENT_DPI1: writel_relaxed(MUTEX_SOF_SINGLE_MODE, -- GitLab From 561fad31e697b73c22e0373e01a33311912b58eb Mon Sep 17 00:00:00 2001 From: "stu.hsieh@mediatek.com" <stu.hsieh@mediatek.com> Date: Wed, 20 Jun 2018 16:19:30 +0800 Subject: [PATCH 0497/1506] drm/mediatek: add third ddp path This patch create third crtc by third ddp path Signed-off-by: Stu Hsieh <stu.hsieh@mediatek.com> Signed-off-by: CK Hu <ck.hu@mediatek.com> --- drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 3 +++ drivers/gpu/drm/mediatek/mtk_drm_drv.c | 5 +++++ drivers/gpu/drm/mediatek/mtk_drm_drv.h | 5 ++++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c index 658b8dd45b834..2d6aa150a9ff0 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c @@ -539,6 +539,9 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev, int ret; int i; + if (!path) + return 0; + for (i = 0; i < path_len; i++) { enum mtk_ddp_comp_id comp_id = path[i]; struct device_node *node; diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c index 08d5d0b47bfe5..3d279a2993830 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c @@ -232,6 +232,11 @@ static int mtk_drm_kms_init(struct drm_device *drm) if (ret < 0) goto err_component_unbind; + ret = mtk_drm_crtc_create(drm, private->data->third_path, + private->data->third_len); + if (ret < 0) + goto err_component_unbind; + /* Use OVL device for all DMA memory allocations */ np = private->comp_node[private->data->main_path[0]] ?: private->comp_node[private->data->ext_path[0]]; diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h index c3378c452c0a0..ecc00ca3221da 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h @@ -17,7 +17,7 @@ #include <linux/io.h> #include "mtk_drm_ddp_comp.h" -#define MAX_CRTC 2 +#define MAX_CRTC 3 #define MAX_CONNECTOR 2 struct device; @@ -33,6 +33,9 @@ struct mtk_mmsys_driver_data { unsigned int main_len; const enum mtk_ddp_comp_id *ext_path; unsigned int ext_len; + const enum mtk_ddp_comp_id *third_path; + unsigned int third_len; + bool shadow_register; }; -- GitLab From 3c8daa7db46dd50c95778b4fbca5c7da6edaac9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <ckoenig.leichtzumerken@gmail.com> Date: Fri, 22 Jun 2018 12:37:37 +0200 Subject: [PATCH 0498/1506] drm/omap: remove now unused functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some functions are unused after removal of the kmap_atomic DMA-buf interface. Signed-off-by: Christian König <christian.koenig@amd.com> Fixes: f664a5269542 ("dma-buf: remove kmap_atomic interface") Link: https://patchwork.freedesktop.org/series/45245/ Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c index 1a073f9b28349..ec04a69ade46b 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c +++ b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c @@ -93,23 +93,6 @@ static int omap_gem_dmabuf_end_cpu_access(struct dma_buf *buffer, return 0; } - -static void *omap_gem_dmabuf_kmap_atomic(struct dma_buf *buffer, - unsigned long page_num) -{ - struct drm_gem_object *obj = buffer->priv; - struct page **pages; - omap_gem_get_pages(obj, &pages, false); - omap_gem_cpu_sync_page(obj, page_num); - return kmap_atomic(pages[page_num]); -} - -static void omap_gem_dmabuf_kunmap_atomic(struct dma_buf *buffer, - unsigned long page_num, void *addr) -{ - kunmap_atomic(addr); -} - static void *omap_gem_dmabuf_kmap(struct dma_buf *buffer, unsigned long page_num) { -- GitLab From 1572042a4ab25567e4785b53b947729dfa2dac99 Mon Sep 17 00:00:00 2001 From: David Herrmann <dh.herrmann@gmail.com> Date: Mon, 18 Jun 2018 16:17:28 +0200 Subject: [PATCH 0499/1506] drm: provide management functions for drm_file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather than doing drm_file allocation/destruction right in the fops, lets provide separate helpers. This decouples drm_file management from the still-mandatory drm-fops. It prepares for use of drm_file without the fops, both by possible separate fops implementations and APIs (not that I am aware of any such plans), and more importantly from in-kernel use where no real file is available. Signed-off-by: David Herrmann <dh.herrmann@gmail.com> Signed-off-by: Noralf Trønnes <noralf@tronnes.org> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180618141739.48151-2-noralf@tronnes.org --- drivers/gpu/drm/drm_file.c | 305 +++++++++++++++++++-------------- drivers/gpu/drm/drm_internal.h | 2 + 2 files changed, 175 insertions(+), 132 deletions(-) diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c index 6d9b9453707c5..c0410b8330436 100644 --- a/drivers/gpu/drm/drm_file.c +++ b/drivers/gpu/drm/drm_file.c @@ -101,6 +101,175 @@ DEFINE_MUTEX(drm_global_mutex); static int drm_open_helper(struct file *filp, struct drm_minor *minor); +/** + * drm_file_alloc - allocate file context + * @minor: minor to allocate on + * + * This allocates a new DRM file context. It is not linked into any context and + * can be used by the caller freely. Note that the context keeps a pointer to + * @minor, so it must be freed before @minor is. + * + * RETURNS: + * Pointer to newly allocated context, ERR_PTR on failure. + */ +struct drm_file *drm_file_alloc(struct drm_minor *minor) +{ + struct drm_device *dev = minor->dev; + struct drm_file *file; + int ret; + + file = kzalloc(sizeof(*file), GFP_KERNEL); + if (!file) + return ERR_PTR(-ENOMEM); + + file->pid = get_pid(task_pid(current)); + file->minor = minor; + + /* for compatibility root is always authenticated */ + file->authenticated = capable(CAP_SYS_ADMIN); + file->lock_count = 0; + + INIT_LIST_HEAD(&file->lhead); + INIT_LIST_HEAD(&file->fbs); + mutex_init(&file->fbs_lock); + INIT_LIST_HEAD(&file->blobs); + INIT_LIST_HEAD(&file->pending_event_list); + INIT_LIST_HEAD(&file->event_list); + init_waitqueue_head(&file->event_wait); + file->event_space = 4096; /* set aside 4k for event buffer */ + + mutex_init(&file->event_read_lock); + + if (drm_core_check_feature(dev, DRIVER_GEM)) + drm_gem_open(dev, file); + + if (drm_core_check_feature(dev, DRIVER_SYNCOBJ)) + drm_syncobj_open(file); + + if (drm_core_check_feature(dev, DRIVER_PRIME)) + drm_prime_init_file_private(&file->prime); + + if (dev->driver->open) { + ret = dev->driver->open(dev, file); + if (ret < 0) + goto out_prime_destroy; + } + + if (drm_is_primary_client(file)) { + ret = drm_master_open(file); + if (ret) + goto out_close; + } + + return file; + +out_close: + if (dev->driver->postclose) + dev->driver->postclose(dev, file); +out_prime_destroy: + if (drm_core_check_feature(dev, DRIVER_PRIME)) + drm_prime_destroy_file_private(&file->prime); + if (drm_core_check_feature(dev, DRIVER_SYNCOBJ)) + drm_syncobj_release(file); + if (drm_core_check_feature(dev, DRIVER_GEM)) + drm_gem_release(dev, file); + put_pid(file->pid); + kfree(file); + + return ERR_PTR(ret); +} + +static void drm_events_release(struct drm_file *file_priv) +{ + struct drm_device *dev = file_priv->minor->dev; + struct drm_pending_event *e, *et; + unsigned long flags; + + spin_lock_irqsave(&dev->event_lock, flags); + + /* Unlink pending events */ + list_for_each_entry_safe(e, et, &file_priv->pending_event_list, + pending_link) { + list_del(&e->pending_link); + e->file_priv = NULL; + } + + /* Remove unconsumed events */ + list_for_each_entry_safe(e, et, &file_priv->event_list, link) { + list_del(&e->link); + kfree(e); + } + + spin_unlock_irqrestore(&dev->event_lock, flags); +} + +/** + * drm_file_free - free file context + * @file: context to free, or NULL + * + * This destroys and deallocates a DRM file context previously allocated via + * drm_file_alloc(). The caller must make sure to unlink it from any contexts + * before calling this. + * + * If NULL is passed, this is a no-op. + * + * RETURNS: + * 0 on success, or error code on failure. + */ +void drm_file_free(struct drm_file *file) +{ + struct drm_device *dev; + + if (!file) + return; + + dev = file->minor->dev; + + DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n", + task_pid_nr(current), + (long)old_encode_dev(file->minor->kdev->devt), + dev->open_count); + + if (drm_core_check_feature(dev, DRIVER_LEGACY) && + dev->driver->preclose) + dev->driver->preclose(dev, file); + + if (drm_core_check_feature(dev, DRIVER_LEGACY)) + drm_legacy_lock_release(dev, file->filp); + + if (drm_core_check_feature(dev, DRIVER_HAVE_DMA)) + drm_legacy_reclaim_buffers(dev, file); + + drm_events_release(file); + + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + drm_fb_release(file); + drm_property_destroy_user_blobs(dev, file); + } + + if (drm_core_check_feature(dev, DRIVER_SYNCOBJ)) + drm_syncobj_release(file); + + if (drm_core_check_feature(dev, DRIVER_GEM)) + drm_gem_release(dev, file); + + drm_legacy_ctxbitmap_flush(dev, file); + + if (drm_is_primary_client(file)) + drm_master_release(file); + + if (dev->driver->postclose) + dev->driver->postclose(dev, file); + + if (drm_core_check_feature(dev, DRIVER_PRIME)) + drm_prime_destroy_file_private(&file->prime); + + WARN_ON(!list_empty(&file->event_list)); + + put_pid(file->pid); + kfree(file); +} + static int drm_setup(struct drm_device * dev) { int ret; @@ -196,7 +365,6 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor) { struct drm_device *dev = minor->dev; struct drm_file *priv; - int ret; if (filp->f_flags & O_EXCL) return -EBUSY; /* No exclusive opens */ @@ -207,51 +375,13 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor) DRM_DEBUG("pid = %d, minor = %d\n", task_pid_nr(current), minor->index); - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; + priv = drm_file_alloc(minor); + if (IS_ERR(priv)) + return PTR_ERR(priv); filp->private_data = priv; filp->f_mode |= FMODE_UNSIGNED_OFFSET; priv->filp = filp; - priv->pid = get_pid(task_pid(current)); - priv->minor = minor; - - /* for compatibility root is always authenticated */ - priv->authenticated = capable(CAP_SYS_ADMIN); - priv->lock_count = 0; - - INIT_LIST_HEAD(&priv->lhead); - INIT_LIST_HEAD(&priv->fbs); - mutex_init(&priv->fbs_lock); - INIT_LIST_HEAD(&priv->blobs); - INIT_LIST_HEAD(&priv->pending_event_list); - INIT_LIST_HEAD(&priv->event_list); - init_waitqueue_head(&priv->event_wait); - priv->event_space = 4096; /* set aside 4k for event buffer */ - - mutex_init(&priv->event_read_lock); - - if (drm_core_check_feature(dev, DRIVER_GEM)) - drm_gem_open(dev, priv); - - if (drm_core_check_feature(dev, DRIVER_SYNCOBJ)) - drm_syncobj_open(priv); - - if (drm_core_check_feature(dev, DRIVER_PRIME)) - drm_prime_init_file_private(&priv->prime); - - if (dev->driver->open) { - ret = dev->driver->open(dev, priv); - if (ret < 0) - goto out_prime_destroy; - } - - if (drm_is_primary_client(priv)) { - ret = drm_master_open(priv); - if (ret) - goto out_close; - } mutex_lock(&dev->filelist_mutex); list_add(&priv->lhead, &dev->filelist); @@ -278,45 +408,6 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor) #endif return 0; - -out_close: - if (dev->driver->postclose) - dev->driver->postclose(dev, priv); -out_prime_destroy: - if (drm_core_check_feature(dev, DRIVER_PRIME)) - drm_prime_destroy_file_private(&priv->prime); - if (drm_core_check_feature(dev, DRIVER_SYNCOBJ)) - drm_syncobj_release(priv); - if (drm_core_check_feature(dev, DRIVER_GEM)) - drm_gem_release(dev, priv); - put_pid(priv->pid); - kfree(priv); - filp->private_data = NULL; - return ret; -} - -static void drm_events_release(struct drm_file *file_priv) -{ - struct drm_device *dev = file_priv->minor->dev; - struct drm_pending_event *e, *et; - unsigned long flags; - - spin_lock_irqsave(&dev->event_lock, flags); - - /* Unlink pending events */ - list_for_each_entry_safe(e, et, &file_priv->pending_event_list, - pending_link) { - list_del(&e->pending_link); - e->file_priv = NULL; - } - - /* Remove unconsumed events */ - list_for_each_entry_safe(e, et, &file_priv->event_list, link) { - list_del(&e->link); - kfree(e); - } - - spin_unlock_irqrestore(&dev->event_lock, flags); } static void drm_legacy_dev_reinit(struct drm_device *dev) @@ -383,57 +474,7 @@ int drm_release(struct inode *inode, struct file *filp) list_del(&file_priv->lhead); mutex_unlock(&dev->filelist_mutex); - if (drm_core_check_feature(dev, DRIVER_LEGACY) && - dev->driver->preclose) - dev->driver->preclose(dev, file_priv); - - /* ======================================================== - * Begin inline drm_release - */ - - DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n", - task_pid_nr(current), - (long)old_encode_dev(file_priv->minor->kdev->devt), - dev->open_count); - - if (drm_core_check_feature(dev, DRIVER_LEGACY)) - drm_legacy_lock_release(dev, filp); - - if (drm_core_check_feature(dev, DRIVER_HAVE_DMA)) - drm_legacy_reclaim_buffers(dev, file_priv); - - drm_events_release(file_priv); - - if (drm_core_check_feature(dev, DRIVER_MODESET)) { - drm_fb_release(file_priv); - drm_property_destroy_user_blobs(dev, file_priv); - } - - if (drm_core_check_feature(dev, DRIVER_SYNCOBJ)) - drm_syncobj_release(file_priv); - - if (drm_core_check_feature(dev, DRIVER_GEM)) - drm_gem_release(dev, file_priv); - - drm_legacy_ctxbitmap_flush(dev, file_priv); - - if (drm_is_primary_client(file_priv)) - drm_master_release(file_priv); - - if (dev->driver->postclose) - dev->driver->postclose(dev, file_priv); - - if (drm_core_check_feature(dev, DRIVER_PRIME)) - drm_prime_destroy_file_private(&file_priv->prime); - - WARN_ON(!list_empty(&file_priv->event_list)); - - put_pid(file_priv->pid); - kfree(file_priv); - - /* ======================================================== - * End inline drm_release - */ + drm_file_free(file_priv); if (!--dev->open_count) { drm_lastclose(dev); diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index b72242e93ea47..40179c5fc6b87 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h @@ -26,6 +26,8 @@ /* drm_file.c */ extern struct mutex drm_global_mutex; +struct drm_file *drm_file_alloc(struct drm_minor *minor); +void drm_file_free(struct drm_file *file); void drm_lastclose(struct drm_device *dev); /* drm_pci.c */ -- GitLab From 7eeaeb90a6a5c8dc0de9bbb16a12d474d31d820e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org> Date: Mon, 18 Jun 2018 16:17:29 +0200 Subject: [PATCH 0500/1506] drm/file: Don't set master on in-kernel clients MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It only makes sense for userspace clients. Signed-off-by: Noralf Trønnes <noralf@tronnes.org> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180618141739.48151-3-noralf@tronnes.org --- drivers/gpu/drm/drm_file.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c index c0410b8330436..66bb403dc8abb 100644 --- a/drivers/gpu/drm/drm_file.c +++ b/drivers/gpu/drm/drm_file.c @@ -155,17 +155,8 @@ struct drm_file *drm_file_alloc(struct drm_minor *minor) goto out_prime_destroy; } - if (drm_is_primary_client(file)) { - ret = drm_master_open(file); - if (ret) - goto out_close; - } - return file; -out_close: - if (dev->driver->postclose) - dev->driver->postclose(dev, file); out_prime_destroy: if (drm_core_check_feature(dev, DRIVER_PRIME)) drm_prime_destroy_file_private(&file->prime); @@ -365,6 +356,7 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor) { struct drm_device *dev = minor->dev; struct drm_file *priv; + int ret; if (filp->f_flags & O_EXCL) return -EBUSY; /* No exclusive opens */ @@ -379,6 +371,14 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor) if (IS_ERR(priv)) return PTR_ERR(priv); + if (drm_is_primary_client(priv)) { + ret = drm_master_open(priv); + if (ret) { + drm_file_free(priv); + return ret; + } + } + filp->private_data = priv; filp->f_mode |= FMODE_UNSIGNED_OFFSET; priv->filp = filp; -- GitLab From d30827ce0df4410648c3fbba48681d7aafb19f36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org> Date: Mon, 18 Jun 2018 16:17:30 +0200 Subject: [PATCH 0501/1506] drm: Make ioctls available for in-kernel clients MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make ioctl wrappers for functions that will be used by the in-kernel API. The following functions are touched: - drm_mode_create_dumb_ioctl() - drm_mode_destroy_dumb_ioctl() - drm_mode_addfb() - drm_mode_rmfb() Signed-off-by: Noralf Trønnes <noralf@tronnes.org> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180618141739.48151-4-noralf@tronnes.org --- drivers/gpu/drm/drm_crtc_internal.h | 19 ++++++++++--- drivers/gpu/drm/drm_dumb_buffers.c | 29 +++++++++++++------- drivers/gpu/drm/drm_framebuffer.c | 42 ++++++++++++++++++----------- drivers/gpu/drm/drm_ioctl.c | 4 +-- 4 files changed, 64 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index 34499800932a2..235d40fce8b54 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -65,6 +65,12 @@ int drm_mode_getresources(struct drm_device *dev, /* drm_dumb_buffers.c */ +int drm_mode_create_dumb(struct drm_device *dev, + struct drm_mode_create_dumb *args, + struct drm_file *file_priv); +int drm_mode_destroy_dumb(struct drm_device *dev, u32 handle, + struct drm_file *file_priv); + /* IOCTLs */ int drm_mode_create_dumb_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); @@ -166,14 +172,19 @@ int drm_framebuffer_check_src_coords(uint32_t src_x, uint32_t src_y, const struct drm_framebuffer *fb); void drm_fb_release(struct drm_file *file_priv); +int drm_mode_addfb(struct drm_device *dev, struct drm_mode_fb_cmd *or, + struct drm_file *file_priv); +int drm_mode_rmfb(struct drm_device *dev, u32 fb_id, + struct drm_file *file_priv); + /* IOCTL */ -int drm_mode_addfb(struct drm_device *dev, - void *data, struct drm_file *file_priv); +int drm_mode_addfb_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv); int drm_mode_addfb2(struct drm_device *dev, void *data, struct drm_file *file_priv); -int drm_mode_rmfb(struct drm_device *dev, - void *data, struct drm_file *file_priv); +int drm_mode_rmfb_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv); int drm_mode_getfb(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_mode_dirtyfb_ioctl(struct drm_device *dev, diff --git a/drivers/gpu/drm/drm_dumb_buffers.c b/drivers/gpu/drm/drm_dumb_buffers.c index 39ac15ce47023..eed9687b8698f 100644 --- a/drivers/gpu/drm/drm_dumb_buffers.c +++ b/drivers/gpu/drm/drm_dumb_buffers.c @@ -53,10 +53,10 @@ * a hardware-specific ioctl to allocate suitable buffer objects. */ -int drm_mode_create_dumb_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv) +int drm_mode_create_dumb(struct drm_device *dev, + struct drm_mode_create_dumb *args, + struct drm_file *file_priv) { - struct drm_mode_create_dumb *args = data; u32 cpp, stride, size; if (!dev->driver->dumb_create) @@ -91,6 +91,12 @@ int drm_mode_create_dumb_ioctl(struct drm_device *dev, return dev->driver->dumb_create(file_priv, dev, args); } +int drm_mode_create_dumb_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + return drm_mode_create_dumb(dev, data, file_priv); +} + /** * drm_mode_mmap_dumb_ioctl - create an mmap offset for a dumb backing storage buffer * @dev: DRM device @@ -122,17 +128,22 @@ int drm_mode_mmap_dumb_ioctl(struct drm_device *dev, &args->offset); } -int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv) +int drm_mode_destroy_dumb(struct drm_device *dev, u32 handle, + struct drm_file *file_priv) { - struct drm_mode_destroy_dumb *args = data; - if (!dev->driver->dumb_create) return -ENOSYS; if (dev->driver->dumb_destroy) - return dev->driver->dumb_destroy(file_priv, dev, args->handle); + return dev->driver->dumb_destroy(file_priv, dev, handle); else - return drm_gem_dumb_destroy(file_priv, dev, args->handle); + return drm_gem_dumb_destroy(file_priv, dev, handle); } +int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_destroy_dumb *args = data; + + return drm_mode_destroy_dumb(dev, args->handle, file_priv); +} diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index 46b11e46edbd6..ed90974a452a1 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -95,21 +95,20 @@ int drm_framebuffer_check_src_coords(uint32_t src_x, uint32_t src_y, /** * drm_mode_addfb - add an FB to the graphics configuration * @dev: drm device for the ioctl - * @data: data pointer for the ioctl - * @file_priv: drm file for the ioctl call + * @or: pointer to request structure + * @file_priv: drm file * * Add a new FB to the specified CRTC, given a user request. This is the * original addfb ioctl which only supported RGB formats. * - * Called by the user via ioctl. + * Called by the user via ioctl, or by an in-kernel client. * * Returns: * Zero on success, negative errno on failure. */ -int drm_mode_addfb(struct drm_device *dev, - void *data, struct drm_file *file_priv) +int drm_mode_addfb(struct drm_device *dev, struct drm_mode_fb_cmd *or, + struct drm_file *file_priv) { - struct drm_mode_fb_cmd *or = data; struct drm_mode_fb_cmd2 r = {}; int ret; @@ -134,6 +133,12 @@ int drm_mode_addfb(struct drm_device *dev, return 0; } +int drm_mode_addfb_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + return drm_mode_addfb(dev, data, file_priv); +} + static int fb_plane_width(int width, const struct drm_format_info *format, int plane) { @@ -367,29 +372,28 @@ static void drm_mode_rmfb_work_fn(struct work_struct *w) /** * drm_mode_rmfb - remove an FB from the configuration - * @dev: drm device for the ioctl - * @data: data pointer for the ioctl - * @file_priv: drm file for the ioctl call + * @dev: drm device + * @fb_id: id of framebuffer to remove + * @file_priv: drm file * - * Remove the FB specified by the user. + * Remove the specified FB. * - * Called by the user via ioctl. + * Called by the user via ioctl, or by an in-kernel client. * * Returns: * Zero on success, negative errno on failure. */ -int drm_mode_rmfb(struct drm_device *dev, - void *data, struct drm_file *file_priv) +int drm_mode_rmfb(struct drm_device *dev, u32 fb_id, + struct drm_file *file_priv) { struct drm_framebuffer *fb = NULL; struct drm_framebuffer *fbl = NULL; - uint32_t *id = data; int found = 0; if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; - fb = drm_framebuffer_lookup(dev, file_priv, *id); + fb = drm_framebuffer_lookup(dev, file_priv, fb_id); if (!fb) return -ENOENT; @@ -435,6 +439,14 @@ int drm_mode_rmfb(struct drm_device *dev, return -ENOENT; } +int drm_mode_rmfb_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + uint32_t *fb_id = data; + + return drm_mode_rmfb(dev, *fb_id, file_priv); +} + /** * drm_mode_getfb - get FB info * @dev: drm device for the ioctl diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index fe49fb0356b5a..3c125041a597c 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -644,9 +644,9 @@ static const struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_mode_connector_property_set_ioctl, DRM_MASTER|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb_ioctl, DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB2, drm_mode_addfb2, DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb_ioctl, DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_PAGE_FLIP, drm_mode_page_flip_ioctl, DRM_MASTER|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_DUMB, drm_mode_create_dumb_ioctl, DRM_UNLOCKED), -- GitLab From 8d52e447807b350b98ffb4e64bc2fcc1f181c5be Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Sat, 23 Jun 2018 11:39:51 +0100 Subject: [PATCH 0502/1506] drm/i915: Defer modeset cleanup to a secondary task If we avoid cleaning up the old state immediately in intel_atomic_commit_tail() and defer it to a second task, we can avoid taking heavily contended locks when the caller is ready to procede. Subsequent modesets will wait for the cleanup operation (either directly via the ordered modeset wq or indirectly through the atomic helperr) which keeps the number of inflight cleanup tasks in check. As an example, during reset an immediate modeset is performed to disable the displays before the HW is reset, which must avoid struct_mutex to avoid recursion. Moving the cleanup to a separate task, defers acquiring the struct_mutex to after the GPU is running again, allowing it to complete. Even in a few patches time (optimist!) when we no longer require struct_mutex to unpin the framebuffers, it will still be good practice to minimise the number of contention points along reset. The mutex dependency still exists (as one modeset flushes the other), but in the short term it resolves the deadlock for simple reset cases. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=101600 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20180623103951.23889-1-chris@chris-wilson.co.uk Acked-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch> --- drivers/gpu/drm/i915/intel_display.c | 30 +++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4db576c3e3649..1469a56f6c469 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12555,6 +12555,19 @@ static void intel_atomic_commit_fence_wait(struct intel_atomic_state *intel_stat finish_wait(&dev_priv->gpu_error.wait_queue, &wait_reset); } +static void intel_atomic_cleanup_work(struct work_struct *work) +{ + struct drm_atomic_state *state = + container_of(work, struct drm_atomic_state, commit_work); + struct drm_i915_private *i915 = to_i915(state->dev); + + drm_atomic_helper_cleanup_planes(&i915->drm, state); + drm_atomic_helper_commit_cleanup_done(state); + drm_atomic_state_put(state); + + intel_atomic_helper_free_state(i915); +} + static void intel_atomic_commit_tail(struct drm_atomic_state *state) { struct drm_device *dev = state->dev; @@ -12715,13 +12728,16 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state) intel_display_power_put(dev_priv, POWER_DOMAIN_MODESET); } - drm_atomic_helper_cleanup_planes(dev, state); - - drm_atomic_helper_commit_cleanup_done(state); - - drm_atomic_state_put(state); - - intel_atomic_helper_free_state(dev_priv); + /* + * Defer the cleanup of the old state to a separate worker to not + * impede the current task (userspace for blocking modesets) that + * are executed inline. For out-of-line asynchronous modesets/flips, + * deferring to a new worker seems overkill, but we would place a + * schedule point (cond_resched()) here anyway to keep latencies + * down. + */ + INIT_WORK(&state->commit_work, intel_atomic_cleanup_work); + schedule_work(&state->commit_work); } static void intel_atomic_commit_work(struct work_struct *work) -- GitLab From dd12c6ca5b45fd54e80c1424b11a5a25ad913dbb Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Mon, 25 Jun 2018 11:06:03 +0100 Subject: [PATCH 0503/1506] drm/i915/execlists: Check for ce->state before destroy As we may cancel the ce->state allocation during context pinning (but crucially after we mark ce as operational), that means we may be asked to destroy a nonexistent ce->state. Given the choice in handing a complex error path on pinning, and just ignoring the lack of state in destroy, choice the latter for simplicity. Reported-by: Zhao Yakui <yakui.zhao@intel.com> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180625100604.22598-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_lrc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 10deebe49543b..8f020537a34b7 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1338,9 +1338,11 @@ static void execlists_schedule(struct i915_request *request, static void execlists_context_destroy(struct intel_context *ce) { - GEM_BUG_ON(!ce->state); GEM_BUG_ON(ce->pin_count); + if (!ce->state) + return; + intel_ring_free(ce->ring); __i915_gem_object_release_unless_active(ce->state->obj); } -- GitLab From efe79d48a7debf57ad156a43a9215f8b0c9210d4 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Mon, 25 Jun 2018 11:06:04 +0100 Subject: [PATCH 0504/1506] drm/i915: Context objects can never be active when freed Due to how we only release the pining on the context state on retirement and never track activity on the context vma itself, the object can never be active at the point of release. Replace the conditional transfer of ownership onto an active-reference with an assert that the object is idle. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180625100604.22598-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_lrc.c | 4 +++- drivers/gpu/drm/i915/intel_ringbuffer.c | 7 +++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 8f020537a34b7..46572976c9420 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1344,7 +1344,9 @@ static void execlists_context_destroy(struct intel_context *ce) return; intel_ring_free(ce->ring); - __i915_gem_object_release_unless_active(ce->state->obj); + + GEM_BUG_ON(i915_gem_object_is_active(ce->state->obj)); + i915_gem_object_put(ce->state->obj); } static void execlists_context_unpin(struct intel_context *ce) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 4dae23885006b..d248742b14739 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1167,8 +1167,11 @@ static void intel_ring_context_destroy(struct intel_context *ce) { GEM_BUG_ON(ce->pin_count); - if (ce->state) - __i915_gem_object_release_unless_active(ce->state->obj); + if (!ce->state) + return; + + GEM_BUG_ON(i915_gem_object_is_active(ce->state->obj)); + i915_gem_object_put(ce->state->obj); } static int __context_pin_ppgtt(struct i915_gem_context *ctx) -- GitLab From 86cd90020688ee8b45268e588a05454cbe979cb7 Mon Sep 17 00:00:00 2001 From: John Stultz <john.stultz@linaro.org> Date: Thu, 21 Jun 2018 16:01:16 -0700 Subject: [PATCH 0505/1506] drm: kirin: Remove useless "Scale not support" error message The driver doesn't support scaling, but when an atomic test is done it repeatedly spits out this warning which isn't particularly useful. So just remove the error message. Cc: Xinliang Liu <z.liuxinliang@hisilicon.com> Cc: Rongrong Zou <zourongrong@gmail.com> Cc: Xinwei Kong <kong.kongxinwei@hisilicon.com> Cc: Chen Feng <puck.chen@hisilicon.com> Cc: David Airlie <airlied@linux.ie> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Cc: Peter Griffin <peter.griffin@linaro.org> Cc: dri-devel@lists.freedesktop.org Signed-off-by: John Stultz <john.stultz@linaro.org> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/1529622076-20386-1-git-send-email-john.stultz@linaro.org --- drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c index 2269be91f3e16..bb774202a5a1b 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c @@ -859,7 +859,6 @@ static int ade_plane_atomic_check(struct drm_plane *plane, return PTR_ERR(crtc_state); if (src_w != crtc_w || src_h != crtc_h) { - DRM_ERROR("Scale not support!!!\n"); return -EINVAL; } -- GitLab From 66ddff86f682a635d2beaa1dc90e2a03e83af77e Mon Sep 17 00:00:00 2001 From: Maxime Ripard <maxime.ripard@bootlin.com> Date: Tue, 29 May 2018 11:49:14 +0200 Subject: [PATCH 0506/1506] dt-bindings: panel: Add the Ilitek ILI9881c panel documentation The LHR050H41 from BananaPi is a 1280x700 4-lanes DSI panel based on the ILI9881c from Ilitek. Acked-by: Rob Herring <robh@kernel.org> Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch> Reviewed-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/a348cdd07d3287e8203ee8d840ea279fe10a6204.1527587352.git-series.maxime.ripard@bootlin.com --- .../display/panel/ilitek,ili9881c.txt | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.txt diff --git a/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.txt b/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.txt new file mode 100644 index 0000000000000..4a041acb4e185 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.txt @@ -0,0 +1,20 @@ +Ilitek ILI9881c based MIPI-DSI panels + +Required properties: + - compatible: must be "ilitek,ili9881c" and one of: + * "bananapi,lhr050h41" + - reg: DSI virtual channel used by that screen + - power-supply: phandle to the power regulator + - reset-gpios: a GPIO phandle for the reset pin + +Optional properties: + - backlight: phandle to the backlight used + +Example: +panel@0 { + compatible = "bananapi,lhr050h41", "ilitek,ili9881c"; + reg = <0>; + power-supply = <®_display>; + reset-gpios = <&r_pio 0 5 GPIO_ACTIVE_LOW>; /* PL05 */ + backlight = <&pwm_bl>; +}; -- GitLab From 26aec25593c2ee2e24f9facabcf85abba54bdb37 Mon Sep 17 00:00:00 2001 From: Maxime Ripard <maxime.ripard@bootlin.com> Date: Tue, 29 May 2018 11:49:15 +0200 Subject: [PATCH 0507/1506] drm/panel: Add Ilitek ILI9881c panel driver The LHR050H41 panel is the panel shipped with the BananaPi M2-Magic, and is based on the Ilitek ILI9881c Controller. Add a driver for it, modelled after the other Ilitek controller drivers. Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch> Reviewed-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/acb5453112ab7c7b801cf4f1669e351b391e77e8.1527587352.git-series.maxime.ripard@bootlin.com --- drivers/gpu/drm/panel/Kconfig | 9 + drivers/gpu/drm/panel/Makefile | 1 + drivers/gpu/drm/panel/panel-ilitek-ili9881c.c | 503 ++++++++++++++++++ 3 files changed, 513 insertions(+) create mode 100644 drivers/gpu/drm/panel/panel-ilitek-ili9881c.c diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 25682ff3449a4..6020c30a33b39 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -46,6 +46,15 @@ config DRM_PANEL_ILITEK_IL9322 Say Y here if you want to enable support for Ilitek IL9322 QVGA (320x240) RGB, YUV and ITU-T BT.656 panels. +config DRM_PANEL_ILITEK_ILI9881C + tristate "Ilitek ILI9881C-based panels" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y if you want to enable support for panels based on the + Ilitek ILI9881c controller. + config DRM_PANEL_INNOLUX_P079ZCA tristate "Innolux P079ZCA panel" depends on OF diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index f26efc11d746d..5ccaaa9d13af5 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -3,6 +3,7 @@ obj-$(CONFIG_DRM_PANEL_ARM_VERSATILE) += panel-arm-versatile.o obj-$(CONFIG_DRM_PANEL_LVDS) += panel-lvds.o obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o obj-$(CONFIG_DRM_PANEL_ILITEK_IL9322) += panel-ilitek-ili9322.o +obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9881C) += panel-ilitek-ili9881c.o obj-$(CONFIG_DRM_PANEL_INNOLUX_P079ZCA) += panel-innolux-p079zca.o obj-$(CONFIG_DRM_PANEL_JDI_LT070ME05000) += panel-jdi-lt070me05000.o obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c new file mode 100644 index 0000000000000..e848af235df57 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c @@ -0,0 +1,503 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2017-2018, Bootlin + */ + +#include <linux/backlight.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/errno.h> +#include <linux/fb.h> +#include <linux/kernel.h> +#include <linux/module.h> + +#include <linux/gpio/consumer.h> +#include <linux/regulator/consumer.h> + +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_modes.h> +#include <drm/drm_panel.h> + +#include <video/mipi_display.h> + +struct ili9881c { + struct drm_panel panel; + struct mipi_dsi_device *dsi; + + struct backlight_device *backlight; + struct regulator *power; + struct gpio_desc *reset; +}; + +enum ili9881c_op { + ILI9881C_SWITCH_PAGE, + ILI9881C_COMMAND, +}; + +struct ili9881c_instr { + enum ili9881c_op op; + + union arg { + struct cmd { + u8 cmd; + u8 data; + } cmd; + u8 page; + } arg; +}; + +#define ILI9881C_SWITCH_PAGE_INSTR(_page) \ + { \ + .op = ILI9881C_SWITCH_PAGE, \ + .arg = { \ + .page = (_page), \ + }, \ + } + +#define ILI9881C_COMMAND_INSTR(_cmd, _data) \ + { \ + .op = ILI9881C_COMMAND, \ + .arg = { \ + .cmd = { \ + .cmd = (_cmd), \ + .data = (_data), \ + }, \ + }, \ + } + +static const struct ili9881c_instr ili9881c_init[] = { + ILI9881C_SWITCH_PAGE_INSTR(3), + ILI9881C_COMMAND_INSTR(0x01, 0x00), + ILI9881C_COMMAND_INSTR(0x02, 0x00), + ILI9881C_COMMAND_INSTR(0x03, 0x73), + ILI9881C_COMMAND_INSTR(0x04, 0x03), + ILI9881C_COMMAND_INSTR(0x05, 0x00), + ILI9881C_COMMAND_INSTR(0x06, 0x06), + ILI9881C_COMMAND_INSTR(0x07, 0x06), + ILI9881C_COMMAND_INSTR(0x08, 0x00), + ILI9881C_COMMAND_INSTR(0x09, 0x18), + ILI9881C_COMMAND_INSTR(0x0a, 0x04), + ILI9881C_COMMAND_INSTR(0x0b, 0x00), + ILI9881C_COMMAND_INSTR(0x0c, 0x02), + ILI9881C_COMMAND_INSTR(0x0d, 0x03), + ILI9881C_COMMAND_INSTR(0x0e, 0x00), + ILI9881C_COMMAND_INSTR(0x0f, 0x25), + ILI9881C_COMMAND_INSTR(0x10, 0x25), + ILI9881C_COMMAND_INSTR(0x11, 0x00), + ILI9881C_COMMAND_INSTR(0x12, 0x00), + ILI9881C_COMMAND_INSTR(0x13, 0x00), + ILI9881C_COMMAND_INSTR(0x14, 0x00), + ILI9881C_COMMAND_INSTR(0x15, 0x00), + ILI9881C_COMMAND_INSTR(0x16, 0x0C), + ILI9881C_COMMAND_INSTR(0x17, 0x00), + ILI9881C_COMMAND_INSTR(0x18, 0x00), + ILI9881C_COMMAND_INSTR(0x19, 0x00), + ILI9881C_COMMAND_INSTR(0x1a, 0x00), + ILI9881C_COMMAND_INSTR(0x1b, 0x00), + ILI9881C_COMMAND_INSTR(0x1c, 0x00), + ILI9881C_COMMAND_INSTR(0x1d, 0x00), + ILI9881C_COMMAND_INSTR(0x1e, 0xC0), + ILI9881C_COMMAND_INSTR(0x1f, 0x80), + ILI9881C_COMMAND_INSTR(0x20, 0x04), + ILI9881C_COMMAND_INSTR(0x21, 0x01), + ILI9881C_COMMAND_INSTR(0x22, 0x00), + ILI9881C_COMMAND_INSTR(0x23, 0x00), + ILI9881C_COMMAND_INSTR(0x24, 0x00), + ILI9881C_COMMAND_INSTR(0x25, 0x00), + ILI9881C_COMMAND_INSTR(0x26, 0x00), + ILI9881C_COMMAND_INSTR(0x27, 0x00), + ILI9881C_COMMAND_INSTR(0x28, 0x33), + ILI9881C_COMMAND_INSTR(0x29, 0x03), + ILI9881C_COMMAND_INSTR(0x2a, 0x00), + ILI9881C_COMMAND_INSTR(0x2b, 0x00), + ILI9881C_COMMAND_INSTR(0x2c, 0x00), + ILI9881C_COMMAND_INSTR(0x2d, 0x00), + ILI9881C_COMMAND_INSTR(0x2e, 0x00), + ILI9881C_COMMAND_INSTR(0x2f, 0x00), + ILI9881C_COMMAND_INSTR(0x30, 0x00), + ILI9881C_COMMAND_INSTR(0x31, 0x00), + ILI9881C_COMMAND_INSTR(0x32, 0x00), + ILI9881C_COMMAND_INSTR(0x33, 0x00), + ILI9881C_COMMAND_INSTR(0x34, 0x04), + ILI9881C_COMMAND_INSTR(0x35, 0x00), + ILI9881C_COMMAND_INSTR(0x36, 0x00), + ILI9881C_COMMAND_INSTR(0x37, 0x00), + ILI9881C_COMMAND_INSTR(0x38, 0x3C), + ILI9881C_COMMAND_INSTR(0x39, 0x00), + ILI9881C_COMMAND_INSTR(0x3a, 0x00), + ILI9881C_COMMAND_INSTR(0x3b, 0x00), + ILI9881C_COMMAND_INSTR(0x3c, 0x00), + ILI9881C_COMMAND_INSTR(0x3d, 0x00), + ILI9881C_COMMAND_INSTR(0x3e, 0x00), + ILI9881C_COMMAND_INSTR(0x3f, 0x00), + ILI9881C_COMMAND_INSTR(0x40, 0x00), + ILI9881C_COMMAND_INSTR(0x41, 0x00), + ILI9881C_COMMAND_INSTR(0x42, 0x00), + ILI9881C_COMMAND_INSTR(0x43, 0x00), + ILI9881C_COMMAND_INSTR(0x44, 0x00), + ILI9881C_COMMAND_INSTR(0x50, 0x01), + ILI9881C_COMMAND_INSTR(0x51, 0x23), + ILI9881C_COMMAND_INSTR(0x52, 0x45), + ILI9881C_COMMAND_INSTR(0x53, 0x67), + ILI9881C_COMMAND_INSTR(0x54, 0x89), + ILI9881C_COMMAND_INSTR(0x55, 0xab), + ILI9881C_COMMAND_INSTR(0x56, 0x01), + ILI9881C_COMMAND_INSTR(0x57, 0x23), + ILI9881C_COMMAND_INSTR(0x58, 0x45), + ILI9881C_COMMAND_INSTR(0x59, 0x67), + ILI9881C_COMMAND_INSTR(0x5a, 0x89), + ILI9881C_COMMAND_INSTR(0x5b, 0xab), + ILI9881C_COMMAND_INSTR(0x5c, 0xcd), + ILI9881C_COMMAND_INSTR(0x5d, 0xef), + ILI9881C_COMMAND_INSTR(0x5e, 0x11), + ILI9881C_COMMAND_INSTR(0x5f, 0x02), + ILI9881C_COMMAND_INSTR(0x60, 0x02), + ILI9881C_COMMAND_INSTR(0x61, 0x02), + ILI9881C_COMMAND_INSTR(0x62, 0x02), + ILI9881C_COMMAND_INSTR(0x63, 0x02), + ILI9881C_COMMAND_INSTR(0x64, 0x02), + ILI9881C_COMMAND_INSTR(0x65, 0x02), + ILI9881C_COMMAND_INSTR(0x66, 0x02), + ILI9881C_COMMAND_INSTR(0x67, 0x02), + ILI9881C_COMMAND_INSTR(0x68, 0x02), + ILI9881C_COMMAND_INSTR(0x69, 0x02), + ILI9881C_COMMAND_INSTR(0x6a, 0x0C), + ILI9881C_COMMAND_INSTR(0x6b, 0x02), + ILI9881C_COMMAND_INSTR(0x6c, 0x0F), + ILI9881C_COMMAND_INSTR(0x6d, 0x0E), + ILI9881C_COMMAND_INSTR(0x6e, 0x0D), + ILI9881C_COMMAND_INSTR(0x6f, 0x06), + ILI9881C_COMMAND_INSTR(0x70, 0x07), + ILI9881C_COMMAND_INSTR(0x71, 0x02), + ILI9881C_COMMAND_INSTR(0x72, 0x02), + ILI9881C_COMMAND_INSTR(0x73, 0x02), + ILI9881C_COMMAND_INSTR(0x74, 0x02), + ILI9881C_COMMAND_INSTR(0x75, 0x02), + ILI9881C_COMMAND_INSTR(0x76, 0x02), + ILI9881C_COMMAND_INSTR(0x77, 0x02), + ILI9881C_COMMAND_INSTR(0x78, 0x02), + ILI9881C_COMMAND_INSTR(0x79, 0x02), + ILI9881C_COMMAND_INSTR(0x7a, 0x02), + ILI9881C_COMMAND_INSTR(0x7b, 0x02), + ILI9881C_COMMAND_INSTR(0x7c, 0x02), + ILI9881C_COMMAND_INSTR(0x7d, 0x02), + ILI9881C_COMMAND_INSTR(0x7e, 0x02), + ILI9881C_COMMAND_INSTR(0x7f, 0x02), + ILI9881C_COMMAND_INSTR(0x80, 0x0C), + ILI9881C_COMMAND_INSTR(0x81, 0x02), + ILI9881C_COMMAND_INSTR(0x82, 0x0F), + ILI9881C_COMMAND_INSTR(0x83, 0x0E), + ILI9881C_COMMAND_INSTR(0x84, 0x0D), + ILI9881C_COMMAND_INSTR(0x85, 0x06), + ILI9881C_COMMAND_INSTR(0x86, 0x07), + ILI9881C_COMMAND_INSTR(0x87, 0x02), + ILI9881C_COMMAND_INSTR(0x88, 0x02), + ILI9881C_COMMAND_INSTR(0x89, 0x02), + ILI9881C_COMMAND_INSTR(0x8A, 0x02), + ILI9881C_SWITCH_PAGE_INSTR(4), + ILI9881C_COMMAND_INSTR(0x6C, 0x15), + ILI9881C_COMMAND_INSTR(0x6E, 0x22), + ILI9881C_COMMAND_INSTR(0x6F, 0x33), + ILI9881C_COMMAND_INSTR(0x3A, 0xA4), + ILI9881C_COMMAND_INSTR(0x8D, 0x0D), + ILI9881C_COMMAND_INSTR(0x87, 0xBA), + ILI9881C_COMMAND_INSTR(0x26, 0x76), + ILI9881C_COMMAND_INSTR(0xB2, 0xD1), + ILI9881C_SWITCH_PAGE_INSTR(1), + ILI9881C_COMMAND_INSTR(0x22, 0x0A), + ILI9881C_COMMAND_INSTR(0x53, 0xDC), + ILI9881C_COMMAND_INSTR(0x55, 0xA7), + ILI9881C_COMMAND_INSTR(0x50, 0x78), + ILI9881C_COMMAND_INSTR(0x51, 0x78), + ILI9881C_COMMAND_INSTR(0x31, 0x02), + ILI9881C_COMMAND_INSTR(0x60, 0x14), + ILI9881C_COMMAND_INSTR(0xA0, 0x2A), + ILI9881C_COMMAND_INSTR(0xA1, 0x39), + ILI9881C_COMMAND_INSTR(0xA2, 0x46), + ILI9881C_COMMAND_INSTR(0xA3, 0x0e), + ILI9881C_COMMAND_INSTR(0xA4, 0x12), + ILI9881C_COMMAND_INSTR(0xA5, 0x25), + ILI9881C_COMMAND_INSTR(0xA6, 0x19), + ILI9881C_COMMAND_INSTR(0xA7, 0x1d), + ILI9881C_COMMAND_INSTR(0xA8, 0xa6), + ILI9881C_COMMAND_INSTR(0xA9, 0x1C), + ILI9881C_COMMAND_INSTR(0xAA, 0x29), + ILI9881C_COMMAND_INSTR(0xAB, 0x85), + ILI9881C_COMMAND_INSTR(0xAC, 0x1C), + ILI9881C_COMMAND_INSTR(0xAD, 0x1B), + ILI9881C_COMMAND_INSTR(0xAE, 0x51), + ILI9881C_COMMAND_INSTR(0xAF, 0x22), + ILI9881C_COMMAND_INSTR(0xB0, 0x2d), + ILI9881C_COMMAND_INSTR(0xB1, 0x4f), + ILI9881C_COMMAND_INSTR(0xB2, 0x59), + ILI9881C_COMMAND_INSTR(0xB3, 0x3F), + ILI9881C_COMMAND_INSTR(0xC0, 0x2A), + ILI9881C_COMMAND_INSTR(0xC1, 0x3a), + ILI9881C_COMMAND_INSTR(0xC2, 0x45), + ILI9881C_COMMAND_INSTR(0xC3, 0x0e), + ILI9881C_COMMAND_INSTR(0xC4, 0x11), + ILI9881C_COMMAND_INSTR(0xC5, 0x24), + ILI9881C_COMMAND_INSTR(0xC6, 0x1a), + ILI9881C_COMMAND_INSTR(0xC7, 0x1c), + ILI9881C_COMMAND_INSTR(0xC8, 0xaa), + ILI9881C_COMMAND_INSTR(0xC9, 0x1C), + ILI9881C_COMMAND_INSTR(0xCA, 0x29), + ILI9881C_COMMAND_INSTR(0xCB, 0x96), + ILI9881C_COMMAND_INSTR(0xCC, 0x1C), + ILI9881C_COMMAND_INSTR(0xCD, 0x1B), + ILI9881C_COMMAND_INSTR(0xCE, 0x51), + ILI9881C_COMMAND_INSTR(0xCF, 0x22), + ILI9881C_COMMAND_INSTR(0xD0, 0x2b), + ILI9881C_COMMAND_INSTR(0xD1, 0x4b), + ILI9881C_COMMAND_INSTR(0xD2, 0x59), + ILI9881C_COMMAND_INSTR(0xD3, 0x3F), +}; + +static inline struct ili9881c *panel_to_ili9881c(struct drm_panel *panel) +{ + return container_of(panel, struct ili9881c, panel); +} + +/* + * The panel seems to accept some private DCS commands that map + * directly to registers. + * + * It is organised by page, with each page having its own set of + * registers, and the first page looks like it's holding the standard + * DCS commands. + * + * So before any attempt at sending a command or data, we have to be + * sure if we're in the right page or not. + */ +static int ili9881c_switch_page(struct ili9881c *ctx, u8 page) +{ + u8 buf[4] = { 0xff, 0x98, 0x81, page }; + int ret; + + ret = mipi_dsi_dcs_write_buffer(ctx->dsi, buf, sizeof(buf)); + if (ret < 0) + return ret; + + return 0; +} + +static int ili9881c_send_cmd_data(struct ili9881c *ctx, u8 cmd, u8 data) +{ + u8 buf[2] = { cmd, data }; + int ret; + + ret = mipi_dsi_dcs_write_buffer(ctx->dsi, buf, sizeof(buf)); + if (ret < 0) + return ret; + + return 0; +} + +static int ili9881c_prepare(struct drm_panel *panel) +{ + struct ili9881c *ctx = panel_to_ili9881c(panel); + unsigned int i; + int ret; + + /* Power the panel */ + ret = regulator_enable(ctx->power); + if (ret) + return ret; + msleep(5); + + /* And reset it */ + gpiod_set_value(ctx->reset, 1); + msleep(20); + + gpiod_set_value(ctx->reset, 0); + msleep(20); + + for (i = 0; i < ARRAY_SIZE(ili9881c_init); i++) { + const struct ili9881c_instr *instr = &ili9881c_init[i]; + + if (instr->op == ILI9881C_SWITCH_PAGE) + ret = ili9881c_switch_page(ctx, instr->arg.page); + else if (instr->op == ILI9881C_COMMAND) + ret = ili9881c_send_cmd_data(ctx, instr->arg.cmd.cmd, + instr->arg.cmd.data); + + if (ret) + return ret; + } + + ret = ili9881c_switch_page(ctx, 0); + if (ret) + return ret; + + ret = mipi_dsi_dcs_set_tear_on(ctx->dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK); + if (ret) + return ret; + + mipi_dsi_dcs_exit_sleep_mode(ctx->dsi); + if (ret) + return ret; + + return 0; +} + +static int ili9881c_enable(struct drm_panel *panel) +{ + struct ili9881c *ctx = panel_to_ili9881c(panel); + + msleep(120); + + mipi_dsi_dcs_set_display_on(ctx->dsi); + backlight_enable(ctx->backlight); + + return 0; +} + +static int ili9881c_disable(struct drm_panel *panel) +{ + struct ili9881c *ctx = panel_to_ili9881c(panel); + + backlight_disable(ctx->backlight); + return mipi_dsi_dcs_set_display_off(ctx->dsi); +} + +static int ili9881c_unprepare(struct drm_panel *panel) +{ + struct ili9881c *ctx = panel_to_ili9881c(panel); + + mipi_dsi_dcs_enter_sleep_mode(ctx->dsi); + regulator_disable(ctx->power); + gpiod_set_value(ctx->reset, 1); + + return 0; +} + +static const struct drm_display_mode bananapi_default_mode = { + .clock = 62000, + .vrefresh = 60, + + .hdisplay = 720, + .hsync_start = 720 + 10, + .hsync_end = 720 + 10 + 20, + .htotal = 720 + 10 + 20 + 30, + + .vdisplay = 1280, + .vsync_start = 1280 + 10, + .vsync_end = 1280 + 10 + 10, + .vtotal = 1280 + 10 + 10 + 20, +}; + +static int ili9881c_get_modes(struct drm_panel *panel) +{ + struct drm_connector *connector = panel->connector; + struct ili9881c *ctx = panel_to_ili9881c(panel); + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(panel->drm, &bananapi_default_mode); + if (!mode) { + dev_err(&ctx->dsi->dev, "failed to add mode %ux%ux@%u\n", + bananapi_default_mode.hdisplay, + bananapi_default_mode.vdisplay, + bananapi_default_mode.vrefresh); + return -ENOMEM; + } + + drm_mode_set_name(mode); + + mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; + drm_mode_probed_add(connector, mode); + + panel->connector->display_info.width_mm = 62; + panel->connector->display_info.height_mm = 110; + + return 1; +} + +static const struct drm_panel_funcs ili9881c_funcs = { + .prepare = ili9881c_prepare, + .unprepare = ili9881c_unprepare, + .enable = ili9881c_enable, + .disable = ili9881c_disable, + .get_modes = ili9881c_get_modes, +}; + +static int ili9881c_dsi_probe(struct mipi_dsi_device *dsi) +{ + struct device_node *np; + struct ili9881c *ctx; + int ret; + + ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + mipi_dsi_set_drvdata(dsi, ctx); + ctx->dsi = dsi; + + drm_panel_init(&ctx->panel); + ctx->panel.dev = &dsi->dev; + ctx->panel.funcs = &ili9881c_funcs; + + ctx->power = devm_regulator_get(&dsi->dev, "power"); + if (IS_ERR(ctx->power)) { + dev_err(&dsi->dev, "Couldn't get our power regulator\n"); + return PTR_ERR(ctx->power); + } + + ctx->reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(ctx->reset)) { + dev_err(&dsi->dev, "Couldn't get our reset GPIO\n"); + return PTR_ERR(ctx->reset); + } + + np = of_parse_phandle(dsi->dev.of_node, "backlight", 0); + if (np) { + ctx->backlight = of_find_backlight_by_node(np); + of_node_put(np); + + if (!ctx->backlight) + return -EPROBE_DEFER; + } + + ret = drm_panel_add(&ctx->panel); + if (ret < 0) + return ret; + + dsi->mode_flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->lanes = 4; + + return mipi_dsi_attach(dsi); +} + +static int ili9881c_dsi_remove(struct mipi_dsi_device *dsi) +{ + struct ili9881c *ctx = mipi_dsi_get_drvdata(dsi); + + mipi_dsi_detach(dsi); + drm_panel_remove(&ctx->panel); + + if (ctx->backlight) + put_device(&ctx->backlight->dev); + + return 0; +} + +static const struct of_device_id ili9881c_of_match[] = { + { .compatible = "bananapi,lhr050h41" }, + { } +}; +MODULE_DEVICE_TABLE(of, ili9881c_of_match); + +static struct mipi_dsi_driver ili9881c_dsi_driver = { + .probe = ili9881c_dsi_probe, + .remove = ili9881c_dsi_remove, + .driver = { + .name = "ili9881c-dsi", + .of_match_table = ili9881c_of_match, + }, +}; +module_mipi_dsi_driver(ili9881c_dsi_driver); + +MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>"); +MODULE_DESCRIPTION("Ilitek ILI9881C Controller Driver"); +MODULE_LICENSE("GPL v2"); -- GitLab From a63d3bd230772b307c6595469e615d44a1dacdab Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann <contact@tzimmermann.org> Date: Mon, 25 Jun 2018 17:21:48 +0200 Subject: [PATCH 0508/1506] drm/gma500: Replace drm_gem_object_unreference_unlocked with put function This patch unifies the naming of DRM functions for reference counting of struct drm_gem_object. The resulting code is more aligned with the rest of the Linux kernel interfaces. Signed-off-by: Thomas Zimmermann <contact@tzimmermann.org> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180625152148.29555-1-contact@tzimmermann.org --- drivers/gpu/drm/gma500/framebuffer.c | 2 +- drivers/gpu/drm/gma500/gem.c | 2 +- drivers/gpu/drm/gma500/gma_display.c | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c index 8fa4ef192c1eb..2f00a37684a22 100644 --- a/drivers/gpu/drm/gma500/framebuffer.c +++ b/drivers/gpu/drm/gma500/framebuffer.c @@ -517,7 +517,7 @@ static int psb_fbdev_destroy(struct drm_device *dev, struct psb_fbdev *fbdev) drm_framebuffer_cleanup(&psbfb->base); if (psbfb->base.obj[0]) - drm_gem_object_unreference_unlocked(psbfb->base.obj[0]); + drm_gem_object_put_unlocked(psbfb->base.obj[0]); return 0; } diff --git a/drivers/gpu/drm/gma500/gem.c b/drivers/gpu/drm/gma500/gem.c index 131239759a75a..913bf4c256faf 100644 --- a/drivers/gpu/drm/gma500/gem.c +++ b/drivers/gpu/drm/gma500/gem.c @@ -93,7 +93,7 @@ int psb_gem_create(struct drm_file *file, struct drm_device *dev, u64 size, return ret; } /* We have the initial and handle reference but need only one now */ - drm_gem_object_unreference_unlocked(&r->gem); + drm_gem_object_put_unlocked(&r->gem); *handlep = handle; return 0; } diff --git a/drivers/gpu/drm/gma500/gma_display.c b/drivers/gpu/drm/gma500/gma_display.c index c8f071c47dafa..015dc9f9348de 100644 --- a/drivers/gpu/drm/gma500/gma_display.c +++ b/drivers/gpu/drm/gma500/gma_display.c @@ -353,7 +353,7 @@ int gma_crtc_cursor_set(struct drm_crtc *crtc, gt = container_of(gma_crtc->cursor_obj, struct gtt_range, gem); psb_gtt_unpin(gt); - drm_gem_object_unreference_unlocked(gma_crtc->cursor_obj); + drm_gem_object_put_unlocked(gma_crtc->cursor_obj); gma_crtc->cursor_obj = NULL; } return 0; @@ -429,7 +429,7 @@ int gma_crtc_cursor_set(struct drm_crtc *crtc, if (gma_crtc->cursor_obj) { gt = container_of(gma_crtc->cursor_obj, struct gtt_range, gem); psb_gtt_unpin(gt); - drm_gem_object_unreference_unlocked(gma_crtc->cursor_obj); + drm_gem_object_put_unlocked(gma_crtc->cursor_obj); } gma_crtc->cursor_obj = obj; @@ -437,7 +437,7 @@ int gma_crtc_cursor_set(struct drm_crtc *crtc, return ret; unref_cursor: - drm_gem_object_unreference_unlocked(obj); + drm_gem_object_put_unlocked(obj); return ret; } -- GitLab From 525280552b21722d2dfb48a7020dcd56f9e2023c Mon Sep 17 00:00:00 2001 From: Imre Deak <imre.deak@intel.com> Date: Thu, 21 Jun 2018 21:44:49 +0300 Subject: [PATCH 0509/1506] drm/i915/ddi: Get AUX power domain for DP main link too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So far we got an AUX power domain reference only for the duration of DP AUX transfers. However, the following suggests that we also need these for main link functionality: - The specification doesn't state whether it's needed or not for main link functionality, but suggests that these power wells need to be enabled already during display core initialization (Sequences to Initialize Display). - For PSR we need to keep the AUX power well enabled. - On ICL combo PHY ports (non-TC) the AUX power well is needed for link training too: while the port is enabled with a DP link training test pattern trying to toggle the AUX power well will time out. - On ICL MG PHY ports (TC) the AUX power well is needed also for main link functionality (both in DP and HDMI modes). - Windows enables these power wells both for main and AUX lane functionality. Based on the above take an AUX power reference for main link functionality too. This makes a difference only on GEN10+ (GLK+) platforms, where we have separate port specific AUX power wells. For PSR we still need to distinguish between port A and the other ports, since on port A DC states must stay enabled for main link functionality, but DC states must be disabled for driver initiated AUX transfers. So re-use the corresponding helper from intel_psr.c. Since we take now a reference for main link functionality on all DP ports we can forgo taking the separate power ref for PSR functionality. v2: - Make sure DC states stay enabled when taking the ref on port A. (Ville) v3: (Ville) - Fix comment about logic for encoders without a crtc state and add FIXME note for a simplification to avoid calling get_power_domains in such cases. - Use intel_crtc_has_dp_encoder() instead !intel_crtc_has_type(HDMI). Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Cc: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Cc: Paulo Zanoni <paulo.r.zanoni@intel.com> Signed-off-by: Imre Deak <imre.deak@intel.com> [Clarified code comments in intel_ddi_main_link_aux_domain() and intel_ddi_get_power_domains() (Imre)] Reviewed-by: José Roberto de Souza <jose.souza@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180621184449.26634-1-imre.deak@intel.com --- drivers/gpu/drm/i915/intel_ddi.c | 54 +++++++++++++++++++++++-- drivers/gpu/drm/i915/intel_display.c | 12 +++++- drivers/gpu/drm/i915/intel_drv.h | 3 +- drivers/gpu/drm/i915/intel_psr.c | 41 ------------------- drivers/gpu/drm/i915/intel_runtime_pm.c | 1 + 5 files changed, 64 insertions(+), 47 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 044fe1fb98727..0319825b725ba 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1983,15 +1983,55 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder, return ret; } -static u64 intel_ddi_get_power_domains(struct intel_encoder *encoder) +static inline enum intel_display_power_domain +intel_ddi_main_link_aux_domain(struct intel_dp *intel_dp) +{ + /* CNL HW requires corresponding AUX IOs to be powered up for PSR with + * DC states enabled at the same time, while for driver initiated AUX + * transfers we need the same AUX IOs to be powered but with DC states + * disabled. Accordingly use the AUX power domain here which leaves DC + * states enabled. + * However, for non-A AUX ports the corresponding non-EDP transcoders + * would have already enabled power well 2 and DC_OFF. This means we can + * acquire a wider POWER_DOMAIN_AUX_{B,C,D,F} reference instead of a + * specific AUX_IO reference without powering up any extra wells. + * Note that PSR is enabled only on Port A even though this function + * returns the correct domain for other ports too. + */ + return intel_dp->aux_ch == AUX_CH_A ? POWER_DOMAIN_AUX_IO_A : + intel_dp->aux_power_domain; +} + +static u64 intel_ddi_get_power_domains(struct intel_encoder *encoder, + struct intel_crtc_state *crtc_state) { struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base); enum pipe pipe; + u64 domains; - if (intel_ddi_get_hw_state(encoder, &pipe)) - return BIT_ULL(dig_port->ddi_io_power_domain); + if (!intel_ddi_get_hw_state(encoder, &pipe)) + return 0; - return 0; + domains = BIT_ULL(dig_port->ddi_io_power_domain); + if (!crtc_state) + return domains; + + /* + * TODO: Add support for MST encoders. Atm, the following should never + * happen since this function will be called only for the primary + * encoder which doesn't have its own pipe/crtc_state. + */ + if (WARN_ON(intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST))) + return domains; + + /* AUX power is only needed for (e)DP mode, not for HDMI. */ + if (intel_crtc_has_dp_encoder(crtc_state)) { + struct intel_dp *intel_dp = &dig_port->dp; + + domains |= BIT_ULL(intel_ddi_main_link_aux_domain(intel_dp)); + } + + return domains; } void intel_ddi_enable_pipe_clock(const struct intel_crtc_state *crtc_state) @@ -2631,6 +2671,9 @@ static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder, WARN_ON(is_mst && (port == PORT_A || port == PORT_E)); + intel_display_power_get(dev_priv, + intel_ddi_main_link_aux_domain(intel_dp)); + intel_dp_set_link_params(intel_dp, crtc_state->port_clock, crtc_state->lane_count, is_mst); @@ -2775,6 +2818,9 @@ static void intel_ddi_post_disable_dp(struct intel_encoder *encoder, intel_display_power_put(dev_priv, dig_port->ddi_io_power_domain); intel_ddi_clk_disable(encoder); + + intel_display_power_put(dev_priv, + intel_ddi_main_link_aux_domain(intel_dp)); } static void intel_ddi_post_disable_hdmi(struct intel_encoder *encoder, diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1469a56f6c469..0db23292eb359 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -15661,11 +15661,21 @@ get_encoder_power_domains(struct drm_i915_private *dev_priv) for_each_intel_encoder(&dev_priv->drm, encoder) { u64 get_domains; enum intel_display_power_domain domain; + struct intel_crtc_state *crtc_state; if (!encoder->get_power_domains) continue; - get_domains = encoder->get_power_domains(encoder); + /* + * For MST and inactive encoders we don't have a crtc state. + * FIXME: no need to call get_power_domains in such cases, it + * will always return 0. + */ + crtc_state = encoder->base.crtc ? + to_intel_crtc_state(encoder->base.crtc->state) : + NULL; + + get_domains = encoder->get_power_domains(encoder, crtc_state); for_each_power_domain(domain, get_domains) intel_display_power_get(dev_priv, domain); } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 9e0a8cc485211..0be45b75cca21 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -254,7 +254,8 @@ struct intel_encoder { struct intel_crtc_state *pipe_config); /* Returns a mask of power domains that need to be referenced as part * of the hardware state readout code. */ - u64 (*get_power_domains)(struct intel_encoder *encoder); + u64 (*get_power_domains)(struct intel_encoder *encoder, + struct intel_crtc_state *crtc_state); /* * Called during system suspend after all pending requests for the * encoder are flushed (for example for DP AUX transactions) and diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index aea81ace854b3..f7ae7e33f453d 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -56,43 +56,6 @@ #include "intel_drv.h" #include "i915_drv.h" -static inline enum intel_display_power_domain -psr_aux_domain(struct intel_dp *intel_dp) -{ - /* CNL HW requires corresponding AUX IOs to be powered up for PSR. - * However, for non-A AUX ports the corresponding non-EDP transcoders - * would have already enabled power well 2 and DC_OFF. This means we can - * acquire a wider POWER_DOMAIN_AUX_{B,C,D,F} reference instead of a - * specific AUX_IO reference without powering up any extra wells. - * Note that PSR is enabled only on Port A even though this function - * returns the correct domain for other ports too. - */ - return intel_dp->aux_ch == AUX_CH_A ? POWER_DOMAIN_AUX_IO_A : - intel_dp->aux_power_domain; -} - -static void psr_aux_io_power_get(struct intel_dp *intel_dp) -{ - struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); - struct drm_i915_private *dev_priv = to_i915(intel_dig_port->base.base.dev); - - if (INTEL_GEN(dev_priv) < 10) - return; - - intel_display_power_get(dev_priv, psr_aux_domain(intel_dp)); -} - -static void psr_aux_io_power_put(struct intel_dp *intel_dp) -{ - struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); - struct drm_i915_private *dev_priv = to_i915(intel_dig_port->base.base.dev); - - if (INTEL_GEN(dev_priv) < 10) - return; - - intel_display_power_put(dev_priv, psr_aux_domain(intel_dp)); -} - void intel_psr_irq_control(struct drm_i915_private *dev_priv, bool debug) { u32 debug_mask, mask; @@ -595,8 +558,6 @@ static void hsw_psr_enable_source(struct intel_dp *intel_dp, struct drm_i915_private *dev_priv = to_i915(dev); enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; - psr_aux_io_power_get(intel_dp); - /* Only HSW and BDW have PSR AUX registers that need to be setup. SKL+ * use hardcoded values PSR AUX transactions */ @@ -717,8 +678,6 @@ static void hsw_psr_disable(struct intel_dp *intel_dp, else WARN_ON(I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE); } - - psr_aux_io_power_put(intel_dp); } /** diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index de3a81034f779..2969787201ef8 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -1824,6 +1824,7 @@ void intel_display_power_put(struct drm_i915_private *dev_priv, BIT_ULL(POWER_DOMAIN_INIT)) #define GLK_DISPLAY_AUX_A_POWER_DOMAINS ( \ BIT_ULL(POWER_DOMAIN_AUX_A) | \ + BIT_ULL(POWER_DOMAIN_AUX_IO_A) | \ BIT_ULL(POWER_DOMAIN_INIT)) #define GLK_DISPLAY_AUX_B_POWER_DOMAINS ( \ BIT_ULL(POWER_DOMAIN_AUX_B) | \ -- GitLab From 80c18ba11a7a84cb97e39e5c9b6cdeee9f3c0728 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" <gustavo@embeddedor.com> Date: Mon, 25 Jun 2018 07:18:44 -0500 Subject: [PATCH 0510/1506] drm/gma500: Fix potential NULL pointer dereference MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fb is being dereferenced before it is null checked, hence there is a potential null pointer dereference. Fix this by moving the pointer dereference after fb has been properly null checked at line 74: if (!fb) Addresses-Coverity-ID: 1470169 ("Dereference before null check") Signed-off-by: Gustavo A. R. Silva <gustavo@embeddedor.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180625121844.GA12466@embeddedor.com --- drivers/gpu/drm/gma500/gma_display.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/gma500/gma_display.c b/drivers/gpu/drm/gma500/gma_display.c index 015dc9f9348de..08f17f85b801d 100644 --- a/drivers/gpu/drm/gma500/gma_display.c +++ b/drivers/gpu/drm/gma500/gma_display.c @@ -60,7 +60,7 @@ int gma_pipe_set_base(struct drm_crtc *crtc, int x, int y, struct drm_psb_private *dev_priv = dev->dev_private; struct gma_crtc *gma_crtc = to_gma_crtc(crtc); struct drm_framebuffer *fb = crtc->primary->fb; - struct gtt_range *gtt = to_gtt_range(fb->obj[0]); + struct gtt_range *gtt; int pipe = gma_crtc->pipe; const struct psb_offset *map = &dev_priv->regmap[pipe]; unsigned long start, offset; @@ -76,6 +76,8 @@ int gma_pipe_set_base(struct drm_crtc *crtc, int x, int y, goto gma_pipe_cleaner; } + gtt = to_gtt_range(fb->obj[0]); + /* We are displaying this buffer, make sure it is actually loaded into the GTT */ ret = psb_gtt_pin(gtt); -- GitLab From 5ae79cf18dc1a97d8d0ab420fc4d3f8674bcf0e8 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" <gustavo@embeddedor.com> Date: Mon, 25 Jun 2018 07:33:55 -0500 Subject: [PATCH 0511/1506] drm/gma500: Fix compile warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the following compile warning: warning: unused variable ‘psbfb’ [-Wunused-variable] struct psb_framebuffer *psbfb = to_psb_fb(fb); Fixes: c7cbed560ce2 ("drm/gma500: Fix Medfield for drm_framebuffer move") Signed-off-by: Gustavo A. R. Silva <gustavo@embeddedor.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180625123355.GA16757@embeddedor.com --- drivers/gpu/drm/gma500/mdfld_intel_display.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/gma500/mdfld_intel_display.c b/drivers/gpu/drm/gma500/mdfld_intel_display.c index 881d613cc2e5e..2b9fa0163dea7 100644 --- a/drivers/gpu/drm/gma500/mdfld_intel_display.c +++ b/drivers/gpu/drm/gma500/mdfld_intel_display.c @@ -167,7 +167,6 @@ static int mdfld__intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, struct drm_psb_private *dev_priv = dev->dev_private; struct drm_framebuffer *fb = crtc->primary->fb; struct gma_crtc *gma_crtc = to_gma_crtc(crtc); - struct psb_framebuffer *psbfb = to_psb_fb(fb); int pipe = gma_crtc->pipe; const struct psb_offset *map = &dev_priv->regmap[pipe]; unsigned long start, offset; -- GitLab From cf5d862db2e301b8e487f42f99c5cf6f5228ddae Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi <rodrigo.vivi@intel.com> Date: Mon, 25 Jun 2018 22:25:36 -0700 Subject: [PATCH 0512/1506] drm/i915/psr: Kill useless function pointers. At some point we introduced the function pointers on PSR code to help with VLV/CHV separation logic because it had a different HW implementation from PSR. Since all converged to HSW PSR and we dropped the VLV/CHV support, let's also kill the useless function pointers and leave the code cleaner. Cc: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180626052536.15137-1-rodrigo.vivi@intel.com --- drivers/gpu/drm/i915/i915_drv.h | 8 ----- drivers/gpu/drm/i915/intel_psr.c | 55 +++++++++++--------------------- 2 files changed, 18 insertions(+), 45 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6f08ab310118a..2b684f431c600 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -631,14 +631,6 @@ struct i915_psr { bool debug; ktime_t last_entry_attempt; ktime_t last_exit; - - void (*enable_source)(struct intel_dp *, - const struct intel_crtc_state *); - void (*disable_source)(struct intel_dp *, - const struct intel_crtc_state *); - void (*enable_sink)(struct intel_dp *); - void (*activate)(struct intel_dp *); - void (*setup_vsc)(struct intel_dp *, const struct intel_crtc_state *); }; enum intel_pch { diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index f7ae7e33f453d..ccaee4a748f25 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -241,8 +241,8 @@ void intel_psr_init_dpcd(struct intel_dp *intel_dp) } } -static void hsw_psr_setup_vsc(struct intel_dp *intel_dp, - const struct intel_crtc_state *crtc_state) +static void intel_psr_setup_vsc(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state) { struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); struct drm_i915_private *dev_priv = to_i915(intel_dig_port->base.base.dev); @@ -307,7 +307,7 @@ static void hsw_psr_setup_aux(struct intel_dp *intel_dp) I915_WRITE(EDP_PSR_AUX_CTL, aux_ctl); } -static void hsw_psr_enable_sink(struct intel_dp *intel_dp) +static void intel_psr_enable_sink(struct intel_dp *intel_dp) { struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct drm_device *dev = dig_port->base.base.dev; @@ -419,24 +419,6 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp) I915_WRITE(EDP_PSR2_CTL, val); } -static void hsw_psr_activate(struct intel_dp *intel_dp) -{ - struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); - struct drm_device *dev = dig_port->base.base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); - - /* On HSW+ after we enable PSR on source it will activate it - * as soon as it match configure idle_frame count. So - * we just actually enable it here on activation time. - */ - - /* psr1 and psr2 are mutually exclusive.*/ - if (dev_priv->psr.psr2_enabled) - hsw_activate_psr2(intel_dp); - else - hsw_activate_psr1(intel_dp); -} - static bool intel_psr2_config_valid(struct intel_dp *intel_dp, struct intel_crtc_state *crtc_state) { @@ -546,12 +528,17 @@ static void intel_psr_activate(struct intel_dp *intel_dp) WARN_ON(dev_priv->psr.active); lockdep_assert_held(&dev_priv->psr.lock); - dev_priv->psr.activate(intel_dp); + /* psr1 and psr2 are mutually exclusive.*/ + if (dev_priv->psr.psr2_enabled) + hsw_activate_psr2(intel_dp); + else + hsw_activate_psr1(intel_dp); + dev_priv->psr.active = true; } -static void hsw_psr_enable_source(struct intel_dp *intel_dp, - const struct intel_crtc_state *crtc_state) +static void intel_psr_enable_source(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state) { struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct drm_device *dev = dig_port->base.base.dev; @@ -627,9 +614,9 @@ void intel_psr_enable(struct intel_dp *intel_dp, dev_priv->psr.psr2_enabled = crtc_state->has_psr2; dev_priv->psr.busy_frontbuffer_bits = 0; - dev_priv->psr.setup_vsc(intel_dp, crtc_state); - dev_priv->psr.enable_sink(intel_dp); - dev_priv->psr.enable_source(intel_dp, crtc_state); + intel_psr_setup_vsc(intel_dp, crtc_state); + intel_psr_enable_sink(intel_dp); + intel_psr_enable_source(intel_dp, crtc_state); dev_priv->psr.enabled = intel_dp; intel_psr_activate(intel_dp); @@ -638,8 +625,9 @@ void intel_psr_enable(struct intel_dp *intel_dp, mutex_unlock(&dev_priv->psr.lock); } -static void hsw_psr_disable(struct intel_dp *intel_dp, - const struct intel_crtc_state *old_crtc_state) +static void +intel_psr_disable_source(struct intel_dp *intel_dp, + const struct intel_crtc_state *old_crtc_state) { struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); struct drm_device *dev = intel_dig_port->base.base.dev; @@ -706,7 +694,7 @@ void intel_psr_disable(struct intel_dp *intel_dp, return; } - dev_priv->psr.disable_source(intel_dp, old_crtc_state); + intel_psr_disable_source(intel_dp, old_crtc_state); /* Disable PSR on Sink */ drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, 0); @@ -945,11 +933,4 @@ void intel_psr_init(struct drm_i915_private *dev_priv) INIT_WORK(&dev_priv->psr.work, intel_psr_work); mutex_init(&dev_priv->psr.lock); - - dev_priv->psr.enable_source = hsw_psr_enable_source; - dev_priv->psr.disable_source = hsw_psr_disable; - dev_priv->psr.enable_sink = hsw_psr_enable_sink; - dev_priv->psr.activate = hsw_psr_activate; - dev_priv->psr.setup_vsc = hsw_psr_setup_vsc; - } -- GitLab From c12e0643a05d978657877630d4da1ace06ea3720 Mon Sep 17 00:00:00 2001 From: Dhinakaran Pandiyan <dhinakaran.pandiyan@gmail.com> Date: Sun, 24 Jun 2018 22:47:40 -0700 Subject: [PATCH 0513/1506] drm/i915/psr: Fix race in intel_psr_work() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 5422b37c907e ("drm/i915/psr: Kill delays when activating psr back.") switched from delayed work to the plain variant and while doing so removed the check for work_busy() before scheduling a PSR activation. This appears to cause consecutive executions of psr_activate() in this scenario - after a worker picks up the PSR work item for execution and before the work function can acquire the PSR mutex, a psr_flush() can get hold of the mutex and schedule another PSR work. Without a psr_exit() between the two psr_activate() calls, warning messages get printed. Further, since we drop the mutex in the midst of psr_work() to wait for PSR to idle, another work item can also get scheduled. Fix this by returning if PSR was already active. Fixes: 5422b37c907e ("drm/i915/psr: Kill delays when activating psr back.") Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=106948 Cc: Rodrigo Vivi <rodrigo.vivi@intel.com> Cc: Chris Wilson <chris@chris-wilson.co.uk> Cc: José Roberto de Souza <jose.souza@intel.com> Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180625054741.3919-1-dhinakaran.pandiyan@intel.com --- drivers/gpu/drm/i915/intel_psr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index ccaee4a748f25..276070d597e14 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -758,7 +758,7 @@ static void intel_psr_work(struct work_struct *work) * recheck. Since psr_flush first clears this and then reschedules we * won't ever miss a flush when bailing out here. */ - if (dev_priv->psr.busy_frontbuffer_bits) + if (dev_priv->psr.busy_frontbuffer_bits || dev_priv->psr.active) goto unlock; intel_psr_activate(dev_priv->psr.enabled); -- GitLab From bcc233b2aa7878bdcfbad6505ac66383a82a73dd Mon Sep 17 00:00:00 2001 From: Dhinakaran Pandiyan <dhinakaran.pandiyan@gmail.com> Date: Tue, 26 Jun 2018 02:05:22 -0700 Subject: [PATCH 0514/1506] drm/i915/psr: Warn for erroneous enabling of both PSR1 and PSR2. Depending whether PSR1 or PSR2 was configured, we print a warning if the corresponding control mmio indicated PSR was erroneously enabled. As Chris pointed out, it makes more sense to check for both the mmio's since we expect neither PSR1 nor PSR2 to be enabled when psr_activate() is called. v2: Read PSR2 control register only on supported platforms (Rodrigo) Cc: Rodrigo Vivi <rodrigo.vivi@intel.com> Cc: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180626090522.17682-1-dhinakaran.pandiyan@intel.com --- drivers/gpu/drm/i915/intel_psr.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 276070d597e14..1b439629cb660 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -521,10 +521,9 @@ static void intel_psr_activate(struct intel_dp *intel_dp) struct drm_device *dev = intel_dig_port->base.base.dev; struct drm_i915_private *dev_priv = to_i915(dev); - if (dev_priv->psr.psr2_enabled) + if (INTEL_GEN(dev_priv) >= 9) WARN_ON(I915_READ(EDP_PSR2_CTL) & EDP_PSR2_ENABLE); - else - WARN_ON(I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE); + WARN_ON(I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE); WARN_ON(dev_priv->psr.active); lockdep_assert_held(&dev_priv->psr.lock); -- GitLab From 42f53ffcad7fcf11b5767767dd0c0ff607d99787 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= <jose.souza@intel.com> Date: Tue, 26 Jun 2018 13:16:40 -0700 Subject: [PATCH 0515/1506] drm/i915/psr: Remove intel_crtc_state parameter from disable_source() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It was only used in VLV/CHV so after the removal of the PSR support for those platforms it is not necessary any more. v7: Rebased Reviewed-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com> Signed-off-by: José Roberto de Souza <jose.souza@intel.com> Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180626201644.21932-1-jose.souza@intel.com --- drivers/gpu/drm/i915/intel_psr.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 1b439629cb660..f6d384a11b796 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -625,8 +625,7 @@ void intel_psr_enable(struct intel_dp *intel_dp, } static void -intel_psr_disable_source(struct intel_dp *intel_dp, - const struct intel_crtc_state *old_crtc_state) +intel_psr_disable_source(struct intel_dp *intel_dp) { struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); struct drm_device *dev = intel_dig_port->base.base.dev; @@ -693,7 +692,7 @@ void intel_psr_disable(struct intel_dp *intel_dp, return; } - intel_psr_disable_source(intel_dp, old_crtc_state); + intel_psr_disable_source(intel_dp); /* Disable PSR on Sink */ drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, 0); -- GitLab From cc3054ff6214f6d14d35ffe629ff8d5032ace7f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= <jose.souza@intel.com> Date: Tue, 26 Jun 2018 13:16:41 -0700 Subject: [PATCH 0516/1506] drm/i915/psr: Begin to handle PSR/PSR2 errors set by sink MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit eDP spec states that sink device will do a short pulse in HPD line when there is a PSR/PSR2 error that needs to be handled by source, this is handling the first and most simples error: DP_PSR_SINK_INTERNAL_ERROR. Here taking the safest approach and disabling PSR(at least until the next modeset), to avoid multiple rendering issues due to bad pannels. v5: added lockdep_assert in psr_disable and renamed psr_disable() to intel_psr_disable_locked() v4: Using CAN_PSR instead of HAS_PSR in intel_psr_short_pulse v3: disabling PSR instead of exiting on error Reviewed-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com> Signed-off-by: José Roberto de Souza <jose.souza@intel.com> Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180626201644.21932-2-jose.souza@intel.com --- drivers/gpu/drm/i915/intel_dp.c | 2 ++ drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_psr.c | 62 ++++++++++++++++++++++++++------ 3 files changed, 54 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index c1b2f00f324bc..5be07e1d816d7 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -4491,6 +4491,8 @@ intel_dp_short_pulse(struct intel_dp *intel_dp) if (intel_dp_needs_link_retrain(intel_dp)) return false; + intel_psr_short_pulse(intel_dp); + if (intel_dp->compliance.test_type == DP_TEST_LINK_TRAINING) { DRM_DEBUG_KMS("Link Training Compliance Test requested\n"); /* Send a Hotplug Uevent to userspace to start modeset */ diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 0be45b75cca21..5a37db292d3a3 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1920,6 +1920,7 @@ void intel_psr_compute_config(struct intel_dp *intel_dp, struct intel_crtc_state *crtc_state); void intel_psr_irq_control(struct drm_i915_private *dev_priv, bool debug); void intel_psr_irq_handler(struct drm_i915_private *dev_priv, u32 psr_iir); +void intel_psr_short_pulse(struct intel_dp *intel_dp); /* intel_runtime_pm.c */ int intel_power_domains_init(struct drm_i915_private *); diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index f6d384a11b796..445e97dc791d1 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -666,6 +666,25 @@ intel_psr_disable_source(struct intel_dp *intel_dp) } } +static void intel_psr_disable_locked(struct intel_dp *intel_dp) +{ + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + struct drm_device *dev = intel_dig_port->base.base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); + + lockdep_assert_held(&dev_priv->psr.lock); + + if (!dev_priv->psr.enabled) + return; + + intel_psr_disable_source(intel_dp); + + /* Disable PSR on Sink */ + drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, 0); + + dev_priv->psr.enabled = NULL; +} + /** * intel_psr_disable - Disable PSR * @intel_dp: Intel DP @@ -687,17 +706,7 @@ void intel_psr_disable(struct intel_dp *intel_dp, return; mutex_lock(&dev_priv->psr.lock); - if (!dev_priv->psr.enabled) { - mutex_unlock(&dev_priv->psr.lock); - return; - } - - intel_psr_disable_source(intel_dp); - - /* Disable PSR on Sink */ - drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, 0); - - dev_priv->psr.enabled = NULL; + intel_psr_disable_locked(intel_dp); mutex_unlock(&dev_priv->psr.lock); cancel_work_sync(&dev_priv->psr.work); } @@ -932,3 +941,34 @@ void intel_psr_init(struct drm_i915_private *dev_priv) INIT_WORK(&dev_priv->psr.work, intel_psr_work); mutex_init(&dev_priv->psr.lock); } + +void intel_psr_short_pulse(struct intel_dp *intel_dp) +{ + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + struct drm_device *dev = intel_dig_port->base.base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); + struct i915_psr *psr = &dev_priv->psr; + u8 val; + + if (!CAN_PSR(dev_priv) || !intel_dp_is_edp(intel_dp)) + return; + + mutex_lock(&psr->lock); + + if (psr->enabled != intel_dp) + goto exit; + + if (drm_dp_dpcd_readb(&intel_dp->aux, DP_PSR_STATUS, &val) != 1) { + DRM_ERROR("PSR_STATUS dpcd read failed\n"); + goto exit; + } + + if ((val & DP_PSR_SINK_STATE_MASK) == DP_PSR_SINK_INTERNAL_ERROR) { + DRM_DEBUG_KMS("PSR sink internal error, disabling PSR\n"); + intel_psr_disable_locked(intel_dp); + } + + /* TODO: handle other PSR/PSR2 errors */ +exit: + mutex_unlock(&psr->lock); +} -- GitLab From 93bf76ed882d5b7c6824e95d868d608f61b4f663 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= <jose.souza@intel.com> Date: Tue, 26 Jun 2018 13:16:42 -0700 Subject: [PATCH 0517/1506] drm/i915/psr: Handle PSR errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sink will interrupt source when it have any PSR error. DP_PSR_VSC_SDP_UNCORRECTABLE_ERROR is a PSR2 but already handling it here. The only missing error to be handled is DP_PSR_LINK_CRC_ERROR that will be taken in care in a futher patch. v6: not handling DP_PSR_LINK_CRC_ERROR here v5: handling all PSR errors here, so the commit message and comment have changed v3: disabling PSR instead of exiting on error Cc: Rodrigo Vivi <rodrigo.vivi@intel.com> Reviewed-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Signed-off-by: José Roberto de Souza <jose.souza@intel.com> Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180626201644.21932-3-jose.souza@intel.com --- drivers/gpu/drm/i915/intel_psr.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 445e97dc791d1..860b46b72403f 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -949,6 +949,8 @@ void intel_psr_short_pulse(struct intel_dp *intel_dp) struct drm_i915_private *dev_priv = to_i915(dev); struct i915_psr *psr = &dev_priv->psr; u8 val; + const u8 errors = DP_PSR_RFB_STORAGE_ERROR | + DP_PSR_VSC_SDP_UNCORRECTABLE_ERROR; if (!CAN_PSR(dev_priv) || !intel_dp_is_edp(intel_dp)) return; @@ -968,7 +970,25 @@ void intel_psr_short_pulse(struct intel_dp *intel_dp) intel_psr_disable_locked(intel_dp); } - /* TODO: handle other PSR/PSR2 errors */ + if (drm_dp_dpcd_readb(&intel_dp->aux, DP_PSR_ERROR_STATUS, &val) != 1) { + DRM_ERROR("PSR_ERROR_STATUS dpcd read failed\n"); + goto exit; + } + + if (val & DP_PSR_RFB_STORAGE_ERROR) + DRM_DEBUG_KMS("PSR RFB storage error, disabling PSR\n"); + if (val & DP_PSR_VSC_SDP_UNCORRECTABLE_ERROR) + DRM_DEBUG_KMS("PSR VSC SDP uncorrectable error, disabling PSR\n"); + + if (val & ~errors) + DRM_ERROR("PSR_ERROR_STATUS unhandled errors %x\n", + val & ~errors); + if (val & errors) + intel_psr_disable_locked(intel_dp); + /* clear status register */ + drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_ERROR_STATUS, val); + + /* TODO: handle PSR2 errors */ exit: mutex_unlock(&psr->lock); } -- GitLab From 3ebe3df50bb1db45c7bf1ce90c3d61c4eed1ba84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= <jose.souza@intel.com> Date: Tue, 26 Jun 2018 13:16:43 -0700 Subject: [PATCH 0518/1506] drm/i915/psr: Avoid PSR exit max time timeout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Specification requires that max time should be masked from bdw and forward but it can be also safely enabled to hsw. This will make PSR exits more deterministic and only when really needed. If this was used to fix a issue in some panel than can only self-refresh for a few seconds, that panel will interrupt and assert one of the PSR errors handled in: 'drm/i915/psr: Handle PSR RFB storage error' and 'drm/i915/psr: Begin to handle PSR/PSR2 errors set by sink' Spec: 21664 v4: patch moved to before 'drm/i915/psr/bdw+: Enable CRC check in the static frame on the sink side' to avoid touch in 2 patches EDP_PSR_DEBUG. Cc: Rodrigo Vivi <rodrigo.vivi@intel.com> Reviewed-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Signed-off-by: José Roberto de Souza <jose.souza@intel.com> Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180626201644.21932-4-jose.souza@intel.com --- drivers/gpu/drm/i915/intel_psr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 860b46b72403f..aa98b62910b40 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -579,7 +579,8 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp, EDP_PSR_DEBUG_MASK_MEMUP | EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP | - EDP_PSR_DEBUG_MASK_DISP_REG_WRITE); + EDP_PSR_DEBUG_MASK_DISP_REG_WRITE | + EDP_PSR_DEBUG_MASK_MAX_SLEEP); } } -- GitLab From 00c8f19463ab42d22332fc9c9fca605f12eadeb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= <jose.souza@intel.com> Date: Tue, 26 Jun 2018 13:16:44 -0700 Subject: [PATCH 0519/1506] drm/i915/psr: Enable CRC check in the static frame on the sink side MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sink can be configured to calculate the CRC over the static frame and compare with the CRC calculated and transmited in the VSC SDP by source, if there is a mismatch sink will do a short pulse in HPD and set DP_PSR_LINK_CRC_ERROR in DP_PSR_ERROR_STATUS. Spec: 7723 v6: andling DP_PSR_LINK_CRC_ERROR here and remove "bdw+" from commit message v4: patch moved to after 'drm/i915/psr: Avoid PSR exit max time timeout' to avoid touch in 2 patches EDP_PSR_DEBUG. v3: disabling PSR instead of exiting on error Reviewed-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com> Signed-off-by: José Roberto de Souza <jose.souza@intel.com> Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180626201644.21932-5-jose.souza@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_psr.c | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index caad19f5f557f..43db91c19f524 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4044,6 +4044,7 @@ enum { #define EDP_PSR_SKIP_AUX_EXIT (1 << 12) #define EDP_PSR_TP1_TP2_SEL (0 << 11) #define EDP_PSR_TP1_TP3_SEL (1 << 11) +#define EDP_PSR_CRC_ENABLE (1 << 10) /* BDW+ */ #define EDP_PSR_TP2_TP3_TIME_500us (0 << 8) #define EDP_PSR_TP2_TP3_TIME_100us (1 << 8) #define EDP_PSR_TP2_TP3_TIME_2500us (2 << 8) diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index aa98b62910b40..45f1cb7d6c043 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -323,6 +323,8 @@ static void intel_psr_enable_sink(struct intel_dp *intel_dp) if (dev_priv->psr.link_standby) dpcd_val |= DP_PSR_MAIN_LINK_ACTIVE; + if (!dev_priv->psr.psr2_enabled && INTEL_GEN(dev_priv) >= 8) + dpcd_val |= DP_PSR_CRC_VERIFICATION; drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, dpcd_val); drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER, DP_SET_POWER_D0); @@ -378,6 +380,9 @@ static void hsw_activate_psr1(struct intel_dp *intel_dp) else val |= EDP_PSR_TP1_TP2_SEL; + if (INTEL_GEN(dev_priv) >= 8) + val |= EDP_PSR_CRC_ENABLE; + val |= I915_READ(EDP_PSR_CTL) & EDP_PSR_RESTORE_PSR_ACTIVE_CTX_MASK; I915_WRITE(EDP_PSR_CTL, val); } @@ -951,7 +956,8 @@ void intel_psr_short_pulse(struct intel_dp *intel_dp) struct i915_psr *psr = &dev_priv->psr; u8 val; const u8 errors = DP_PSR_RFB_STORAGE_ERROR | - DP_PSR_VSC_SDP_UNCORRECTABLE_ERROR; + DP_PSR_VSC_SDP_UNCORRECTABLE_ERROR | + DP_PSR_LINK_CRC_ERROR; if (!CAN_PSR(dev_priv) || !intel_dp_is_edp(intel_dp)) return; @@ -980,6 +986,8 @@ void intel_psr_short_pulse(struct intel_dp *intel_dp) DRM_DEBUG_KMS("PSR RFB storage error, disabling PSR\n"); if (val & DP_PSR_VSC_SDP_UNCORRECTABLE_ERROR) DRM_DEBUG_KMS("PSR VSC SDP uncorrectable error, disabling PSR\n"); + if (val & DP_PSR_LINK_CRC_ERROR) + DRM_ERROR("PSR Link CRC error, disabling PSR\n"); if (val & ~errors) DRM_ERROR("PSR_ERROR_STATUS unhandled errors %x\n", -- GitLab From a3e77e1655961f4ed7ad4eea8763aed418bd932e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Tue, 26 Jun 2018 22:47:13 +0300 Subject: [PATCH 0520/1506] drm/rockchip: Use drm_crtc_mask() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use drm_crtc_mask() where appropriate. Cc: Sandy Huang <hjc@rock-chips.com> Cc: "Heiko Stübner" <heiko@sntech.de> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Signed-off-by: Heiko Stuebner <heiko@sntech.de> Link: https://patchwork.freedesktop.org/patch/msgid/20180626194716.12522-7-ville.syrjala@linux.intel.com --- drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index c9222119767d8..effecbed2d11c 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -1308,7 +1308,7 @@ static int vop_create_crtc(struct vop *vop) for (i = 0; i < vop_data->win_size; i++) { struct vop_win *vop_win = &vop->win[i]; const struct vop_win_data *win_data = vop_win->data; - unsigned long possible_crtcs = 1 << drm_crtc_index(crtc); + unsigned long possible_crtcs = drm_crtc_mask(crtc); if (win_data->type != DRM_PLANE_TYPE_OVERLAY) continue; -- GitLab From 106359177a57c7ea4a0c31e9cd24e6313b355ed7 Mon Sep 17 00:00:00 2001 From: Sandy Huang <hjc@rock-chips.com> Date: Tue, 26 Jun 2018 16:16:44 +0800 Subject: [PATCH 0521/1506] drm/rockchip: vop: fixup linebuffer mode calc error linebuffer mode should be LB_YUV_3840X5 when width is bigger than 1280 in yuv mode. Separate yuv and rgb case makes the scl_vop_cal_lb_mode() logic clearer. Signed-off-by: Sandy Huang <hjc@rock-chips.com> Signed-off-by: Heiko Stuebner <heiko@sntech.de> Link: https://patchwork.freedesktop.org/patch/msgid/1530001004-25036-1-git-send-email-hjc@rock-chips.com --- drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 23 ++++++++++++--------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h index 084acdd0019a8..fcb91041a666d 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h @@ -331,16 +331,19 @@ static inline int scl_vop_cal_lb_mode(int width, bool is_yuv) { int lb_mode; - if (width > 2560) - lb_mode = LB_RGB_3840X2; - else if (width > 1920) - lb_mode = LB_RGB_2560X4; - else if (!is_yuv) - lb_mode = LB_RGB_1920X5; - else if (width > 1280) - lb_mode = LB_YUV_3840X5; - else - lb_mode = LB_YUV_2560X8; + if (is_yuv) { + if (width > 1280) + lb_mode = LB_YUV_3840X5; + else + lb_mode = LB_YUV_2560X8; + } else { + if (width > 2560) + lb_mode = LB_RGB_3840X2; + else if (width > 1920) + lb_mode = LB_RGB_2560X4; + else + lb_mode = LB_RGB_1920X5; + } return lb_mode; } -- GitLab From 67ca07e7ac10d7cdc2aa7ac216cab7fb64c95e50 Mon Sep 17 00:00:00 2001 From: Imre Deak <imre.deak@intel.com> Date: Tue, 26 Jun 2018 17:22:32 +0300 Subject: [PATCH 0522/1506] drm/i915/icl: Add power well support Add the definition for ICL power wells and their mapping to power domains. On ICL there are 3 power well control registers, we'll select the correct one based on higher bits of the power well ID. The offset for the control and status flags within this register is based on the lower bits of the ID as on older platforms. As the DC state programming is also the same as on old platforms we can reuse the corresponding helpers. For this we mark here the DC-off power well as shared among multiple platforms. Other than the above the delta between old platforms and ICL: - Pipe C has its own power well, so we can save some additional power in the pipe A+B and (non-eDP) pipe A configurations. - Power wells for port E/F DDI/AUX IO and Thunderbolt 1-4 AUX IO v2: - Rebase on drm-tip after prep patch for this was merged there as requested by Paulo. - Actually add the new AUX and DDI power well control regs (Rakshmi) v3: - Fix power well register names in code comments - Add TBT AUX->power well 3 dependency v4: - Rebase v5: - Detach AUX power wells from the INIT power domain. These power wells can only be enabled in a TC/TBT connected state and otherwise not needed during driver initialization. v6: - Use _MMIO_PORT(...) instead _MMIO(_PICK(...)) (Paulo) Fix checkpatch warnings. Cc: Animesh Manna <animesh.manna@intel.com> Cc: Rakshmi Bhatia <rakshmi.bhatia@intel.com> Cc: Paulo Zanoni <paulo.r.zanoni@intel.com> Signed-off-by: Imre Deak <imre.deak@intel.com> Reviewed-by: Animesh Manna <animesh.manna@intel.com> (v1) Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180626142232.22361-1-imre.deak@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 78 +++++- drivers/gpu/drm/i915/intel_display.h | 4 + drivers/gpu/drm/i915/intel_runtime_pm.c | 329 +++++++++++++++++++++++- 3 files changed, 395 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 43db91c19f524..2c20dc0db6482 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1045,13 +1045,13 @@ enum i915_power_well_id { /* * HSW/BDW - * - HSW_PWR_WELL_CTL_DRIVER(0) (status bit: id*2, req bit: id*2+1) + * - _HSW_PWR_WELL_CTL1-4 (status bit: id*2, req bit: id*2+1) */ HSW_DISP_PW_GLOBAL = 15, /* * GEN9+ - * - HSW_PWR_WELL_CTL_DRIVER(0) (status bit: id*2, req bit: id*2+1) + * - _HSW_PWR_WELL_CTL1-4 (status bit: id*2, req bit: id*2+1) */ SKL_DISP_PW_MISC_IO = 0, SKL_DISP_PW_DDI_A_E, @@ -1075,17 +1075,54 @@ enum i915_power_well_id { SKL_DISP_PW_2, /* - custom power wells */ - SKL_DISP_PW_DC_OFF, BXT_DPIO_CMN_A, BXT_DPIO_CMN_BC, - GLK_DPIO_CMN_C, /* 19 */ + GLK_DPIO_CMN_C, /* 18 */ + + /* + * GEN11+ + * - _HSW_PWR_WELL_CTL1-4 + * (status bit: (id&15)*2, req bit:(id&15)*2+1) + */ + ICL_DISP_PW_1 = 0, + ICL_DISP_PW_2, + ICL_DISP_PW_3, + ICL_DISP_PW_4, + + /* + * - _HSW_PWR_WELL_CTL_AUX1/2/4 + * (status bit: (id&15)*2, req bit:(id&15)*2+1) + */ + ICL_DISP_PW_AUX_A = 16, + ICL_DISP_PW_AUX_B, + ICL_DISP_PW_AUX_C, + ICL_DISP_PW_AUX_D, + ICL_DISP_PW_AUX_E, + ICL_DISP_PW_AUX_F, + + ICL_DISP_PW_AUX_TBT1 = 24, + ICL_DISP_PW_AUX_TBT2, + ICL_DISP_PW_AUX_TBT3, + ICL_DISP_PW_AUX_TBT4, + + /* + * - _HSW_PWR_WELL_CTL_DDI1/2/4 + * (status bit: (id&15)*2, req bit:(id&15)*2+1) + */ + ICL_DISP_PW_DDI_A = 32, + ICL_DISP_PW_DDI_B, + ICL_DISP_PW_DDI_C, + ICL_DISP_PW_DDI_D, + ICL_DISP_PW_DDI_E, + ICL_DISP_PW_DDI_F, /* 37 */ /* * Multiple platforms. * Must start following the highest ID of any platform. * - custom power wells */ - I915_DISP_PW_ALWAYS_ON = 20, + SKL_DISP_PW_DC_OFF = 38, + I915_DISP_PW_ALWAYS_ON, }; #define PUNIT_REG_PWRGT_CTRL 0x60 @@ -1679,6 +1716,13 @@ enum i915_power_well_id { #define IREF1RC_OFFSET_MASK (0xFF << IREF1RC_OFFSET_SHIFT) #define BXT_PORT_CL1CM_DW10(phy) _BXT_PHY((phy), _PORT_CL1CM_DW10_BC) +#define _ICL_PORT_CL_DW12_A 0x162030 +#define _ICL_PORT_CL_DW12_B 0x6C030 +#define ICL_LANE_ENABLE_AUX (1 << 0) +#define ICL_PORT_CL_DW12(port) _MMIO_PORT((port), \ + _ICL_PORT_CL_DW12_A, \ + _ICL_PORT_CL_DW12_B) + #define _PORT_CL1CM_DW28_A 0x162070 #define _PORT_CL1CM_DW28_BC 0x6C070 #define OCL1_POWER_DOWN_EN (1 << 23) @@ -8564,6 +8608,14 @@ enum { #define _HSW_PWR_WELL_CTL3 0x45408 #define _HSW_PWR_WELL_CTL4 0x4540C +#define _ICL_PWR_WELL_CTL_AUX1 0x45440 +#define _ICL_PWR_WELL_CTL_AUX2 0x45444 +#define _ICL_PWR_WELL_CTL_AUX4 0x4544C + +#define _ICL_PWR_WELL_CTL_DDI1 0x45450 +#define _ICL_PWR_WELL_CTL_DDI2 0x45454 +#define _ICL_PWR_WELL_CTL_DDI4 0x4545C + /* * Each power well control register contains up to 16 (request, status) HW * flag tuples. The register index and HW flag shift is determined by the @@ -8573,14 +8625,20 @@ enum { */ #define _HSW_PW_REG_IDX(pw) ((pw) >> 4) #define _HSW_PW_SHIFT(pw) (((pw) & 0xf) * 2) -/* TODO: Add all PWR_WELL_CTL registers below for new platforms */ #define HSW_PWR_WELL_CTL_BIOS(pw) _MMIO(_PICK(_HSW_PW_REG_IDX(pw), \ - _HSW_PWR_WELL_CTL1)) + _HSW_PWR_WELL_CTL1, \ + _ICL_PWR_WELL_CTL_AUX1, \ + _ICL_PWR_WELL_CTL_DDI1)) #define HSW_PWR_WELL_CTL_DRIVER(pw) _MMIO(_PICK(_HSW_PW_REG_IDX(pw), \ - _HSW_PWR_WELL_CTL2)) + _HSW_PWR_WELL_CTL2, \ + _ICL_PWR_WELL_CTL_AUX2, \ + _ICL_PWR_WELL_CTL_DDI2)) +/* KVMR doesn't have a reg for AUX or DDI power well control */ #define HSW_PWR_WELL_CTL_KVMR _MMIO(_HSW_PWR_WELL_CTL3) #define HSW_PWR_WELL_CTL_DEBUG(pw) _MMIO(_PICK(_HSW_PW_REG_IDX(pw), \ - _HSW_PWR_WELL_CTL4)) + _HSW_PWR_WELL_CTL4, \ + _ICL_PWR_WELL_CTL_AUX4, \ + _ICL_PWR_WELL_CTL_DDI4)) #define HSW_PWR_WELL_CTL_REQ(pw) (1 << (_HSW_PW_SHIFT(pw) + 1)) #define HSW_PWR_WELL_CTL_STATE(pw) (1 << _HSW_PW_SHIFT(pw)) @@ -8601,6 +8659,8 @@ enum skl_power_gate { #define SKL_FUSE_DOWNLOAD_STATUS (1 << 31) /* PG0 (HW control->no power well ID), PG1..PG2 (SKL_DISP_PW1..SKL_DISP_PW2) */ #define SKL_PW_TO_PG(pw) ((pw) - SKL_DISP_PW_1 + SKL_PG1) +/* PG0 (HW control->no power well ID), PG1..PG4 (ICL_DISP_PW1..ICL_DISP_PW4) */ +#define ICL_PW_TO_PG(pw) ((pw) - ICL_DISP_PW_1 + SKL_PG1) #define SKL_FUSE_PG_DIST_STATUS(pg) (1 << (27 - (pg))) #define _CNL_AUX_REG_IDX(pw) ((pw) - 9) diff --git a/drivers/gpu/drm/i915/intel_display.h b/drivers/gpu/drm/i915/intel_display.h index dfb02da73ac86..a77dd29db2ecb 100644 --- a/drivers/gpu/drm/i915/intel_display.h +++ b/drivers/gpu/drm/i915/intel_display.h @@ -199,6 +199,10 @@ enum intel_display_power_domain { POWER_DOMAIN_AUX_E, POWER_DOMAIN_AUX_F, POWER_DOMAIN_AUX_IO_A, + POWER_DOMAIN_AUX_TBT1, + POWER_DOMAIN_AUX_TBT2, + POWER_DOMAIN_AUX_TBT3, + POWER_DOMAIN_AUX_TBT4, POWER_DOMAIN_GMBUS, POWER_DOMAIN_MODESET, POWER_DOMAIN_GT_IRQ, diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 2969787201ef8..d81b2cfe1c5ed 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -134,6 +134,14 @@ intel_display_power_domain_str(enum intel_display_power_domain domain) return "AUX_F"; case POWER_DOMAIN_AUX_IO_A: return "AUX_IO_A"; + case POWER_DOMAIN_AUX_TBT1: + return "AUX_TBT1"; + case POWER_DOMAIN_AUX_TBT2: + return "AUX_TBT2"; + case POWER_DOMAIN_AUX_TBT3: + return "AUX_TBT3"; + case POWER_DOMAIN_AUX_TBT4: + return "AUX_TBT4"; case POWER_DOMAIN_GMBUS: return "GMBUS"; case POWER_DOMAIN_INIT: @@ -384,7 +392,8 @@ static void hsw_power_well_enable(struct drm_i915_private *dev_priv, u32 val; if (wait_fuses) { - pg = SKL_PW_TO_PG(id); + pg = INTEL_GEN(dev_priv) >= 11 ? ICL_PW_TO_PG(id) : + SKL_PW_TO_PG(id); /* * For PW1 we have to wait both for the PW0/PG0 fuse state * before enabling the power well and PW1/PG1's own fuse @@ -430,6 +439,43 @@ static void hsw_power_well_disable(struct drm_i915_private *dev_priv, hsw_wait_for_power_well_disable(dev_priv, power_well); } +#define ICL_AUX_PW_TO_PORT(pw) ((pw) - ICL_DISP_PW_AUX_A) + +static void +icl_combo_phy_aux_power_well_enable(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well) +{ + enum i915_power_well_id id = power_well->id; + enum port port = ICL_AUX_PW_TO_PORT(id); + u32 val; + + val = I915_READ(HSW_PWR_WELL_CTL_DRIVER(id)); + I915_WRITE(HSW_PWR_WELL_CTL_DRIVER(id), val | HSW_PWR_WELL_CTL_REQ(id)); + + val = I915_READ(ICL_PORT_CL_DW12(port)); + I915_WRITE(ICL_PORT_CL_DW12(port), val | ICL_LANE_ENABLE_AUX); + + hsw_wait_for_power_well_enable(dev_priv, power_well); +} + +static void +icl_combo_phy_aux_power_well_disable(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well) +{ + enum i915_power_well_id id = power_well->id; + enum port port = ICL_AUX_PW_TO_PORT(id); + u32 val; + + val = I915_READ(ICL_PORT_CL_DW12(port)); + I915_WRITE(ICL_PORT_CL_DW12(port), val & ~ICL_LANE_ENABLE_AUX); + + val = I915_READ(HSW_PWR_WELL_CTL_DRIVER(id)); + I915_WRITE(HSW_PWR_WELL_CTL_DRIVER(id), + val & ~HSW_PWR_WELL_CTL_REQ(id)); + + hsw_wait_for_power_well_disable(dev_priv, power_well); +} + /* * We should only use the power well if we explicitly asked the hardware to * enable it, so check if it's enabled and also check if we've requested it to @@ -1897,6 +1943,105 @@ void intel_display_power_put(struct drm_i915_private *dev_priv, BIT_ULL(POWER_DOMAIN_AUX_A) | \ BIT_ULL(POWER_DOMAIN_INIT)) +/* + * ICL PW_0/PG_0 domains (HW/DMC control): + * - PCI + * - clocks except port PLL + * - central power except FBC + * - shared functions except pipe interrupts, pipe MBUS, DBUF registers + * ICL PW_1/PG_1 domains (HW/DMC control): + * - DBUF function + * - PIPE_A and its planes, except VGA + * - transcoder EDP + PSR + * - transcoder DSI + * - DDI_A + * - FBC + */ +#define ICL_PW_4_POWER_DOMAINS ( \ + BIT_ULL(POWER_DOMAIN_PIPE_C) | \ + BIT_ULL(POWER_DOMAIN_PIPE_C_PANEL_FITTER) | \ + BIT_ULL(POWER_DOMAIN_INIT)) + /* VDSC/joining */ +#define ICL_PW_3_POWER_DOMAINS ( \ + ICL_PW_4_POWER_DOMAINS | \ + BIT_ULL(POWER_DOMAIN_PIPE_B) | \ + BIT_ULL(POWER_DOMAIN_TRANSCODER_A) | \ + BIT_ULL(POWER_DOMAIN_TRANSCODER_B) | \ + BIT_ULL(POWER_DOMAIN_TRANSCODER_C) | \ + BIT_ULL(POWER_DOMAIN_PIPE_B_PANEL_FITTER) | \ + BIT_ULL(POWER_DOMAIN_PORT_DDI_B_LANES) | \ + BIT_ULL(POWER_DOMAIN_PORT_DDI_B_IO) | \ + BIT_ULL(POWER_DOMAIN_PORT_DDI_C_LANES) | \ + BIT_ULL(POWER_DOMAIN_PORT_DDI_C_IO) | \ + BIT_ULL(POWER_DOMAIN_PORT_DDI_D_LANES) | \ + BIT_ULL(POWER_DOMAIN_PORT_DDI_D_IO) | \ + BIT_ULL(POWER_DOMAIN_PORT_DDI_E_LANES) | \ + BIT_ULL(POWER_DOMAIN_PORT_DDI_E_IO) | \ + BIT_ULL(POWER_DOMAIN_PORT_DDI_F_LANES) | \ + BIT_ULL(POWER_DOMAIN_PORT_DDI_F_IO) | \ + BIT_ULL(POWER_DOMAIN_AUX_B) | \ + BIT_ULL(POWER_DOMAIN_AUX_C) | \ + BIT_ULL(POWER_DOMAIN_AUX_D) | \ + BIT_ULL(POWER_DOMAIN_AUX_E) | \ + BIT_ULL(POWER_DOMAIN_AUX_F) | \ + BIT_ULL(POWER_DOMAIN_AUX_TBT1) | \ + BIT_ULL(POWER_DOMAIN_AUX_TBT2) | \ + BIT_ULL(POWER_DOMAIN_AUX_TBT3) | \ + BIT_ULL(POWER_DOMAIN_AUX_TBT4) | \ + BIT_ULL(POWER_DOMAIN_VGA) | \ + BIT_ULL(POWER_DOMAIN_AUDIO) | \ + BIT_ULL(POWER_DOMAIN_INIT)) + /* + * - transcoder WD + * - KVMR (HW control) + */ +#define ICL_PW_2_POWER_DOMAINS ( \ + ICL_PW_3_POWER_DOMAINS | \ + BIT_ULL(POWER_DOMAIN_INIT)) + /* + * - eDP/DSI VDSC + * - KVMR (HW control) + */ +#define ICL_DISPLAY_DC_OFF_POWER_DOMAINS ( \ + ICL_PW_2_POWER_DOMAINS | \ + BIT_ULL(POWER_DOMAIN_MODESET) | \ + BIT_ULL(POWER_DOMAIN_AUX_A) | \ + BIT_ULL(POWER_DOMAIN_INIT)) + +#define ICL_DDI_IO_A_POWER_DOMAINS ( \ + BIT_ULL(POWER_DOMAIN_PORT_DDI_A_IO)) +#define ICL_DDI_IO_B_POWER_DOMAINS ( \ + BIT_ULL(POWER_DOMAIN_PORT_DDI_B_IO)) +#define ICL_DDI_IO_C_POWER_DOMAINS ( \ + BIT_ULL(POWER_DOMAIN_PORT_DDI_C_IO)) +#define ICL_DDI_IO_D_POWER_DOMAINS ( \ + BIT_ULL(POWER_DOMAIN_PORT_DDI_D_IO)) +#define ICL_DDI_IO_E_POWER_DOMAINS ( \ + BIT_ULL(POWER_DOMAIN_PORT_DDI_E_IO)) +#define ICL_DDI_IO_F_POWER_DOMAINS ( \ + BIT_ULL(POWER_DOMAIN_PORT_DDI_F_IO)) + +#define ICL_AUX_A_IO_POWER_DOMAINS ( \ + BIT_ULL(POWER_DOMAIN_AUX_A)) +#define ICL_AUX_B_IO_POWER_DOMAINS ( \ + BIT_ULL(POWER_DOMAIN_AUX_B)) +#define ICL_AUX_C_IO_POWER_DOMAINS ( \ + BIT_ULL(POWER_DOMAIN_AUX_C)) +#define ICL_AUX_D_IO_POWER_DOMAINS ( \ + BIT_ULL(POWER_DOMAIN_AUX_D)) +#define ICL_AUX_E_IO_POWER_DOMAINS ( \ + BIT_ULL(POWER_DOMAIN_AUX_E)) +#define ICL_AUX_F_IO_POWER_DOMAINS ( \ + BIT_ULL(POWER_DOMAIN_AUX_F)) +#define ICL_AUX_TBT1_IO_POWER_DOMAINS ( \ + BIT_ULL(POWER_DOMAIN_AUX_TBT1)) +#define ICL_AUX_TBT2_IO_POWER_DOMAINS ( \ + BIT_ULL(POWER_DOMAIN_AUX_TBT2)) +#define ICL_AUX_TBT3_IO_POWER_DOMAINS ( \ + BIT_ULL(POWER_DOMAIN_AUX_TBT3)) +#define ICL_AUX_TBT4_IO_POWER_DOMAINS ( \ + BIT_ULL(POWER_DOMAIN_AUX_TBT4)) + static const struct i915_power_well_ops i9xx_always_on_power_well_ops = { .sync_hw = i9xx_power_well_sync_hw_noop, .enable = i9xx_always_on_power_well_noop, @@ -2454,6 +2599,157 @@ static struct i915_power_well cnl_power_wells[] = { }, }; +static const struct i915_power_well_ops icl_combo_phy_aux_power_well_ops = { + .sync_hw = hsw_power_well_sync_hw, + .enable = icl_combo_phy_aux_power_well_enable, + .disable = icl_combo_phy_aux_power_well_disable, + .is_enabled = hsw_power_well_enabled, +}; + +static struct i915_power_well icl_power_wells[] = { + { + .name = "always-on", + .always_on = 1, + .domains = POWER_DOMAIN_MASK, + .ops = &i9xx_always_on_power_well_ops, + .id = I915_DISP_PW_ALWAYS_ON, + }, + { + .name = "power well 1", + /* Handled by the DMC firmware */ + .domains = 0, + .ops = &hsw_power_well_ops, + .id = ICL_DISP_PW_1, + .hsw.has_fuses = true, + }, + { + .name = "power well 2", + .domains = ICL_PW_2_POWER_DOMAINS, + .ops = &hsw_power_well_ops, + .id = ICL_DISP_PW_2, + .hsw.has_fuses = true, + }, + { + .name = "DC off", + .domains = ICL_DISPLAY_DC_OFF_POWER_DOMAINS, + .ops = &gen9_dc_off_power_well_ops, + .id = SKL_DISP_PW_DC_OFF, + }, + { + .name = "power well 3", + .domains = ICL_PW_3_POWER_DOMAINS, + .ops = &hsw_power_well_ops, + .id = ICL_DISP_PW_3, + .hsw.irq_pipe_mask = BIT(PIPE_B), + .hsw.has_vga = true, + .hsw.has_fuses = true, + }, + { + .name = "DDI A IO", + .domains = ICL_DDI_IO_A_POWER_DOMAINS, + .ops = &hsw_power_well_ops, + .id = ICL_DISP_PW_DDI_A, + }, + { + .name = "DDI B IO", + .domains = ICL_DDI_IO_B_POWER_DOMAINS, + .ops = &hsw_power_well_ops, + .id = ICL_DISP_PW_DDI_B, + }, + { + .name = "DDI C IO", + .domains = ICL_DDI_IO_C_POWER_DOMAINS, + .ops = &hsw_power_well_ops, + .id = ICL_DISP_PW_DDI_C, + }, + { + .name = "DDI D IO", + .domains = ICL_DDI_IO_D_POWER_DOMAINS, + .ops = &hsw_power_well_ops, + .id = ICL_DISP_PW_DDI_D, + }, + { + .name = "DDI E IO", + .domains = ICL_DDI_IO_E_POWER_DOMAINS, + .ops = &hsw_power_well_ops, + .id = ICL_DISP_PW_DDI_E, + }, + { + .name = "DDI F IO", + .domains = ICL_DDI_IO_F_POWER_DOMAINS, + .ops = &hsw_power_well_ops, + .id = ICL_DISP_PW_DDI_F, + }, + { + .name = "AUX A", + .domains = ICL_AUX_A_IO_POWER_DOMAINS, + .ops = &icl_combo_phy_aux_power_well_ops, + .id = ICL_DISP_PW_AUX_A, + }, + { + .name = "AUX B", + .domains = ICL_AUX_B_IO_POWER_DOMAINS, + .ops = &icl_combo_phy_aux_power_well_ops, + .id = ICL_DISP_PW_AUX_B, + }, + { + .name = "AUX C", + .domains = ICL_AUX_C_IO_POWER_DOMAINS, + .ops = &hsw_power_well_ops, + .id = ICL_DISP_PW_AUX_C, + }, + { + .name = "AUX D", + .domains = ICL_AUX_D_IO_POWER_DOMAINS, + .ops = &hsw_power_well_ops, + .id = ICL_DISP_PW_AUX_D, + }, + { + .name = "AUX E", + .domains = ICL_AUX_E_IO_POWER_DOMAINS, + .ops = &hsw_power_well_ops, + .id = ICL_DISP_PW_AUX_E, + }, + { + .name = "AUX F", + .domains = ICL_AUX_F_IO_POWER_DOMAINS, + .ops = &hsw_power_well_ops, + .id = ICL_DISP_PW_AUX_F, + }, + { + .name = "AUX TBT1", + .domains = ICL_AUX_TBT1_IO_POWER_DOMAINS, + .ops = &hsw_power_well_ops, + .id = ICL_DISP_PW_AUX_TBT1, + }, + { + .name = "AUX TBT2", + .domains = ICL_AUX_TBT2_IO_POWER_DOMAINS, + .ops = &hsw_power_well_ops, + .id = ICL_DISP_PW_AUX_TBT2, + }, + { + .name = "AUX TBT3", + .domains = ICL_AUX_TBT3_IO_POWER_DOMAINS, + .ops = &hsw_power_well_ops, + .id = ICL_DISP_PW_AUX_TBT3, + }, + { + .name = "AUX TBT4", + .domains = ICL_AUX_TBT4_IO_POWER_DOMAINS, + .ops = &hsw_power_well_ops, + .id = ICL_DISP_PW_AUX_TBT4, + }, + { + .name = "power well 4", + .domains = ICL_PW_4_POWER_DOMAINS, + .ops = &hsw_power_well_ops, + .id = ICL_DISP_PW_4, + .hsw.has_fuses = true, + .hsw.irq_pipe_mask = BIT(PIPE_C), + }, +}; + static int sanitize_disable_power_well_option(const struct drm_i915_private *dev_priv, int disable_power_well) @@ -2471,7 +2767,7 @@ static uint32_t get_allowed_dc_mask(const struct drm_i915_private *dev_priv, int requested_dc; int max_dc; - if (IS_GEN9_BC(dev_priv) || IS_CANNONLAKE(dev_priv)) { + if (IS_GEN9_BC(dev_priv) || INTEL_INFO(dev_priv)->gen >= 10) { max_dc = 2; mask = 0; } else if (IS_GEN9_LP(dev_priv)) { @@ -2559,7 +2855,9 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv) * The enabling order will be from lower to higher indexed wells, * the disabling order is reversed. */ - if (IS_HASWELL(dev_priv)) { + if (IS_ICELAKE(dev_priv)) { + set_power_wells(power_domains, icl_power_wells); + } else if (IS_HASWELL(dev_priv)) { set_power_wells(power_domains, hsw_power_wells); } else if (IS_BROADWELL(dev_priv)) { set_power_wells(power_domains, bdw_power_wells); @@ -3026,6 +3324,8 @@ static void cnl_display_core_uninit(struct drm_i915_private *dev_priv) static void icl_display_core_init(struct drm_i915_private *dev_priv, bool resume) { + struct i915_power_domains *power_domains = &dev_priv->power_domains; + struct i915_power_well *well; enum port port; u32 val; @@ -3054,8 +3354,14 @@ static void icl_display_core_init(struct drm_i915_private *dev_priv, I915_WRITE(ICL_PORT_CL_DW5(port), val); } - /* 4. Enable power well 1 (PG1) and aux IO power. */ - /* FIXME: ICL power wells code not here yet. */ + /* + * 4. Enable Power Well 1 (PG1). + * The AUX IO power wells will be enabled on demand. + */ + mutex_lock(&power_domains->lock); + well = lookup_power_well(dev_priv, ICL_DISP_PW_1); + intel_power_well_enable(dev_priv, well); + mutex_unlock(&power_domains->lock); /* 5. Enable CDCLK. */ icl_init_cdclk(dev_priv); @@ -3073,6 +3379,8 @@ static void icl_display_core_init(struct drm_i915_private *dev_priv, static void icl_display_core_uninit(struct drm_i915_private *dev_priv) { + struct i915_power_domains *power_domains = &dev_priv->power_domains; + struct i915_power_well *well; enum port port; u32 val; @@ -3086,8 +3394,15 @@ static void icl_display_core_uninit(struct drm_i915_private *dev_priv) /* 3. Disable CD clock */ icl_uninit_cdclk(dev_priv); - /* 4. Disable Power Well 1 (PG1) and Aux IO Power */ - /* FIXME: ICL power wells code not here yet. */ + /* + * 4. Disable Power Well 1 (PG1). + * The AUX IO power wells are toggled on demand, so they are already + * disabled at this point. + */ + mutex_lock(&power_domains->lock); + well = lookup_power_well(dev_priv, ICL_DISP_PW_1); + intel_power_well_disable(dev_priv, well); + mutex_unlock(&power_domains->lock); /* 5. Disable Comp */ for (port = PORT_A; port <= PORT_B; port++) { -- GitLab From 5a2fbbd832758157a85a7f5a83ea33e06cf92217 Mon Sep 17 00:00:00 2001 From: CK Hu <ck.hu@mediatek.com> Date: Wed, 27 Jun 2018 21:04:05 +0800 Subject: [PATCH 0523/1506] drm/mediatek: Split line to not over 80 characters Split the long line into two short line to make sure eache line not over 80 characters. Signed-off-by: CK Hu <ck.hu@mediatek.com> --- drivers/gpu/drm/mediatek/mtk_drm_drv.c | 54 +++++++++++++++++--------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c index 3d279a2993830..1f0657233a3e2 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c @@ -365,24 +365,42 @@ static const struct component_master_ops mtk_drm_ops = { }; static const struct of_device_id mtk_ddp_comp_dt_ids[] = { - { .compatible = "mediatek,mt2701-disp-ovl", .data = (void *)MTK_DISP_OVL }, - { .compatible = "mediatek,mt8173-disp-ovl", .data = (void *)MTK_DISP_OVL }, - { .compatible = "mediatek,mt2701-disp-rdma", .data = (void *)MTK_DISP_RDMA }, - { .compatible = "mediatek,mt8173-disp-rdma", .data = (void *)MTK_DISP_RDMA }, - { .compatible = "mediatek,mt8173-disp-wdma", .data = (void *)MTK_DISP_WDMA }, - { .compatible = "mediatek,mt2701-disp-color", .data = (void *)MTK_DISP_COLOR }, - { .compatible = "mediatek,mt8173-disp-color", .data = (void *)MTK_DISP_COLOR }, - { .compatible = "mediatek,mt8173-disp-aal", .data = (void *)MTK_DISP_AAL}, - { .compatible = "mediatek,mt8173-disp-gamma", .data = (void *)MTK_DISP_GAMMA, }, - { .compatible = "mediatek,mt8173-disp-ufoe", .data = (void *)MTK_DISP_UFOE }, - { .compatible = "mediatek,mt2701-dsi", .data = (void *)MTK_DSI }, - { .compatible = "mediatek,mt8173-dsi", .data = (void *)MTK_DSI }, - { .compatible = "mediatek,mt8173-dpi", .data = (void *)MTK_DPI }, - { .compatible = "mediatek,mt2701-disp-mutex", .data = (void *)MTK_DISP_MUTEX }, - { .compatible = "mediatek,mt8173-disp-mutex", .data = (void *)MTK_DISP_MUTEX }, - { .compatible = "mediatek,mt2701-disp-pwm", .data = (void *)MTK_DISP_BLS }, - { .compatible = "mediatek,mt8173-disp-pwm", .data = (void *)MTK_DISP_PWM }, - { .compatible = "mediatek,mt8173-disp-od", .data = (void *)MTK_DISP_OD }, + { .compatible = "mediatek,mt2701-disp-ovl", + .data = (void *)MTK_DISP_OVL }, + { .compatible = "mediatek,mt8173-disp-ovl", + .data = (void *)MTK_DISP_OVL }, + { .compatible = "mediatek,mt2701-disp-rdma", + .data = (void *)MTK_DISP_RDMA }, + { .compatible = "mediatek,mt8173-disp-rdma", + .data = (void *)MTK_DISP_RDMA }, + { .compatible = "mediatek,mt8173-disp-wdma", + .data = (void *)MTK_DISP_WDMA }, + { .compatible = "mediatek,mt2701-disp-color", + .data = (void *)MTK_DISP_COLOR }, + { .compatible = "mediatek,mt8173-disp-color", + .data = (void *)MTK_DISP_COLOR }, + { .compatible = "mediatek,mt8173-disp-aal", + .data = (void *)MTK_DISP_AAL}, + { .compatible = "mediatek,mt8173-disp-gamma", + .data = (void *)MTK_DISP_GAMMA, }, + { .compatible = "mediatek,mt8173-disp-ufoe", + .data = (void *)MTK_DISP_UFOE }, + { .compatible = "mediatek,mt2701-dsi", + .data = (void *)MTK_DSI }, + { .compatible = "mediatek,mt8173-dsi", + .data = (void *)MTK_DSI }, + { .compatible = "mediatek,mt8173-dpi", + .data = (void *)MTK_DPI }, + { .compatible = "mediatek,mt2701-disp-mutex", + .data = (void *)MTK_DISP_MUTEX }, + { .compatible = "mediatek,mt8173-disp-mutex", + .data = (void *)MTK_DISP_MUTEX }, + { .compatible = "mediatek,mt2701-disp-pwm", + .data = (void *)MTK_DISP_BLS }, + { .compatible = "mediatek,mt8173-disp-pwm", + .data = (void *)MTK_DISP_PWM }, + { .compatible = "mediatek,mt8173-disp-od", + .data = (void *)MTK_DISP_OD }, { } }; -- GitLab From e6ab087a224fd7bcf712db698fbade673cc9addd Mon Sep 17 00:00:00 2001 From: "stu.hsieh@mediatek.com" <stu.hsieh@mediatek.com> Date: Wed, 20 Jun 2018 16:19:31 +0800 Subject: [PATCH 0524/1506] drm/mediatek: Add support for mediatek SOC MT2712 This patch add support for the Mediatek MT2712 DISP subsystem. There are two OVL engine and three disp output in MT2712. Signed-off-by: Stu Hsieh <stu.hsieh@mediatek.com> Signed-off-by: CK Hu <ck.hu@mediatek.com> --- drivers/gpu/drm/mediatek/mtk_drm_ddp.c | 39 ++++++++++++++++++++++++++ drivers/gpu/drm/mediatek/mtk_drm_drv.c | 39 ++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c index 15e436d4e8a07..87e4191c250eb 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp.c @@ -65,6 +65,24 @@ #define MT8173_MUTEX_MOD_DISP_PWM1 24 #define MT8173_MUTEX_MOD_DISP_OD 25 +#define MT2712_MUTEX_MOD_DISP_PWM2 10 +#define MT2712_MUTEX_MOD_DISP_OVL0 11 +#define MT2712_MUTEX_MOD_DISP_OVL1 12 +#define MT2712_MUTEX_MOD_DISP_RDMA0 13 +#define MT2712_MUTEX_MOD_DISP_RDMA1 14 +#define MT2712_MUTEX_MOD_DISP_RDMA2 15 +#define MT2712_MUTEX_MOD_DISP_WDMA0 16 +#define MT2712_MUTEX_MOD_DISP_WDMA1 17 +#define MT2712_MUTEX_MOD_DISP_COLOR0 18 +#define MT2712_MUTEX_MOD_DISP_COLOR1 19 +#define MT2712_MUTEX_MOD_DISP_AAL0 20 +#define MT2712_MUTEX_MOD_DISP_UFOE 22 +#define MT2712_MUTEX_MOD_DISP_PWM0 23 +#define MT2712_MUTEX_MOD_DISP_PWM1 24 +#define MT2712_MUTEX_MOD_DISP_OD0 25 +#define MT2712_MUTEX_MOD2_DISP_AAL1 33 +#define MT2712_MUTEX_MOD2_DISP_OD1 34 + #define MT2701_MUTEX_MOD_DISP_OVL 3 #define MT2701_MUTEX_MOD_DISP_WDMA 6 #define MT2701_MUTEX_MOD_DISP_COLOR 7 @@ -138,6 +156,26 @@ static const unsigned int mt2701_mutex_mod[DDP_COMPONENT_ID_MAX] = { [DDP_COMPONENT_WDMA0] = MT2701_MUTEX_MOD_DISP_WDMA, }; +static const unsigned int mt2712_mutex_mod[DDP_COMPONENT_ID_MAX] = { + [DDP_COMPONENT_AAL0] = MT2712_MUTEX_MOD_DISP_AAL0, + [DDP_COMPONENT_AAL1] = MT2712_MUTEX_MOD2_DISP_AAL1, + [DDP_COMPONENT_COLOR0] = MT2712_MUTEX_MOD_DISP_COLOR0, + [DDP_COMPONENT_COLOR1] = MT2712_MUTEX_MOD_DISP_COLOR1, + [DDP_COMPONENT_OD0] = MT2712_MUTEX_MOD_DISP_OD0, + [DDP_COMPONENT_OD1] = MT2712_MUTEX_MOD2_DISP_OD1, + [DDP_COMPONENT_OVL0] = MT2712_MUTEX_MOD_DISP_OVL0, + [DDP_COMPONENT_OVL1] = MT2712_MUTEX_MOD_DISP_OVL1, + [DDP_COMPONENT_PWM0] = MT2712_MUTEX_MOD_DISP_PWM0, + [DDP_COMPONENT_PWM1] = MT2712_MUTEX_MOD_DISP_PWM1, + [DDP_COMPONENT_PWM2] = MT2712_MUTEX_MOD_DISP_PWM2, + [DDP_COMPONENT_RDMA0] = MT2712_MUTEX_MOD_DISP_RDMA0, + [DDP_COMPONENT_RDMA1] = MT2712_MUTEX_MOD_DISP_RDMA1, + [DDP_COMPONENT_RDMA2] = MT2712_MUTEX_MOD_DISP_RDMA2, + [DDP_COMPONENT_UFOE] = MT2712_MUTEX_MOD_DISP_UFOE, + [DDP_COMPONENT_WDMA0] = MT2712_MUTEX_MOD_DISP_WDMA0, + [DDP_COMPONENT_WDMA1] = MT2712_MUTEX_MOD_DISP_WDMA1, +}; + static const unsigned int mt8173_mutex_mod[DDP_COMPONENT_ID_MAX] = { [DDP_COMPONENT_AAL0] = MT8173_MUTEX_MOD_DISP_AAL, [DDP_COMPONENT_COLOR0] = MT8173_MUTEX_MOD_DISP_COLOR0, @@ -533,6 +571,7 @@ static int mtk_ddp_remove(struct platform_device *pdev) static const struct of_device_id ddp_driver_dt_match[] = { { .compatible = "mediatek,mt2701-disp-mutex", .data = mt2701_mutex_mod}, + { .compatible = "mediatek,mt2712-disp-mutex", .data = mt2712_mutex_mod}, { .compatible = "mediatek,mt8173-disp-mutex", .data = mt8173_mutex_mod}, {}, }; diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c index 1f0657233a3e2..39721119713bc 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c @@ -146,6 +146,32 @@ static const enum mtk_ddp_comp_id mt2701_mtk_ddp_ext[] = { DDP_COMPONENT_DPI0, }; +static const enum mtk_ddp_comp_id mt2712_mtk_ddp_main[] = { + DDP_COMPONENT_OVL0, + DDP_COMPONENT_COLOR0, + DDP_COMPONENT_AAL0, + DDP_COMPONENT_OD0, + DDP_COMPONENT_RDMA0, + DDP_COMPONENT_DPI0, + DDP_COMPONENT_PWM0, +}; + +static const enum mtk_ddp_comp_id mt2712_mtk_ddp_ext[] = { + DDP_COMPONENT_OVL1, + DDP_COMPONENT_COLOR1, + DDP_COMPONENT_AAL1, + DDP_COMPONENT_OD1, + DDP_COMPONENT_RDMA1, + DDP_COMPONENT_DPI1, + DDP_COMPONENT_PWM1, +}; + +static const enum mtk_ddp_comp_id mt2712_mtk_ddp_third[] = { + DDP_COMPONENT_RDMA2, + DDP_COMPONENT_DSI3, + DDP_COMPONENT_PWM2, +}; + static const enum mtk_ddp_comp_id mt8173_mtk_ddp_main[] = { DDP_COMPONENT_OVL0, DDP_COMPONENT_COLOR0, @@ -173,6 +199,15 @@ static const struct mtk_mmsys_driver_data mt2701_mmsys_driver_data = { .shadow_register = true, }; +static const struct mtk_mmsys_driver_data mt2712_mmsys_driver_data = { + .main_path = mt2712_mtk_ddp_main, + .main_len = ARRAY_SIZE(mt2712_mtk_ddp_main), + .ext_path = mt2712_mtk_ddp_ext, + .ext_len = ARRAY_SIZE(mt2712_mtk_ddp_ext), + .third_path = mt2712_mtk_ddp_third, + .third_len = ARRAY_SIZE(mt2712_mtk_ddp_third), +}; + static const struct mtk_mmsys_driver_data mt8173_mmsys_driver_data = { .main_path = mt8173_mtk_ddp_main, .main_len = ARRAY_SIZE(mt8173_mtk_ddp_main), @@ -393,6 +428,8 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = { .data = (void *)MTK_DPI }, { .compatible = "mediatek,mt2701-disp-mutex", .data = (void *)MTK_DISP_MUTEX }, + { .compatible = "mediatek,mt2712-disp-mutex", + .data = (void *)MTK_DISP_MUTEX }, { .compatible = "mediatek,mt8173-disp-mutex", .data = (void *)MTK_DISP_MUTEX }, { .compatible = "mediatek,mt2701-disp-pwm", @@ -575,6 +612,8 @@ static SIMPLE_DEV_PM_OPS(mtk_drm_pm_ops, mtk_drm_sys_suspend, static const struct of_device_id mtk_drm_of_ids[] = { { .compatible = "mediatek,mt2701-mmsys", .data = &mt2701_mmsys_driver_data}, + { .compatible = "mediatek,mt2712-mmsys", + .data = &mt2712_mmsys_driver_data}, { .compatible = "mediatek,mt8173-mmsys", .data = &mt8173_mmsys_driver_data}, { } -- GitLab From 06ede493a9d755185ba8a97225ce1352fa5c310c Mon Sep 17 00:00:00 2001 From: Daniel Stone <daniels@collabora.com> Date: Fri, 18 May 2018 14:47:03 +0100 Subject: [PATCH 0525/1506] drm/mtk: Remove impossible internal error We cannot create a framebuffer with no objects, so there's no point testing for it. v2: Remove the error entirely. (Sean, CK, Thierry) Signed-off-by: Daniel Stone <daniels@collabora.com> Cc: Sean Paul <seanpaul@chromium.org> Cc: Thierry Reding <treding@nvidia.com> Cc: CK Hu <ck.hu@mediatek.com> Cc: Philipp Zabel <p.zabel@pengutronix.de> Acked-by: Thierry Reding <treding@nvidia.com> Signed-off-by: CK Hu <ck.hu@mediatek.com> --- drivers/gpu/drm/mediatek/mtk_drm_plane.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.c b/drivers/gpu/drm/mediatek/mtk_drm_plane.c index 2f4b0ffee5989..149fc4372917b 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_plane.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.c @@ -95,11 +95,6 @@ static int mtk_plane_atomic_check(struct drm_plane *plane, if (!fb) return 0; - if (!mtk_fb_get_gem_obj(fb)) { - DRM_DEBUG_KMS("buffer is null\n"); - return -EFAULT; - } - if (!state->crtc) return 0; -- GitLab From 548cb82538582f1b2badbc78df83c46899b6c694 Mon Sep 17 00:00:00 2001 From: Daniel Stone <daniels@collabora.com> Date: Fri, 18 May 2018 14:47:04 +0100 Subject: [PATCH 0526/1506] drm/mtk: Move GEM BO to drm_framebuffer Since drm_framebuffer can now store GEM objects directly, place them there rather than in our own subclass. As this makes the framebuffer create_handle and destroy functions the same as the GEM framebuffer helper, we can reuse those. Signed-off-by: Daniel Stone <daniels@collabora.com> Signed-off-by: CK Hu <ck.hu@mediatek.com> Reviewed-by: Thierry Reding <treding@nvidia.com> Reviewed-by: Sean Paul <seanpaul@chromium.org> Cc: Philipp Zabel <p.zabel@pengutronix.de> --- drivers/gpu/drm/mediatek/mtk_drm_fb.c | 38 ++++-------------------- drivers/gpu/drm/mediatek/mtk_drm_fb.h | 1 - drivers/gpu/drm/mediatek/mtk_drm_plane.c | 2 +- 3 files changed, 6 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_fb.c b/drivers/gpu/drm/mediatek/mtk_drm_fb.c index 0d8d506695f9f..f130e37123b5d 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_fb.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_fb.c @@ -15,6 +15,7 @@ #include <drm/drm_crtc_helper.h> #include <drm/drm_fb_helper.h> #include <drm/drm_gem.h> +#include <drm/drm_gem_framebuffer_helper.h> #include <linux/dma-buf.h> #include <linux/reservation.h> @@ -30,42 +31,13 @@ */ struct mtk_drm_fb { struct drm_framebuffer base; - /* For now we only support a single plane */ - struct drm_gem_object *gem_obj; }; #define to_mtk_fb(x) container_of(x, struct mtk_drm_fb, base) -struct drm_gem_object *mtk_fb_get_gem_obj(struct drm_framebuffer *fb) -{ - struct mtk_drm_fb *mtk_fb = to_mtk_fb(fb); - - return mtk_fb->gem_obj; -} - -static int mtk_drm_fb_create_handle(struct drm_framebuffer *fb, - struct drm_file *file_priv, - unsigned int *handle) -{ - struct mtk_drm_fb *mtk_fb = to_mtk_fb(fb); - - return drm_gem_handle_create(file_priv, mtk_fb->gem_obj, handle); -} - -static void mtk_drm_fb_destroy(struct drm_framebuffer *fb) -{ - struct mtk_drm_fb *mtk_fb = to_mtk_fb(fb); - - drm_framebuffer_cleanup(fb); - - drm_gem_object_put_unlocked(mtk_fb->gem_obj); - - kfree(mtk_fb); -} - static const struct drm_framebuffer_funcs mtk_drm_fb_funcs = { - .create_handle = mtk_drm_fb_create_handle, - .destroy = mtk_drm_fb_destroy, + .create_handle = drm_gem_fb_create_handle, + .destroy = drm_gem_fb_destroy, }; static struct mtk_drm_fb *mtk_drm_framebuffer_init(struct drm_device *dev, @@ -84,7 +56,7 @@ static struct mtk_drm_fb *mtk_drm_framebuffer_init(struct drm_device *dev, drm_helper_mode_fill_fb_struct(dev, &mtk_fb->base, mode); - mtk_fb->gem_obj = obj; + mtk_fb->base.obj[0] = obj; ret = drm_framebuffer_init(dev, &mtk_fb->base, &mtk_drm_fb_funcs); if (ret) { @@ -110,7 +82,7 @@ int mtk_fb_wait(struct drm_framebuffer *fb) if (!fb) return 0; - gem = mtk_fb_get_gem_obj(fb); + gem = fb->obj[0]; if (!gem || !gem->dma_buf || !gem->dma_buf->resv) return 0; diff --git a/drivers/gpu/drm/mediatek/mtk_drm_fb.h b/drivers/gpu/drm/mediatek/mtk_drm_fb.h index 9b2ae345a4e90..7f976b196a154 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_fb.h +++ b/drivers/gpu/drm/mediatek/mtk_drm_fb.h @@ -14,7 +14,6 @@ #ifndef MTK_DRM_FB_H #define MTK_DRM_FB_H -struct drm_gem_object *mtk_fb_get_gem_obj(struct drm_framebuffer *fb); int mtk_fb_wait(struct drm_framebuffer *fb); struct drm_framebuffer *mtk_drm_mode_fb_create(struct drm_device *dev, struct drm_file *file, diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.c b/drivers/gpu/drm/mediatek/mtk_drm_plane.c index 149fc4372917b..f7e6aa1b5b7d1 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_plane.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.c @@ -122,7 +122,7 @@ static void mtk_plane_atomic_update(struct drm_plane *plane, if (!crtc || WARN_ON(!fb)) return; - gem = mtk_fb_get_gem_obj(fb); + gem = fb->obj[0]; mtk_gem = to_mtk_gem_obj(gem); addr = mtk_gem->dma_addr; pitch = fb->pitches[0]; -- GitLab From 57c7f58111806faa0165b88155bff15679024122 Mon Sep 17 00:00:00 2001 From: Daniel Stone <daniels@collabora.com> Date: Fri, 18 May 2018 14:47:05 +0100 Subject: [PATCH 0527/1506] drm/mtk: mtk_drm_fb -> drm_framebuffer Now that mtk_drm_fb is an empty wrapper around drm_framebuffer, we can just delete it. Signed-off-by: Daniel Stone <daniels@collabora.com> Signed-off-by: CK Hu <ck.hu@mediatek.com> Reviewed-by: Thierry Reding <treding@nvidia.com> Reviewed-by: Sean Paul <seanpaul@chromium.org> Cc: Philipp Zabel <p.zabel@pengutronix.de> --- drivers/gpu/drm/mediatek/mtk_drm_fb.c | 40 ++++++++++----------------- 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_fb.c b/drivers/gpu/drm/mediatek/mtk_drm_fb.c index f130e37123b5d..be5f6f1daf554 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_fb.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_fb.c @@ -23,49 +23,37 @@ #include "mtk_drm_fb.h" #include "mtk_drm_gem.h" -/* - * mtk specific framebuffer structure. - * - * @fb: drm framebuffer object. - * @gem_obj: array of gem objects. - */ -struct mtk_drm_fb { - struct drm_framebuffer base; -}; - -#define to_mtk_fb(x) container_of(x, struct mtk_drm_fb, base) - static const struct drm_framebuffer_funcs mtk_drm_fb_funcs = { .create_handle = drm_gem_fb_create_handle, .destroy = drm_gem_fb_destroy, }; -static struct mtk_drm_fb *mtk_drm_framebuffer_init(struct drm_device *dev, +static struct drm_framebuffer *mtk_drm_framebuffer_init(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode, struct drm_gem_object *obj) { - struct mtk_drm_fb *mtk_fb; + struct drm_framebuffer *fb; int ret; if (drm_format_num_planes(mode->pixel_format) != 1) return ERR_PTR(-EINVAL); - mtk_fb = kzalloc(sizeof(*mtk_fb), GFP_KERNEL); - if (!mtk_fb) + fb = kzalloc(sizeof(*fb), GFP_KERNEL); + if (!fb) return ERR_PTR(-ENOMEM); - drm_helper_mode_fill_fb_struct(dev, &mtk_fb->base, mode); + drm_helper_mode_fill_fb_struct(dev, fb, mode); - mtk_fb->base.obj[0] = obj; + fb->obj[0] = obj; - ret = drm_framebuffer_init(dev, &mtk_fb->base, &mtk_drm_fb_funcs); + ret = drm_framebuffer_init(dev, fb, &mtk_drm_fb_funcs); if (ret) { DRM_ERROR("failed to initialize framebuffer\n"); - kfree(mtk_fb); + kfree(fb); return ERR_PTR(ret); } - return mtk_fb; + return fb; } /* @@ -100,7 +88,7 @@ struct drm_framebuffer *mtk_drm_mode_fb_create(struct drm_device *dev, struct drm_file *file, const struct drm_mode_fb_cmd2 *cmd) { - struct mtk_drm_fb *mtk_fb; + struct drm_framebuffer *fb; struct drm_gem_object *gem; unsigned int width = cmd->width; unsigned int height = cmd->height; @@ -123,13 +111,13 @@ struct drm_framebuffer *mtk_drm_mode_fb_create(struct drm_device *dev, goto unreference; } - mtk_fb = mtk_drm_framebuffer_init(dev, cmd, gem); - if (IS_ERR(mtk_fb)) { - ret = PTR_ERR(mtk_fb); + fb = mtk_drm_framebuffer_init(dev, cmd, gem); + if (IS_ERR(fb)) { + ret = PTR_ERR(fb); goto unreference; } - return &mtk_fb->base; + return fb; unreference: drm_gem_object_put_unlocked(gem); -- GitLab From a61b47f672c1ebd56b273a55cfed9621448d253e Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Wed, 27 Jun 2018 12:53:34 +0100 Subject: [PATCH 0528/1506] drm/i915: Wait for engines to idle before retiring In the next^W forthcoming patch, we will start to defer retiring the request from the engine list if it is still active on the submission backend. To preserve the semantics that after wait-for-idle completes the system is idle and fully retired, we need to therefore wait for the backends to idle before calling i915_retire_requests(). Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180627115334.16282-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 858d188dd33bc..5a9cae604e2b8 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3810,10 +3810,13 @@ int i915_gem_wait_for_idle(struct drm_i915_private *i915, unsigned int flags) if (err) return err; } + + err = wait_for_engines(i915); + if (err) + return err; + i915_retire_requests(i915); GEM_BUG_ON(i915->gt.active_requests); - - return wait_for_engines(i915); } else { struct intel_engine_cs *engine; enum intel_engine_id id; @@ -3824,9 +3827,9 @@ int i915_gem_wait_for_idle(struct drm_i915_private *i915, unsigned int flags) if (err) return err; } - - return 0; } + + return 0; } static void __i915_gem_object_flush_for_display(struct drm_i915_gem_object *obj) -- GitLab From 10cfc747835e34c5ee09599c236128067b990723 Mon Sep 17 00:00:00 2001 From: David Lechner <david@lechnology.com> Date: Fri, 25 May 2018 14:36:20 -0500 Subject: [PATCH 0529/1506] MAINTAINERS: fix path to ilitek, ili9225 device tree bindings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes the path to the ilitek,ili9225 device tree binding file. Signed-off-by: David Lechner <david@lechnology.com> Reviewed-by: Noralf Trønnes <noralf@tronnes.org> Link: https://patchwork.freedesktop.org/patch/msgid/20180525193623.15533-2-david@lechnology.com --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index c7fe1c331bb1b..e507c34798ff1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4476,7 +4476,7 @@ DRM DRIVER FOR ILITEK ILI9225 PANELS M: David Lechner <david@lechnology.com> S: Maintained F: drivers/gpu/drm/tinydrm/ili9225.c -F: Documentation/devicetree/bindings/display/ili9225.txt +F: Documentation/devicetree/bindings/display/ilitek,ili9225.txt DRM DRIVER FOR INTEL I810 VIDEO CARDS S: Orphan / Obsolete -- GitLab From bb2a9b6eb1f6d1a6efee629198beafdcb188b851 Mon Sep 17 00:00:00 2001 From: David Lechner <david@lechnology.com> Date: Fri, 25 May 2018 14:36:21 -0500 Subject: [PATCH 0530/1506] dt-bindings: Add vendor prefix for Adafruit This adds a device tree vendor prefix for Adafruit Industries, LLC. Signed-off-by: David Lechner <david@lechnology.com> Acked-by: Rob Herring <robh@kernel.org> Link: https://patchwork.freedesktop.org/patch/msgid/20180525193623.15533-3-david@lechnology.com --- Documentation/devicetree/bindings/vendor-prefixes.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index a38d8bfae19c3..ff7e024ef0f7b 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -8,6 +8,7 @@ abracon Abracon Corporation actions Actions Semiconductor Co., Ltd. active-semi Active-Semi International Inc ad Avionic Design GmbH +adafruit Adafruit Industries, LLC adapteva Adapteva, Inc. adaptrum Adaptrum, Inc. adh AD Holdings Plc. -- GitLab From 7b59d2d8d7980522bb4b532dcecb39bac3639726 Mon Sep 17 00:00:00 2001 From: David Lechner <david@lechnology.com> Date: Fri, 25 May 2018 14:36:22 -0500 Subject: [PATCH 0531/1506] dt-bindings: new binding for Ilitek ILI9341 display panels This adds a new binding for Ilitek ILI9341 display panels. It includes a compatible string for one display (more can be added in the future). The YX240QV29-T panel[1] is found, for example, in an Adafruit breakout board[2] and in Mindsensors' PiStorms[3]. The vendor prefix "adafruit" is used because the actual vendor is not known, but Adafruit is the most common source for a product that contains this panel. [1]: https://cdn-learn.adafruit.com/assets/assets/000/046/879/original/SPEC-YX240QV29-T_Rev.A__1_.pdf [2]: https://www.adafruit.com/product/2478 [3]: http://www.mindsensors.com/stem-with-robotics/13-pistorms-v2-base-kit-raspberry-pi-brain-for-lego-robot Signed-off-by: David Lechner <david@lechnology.com> Reviewed-by: Rob Herring <robh@kernel.org> Link: https://patchwork.freedesktop.org/patch/msgid/20180525193623.15533-4-david@lechnology.com --- .../bindings/display/ilitek,ili9341.txt | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/ilitek,ili9341.txt diff --git a/Documentation/devicetree/bindings/display/ilitek,ili9341.txt b/Documentation/devicetree/bindings/display/ilitek,ili9341.txt new file mode 100644 index 0000000000000..169b32e4ee4ed --- /dev/null +++ b/Documentation/devicetree/bindings/display/ilitek,ili9341.txt @@ -0,0 +1,27 @@ +Ilitek ILI9341 display panels + +This binding is for display panels using an Ilitek ILI9341 controller in SPI +mode. + +Required properties: +- compatible: "adafruit,yx240qv29", "ilitek,ili9341" +- dc-gpios: D/C pin +- reset-gpios: Reset pin + +The node for this driver must be a child node of a SPI controller, hence +all mandatory properties described in ../spi/spi-bus.txt must be specified. + +Optional properties: +- rotation: panel rotation in degrees counter clockwise (0,90,180,270) +- backlight: phandle of the backlight device attached to the panel + +Example: + display@0{ + compatible = "adafruit,yx240qv29", "ilitek,ili9341"; + reg = <0>; + spi-max-frequency = <32000000>; + dc-gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio0 8 GPIO_ACTIVE_HIGH>; + rotation = <270>; + backlight = <&backlight>; + }; -- GitLab From 3fa0e8f6f9609ba195b8b3e4cf3e61420451fc7b Mon Sep 17 00:00:00 2001 From: David Lechner <david@lechnology.com> Date: Fri, 25 May 2018 14:36:23 -0500 Subject: [PATCH 0532/1506] drm/tinydrm: new driver for ILI9341 display panels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds a new driver for display panels that use the Ilitek ILI9341 controller. It currently supports a single display panel, namely the YX240QV29-T (e.g. Adafruit 2.4" TFT). The init sequence is from the Adafruit Python library for the ILI9341 controller. https://github.com/adafruit/Adafruit_Python_ILI9341 Signed-off-by: David Lechner <david@lechnology.com> Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com> Reviewed-by: Noralf Trønnes <noralf@tronnes.org> Link: https://patchwork.freedesktop.org/patch/msgid/20180525193623.15533-5-david@lechnology.com --- MAINTAINERS | 6 + drivers/gpu/drm/tinydrm/Kconfig | 10 ++ drivers/gpu/drm/tinydrm/Makefile | 1 + drivers/gpu/drm/tinydrm/ili9341.c | 233 ++++++++++++++++++++++++++++++ 4 files changed, 250 insertions(+) create mode 100644 drivers/gpu/drm/tinydrm/ili9341.c diff --git a/MAINTAINERS b/MAINTAINERS index e507c34798ff1..e3e44326e5535 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4478,6 +4478,12 @@ S: Maintained F: drivers/gpu/drm/tinydrm/ili9225.c F: Documentation/devicetree/bindings/display/ilitek,ili9225.txt +DRM DRIVER FOR ILITEK ILI9341 PANELS +M: David Lechner <david@lechnology.com> +S: Maintained +F: drivers/gpu/drm/tinydrm/ili9341.c +F: Documentation/devicetree/bindings/display/ilitek,ili9341.txt + DRM DRIVER FOR INTEL I810 VIDEO CARDS S: Orphan / Obsolete F: drivers/gpu/drm/i810/ diff --git a/drivers/gpu/drm/tinydrm/Kconfig b/drivers/gpu/drm/tinydrm/Kconfig index 4592a5e3f20bf..7a8008b0783fc 100644 --- a/drivers/gpu/drm/tinydrm/Kconfig +++ b/drivers/gpu/drm/tinydrm/Kconfig @@ -20,6 +20,16 @@ config TINYDRM_ILI9225 If M is selected the module will be called ili9225. +config TINYDRM_ILI9341 + tristate "DRM support for ILI9341 display panels" + depends on DRM_TINYDRM && SPI + select TINYDRM_MIPI_DBI + help + DRM driver for the following Ilitek ILI9341 panels: + * YX240QV29-T 2.4" 240x320 TFT (Adafruit 2.4") + + If M is selected the module will be called ili9341. + config TINYDRM_MI0283QT tristate "DRM support for MI0283QT" depends on DRM_TINYDRM && SPI diff --git a/drivers/gpu/drm/tinydrm/Makefile b/drivers/gpu/drm/tinydrm/Makefile index 49a111929724a..14d99080665a4 100644 --- a/drivers/gpu/drm/tinydrm/Makefile +++ b/drivers/gpu/drm/tinydrm/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_TINYDRM_MIPI_DBI) += mipi-dbi.o # Displays obj-$(CONFIG_TINYDRM_ILI9225) += ili9225.o +obj-$(CONFIG_TINYDRM_ILI9341) += ili9341.o obj-$(CONFIG_TINYDRM_MI0283QT) += mi0283qt.o obj-$(CONFIG_TINYDRM_REPAPER) += repaper.o obj-$(CONFIG_TINYDRM_ST7586) += st7586.o diff --git a/drivers/gpu/drm/tinydrm/ili9341.c b/drivers/gpu/drm/tinydrm/ili9341.c new file mode 100644 index 0000000000000..8864dcde6edca --- /dev/null +++ b/drivers/gpu/drm/tinydrm/ili9341.c @@ -0,0 +1,233 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * DRM driver for Ilitek ILI9341 panels + * + * Copyright 2018 David Lechner <david@lechnology.com> + * + * Based on mi0283qt.c: + * Copyright 2016 Noralf Trønnes + */ + +#include <linux/backlight.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/property.h> +#include <linux/spi/spi.h> + +#include <drm/drm_fb_helper.h> +#include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_modeset_helper.h> +#include <drm/tinydrm/mipi-dbi.h> +#include <drm/tinydrm/tinydrm-helpers.h> +#include <video/mipi_display.h> + +#define ILI9341_FRMCTR1 0xb1 +#define ILI9341_DISCTRL 0xb6 +#define ILI9341_ETMOD 0xb7 + +#define ILI9341_PWCTRL1 0xc0 +#define ILI9341_PWCTRL2 0xc1 +#define ILI9341_VMCTRL1 0xc5 +#define ILI9341_VMCTRL2 0xc7 +#define ILI9341_PWCTRLA 0xcb +#define ILI9341_PWCTRLB 0xcf + +#define ILI9341_PGAMCTRL 0xe0 +#define ILI9341_NGAMCTRL 0xe1 +#define ILI9341_DTCTRLA 0xe8 +#define ILI9341_DTCTRLB 0xea +#define ILI9341_PWRSEQ 0xed + +#define ILI9341_EN3GAM 0xf2 +#define ILI9341_PUMPCTRL 0xf7 + +#define ILI9341_MADCTL_BGR BIT(3) +#define ILI9341_MADCTL_MV BIT(5) +#define ILI9341_MADCTL_MX BIT(6) +#define ILI9341_MADCTL_MY BIT(7) + +static void yx240qv29_enable(struct drm_simple_display_pipe *pipe, + struct drm_crtc_state *crtc_state, + struct drm_plane_state *plane_state) +{ + struct tinydrm_device *tdev = pipe_to_tinydrm(pipe); + struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev); + u8 addr_mode; + int ret; + + DRM_DEBUG_KMS("\n"); + + ret = mipi_dbi_poweron_conditional_reset(mipi); + if (ret < 0) + return; + if (ret == 1) + goto out_enable; + + mipi_dbi_command(mipi, MIPI_DCS_SET_DISPLAY_OFF); + + mipi_dbi_command(mipi, ILI9341_PWCTRLB, 0x00, 0xc1, 0x30); + mipi_dbi_command(mipi, ILI9341_PWRSEQ, 0x64, 0x03, 0x12, 0x81); + mipi_dbi_command(mipi, ILI9341_DTCTRLA, 0x85, 0x00, 0x78); + mipi_dbi_command(mipi, ILI9341_PWCTRLA, 0x39, 0x2c, 0x00, 0x34, 0x02); + mipi_dbi_command(mipi, ILI9341_PUMPCTRL, 0x20); + mipi_dbi_command(mipi, ILI9341_DTCTRLB, 0x00, 0x00); + + /* Power Control */ + mipi_dbi_command(mipi, ILI9341_PWCTRL1, 0x23); + mipi_dbi_command(mipi, ILI9341_PWCTRL2, 0x10); + /* VCOM */ + mipi_dbi_command(mipi, ILI9341_VMCTRL1, 0x3e, 0x28); + mipi_dbi_command(mipi, ILI9341_VMCTRL2, 0x86); + + /* Memory Access Control */ + mipi_dbi_command(mipi, MIPI_DCS_SET_PIXEL_FORMAT, MIPI_DCS_PIXEL_FMT_16BIT); + + /* Frame Rate */ + mipi_dbi_command(mipi, ILI9341_FRMCTR1, 0x00, 0x1b); + + /* Gamma */ + mipi_dbi_command(mipi, ILI9341_EN3GAM, 0x00); + mipi_dbi_command(mipi, MIPI_DCS_SET_GAMMA_CURVE, 0x01); + mipi_dbi_command(mipi, ILI9341_PGAMCTRL, + 0x0f, 0x31, 0x2b, 0x0c, 0x0e, 0x08, 0x4e, 0xf1, + 0x37, 0x07, 0x10, 0x03, 0x0e, 0x09, 0x00); + mipi_dbi_command(mipi, ILI9341_NGAMCTRL, + 0x00, 0x0e, 0x14, 0x03, 0x11, 0x07, 0x31, 0xc1, + 0x48, 0x08, 0x0f, 0x0c, 0x31, 0x36, 0x0f); + + /* DDRAM */ + mipi_dbi_command(mipi, ILI9341_ETMOD, 0x07); + + /* Display */ + mipi_dbi_command(mipi, ILI9341_DISCTRL, 0x08, 0x82, 0x27, 0x00); + mipi_dbi_command(mipi, MIPI_DCS_EXIT_SLEEP_MODE); + msleep(100); + + mipi_dbi_command(mipi, MIPI_DCS_SET_DISPLAY_ON); + msleep(100); + +out_enable: + switch (mipi->rotation) { + default: + addr_mode = ILI9341_MADCTL_MX; + break; + case 90: + addr_mode = ILI9341_MADCTL_MV; + break; + case 180: + addr_mode = ILI9341_MADCTL_MY; + break; + case 270: + addr_mode = ILI9341_MADCTL_MV | ILI9341_MADCTL_MY | + ILI9341_MADCTL_MX; + break; + } + addr_mode |= ILI9341_MADCTL_BGR; + mipi_dbi_command(mipi, MIPI_DCS_SET_ADDRESS_MODE, addr_mode); + mipi_dbi_enable_flush(mipi, crtc_state, plane_state); +} + +static const struct drm_simple_display_pipe_funcs ili9341_pipe_funcs = { + .enable = yx240qv29_enable, + .disable = mipi_dbi_pipe_disable, + .update = tinydrm_display_pipe_update, + .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb, +}; + +static const struct drm_display_mode yx240qv29_mode = { + TINYDRM_MODE(240, 320, 37, 49), +}; + +DEFINE_DRM_GEM_CMA_FOPS(ili9341_fops); + +static struct drm_driver ili9341_driver = { + .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_ATOMIC, + .fops = &ili9341_fops, + TINYDRM_GEM_DRIVER_OPS, + .lastclose = drm_fb_helper_lastclose, + .debugfs_init = mipi_dbi_debugfs_init, + .name = "ili9341", + .desc = "Ilitek ILI9341", + .date = "20180514", + .major = 1, + .minor = 0, +}; + +static const struct of_device_id ili9341_of_match[] = { + { .compatible = "adafruit,yx240qv29" }, + { } +}; +MODULE_DEVICE_TABLE(of, ili9341_of_match); + +static const struct spi_device_id ili9341_id[] = { + { "yx240qv29", 0 }, + { } +}; +MODULE_DEVICE_TABLE(spi, ili9341_id); + +static int ili9341_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + struct mipi_dbi *mipi; + struct gpio_desc *dc; + u32 rotation = 0; + int ret; + + mipi = devm_kzalloc(dev, sizeof(*mipi), GFP_KERNEL); + if (!mipi) + return -ENOMEM; + + mipi->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(mipi->reset)) { + DRM_DEV_ERROR(dev, "Failed to get gpio 'reset'\n"); + return PTR_ERR(mipi->reset); + } + + dc = devm_gpiod_get_optional(dev, "dc", GPIOD_OUT_LOW); + if (IS_ERR(dc)) { + DRM_DEV_ERROR(dev, "Failed to get gpio 'dc'\n"); + return PTR_ERR(dc); + } + + mipi->backlight = devm_of_find_backlight(dev); + if (IS_ERR(mipi->backlight)) + return PTR_ERR(mipi->backlight); + + device_property_read_u32(dev, "rotation", &rotation); + + ret = mipi_dbi_spi_init(spi, mipi, dc); + if (ret) + return ret; + + ret = mipi_dbi_init(&spi->dev, mipi, &ili9341_pipe_funcs, + &ili9341_driver, &yx240qv29_mode, rotation); + if (ret) + return ret; + + spi_set_drvdata(spi, mipi); + + return devm_tinydrm_register(&mipi->tinydrm); +} + +static void ili9341_shutdown(struct spi_device *spi) +{ + struct mipi_dbi *mipi = spi_get_drvdata(spi); + + tinydrm_shutdown(&mipi->tinydrm); +} + +static struct spi_driver ili9341_spi_driver = { + .driver = { + .name = "ili9341", + .of_match_table = ili9341_of_match, + }, + .id_table = ili9341_id, + .probe = ili9341_probe, + .shutdown = ili9341_shutdown, +}; +module_spi_driver(ili9341_spi_driver); + +MODULE_DESCRIPTION("Ilitek ILI9341 DRM driver"); +MODULE_AUTHOR("David Lechner <david@lechnology.com>"); +MODULE_LICENSE("GPL"); -- GitLab From 59a9c39544cd1e5952c2a33028d71aa8180648f8 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec <jernej.skrabec@siol.net> Date: Mon, 25 Jun 2018 14:02:44 +0200 Subject: [PATCH 0533/1506] dt-bindings: display: sunxi-drm: Add TCON TOP description TCON TOP main purpose is to configure whole display pipeline. It determines relationships between mixers and TCONs, selects source TCON for HDMI, muxes LCD and TV encoder GPIO output, selects TV encoder clock source and contains additional TV TCON and DSI gates. Reviewed-by: Rob Herring <robh@kernel.org> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180625120304.7543-5-jernej.skrabec@siol.net --- .../bindings/display/sunxi/sun4i-drm.txt | 56 +++++++++++++++++++ include/dt-bindings/clock/sun8i-tcon-top.h | 11 ++++ 2 files changed, 67 insertions(+) create mode 100644 include/dt-bindings/clock/sun8i-tcon-top.h diff --git a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt index 3346c1e2a7a00..fe31b15107179 100644 --- a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt +++ b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt @@ -187,6 +187,62 @@ And on the A23, A31, A31s and A33, you need one more clock line: - 'lvds-alt': An alternative clock source, separate from the TCON channel 0 clock, that can be used to drive the LVDS clock +TCON TOP +-------- + +TCON TOPs main purpose is to configure whole display pipeline. It determines +relationships between mixers and TCONs, selects source TCON for HDMI, muxes +LCD and TV encoder GPIO output, selects TV encoder clock source and contains +additional TV TCON and DSI gates. + +It allows display pipeline to be configured in very different ways: + + / LCD0/LVDS0 + / [0] TCON-LCD0 + | \ MIPI DSI + mixer0 | + \ / [1] TCON-LCD1 - LCD1/LVDS1 + TCON-TOP + / \ [2] TCON-TV0 [0] - TVE0/RGB + mixer1 | \ + | TCON-TOP - HDMI + | / + \ [3] TCON-TV1 [1] - TVE1/RGB + +Note that both TCON TOP references same physical unit. Both mixers can be +connected to any TCON. + +Required properties: + - compatible: value must be one of: + * allwinner,sun8i-r40-tcon-top + - reg: base address and size of the memory-mapped region. + - clocks: phandle to the clocks feeding the TCON TOP + * bus: TCON TOP interface clock + * tcon-tv0: TCON TV0 clock + * tve0: TVE0 clock + * tcon-tv1: TCON TV1 clock + * tve1: TVE0 clock + * dsi: MIPI DSI clock + - clock-names: clock name mentioned above + - resets: phandle to the reset line driving the TCON TOP + - #clock-cells : must contain 1 + - clock-output-names: Names of clocks created for TCON TV0 channel clock, + TCON TV1 channel clock and DSI channel clock, in that order. + +- ports: A ports node with endpoint definitions as defined in + Documentation/devicetree/bindings/media/video-interfaces.txt. 6 ports should + be defined: + * port 0 is input for mixer0 mux + * port 1 is output for mixer0 mux + * port 2 is input for mixer1 mux + * port 3 is output for mixer1 mux + * port 4 is input for HDMI mux + * port 5 is output for HDMI mux + All output endpoints for mixer muxes and input endpoints for HDMI mux should + have reg property with the id of the target TCON, as shown in above graph + (0-3 for mixer muxes and 0-1 for HDMI mux). All ports should have only one + endpoint connected to remote endpoint. + DRC --- diff --git a/include/dt-bindings/clock/sun8i-tcon-top.h b/include/dt-bindings/clock/sun8i-tcon-top.h new file mode 100644 index 0000000000000..25164d7678353 --- /dev/null +++ b/include/dt-bindings/clock/sun8i-tcon-top.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ +/* Copyright (C) 2018 Jernej Skrabec <jernej.skrabec@siol.net> */ + +#ifndef _DT_BINDINGS_CLOCK_SUN8I_TCON_TOP_H_ +#define _DT_BINDINGS_CLOCK_SUN8I_TCON_TOP_H_ + +#define CLK_TCON_TOP_TV0 0 +#define CLK_TCON_TOP_TV1 1 +#define CLK_TCON_TOP_DSI 2 + +#endif /* _DT_BINDINGS_CLOCK_SUN8I_TCON_TOP_H_ */ -- GitLab From 19f3ebed3f3612f97ee28af26d53656f5776f89a Mon Sep 17 00:00:00 2001 From: Jernej Skrabec <jernej.skrabec@siol.net> Date: Mon, 25 Jun 2018 14:02:45 +0200 Subject: [PATCH 0534/1506] drm/sun4i: Add TCON TOP driver As already described in DT binding, TCON TOP is responsible for configuring display pipeline. In this initial driver focus is on HDMI pipeline, so TVE and LCD configuration is not implemented. Implemented features: - HDMI source selection - clock driver (TCON and DSI gating) - connecting mixers and TCONS Something similar also existed in previous SoCs, except that it was part of first TCON. Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180625120304.7543-6-jernej.skrabec@siol.net --- drivers/gpu/drm/sun4i/Makefile | 2 +- drivers/gpu/drm/sun4i/sun8i_tcon_top.c | 300 +++++++++++++++++++++++++ drivers/gpu/drm/sun4i/sun8i_tcon_top.h | 40 ++++ 3 files changed, 341 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/sun4i/sun8i_tcon_top.c create mode 100644 drivers/gpu/drm/sun4i/sun8i_tcon_top.h diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile index 2589f4acd5ae2..14f420f1d4ae9 100644 --- a/drivers/gpu/drm/sun4i/Makefile +++ b/drivers/gpu/drm/sun4i/Makefile @@ -36,4 +36,4 @@ obj-$(CONFIG_DRM_SUN4I_BACKEND) += sun4i-backend.o sun4i-frontend.o obj-$(CONFIG_DRM_SUN4I_HDMI) += sun4i-drm-hdmi.o obj-$(CONFIG_DRM_SUN6I_DSI) += sun6i-dsi.o obj-$(CONFIG_DRM_SUN8I_DW_HDMI) += sun8i-drm-hdmi.o -obj-$(CONFIG_DRM_SUN8I_MIXER) += sun8i-mixer.o +obj-$(CONFIG_DRM_SUN8I_MIXER) += sun8i-mixer.o sun8i_tcon_top.o diff --git a/drivers/gpu/drm/sun4i/sun8i_tcon_top.c b/drivers/gpu/drm/sun4i/sun8i_tcon_top.c new file mode 100644 index 0000000000000..8da0460e0028c --- /dev/null +++ b/drivers/gpu/drm/sun4i/sun8i_tcon_top.c @@ -0,0 +1,300 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (c) 2018 Jernej Skrabec <jernej.skrabec@siol.net> */ + +#include <drm/drmP.h> + +#include <dt-bindings/clock/sun8i-tcon-top.h> + +#include <linux/bitfield.h> +#include <linux/component.h> +#include <linux/device.h> +#include <linux/module.h> +#include <linux/of_graph.h> +#include <linux/platform_device.h> + +#include "sun8i_tcon_top.h" + +static int sun8i_tcon_top_get_connected_ep_id(struct device_node *node, + int port_id) +{ + struct device_node *ep, *remote, *port; + struct of_endpoint endpoint; + + port = of_graph_get_port_by_id(node, port_id); + if (!port) + return -ENOENT; + + for_each_available_child_of_node(port, ep) { + remote = of_graph_get_remote_port_parent(ep); + if (!remote) + continue; + + if (of_device_is_available(remote)) { + of_graph_parse_endpoint(ep, &endpoint); + + of_node_put(remote); + + return endpoint.id; + } + + of_node_put(remote); + } + + return -ENOENT; +} + +static struct clk_hw *sun8i_tcon_top_register_gate(struct device *dev, + struct clk *parent, + void __iomem *regs, + spinlock_t *lock, + u8 bit, int name_index) +{ + const char *clk_name, *parent_name; + int ret; + + parent_name = __clk_get_name(parent); + ret = of_property_read_string_index(dev->of_node, + "clock-output-names", name_index, + &clk_name); + if (ret) + return ERR_PTR(ret); + + return clk_hw_register_gate(dev, clk_name, parent_name, + CLK_SET_RATE_PARENT, + regs + TCON_TOP_GATE_SRC_REG, + bit, 0, lock); +}; + +static int sun8i_tcon_top_bind(struct device *dev, struct device *master, + void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + struct clk *dsi, *tcon_tv0, *tcon_tv1, *tve0, *tve1; + struct clk_hw_onecell_data *clk_data; + struct sun8i_tcon_top *tcon_top; + bool mixer0_unused = false; + struct resource *res; + void __iomem *regs; + int ret, i, id; + u32 val; + + tcon_top = devm_kzalloc(dev, sizeof(*tcon_top), GFP_KERNEL); + if (!tcon_top) + return -ENOMEM; + + clk_data = devm_kzalloc(dev, sizeof(*clk_data) + + sizeof(*clk_data->hws) * CLK_NUM, + GFP_KERNEL); + if (!clk_data) + return -ENOMEM; + tcon_top->clk_data = clk_data; + + spin_lock_init(&tcon_top->reg_lock); + + tcon_top->rst = devm_reset_control_get(dev, NULL); + if (IS_ERR(tcon_top->rst)) { + dev_err(dev, "Couldn't get our reset line\n"); + return PTR_ERR(tcon_top->rst); + } + + tcon_top->bus = devm_clk_get(dev, "bus"); + if (IS_ERR(tcon_top->bus)) { + dev_err(dev, "Couldn't get the bus clock\n"); + return PTR_ERR(tcon_top->bus); + } + + dsi = devm_clk_get(dev, "dsi"); + if (IS_ERR(dsi)) { + dev_err(dev, "Couldn't get the dsi clock\n"); + return PTR_ERR(dsi); + } + + tcon_tv0 = devm_clk_get(dev, "tcon-tv0"); + if (IS_ERR(tcon_tv0)) { + dev_err(dev, "Couldn't get the tcon-tv0 clock\n"); + return PTR_ERR(tcon_tv0); + } + + tcon_tv1 = devm_clk_get(dev, "tcon-tv1"); + if (IS_ERR(tcon_tv1)) { + dev_err(dev, "Couldn't get the tcon-tv1 clock\n"); + return PTR_ERR(tcon_tv1); + } + + tve0 = devm_clk_get(dev, "tve0"); + if (IS_ERR(tve0)) { + dev_err(dev, "Couldn't get the tve0 clock\n"); + return PTR_ERR(tve0); + } + + tve1 = devm_clk_get(dev, "tve1"); + if (IS_ERR(tve1)) { + dev_err(dev, "Couldn't get the tve1 clock\n"); + return PTR_ERR(tve1); + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + regs = devm_ioremap_resource(dev, res); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + ret = reset_control_deassert(tcon_top->rst); + if (ret) { + dev_err(dev, "Could not deassert ctrl reset control\n"); + return ret; + } + + ret = clk_prepare_enable(tcon_top->bus); + if (ret) { + dev_err(dev, "Could not enable bus clock\n"); + goto err_assert_reset; + } + + val = 0; + + /* check if HDMI mux output is connected */ + if (sun8i_tcon_top_get_connected_ep_id(dev->of_node, 5) >= 0) { + /* find HDMI input endpoint id, if it is connected at all*/ + id = sun8i_tcon_top_get_connected_ep_id(dev->of_node, 4); + if (id >= 0) + val = FIELD_PREP(TCON_TOP_HDMI_SRC_MSK, id + 1); + else + DRM_DEBUG_DRIVER("TCON TOP HDMI input is not connected\n"); + } else { + DRM_DEBUG_DRIVER("TCON TOP HDMI output is not connected\n"); + } + + writel(val, regs + TCON_TOP_GATE_SRC_REG); + + val = 0; + + /* process mixer0 mux output */ + id = sun8i_tcon_top_get_connected_ep_id(dev->of_node, 1); + if (id >= 0) { + val = FIELD_PREP(TCON_TOP_PORT_DE0_MSK, id); + } else { + DRM_DEBUG_DRIVER("TCON TOP mixer0 output is not connected\n"); + mixer0_unused = true; + } + + /* process mixer1 mux output */ + id = sun8i_tcon_top_get_connected_ep_id(dev->of_node, 3); + if (id >= 0) { + val |= FIELD_PREP(TCON_TOP_PORT_DE1_MSK, id); + + /* + * mixer0 mux has priority over mixer1 mux. We have to + * make sure mixer0 doesn't overtake TCON from mixer1. + */ + if (mixer0_unused && id == 0) + val |= FIELD_PREP(TCON_TOP_PORT_DE0_MSK, 1); + } else { + DRM_DEBUG_DRIVER("TCON TOP mixer1 output is not connected\n"); + } + + writel(val, regs + TCON_TOP_PORT_SEL_REG); + + /* + * TCON TOP has two muxes, which select parent clock for each TCON TV + * channel clock. Parent could be either TCON TV or TVE clock. For now + * we leave this fixed to TCON TV, since TVE driver for R40 is not yet + * implemented. Once it is, graph needs to be traversed to determine + * if TVE is active on each TCON TV. If it is, mux should be switched + * to TVE clock parent. + */ + clk_data->hws[CLK_TCON_TOP_TV0] = + sun8i_tcon_top_register_gate(dev, tcon_tv0, regs, + &tcon_top->reg_lock, + TCON_TOP_TCON_TV0_GATE, 0); + + clk_data->hws[CLK_TCON_TOP_TV1] = + sun8i_tcon_top_register_gate(dev, tcon_tv1, regs, + &tcon_top->reg_lock, + TCON_TOP_TCON_TV1_GATE, 1); + + clk_data->hws[CLK_TCON_TOP_DSI] = + sun8i_tcon_top_register_gate(dev, dsi, regs, + &tcon_top->reg_lock, + TCON_TOP_TCON_DSI_GATE, 2); + + for (i = 0; i < CLK_NUM; i++) + if (IS_ERR(clk_data->hws[i])) { + ret = PTR_ERR(clk_data->hws[i]); + goto err_unregister_gates; + } + + clk_data->num = CLK_NUM; + + ret = of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, + clk_data); + if (ret) + goto err_unregister_gates; + + dev_set_drvdata(dev, tcon_top); + + return 0; + +err_unregister_gates: + for (i = 0; i < CLK_NUM; i++) + if (clk_data->hws[i]) + clk_hw_unregister_gate(clk_data->hws[i]); + clk_disable_unprepare(tcon_top->bus); +err_assert_reset: + reset_control_assert(tcon_top->rst); + + return ret; +} + +static void sun8i_tcon_top_unbind(struct device *dev, struct device *master, + void *data) +{ + struct sun8i_tcon_top *tcon_top = dev_get_drvdata(dev); + struct clk_hw_onecell_data *clk_data = tcon_top->clk_data; + int i; + + of_clk_del_provider(dev->of_node); + for (i = 0; i < CLK_NUM; i++) + clk_hw_unregister_gate(clk_data->hws[i]); + + clk_disable_unprepare(tcon_top->bus); + reset_control_assert(tcon_top->rst); +} + +static const struct component_ops sun8i_tcon_top_ops = { + .bind = sun8i_tcon_top_bind, + .unbind = sun8i_tcon_top_unbind, +}; + +static int sun8i_tcon_top_probe(struct platform_device *pdev) +{ + return component_add(&pdev->dev, &sun8i_tcon_top_ops); +} + +static int sun8i_tcon_top_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &sun8i_tcon_top_ops); + + return 0; +} + +/* sun4i_drv uses this list to check if a device node is a TCON TOP */ +const struct of_device_id sun8i_tcon_top_of_table[] = { + { .compatible = "allwinner,sun8i-r40-tcon-top" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, sun8i_tcon_top_of_table); +EXPORT_SYMBOL(sun8i_tcon_top_of_table); + +static struct platform_driver sun8i_tcon_top_platform_driver = { + .probe = sun8i_tcon_top_probe, + .remove = sun8i_tcon_top_remove, + .driver = { + .name = "sun8i-tcon-top", + .of_match_table = sun8i_tcon_top_of_table, + }, +}; +module_platform_driver(sun8i_tcon_top_platform_driver); + +MODULE_AUTHOR("Jernej Skrabec <jernej.skrabec@siol.net>"); +MODULE_DESCRIPTION("Allwinner R40 TCON TOP driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/sun4i/sun8i_tcon_top.h b/drivers/gpu/drm/sun4i/sun8i_tcon_top.h new file mode 100644 index 0000000000000..39838bbfeaee9 --- /dev/null +++ b/drivers/gpu/drm/sun4i/sun8i_tcon_top.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2018 Jernej Skrabec <jernej.skrabec@siol.net> */ + +#ifndef _SUN8I_TCON_TOP_H_ +#define _SUN8I_TCON_TOP_H_ + +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/reset.h> +#include <linux/spinlock.h> + +#define TCON_TOP_TCON_TV_SETUP_REG 0x00 + +#define TCON_TOP_PORT_SEL_REG 0x1C +#define TCON_TOP_PORT_DE0_MSK GENMASK(1, 0) +#define TCON_TOP_PORT_DE1_MSK GENMASK(5, 4) + +#define TCON_TOP_GATE_SRC_REG 0x20 +#define TCON_TOP_HDMI_SRC_MSK GENMASK(29, 28) +#define TCON_TOP_TCON_TV1_GATE 24 +#define TCON_TOP_TCON_TV0_GATE 20 +#define TCON_TOP_TCON_DSI_GATE 16 + +#define CLK_NUM 3 + +struct sun8i_tcon_top { + struct clk *bus; + struct clk_hw_onecell_data *clk_data; + struct reset_control *rst; + + /* + * spinlock is used to synchronize access to same + * register where multiple clock gates can be set. + */ + spinlock_t reg_lock; +}; + +extern const struct of_device_id sun8i_tcon_top_of_table[]; + +#endif /* _SUN8I_TCON_TOP_H_ */ -- GitLab From 367c359aa8637b15ee8df6335c5a29b7623966ec Mon Sep 17 00:00:00 2001 From: Jernej Skrabec <jernej.skrabec@siol.net> Date: Mon, 25 Jun 2018 14:02:46 +0200 Subject: [PATCH 0535/1506] drm/sun4i: Fix releasing node when enumerating enpoints sun4i_drv_add_endpoints() has a memory leak since it uses of_node_put() when remote is equal to NULL and does nothing when remote has a valid pointer. Invert the logic to fix memory leak. Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180625120304.7543-7-jernej.skrabec@siol.net --- drivers/gpu/drm/sun4i/sun4i_drv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c index 50d19605c38fb..e15fa2389e3f4 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.c +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c @@ -283,7 +283,6 @@ static int sun4i_drv_add_endpoints(struct device *dev, remote = of_graph_get_remote_port_parent(ep); if (!remote) { DRM_DEBUG_DRIVER("Error retrieving the output node\n"); - of_node_put(remote); continue; } @@ -297,11 +296,13 @@ static int sun4i_drv_add_endpoints(struct device *dev, if (of_graph_parse_endpoint(ep, &endpoint)) { DRM_DEBUG_DRIVER("Couldn't parse endpoint\n"); + of_node_put(remote); continue; } if (!endpoint.id) { DRM_DEBUG_DRIVER("Endpoint is our panel... skipping\n"); + of_node_put(remote); continue; } } -- GitLab From 71f4796ac09d6b634f4756388cfdbe9d778499e9 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec <jernej.skrabec@siol.net> Date: Mon, 25 Jun 2018 14:02:47 +0200 Subject: [PATCH 0536/1506] drm/sun4i: Split out code for enumerating endpoints in output port Until now, each node has one input port and one output port. However, with TCON TOP this is no longer true. It has 3 input and 3 output ports. In order to prepare to this situation, split out the code which checks all endpoints in input port and adds available components to fifo. This patch doesn't do any functional change. Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180625120304.7543-8-jernej.skrabec@siol.net --- drivers/gpu/drm/sun4i/sun4i_drv.c | 84 +++++++++++++++++-------------- 1 file changed, 46 insertions(+), 38 deletions(-) diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c index e15fa2389e3f4..20193d6f33baa 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.c +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c @@ -231,12 +231,55 @@ struct endpoint_list { DECLARE_KFIFO(fifo, struct device_node *, 16); }; +static void sun4i_drv_traverse_endpoints(struct endpoint_list *list, + struct device_node *node, + int port_id) +{ + struct device_node *ep, *remote, *port; + + port = of_graph_get_port_by_id(node, port_id); + if (!port) { + DRM_DEBUG_DRIVER("No output to bind on port %d\n", port_id); + return; + } + + for_each_available_child_of_node(port, ep) { + remote = of_graph_get_remote_port_parent(ep); + if (!remote) { + DRM_DEBUG_DRIVER("Error retrieving the output node\n"); + continue; + } + + /* + * If the node is our TCON, the first port is used for + * panel or bridges, and will not be part of the + * component framework. + */ + if (sun4i_drv_node_is_tcon(node)) { + struct of_endpoint endpoint; + + if (of_graph_parse_endpoint(ep, &endpoint)) { + DRM_DEBUG_DRIVER("Couldn't parse endpoint\n"); + of_node_put(remote); + continue; + } + + if (!endpoint.id) { + DRM_DEBUG_DRIVER("Endpoint is our panel... skipping\n"); + of_node_put(remote); + continue; + } + } + + kfifo_put(&list->fifo, remote); + } +} + static int sun4i_drv_add_endpoints(struct device *dev, struct endpoint_list *list, struct component_match **match, struct device_node *node) { - struct device_node *port, *ep, *remote; int count = 0; /* @@ -272,43 +315,8 @@ static int sun4i_drv_add_endpoints(struct device *dev, count++; } - /* Inputs are listed first, then outputs */ - port = of_graph_get_port_by_id(node, 1); - if (!port) { - DRM_DEBUG_DRIVER("No output to bind\n"); - return count; - } - - for_each_available_child_of_node(port, ep) { - remote = of_graph_get_remote_port_parent(ep); - if (!remote) { - DRM_DEBUG_DRIVER("Error retrieving the output node\n"); - continue; - } - - /* - * If the node is our TCON, the first port is used for - * panel or bridges, and will not be part of the - * component framework. - */ - if (sun4i_drv_node_is_tcon(node)) { - struct of_endpoint endpoint; - - if (of_graph_parse_endpoint(ep, &endpoint)) { - DRM_DEBUG_DRIVER("Couldn't parse endpoint\n"); - of_node_put(remote); - continue; - } - - if (!endpoint.id) { - DRM_DEBUG_DRIVER("Endpoint is our panel... skipping\n"); - of_node_put(remote); - continue; - } - } - - kfifo_put(&list->fifo, remote); - } + /* each node has at least one output */ + sun4i_drv_traverse_endpoints(list, node, 1); return count; } -- GitLab From ef0cf6441fbb1ac4390e4fa4223d421a924fd458 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec <jernej.skrabec@siol.net> Date: Mon, 25 Jun 2018 14:02:48 +0200 Subject: [PATCH 0537/1506] drm/sun4i: Add support for traversing graph with TCON TOP TCON TOP is different from other nodes in graph by having 3 input and 3 output ports. Additionally, connection to TV TCON might lead back to HDMI mux input port, creating loops. Add support for traversing such graph. Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180625120304.7543-9-jernej.skrabec@siol.net --- drivers/gpu/drm/sun4i/sun4i_drv.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c index 20193d6f33baa..e6c62c0791466 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.c +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c @@ -26,6 +26,7 @@ #include "sun4i_frontend.h" #include "sun4i_framebuffer.h" #include "sun4i_tcon.h" +#include "sun8i_tcon_top.h" DEFINE_DRM_GEM_CMA_FOPS(sun4i_drv_fops); @@ -197,6 +198,11 @@ static bool sun4i_drv_node_is_tcon(struct device_node *node) return !!of_match_node(sun4i_tcon_of_table, node); } +static bool sun4i_drv_node_is_tcon_top(struct device_node *node) +{ + return !!of_match_node(sun8i_tcon_top_of_table, node); +} + static int compare_of(struct device *dev, void *data) { DRM_DEBUG_DRIVER("Comparing of node %pOF with %pOF\n", @@ -258,6 +264,18 @@ static void sun4i_drv_traverse_endpoints(struct endpoint_list *list, if (sun4i_drv_node_is_tcon(node)) { struct of_endpoint endpoint; + /* + * TCON TOP is always probed before TCON. However, TCON + * points back to TCON TOP when it is source for HDMI. + * We have to skip it here to prevent infinite looping + * between TCON TOP and TCON. + */ + if (sun4i_drv_node_is_tcon_top(remote)) { + DRM_DEBUG_DRIVER("TCON output endpoint is TCON TOP... skipping\n"); + of_node_put(remote); + continue; + } + if (of_graph_parse_endpoint(ep, &endpoint)) { DRM_DEBUG_DRIVER("Couldn't parse endpoint\n"); of_node_put(remote); @@ -318,6 +336,12 @@ static int sun4i_drv_add_endpoints(struct device *dev, /* each node has at least one output */ sun4i_drv_traverse_endpoints(list, node, 1); + /* TCON TOP has second and third output */ + if (sun4i_drv_node_is_tcon_top(node)) { + sun4i_drv_traverse_endpoints(list, node, 3); + sun4i_drv_traverse_endpoints(list, node, 5); + } + return count; } -- GitLab From c5cf04df56e62f5a3ef09452181ee1dc51106080 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec <jernej.skrabec@siol.net> Date: Mon, 25 Jun 2018 14:02:49 +0200 Subject: [PATCH 0538/1506] drm/sun4i: Don't skip TCONs if they don't have channel 0 TV TCONs (channel 1 only) are always connected to TV or HDMI encoder. Because of that, all output endpoints on such TCON node will point to a encoder which is part of component framework. Correct current graph traversing algorithm in such way that it doesn't skip output enpoints with id 0 on TV TCONs. Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180625120304.7543-10-jernej.skrabec@siol.net --- drivers/gpu/drm/sun4i/sun4i_drv.c | 52 +++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c index e6c62c0791466..6ddf4eaccb400 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.c +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c @@ -198,6 +198,22 @@ static bool sun4i_drv_node_is_tcon(struct device_node *node) return !!of_match_node(sun4i_tcon_of_table, node); } +static bool sun4i_drv_node_is_tcon_with_ch0(struct device_node *node) +{ + const struct of_device_id *match; + + match = of_match_node(sun4i_tcon_of_table, node); + if (match) { + struct sun4i_tcon_quirks *quirks; + + quirks = (struct sun4i_tcon_quirks *)match->data; + + return quirks->has_channel_0; + } + + return false; +} + static bool sun4i_drv_node_is_tcon_top(struct device_node *node) { return !!of_match_node(sun8i_tcon_top_of_table, node); @@ -256,14 +272,7 @@ static void sun4i_drv_traverse_endpoints(struct endpoint_list *list, continue; } - /* - * If the node is our TCON, the first port is used for - * panel or bridges, and will not be part of the - * component framework. - */ if (sun4i_drv_node_is_tcon(node)) { - struct of_endpoint endpoint; - /* * TCON TOP is always probed before TCON. However, TCON * points back to TCON TOP when it is source for HDMI. @@ -276,16 +285,25 @@ static void sun4i_drv_traverse_endpoints(struct endpoint_list *list, continue; } - if (of_graph_parse_endpoint(ep, &endpoint)) { - DRM_DEBUG_DRIVER("Couldn't parse endpoint\n"); - of_node_put(remote); - continue; - } - - if (!endpoint.id) { - DRM_DEBUG_DRIVER("Endpoint is our panel... skipping\n"); - of_node_put(remote); - continue; + /* + * If the node is our TCON with channel 0, the first + * port is used for panel or bridges, and will not be + * part of the component framework. + */ + if (sun4i_drv_node_is_tcon_with_ch0(node)) { + struct of_endpoint endpoint; + + if (of_graph_parse_endpoint(ep, &endpoint)) { + DRM_DEBUG_DRIVER("Couldn't parse endpoint\n"); + of_node_put(remote); + continue; + } + + if (!endpoint.id) { + DRM_DEBUG_DRIVER("Endpoint is our panel... skipping\n"); + of_node_put(remote); + continue; + } } } -- GitLab From 49836b11fe71b93bd0124cbaecac0814aadec9eb Mon Sep 17 00:00:00 2001 From: Jernej Skrabec <jernej.skrabec@siol.net> Date: Mon, 25 Jun 2018 14:02:50 +0200 Subject: [PATCH 0539/1506] drm/sun4i: tcon: Generalize engine search algorithm Current "old" method to find engine worked pretty well for DE2. However, it doesn't work when TCON TOP is between mixer (engine) and TCON. TCON TOP has multiple input ports, but current engine search algorithm expects only one. This can be fixed by first looking for output port id and selecting matching input by subtracting 1 for the next round. This work even if there is only one input and output. Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180625120304.7543-11-jernej.skrabec@siol.net --- drivers/gpu/drm/sun4i/sun4i_tcon.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c index 08747fc3ee713..264bcc43da114 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c @@ -791,12 +791,14 @@ static int sun4i_tcon_init_regmap(struct device *dev, */ static struct sunxi_engine * sun4i_tcon_find_engine_traverse(struct sun4i_drv *drv, - struct device_node *node) + struct device_node *node, + u32 port_id) { struct device_node *port, *ep, *remote; struct sunxi_engine *engine = ERR_PTR(-EINVAL); + u32 reg = 0; - port = of_graph_get_port_by_id(node, 0); + port = of_graph_get_port_by_id(node, port_id); if (!port) return ERR_PTR(-EINVAL); @@ -826,8 +828,20 @@ sun4i_tcon_find_engine_traverse(struct sun4i_drv *drv, if (remote == engine->node) goto out_put_remote; + /* + * According to device tree binding input ports have even id + * number and output ports have odd id. Since component with + * more than one input and one output (TCON TOP) exits, correct + * remote input id has to be calculated by subtracting 1 from + * remote output id. If this for some reason can't be done, 0 + * is used as input port id. + */ + port = of_graph_get_remote_port(ep); + if (!of_property_read_u32(port, "reg", ®) && reg > 0) + reg -= 1; + /* keep looking through upstream ports */ - engine = sun4i_tcon_find_engine_traverse(drv, remote); + engine = sun4i_tcon_find_engine_traverse(drv, remote, reg); out_put_remote: of_node_put(remote); @@ -950,7 +964,7 @@ static struct sunxi_engine *sun4i_tcon_find_engine(struct sun4i_drv *drv, /* Fallback to old method by traversing input endpoints */ of_node_put(port); - return sun4i_tcon_find_engine_traverse(drv, node); + return sun4i_tcon_find_engine_traverse(drv, node, 0); } static int sun4i_tcon_bind(struct device *dev, struct device *master, -- GitLab From 2a72d0c5796b7ec90ebf51e714b3d305d4367341 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec <jernej.skrabec@siol.net> Date: Mon, 25 Jun 2018 14:02:51 +0200 Subject: [PATCH 0540/1506] drm/sun4i: Don't check for LVDS and RGB when TCON has only ch1 LVDS and RGB interfaces are always connected to TCONs which have channel 0. It doesn't make sense to try to init them on TV TCONs. Add a check if TCON has channel 0 before trying to init LVDS or RGB interface. Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180625120304.7543-12-jernej.skrabec@siol.net --- drivers/gpu/drm/sun4i/sun4i_tcon.c | 32 ++++++++++++++++-------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c index 264bcc43da114..761687ebacbae 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c @@ -1106,23 +1106,25 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master, goto err_free_dotclock; } - /* - * If we have an LVDS panel connected to the TCON, we should - * just probe the LVDS connector. Otherwise, just probe RGB as - * we used to. - */ - remote = of_graph_get_remote_node(dev->of_node, 1, 0); - if (of_device_is_compatible(remote, "panel-lvds")) - if (can_lvds) - ret = sun4i_lvds_init(drm, tcon); + if (tcon->quirks->has_channel_0) { + /* + * If we have an LVDS panel connected to the TCON, we should + * just probe the LVDS connector. Otherwise, just probe RGB as + * we used to. + */ + remote = of_graph_get_remote_node(dev->of_node, 1, 0); + if (of_device_is_compatible(remote, "panel-lvds")) + if (can_lvds) + ret = sun4i_lvds_init(drm, tcon); + else + ret = -EINVAL; else - ret = -EINVAL; - else - ret = sun4i_rgb_init(drm, tcon); - of_node_put(remote); + ret = sun4i_rgb_init(drm, tcon); + of_node_put(remote); - if (ret < 0) - goto err_free_dotclock; + if (ret < 0) + goto err_free_dotclock; + } if (tcon->quirks->needs_de_be_mux) { /* -- GitLab From 63d6310f6cc63735f08b86b3c8390b9f066a2221 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec <jernej.skrabec@siol.net> Date: Mon, 25 Jun 2018 14:02:52 +0200 Subject: [PATCH 0541/1506] drm/sun4i: Don't check for panel or bridge on TV TCONs TV TCONs are always connected to TV or HDMI encoder, so it doesn't make sense to check if panel or bridge is connected to them. Check if TCON has channel 0 and only then check for connected panel or bridges. Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180625120304.7543-13-jernej.skrabec@siol.net --- drivers/gpu/drm/sun4i/sun4i_tcon.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c index 761687ebacbae..a41c7bb0d557c 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c @@ -1178,13 +1178,19 @@ static const struct component_ops sun4i_tcon_ops = { static int sun4i_tcon_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; + const struct sun4i_tcon_quirks *quirks; struct drm_bridge *bridge; struct drm_panel *panel; int ret; - ret = drm_of_find_panel_or_bridge(node, 1, 0, &panel, &bridge); - if (ret == -EPROBE_DEFER) - return ret; + quirks = of_device_get_match_data(&pdev->dev); + + /* panels and bridges are present only on TCONs with channel 0 */ + if (quirks->has_channel_0) { + ret = drm_of_find_panel_or_bridge(node, 1, 0, &panel, &bridge); + if (ret == -EPROBE_DEFER) + return ret; + } return component_add(&pdev->dev, &sun4i_tcon_ops); } -- GitLab From 0740845909b1e0089ff60ee62b55622759875e4f Mon Sep 17 00:00:00 2001 From: Jernej Skrabec <jernej.skrabec@siol.net> Date: Mon, 25 Jun 2018 14:02:54 +0200 Subject: [PATCH 0542/1506] drm/sun4i: Add support for R40 mixers Both mixers have similar capabilities as others SoCs with DE2. First mixer has 1 VI and 3 UI planes and supports HW scaling on all planes. Second mixer has 1 VI and 1 UI planes and also supports HW scaling on all planes. Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180625120304.7543-15-jernej.skrabec@siol.net --- drivers/gpu/drm/sun4i/sun8i_mixer.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c index 126899d6f0d3a..ee8febb25903c 100644 --- a/drivers/gpu/drm/sun4i/sun8i_mixer.c +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c @@ -500,6 +500,22 @@ static const struct sun8i_mixer_cfg sun8i_h3_mixer0_cfg = { .vi_num = 1, }; +static const struct sun8i_mixer_cfg sun8i_r40_mixer0_cfg = { + .ccsc = 0, + .mod_rate = 297000000, + .scaler_mask = 0xf, + .ui_num = 3, + .vi_num = 1, +}; + +static const struct sun8i_mixer_cfg sun8i_r40_mixer1_cfg = { + .ccsc = 1, + .mod_rate = 297000000, + .scaler_mask = 0x3, + .ui_num = 1, + .vi_num = 1, +}; + static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = { .vi_num = 2, .ui_num = 1, @@ -521,6 +537,14 @@ static const struct of_device_id sun8i_mixer_of_table[] = { .compatible = "allwinner,sun8i-h3-de2-mixer-0", .data = &sun8i_h3_mixer0_cfg, }, + { + .compatible = "allwinner,sun8i-r40-de2-mixer-0", + .data = &sun8i_r40_mixer0_cfg, + }, + { + .compatible = "allwinner,sun8i-r40-de2-mixer-1", + .data = &sun8i_r40_mixer1_cfg, + }, { .compatible = "allwinner,sun8i-v3s-de2-mixer", .data = &sun8i_v3s_mixer_cfg, -- GitLab From 03c35dbf73e0726136bad921cb2649728ce909d5 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec <jernej.skrabec@siol.net> Date: Mon, 25 Jun 2018 14:02:55 +0200 Subject: [PATCH 0543/1506] dt-bindings: display: sun4i-drm: Add description of A64 HDMI PHY A64 HDMI PHY is similar to H3 HDMI PHY except it has two possible PLL clock parents. It is compatible to other HDMI PHYs, like that found in R40. Acked-by: Rob Herring <robh@kernel.org> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180625120304.7543-16-jernej.skrabec@siol.net --- Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt index fe31b15107179..5a9319ad8861c 100644 --- a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt +++ b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt @@ -101,6 +101,7 @@ DWC HDMI PHY Required properties: - compatible: value must be one of: + * allwinner,sun50i-a64-hdmi-phy * allwinner,sun8i-a83t-hdmi-phy * allwinner,sun8i-h3-hdmi-phy - reg: base address and size of memory-mapped region @@ -111,8 +112,9 @@ Required properties: - resets: phandle to the reset controller driving the PHY - reset-names: must be "phy" -H3 HDMI PHY requires additional clock: +H3 and A64 HDMI PHY require additional clocks: - pll-0: parent of phy clock + - pll-1: second possible phy clock parent (A64 only) TV Encoder ---------- -- GitLab From 09773c532d30187f86a142901c27c93e629ce6ba Mon Sep 17 00:00:00 2001 From: Jernej Skrabec <jernej.skrabec@siol.net> Date: Mon, 25 Jun 2018 14:02:56 +0200 Subject: [PATCH 0544/1506] drm/sun4i: Enable DW HDMI PHY clock Current DW HDMI PHY code never prepares and enables PHY clock after it is created. It's just used as it is. This may work in some cases, but it's clearly wrong. Fix it by adding proper calls to enable/disable PHY clock. Fixes: 4f86e81748fe ("drm/sun4i: Add support for H3 HDMI PHY variant") Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180625120304.7543-17-jernej.skrabec@siol.net --- drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c index 5a52fc489a9d5..966688f047415 100644 --- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c +++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c @@ -477,13 +477,15 @@ int sun8i_hdmi_phy_probe(struct sun8i_dw_hdmi *hdmi, struct device_node *node) dev_err(dev, "Couldn't create the PHY clock\n"); goto err_put_clk_pll0; } + + clk_prepare_enable(phy->clk_phy); } phy->rst_phy = of_reset_control_get_shared(node, "phy"); if (IS_ERR(phy->rst_phy)) { dev_err(dev, "Could not get phy reset control\n"); ret = PTR_ERR(phy->rst_phy); - goto err_put_clk_pll0; + goto err_disable_clk_phy; } ret = reset_control_deassert(phy->rst_phy); @@ -514,6 +516,8 @@ int sun8i_hdmi_phy_probe(struct sun8i_dw_hdmi *hdmi, struct device_node *node) reset_control_assert(phy->rst_phy); err_put_rst_phy: reset_control_put(phy->rst_phy); +err_disable_clk_phy: + clk_disable_unprepare(phy->clk_phy); err_put_clk_pll0: if (phy->variant->has_phy_clk) clk_put(phy->clk_pll0); @@ -531,6 +535,7 @@ void sun8i_hdmi_phy_remove(struct sun8i_dw_hdmi *hdmi) clk_disable_unprepare(phy->clk_mod); clk_disable_unprepare(phy->clk_bus); + clk_disable_unprepare(phy->clk_phy); reset_control_assert(phy->rst_phy); -- GitLab From 09f380e3ba4103a32faf4fad35d90dc144578214 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec <jernej.skrabec@siol.net> Date: Mon, 25 Jun 2018 14:02:57 +0200 Subject: [PATCH 0545/1506] drm/sun4i: Don't change clock bits in DW HDMI PHY driver DW HDMI PHY driver and PHY clock driver share same registers. Make sure that DW HDMI PHY setup code doesn't change any clock related bits. During initialization, set PHY PLL parent bit to 0. Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180625120304.7543-18-jernej.skrabec@siol.net --- drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h | 2 +- drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h index 79154f0f674af..3ba71aff92fc2 100644 --- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h +++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h @@ -98,7 +98,7 @@ #define SUN8I_HDMI_PHY_PLL_CFG1_LDO2_EN BIT(29) #define SUN8I_HDMI_PHY_PLL_CFG1_LDO1_EN BIT(28) #define SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 BIT(27) -#define SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL BIT(26) +#define SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK BIT(26) #define SUN8I_HDMI_PHY_PLL_CFG1_PLLEN BIT(25) #define SUN8I_HDMI_PHY_PLL_CFG1_LDO_VSET(x) ((x) << 22) #define SUN8I_HDMI_PHY_PLL_CFG1_UNKNOWN(x) ((x) << 20) diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c index 966688f047415..e56b9e5b1c428 100644 --- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c +++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c @@ -183,7 +183,13 @@ static int sun8i_hdmi_phy_config_h3(struct dw_hdmi *hdmi, regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, SUN8I_HDMI_PHY_ANA_CFG1_TXEN_MASK, 0); - regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, pll_cfg1_init); + /* + * NOTE: We have to be careful not to overwrite PHY parent + * clock selection bit and clock divider. + */ + regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, + (u32)~SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK, + pll_cfg1_init); regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG2_REG, (u32)~SUN8I_HDMI_PHY_PLL_CFG2_PREDIV_MSK, pll_cfg2_init); @@ -352,6 +358,10 @@ static void sun8i_hdmi_phy_init_h3(struct sun8i_hdmi_phy *phy) SUN8I_HDMI_PHY_ANA_CFG3_SCLEN | SUN8I_HDMI_PHY_ANA_CFG3_SDAEN); + /* reset PHY PLL clock parent */ + regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, + SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK, 0); + /* set HW control of CEC pins */ regmap_write(phy->regs, SUN8I_HDMI_PHY_CEC_REG, 0); -- GitLab From aef13fd8426279fcd9e0b2b5b446d35c0d49ec5d Mon Sep 17 00:00:00 2001 From: Jernej Skrabec <jernej.skrabec@siol.net> Date: Mon, 25 Jun 2018 14:02:58 +0200 Subject: [PATCH 0546/1506] drm/sun4i: DW HDMI PHY: Add support for second PLL Some DW HDMI PHYs, like those found in A64 and R40 SoCs, can select between two clock parents. Add code which reads second PLL from DT. Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180625120304.7543-19-jernej.skrabec@siol.net --- drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h | 2 ++ drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 20 +++++++++++++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h index 3ba71aff92fc2..46a3aa6a53a98 100644 --- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h +++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h @@ -147,6 +147,7 @@ struct sun8i_hdmi_phy; struct sun8i_hdmi_phy_variant { bool has_phy_clk; + bool has_second_pll; void (*phy_init)(struct sun8i_hdmi_phy *phy); void (*phy_disable)(struct dw_hdmi *hdmi, struct sun8i_hdmi_phy *phy); @@ -160,6 +161,7 @@ struct sun8i_hdmi_phy { struct clk *clk_mod; struct clk *clk_phy; struct clk *clk_pll0; + struct clk *clk_pll1; unsigned int rcal; struct regmap *regs; struct reset_control *rst_phy; diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c index e56b9e5b1c428..f0877b3f67e75 100644 --- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c +++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c @@ -482,10 +482,19 @@ int sun8i_hdmi_phy_probe(struct sun8i_dw_hdmi *hdmi, struct device_node *node) goto err_put_clk_mod; } + if (phy->variant->has_second_pll) { + phy->clk_pll1 = of_clk_get_by_name(node, "pll-1"); + if (IS_ERR(phy->clk_pll1)) { + dev_err(dev, "Could not get pll-1 clock\n"); + ret = PTR_ERR(phy->clk_pll1); + goto err_put_clk_pll0; + } + } + ret = sun8i_phy_clk_create(phy, dev); if (ret) { dev_err(dev, "Couldn't create the PHY clock\n"); - goto err_put_clk_pll0; + goto err_put_clk_pll1; } clk_prepare_enable(phy->clk_phy); @@ -528,9 +537,10 @@ int sun8i_hdmi_phy_probe(struct sun8i_dw_hdmi *hdmi, struct device_node *node) reset_control_put(phy->rst_phy); err_disable_clk_phy: clk_disable_unprepare(phy->clk_phy); +err_put_clk_pll1: + clk_put(phy->clk_pll1); err_put_clk_pll0: - if (phy->variant->has_phy_clk) - clk_put(phy->clk_pll0); + clk_put(phy->clk_pll0); err_put_clk_mod: clk_put(phy->clk_mod); err_put_clk_bus: @@ -551,8 +561,8 @@ void sun8i_hdmi_phy_remove(struct sun8i_dw_hdmi *hdmi) reset_control_put(phy->rst_phy); - if (phy->variant->has_phy_clk) - clk_put(phy->clk_pll0); + clk_put(phy->clk_pll0); + clk_put(phy->clk_pll1); clk_put(phy->clk_mod); clk_put(phy->clk_bus); } -- GitLab From c891a65a7fc940ed387ad822732f711cae554b24 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec <jernej.skrabec@siol.net> Date: Mon, 25 Jun 2018 14:02:59 +0200 Subject: [PATCH 0547/1506] drm/sun4i: Add support for second clock parent to DW HDMI PHY clk driver Expand HDMI PHY clock driver to support second clock parent. Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180625120304.7543-20-jernej.skrabec@siol.net --- drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h | 4 +- drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 3 +- drivers/gpu/drm/sun4i/sun8i_hdmi_phy_clk.c | 90 ++++++++++++++++------ 3 files changed, 73 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h index 46a3aa6a53a98..aadbe0a10b0c6 100644 --- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h +++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h @@ -99,6 +99,7 @@ #define SUN8I_HDMI_PHY_PLL_CFG1_LDO1_EN BIT(28) #define SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 BIT(27) #define SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK BIT(26) +#define SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_SHIFT 26 #define SUN8I_HDMI_PHY_PLL_CFG1_PLLEN BIT(25) #define SUN8I_HDMI_PHY_PLL_CFG1_LDO_VSET(x) ((x) << 22) #define SUN8I_HDMI_PHY_PLL_CFG1_UNKNOWN(x) ((x) << 20) @@ -190,6 +191,7 @@ void sun8i_hdmi_phy_remove(struct sun8i_dw_hdmi *hdmi); void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy); const struct dw_hdmi_phy_ops *sun8i_hdmi_phy_get_ops(void); -int sun8i_phy_clk_create(struct sun8i_hdmi_phy *phy, struct device *dev); +int sun8i_phy_clk_create(struct sun8i_hdmi_phy *phy, struct device *dev, + bool second_parent); #endif /* _SUN8I_DW_HDMI_H_ */ diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c index f0877b3f67e75..aea46b08f127c 100644 --- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c +++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c @@ -491,7 +491,8 @@ int sun8i_hdmi_phy_probe(struct sun8i_dw_hdmi *hdmi, struct device_node *node) } } - ret = sun8i_phy_clk_create(phy, dev); + ret = sun8i_phy_clk_create(phy, dev, + phy->variant->has_second_pll); if (ret) { dev_err(dev, "Couldn't create the PHY clock\n"); goto err_put_clk_pll1; diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy_clk.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy_clk.c index faea449812f83..a4d31fe3abff1 100644 --- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy_clk.c +++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy_clk.c @@ -22,35 +22,45 @@ static int sun8i_phy_clk_determine_rate(struct clk_hw *hw, { unsigned long rate = req->rate; unsigned long best_rate = 0; + struct clk_hw *best_parent = NULL; struct clk_hw *parent; int best_div = 1; - int i; + int i, p; - parent = clk_hw_get_parent(hw); - - for (i = 1; i <= 16; i++) { - unsigned long ideal = rate * i; - unsigned long rounded; - - rounded = clk_hw_round_rate(parent, ideal); + for (p = 0; p < clk_hw_get_num_parents(hw); p++) { + parent = clk_hw_get_parent_by_index(hw, p); + if (!parent) + continue; - if (rounded == ideal) { - best_rate = rounded; - best_div = i; - break; + for (i = 1; i <= 16; i++) { + unsigned long ideal = rate * i; + unsigned long rounded; + + rounded = clk_hw_round_rate(parent, ideal); + + if (rounded == ideal) { + best_rate = rounded; + best_div = i; + best_parent = parent; + break; + } + + if (!best_rate || + abs(rate - rounded / i) < + abs(rate - best_rate / best_div)) { + best_rate = rounded; + best_div = i; + best_parent = parent; + } } - if (!best_rate || - abs(rate - rounded / i) < - abs(rate - best_rate / best_div)) { - best_rate = rounded; - best_div = i; - } + if (best_rate / best_div == rate) + break; } req->rate = best_rate / best_div; req->best_parent_rate = best_rate; - req->best_parent_hw = parent; + req->best_parent_hw = best_parent; return 0; } @@ -95,22 +105,58 @@ static int sun8i_phy_clk_set_rate(struct clk_hw *hw, unsigned long rate, return 0; } +static u8 sun8i_phy_clk_get_parent(struct clk_hw *hw) +{ + struct sun8i_phy_clk *priv = hw_to_phy_clk(hw); + u32 reg; + + regmap_read(priv->phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, ®); + reg = (reg & SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK) >> + SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_SHIFT; + + return reg; +} + +static int sun8i_phy_clk_set_parent(struct clk_hw *hw, u8 index) +{ + struct sun8i_phy_clk *priv = hw_to_phy_clk(hw); + + if (index > 1) + return -EINVAL; + + regmap_update_bits(priv->phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, + SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK, + index << SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_SHIFT); + + return 0; +} + static const struct clk_ops sun8i_phy_clk_ops = { .determine_rate = sun8i_phy_clk_determine_rate, .recalc_rate = sun8i_phy_clk_recalc_rate, .set_rate = sun8i_phy_clk_set_rate, + + .get_parent = sun8i_phy_clk_get_parent, + .set_parent = sun8i_phy_clk_set_parent, }; -int sun8i_phy_clk_create(struct sun8i_hdmi_phy *phy, struct device *dev) +int sun8i_phy_clk_create(struct sun8i_hdmi_phy *phy, struct device *dev, + bool second_parent) { struct clk_init_data init; struct sun8i_phy_clk *priv; - const char *parents[1]; + const char *parents[2]; parents[0] = __clk_get_name(phy->clk_pll0); if (!parents[0]) return -ENODEV; + if (second_parent) { + parents[1] = __clk_get_name(phy->clk_pll1); + if (!parents[1]) + return -ENODEV; + } + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -118,7 +164,7 @@ int sun8i_phy_clk_create(struct sun8i_hdmi_phy *phy, struct device *dev) init.name = "hdmi-phy-clk"; init.ops = &sun8i_phy_clk_ops; init.parent_names = parents; - init.num_parents = 1; + init.num_parents = second_parent ? 2 : 1; init.flags = CLK_SET_RATE_PARENT; priv->phy = phy; -- GitLab From b46e2c9f5f64a3bbd925856cab5336680ca2e9be Mon Sep 17 00:00:00 2001 From: Jernej Skrabec <jernej.skrabec@siol.net> Date: Mon, 25 Jun 2018 14:03:00 +0200 Subject: [PATCH 0548/1506] drm/sun4i: Add support for A64 HDMI PHY PHY is the same as in H3, except it can switch between two clock parents. Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180625120304.7543-21-jernej.skrabec@siol.net --- drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c index aea46b08f127c..82502b351aec8 100644 --- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c +++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c @@ -396,6 +396,14 @@ static struct regmap_config sun8i_hdmi_phy_regmap_config = { .name = "phy" }; +static const struct sun8i_hdmi_phy_variant sun50i_a64_hdmi_phy = { + .has_phy_clk = true, + .has_second_pll = true, + .phy_init = &sun8i_hdmi_phy_init_h3, + .phy_disable = &sun8i_hdmi_phy_disable_h3, + .phy_config = &sun8i_hdmi_phy_config_h3, +}; + static const struct sun8i_hdmi_phy_variant sun8i_a83t_hdmi_phy = { .phy_init = &sun8i_hdmi_phy_init_a83t, .phy_disable = &sun8i_hdmi_phy_disable_a83t, @@ -410,6 +418,10 @@ static const struct sun8i_hdmi_phy_variant sun8i_h3_hdmi_phy = { }; static const struct of_device_id sun8i_hdmi_phy_of_table[] = { + { + .compatible = "allwinner,sun50i-a64-hdmi-phy", + .data = &sun50i_a64_hdmi_phy, + }, { .compatible = "allwinner,sun8i-a83t-hdmi-phy", .data = &sun8i_a83t_hdmi_phy, -- GitLab From 8b5f7a62464a24cb83d6290c01d6cf9c8871774a Mon Sep 17 00:00:00 2001 From: Jernej Skrabec <jernej.skrabec@siol.net> Date: Mon, 25 Jun 2018 14:03:01 +0200 Subject: [PATCH 0549/1506] drm: of: Export and rename drm_crtc_port_mask() Function is useful when drm_of_find_possible_crtcs() can't be used and custom parsing is needed. This can happen for example when there is a node with multiple muxes between crtc and encoder. Reviewed-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net> [maxime: change the function to have a consistent prefix] Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180625120304.7543-22-jernej.skrabec@siol.net --- drivers/gpu/drm/drm_of.c | 9 +++++---- include/drm/drm_of.h | 8 ++++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c index 1fe122461298e..3b8c7a6a5720d 100644 --- a/drivers/gpu/drm/drm_of.c +++ b/drivers/gpu/drm/drm_of.c @@ -15,15 +15,15 @@ static void drm_release_of(struct device *dev, void *data) } /** - * drm_crtc_port_mask - find the mask of a registered CRTC by port OF node + * drm_of_crtc_port_mask - find the mask of a registered CRTC by port OF node * @dev: DRM device * @port: port OF node * * Given a port OF node, return the possible mask of the corresponding * CRTC within a device's list of CRTCs. Returns zero if not found. */ -static uint32_t drm_crtc_port_mask(struct drm_device *dev, - struct device_node *port) +uint32_t drm_of_crtc_port_mask(struct drm_device *dev, + struct device_node *port) { unsigned int index = 0; struct drm_crtc *tmp; @@ -37,6 +37,7 @@ static uint32_t drm_crtc_port_mask(struct drm_device *dev, return 0; } +EXPORT_SYMBOL(drm_of_crtc_port_mask); /** * drm_of_find_possible_crtcs - find the possible CRTCs for an encoder port @@ -62,7 +63,7 @@ uint32_t drm_of_find_possible_crtcs(struct drm_device *dev, return 0; } - possible_crtcs |= drm_crtc_port_mask(dev, remote_port); + possible_crtcs |= drm_of_crtc_port_mask(dev, remote_port); of_node_put(remote_port); } diff --git a/include/drm/drm_of.h b/include/drm/drm_of.h index b93c239afb608..ead34ab5ca4e9 100644 --- a/include/drm/drm_of.h +++ b/include/drm/drm_of.h @@ -17,6 +17,8 @@ struct drm_bridge; struct device_node; #ifdef CONFIG_OF +uint32_t drm_of_crtc_port_mask(struct drm_device *dev, + struct device_node *port); uint32_t drm_of_find_possible_crtcs(struct drm_device *dev, struct device_node *port); void drm_of_component_match_add(struct device *master, @@ -34,6 +36,12 @@ int drm_of_find_panel_or_bridge(const struct device_node *np, struct drm_panel **panel, struct drm_bridge **bridge); #else +static inline uint32_t drm_of_crtc_port_mask(struct drm_device *dev, + struct device_node *port) +{ + return 0; +} + static inline uint32_t drm_of_find_possible_crtcs(struct drm_device *dev, struct device_node *port) { -- GitLab From 57e23de02f4878061818fd118129a6b0e1516b11 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec <jernej.skrabec@siol.net> Date: Mon, 25 Jun 2018 14:03:02 +0200 Subject: [PATCH 0550/1506] drm/sun4i: DW HDMI: Expand algorithm for possible crtcs drm_of_find_possible_crtcs() doesn't work when DW HDMI encoder is connected to TCON (crtc) through mux in TCON TOP. In that case TCON TOP HDMI mux input port has to be manually traversed and checked if it matches any known crtc. Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180625120304.7543-23-jernej.skrabec@siol.net --- drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c | 46 ++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c index 9f40a44b456b2..3459b9ec56c9b 100644 --- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c +++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c @@ -12,6 +12,7 @@ #include <drm/drm_crtc_helper.h> #include "sun8i_dw_hdmi.h" +#include "sun8i_tcon_top.h" static void sun8i_dw_hdmi_encoder_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, @@ -41,6 +42,48 @@ sun8i_dw_hdmi_mode_valid(struct drm_connector *connector, return MODE_OK; } +static bool sun8i_dw_hdmi_node_is_tcon_top(struct device_node *node) +{ + return !!of_match_node(sun8i_tcon_top_of_table, node); +} + +static u32 sun8i_dw_hdmi_find_possible_crtcs(struct drm_device *drm, + struct device_node *node) +{ + struct device_node *port, *ep, *remote, *remote_port; + u32 crtcs = 0; + + port = of_graph_get_port_by_id(node, 0); + if (!port) + return 0; + + ep = of_get_next_available_child(port, NULL); + if (!ep) + return 0; + + remote = of_graph_get_remote_port_parent(ep); + if (!remote) + return 0; + + if (sun8i_dw_hdmi_node_is_tcon_top(remote)) { + port = of_graph_get_port_by_id(remote, 4); + if (!port) + return 0; + + for_each_child_of_node(port, ep) { + remote_port = of_graph_get_remote_port(ep); + if (remote_port) { + crtcs |= drm_of_crtc_port_mask(drm, remote_port); + of_node_put(remote_port); + } + } + } else { + crtcs = drm_of_find_possible_crtcs(drm, node); + } + + return crtcs; +} + static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master, void *data) { @@ -63,7 +106,8 @@ static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master, hdmi->dev = &pdev->dev; encoder = &hdmi->encoder; - encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); + encoder->possible_crtcs = + sun8i_dw_hdmi_find_possible_crtcs(drm, dev->of_node); /* * If we failed to find the CRTC(s) which this encoder is * supposed to be connected to, it's because the CRTC has -- GitLab From 3160422251b214c7a7a8ef91bb76da012bb44b57 Mon Sep 17 00:00:00 2001 From: Anusha Srivatsa <anusha.srivatsa@intel.com> Date: Tue, 26 Jun 2018 13:52:23 -0700 Subject: [PATCH 0551/1506] drm/i915/icp: Add Interrupt Support This patch addresses Interrupts from south display engine (SDE). ICP has two registers - SHOTPLUG_CTL_DDI and SHOTPLUG_CTL_TC. Introduce these registers and their intended values. Introduce icp_irq_handler(). The icp_irq_postinstall() takes care of enabling all PCH interrupt sources, to unmask them as needed with SDEIMR, as is done done by ibx_irq_pre_postinstall() for earlier platforms. We do not need to explicitly call the ibx_irq_pre_postinstall(). Also, while changing these, s/CPT/PPT/CPT-CNP comment. v2: - remove redundant register defines.(Lucas) - Change register names to be more consistent with previous platforms (Lucas) v3: -Reorder bit defines to a more appropriate location. Change the comments. Confirm in the commit message that icp_irq_postinstall() need not go to ibx_irq_pre_postinstall() and ibx_irq_postinstall() as in earlier platforms. (Paulo) Cc: Lucas De Marchi <lucas.de.marchi@gmail.com> Cc: Paulo Zanoni <paulo.r.zanoni@intel.com> Cc: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Cc: Ville Syrjala <ville.syrjala@linux.intel.com> Reviewed-by: Lucas De Marchi <lucas.demarchi@intel.com> Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Signed-off-by: Anusha Srivatsa <anusha.srivatsa@intel.com> [Paulo: coding style bikesheds and rebases]. Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/1530046343-30649-1-git-send-email-anusha.srivatsa@intel.com --- drivers/gpu/drm/i915/i915_irq.c | 134 +++++++++++++++++++++++++++++++- drivers/gpu/drm/i915/i915_reg.h | 41 +++++++++- 2 files changed, 172 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 46aaef5c1851e..7a7c4a2bd7783 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -122,6 +122,15 @@ static const u32 hpd_gen11[HPD_NUM_PINS] = { [HPD_PORT_F] = GEN11_TC4_HOTPLUG | GEN11_TBT4_HOTPLUG }; +static const u32 hpd_icp[HPD_NUM_PINS] = { + [HPD_PORT_A] = SDE_DDIA_HOTPLUG_ICP, + [HPD_PORT_B] = SDE_DDIB_HOTPLUG_ICP, + [HPD_PORT_C] = SDE_TC1_HOTPLUG_ICP, + [HPD_PORT_D] = SDE_TC2_HOTPLUG_ICP, + [HPD_PORT_E] = SDE_TC3_HOTPLUG_ICP, + [HPD_PORT_F] = SDE_TC4_HOTPLUG_ICP +}; + /* IIR can theoretically queue up two events. Be paranoid. */ #define GEN8_IRQ_RESET_NDX(type, which) do { \ I915_WRITE(GEN8_##type##_IMR(which), 0xffffffff); \ @@ -1586,6 +1595,34 @@ static bool bxt_port_hotplug_long_detect(enum port port, u32 val) } } +static bool icp_ddi_port_hotplug_long_detect(enum port port, u32 val) +{ + switch (port) { + case PORT_A: + return val & ICP_DDIA_HPD_LONG_DETECT; + case PORT_B: + return val & ICP_DDIB_HPD_LONG_DETECT; + default: + return false; + } +} + +static bool icp_tc_port_hotplug_long_detect(enum port port, u32 val) +{ + switch (port) { + case PORT_C: + return val & ICP_TC_HPD_LONG_DETECT(PORT_TC1); + case PORT_D: + return val & ICP_TC_HPD_LONG_DETECT(PORT_TC2); + case PORT_E: + return val & ICP_TC_HPD_LONG_DETECT(PORT_TC3); + case PORT_F: + return val & ICP_TC_HPD_LONG_DETECT(PORT_TC4); + default: + return false; + } +} + static bool spt_port_hotplug2_long_detect(enum port port, u32 val) { switch (port) { @@ -2385,6 +2422,43 @@ static void cpt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir) cpt_serr_int_handler(dev_priv); } +static void icp_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir) +{ + u32 ddi_hotplug_trigger = pch_iir & SDE_DDI_MASK_ICP; + u32 tc_hotplug_trigger = pch_iir & SDE_TC_MASK_ICP; + u32 pin_mask = 0, long_mask = 0; + + if (ddi_hotplug_trigger) { + u32 dig_hotplug_reg; + + dig_hotplug_reg = I915_READ(SHOTPLUG_CTL_DDI); + I915_WRITE(SHOTPLUG_CTL_DDI, dig_hotplug_reg); + + intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, + ddi_hotplug_trigger, + dig_hotplug_reg, hpd_icp, + icp_ddi_port_hotplug_long_detect); + } + + if (tc_hotplug_trigger) { + u32 dig_hotplug_reg; + + dig_hotplug_reg = I915_READ(SHOTPLUG_CTL_TC); + I915_WRITE(SHOTPLUG_CTL_TC, dig_hotplug_reg); + + intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask, + tc_hotplug_trigger, + dig_hotplug_reg, hpd_icp, + icp_tc_port_hotplug_long_detect); + } + + if (pin_mask) + intel_hpd_irq_handler(dev_priv, pin_mask, long_mask); + + if (pch_iir & SDE_GMBUS_ICP) + gmbus_irq_handler(dev_priv); +} + static void spt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir) { u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_SPT & @@ -2804,8 +2878,11 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl) I915_WRITE(SDEIIR, iir); ret = IRQ_HANDLED; - if (HAS_PCH_SPT(dev_priv) || HAS_PCH_KBP(dev_priv) || - HAS_PCH_CNP(dev_priv)) + if (HAS_PCH_ICP(dev_priv)) + icp_irq_handler(dev_priv, iir); + else if (HAS_PCH_SPT(dev_priv) || + HAS_PCH_KBP(dev_priv) || + HAS_PCH_CNP(dev_priv)) spt_irq_handler(dev_priv, iir); else cpt_irq_handler(dev_priv, iir); @@ -3584,6 +3661,9 @@ static void gen11_irq_reset(struct drm_device *dev) GEN3_IRQ_RESET(GEN11_DE_HPD_); GEN3_IRQ_RESET(GEN11_GU_MISC_); GEN3_IRQ_RESET(GEN8_PCU_); + + if (HAS_PCH_ICP(dev_priv)) + GEN3_IRQ_RESET(SDE); } void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv, @@ -3700,6 +3780,35 @@ static void ibx_hpd_irq_setup(struct drm_i915_private *dev_priv) ibx_hpd_detection_setup(dev_priv); } +static void icp_hpd_detection_setup(struct drm_i915_private *dev_priv) +{ + u32 hotplug; + + hotplug = I915_READ(SHOTPLUG_CTL_DDI); + hotplug |= ICP_DDIA_HPD_ENABLE | + ICP_DDIB_HPD_ENABLE; + I915_WRITE(SHOTPLUG_CTL_DDI, hotplug); + + hotplug = I915_READ(SHOTPLUG_CTL_TC); + hotplug |= ICP_TC_HPD_ENABLE(PORT_TC1) | + ICP_TC_HPD_ENABLE(PORT_TC2) | + ICP_TC_HPD_ENABLE(PORT_TC3) | + ICP_TC_HPD_ENABLE(PORT_TC4); + I915_WRITE(SHOTPLUG_CTL_TC, hotplug); +} + +static void icp_hpd_irq_setup(struct drm_i915_private *dev_priv) +{ + u32 hotplug_irqs, enabled_irqs; + + hotplug_irqs = SDE_DDI_MASK_ICP | SDE_TC_MASK_ICP; + enabled_irqs = intel_hpd_enabled_irqs(dev_priv, hpd_icp); + + ibx_display_interrupt_update(dev_priv, hotplug_irqs, enabled_irqs); + + icp_hpd_detection_setup(dev_priv); +} + static void gen11_hpd_detection_setup(struct drm_i915_private *dev_priv) { u32 hotplug; @@ -3733,6 +3842,9 @@ static void gen11_hpd_irq_setup(struct drm_i915_private *dev_priv) POSTING_READ(GEN11_DE_HPD_IMR); gen11_hpd_detection_setup(dev_priv); + + if (HAS_PCH_ICP(dev_priv)) + icp_hpd_irq_setup(dev_priv); } static void spt_hpd_detection_setup(struct drm_i915_private *dev_priv) @@ -4168,11 +4280,29 @@ static void gen11_gt_irq_postinstall(struct drm_i915_private *dev_priv) I915_WRITE(GEN11_GPM_WGBOXPERF_INTR_MASK, ~0); } +static void icp_irq_postinstall(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = to_i915(dev); + u32 mask = SDE_GMBUS_ICP; + + WARN_ON(I915_READ(SDEIER) != 0); + I915_WRITE(SDEIER, 0xffffffff); + POSTING_READ(SDEIER); + + gen3_assert_iir_is_zero(dev_priv, SDEIIR); + I915_WRITE(SDEIMR, ~mask); + + icp_hpd_detection_setup(dev_priv); +} + static int gen11_irq_postinstall(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; u32 gu_misc_masked = GEN11_GU_MISC_GSE; + if (HAS_PCH_ICP(dev_priv)) + icp_irq_postinstall(dev); + gen11_gt_irq_postinstall(dev_priv); gen8_de_irq_postinstall(dev_priv); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 2c20dc0db6482..c30cfcd907546 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -7462,7 +7462,7 @@ enum { #define SDE_TRANSA_FIFO_UNDER (1 << 0) #define SDE_TRANS_MASK (0x3f) -/* south display engine interrupt: CPT/PPT */ +/* south display engine interrupt: CPT - CNP */ #define SDE_AUDIO_POWER_D_CPT (1 << 31) #define SDE_AUDIO_POWER_C_CPT (1 << 30) #define SDE_AUDIO_POWER_B_CPT (1 << 29) @@ -7510,6 +7510,21 @@ enum { SDE_FDI_RXB_CPT | \ SDE_FDI_RXA_CPT) +/* south display engine interrupt: ICP */ +#define SDE_TC4_HOTPLUG_ICP (1 << 27) +#define SDE_TC3_HOTPLUG_ICP (1 << 26) +#define SDE_TC2_HOTPLUG_ICP (1 << 25) +#define SDE_TC1_HOTPLUG_ICP (1 << 24) +#define SDE_GMBUS_ICP (1 << 23) +#define SDE_DDIB_HOTPLUG_ICP (1 << 17) +#define SDE_DDIA_HOTPLUG_ICP (1 << 16) +#define SDE_DDI_MASK_ICP (SDE_DDIB_HOTPLUG_ICP | \ + SDE_DDIA_HOTPLUG_ICP) +#define SDE_TC_MASK_ICP (SDE_TC4_HOTPLUG_ICP | \ + SDE_TC3_HOTPLUG_ICP | \ + SDE_TC2_HOTPLUG_ICP | \ + SDE_TC1_HOTPLUG_ICP) + #define SDEISR _MMIO(0xc4000) #define SDEIMR _MMIO(0xc4004) #define SDEIIR _MMIO(0xc4008) @@ -7570,6 +7585,30 @@ enum { #define PORTE_HOTPLUG_SHORT_DETECT (1 << 0) #define PORTE_HOTPLUG_LONG_DETECT (2 << 0) +/* This register is a reuse of PCH_PORT_HOTPLUG register. The + * functionality covered in PCH_PORT_HOTPLUG is split into + * SHOTPLUG_CTL_DDI and SHOTPLUG_CTL_TC. + */ + +#define SHOTPLUG_CTL_DDI _MMIO(0xc4030) +#define ICP_DDIB_HPD_ENABLE (1 << 7) +#define ICP_DDIB_HPD_STATUS_MASK (3 << 4) +#define ICP_DDIB_HPD_NO_DETECT (0 << 4) +#define ICP_DDIB_HPD_SHORT_DETECT (1 << 4) +#define ICP_DDIB_HPD_LONG_DETECT (2 << 4) +#define ICP_DDIB_HPD_SHORT_LONG_DETECT (3 << 4) +#define ICP_DDIA_HPD_ENABLE (1 << 3) +#define ICP_DDIA_HPD_STATUS_MASK (3 << 0) +#define ICP_DDIA_HPD_NO_DETECT (0 << 0) +#define ICP_DDIA_HPD_SHORT_DETECT (1 << 0) +#define ICP_DDIA_HPD_LONG_DETECT (2 << 0) +#define ICP_DDIA_HPD_SHORT_LONG_DETECT (3 << 0) + +#define SHOTPLUG_CTL_TC _MMIO(0xc4034) +#define ICP_TC_HPD_ENABLE(tc_port) (8 << (tc_port) * 4) +#define ICP_TC_HPD_LONG_DETECT(tc_port) (2 << (tc_port) * 4) +#define ICP_TC_HPD_SHORT_DETECT(tc_port) (1 << (tc_port) * 4) + #define PCH_GPIOA _MMIO(0xc5010) #define PCH_GPIOB _MMIO(0xc5014) #define PCH_GPIOC _MMIO(0xc5018) -- GitLab From 6ada1328642b8ffc25917c89569d3e16354b43d2 Mon Sep 17 00:00:00 2001 From: Souptick Joarder <jrdr.linux@gmail.com> Date: Tue, 22 May 2018 23:43:57 +0530 Subject: [PATCH 0552/1506] gpu: drm: omapdrm: Adding new typedef vm_fault_t Use new return type vm_fault_t for fault handler. For now, this is just documenting that the function returns a VM_FAULT value rather than an errno. Once all instances are converted, vm_fault_t will become a distinct type. Ref-> commit 1c8f422059ae ("mm: change return type to vm_fault_t") Previously vm_insert_mixed() returns err which driver mapped into VM_FAULT_* type. Also return value of vm_insert_mixed() not handled correctly and 0 was returned inside fault_2d() as default. The new function vmf_insert_mixed() will replace this inefficiency by returning correct VM_FAULT_* type. vmf_error() is the newly introduce inline function in 4.17-rc6. Signed-off-by: Souptick Joarder <jrdr.linux@gmail.com> Reviewed-by: Matthew Wilcox <mawilcox@microsoft.com> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com> --- drivers/gpu/drm/omapdrm/omap_gem.c | 51 ++++++++++++++---------------- drivers/gpu/drm/omapdrm/omap_gem.h | 3 +- 2 files changed, 25 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c index 17a53d2079781..6030de7ec2ba3 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.c +++ b/drivers/gpu/drm/omapdrm/omap_gem.c @@ -371,7 +371,7 @@ size_t omap_gem_mmap_size(struct drm_gem_object *obj) */ /* Normal handling for the case of faulting in non-tiled buffers */ -static int fault_1d(struct drm_gem_object *obj, +static vm_fault_t fault_1d(struct drm_gem_object *obj, struct vm_area_struct *vma, struct vm_fault *vmf) { struct omap_gem_object *omap_obj = to_omap_bo(obj); @@ -392,11 +392,12 @@ static int fault_1d(struct drm_gem_object *obj, VERB("Inserting %p pfn %lx, pa %lx", (void *)vmf->address, pfn, pfn << PAGE_SHIFT); - return vm_insert_mixed(vma, vmf->address, __pfn_to_pfn_t(pfn, PFN_DEV)); + return vmf_insert_mixed(vma, vmf->address, + __pfn_to_pfn_t(pfn, PFN_DEV)); } /* Special handling for the case of faulting in 2d tiled buffers */ -static int fault_2d(struct drm_gem_object *obj, +static vm_fault_t fault_2d(struct drm_gem_object *obj, struct vm_area_struct *vma, struct vm_fault *vmf) { struct omap_gem_object *omap_obj = to_omap_bo(obj); @@ -407,7 +408,8 @@ static int fault_2d(struct drm_gem_object *obj, unsigned long pfn; pgoff_t pgoff, base_pgoff; unsigned long vaddr; - int i, ret, slots; + int i, err, slots; + vm_fault_t ret = VM_FAULT_NOPAGE; /* * Note the height of the slot is also equal to the number of pages @@ -473,9 +475,10 @@ static int fault_2d(struct drm_gem_object *obj, memset(pages + slots, 0, sizeof(struct page *) * (n - slots)); - ret = tiler_pin(entry->block, pages, ARRAY_SIZE(pages), 0, true); - if (ret) { - dev_err(obj->dev->dev, "failed to pin: %d\n", ret); + err = tiler_pin(entry->block, pages, ARRAY_SIZE(pages), 0, true); + if (err) { + ret = vmf_error(err); + dev_err(obj->dev->dev, "failed to pin: %d\n", err); return ret; } @@ -485,7 +488,10 @@ static int fault_2d(struct drm_gem_object *obj, pfn, pfn << PAGE_SHIFT); for (i = n; i > 0; i--) { - vm_insert_mixed(vma, vaddr, __pfn_to_pfn_t(pfn, PFN_DEV)); + ret = vmf_insert_mixed(vma, + vaddr, __pfn_to_pfn_t(pfn, PFN_DEV)); + if (ret & VM_FAULT_ERROR) + break; pfn += priv->usergart[fmt].stride_pfn; vaddr += PAGE_SIZE * m; } @@ -494,7 +500,7 @@ static int fault_2d(struct drm_gem_object *obj, priv->usergart[fmt].last = (priv->usergart[fmt].last + 1) % NUM_USERGART_ENTRIES; - return 0; + return ret; } /** @@ -509,14 +515,15 @@ static int fault_2d(struct drm_gem_object *obj, * vma->vm_private_data points to the GEM object that is backing this * mapping. */ -int omap_gem_fault(struct vm_fault *vmf) +vm_fault_t omap_gem_fault(struct vm_fault *vmf) { struct vm_area_struct *vma = vmf->vma; struct drm_gem_object *obj = vma->vm_private_data; struct omap_gem_object *omap_obj = to_omap_bo(obj); struct drm_device *dev = obj->dev; struct page **pages; - int ret; + int err; + vm_fault_t ret; /* Make sure we don't parallel update on a fault, nor move or remove * something from beneath our feet @@ -524,9 +531,11 @@ int omap_gem_fault(struct vm_fault *vmf) mutex_lock(&dev->struct_mutex); /* if a shmem backed object, make sure we have pages attached now */ - ret = get_pages(obj, &pages); - if (ret) + err = get_pages(obj, &pages); + if (err) { + ret = vmf_error(err); goto fail; + } /* where should we do corresponding put_pages().. we are mapping * the original page, rather than thru a GART, so we can't rely @@ -542,21 +551,7 @@ int omap_gem_fault(struct vm_fault *vmf) fail: mutex_unlock(&dev->struct_mutex); - switch (ret) { - case 0: - case -ERESTARTSYS: - case -EINTR: - case -EBUSY: - /* - * EBUSY is ok: this just means that another thread - * already did the job. - */ - return VM_FAULT_NOPAGE; - case -ENOMEM: - return VM_FAULT_OOM; - default: - return VM_FAULT_SIGBUS; - } + return ret; } /** We override mainly to fix up some of the vm mapping flags.. */ diff --git a/drivers/gpu/drm/omapdrm/omap_gem.h b/drivers/gpu/drm/omapdrm/omap_gem.h index a78bde05193ab..c1c45fbde155c 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.h +++ b/drivers/gpu/drm/omapdrm/omap_gem.h @@ -21,6 +21,7 @@ #define __OMAPDRM_GEM_H__ #include <linux/types.h> +#include <linux/mm_types.h> enum dma_data_direction; @@ -80,7 +81,7 @@ struct dma_buf *omap_gem_prime_export(struct drm_device *dev, struct drm_gem_object *omap_gem_prime_import(struct drm_device *dev, struct dma_buf *buffer); -int omap_gem_fault(struct vm_fault *vmf); +vm_fault_t omap_gem_fault(struct vm_fault *vmf); int omap_gem_roll(struct drm_gem_object *obj, u32 roll); void omap_gem_cpu_sync_page(struct drm_gem_object *obj, int pgoff); void omap_gem_dma_sync_buffer(struct drm_gem_object *obj, -- GitLab From c618a3a93b5a118fcf4afe5fe85e83c190f4b127 Mon Sep 17 00:00:00 2001 From: Venkateswara Rao Mandela <venkat.mandela@ti.com> Date: Wed, 24 Jan 2018 16:15:09 +0530 Subject: [PATCH 0553/1506] drm/omap: Implement workaround for DRA7 errata ID:i932 Description of DRA7 Errata i932: In rare circumstances DPLL_VIDEO1 and DPLL_VIDEO2 PLL's may not lock on the first attempt during DSS initialization. When this occurs, a subsequent attempt to relock the PLL will result in PLL successfully locking. This patch does the following as per the errata recommendation: - retries locking the PLL upto 20 times. - The time to wait for a PLL lock set to 1000 REFCLK cycles. We use usleep_range to wait for 1000 REFCLK cycles in the us range. This tight constraint is imposed as a lock later than 1000 REFCLK cycles may have high jitter. - Criteria for PLL lock is extended from check on just the PLL_LOCK bit to check on 6 PLL_STATUS bits. Silicon Versions Impacted: DRA71, DRA72, DRA74, DRA76 - All silicon revisions AM57x - All silicon revisions OMAP4/5 are not impacted by this errata Signed-off-by: Venkateswara Rao Mandela <venkat.mandela@ti.com> [tomi.valkeinen@ti.com: ported to v4.14] Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com> --- drivers/gpu/drm/omapdrm/dss/dss.h | 3 + drivers/gpu/drm/omapdrm/dss/pll.c | 73 +++++++++++++++++++++---- drivers/gpu/drm/omapdrm/dss/video-pll.c | 1 + 3 files changed, 67 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/dss/dss.h b/drivers/gpu/drm/omapdrm/dss/dss.h index 847c78ade024d..9f9a700bb6d5d 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.h +++ b/drivers/gpu/drm/omapdrm/dss/dss.h @@ -180,6 +180,9 @@ struct dss_pll_hw { /* DRA7 errata i886: use high N & M to avoid jitter */ bool errata_i886; + + /* DRA7 errata i932: retry pll lock on failure */ + bool errata_i932; }; struct dss_pll { diff --git a/drivers/gpu/drm/omapdrm/dss/pll.c b/drivers/gpu/drm/omapdrm/dss/pll.c index 078b0e8216c38..ff362b38bf0d4 100644 --- a/drivers/gpu/drm/omapdrm/dss/pll.c +++ b/drivers/gpu/drm/omapdrm/dss/pll.c @@ -16,6 +16,7 @@ #define DSS_SUBSYS_NAME "PLL" +#include <linux/delay.h> #include <linux/clk.h> #include <linux/io.h> #include <linux/kernel.h> @@ -381,6 +382,22 @@ static int dss_wait_hsdiv_ack(struct dss_pll *pll, u32 hsdiv_ack_mask) return -ETIMEDOUT; } +static bool pll_is_locked(u32 stat) +{ + /* + * Required value for each bitfield listed below + * + * PLL_STATUS[6] = 0 PLL_BYPASS + * PLL_STATUS[5] = 0 PLL_HIGHJITTER + * + * PLL_STATUS[3] = 0 PLL_LOSSREF + * PLL_STATUS[2] = 0 PLL_RECAL + * PLL_STATUS[1] = 1 PLL_LOCK + * PLL_STATUS[0] = 1 PLL_CTRL_RESET_DONE + */ + return ((stat & 0x6f) == 0x3); +} + int dss_pll_write_config_type_a(struct dss_pll *pll, const struct dss_pll_clock_info *cinfo) { @@ -436,18 +453,54 @@ int dss_pll_write_config_type_a(struct dss_pll *pll, l = FLD_MOD(l, 0, 25, 25); /* M7_CLOCK_EN */ writel_relaxed(l, base + PLL_CONFIGURATION2); - writel_relaxed(1, base + PLL_GO); /* PLL_GO */ + if (hw->errata_i932) { + int cnt = 0; + u32 sleep_time; + const u32 max_lock_retries = 20; - if (wait_for_bit_change(base + PLL_GO, 0, 0) != 0) { - DSSERR("DSS DPLL GO bit not going down.\n"); - r = -EIO; - goto err; - } + /* + * Calculate wait time for PLL LOCK + * 1000 REFCLK cycles in us. + */ + sleep_time = DIV_ROUND_UP(1000*1000*1000, cinfo->fint); - if (wait_for_bit_change(base + PLL_STATUS, 1, 1) != 1) { - DSSERR("cannot lock DSS DPLL\n"); - r = -EIO; - goto err; + for (cnt = 0; cnt < max_lock_retries; cnt++) { + writel_relaxed(1, base + PLL_GO); /* PLL_GO */ + + /** + * read the register back to ensure the write is + * flushed + */ + readl_relaxed(base + PLL_GO); + + usleep_range(sleep_time, sleep_time + 5); + l = readl_relaxed(base + PLL_STATUS); + + if (pll_is_locked(l) && + !(readl_relaxed(base + PLL_GO) & 0x1)) + break; + + } + + if (cnt == max_lock_retries) { + DSSERR("cannot lock PLL\n"); + r = -EIO; + goto err; + } + } else { + writel_relaxed(1, base + PLL_GO); /* PLL_GO */ + + if (wait_for_bit_change(base + PLL_GO, 0, 0) != 0) { + DSSERR("DSS DPLL GO bit not going down.\n"); + r = -EIO; + goto err; + } + + if (wait_for_bit_change(base + PLL_STATUS, 1, 1) != 1) { + DSSERR("cannot lock DSS DPLL\n"); + r = -EIO; + goto err; + } } l = readl_relaxed(base + PLL_CONFIGURATION2); diff --git a/drivers/gpu/drm/omapdrm/dss/video-pll.c b/drivers/gpu/drm/omapdrm/dss/video-pll.c index 585ed94ccf178..cb46311f92c9d 100644 --- a/drivers/gpu/drm/omapdrm/dss/video-pll.c +++ b/drivers/gpu/drm/omapdrm/dss/video-pll.c @@ -134,6 +134,7 @@ static const struct dss_pll_hw dss_dra7_video_pll_hw = { .has_refsel = true, .errata_i886 = true, + .errata_i932 = true, }; struct dss_pll *dss_video_pll_init(struct dss_device *dss, -- GitLab From 6505d75cd23291565ca668dd1e66f4e38b5c8f38 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen <tomi.valkeinen@ti.com> Date: Thu, 24 May 2018 14:46:19 +0300 Subject: [PATCH 0554/1506] drm/omap: fix email address Change tomi.valkeinen@nokia.com to tomi.valkeinen@ti.com. Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com> --- drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c | 2 +- drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c | 2 +- drivers/gpu/drm/omapdrm/dss/core.c | 4 ++-- drivers/gpu/drm/omapdrm/dss/dispc.c | 2 +- drivers/gpu/drm/omapdrm/dss/display.c | 2 +- drivers/gpu/drm/omapdrm/dss/dpi.c | 2 +- drivers/gpu/drm/omapdrm/dss/dsi.c | 2 +- drivers/gpu/drm/omapdrm/dss/dss.c | 2 +- drivers/gpu/drm/omapdrm/dss/dss.h | 2 +- drivers/gpu/drm/omapdrm/dss/sdi.c | 2 +- drivers/gpu/drm/omapdrm/dss/venc.c | 2 +- 11 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c b/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c index 92fe125ce22e4..f34c06bb5bd74 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c @@ -4,7 +4,7 @@ * Copyright (C) 2010 Nokia Corporation * * Original Driver Author: Imre Deak <imre.deak@nokia.com> - * Based on panel-generic.c by Tomi Valkeinen <tomi.valkeinen@nokia.com> + * Based on panel-generic.c by Tomi Valkeinen <tomi.valkeinen@ti.com> * Adapted to new DSS2 framework: Roger Quadros <roger.quadros@nokia.com> * * This program is free software; you can redistribute it and/or modify it diff --git a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c index b5d8a00df811b..a1f1dc18407a3 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c @@ -2,7 +2,7 @@ * Toppoly TD028TTEC1 panel support * * Copyright (C) 2008 Nokia Corporation - * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> + * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> * * Neo 1973 code (jbt6k74.c): * Copyright (C) 2006-2007 by OpenMoko, Inc. diff --git a/drivers/gpu/drm/omapdrm/dss/core.c b/drivers/gpu/drm/omapdrm/dss/core.c index acef7ece57833..07d00a186f151 100644 --- a/drivers/gpu/drm/omapdrm/dss/core.c +++ b/drivers/gpu/drm/omapdrm/dss/core.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2009 Nokia Corporation - * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> + * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> * * Some code and ideas taken from drivers/video/omap/ driver * by Imre Deak. @@ -82,7 +82,7 @@ static void __exit omap_dss_exit(void) module_init(omap_dss_init); module_exit(omap_dss_exit); -MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>"); +MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>"); MODULE_DESCRIPTION("OMAP2/3 Display Subsystem"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c index 7f3ac6b13b567..84f274c4a4cbf 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.c +++ b/drivers/gpu/drm/omapdrm/dss/dispc.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2009 Nokia Corporation - * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> + * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> * * Some code and ideas taken from drivers/video/omap/ driver * by Imre Deak. diff --git a/drivers/gpu/drm/omapdrm/dss/display.c b/drivers/gpu/drm/omapdrm/dss/display.c index 424143128cd49..9e7fcbd57e529 100644 --- a/drivers/gpu/drm/omapdrm/dss/display.c +++ b/drivers/gpu/drm/omapdrm/dss/display.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2009 Nokia Corporation - * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> + * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> * * Some code and ideas taken from drivers/video/omap/ driver * by Imre Deak. diff --git a/drivers/gpu/drm/omapdrm/dss/dpi.c b/drivers/gpu/drm/omapdrm/dss/dpi.c index 3d662e6805eb0..9fcc502171336 100644 --- a/drivers/gpu/drm/omapdrm/dss/dpi.c +++ b/drivers/gpu/drm/omapdrm/dss/dpi.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2009 Nokia Corporation - * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> + * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> * * Some code and ideas taken from drivers/video/omap/ driver * by Imre Deak. diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c index d4a680629825a..74467b3087218 100644 --- a/drivers/gpu/drm/omapdrm/dss/dsi.c +++ b/drivers/gpu/drm/omapdrm/dss/dsi.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2009 Nokia Corporation - * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> + * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> * * 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 diff --git a/drivers/gpu/drm/omapdrm/dss/dss.c b/drivers/gpu/drm/omapdrm/dss/dss.c index 0b908e9de792b..cb80ddaa19d26 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.c +++ b/drivers/gpu/drm/omapdrm/dss/dss.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2009 Nokia Corporation - * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> + * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> * * Some code and ideas taken from drivers/video/omap/ driver * by Imre Deak. diff --git a/drivers/gpu/drm/omapdrm/dss/dss.h b/drivers/gpu/drm/omapdrm/dss/dss.h index 9f9a700bb6d5d..38302631b64ba 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.h +++ b/drivers/gpu/drm/omapdrm/dss/dss.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2009 Nokia Corporation - * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> + * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> * * Some code and ideas taken from drivers/video/omap/ driver * by Imre Deak. diff --git a/drivers/gpu/drm/omapdrm/dss/sdi.c b/drivers/gpu/drm/omapdrm/dss/sdi.c index 1e2c931f6acfa..69c3b7a3d5c75 100644 --- a/drivers/gpu/drm/omapdrm/dss/sdi.c +++ b/drivers/gpu/drm/omapdrm/dss/sdi.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2009 Nokia Corporation - * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> + * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> * * 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 diff --git a/drivers/gpu/drm/omapdrm/dss/venc.c b/drivers/gpu/drm/omapdrm/dss/venc.c index 24d1ced210bd5..ac01907dcc345 100644 --- a/drivers/gpu/drm/omapdrm/dss/venc.c +++ b/drivers/gpu/drm/omapdrm/dss/venc.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2009 Nokia Corporation - * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> + * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> * * VENC settings from TI's DSS driver * -- GitLab From 620063e10ed48c63027c4f59dab97d2ead67f9f1 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Date: Fri, 25 May 2018 19:39:20 +0300 Subject: [PATCH 0555/1506] drm/omap: gem: Rename GEM function with omap_gem_* prefix get_pages() as a local function name is too generic and easily confused for a generic MM kernel function. Rename it to __omap_gem_get_pages(). Rename the is_contiguous(), is_cache_coherent(), evict(), evict_entry(), fault_1d() and fault_2d() functions for the same reason. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ti.com> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com> --- drivers/gpu/drm/omapdrm/omap_gem.c | 48 ++++++++++++++++-------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c index 6030de7ec2ba3..7a4ee4edab5b2 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.c +++ b/drivers/gpu/drm/omapdrm/omap_gem.c @@ -156,7 +156,7 @@ static u64 mmap_offset(struct drm_gem_object *obj) return drm_vma_node_offset_addr(&obj->vma_node); } -static bool is_contiguous(struct omap_gem_object *omap_obj) +static bool omap_gem_is_contiguous(struct omap_gem_object *omap_obj) { if (omap_obj->flags & OMAP_BO_MEM_DMA_API) return true; @@ -171,7 +171,7 @@ static bool is_contiguous(struct omap_gem_object *omap_obj) * Eviction */ -static void evict_entry(struct drm_gem_object *obj, +static void omap_gem_evict_entry(struct drm_gem_object *obj, enum tiler_fmt fmt, struct omap_drm_usergart_entry *entry) { struct omap_gem_object *omap_obj = to_omap_bo(obj); @@ -199,7 +199,7 @@ static void evict_entry(struct drm_gem_object *obj, } /* Evict a buffer from usergart, if it is mapped there */ -static void evict(struct drm_gem_object *obj) +static void omap_gem_evict(struct drm_gem_object *obj) { struct omap_gem_object *omap_obj = to_omap_bo(obj); struct omap_drm_private *priv = obj->dev->dev_private; @@ -213,7 +213,7 @@ static void evict(struct drm_gem_object *obj) &priv->usergart[fmt].entry[i]; if (entry->obj == obj) - evict_entry(obj, fmt, entry); + omap_gem_evict_entry(obj, fmt, entry); } } } @@ -291,7 +291,8 @@ static int omap_gem_attach_pages(struct drm_gem_object *obj) /* acquire pages when needed (for example, for DMA where physically * contiguous buffer is not required */ -static int get_pages(struct drm_gem_object *obj, struct page ***pages) +static int __omap_gem_get_pages(struct drm_gem_object *obj, + struct page ***pages) { struct omap_gem_object *omap_obj = to_omap_bo(obj); int ret = 0; @@ -371,7 +372,7 @@ size_t omap_gem_mmap_size(struct drm_gem_object *obj) */ /* Normal handling for the case of faulting in non-tiled buffers */ -static vm_fault_t fault_1d(struct drm_gem_object *obj, +static vm_fault_t omap_gem_fault_1d(struct drm_gem_object *obj, struct vm_area_struct *vma, struct vm_fault *vmf) { struct omap_gem_object *omap_obj = to_omap_bo(obj); @@ -385,7 +386,7 @@ static vm_fault_t fault_1d(struct drm_gem_object *obj, omap_gem_cpu_sync_page(obj, pgoff); pfn = page_to_pfn(omap_obj->pages[pgoff]); } else { - BUG_ON(!is_contiguous(omap_obj)); + BUG_ON(!omap_gem_is_contiguous(omap_obj)); pfn = (omap_obj->dma_addr >> PAGE_SHIFT) + pgoff; } @@ -397,7 +398,7 @@ static vm_fault_t fault_1d(struct drm_gem_object *obj, } /* Special handling for the case of faulting in 2d tiled buffers */ -static vm_fault_t fault_2d(struct drm_gem_object *obj, +static vm_fault_t omap_gem_fault_2d(struct drm_gem_object *obj, struct vm_area_struct *vma, struct vm_fault *vmf) { struct omap_gem_object *omap_obj = to_omap_bo(obj); @@ -445,7 +446,7 @@ static vm_fault_t fault_2d(struct drm_gem_object *obj, /* evict previous buffer using this usergart entry, if any: */ if (entry->obj) - evict_entry(entry->obj, fmt, entry); + omap_gem_evict_entry(entry->obj, fmt, entry); entry->obj = obj; entry->obj_pgoff = base_pgoff; @@ -531,7 +532,7 @@ vm_fault_t omap_gem_fault(struct vm_fault *vmf) mutex_lock(&dev->struct_mutex); /* if a shmem backed object, make sure we have pages attached now */ - err = get_pages(obj, &pages); + err = __omap_gem_get_pages(obj, &pages); if (err) { ret = vmf_error(err); goto fail; @@ -544,9 +545,9 @@ vm_fault_t omap_gem_fault(struct vm_fault *vmf) */ if (omap_obj->flags & OMAP_BO_TILED) - ret = fault_2d(obj, vma, vmf); + ret = omap_gem_fault_2d(obj, vma, vmf); else - ret = fault_1d(obj, vma, vmf); + ret = omap_gem_fault_1d(obj, vma, vmf); fail: @@ -689,7 +690,8 @@ int omap_gem_roll(struct drm_gem_object *obj, u32 roll) /* if we aren't mapped yet, we don't need to do anything */ if (omap_obj->block) { struct page **pages; - ret = get_pages(obj, &pages); + + ret = __omap_gem_get_pages(obj, &pages); if (ret) goto fail; ret = tiler_pin(omap_obj->block, pages, npages, roll, true); @@ -717,7 +719,7 @@ int omap_gem_roll(struct drm_gem_object *obj, u32 roll) * the omap_obj->dma_addrs[i] is set to the DMA address, and the page is * unmapped from the CPU. */ -static inline bool is_cached_coherent(struct drm_gem_object *obj) +static inline bool omap_gem_is_cached_coherent(struct drm_gem_object *obj) { struct omap_gem_object *omap_obj = to_omap_bo(obj); @@ -733,7 +735,7 @@ void omap_gem_cpu_sync_page(struct drm_gem_object *obj, int pgoff) struct drm_device *dev = obj->dev; struct omap_gem_object *omap_obj = to_omap_bo(obj); - if (is_cached_coherent(obj)) + if (omap_gem_is_cached_coherent(obj)) return; if (omap_obj->dma_addrs[pgoff]) { @@ -753,7 +755,7 @@ void omap_gem_dma_sync_buffer(struct drm_gem_object *obj, struct page **pages = omap_obj->pages; bool dirty = false; - if (is_cached_coherent(obj)) + if (omap_gem_is_cached_coherent(obj)) return; for (i = 0; i < npages; i++) { @@ -801,7 +803,7 @@ int omap_gem_pin(struct drm_gem_object *obj, dma_addr_t *dma_addr) mutex_lock(&obj->dev->struct_mutex); - if (!is_contiguous(omap_obj) && priv->has_dmm) { + if (!omap_gem_is_contiguous(omap_obj) && priv->has_dmm) { if (omap_obj->dma_addr_cnt == 0) { struct page **pages; u32 npages = obj->size >> PAGE_SHIFT; @@ -810,7 +812,7 @@ int omap_gem_pin(struct drm_gem_object *obj, dma_addr_t *dma_addr) BUG_ON(omap_obj->block); - ret = get_pages(obj, &pages); + ret = __omap_gem_get_pages(obj, &pages); if (ret) goto fail; @@ -848,7 +850,7 @@ int omap_gem_pin(struct drm_gem_object *obj, dma_addr_t *dma_addr) omap_obj->dma_addr_cnt++; *dma_addr = omap_obj->dma_addr; - } else if (is_contiguous(omap_obj)) { + } else if (omap_gem_is_contiguous(omap_obj)) { *dma_addr = omap_obj->dma_addr; } else { ret = -EINVAL; @@ -948,7 +950,7 @@ int omap_gem_get_pages(struct drm_gem_object *obj, struct page ***pages, return 0; } mutex_lock(&obj->dev->struct_mutex); - ret = get_pages(obj, pages); + ret = __omap_gem_get_pages(obj, pages); mutex_unlock(&obj->dev->struct_mutex); return ret; } @@ -974,7 +976,9 @@ void *omap_gem_vaddr(struct drm_gem_object *obj) WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex)); if (!omap_obj->vaddr) { struct page **pages; - int ret = get_pages(obj, &pages); + int ret; + + ret = __omap_gem_get_pages(obj, &pages); if (ret) return ERR_PTR(ret); omap_obj->vaddr = vmap(pages, obj->size >> PAGE_SHIFT, @@ -1076,7 +1080,7 @@ void omap_gem_free_object(struct drm_gem_object *obj) struct omap_drm_private *priv = dev->dev_private; struct omap_gem_object *omap_obj = to_omap_bo(obj); - evict(obj); + omap_gem_evict(obj); WARN_ON(!mutex_is_locked(&dev->struct_mutex)); -- GitLab From 2491244d7709d4e35f61d75ed3f6b4ea31b0a6f3 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Date: Fri, 25 May 2018 19:39:21 +0300 Subject: [PATCH 0556/1506] drm/omap: gem: Merge __omap_gem_get_pages() and omap_gem_attach_pages() The __omap_gem_get_pages() function is a wrapper around omap_gem_attach_pages() that returns the omap_obj->pages pointer through a function argument. Some callers don't need the pages pointer, and all of them can access omap_obj->pages directly. To simplify the code merge the __omap_gem_get_pages() wrapper with omap_gem_attach_pages() and update the callers accordingly. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ti.com> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com> --- drivers/gpu/drm/omapdrm/omap_gem.c | 59 ++++++++++-------------------- 1 file changed, 20 insertions(+), 39 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c index 7a4ee4edab5b2..a3efac4abd4b0 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.c +++ b/drivers/gpu/drm/omapdrm/omap_gem.c @@ -222,7 +222,7 @@ static void omap_gem_evict(struct drm_gem_object *obj) * Page Management */ -/** ensure backing pages are allocated */ +/* Ensure backing pages are allocated. */ static int omap_gem_attach_pages(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; @@ -232,7 +232,12 @@ static int omap_gem_attach_pages(struct drm_gem_object *obj) int i, ret; dma_addr_t *addrs; - WARN_ON(omap_obj->pages); + /* + * If not using shmem (in which case backing pages don't need to be + * allocated) or if pages are already allocated we're done. + */ + if (!(omap_obj->flags & OMAP_BO_MEM_SHMEM) || omap_obj->pages) + return 0; pages = drm_gem_get_pages(obj); if (IS_ERR(pages)) { @@ -288,29 +293,6 @@ static int omap_gem_attach_pages(struct drm_gem_object *obj) return ret; } -/* acquire pages when needed (for example, for DMA where physically - * contiguous buffer is not required - */ -static int __omap_gem_get_pages(struct drm_gem_object *obj, - struct page ***pages) -{ - struct omap_gem_object *omap_obj = to_omap_bo(obj); - int ret = 0; - - if ((omap_obj->flags & OMAP_BO_MEM_SHMEM) && !omap_obj->pages) { - ret = omap_gem_attach_pages(obj); - if (ret) { - dev_err(obj->dev->dev, "could not attach pages\n"); - return ret; - } - } - - /* TODO: even phys-contig.. we should have a list of pages? */ - *pages = omap_obj->pages; - - return 0; -} - /** release backing pages */ static void omap_gem_detach_pages(struct drm_gem_object *obj) { @@ -522,7 +504,6 @@ vm_fault_t omap_gem_fault(struct vm_fault *vmf) struct drm_gem_object *obj = vma->vm_private_data; struct omap_gem_object *omap_obj = to_omap_bo(obj); struct drm_device *dev = obj->dev; - struct page **pages; int err; vm_fault_t ret; @@ -532,7 +513,7 @@ vm_fault_t omap_gem_fault(struct vm_fault *vmf) mutex_lock(&dev->struct_mutex); /* if a shmem backed object, make sure we have pages attached now */ - err = __omap_gem_get_pages(obj, &pages); + err = omap_gem_attach_pages(obj); if (err) { ret = vmf_error(err); goto fail; @@ -689,12 +670,12 @@ int omap_gem_roll(struct drm_gem_object *obj, u32 roll) /* if we aren't mapped yet, we don't need to do anything */ if (omap_obj->block) { - struct page **pages; - - ret = __omap_gem_get_pages(obj, &pages); + ret = omap_gem_attach_pages(obj); if (ret) goto fail; - ret = tiler_pin(omap_obj->block, pages, npages, roll, true); + + ret = tiler_pin(omap_obj->block, omap_obj->pages, npages, + roll, true); if (ret) dev_err(obj->dev->dev, "could not repin: %d\n", ret); } @@ -805,14 +786,13 @@ int omap_gem_pin(struct drm_gem_object *obj, dma_addr_t *dma_addr) if (!omap_gem_is_contiguous(omap_obj) && priv->has_dmm) { if (omap_obj->dma_addr_cnt == 0) { - struct page **pages; u32 npages = obj->size >> PAGE_SHIFT; enum tiler_fmt fmt = gem2fmt(omap_obj->flags); struct tiler_block *block; BUG_ON(omap_obj->block); - ret = __omap_gem_get_pages(obj, &pages); + ret = omap_gem_attach_pages(obj); if (ret) goto fail; @@ -832,7 +812,7 @@ int omap_gem_pin(struct drm_gem_object *obj, dma_addr_t *dma_addr) } /* TODO: enable async refill.. */ - ret = tiler_pin(block, pages, npages, + ret = tiler_pin(block, omap_obj->pages, npages, omap_obj->roll, true); if (ret) { tiler_release(block); @@ -941,16 +921,18 @@ int omap_gem_tiled_stride(struct drm_gem_object *obj, u32 orient) int omap_gem_get_pages(struct drm_gem_object *obj, struct page ***pages, bool remap) { + struct omap_gem_object *omap_obj = to_omap_bo(obj); int ret; + if (!remap) { - struct omap_gem_object *omap_obj = to_omap_bo(obj); if (!omap_obj->pages) return -ENOMEM; *pages = omap_obj->pages; return 0; } mutex_lock(&obj->dev->struct_mutex); - ret = __omap_gem_get_pages(obj, pages); + ret = omap_gem_attach_pages(obj); + *pages = omap_obj->pages; mutex_unlock(&obj->dev->struct_mutex); return ret; } @@ -975,13 +957,12 @@ void *omap_gem_vaddr(struct drm_gem_object *obj) struct omap_gem_object *omap_obj = to_omap_bo(obj); WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex)); if (!omap_obj->vaddr) { - struct page **pages; int ret; - ret = __omap_gem_get_pages(obj, &pages); + ret = omap_gem_attach_pages(obj); if (ret) return ERR_PTR(ret); - omap_obj->vaddr = vmap(pages, obj->size >> PAGE_SHIFT, + omap_obj->vaddr = vmap(omap_obj->pages, obj->size >> PAGE_SHIFT, VM_MAP, pgprot_writecombine(PAGE_KERNEL)); } return omap_obj->vaddr; -- GitLab From dc8c9aeee5098688c1085691213fb9a703bf20ad Mon Sep 17 00:00:00 2001 From: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Date: Fri, 25 May 2018 19:39:22 +0300 Subject: [PATCH 0557/1506] drm/omap: gem: Don't take struct_mutex to get GEM object mmap offset GEM objects mmap offsets are created by calling drm_gem_create_mmap_offset_size() that doesn't need struct_mutex protection as it includes its own locking, based on a size that is static across the object's life time. Remove the unneeded struct_mutex locking. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ti.com> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com> --- drivers/gpu/drm/omapdrm/omap_gem.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c index a3efac4abd4b0..623856d9b85a9 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.c +++ b/drivers/gpu/drm/omapdrm/omap_gem.c @@ -137,14 +137,12 @@ struct omap_drm_usergart { */ /** get mmap offset */ -static u64 mmap_offset(struct drm_gem_object *obj) +u64 omap_gem_mmap_offset(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; int ret; size_t size; - WARN_ON(!mutex_is_locked(&dev->struct_mutex)); - /* Make it mmapable */ size = omap_gem_mmap_size(obj); ret = drm_gem_create_mmap_offset_size(obj, size); @@ -178,7 +176,7 @@ static void omap_gem_evict_entry(struct drm_gem_object *obj, struct omap_drm_private *priv = obj->dev->dev_private; int n = priv->usergart[fmt].height; size_t size = PAGE_SIZE * n; - loff_t off = mmap_offset(obj) + + loff_t off = omap_gem_mmap_offset(obj) + (entry->obj_pgoff << PAGE_SHIFT); const int m = DIV_ROUND_UP(omap_obj->width << fmt, PAGE_SIZE); @@ -319,16 +317,6 @@ u32 omap_gem_flags(struct drm_gem_object *obj) return to_omap_bo(obj)->flags; } -u64 omap_gem_mmap_offset(struct drm_gem_object *obj) -{ - u64 offset; - - mutex_lock(&obj->dev->struct_mutex); - offset = mmap_offset(obj); - mutex_unlock(&obj->dev->struct_mutex); - return offset; -} - /** get mmap size */ size_t omap_gem_mmap_size(struct drm_gem_object *obj) { -- GitLab From 3cbd0c587b129beaefb1405bbe43831e6bc9461e Mon Sep 17 00:00:00 2001 From: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Date: Sat, 26 May 2018 19:54:33 +0300 Subject: [PATCH 0558/1506] drm/omap: gem: Replace struct_mutex usage with omap_obj private lock The DRM device struct_mutex is used to protect against concurrent GEM object operations that deal with memory allocation and pinning. All those operations are local to a GEM object and don't need to be serialized across different GEM objects. Replace the struct_mutex with a local omap_obj.lock or drop it altogether where not needed. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ti.com> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com> --- drivers/gpu/drm/omapdrm/omap_debugfs.c | 7 -- drivers/gpu/drm/omapdrm/omap_fbdev.c | 8 +- drivers/gpu/drm/omapdrm/omap_gem.c | 127 +++++++++++++++++-------- 3 files changed, 86 insertions(+), 56 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/omap_debugfs.c b/drivers/gpu/drm/omapdrm/omap_debugfs.c index b42e286616b00..95ade441caa87 100644 --- a/drivers/gpu/drm/omapdrm/omap_debugfs.c +++ b/drivers/gpu/drm/omapdrm/omap_debugfs.c @@ -30,17 +30,10 @@ static int gem_show(struct seq_file *m, void *arg) struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; struct omap_drm_private *priv = dev->dev_private; - int ret; - - ret = mutex_lock_interruptible(&dev->struct_mutex); - if (ret) - return ret; seq_printf(m, "All Objects:\n"); omap_gem_describe_objects(&priv->obj_list, m); - mutex_unlock(&dev->struct_mutex); - return 0; } diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c index 0f66c74a54b0e..d958cc813a94c 100644 --- a/drivers/gpu/drm/omapdrm/omap_fbdev.c +++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c @@ -170,13 +170,11 @@ static int omap_fbdev_create(struct drm_fb_helper *helper, goto fail; } - mutex_lock(&dev->struct_mutex); - fbi = drm_fb_helper_alloc_fbi(helper); if (IS_ERR(fbi)) { dev_err(dev->dev, "failed to allocate fb info\n"); ret = PTR_ERR(fbi); - goto fail_unlock; + goto fail; } DBG("fbi=%p, dev=%p", fbi, dev); @@ -212,12 +210,8 @@ static int omap_fbdev_create(struct drm_fb_helper *helper, DBG("par=%p, %dx%d", fbi->par, fbi->var.xres, fbi->var.yres); DBG("allocated %dx%d fb", fbdev->fb->width, fbdev->fb->height); - mutex_unlock(&dev->struct_mutex); - return 0; -fail_unlock: - mutex_unlock(&dev->struct_mutex); fail: if (ret) { diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c index 623856d9b85a9..cebbdf081e5dd 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.c +++ b/drivers/gpu/drm/omapdrm/omap_gem.c @@ -47,6 +47,9 @@ struct omap_gem_object { /** roll applied when mapping to DMM */ u32 roll; + /** protects dma_addr_cnt, block, pages, dma_addrs and vaddr */ + struct mutex lock; + /** * dma_addr contains the buffer DMA address. It is valid for * @@ -220,7 +223,10 @@ static void omap_gem_evict(struct drm_gem_object *obj) * Page Management */ -/* Ensure backing pages are allocated. */ +/* + * Ensure backing pages are allocated. Must be called with the omap_obj.lock + * held. + */ static int omap_gem_attach_pages(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; @@ -230,6 +236,8 @@ static int omap_gem_attach_pages(struct drm_gem_object *obj) int i, ret; dma_addr_t *addrs; + lockdep_assert_held(&omap_obj->lock); + /* * If not using shmem (in which case backing pages don't need to be * allocated) or if pages are already allocated we're done. @@ -291,13 +299,15 @@ static int omap_gem_attach_pages(struct drm_gem_object *obj) return ret; } -/** release backing pages */ +/* Release backing pages. Must be called with the omap_obj.lock held. */ static void omap_gem_detach_pages(struct drm_gem_object *obj) { struct omap_gem_object *omap_obj = to_omap_bo(obj); unsigned int npages = obj->size >> PAGE_SHIFT; unsigned int i; + lockdep_assert_held(&omap_obj->lock); + for (i = 0; i < npages; i++) { if (omap_obj->dma_addrs[i]) dma_unmap_page(obj->dev->dev, omap_obj->dma_addrs[i], @@ -491,14 +501,13 @@ vm_fault_t omap_gem_fault(struct vm_fault *vmf) struct vm_area_struct *vma = vmf->vma; struct drm_gem_object *obj = vma->vm_private_data; struct omap_gem_object *omap_obj = to_omap_bo(obj); - struct drm_device *dev = obj->dev; int err; vm_fault_t ret; /* Make sure we don't parallel update on a fault, nor move or remove * something from beneath our feet */ - mutex_lock(&dev->struct_mutex); + mutex_lock(&omap_obj->lock); /* if a shmem backed object, make sure we have pages attached now */ err = omap_gem_attach_pages(obj); @@ -520,7 +529,7 @@ vm_fault_t omap_gem_fault(struct vm_fault *vmf) fail: - mutex_unlock(&dev->struct_mutex); + mutex_unlock(&omap_obj->lock); return ret; } @@ -654,7 +663,7 @@ int omap_gem_roll(struct drm_gem_object *obj, u32 roll) omap_obj->roll = roll; - mutex_lock(&obj->dev->struct_mutex); + mutex_lock(&omap_obj->lock); /* if we aren't mapped yet, we don't need to do anything */ if (omap_obj->block) { @@ -669,7 +678,7 @@ int omap_gem_roll(struct drm_gem_object *obj, u32 roll) } fail: - mutex_unlock(&obj->dev->struct_mutex); + mutex_unlock(&omap_obj->lock); return ret; } @@ -770,7 +779,7 @@ int omap_gem_pin(struct drm_gem_object *obj, dma_addr_t *dma_addr) struct omap_gem_object *omap_obj = to_omap_bo(obj); int ret = 0; - mutex_lock(&obj->dev->struct_mutex); + mutex_lock(&omap_obj->lock); if (!omap_gem_is_contiguous(omap_obj) && priv->has_dmm) { if (omap_obj->dma_addr_cnt == 0) { @@ -826,7 +835,7 @@ int omap_gem_pin(struct drm_gem_object *obj, dma_addr_t *dma_addr) } fail: - mutex_unlock(&obj->dev->struct_mutex); + mutex_unlock(&omap_obj->lock); return ret; } @@ -844,7 +853,8 @@ void omap_gem_unpin(struct drm_gem_object *obj) struct omap_gem_object *omap_obj = to_omap_bo(obj); int ret; - mutex_lock(&obj->dev->struct_mutex); + mutex_lock(&omap_obj->lock); + if (omap_obj->dma_addr_cnt > 0) { omap_obj->dma_addr_cnt--; if (omap_obj->dma_addr_cnt == 0) { @@ -863,7 +873,7 @@ void omap_gem_unpin(struct drm_gem_object *obj) } } - mutex_unlock(&obj->dev->struct_mutex); + mutex_unlock(&omap_obj->lock); } /* Get rotated scanout address (only valid if already pinned), at the @@ -876,13 +886,16 @@ int omap_gem_rotated_dma_addr(struct drm_gem_object *obj, u32 orient, struct omap_gem_object *omap_obj = to_omap_bo(obj); int ret = -EINVAL; - mutex_lock(&obj->dev->struct_mutex); + mutex_lock(&omap_obj->lock); + if ((omap_obj->dma_addr_cnt > 0) && omap_obj->block && (omap_obj->flags & OMAP_BO_TILED)) { *dma_addr = tiler_tsptr(omap_obj->block, orient, x, y); ret = 0; } - mutex_unlock(&obj->dev->struct_mutex); + + mutex_unlock(&omap_obj->lock); + return ret; } @@ -910,18 +923,26 @@ int omap_gem_get_pages(struct drm_gem_object *obj, struct page ***pages, bool remap) { struct omap_gem_object *omap_obj = to_omap_bo(obj); - int ret; + int ret = 0; - if (!remap) { - if (!omap_obj->pages) - return -ENOMEM; - *pages = omap_obj->pages; - return 0; + mutex_lock(&omap_obj->lock); + + if (remap) { + ret = omap_gem_attach_pages(obj); + if (ret) + goto unlock; } - mutex_lock(&obj->dev->struct_mutex); - ret = omap_gem_attach_pages(obj); + + if (!omap_obj->pages) { + ret = -ENOMEM; + goto unlock; + } + *pages = omap_obj->pages; - mutex_unlock(&obj->dev->struct_mutex); + +unlock: + mutex_unlock(&omap_obj->lock); + return ret; } @@ -936,24 +957,34 @@ int omap_gem_put_pages(struct drm_gem_object *obj) } #ifdef CONFIG_DRM_FBDEV_EMULATION -/* Get kernel virtual address for CPU access.. this more or less only - * exists for omap_fbdev. This should be called with struct_mutex - * held. +/* + * Get kernel virtual address for CPU access.. this more or less only + * exists for omap_fbdev. */ void *omap_gem_vaddr(struct drm_gem_object *obj) { struct omap_gem_object *omap_obj = to_omap_bo(obj); - WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex)); - if (!omap_obj->vaddr) { - int ret; + void *vaddr; + int ret; + + mutex_lock(&omap_obj->lock); + if (!omap_obj->vaddr) { ret = omap_gem_attach_pages(obj); - if (ret) - return ERR_PTR(ret); + if (ret) { + vaddr = ERR_PTR(ret); + goto unlock; + } + omap_obj->vaddr = vmap(omap_obj->pages, obj->size >> PAGE_SHIFT, VM_MAP, pgprot_writecombine(PAGE_KERNEL)); } - return omap_obj->vaddr; + + vaddr = omap_obj->vaddr; + +unlock: + mutex_unlock(&omap_obj->lock); + return vaddr; } #endif @@ -1001,6 +1032,8 @@ void omap_gem_describe(struct drm_gem_object *obj, struct seq_file *m) off = drm_vma_node_start(&obj->vma_node); + mutex_lock(&omap_obj->lock); + seq_printf(m, "%08x: %2d (%2d) %08llx %pad (%2d) %p %4d", omap_obj->flags, obj->name, kref_read(&obj->refcount), off, &omap_obj->dma_addr, omap_obj->dma_addr_cnt, @@ -1018,6 +1051,8 @@ void omap_gem_describe(struct drm_gem_object *obj, struct seq_file *m) seq_printf(m, " %zu", obj->size); } + mutex_unlock(&omap_obj->lock); + seq_printf(m, "\n"); } @@ -1051,15 +1086,19 @@ void omap_gem_free_object(struct drm_gem_object *obj) omap_gem_evict(obj); - WARN_ON(!mutex_is_locked(&dev->struct_mutex)); - spin_lock(&priv->list_lock); list_del(&omap_obj->mm_list); spin_unlock(&priv->list_lock); - /* this means the object is still pinned.. which really should - * not happen. I think.. + /* + * We own the sole reference to the object at this point, but to keep + * lockdep happy, we must still take the omap_obj_lock to call + * omap_gem_detach_pages(). This should hardly make any difference as + * there can't be any lock contention. */ + mutex_lock(&omap_obj->lock); + + /* The object should not be pinned. */ WARN_ON(omap_obj->dma_addr_cnt > 0); if (omap_obj->pages) { @@ -1078,8 +1117,12 @@ void omap_gem_free_object(struct drm_gem_object *obj) drm_prime_gem_destroy(obj, omap_obj->sgt); } + mutex_unlock(&omap_obj->lock); + drm_gem_object_release(obj); + mutex_destroy(&omap_obj->lock); + kfree(omap_obj); } @@ -1135,6 +1178,7 @@ struct drm_gem_object *omap_gem_new(struct drm_device *dev, obj = &omap_obj->base; omap_obj->flags = flags; + mutex_init(&omap_obj->lock); if (flags & OMAP_BO_TILED) { /* @@ -1199,16 +1243,15 @@ struct drm_gem_object *omap_gem_new_dmabuf(struct drm_device *dev, size_t size, if (sgt->orig_nents != 1 && !priv->has_dmm) return ERR_PTR(-EINVAL); - mutex_lock(&dev->struct_mutex); - gsize.bytes = PAGE_ALIGN(size); obj = omap_gem_new(dev, gsize, OMAP_BO_MEM_DMABUF | OMAP_BO_WC); - if (!obj) { - obj = ERR_PTR(-ENOMEM); - goto done; - } + if (!obj) + return ERR_PTR(-ENOMEM); omap_obj = to_omap_bo(obj); + + mutex_lock(&omap_obj->lock); + omap_obj->sgt = sgt; if (sgt->orig_nents == 1) { @@ -1244,7 +1287,7 @@ struct drm_gem_object *omap_gem_new_dmabuf(struct drm_device *dev, size_t size, } done: - mutex_unlock(&dev->struct_mutex); + mutex_unlock(&omap_obj->lock); return obj; } -- GitLab From 5117bd898e8c0a31e8ab3a9b8523aecf0706e997 Mon Sep 17 00:00:00 2001 From: Daniel Vetter <daniel.vetter@ffwll.ch> Date: Fri, 25 May 2018 19:39:24 +0300 Subject: [PATCH 0559/1506] drm/omap: gem: Fix mm_list locking - None of the list walkings where protected. - Switch to a mutex since the list walking at device resume time can sleep when pinning buffers through the tiler. Only thing we need to be careful with here is that while we walk the list we can't unreference any gem objects, since the final unref would result in a recursive deadlock. But the only functions that walk the list is the device resume and debugfs dumping, so all safe. Signed-off-by: Daniel Vetter <daniel.vetter@intel.com> Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ti.com> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com> --- drivers/gpu/drm/omapdrm/omap_debugfs.c | 2 ++ drivers/gpu/drm/omapdrm/omap_drv.c | 2 +- drivers/gpu/drm/omapdrm/omap_drv.h | 2 +- drivers/gpu/drm/omapdrm/omap_gem.c | 15 +++++++++------ 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/omap_debugfs.c b/drivers/gpu/drm/omapdrm/omap_debugfs.c index 95ade441caa87..91cf043f2b6ba 100644 --- a/drivers/gpu/drm/omapdrm/omap_debugfs.c +++ b/drivers/gpu/drm/omapdrm/omap_debugfs.c @@ -32,7 +32,9 @@ static int gem_show(struct seq_file *m, void *arg) struct omap_drm_private *priv = dev->dev_private; seq_printf(m, "All Objects:\n"); + mutex_lock(&priv->list_lock); omap_gem_describe_objects(&priv->obj_list, m); + mutex_unlock(&priv->list_lock); return 0; } diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index ef3b0e3571ec8..5fcf9eaf3eafe 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -540,7 +540,7 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev) priv->omaprev = soc ? (unsigned int)soc->data : 0; priv->wq = alloc_ordered_workqueue("omapdrm", 0); - spin_lock_init(&priv->list_lock); + mutex_init(&priv->list_lock); INIT_LIST_HEAD(&priv->obj_list); /* Allocate and initialize the DRM device. */ diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h index 6eaee4df45594..f27c8e216adf8 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.h +++ b/drivers/gpu/drm/omapdrm/omap_drv.h @@ -71,7 +71,7 @@ struct omap_drm_private { struct workqueue_struct *wq; /* lock for obj_list below */ - spinlock_t list_lock; + struct mutex list_lock; /* list of GEM objects: */ struct list_head obj_list; diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c index cebbdf081e5dd..4ba5d035c5909 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.c +++ b/drivers/gpu/drm/omapdrm/omap_gem.c @@ -1000,6 +1000,7 @@ int omap_gem_resume(struct drm_device *dev) struct omap_gem_object *omap_obj; int ret = 0; + mutex_lock(&priv->list_lock); list_for_each_entry(omap_obj, &priv->obj_list, mm_list) { if (omap_obj->block) { struct drm_gem_object *obj = &omap_obj->base; @@ -1011,12 +1012,14 @@ int omap_gem_resume(struct drm_device *dev) omap_obj->roll, true); if (ret) { dev_err(dev->dev, "could not repin: %d\n", ret); - return ret; + goto done; } } } - return 0; +done: + mutex_unlock(&priv->list_lock); + return ret; } #endif @@ -1086,9 +1089,9 @@ void omap_gem_free_object(struct drm_gem_object *obj) omap_gem_evict(obj); - spin_lock(&priv->list_lock); + mutex_lock(&priv->list_lock); list_del(&omap_obj->mm_list); - spin_unlock(&priv->list_lock); + mutex_unlock(&priv->list_lock); /* * We own the sole reference to the object at this point, but to keep @@ -1218,9 +1221,9 @@ struct drm_gem_object *omap_gem_new(struct drm_device *dev, goto err_release; } - spin_lock(&priv->list_lock); + mutex_lock(&priv->list_lock); list_add(&omap_obj->mm_list, &priv->obj_list); - spin_unlock(&priv->list_lock); + mutex_unlock(&priv->list_lock); return obj; -- GitLab From f8466184bd5b5c21eb6196cd0e44668725a2e47a Mon Sep 17 00:00:00 2001 From: Daniel Vetter <daniel.vetter@ffwll.ch> Date: Fri, 25 May 2018 19:39:25 +0300 Subject: [PATCH 0560/1506] drm/omap: gem: Switch to gem_free_object_unlocked() The only thing that omap_gem_free_object does that might need the magic protection of struct_mutex (of keeping all objects alive if that lock is held, even if the last reference is gone) is the mm_list manipulation. This is already protected by the separate omapdrm->list_lock, which means that struct_mutex is not needed by omapdrm. We can switch to gem_free_object_unlocked() Signed-off-by: Daniel Vetter <daniel.vetter@intel.com> Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ti.com> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com> --- drivers/gpu/drm/omapdrm/omap_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index 5fcf9eaf3eafe..5005ecc284d22 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -493,7 +493,7 @@ static struct drm_driver omap_drm_driver = { .prime_fd_to_handle = drm_gem_prime_fd_to_handle, .gem_prime_export = omap_gem_prime_export, .gem_prime_import = omap_gem_prime_import, - .gem_free_object = omap_gem_free_object, + .gem_free_object_unlocked = omap_gem_free_object, .gem_vm_ops = &omap_gem_vm_ops, .dumb_create = omap_gem_dumb_create, .dumb_map_offset = omap_gem_dumb_map_offset, -- GitLab From d48de54a9dab5370edd2e991f78cc7996cf5483e Mon Sep 17 00:00:00 2001 From: Hans de Goede <hdegoede@redhat.com> Date: Thu, 28 Jun 2018 15:20:27 +0200 Subject: [PATCH 0561/1506] printk: Export is_console_locked This is a preparation patch for adding a number of WARN_CONSOLE_UNLOCKED() calls to the fbcon code, which may be built as a module (event though usually it is not). Acked-by: Steven Rostedt (VMware) <rostedt@goodmis.org> Acked-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com> Acked-by: Petr Mladek <pmladek@suse.com> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com> --- kernel/printk/printk.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 247808333ba43..3f041e7cbfc9e 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -2243,6 +2243,7 @@ int is_console_locked(void) { return console_locked; } +EXPORT_SYMBOL(is_console_locked); /* * Check if we have any console that is capable of printing while cpu is -- GitLab From 3bd3a0e330aae4fffa8028aba2407ef615ab040b Mon Sep 17 00:00:00 2001 From: Hans de Goede <hdegoede@redhat.com> Date: Thu, 28 Jun 2018 15:20:28 +0200 Subject: [PATCH 0562/1506] fbcon: Call WARN_CONSOLE_UNLOCKED() where applicable Replace comments about places where the console lock should be held with calls to WARN_CONSOLE_UNLOCKED() to assert that it is actually held. Acked-by: Steven Rostedt (VMware) <rostedt@goodmis.org> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Reviewed-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com> Signed-off-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com> --- drivers/video/fbdev/core/fbcon.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index c910e74d46fff..cd8d52a967aae 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -828,6 +828,8 @@ static int set_con2fb_map(int unit, int newidx, int user) struct fb_info *oldinfo = NULL; int found, err = 0; + WARN_CONSOLE_UNLOCKED(); + if (oldidx == newidx) return 0; @@ -3044,6 +3046,8 @@ static int fbcon_fb_unbind(int idx) { int i, new_idx = -1, ret = 0; + WARN_CONSOLE_UNLOCKED(); + if (!fbcon_has_console_bind) return 0; @@ -3094,6 +3098,8 @@ static int fbcon_fb_unregistered(struct fb_info *info) { int i, idx; + WARN_CONSOLE_UNLOCKED(); + idx = info->node; for (i = first_fb_vc; i <= last_fb_vc; i++) { if (con2fb_map[i] == idx) @@ -3131,6 +3137,9 @@ static int fbcon_fb_unregistered(struct fb_info *info) static void fbcon_remap_all(int idx) { int i; + + WARN_CONSOLE_UNLOCKED(); + for (i = first_fb_vc; i <= last_fb_vc; i++) set_con2fb_map(i, idx, 0); @@ -3177,6 +3186,8 @@ static int fbcon_fb_registered(struct fb_info *info) { int ret = 0, i, idx; + WARN_CONSOLE_UNLOCKED(); + idx = info->node; fbcon_select_primary(info); -- GitLab From 83d83bebf40132e2d55ec58af666713cc76f9764 Mon Sep 17 00:00:00 2001 From: Hans de Goede <hdegoede@redhat.com> Date: Thu, 28 Jun 2018 15:20:30 +0200 Subject: [PATCH 0563/1506] console/fbcon: Add support for deferred console takeover Currently fbcon claims fbdevs as soon as they are registered and takes over the console as soon as the first fbdev gets registered. This behavior is undesirable in cases where a smooth graphical bootup is desired, in such cases we typically want the contents of the framebuffer (typically a vendor logo) to stay in place as is. The current solution for this problem (on embedded systems) is to not enable fbcon. This commit adds a new FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER config option, which when enabled defers fbcon taking over the console from the dummy console until the first text is displayed on the console. Together with the "quiet" kernel commandline option, this allows fbcon to still be used together with a smooth graphical bootup, having it take over the console as soon as e.g. an error message is logged. Note the choice to detect the first console output in the dummycon driver, rather then handling this entirely inside the fbcon code, was made after 2 failed attempts to handle this entirely inside the fbcon code. The fbcon code is woven quite tightly into the console code, making this to only feasible option. Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com> --- Documentation/fb/fbcon.txt | 7 ++++ drivers/video/console/Kconfig | 11 +++++ drivers/video/console/dummycon.c | 67 +++++++++++++++++++++++++---- drivers/video/fbdev/core/fbcon.c | 72 ++++++++++++++++++++++++++++++++ include/linux/console.h | 5 +++ 5 files changed, 154 insertions(+), 8 deletions(-) diff --git a/Documentation/fb/fbcon.txt b/Documentation/fb/fbcon.txt index 79c22d096bbc0..d4d642e1ce9ce 100644 --- a/Documentation/fb/fbcon.txt +++ b/Documentation/fb/fbcon.txt @@ -155,6 +155,13 @@ C. Boot options used by text. By default, this area will be black. The 'color' value is an integer number that depends on the framebuffer driver being used. +6. fbcon=nodefer + + If the kernel is compiled with deferred fbcon takeover support, normally + the framebuffer contents, left in place by the firmware/bootloader, will + be preserved until there actually is some text is output to the console. + This option causes fbcon to bind immediately to the fbdev device. + C. Attaching, Detaching and Unloading Before going on how to attach, detach and unload the framebuffer console, an diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index 4110ba7d7ca90..e91edef98633e 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig @@ -150,6 +150,17 @@ config FRAMEBUFFER_CONSOLE_ROTATION such that other users of the framebuffer will remain normally oriented. +config FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER + bool "Framebuffer Console Deferred Takeover" + depends on FRAMEBUFFER_CONSOLE=y && DUMMY_CONSOLE=y + help + If enabled this defers the framebuffer console taking over the + console from the dummy console until the first text is displayed on + the console. This is useful in combination with the "quiet" kernel + commandline option to keep the framebuffer contents initially put up + by the firmware in place, rather then replacing the contents with a + black screen as soon as fbcon loads. + config STI_CONSOLE bool "STI text console" depends on PARISC && HAS_IOMEM diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c index f2eafe2ed9806..45ad925ad5f8f 100644 --- a/drivers/video/console/dummycon.c +++ b/drivers/video/console/dummycon.c @@ -26,6 +26,65 @@ #define DUMMY_ROWS CONFIG_DUMMY_CONSOLE_ROWS #endif +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER +/* These are both protected by the console_lock */ +static RAW_NOTIFIER_HEAD(dummycon_output_nh); +static bool dummycon_putc_called; + +void dummycon_register_output_notifier(struct notifier_block *nb) +{ + raw_notifier_chain_register(&dummycon_output_nh, nb); + + if (dummycon_putc_called) + nb->notifier_call(nb, 0, NULL); +} + +void dummycon_unregister_output_notifier(struct notifier_block *nb) +{ + raw_notifier_chain_unregister(&dummycon_output_nh, nb); +} + +static void dummycon_putc(struct vc_data *vc, int c, int ypos, int xpos) +{ + dummycon_putc_called = true; + raw_notifier_call_chain(&dummycon_output_nh, 0, NULL); +} + +static void dummycon_putcs(struct vc_data *vc, const unsigned short *s, + int count, int ypos, int xpos) +{ + int i; + + if (!dummycon_putc_called) { + /* Ignore erases */ + for (i = 0 ; i < count; i++) { + if (s[i] != vc->vc_video_erase_char) + break; + } + if (i == count) + return; + + dummycon_putc_called = true; + } + + raw_notifier_call_chain(&dummycon_output_nh, 0, NULL); +} + +static int dummycon_blank(struct vc_data *vc, int blank, int mode_switch) +{ + /* Redraw, so that we get putc(s) for output done while blanked */ + return 1; +} +#else +static void dummycon_putc(struct vc_data *vc, int c, int ypos, int xpos) { } +static void dummycon_putcs(struct vc_data *vc, const unsigned short *s, + int count, int ypos, int xpos) { } +static int dummycon_blank(struct vc_data *vc, int blank, int mode_switch) +{ + return 0; +} +#endif + static const char *dummycon_startup(void) { return "dummy device"; @@ -44,9 +103,6 @@ static void dummycon_init(struct vc_data *vc, int init) static void dummycon_deinit(struct vc_data *vc) { } static void dummycon_clear(struct vc_data *vc, int sy, int sx, int height, int width) { } -static void dummycon_putc(struct vc_data *vc, int c, int ypos, int xpos) { } -static void dummycon_putcs(struct vc_data *vc, const unsigned short *s, - int count, int ypos, int xpos) { } static void dummycon_cursor(struct vc_data *vc, int mode) { } static bool dummycon_scroll(struct vc_data *vc, unsigned int top, @@ -61,11 +117,6 @@ static int dummycon_switch(struct vc_data *vc) return 0; } -static int dummycon_blank(struct vc_data *vc, int blank, int mode_switch) -{ - return 0; -} - static int dummycon_font_set(struct vc_data *vc, struct console_font *font, unsigned int flags) { diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index cd8d52a967aae..5fb156bdcf4e5 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -129,6 +129,12 @@ static inline void fbcon_map_override(void) } #endif /* CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY */ +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER +static bool deferred_takeover = true; +#else +#define deferred_takeover false +#endif + /* font data */ static char fontname[40]; @@ -499,6 +505,12 @@ static int __init fb_console_setup(char *this_opt) margin_color = simple_strtoul(options, &options, 0); continue; } +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER + if (!strcmp(options, "nodefer")) { + deferred_takeover = false; + continue; + } +#endif } return 1; } @@ -3100,6 +3112,9 @@ static int fbcon_fb_unregistered(struct fb_info *info) WARN_CONSOLE_UNLOCKED(); + if (deferred_takeover) + return 0; + idx = info->node; for (i = first_fb_vc; i <= last_fb_vc; i++) { if (con2fb_map[i] == idx) @@ -3140,6 +3155,13 @@ static void fbcon_remap_all(int idx) WARN_CONSOLE_UNLOCKED(); + if (deferred_takeover) { + for (i = first_fb_vc; i <= last_fb_vc; i++) + con2fb_map_boot[i] = idx; + fbcon_map_override(); + return; + } + for (i = first_fb_vc; i <= last_fb_vc; i++) set_con2fb_map(i, idx, 0); @@ -3191,6 +3213,11 @@ static int fbcon_fb_registered(struct fb_info *info) idx = info->node; fbcon_select_primary(info); + if (deferred_takeover) { + pr_info("fbcon: Deferring console take-over\n"); + return 0; + } + if (info_idx == -1) { for (i = first_fb_vc; i <= last_fb_vc; i++) { if (con2fb_map_boot[i] == idx) { @@ -3566,8 +3593,46 @@ static int fbcon_init_device(void) return 0; } +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER +static struct notifier_block fbcon_output_nb; + +static int fbcon_output_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + int i; + + WARN_CONSOLE_UNLOCKED(); + + pr_info("fbcon: Taking over console\n"); + + dummycon_unregister_output_notifier(&fbcon_output_nb); + deferred_takeover = false; + logo_shown = FBCON_LOGO_DONTSHOW; + + for (i = 0; i < FB_MAX; i++) { + if (registered_fb[i]) + fbcon_fb_registered(registered_fb[i]); + } + + return NOTIFY_OK; +} + +static void fbcon_register_output_notifier(void) +{ + fbcon_output_nb.notifier_call = fbcon_output_notifier; + dummycon_register_output_notifier(&fbcon_output_nb); +} +#else +static inline void fbcon_register_output_notifier(void) {} +#endif + static void fbcon_start(void) { + if (deferred_takeover) { + fbcon_register_output_notifier(); + return; + } + if (num_registered_fb) { int i; @@ -3594,6 +3659,13 @@ static void fbcon_exit(void) if (fbcon_has_exited) return; +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER + if (deferred_takeover) { + dummycon_unregister_output_notifier(&fbcon_output_nb); + deferred_takeover = false; + } +#endif + kfree((void *)softback_buf); softback_buf = 0UL; diff --git a/include/linux/console.h b/include/linux/console.h index dfd6b0e978551..f59f3dbca65cb 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -21,6 +21,7 @@ struct console_font_op; struct console_font; struct module; struct tty_struct; +struct notifier_block; /* * this is what the terminal answers to a ESC-Z or csi0c query. @@ -220,4 +221,8 @@ static inline bool vgacon_text_force(void) { return false; } extern void console_init(void); +/* For deferred console takeover */ +void dummycon_register_output_notifier(struct notifier_block *nb); +void dummycon_unregister_output_notifier(struct notifier_block *nb); + #endif /* _LINUX_CONSOLE_H */ -- GitLab From ef196b5c2f4fb7a701a8f189cdcba94f422c9009 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann <tdz@users.sourceforge.net> Date: Mon, 18 Jun 2018 13:01:50 +0200 Subject: [PATCH 0564/1506] drm/i915: Replace drm_connector_{un/reference} with put,get functions This patch unifies the naming of DRM functions for reference counting of struct drm_connector. The resulting code is more aligned with the rest of the Linux kernel interfaces. Signed-off-by: Thomas Zimmermann <tdz@users.sourceforge.net> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180618110154.30462-2-tdz@users.sourceforge.net --- drivers/gpu/drm/i915/intel_display.c | 4 ++-- drivers/gpu/drm/i915/intel_dp_mst.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0db23292eb359..fca72ce0b3b34 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10737,7 +10737,7 @@ static void intel_modeset_update_connector_atomic_state(struct drm_device *dev) drm_connector_list_iter_begin(dev, &conn_iter); for_each_intel_connector_iter(connector, &conn_iter) { if (connector->base.state->crtc) - drm_connector_unreference(&connector->base); + drm_connector_put(&connector->base); if (connector->base.encoder) { connector->base.state->best_encoder = @@ -10745,7 +10745,7 @@ static void intel_modeset_update_connector_atomic_state(struct drm_device *dev) connector->base.state->crtc = connector->base.encoder->crtc; - drm_connector_reference(&connector->base); + drm_connector_get(&connector->base); } else { connector->base.state->best_encoder = NULL; connector->base.state->crtc = NULL; diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index 5890500a3a8b6..789a403e9f99b 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -524,7 +524,7 @@ static void intel_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr, intel_connector->mst_port = NULL; drm_modeset_unlock(&connector->dev->mode_config.connection_mutex); - drm_connector_unreference(connector); + drm_connector_put(connector); } static void intel_dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr) -- GitLab From 0f67706e6600cab897e1806133eea7f5000a2789 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann <tdz@users.sourceforge.net> Date: Mon, 18 Jun 2018 13:01:51 +0200 Subject: [PATCH 0565/1506] drm/i915: Replace drm_gem_object_{un/reference} with {put,get} functions This patch unifies the naming of DRM functions for reference counting of struct drm_gem_object. The resulting code is more aligned with the rest of the Linux kernel interfaces. Signed-off-by: Thomas Zimmermann <tdz@users.sourceforge.net> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180618110154.30462-3-tdz@users.sourceforge.net --- drivers/gpu/drm/i915/i915_gem_object.h | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_object.h b/drivers/gpu/drm/i915/i915_gem_object.h index 54f00b3507797..da6e849f41a45 100644 --- a/drivers/gpu/drm/i915/i915_gem_object.h +++ b/drivers/gpu/drm/i915/i915_gem_object.h @@ -337,13 +337,10 @@ __attribute__((nonnull)) static inline struct drm_i915_gem_object * i915_gem_object_get(struct drm_i915_gem_object *obj) { - drm_gem_object_reference(&obj->base); + drm_gem_object_get(&obj->base); return obj; } -__deprecated -extern void drm_gem_object_reference(struct drm_gem_object *); - __attribute__((nonnull)) static inline void i915_gem_object_put(struct drm_i915_gem_object *obj) @@ -351,9 +348,6 @@ i915_gem_object_put(struct drm_i915_gem_object *obj) __drm_gem_object_unreference(&obj->base); } -__deprecated -extern void drm_gem_object_unreference(struct drm_gem_object *); - __deprecated extern void drm_gem_object_unreference_unlocked(struct drm_gem_object *); -- GitLab From 55f95c2723daedb44b0552c6ab10401e0bd32a22 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann <tdz@users.sourceforge.net> Date: Mon, 18 Jun 2018 13:01:52 +0200 Subject: [PATCH 0566/1506] drm/i915: Replace __drm_gem_object_unreference with __drm_gem_object_put This patch unifies the naming of DRM functions for reference counting of struct drm_gem_object. The resulting code is more aligned with the rest of the Linux kernel interfaces. Signed-off-by: Thomas Zimmermann <tdz@users.sourceforge.net> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180618110154.30462-4-tdz@users.sourceforge.net --- drivers/gpu/drm/i915/i915_gem_object.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_object.h b/drivers/gpu/drm/i915/i915_gem_object.h index da6e849f41a45..0042496216fe1 100644 --- a/drivers/gpu/drm/i915/i915_gem_object.h +++ b/drivers/gpu/drm/i915/i915_gem_object.h @@ -345,7 +345,7 @@ __attribute__((nonnull)) static inline void i915_gem_object_put(struct drm_i915_gem_object *obj) { - __drm_gem_object_unreference(&obj->base); + __drm_gem_object_put(&obj->base); } __deprecated -- GitLab From 01159b47a400fa8ba7026dd647d52e89ef7322bd Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann <tdz@users.sourceforge.net> Date: Mon, 18 Jun 2018 13:01:53 +0200 Subject: [PATCH 0567/1506] drm/i915: Replace drm_gem_object_unreference_unlocked with put function This patch unifies the naming of DRM functions for reference counting of struct drm_gem_object. The resulting code is more aligned with the rest of the Linux kernel interfaces. Signed-off-by: Thomas Zimmermann <tdz@users.sourceforge.net> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180618110154.30462-5-tdz@users.sourceforge.net --- drivers/gpu/drm/i915/i915_gem_object.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_object.h b/drivers/gpu/drm/i915/i915_gem_object.h index 0042496216fe1..c3c6f2e588fbe 100644 --- a/drivers/gpu/drm/i915/i915_gem_object.h +++ b/drivers/gpu/drm/i915/i915_gem_object.h @@ -348,9 +348,6 @@ i915_gem_object_put(struct drm_i915_gem_object *obj) __drm_gem_object_put(&obj->base); } -__deprecated -extern void drm_gem_object_unreference_unlocked(struct drm_gem_object *); - static inline void i915_gem_object_lock(struct drm_i915_gem_object *obj) { reservation_object_lock(obj->resv, NULL); -- GitLab From a24362ead99ab5d39b594a7b4ff48abc9addc059 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann <tdz@users.sourceforge.net> Date: Mon, 18 Jun 2018 13:01:54 +0200 Subject: [PATCH 0568/1506] drm/i915: 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 <tdz@users.sourceforge.net> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180618110154.30462-6-tdz@users.sourceforge.net --- drivers/gpu/drm/i915/selftests/huge_pages.c | 2 +- drivers/gpu/drm/i915/selftests/i915_gem_context.c | 2 +- drivers/gpu/drm/i915/selftests/i915_gem_dmabuf.c | 2 +- drivers/gpu/drm/i915/selftests/i915_gem_evict.c | 2 +- drivers/gpu/drm/i915/selftests/i915_gem_gtt.c | 2 +- drivers/gpu/drm/i915/selftests/i915_gem_object.c | 2 +- drivers/gpu/drm/i915/selftests/i915_request.c | 2 +- drivers/gpu/drm/i915/selftests/i915_vma.c | 2 +- drivers/gpu/drm/i915/selftests/intel_breadcrumbs.c | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/selftests/huge_pages.c b/drivers/gpu/drm/i915/selftests/huge_pages.c index fbe4324116d72..b5e87fcdcdae4 100644 --- a/drivers/gpu/drm/i915/selftests/huge_pages.c +++ b/drivers/gpu/drm/i915/selftests/huge_pages.c @@ -1724,7 +1724,7 @@ int i915_gem_huge_page_mock_selftests(void) i915_modparams.enable_ppgtt = saved_ppgtt; - drm_dev_unref(&dev_priv->drm); + drm_dev_put(&dev_priv->drm); return err; } diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_context.c b/drivers/gpu/drm/i915/selftests/i915_gem_context.c index 90c3c36173ba1..c0c26fae45c71 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_context.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_context.c @@ -586,7 +586,7 @@ int i915_gem_context_mock_selftests(void) err = i915_subtests(tests, i915); - drm_dev_unref(&i915->drm); + drm_dev_put(&i915->drm); return err; } diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/selftests/i915_gem_dmabuf.c index 89dc25a5a53b8..a7055b12e53ce 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_dmabuf.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_dmabuf.c @@ -389,7 +389,7 @@ int i915_gem_dmabuf_mock_selftests(void) err = i915_subtests(tests, i915); - drm_dev_unref(&i915->drm); + drm_dev_put(&i915->drm); return err; } diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_evict.c b/drivers/gpu/drm/i915/selftests/i915_gem_evict.c index 2dc72a984d450..8059268800fa5 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_evict.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_evict.c @@ -490,7 +490,7 @@ int i915_gem_evict_mock_selftests(void) err = i915_subtests(tests, i915); mutex_unlock(&i915->drm.struct_mutex); - drm_dev_unref(&i915->drm); + drm_dev_put(&i915->drm); return err; } diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c index a4060238bef03..a28ee0cc6a633 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c @@ -1644,7 +1644,7 @@ int i915_gem_gtt_mock_selftests(void) err = i915_subtests(tests, i915); mutex_unlock(&i915->drm.struct_mutex); - drm_dev_unref(&i915->drm); + drm_dev_put(&i915->drm); return err; } diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_object.c b/drivers/gpu/drm/i915/selftests/i915_gem_object.c index 2b2dde94526f7..549707b9d7388 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_object.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_object.c @@ -586,7 +586,7 @@ int i915_gem_object_mock_selftests(void) err = i915_subtests(tests, i915); - drm_dev_unref(&i915->drm); + drm_dev_put(&i915->drm); return err; } diff --git a/drivers/gpu/drm/i915/selftests/i915_request.c b/drivers/gpu/drm/i915/selftests/i915_request.c index 63cd9486cc139..521ae4a90ddfb 100644 --- a/drivers/gpu/drm/i915/selftests/i915_request.c +++ b/drivers/gpu/drm/i915/selftests/i915_request.c @@ -262,7 +262,7 @@ int i915_request_mock_selftests(void) return -ENOMEM; err = i915_subtests(tests, i915); - drm_dev_unref(&i915->drm); + drm_dev_put(&i915->drm); return err; } diff --git a/drivers/gpu/drm/i915/selftests/i915_vma.c b/drivers/gpu/drm/i915/selftests/i915_vma.c index 8400a8cc5cf20..ffa74290e0547 100644 --- a/drivers/gpu/drm/i915/selftests/i915_vma.c +++ b/drivers/gpu/drm/i915/selftests/i915_vma.c @@ -733,7 +733,7 @@ int i915_vma_mock_selftests(void) err = i915_subtests(tests, i915); mutex_unlock(&i915->drm.struct_mutex); - drm_dev_unref(&i915->drm); + drm_dev_put(&i915->drm); return err; } diff --git a/drivers/gpu/drm/i915/selftests/intel_breadcrumbs.c b/drivers/gpu/drm/i915/selftests/intel_breadcrumbs.c index d6926e7820e56..f03b407fdbe24 100644 --- a/drivers/gpu/drm/i915/selftests/intel_breadcrumbs.c +++ b/drivers/gpu/drm/i915/selftests/intel_breadcrumbs.c @@ -464,7 +464,7 @@ int intel_breadcrumbs_mock_selftests(void) return -ENOMEM; err = i915_subtests(tests, i915->engine[RCS]); - drm_dev_unref(&i915->drm); + drm_dev_put(&i915->drm); return err; } -- GitLab From 10195b1e4411191a30456e3e60bc539531b17053 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 28 Jun 2018 14:22:06 +0100 Subject: [PATCH 0569/1506] drm/i915: Show vma allocator stack when in doubt At the moment, gem_exec_gttfill fails with a sporadic EBUSY due to us wanting to unbind a pinned batch. Let's dump who first bound that vma to see if that helps us identify who still unexpectedly has it pinned. v2: We cannot allocate inside the printer (as it may be on an fs-reclaim path), so hope for the best and build the string on the stack v3: stack depth of 16 routinely overflows a 512 character string, limit it to 12 to avoid unsightly truncation. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180628132206.8329-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_vma.c | 39 +++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c index e82aa804cdba3..d0e606e9b27a4 100644 --- a/drivers/gpu/drm/i915/i915_vma.c +++ b/drivers/gpu/drm/i915/i915_vma.c @@ -21,7 +21,7 @@ * IN THE SOFTWARE. * */ - + #include "i915_vma.h" #include "i915_drv.h" @@ -30,6 +30,39 @@ #include <drm/drm_gem.h> +#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM) && IS_ENABLED(CONFIG_DRM_DEBUG_MM) + +#include <linux/stackdepot.h> + +static void vma_print_allocator(struct i915_vma *vma, const char *reason) +{ + unsigned long entries[12]; + struct stack_trace trace = { + .entries = entries, + .max_entries = ARRAY_SIZE(entries), + }; + char buf[512]; + + if (!vma->node.stack) { + DRM_DEBUG_DRIVER("vma.node [%08llx + %08llx] %s: unknown owner\n", + vma->node.start, vma->node.size, reason); + return; + } + + depot_fetch_stack(vma->node.stack, &trace); + snprint_stack_trace(buf, sizeof(buf), &trace, 0); + DRM_DEBUG_DRIVER("vma.node [%08llx + %08llx] %s: inserted at %s\n", + vma->node.start, vma->node.size, reason, buf); +} + +#else + +static void vma_print_allocator(struct i915_vma *vma, const char *reason) +{ +} + +#endif + static void i915_vma_retire(struct i915_gem_active *active, struct i915_request *rq) { @@ -875,8 +908,10 @@ int i915_vma_unbind(struct i915_vma *vma) } GEM_BUG_ON(i915_vma_is_active(vma)); - if (i915_vma_is_pinned(vma)) + if (i915_vma_is_pinned(vma)) { + vma_print_allocator(vma, "is pinned"); return -EBUSY; + } if (!drm_mm_node_allocated(&vma->node)) return 0; -- GitLab From 3f88325c2e396658a17632a19b59958750d7ad89 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Wed, 27 Jun 2018 21:13:01 +0100 Subject: [PATCH 0570/1506] drm/i915: Reduce spinlock hold time during notify_ring() interrupt By taking advantage of the RCU protection of the task struct, we can find the appropriate signaler under the spinlock and then release the spinlock before waking the task and signaling the fence. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180627201304.15817-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_irq.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 7a7c4a2bd7783..8893e795f6720 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1154,21 +1154,23 @@ static void ironlake_rps_change_irq_handler(struct drm_i915_private *dev_priv) static void notify_ring(struct intel_engine_cs *engine) { + const u32 seqno = intel_engine_get_seqno(engine); struct i915_request *rq = NULL; + struct task_struct *tsk = NULL; struct intel_wait *wait; - if (!engine->breadcrumbs.irq_armed) + if (unlikely(!engine->breadcrumbs.irq_armed)) return; atomic_inc(&engine->irq_count); - set_bit(ENGINE_IRQ_BREADCRUMB, &engine->irq_posted); + + rcu_read_lock(); spin_lock(&engine->breadcrumbs.irq_lock); wait = engine->breadcrumbs.irq_wait; if (wait) { - bool wakeup = engine->irq_seqno_barrier; - - /* We use a callback from the dma-fence to submit + /* + * We use a callback from the dma-fence to submit * requests after waiting on our own requests. To * ensure minimum delay in queuing the next request to * hardware, signal the fence now rather than wait for @@ -1179,19 +1181,22 @@ static void notify_ring(struct intel_engine_cs *engine) * and to handle coalescing of multiple seqno updates * and many waiters. */ - if (i915_seqno_passed(intel_engine_get_seqno(engine), - wait->seqno)) { + if (i915_seqno_passed(seqno, wait->seqno)) { struct i915_request *waiter = wait->request; - wakeup = true; if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &waiter->fence.flags) && intel_wait_check_request(wait, waiter)) rq = i915_request_get(waiter); - } - if (wakeup) - wake_up_process(wait->tsk); + tsk = wait->tsk; + } else { + if (engine->irq_seqno_barrier) { + set_bit(ENGINE_IRQ_BREADCRUMB, + &engine->irq_posted); + tsk = wait->tsk; + } + } } else { if (engine->breadcrumbs.irq_armed) __intel_engine_disarm_breadcrumbs(engine); @@ -1204,6 +1209,11 @@ static void notify_ring(struct intel_engine_cs *engine) i915_request_put(rq); } + if (tsk && tsk->state & TASK_NORMAL) + wake_up_process(tsk); + + rcu_read_unlock(); + trace_intel_engine_notify(engine, wait); } -- GitLab From 69dc4d003e3b7c262fd5fea3f25852e853eb6d4f Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Wed, 27 Jun 2018 21:13:02 +0100 Subject: [PATCH 0571/1506] drm/i915: Only trigger missed-seqno checking next to boundary If we have more interrupts pending (because we know there are more breadcrumb signals before the completion), then we do not need to trigger an irq_seqno_barrier or even wakeup the task on this interrupt as there will be another. To allow some margin of error (we are trying to work around incoherent seqno after all), we wakeup the breadcrumb before the target as well as on the target. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180627201304.15817-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_irq.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 8893e795f6720..4f137eeaf3951 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1191,7 +1191,8 @@ static void notify_ring(struct intel_engine_cs *engine) tsk = wait->tsk; } else { - if (engine->irq_seqno_barrier) { + if (engine->irq_seqno_barrier && + i915_seqno_passed(seqno, wait->seqno - 1)) { set_bit(ENGINE_IRQ_BREADCRUMB, &engine->irq_posted); tsk = wait->tsk; -- GitLab From 78796877c37cb2c3898c4bcd2a12238d83858287 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Wed, 27 Jun 2018 21:13:03 +0100 Subject: [PATCH 0572/1506] drm/i915: Move the irq_counter inside the spinlock Rather than have multiple locked instructions inside the notify_ring() irq handler, move them inside the spinlock and reduce their intrinsic locking. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180627201304.15817-3-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_irq.c | 4 ++-- drivers/gpu/drm/i915/i915_request.c | 4 ++-- drivers/gpu/drm/i915/intel_breadcrumbs.c | 11 +++++++---- drivers/gpu/drm/i915/intel_ringbuffer.h | 2 +- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 4f137eeaf3951..c81b4c1877cce 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1162,8 +1162,6 @@ static void notify_ring(struct intel_engine_cs *engine) if (unlikely(!engine->breadcrumbs.irq_armed)) return; - atomic_inc(&engine->irq_count); - rcu_read_lock(); spin_lock(&engine->breadcrumbs.irq_lock); @@ -1198,6 +1196,8 @@ static void notify_ring(struct intel_engine_cs *engine) tsk = wait->tsk; } } + + engine->breadcrumbs.irq_count++; } else { if (engine->breadcrumbs.irq_armed) __intel_engine_disarm_breadcrumbs(engine); diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index e1dbb544046fe..39b296878ba28 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -1196,7 +1196,7 @@ static bool __i915_spin_request(const struct i915_request *rq, * takes to sleep on a request, on the order of a microsecond. */ - irq = atomic_read(&engine->irq_count); + irq = READ_ONCE(engine->breadcrumbs.irq_count); timeout_us += local_clock_us(&cpu); do { if (i915_seqno_passed(intel_engine_get_seqno(engine), seqno)) @@ -1208,7 +1208,7 @@ static bool __i915_spin_request(const struct i915_request *rq, * assume we won't see one in the near future but require * the engine->seqno_barrier() to fixup coherency. */ - if (atomic_read(&engine->irq_count) != irq) + if (READ_ONCE(engine->breadcrumbs.irq_count) != irq) break; if (signal_pending_state(state, current)) diff --git a/drivers/gpu/drm/i915/intel_breadcrumbs.c b/drivers/gpu/drm/i915/intel_breadcrumbs.c index 86a987b8ac667..1db6ba7d926ee 100644 --- a/drivers/gpu/drm/i915/intel_breadcrumbs.c +++ b/drivers/gpu/drm/i915/intel_breadcrumbs.c @@ -98,12 +98,14 @@ static void intel_breadcrumbs_hangcheck(struct timer_list *t) struct intel_engine_cs *engine = from_timer(engine, t, breadcrumbs.hangcheck); struct intel_breadcrumbs *b = &engine->breadcrumbs; + unsigned int irq_count; if (!b->irq_armed) return; - if (b->hangcheck_interrupts != atomic_read(&engine->irq_count)) { - b->hangcheck_interrupts = atomic_read(&engine->irq_count); + irq_count = READ_ONCE(b->irq_count); + if (b->hangcheck_interrupts != irq_count) { + b->hangcheck_interrupts = irq_count; mod_timer(&b->hangcheck, wait_timeout()); return; } @@ -272,13 +274,14 @@ static bool use_fake_irq(const struct intel_breadcrumbs *b) if (!test_bit(engine->id, &engine->i915->gpu_error.missed_irq_rings)) return false; - /* Only start with the heavy weight fake irq timer if we have not + /* + * Only start with the heavy weight fake irq timer if we have not * seen any interrupts since enabling it the first time. If the * interrupts are still arriving, it means we made a mistake in our * engine->seqno_barrier(), a timing error that should be transient * and unlikely to reoccur. */ - return atomic_read(&engine->irq_count) == b->hangcheck_interrupts; + return READ_ONCE(b->irq_count) == b->hangcheck_interrupts; } static void enable_fake_irq(struct intel_breadcrumbs *b) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index a0bc7a8222b40..44ac90ec540c2 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -345,7 +345,6 @@ struct intel_engine_cs { struct drm_i915_gem_object *default_state; void *pinned_default_state; - atomic_t irq_count; unsigned long irq_posted; #define ENGINE_IRQ_BREADCRUMB 0 #define ENGINE_IRQ_EXECLIST 1 @@ -380,6 +379,7 @@ struct intel_engine_cs { unsigned int hangcheck_interrupts; unsigned int irq_enabled; + unsigned int irq_count; bool irq_armed : 1; I915_SELFTEST_DECLARE(bool mock : 1); -- GitLab From e3be4079ea91c8b7bcb97cf44889ec5663c55fb4 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Wed, 27 Jun 2018 21:13:04 +0100 Subject: [PATCH 0573/1506] drm/i915: Only signal from interrupt when requested Avoid calling dma_fence_signal() from inside the interrupt if we haven't enabled signaling on the request. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180627201304.15817-4-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_irq.c | 8 ++++++-- drivers/gpu/drm/i915/i915_request.c | 2 +- drivers/gpu/drm/i915/intel_ringbuffer.h | 5 ++--- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index c81b4c1877cce..4be56aec99b34 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1182,7 +1182,8 @@ static void notify_ring(struct intel_engine_cs *engine) if (i915_seqno_passed(seqno, wait->seqno)) { struct i915_request *waiter = wait->request; - if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, + if (waiter && + !test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &waiter->fence.flags) && intel_wait_check_request(wait, waiter)) rq = i915_request_get(waiter); @@ -1205,8 +1206,11 @@ static void notify_ring(struct intel_engine_cs *engine) spin_unlock(&engine->breadcrumbs.irq_lock); if (rq) { - dma_fence_signal(&rq->fence); + spin_lock(&rq->lock); + dma_fence_signal_locked(&rq->fence); GEM_BUG_ON(!i915_request_completed(rq)); + spin_unlock(&rq->lock); + i915_request_put(rq); } diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index 39b296878ba28..a2f7e9358450f 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -1285,7 +1285,7 @@ long i915_request_wait(struct i915_request *rq, if (flags & I915_WAIT_LOCKED) add_wait_queue(errq, &reset); - intel_wait_init(&wait, rq); + intel_wait_init(&wait); restart: do { diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 44ac90ec540c2..78f01a35823af 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -928,11 +928,10 @@ static inline u32 intel_hws_preempt_done_address(struct intel_engine_cs *engine) /* intel_breadcrumbs.c -- user interrupt bottom-half for waiters */ int intel_engine_init_breadcrumbs(struct intel_engine_cs *engine); -static inline void intel_wait_init(struct intel_wait *wait, - struct i915_request *rq) +static inline void intel_wait_init(struct intel_wait *wait) { wait->tsk = current; - wait->request = rq; + wait->request = NULL; } static inline void intel_wait_init_for_seqno(struct intel_wait *wait, u32 seqno) -- GitLab From c39d2e7e35f6f357e59c7313dab8e90f7d1ff93e Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko <michal.wajdeczko@intel.com> Date: Thu, 28 Jun 2018 14:15:20 +0000 Subject: [PATCH 0574/1506] drm/i915/guc: Use intel_guc_init_misc to hide GuC internals We will add more init steps to misc phase and there is no need to expose them separately for use in uc_init_misc function. Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com> Cc: Michel Thierry <michel.thierry@intel.com> Reviewed-by: Michel Thierry <michel.thierry@intel.com> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20180628141522.62788-1-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/intel_guc.c | 28 ++++++++++++++++++++++++---- drivers/gpu/drm/i915/intel_guc.h | 5 ++--- drivers/gpu/drm/i915/intel_uc.c | 6 ++---- 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c index f651e57b4c619..0b06f27d3e1ad 100644 --- a/drivers/gpu/drm/i915/intel_guc.c +++ b/drivers/gpu/drm/i915/intel_guc.c @@ -27,6 +27,8 @@ #include "intel_guc_submission.h" #include "i915_drv.h" +static void guc_init_ggtt_pin_bias(struct intel_guc *guc); + static void gen8_guc_raise_irq(struct intel_guc *guc) { struct drm_i915_private *dev_priv = guc_to_i915(guc); @@ -73,7 +75,7 @@ void intel_guc_init_early(struct intel_guc *guc) guc->notify = gen8_guc_raise_irq; } -int intel_guc_init_wq(struct intel_guc *guc) +static int guc_init_wq(struct intel_guc *guc) { struct drm_i915_private *dev_priv = guc_to_i915(guc); @@ -124,7 +126,7 @@ int intel_guc_init_wq(struct intel_guc *guc) return 0; } -void intel_guc_fini_wq(struct intel_guc *guc) +static void guc_fini_wq(struct intel_guc *guc) { struct drm_i915_private *dev_priv = guc_to_i915(guc); @@ -135,6 +137,24 @@ void intel_guc_fini_wq(struct intel_guc *guc) destroy_workqueue(guc->log.relay.flush_wq); } +int intel_guc_init_misc(struct intel_guc *guc) +{ + int ret; + + guc_init_ggtt_pin_bias(guc); + + ret = guc_init_wq(guc); + if (ret) + return ret; + + return 0; +} + +void intel_guc_fini_misc(struct intel_guc *guc) +{ + guc_fini_wq(guc); +} + static int guc_shared_data_create(struct intel_guc *guc) { struct i915_vma *vma; @@ -582,13 +602,13 @@ int intel_guc_resume(struct intel_guc *guc) */ /** - * intel_guc_init_ggtt_pin_bias() - Initialize the GuC ggtt_pin_bias value. + * guc_init_ggtt_pin_bias() - Initialize the GuC ggtt_pin_bias value. * @guc: intel_guc structure. * * This function will calculate and initialize the ggtt_pin_bias value based on * overall WOPCM size and GuC WOPCM size. */ -void intel_guc_init_ggtt_pin_bias(struct intel_guc *guc) +static void guc_init_ggtt_pin_bias(struct intel_guc *guc) { struct drm_i915_private *i915 = guc_to_i915(guc); diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h index f1265e122d307..4121928a495e0 100644 --- a/drivers/gpu/drm/i915/intel_guc.h +++ b/drivers/gpu/drm/i915/intel_guc.h @@ -151,11 +151,10 @@ static inline u32 intel_guc_ggtt_offset(struct intel_guc *guc, void intel_guc_init_early(struct intel_guc *guc); void intel_guc_init_send_regs(struct intel_guc *guc); void intel_guc_init_params(struct intel_guc *guc); -void intel_guc_init_ggtt_pin_bias(struct intel_guc *guc); -int intel_guc_init_wq(struct intel_guc *guc); -void intel_guc_fini_wq(struct intel_guc *guc); +int intel_guc_init_misc(struct intel_guc *guc); int intel_guc_init(struct intel_guc *guc); void intel_guc_fini(struct intel_guc *guc); +void intel_guc_fini_misc(struct intel_guc *guc); int intel_guc_send_nop(struct intel_guc *guc, const u32 *action, u32 len, u32 *response_buf, u32 response_buf_size); int intel_guc_send_mmio(struct intel_guc *guc, const u32 *action, u32 len, diff --git a/drivers/gpu/drm/i915/intel_uc.c b/drivers/gpu/drm/i915/intel_uc.c index 94e8863bd97c6..cd49b4f510f0a 100644 --- a/drivers/gpu/drm/i915/intel_uc.c +++ b/drivers/gpu/drm/i915/intel_uc.c @@ -257,9 +257,7 @@ int intel_uc_init_misc(struct drm_i915_private *i915) if (!USES_GUC(i915)) return 0; - intel_guc_init_ggtt_pin_bias(guc); - - ret = intel_guc_init_wq(guc); + ret = intel_guc_init_misc(guc); if (ret) return ret; @@ -273,7 +271,7 @@ void intel_uc_fini_misc(struct drm_i915_private *i915) if (!USES_GUC(i915)) return; - intel_guc_fini_wq(guc); + intel_guc_fini_misc(guc); } int intel_uc_init(struct drm_i915_private *i915) -- GitLab From f7dc0157e4b5f23780559c6b71d3f7282f6c7f1b Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko <michal.wajdeczko@intel.com> Date: Thu, 28 Jun 2018 14:15:21 +0000 Subject: [PATCH 0575/1506] drm/i915/uc: Fetch GuC/HuC firmwares from guc/huc specific init We're fetching GuC/HuC firmwares directly from uc level during init_early stage but this breaks guc/huc struct isolation and also strict SW-only initialization rule for init_early. Move fw fetching to init phase and do it separately per guc/huc struct. v2: don't forget to move wopcm_init - Michele v3: fetch in init_misc phase - Michal Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com> Cc: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com> Cc: Michel Thierry <michel.thierry@intel.com> Reviewed-by: Michel Thierry <michel.thierry@intel.com> #2 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20180628141522.62788-2-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/i915_gem.c | 7 ++++--- drivers/gpu/drm/i915/intel_guc.c | 9 ++++++++- drivers/gpu/drm/i915/intel_huc.c | 8 ++++++++ drivers/gpu/drm/i915/intel_huc.h | 6 ++++++ drivers/gpu/drm/i915/intel_uc.c | 28 +++++++++++++++------------- 5 files changed, 41 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 5a9cae604e2b8..8954db6ab083b 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5459,13 +5459,13 @@ int i915_gem_init(struct drm_i915_private *dev_priv) if (ret) return ret; - ret = intel_wopcm_init(&dev_priv->wopcm); + ret = intel_uc_init_misc(dev_priv); if (ret) return ret; - ret = intel_uc_init_misc(dev_priv); + ret = intel_wopcm_init(&dev_priv->wopcm); if (ret) - return ret; + goto err_uc_misc; /* This is just a security blanket to placate dragons. * On some systems, we very sporadically observe that the first TLBs @@ -5563,6 +5563,7 @@ int i915_gem_init(struct drm_i915_private *dev_priv) intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL); mutex_unlock(&dev_priv->drm.struct_mutex); +err_uc_misc: intel_uc_fini_misc(dev_priv); if (ret != -EIO) diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c index 0b06f27d3e1ad..53b43bc73c017 100644 --- a/drivers/gpu/drm/i915/intel_guc.c +++ b/drivers/gpu/drm/i915/intel_guc.c @@ -139,6 +139,7 @@ static void guc_fini_wq(struct intel_guc *guc) int intel_guc_init_misc(struct intel_guc *guc) { + struct drm_i915_private *i915 = guc_to_i915(guc); int ret; guc_init_ggtt_pin_bias(guc); @@ -147,11 +148,14 @@ int intel_guc_init_misc(struct intel_guc *guc) if (ret) return ret; + intel_uc_fw_fetch(i915, &guc->fw); + return 0; } void intel_guc_fini_misc(struct intel_guc *guc) { + intel_uc_fw_fini(&guc->fw); guc_fini_wq(guc); } @@ -189,7 +193,7 @@ int intel_guc_init(struct intel_guc *guc) ret = guc_shared_data_create(guc); if (ret) - return ret; + goto err_fetch; GEM_BUG_ON(!guc->shared_data); ret = intel_guc_log_create(&guc->log); @@ -210,6 +214,8 @@ int intel_guc_init(struct intel_guc *guc) intel_guc_log_destroy(&guc->log); err_shared: guc_shared_data_destroy(guc); +err_fetch: + intel_uc_fw_fini(&guc->fw); return ret; } @@ -221,6 +227,7 @@ void intel_guc_fini(struct intel_guc *guc) intel_guc_ads_destroy(guc); intel_guc_log_destroy(&guc->log); guc_shared_data_destroy(guc); + intel_uc_fw_fini(&guc->fw); } static u32 guc_ctl_debug_flags(struct intel_guc *guc) diff --git a/drivers/gpu/drm/i915/intel_huc.c b/drivers/gpu/drm/i915/intel_huc.c index 2912852774035..ffcad5fad6a7b 100644 --- a/drivers/gpu/drm/i915/intel_huc.c +++ b/drivers/gpu/drm/i915/intel_huc.c @@ -32,6 +32,14 @@ void intel_huc_init_early(struct intel_huc *huc) intel_huc_fw_init_early(huc); } +int intel_huc_init_misc(struct intel_huc *huc) +{ + struct drm_i915_private *i915 = huc_to_i915(huc); + + intel_uc_fw_fetch(i915, &huc->fw); + return 0; +} + /** * intel_huc_auth() - Authenticate HuC uCode * @huc: intel_huc structure diff --git a/drivers/gpu/drm/i915/intel_huc.h b/drivers/gpu/drm/i915/intel_huc.h index aa854907abac8..7e41d870b509c 100644 --- a/drivers/gpu/drm/i915/intel_huc.h +++ b/drivers/gpu/drm/i915/intel_huc.h @@ -36,9 +36,15 @@ struct intel_huc { }; void intel_huc_init_early(struct intel_huc *huc); +int intel_huc_init_misc(struct intel_huc *huc); int intel_huc_auth(struct intel_huc *huc); int intel_huc_check_status(struct intel_huc *huc); +static inline void intel_huc_fini_misc(struct intel_huc *huc) +{ + intel_uc_fw_fini(&huc->fw); +} + static inline int intel_huc_sanitize(struct intel_huc *huc) { intel_uc_fw_sanitize(&huc->fw); diff --git a/drivers/gpu/drm/i915/intel_uc.c b/drivers/gpu/drm/i915/intel_uc.c index cd49b4f510f0a..7c95697e1a358 100644 --- a/drivers/gpu/drm/i915/intel_uc.c +++ b/drivers/gpu/drm/i915/intel_uc.c @@ -171,24 +171,11 @@ void intel_uc_init_early(struct drm_i915_private *i915) intel_huc_init_early(huc); sanitize_options_early(i915); - - if (USES_GUC(i915)) - intel_uc_fw_fetch(i915, &guc->fw); - - if (USES_HUC(i915)) - intel_uc_fw_fetch(i915, &huc->fw); } void intel_uc_cleanup_early(struct drm_i915_private *i915) { struct intel_guc *guc = &i915->guc; - struct intel_huc *huc = &i915->huc; - - if (USES_HUC(i915)) - intel_uc_fw_fini(&huc->fw); - - if (USES_GUC(i915)) - intel_uc_fw_fini(&guc->fw); guc_free_load_err_log(guc); } @@ -252,6 +239,7 @@ static void guc_disable_communication(struct intel_guc *guc) int intel_uc_init_misc(struct drm_i915_private *i915) { struct intel_guc *guc = &i915->guc; + struct intel_huc *huc = &i915->huc; int ret; if (!USES_GUC(i915)) @@ -261,16 +249,30 @@ int intel_uc_init_misc(struct drm_i915_private *i915) if (ret) return ret; + if (USES_HUC(i915)) { + ret = intel_huc_init_misc(huc); + if (ret) + goto err_guc; + } + return 0; + +err_guc: + intel_guc_fini_misc(guc); + return ret; } void intel_uc_fini_misc(struct drm_i915_private *i915) { struct intel_guc *guc = &i915->guc; + struct intel_huc *huc = &i915->huc; if (!USES_GUC(i915)) return; + if (USES_HUC(i915)) + intel_huc_fini_misc(huc); + intel_guc_fini_misc(guc); } -- GitLab From 74093f3eccac232447ef95536c6a359ee7661650 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 28 Jun 2018 21:12:03 +0100 Subject: [PATCH 0576/1506] drm/i915: Drop posting reads to flush master interrupts We do not need to do a posting read of our uncached mmio write to re-enable the master interrupt lines after handling an interrupt, so don't. This saves us a slow UC read before we can process the interrupt, most noticeable in execlists where any stalls imposes extra latency on GPU command execution. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Ville Syrjala <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180628201211.13837-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_irq.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 4be56aec99b34..02fe0d32382e6 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2183,7 +2183,6 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg) I915_WRITE(VLV_IER, ier); I915_WRITE(VLV_MASTER_IER, MASTER_INTERRUPT_ENABLE); - POSTING_READ(VLV_MASTER_IER); if (gt_iir) snb_gt_irq_handler(dev_priv, gt_iir); @@ -2268,7 +2267,6 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg) I915_WRITE(VLV_IER, ier); I915_WRITE(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL); - POSTING_READ(GEN8_MASTER_IRQ); gen8_gt_irq_handler(dev_priv, master_ctl, gt_iir); @@ -2637,7 +2635,6 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg) /* disable master interrupt before clearing iir */ de_ier = I915_READ(DEIER); I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL); - POSTING_READ(DEIER); /* Disable south interrupts. We'll only write to SDEIIR once, so further * interrupts will will be stored on its back queue, and then we'll be @@ -2647,7 +2644,6 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg) if (!HAS_PCH_NOP(dev_priv)) { sde_ier = I915_READ(SDEIER); I915_WRITE(SDEIER, 0); - POSTING_READ(SDEIER); } /* Find, clear, then process each source of interrupt */ @@ -2682,11 +2678,8 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg) } I915_WRITE(DEIER, de_ier); - POSTING_READ(DEIER); - if (!HAS_PCH_NOP(dev_priv)) { + if (!HAS_PCH_NOP(dev_priv)) I915_WRITE(SDEIER, sde_ier); - POSTING_READ(SDEIER); - } /* IRQs are synced during runtime_suspend, we don't require a wakeref */ enable_rpm_wakeref_asserts(dev_priv); -- GitLab From 0b02befa828c0be67a5416e10a0244e181fde0d3 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 28 Jun 2018 21:12:04 +0100 Subject: [PATCH 0577/1506] drm/i915/execlists: Pull submit after dequeue under timeline lock In the next patch, we will begin processing the CSB from inside the submission path (underneath an irqsoff section, and even from inside interrupt handlers). This means that updating the execlists->port[] will no longer be serialised by the tasklet but needs to be locked by the engine->timeline.lock instead. Pull dequeue and submit under the same lock for protection. (An alternate future plan is to keep the in/out arrays separate for concurrent processing and reduced lock coverage.) Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180628201211.13837-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_lrc.c | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 46572976c9420..af94949d08c89 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -567,7 +567,7 @@ static void complete_preempt_context(struct intel_engine_execlists *execlists) execlists_clear_active(execlists, EXECLISTS_ACTIVE_PREEMPT); } -static bool __execlists_dequeue(struct intel_engine_cs *engine) +static void __execlists_dequeue(struct intel_engine_cs *engine) { struct intel_engine_execlists * const execlists = &engine->execlists; struct execlist_port *port = execlists->port; @@ -622,11 +622,11 @@ static bool __execlists_dequeue(struct intel_engine_cs *engine) * the HW to indicate that it has had a chance to respond. */ if (!execlists_is_active(execlists, EXECLISTS_ACTIVE_HWACK)) - return false; + return; if (need_preempt(engine, last, execlists->queue_priority)) { inject_preempt_context(engine); - return false; + return; } /* @@ -651,7 +651,7 @@ static bool __execlists_dequeue(struct intel_engine_cs *engine) * priorities of the ports haven't been switch. */ if (port_count(&port[1])) - return false; + return; /* * WaIdleLiteRestore:bdw,skl @@ -751,8 +751,10 @@ static bool __execlists_dequeue(struct intel_engine_cs *engine) port != execlists->port ? rq_prio(last) : INT_MIN; execlists->first = rb; - if (submit) + if (submit) { port_assign(port, last); + execlists_submit_ports(engine); + } /* We must always keep the beast fed if we have work piled up */ GEM_BUG_ON(execlists->first && !port_isset(execlists->port)); @@ -761,24 +763,19 @@ static bool __execlists_dequeue(struct intel_engine_cs *engine) if (last) execlists_user_begin(execlists, execlists->port); - return submit; + /* If the engine is now idle, so should be the flag; and vice versa. */ + GEM_BUG_ON(execlists_is_active(&engine->execlists, + EXECLISTS_ACTIVE_USER) == + !port_isset(engine->execlists.port)); } static void execlists_dequeue(struct intel_engine_cs *engine) { - struct intel_engine_execlists * const execlists = &engine->execlists; unsigned long flags; - bool submit; spin_lock_irqsave(&engine->timeline.lock, flags); - submit = __execlists_dequeue(engine); + __execlists_dequeue(engine); spin_unlock_irqrestore(&engine->timeline.lock, flags); - - if (submit) - execlists_submit_ports(engine); - - GEM_BUG_ON(port_isset(execlists->port) && - !execlists_is_active(execlists, EXECLISTS_ACTIVE_USER)); } void @@ -1162,11 +1159,6 @@ static void execlists_submission_tasklet(unsigned long data) if (!execlists_is_active(&engine->execlists, EXECLISTS_ACTIVE_PREEMPT)) execlists_dequeue(engine); - - /* If the engine is now idle, so should be the flag; and vice versa. */ - GEM_BUG_ON(execlists_is_active(&engine->execlists, - EXECLISTS_ACTIVE_USER) == - !port_isset(engine->execlists.port)); } static void queue_request(struct intel_engine_cs *engine, -- GitLab From d8857d541c67110cdcedb330e9677efdc9c5844d Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 28 Jun 2018 21:12:05 +0100 Subject: [PATCH 0578/1506] drm/i915/execlists: Pull CSB reset under the timeline.lock In the following patch, we will process the CSB events under the timeline.lock and not serialised by the tasklet. This also means that we will need to protect access to common variables such as execlists->csb_head with the timeline.lock during reset. v2: Move sync_irq to avoid deadlocks between taking timeline.lock from our interrupt handler. v3: Kill off the synchronize_hardirq as it raises more questions than answered; now we use the timeline.lock entirely for CSB serialisation between the irq and elsewhere, we don't need to be so heavy handed with flushing v4: Treat request cancellation (wedging after failed reset) similarly Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180628201211.13837-3-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_lrc.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index af94949d08c89..0cee34e393437 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -872,7 +872,6 @@ static void reset_irq(struct intel_engine_cs *engine) { /* Mark all CS interrupts as complete */ smp_store_mb(engine->execlists.active, 0); - synchronize_hardirq(engine->i915->drm.irq); clear_gtiir(engine); @@ -909,14 +908,12 @@ static void execlists_cancel_requests(struct intel_engine_cs *engine) * submission's irq state, we also wish to remind ourselves that * it is irq state.) */ - local_irq_save(flags); + spin_lock_irqsave(&engine->timeline.lock, flags); /* Cancel the requests on the HW and clear the ELSP tracker. */ execlists_cancel_port_requests(execlists); reset_irq(engine); - spin_lock(&engine->timeline.lock); - /* Mark all executing requests as skipped. */ list_for_each_entry(rq, &engine->timeline.requests, link) { GEM_BUG_ON(!rq->global_seqno); @@ -950,9 +947,7 @@ static void execlists_cancel_requests(struct intel_engine_cs *engine) execlists->first = NULL; GEM_BUG_ON(port_isset(execlists->port)); - spin_unlock(&engine->timeline.lock); - - local_irq_restore(flags); + spin_unlock_irqrestore(&engine->timeline.lock, flags); } static void process_csb(struct intel_engine_cs *engine) @@ -1970,8 +1965,7 @@ static void execlists_reset(struct intel_engine_cs *engine, engine->name, request ? request->global_seqno : 0, intel_engine_get_seqno(engine)); - /* See execlists_cancel_requests() for the irq/spinlock split. */ - local_irq_save(flags); + spin_lock_irqsave(&engine->timeline.lock, flags); /* * Catch up with any missed context-switch interrupts. @@ -1986,14 +1980,12 @@ static void execlists_reset(struct intel_engine_cs *engine, reset_irq(engine); /* Push back any incomplete requests for replay after the reset. */ - spin_lock(&engine->timeline.lock); __unwind_incomplete_requests(engine); - spin_unlock(&engine->timeline.lock); /* Following the reset, we need to reload the CSB read/write pointers */ engine->execlists.csb_head = GEN8_CSB_ENTRIES - 1; - local_irq_restore(flags); + spin_unlock_irqrestore(&engine->timeline.lock, flags); /* * If the request was innocent, we leave the request in the ELSP -- GitLab From 8ea397fa70be357f52988eb156b324105b286607 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 28 Jun 2018 21:12:06 +0100 Subject: [PATCH 0579/1506] drm/i915/execlists: Process one CSB update at a time In the next patch, we will process the CSB events directly from the submission path, rather than only after a CS interrupt. Hence, we will no longer have the need for a loop until the has-interrupt bit is clear, and in the meantime can remove that small optimisation. v2: Tvrtko pointed out it was safer to unconditionally kick the tasklet after each irq, when assuming that the tasklet is called for each irq. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180628201211.13837-4-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_irq.c | 7 +- drivers/gpu/drm/i915/intel_lrc.c | 278 +++++++++++++++---------------- 2 files changed, 141 insertions(+), 144 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 02fe0d32382e6..c95cb278a8bcb 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1497,9 +1497,10 @@ gen8_cs_irq_handler(struct intel_engine_cs *engine, u32 iir) bool tasklet = false; if (iir & GT_CONTEXT_SWITCH_INTERRUPT) { - if (READ_ONCE(engine->execlists.active)) - tasklet = !test_and_set_bit(ENGINE_IRQ_EXECLIST, - &engine->irq_posted); + if (READ_ONCE(engine->execlists.active)) { + set_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted); + tasklet = true; + } } if (iir & GT_RENDER_USER_INTERRUPT) { diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 0cee34e393437..c8d3d41011ce2 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -955,166 +955,162 @@ static void process_csb(struct intel_engine_cs *engine) struct intel_engine_execlists * const execlists = &engine->execlists; struct execlist_port *port = execlists->port; struct drm_i915_private *i915 = engine->i915; + + /* The HWSP contains a (cacheable) mirror of the CSB */ + const u32 *buf = + &engine->status_page.page_addr[I915_HWS_CSB_BUF0_INDEX]; + unsigned int head, tail; bool fw = false; - do { - /* The HWSP contains a (cacheable) mirror of the CSB */ - const u32 *buf = - &engine->status_page.page_addr[I915_HWS_CSB_BUF0_INDEX]; - unsigned int head, tail; - - /* Clear before reading to catch new interrupts */ - clear_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted); - smp_mb__after_atomic(); - - if (unlikely(execlists->csb_use_mmio)) { - if (!fw) { - intel_uncore_forcewake_get(i915, execlists->fw_domains); - fw = true; - } + /* Clear before reading to catch new interrupts */ + clear_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted); + smp_mb__after_atomic(); - buf = (u32 * __force) - (i915->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_BUF_LO(engine, 0))); + if (unlikely(execlists->csb_use_mmio)) { + intel_uncore_forcewake_get(i915, execlists->fw_domains); + fw = true; - head = readl(i915->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_PTR(engine))); - tail = GEN8_CSB_WRITE_PTR(head); - head = GEN8_CSB_READ_PTR(head); - execlists->csb_head = head; - } else { - const int write_idx = - intel_hws_csb_write_index(i915) - - I915_HWS_CSB_BUF0_INDEX; + buf = (u32 * __force) + (i915->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_BUF_LO(engine, 0))); - head = execlists->csb_head; - tail = READ_ONCE(buf[write_idx]); - rmb(); /* Hopefully paired with a wmb() in HW */ - } - GEM_TRACE("%s cs-irq head=%d [%d%s], tail=%d [%d%s]\n", - engine->name, - head, GEN8_CSB_READ_PTR(readl(i915->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_PTR(engine)))), fw ? "" : "?", - tail, GEN8_CSB_WRITE_PTR(readl(i915->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_PTR(engine)))), fw ? "" : "?"); + head = readl(i915->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_PTR(engine))); + tail = GEN8_CSB_WRITE_PTR(head); + head = GEN8_CSB_READ_PTR(head); + execlists->csb_head = head; + } else { + const int write_idx = + intel_hws_csb_write_index(i915) - + I915_HWS_CSB_BUF0_INDEX; - while (head != tail) { - struct i915_request *rq; - unsigned int status; - unsigned int count; + head = execlists->csb_head; + tail = READ_ONCE(buf[write_idx]); + rmb(); /* Hopefully paired with a wmb() in HW */ + } + GEM_TRACE("%s cs-irq head=%d [%d%s], tail=%d [%d%s]\n", + engine->name, + head, GEN8_CSB_READ_PTR(readl(i915->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_PTR(engine)))), fw ? "" : "?", + tail, GEN8_CSB_WRITE_PTR(readl(i915->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_PTR(engine)))), fw ? "" : "?"); - if (++head == GEN8_CSB_ENTRIES) - head = 0; + while (head != tail) { + struct i915_request *rq; + unsigned int status; + unsigned int count; - /* - * We are flying near dragons again. - * - * We hold a reference to the request in execlist_port[] - * but no more than that. We are operating in softirq - * context and so cannot hold any mutex or sleep. That - * prevents us stopping the requests we are processing - * in port[] from being retired simultaneously (the - * breadcrumb will be complete before we see the - * context-switch). As we only hold the reference to the - * request, any pointer chasing underneath the request - * is subject to a potential use-after-free. Thus we - * store all of the bookkeeping within port[] as - * required, and avoid using unguarded pointers beneath - * request itself. The same applies to the atomic - * status notifier. - */ + if (++head == GEN8_CSB_ENTRIES) + head = 0; - status = READ_ONCE(buf[2 * head]); /* maybe mmio! */ - GEM_TRACE("%s csb[%d]: status=0x%08x:0x%08x, active=0x%x\n", - engine->name, head, - status, buf[2*head + 1], - execlists->active); - - if (status & (GEN8_CTX_STATUS_IDLE_ACTIVE | - GEN8_CTX_STATUS_PREEMPTED)) - execlists_set_active(execlists, - EXECLISTS_ACTIVE_HWACK); - if (status & GEN8_CTX_STATUS_ACTIVE_IDLE) - execlists_clear_active(execlists, - EXECLISTS_ACTIVE_HWACK); - - if (!(status & GEN8_CTX_STATUS_COMPLETED_MASK)) - continue; + /* + * We are flying near dragons again. + * + * We hold a reference to the request in execlist_port[] + * but no more than that. We are operating in softirq + * context and so cannot hold any mutex or sleep. That + * prevents us stopping the requests we are processing + * in port[] from being retired simultaneously (the + * breadcrumb will be complete before we see the + * context-switch). As we only hold the reference to the + * request, any pointer chasing underneath the request + * is subject to a potential use-after-free. Thus we + * store all of the bookkeeping within port[] as + * required, and avoid using unguarded pointers beneath + * request itself. The same applies to the atomic + * status notifier. + */ - /* We should never get a COMPLETED | IDLE_ACTIVE! */ - GEM_BUG_ON(status & GEN8_CTX_STATUS_IDLE_ACTIVE); + status = READ_ONCE(buf[2 * head]); /* maybe mmio! */ + GEM_TRACE("%s csb[%d]: status=0x%08x:0x%08x, active=0x%x\n", + engine->name, head, + status, buf[2*head + 1], + execlists->active); + + if (status & (GEN8_CTX_STATUS_IDLE_ACTIVE | + GEN8_CTX_STATUS_PREEMPTED)) + execlists_set_active(execlists, + EXECLISTS_ACTIVE_HWACK); + if (status & GEN8_CTX_STATUS_ACTIVE_IDLE) + execlists_clear_active(execlists, + EXECLISTS_ACTIVE_HWACK); + + if (!(status & GEN8_CTX_STATUS_COMPLETED_MASK)) + continue; - if (status & GEN8_CTX_STATUS_COMPLETE && - buf[2*head + 1] == execlists->preempt_complete_status) { - GEM_TRACE("%s preempt-idle\n", engine->name); - complete_preempt_context(execlists); - continue; - } + /* We should never get a COMPLETED | IDLE_ACTIVE! */ + GEM_BUG_ON(status & GEN8_CTX_STATUS_IDLE_ACTIVE); - if (status & GEN8_CTX_STATUS_PREEMPTED && - execlists_is_active(execlists, - EXECLISTS_ACTIVE_PREEMPT)) - continue; + if (status & GEN8_CTX_STATUS_COMPLETE && + buf[2*head + 1] == execlists->preempt_complete_status) { + GEM_TRACE("%s preempt-idle\n", engine->name); + complete_preempt_context(execlists); + continue; + } - GEM_BUG_ON(!execlists_is_active(execlists, - EXECLISTS_ACTIVE_USER)); + if (status & GEN8_CTX_STATUS_PREEMPTED && + execlists_is_active(execlists, + EXECLISTS_ACTIVE_PREEMPT)) + continue; - rq = port_unpack(port, &count); - GEM_TRACE("%s out[0]: ctx=%d.%d, global=%d (fence %llx:%d) (current %d), prio=%d\n", - engine->name, - port->context_id, count, - rq ? rq->global_seqno : 0, - rq ? rq->fence.context : 0, - rq ? rq->fence.seqno : 0, - intel_engine_get_seqno(engine), - rq ? rq_prio(rq) : 0); + GEM_BUG_ON(!execlists_is_active(execlists, + EXECLISTS_ACTIVE_USER)); - /* Check the context/desc id for this event matches */ - GEM_DEBUG_BUG_ON(buf[2 * head + 1] != port->context_id); + rq = port_unpack(port, &count); + GEM_TRACE("%s out[0]: ctx=%d.%d, global=%d (fence %llx:%d) (current %d), prio=%d\n", + engine->name, + port->context_id, count, + rq ? rq->global_seqno : 0, + rq ? rq->fence.context : 0, + rq ? rq->fence.seqno : 0, + intel_engine_get_seqno(engine), + rq ? rq_prio(rq) : 0); + + /* Check the context/desc id for this event matches */ + GEM_DEBUG_BUG_ON(buf[2 * head + 1] != port->context_id); + + GEM_BUG_ON(count == 0); + if (--count == 0) { + /* + * On the final event corresponding to the + * submission of this context, we expect either + * an element-switch event or a completion + * event (and on completion, the active-idle + * marker). No more preemptions, lite-restore + * or otherwise. + */ + GEM_BUG_ON(status & GEN8_CTX_STATUS_PREEMPTED); + GEM_BUG_ON(port_isset(&port[1]) && + !(status & GEN8_CTX_STATUS_ELEMENT_SWITCH)); + GEM_BUG_ON(!port_isset(&port[1]) && + !(status & GEN8_CTX_STATUS_ACTIVE_IDLE)); - GEM_BUG_ON(count == 0); - if (--count == 0) { - /* - * On the final event corresponding to the - * submission of this context, we expect either - * an element-switch event or a completion - * event (and on completion, the active-idle - * marker). No more preemptions, lite-restore - * or otherwise. - */ - GEM_BUG_ON(status & GEN8_CTX_STATUS_PREEMPTED); - GEM_BUG_ON(port_isset(&port[1]) && - !(status & GEN8_CTX_STATUS_ELEMENT_SWITCH)); - GEM_BUG_ON(!port_isset(&port[1]) && - !(status & GEN8_CTX_STATUS_ACTIVE_IDLE)); + /* + * We rely on the hardware being strongly + * ordered, that the breadcrumb write is + * coherent (visible from the CPU) before the + * user interrupt and CSB is processed. + */ + GEM_BUG_ON(!i915_request_completed(rq)); - /* - * We rely on the hardware being strongly - * ordered, that the breadcrumb write is - * coherent (visible from the CPU) before the - * user interrupt and CSB is processed. - */ - GEM_BUG_ON(!i915_request_completed(rq)); - - execlists_context_schedule_out(rq, - INTEL_CONTEXT_SCHEDULE_OUT); - i915_request_put(rq); - - GEM_TRACE("%s completed ctx=%d\n", - engine->name, port->context_id); - - port = execlists_port_complete(execlists, port); - if (port_isset(port)) - execlists_user_begin(execlists, port); - else - execlists_user_end(execlists); - } else { - port_set(port, port_pack(rq, count)); - } - } + execlists_context_schedule_out(rq, + INTEL_CONTEXT_SCHEDULE_OUT); + i915_request_put(rq); - if (head != execlists->csb_head) { - execlists->csb_head = head; - writel(_MASKED_FIELD(GEN8_CSB_READ_PTR_MASK, head << 8), - i915->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_PTR(engine))); + GEM_TRACE("%s completed ctx=%d\n", + engine->name, port->context_id); + + port = execlists_port_complete(execlists, port); + if (port_isset(port)) + execlists_user_begin(execlists, port); + else + execlists_user_end(execlists); + } else { + port_set(port, port_pack(rq, count)); } - } while (test_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted)); + } + + if (head != execlists->csb_head) { + execlists->csb_head = head; + writel(_MASKED_FIELD(GEN8_CSB_READ_PTR_MASK, head << 8), + i915->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_PTR(engine))); + } if (unlikely(fw)) intel_uncore_forcewake_put(i915, execlists->fw_domains); -- GitLab From bc4237ec8deaaee5f75d1afa91a19bfe6f948c6f Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 28 Jun 2018 21:12:07 +0100 Subject: [PATCH 0580/1506] drm/i915/execlists: Unify CSB access pointers Following the removal of the last workarounds, the only CSB mmio access is for the old vGPU interface. The mmio registers presented by vGPU do not require forcewake and can be treated as ordinary volatile memory, i.e. they behave just like the HWSP access just at a different location. We can reduce the CSB access to a set of read/write/buffer pointers and treat the various paths identically and not worry about forcewake. (Forcewake is nightmare for worstcase latency, and we want to process this all with irqsoff -- no latency allowed!) v2: Comments, comments, comments. Well, 2 bonus comments. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180628201211.13837-5-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_engine_cs.c | 12 --- drivers/gpu/drm/i915/intel_lrc.c | 133 ++++++++++++------------ drivers/gpu/drm/i915/intel_ringbuffer.h | 23 ++-- 3 files changed, 82 insertions(+), 86 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index d3264bd6e9dcc..7209c22798e62 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -25,7 +25,6 @@ #include <drm/drm_print.h> #include "i915_drv.h" -#include "i915_vgpu.h" #include "intel_ringbuffer.h" #include "intel_lrc.h" @@ -456,21 +455,10 @@ static void intel_engine_init_batch_pool(struct intel_engine_cs *engine) i915_gem_batch_pool_init(&engine->batch_pool, engine); } -static bool csb_force_mmio(struct drm_i915_private *i915) -{ - /* Older GVT emulation depends upon intercepting CSB mmio */ - if (intel_vgpu_active(i915) && !intel_vgpu_has_hwsp_emulation(i915)) - return true; - - return false; -} - static void intel_engine_init_execlist(struct intel_engine_cs *engine) { struct intel_engine_execlists * const execlists = &engine->execlists; - execlists->csb_use_mmio = csb_force_mmio(engine->i915); - execlists->port_mask = 1; BUILD_BUG_ON_NOT_POWER_OF_2(execlists_num_ports(execlists)); GEM_BUG_ON(execlists_num_ports(execlists) > EXECLIST_MAX_PORTS); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index c8d3d41011ce2..81f000c245ab9 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -137,6 +137,7 @@ #include <drm/i915_drm.h> #include "i915_drv.h" #include "i915_gem_render_state.h" +#include "i915_vgpu.h" #include "intel_lrc_reg.h" #include "intel_mocs.h" #include "intel_workarounds.h" @@ -954,44 +955,40 @@ static void process_csb(struct intel_engine_cs *engine) { struct intel_engine_execlists * const execlists = &engine->execlists; struct execlist_port *port = execlists->port; - struct drm_i915_private *i915 = engine->i915; - - /* The HWSP contains a (cacheable) mirror of the CSB */ - const u32 *buf = - &engine->status_page.page_addr[I915_HWS_CSB_BUF0_INDEX]; - unsigned int head, tail; - bool fw = false; + const u32 * const buf = execlists->csb_status; + u8 head, tail; /* Clear before reading to catch new interrupts */ clear_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted); smp_mb__after_atomic(); - if (unlikely(execlists->csb_use_mmio)) { - intel_uncore_forcewake_get(i915, execlists->fw_domains); - fw = true; - - buf = (u32 * __force) - (i915->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_BUF_LO(engine, 0))); - - head = readl(i915->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_PTR(engine))); - tail = GEN8_CSB_WRITE_PTR(head); - head = GEN8_CSB_READ_PTR(head); - execlists->csb_head = head; - } else { - const int write_idx = - intel_hws_csb_write_index(i915) - - I915_HWS_CSB_BUF0_INDEX; + /* + * Note that csb_write, csb_status may be either in HWSP or mmio. + * When reading from the csb_write mmio register, we have to be + * careful to only use the GEN8_CSB_WRITE_PTR portion, which is + * the low 4bits. As it happens we know the next 4bits are always + * zero and so we can simply masked off the low u8 of the register + * and treat it identically to reading from the HWSP (without having + * to use explicit shifting and masking, and probably bifurcating + * the code to handle the legacy mmio read). + */ + head = execlists->csb_head; + tail = READ_ONCE(*execlists->csb_write); + GEM_TRACE("%s cs-irq head=%d, tail=%d\n", engine->name, head, tail); + if (unlikely(head == tail)) + return; - head = execlists->csb_head; - tail = READ_ONCE(buf[write_idx]); - rmb(); /* Hopefully paired with a wmb() in HW */ - } - GEM_TRACE("%s cs-irq head=%d [%d%s], tail=%d [%d%s]\n", - engine->name, - head, GEN8_CSB_READ_PTR(readl(i915->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_PTR(engine)))), fw ? "" : "?", - tail, GEN8_CSB_WRITE_PTR(readl(i915->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_PTR(engine)))), fw ? "" : "?"); + /* + * Hopefully paired with a wmb() in HW! + * + * We must complete the read of the write pointer before any reads + * from the CSB, so that we do not see stale values. Without an rmb + * (lfence) the HW may speculatively perform the CSB[] reads *before* + * we perform the READ_ONCE(*csb_write). + */ + rmb(); - while (head != tail) { + do { struct i915_request *rq; unsigned int status; unsigned int count; @@ -1017,12 +1014,12 @@ static void process_csb(struct intel_engine_cs *engine) * status notifier. */ - status = READ_ONCE(buf[2 * head]); /* maybe mmio! */ GEM_TRACE("%s csb[%d]: status=0x%08x:0x%08x, active=0x%x\n", engine->name, head, - status, buf[2*head + 1], + buf[2 * head + 0], buf[2 * head + 1], execlists->active); + status = buf[2 * head]; if (status & (GEN8_CTX_STATUS_IDLE_ACTIVE | GEN8_CTX_STATUS_PREEMPTED)) execlists_set_active(execlists, @@ -1104,16 +1101,11 @@ static void process_csb(struct intel_engine_cs *engine) } else { port_set(port, port_pack(rq, count)); } - } - - if (head != execlists->csb_head) { - execlists->csb_head = head; - writel(_MASKED_FIELD(GEN8_CSB_READ_PTR_MASK, head << 8), - i915->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_PTR(engine))); - } + } while (head != tail); - if (unlikely(fw)) - intel_uncore_forcewake_put(i915, execlists->fw_domains); + writel(_MASKED_FIELD(GEN8_CSB_READ_PTR_MASK, head << 8), + execlists->csb_read); + execlists->csb_head = head; } /* @@ -2431,28 +2423,11 @@ logical_ring_default_irqs(struct intel_engine_cs *engine) static void logical_ring_setup(struct intel_engine_cs *engine) { - struct drm_i915_private *dev_priv = engine->i915; - enum forcewake_domains fw_domains; - intel_engine_setup_common(engine); /* Intentionally left blank. */ engine->buffer = NULL; - fw_domains = intel_uncore_forcewake_for_reg(dev_priv, - RING_ELSP(engine), - FW_REG_WRITE); - - fw_domains |= intel_uncore_forcewake_for_reg(dev_priv, - RING_CONTEXT_STATUS_PTR(engine), - FW_REG_READ | FW_REG_WRITE); - - fw_domains |= intel_uncore_forcewake_for_reg(dev_priv, - RING_CONTEXT_STATUS_BUF_BASE(engine), - FW_REG_READ); - - engine->execlists.fw_domains = fw_domains; - tasklet_init(&engine->execlists.tasklet, execlists_submission_tasklet, (unsigned long)engine); @@ -2460,34 +2435,56 @@ logical_ring_setup(struct intel_engine_cs *engine) logical_ring_default_irqs(engine); } +static bool csb_force_mmio(struct drm_i915_private *i915) +{ + /* Older GVT emulation depends upon intercepting CSB mmio */ + return intel_vgpu_active(i915) && !intel_vgpu_has_hwsp_emulation(i915); +} + static int logical_ring_init(struct intel_engine_cs *engine) { + struct drm_i915_private *i915 = engine->i915; + struct intel_engine_execlists * const execlists = &engine->execlists; int ret; ret = intel_engine_init_common(engine); if (ret) goto error; - if (HAS_LOGICAL_RING_ELSQ(engine->i915)) { - engine->execlists.submit_reg = engine->i915->regs + + if (HAS_LOGICAL_RING_ELSQ(i915)) { + execlists->submit_reg = i915->regs + i915_mmio_reg_offset(RING_EXECLIST_SQ_CONTENTS(engine)); - engine->execlists.ctrl_reg = engine->i915->regs + + execlists->ctrl_reg = i915->regs + i915_mmio_reg_offset(RING_EXECLIST_CONTROL(engine)); } else { - engine->execlists.submit_reg = engine->i915->regs + + execlists->submit_reg = i915->regs + i915_mmio_reg_offset(RING_ELSP(engine)); } - engine->execlists.preempt_complete_status = ~0u; - if (engine->i915->preempt_context) { + execlists->preempt_complete_status = ~0u; + if (i915->preempt_context) { struct intel_context *ce = - to_intel_context(engine->i915->preempt_context, engine); + to_intel_context(i915->preempt_context, engine); - engine->execlists.preempt_complete_status = + execlists->preempt_complete_status = upper_32_bits(ce->lrc_desc); } - engine->execlists.csb_head = GEN8_CSB_ENTRIES - 1; + execlists->csb_head = GEN8_CSB_ENTRIES - 1; + execlists->csb_read = + i915->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_PTR(engine)); + if (csb_force_mmio(i915)) { + execlists->csb_status = (u32 __force *) + (i915->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_BUF_LO(engine, 0))); + + execlists->csb_write = (u32 __force *)execlists->csb_read; + } else { + execlists->csb_status = + &engine->status_page.page_addr[I915_HWS_CSB_BUF0_INDEX]; + + execlists->csb_write = + &engine->status_page.page_addr[intel_hws_csb_write_index(i915)]; + } return 0; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 78f01a35823af..25792889dbf4b 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -300,24 +300,35 @@ struct intel_engine_execlists { struct rb_node *first; /** - * @fw_domains: forcewake domains for irq tasklet + * @csb_read: control register for Context Switch buffer + * + * Note this register is always in mmio. */ - unsigned int fw_domains; + u32 __iomem *csb_read; /** - * @csb_head: context status buffer head + * @csb_write: control register for Context Switch buffer + * + * Note this register may be either mmio or HWSP shadow. */ - unsigned int csb_head; + u32 *csb_write; /** - * @csb_use_mmio: access csb through mmio, instead of hwsp + * @csb_status: status array for Context Switch buffer + * + * Note these register may be either mmio or HWSP shadow. */ - bool csb_use_mmio; + u32 *csb_status; /** * @preempt_complete_status: expected CSB upon completing preemption */ u32 preempt_complete_status; + + /** + * @csb_head: context status buffer head + */ + u8 csb_head; }; #define INTEL_ENGINE_CS_MAX_NAME 8 -- GitLab From f4b58f0438ba53002e2032e3817c8e847da9a9e1 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 28 Jun 2018 21:12:08 +0100 Subject: [PATCH 0581/1506] drm/i915/execlists: Reset CSB write pointer after reset On HW reset, the HW clears the write pointer (to 0). But since it also writes its first CSB entry to slot 0, we need to reset the write pointer back to the element before (so the first entry we read is 0). This is required for the next patch, where we trust the CSB completely! v2: Use _MASKED_FIELD v3: Store the reset value, so that we differentiate between mmio/hwsp transparently and without pretense. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180628201211.13837-6-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_lrc.c | 23 +++++++++++++++++++++-- drivers/gpu/drm/i915/intel_ringbuffer.h | 9 +++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 81f000c245ab9..88289d1d07e72 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -885,6 +885,21 @@ static void reset_irq(struct intel_engine_cs *engine) clear_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted); } +static void reset_csb_pointers(struct intel_engine_execlists *execlists) +{ + /* + * After a reset, the HW starts writing into CSB entry [0]. We + * therefore have to set our HEAD pointer back one entry so that + * the *first* entry we check is entry 0. To complicate this further, + * as we don't wait for the first interrupt after reset, we have to + * fake the HW write to point back to the last entry so that our + * inline comparison of our cached head position against the last HW + * write works even before the first interrupt. + */ + execlists->csb_head = execlists->csb_write_reset; + WRITE_ONCE(*execlists->csb_write, execlists->csb_write_reset); +} + static void execlists_cancel_requests(struct intel_engine_cs *engine) { struct intel_engine_execlists * const execlists = &engine->execlists; @@ -1971,7 +1986,7 @@ static void execlists_reset(struct intel_engine_cs *engine, __unwind_incomplete_requests(engine); /* Following the reset, we need to reload the CSB read/write pointers */ - engine->execlists.csb_head = GEN8_CSB_ENTRIES - 1; + reset_csb_pointers(&engine->execlists); spin_unlock_irqrestore(&engine->timeline.lock, flags); @@ -2470,7 +2485,6 @@ static int logical_ring_init(struct intel_engine_cs *engine) upper_32_bits(ce->lrc_desc); } - execlists->csb_head = GEN8_CSB_ENTRIES - 1; execlists->csb_read = i915->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_PTR(engine)); if (csb_force_mmio(i915)) { @@ -2478,13 +2492,18 @@ static int logical_ring_init(struct intel_engine_cs *engine) (i915->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_BUF_LO(engine, 0))); execlists->csb_write = (u32 __force *)execlists->csb_read; + execlists->csb_write_reset = + _MASKED_FIELD(GEN8_CSB_WRITE_PTR_MASK, + GEN8_CSB_ENTRIES - 1); } else { execlists->csb_status = &engine->status_page.page_addr[I915_HWS_CSB_BUF0_INDEX]; execlists->csb_write = &engine->status_page.page_addr[intel_hws_csb_write_index(i915)]; + execlists->csb_write_reset = GEN8_CSB_ENTRIES - 1; } + reset_csb_pointers(execlists); return 0; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 25792889dbf4b..b026209908597 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -325,6 +325,15 @@ struct intel_engine_execlists { */ u32 preempt_complete_status; + /** + * @csb_write_reset: reset value for CSB write pointer + * + * As the CSB write pointer maybe either in HWSP or as a field + * inside an mmio register, we want to reprogram it slightly + * differently to avoid later confusion. + */ + u32 csb_write_reset; + /** * @csb_head: context status buffer head */ -- GitLab From 3800cd1953059b64593c7ca1022071b96bc40ef3 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 28 Jun 2018 21:12:09 +0100 Subject: [PATCH 0582/1506] drm/i915/execlists: Stop storing the CSB read pointer in the mmio register As we now never read back our current head position from the CSB pointers register, and the HW itself doesn't use it to prevent overwriting unread CSB entries, we do not need to keep updating the register. As it turns out this register is not listed as being shadowed, and so requires forcewake -- but we haven't been taking forcewake around it so the writes has probably been regularly dropped. Fortuitously, we only read the value after a reset where it did not matter, and zero was the right answer (well, close enough). Mika pointed out that this was how we used to do it (accidentally!) before he fixed it in commit cc53699b25b5 ("drm/i915: Use masked write for Context Status Buffer Pointer"). References: cc53699b25b5 ("drm/i915: Use masked write for Context Status Buffer Pointer") Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Cc: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180628201211.13837-7-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_lrc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 88289d1d07e72..ed81f8ac60ca2 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1118,8 +1118,6 @@ static void process_csb(struct intel_engine_cs *engine) } } while (head != tail); - writel(_MASKED_FIELD(GEN8_CSB_READ_PTR_MASK, head << 8), - execlists->csb_read); execlists->csb_head = head; } -- GitLab From fd8526e509020ed30298ab57d03edc97bef83962 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 28 Jun 2018 21:12:10 +0100 Subject: [PATCH 0583/1506] drm/i915/execlists: Trust the CSB Now that we use the CSB stored in the CPU friendly HWSP, we do not need to track interrupts for when the mmio CSB registers are valid and can just check where we read up to last from the cached HWSP. This means we can forgo the atomic bit tracking from interrupt, and in the next patch it means we can check the CSB at any time. v2: Change the splitting inside reset_prepare, we only want to lose testing the interrupt in this patch, the next patch requires the change in locking Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180628201211.13837-8-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_irq.c | 11 +++------- drivers/gpu/drm/i915/intel_engine_cs.c | 8 ++----- drivers/gpu/drm/i915/intel_lrc.c | 29 ++++--------------------- drivers/gpu/drm/i915/intel_ringbuffer.h | 1 - 4 files changed, 9 insertions(+), 40 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index c95cb278a8bcb..435a4444314ca 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1493,15 +1493,10 @@ static void snb_gt_irq_handler(struct drm_i915_private *dev_priv, static void gen8_cs_irq_handler(struct intel_engine_cs *engine, u32 iir) { - struct intel_engine_execlists * const execlists = &engine->execlists; bool tasklet = false; - if (iir & GT_CONTEXT_SWITCH_INTERRUPT) { - if (READ_ONCE(engine->execlists.active)) { - set_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted); - tasklet = true; - } - } + if (iir & GT_CONTEXT_SWITCH_INTERRUPT) + tasklet = true; if (iir & GT_RENDER_USER_INTERRUPT) { notify_ring(engine); @@ -1509,7 +1504,7 @@ gen8_cs_irq_handler(struct intel_engine_cs *engine, u32 iir) } if (tasklet) - tasklet_hi_schedule(&execlists->tasklet); + tasklet_hi_schedule(&engine->execlists.tasklet); } static void gen8_gt_irq_ack(struct drm_i915_private *i915, diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index 7209c22798e62..ace93958689ef 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -1353,12 +1353,10 @@ static void intel_engine_print_registers(const struct intel_engine_cs *engine, ptr = I915_READ(RING_CONTEXT_STATUS_PTR(engine)); read = GEN8_CSB_READ_PTR(ptr); write = GEN8_CSB_WRITE_PTR(ptr); - drm_printf(m, "\tExeclist CSB read %d [%d cached], write %d [%d from hws], interrupt posted? %s, tasklet queued? %s (%s)\n", + drm_printf(m, "\tExeclist CSB read %d [%d cached], write %d [%d from hws], tasklet queued? %s (%s)\n", read, execlists->csb_head, write, intel_read_status_page(engine, intel_hws_csb_write_index(engine->i915)), - yesno(test_bit(ENGINE_IRQ_EXECLIST, - &engine->irq_posted)), yesno(test_bit(TASKLET_STATE_SCHED, &engine->execlists.tasklet.state)), enableddisabled(!atomic_read(&engine->execlists.tasklet.count))); @@ -1570,11 +1568,9 @@ void intel_engine_dump(struct intel_engine_cs *engine, spin_unlock(&b->rb_lock); local_irq_restore(flags); - drm_printf(m, "IRQ? 0x%lx (breadcrumbs? %s) (execlists? %s)\n", + drm_printf(m, "IRQ? 0x%lx (breadcrumbs? %s)\n", engine->irq_posted, yesno(test_bit(ENGINE_IRQ_BREADCRUMB, - &engine->irq_posted)), - yesno(test_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted))); drm_printf(m, "HWSP:\n"); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index ed81f8ac60ca2..d835da128a172 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -875,14 +875,6 @@ static void reset_irq(struct intel_engine_cs *engine) smp_store_mb(engine->execlists.active, 0); clear_gtiir(engine); - - /* - * The port is checked prior to scheduling a tasklet, but - * just in case we have suspended the tasklet to do the - * wedging make sure that when it wakes, it decides there - * is no work to do by clearing the irq_posted bit. - */ - clear_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted); } static void reset_csb_pointers(struct intel_engine_execlists *execlists) @@ -973,10 +965,6 @@ static void process_csb(struct intel_engine_cs *engine) const u32 * const buf = execlists->csb_status; u8 head, tail; - /* Clear before reading to catch new interrupts */ - clear_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted); - smp_mb__after_atomic(); - /* * Note that csb_write, csb_status may be either in HWSP or mmio. * When reading from the csb_write mmio register, we have to be @@ -1129,11 +1117,10 @@ static void execlists_submission_tasklet(unsigned long data) { struct intel_engine_cs * const engine = (struct intel_engine_cs *)data; - GEM_TRACE("%s awake?=%d, active=%x, irq-posted?=%d\n", + GEM_TRACE("%s awake?=%d, active=%x\n", engine->name, engine->i915->gt.awake, - engine->execlists.active, - test_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted)); + engine->execlists.active); /* * We can skip acquiring intel_runtime_pm_get() here as it was taken @@ -1145,14 +1132,7 @@ static void execlists_submission_tasklet(unsigned long data) */ GEM_BUG_ON(!engine->i915->gt.awake); - /* - * Prefer doing test_and_clear_bit() as a two stage operation to avoid - * imposing the cost of a locked atomic transaction when submitting a - * new request (outside of the context-switch interrupt). - */ - if (test_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted)) - process_csb(engine); - + process_csb(engine); if (!execlists_is_active(&engine->execlists, EXECLISTS_ACTIVE_PREEMPT)) execlists_dequeue(engine); } @@ -1920,8 +1900,7 @@ execlists_reset_prepare(struct intel_engine_cs *engine) * and avoid blaming an innocent request if the stall was due to the * preemption itself. */ - if (test_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted)) - process_csb(engine); + process_csb(engine); /* * The last active request can then be no later than the last request diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index b026209908597..ce6cc2a6cf7af 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -367,7 +367,6 @@ struct intel_engine_cs { unsigned long irq_posted; #define ENGINE_IRQ_BREADCRUMB 0 -#define ENGINE_IRQ_EXECLIST 1 /* Rather than have every client wait upon all user interrupts, * with the herd waking after every interrupt and each doing the -- GitLab From 9512f985c32d45ab439a210981e0d73071da395a Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 28 Jun 2018 21:12:11 +0100 Subject: [PATCH 0584/1506] drm/i915/execlists: Direct submission of new requests (avoid tasklet/ksoftirqd) Back in commit 27af5eea54d1 ("drm/i915: Move execlists irq handler to a bottom half"), we came to the conclusion that running our CSB processing and ELSP submission from inside the irq handler was a bad idea. A really bad idea as we could impose nearly 1s latency on other users of the system, on average! Deferring our work to a tasklet allowed us to do the processing with irqs enabled, reducing the impact to an average of about 50us. We have since eradicated the use of forcewaked mmio from inside the CSB processing and ELSP submission, bringing the impact down to around 5us (on Kabylake); an order of magnitude better than our measurements 2 years ago on Broadwell and only about 2x worse on average than the gem_syslatency on an unladen system. In this iteration of the tasklet-vs-direct submission debate, we seek a compromise where by we submit new requests immediately to the HW but defer processing the CS interrupt onto a tasklet. We gain the advantage of low-latency and ksoftirqd avoidance when waking up the HW, while avoiding the system-wide starvation of our CS irq-storms. Comparing the impact on the maximum latency observed (that is the time stolen from an RT process) over a 120s interval, repeated several times (using gem_syslatency, similar to RT's cyclictest) while the system is fully laden with i915 nops, we see that direct submission an actually improve the worse case. Maximum latency in microseconds of a third party RT thread (gem_syslatency -t 120 -f 2) x Always using tasklets (a couple of >1000us outliers removed) + Only using tasklets from CS irq, direct submission of requests +------------------------------------------------------------------------+ | + | | + | | + | | + + | | + + + | | + + + + x x x | | +++ + + + x x x x x x | | +++ + ++ + + *x x x x x x | | +++ + ++ + * *x x * x x x | | + +++ + ++ * * +*xxx * x x xx | | * +++ + ++++* *x+**xx+ * x x xxxx x | | **x++++*++**+*x*x****x+ * +x xx xxxx x x | |x* ******+***************++*+***xxxxxx* xx*x xxx + x+| | |__________MA___________| | | |______M__A________| | +------------------------------------------------------------------------+ N Min Max Median Avg Stddev x 118 91 186 124 125.28814 16.279137 + 120 92 187 109 112.00833 13.458617 Difference at 95.0% confidence -13.2798 +/- 3.79219 -10.5994% +/- 3.02677% (Student's t, pooled s = 14.9237) However the mean latency is adversely affected: Mean latency in microseconds of a third party RT thread (gem_syslatency -t 120 -f 1) x Always using tasklets + Only using tasklets from CS irq, direct submission of requests +------------------------------------------------------------------------+ | xxxxxx + ++ | | xxxxxx + ++ | | xxxxxx + +++ ++ | | xxxxxxx +++++ ++ | | xxxxxxx +++++ ++ | | xxxxxxx +++++ +++ | | xxxxxxx + ++++++++++ | | xxxxxxxx ++ ++++++++++ | | xxxxxxxx ++ ++++++++++ | | xxxxxxxxxx +++++++++++++++ | | xxxxxxxxxxx x +++++++++++++++ | |x xxxxxxxxxxxxx x + + ++++++++++++++++++ +| | |__A__| | | |____A___| | +------------------------------------------------------------------------+ N Min Max Median Avg Stddev x 120 3.506 3.727 3.631 3.6321417 0.02773109 + 120 3.834 4.149 4.039 4.0375167 0.041221676 Difference at 95.0% confidence 0.405375 +/- 0.00888913 11.1608% +/- 0.244735% (Student's t, pooled s = 0.03513) However, since the mean latency corresponds to the amount of irqsoff processing we have to do for a CS interrupt, we only need to speed that up to benefit not just system latency but our own throughput. v2: Remember to defer submissions when under reset. v4: Only use direct submission for new requests v5: Be aware that with mixing direct tasklet evaluation and deferred tasklets, we may end up idling before running the deferred tasklet. v6: Remove the redudant likely() from tasklet_is_enabled(), restrict the annotation to reset_in_progress(). v7: Take the full timeline.lock when enabling perf_pmu stats as the tasklet is no longer a valid guard. A consequence is that the stats are now only valid for engines also using the timeline.lock to process state. Testcase: igt/gem_exec_latency/*rthog* References: 27af5eea54d1 ("drm/i915: Move execlists irq handler to a bottom half") Suggested-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180628201211.13837-9-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.h | 5 ++ drivers/gpu/drm/i915/intel_engine_cs.c | 8 +- drivers/gpu/drm/i915/intel_lrc.c | 102 ++++++++++++++++--------- 3 files changed, 75 insertions(+), 40 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.h b/drivers/gpu/drm/i915/i915_gem.h index 261da577829a6..e465929568726 100644 --- a/drivers/gpu/drm/i915/i915_gem.h +++ b/drivers/gpu/drm/i915/i915_gem.h @@ -88,4 +88,9 @@ static inline void __tasklet_enable_sync_once(struct tasklet_struct *t) tasklet_kill(t); } +static inline bool __tasklet_is_enabled(const struct tasklet_struct *t) +{ + return !atomic_read(&t->count); +} + #endif /* __I915_GEM_H__ */ diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index ace93958689ef..01862884a4360 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -1619,8 +1619,8 @@ int intel_enable_engine_stats(struct intel_engine_cs *engine) if (!intel_engine_supports_stats(engine)) return -ENODEV; - tasklet_disable(&execlists->tasklet); - write_seqlock_irqsave(&engine->stats.lock, flags); + spin_lock_irqsave(&engine->timeline.lock, flags); + write_seqlock(&engine->stats.lock); if (unlikely(engine->stats.enabled == ~0)) { err = -EBUSY; @@ -1644,8 +1644,8 @@ int intel_enable_engine_stats(struct intel_engine_cs *engine) } unlock: - write_sequnlock_irqrestore(&engine->stats.lock, flags); - tasklet_enable(&execlists->tasklet); + write_sequnlock(&engine->stats.lock); + spin_unlock_irqrestore(&engine->timeline.lock, flags); return err; } diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index d835da128a172..6ab6ddb103d12 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -563,12 +563,14 @@ static void complete_preempt_context(struct intel_engine_execlists *execlists) GEM_BUG_ON(!execlists_is_active(execlists, EXECLISTS_ACTIVE_PREEMPT)); execlists_cancel_port_requests(execlists); - execlists_unwind_incomplete_requests(execlists); + __unwind_incomplete_requests(container_of(execlists, + struct intel_engine_cs, + execlists)); execlists_clear_active(execlists, EXECLISTS_ACTIVE_PREEMPT); } -static void __execlists_dequeue(struct intel_engine_cs *engine) +static void execlists_dequeue(struct intel_engine_cs *engine) { struct intel_engine_execlists * const execlists = &engine->execlists; struct execlist_port *port = execlists->port; @@ -578,9 +580,8 @@ static void __execlists_dequeue(struct intel_engine_cs *engine) struct rb_node *rb; bool submit = false; - lockdep_assert_held(&engine->timeline.lock); - - /* Hardware submission is through 2 ports. Conceptually each port + /* + * Hardware submission is through 2 ports. Conceptually each port * has a (RING_START, RING_HEAD, RING_TAIL) tuple. RING_START is * static for a context, and unique to each, so we only execute * requests belonging to a single context from each ring. RING_HEAD @@ -770,15 +771,6 @@ static void __execlists_dequeue(struct intel_engine_cs *engine) !port_isset(engine->execlists.port)); } -static void execlists_dequeue(struct intel_engine_cs *engine) -{ - unsigned long flags; - - spin_lock_irqsave(&engine->timeline.lock, flags); - __execlists_dequeue(engine); - spin_unlock_irqrestore(&engine->timeline.lock, flags); -} - void execlists_cancel_port_requests(struct intel_engine_execlists * const execlists) { @@ -958,6 +950,12 @@ static void execlists_cancel_requests(struct intel_engine_cs *engine) spin_unlock_irqrestore(&engine->timeline.lock, flags); } +static inline bool +reset_in_progress(const struct intel_engine_execlists *execlists) +{ + return unlikely(!__tasklet_is_enabled(&execlists->tasklet)); +} + static void process_csb(struct intel_engine_cs *engine) { struct intel_engine_execlists * const execlists = &engine->execlists; @@ -1109,18 +1107,9 @@ static void process_csb(struct intel_engine_cs *engine) execlists->csb_head = head; } -/* - * Check the unread Context Status Buffers and manage the submission of new - * contexts to the ELSP accordingly. - */ -static void execlists_submission_tasklet(unsigned long data) +static void __execlists_submission_tasklet(struct intel_engine_cs *const engine) { - struct intel_engine_cs * const engine = (struct intel_engine_cs *)data; - - GEM_TRACE("%s awake?=%d, active=%x\n", - engine->name, - engine->i915->gt.awake, - engine->execlists.active); + lockdep_assert_held(&engine->timeline.lock); /* * We can skip acquiring intel_runtime_pm_get() here as it was taken @@ -1137,6 +1126,28 @@ static void execlists_submission_tasklet(unsigned long data) execlists_dequeue(engine); } +/* + * Check the unread Context Status Buffers and manage the submission of new + * contexts to the ELSP accordingly. + */ +static void execlists_submission_tasklet(unsigned long data) +{ + struct intel_engine_cs * const engine = (struct intel_engine_cs *)data; + unsigned long flags; + + GEM_TRACE("%s awake?=%d, active=%x\n", + engine->name, + engine->i915->gt.awake, + engine->execlists.active); + + spin_lock_irqsave(&engine->timeline.lock, flags); + + if (engine->i915->gt.awake) /* we may be delayed until after we idle! */ + __execlists_submission_tasklet(engine); + + spin_unlock_irqrestore(&engine->timeline.lock, flags); +} + static void queue_request(struct intel_engine_cs *engine, struct i915_sched_node *node, int prio) @@ -1145,16 +1156,30 @@ static void queue_request(struct intel_engine_cs *engine, &lookup_priolist(engine, prio)->requests); } -static void __submit_queue(struct intel_engine_cs *engine, int prio) +static void __update_queue(struct intel_engine_cs *engine, int prio) { engine->execlists.queue_priority = prio; - tasklet_hi_schedule(&engine->execlists.tasklet); +} + +static void __submit_queue_imm(struct intel_engine_cs *engine) +{ + struct intel_engine_execlists * const execlists = &engine->execlists; + + if (reset_in_progress(execlists)) + return; /* defer until we restart the engine following reset */ + + if (execlists->tasklet.func == execlists_submission_tasklet) + __execlists_submission_tasklet(engine); + else + tasklet_hi_schedule(&execlists->tasklet); } static void submit_queue(struct intel_engine_cs *engine, int prio) { - if (prio > engine->execlists.queue_priority) - __submit_queue(engine, prio); + if (prio > engine->execlists.queue_priority) { + __update_queue(engine, prio); + __submit_queue_imm(engine); + } } static void execlists_submit_request(struct i915_request *request) @@ -1166,11 +1191,12 @@ static void execlists_submit_request(struct i915_request *request) spin_lock_irqsave(&engine->timeline.lock, flags); queue_request(engine, &request->sched, rq_prio(request)); - submit_queue(engine, rq_prio(request)); GEM_BUG_ON(!engine->execlists.first); GEM_BUG_ON(list_empty(&request->sched.link)); + submit_queue(engine, rq_prio(request)); + spin_unlock_irqrestore(&engine->timeline.lock, flags); } @@ -1297,8 +1323,11 @@ static void execlists_schedule(struct i915_request *request, } if (prio > engine->execlists.queue_priority && - i915_sw_fence_done(&sched_to_request(node)->submit)) - __submit_queue(engine, prio); + i915_sw_fence_done(&sched_to_request(node)->submit)) { + /* defer submission until after all of our updates */ + __update_queue(engine, prio); + tasklet_hi_schedule(&engine->execlists.tasklet); + } } spin_unlock_irq(&engine->timeline.lock); @@ -1879,6 +1908,7 @@ execlists_reset_prepare(struct intel_engine_cs *engine) { struct intel_engine_execlists * const execlists = &engine->execlists; struct i915_request *request, *active; + unsigned long flags; GEM_TRACE("%s\n", engine->name); @@ -1893,6 +1923,8 @@ execlists_reset_prepare(struct intel_engine_cs *engine) */ __tasklet_disable_sync_once(&execlists->tasklet); + spin_lock_irqsave(&engine->timeline.lock, flags); + /* * We want to flush the pending context switches, having disabled * the tasklet above, we can assume exclusive access to the execlists. @@ -1910,15 +1942,12 @@ execlists_reset_prepare(struct intel_engine_cs *engine) active = NULL; request = port_request(execlists->port); if (request) { - unsigned long flags; - /* * Prevent the breadcrumb from advancing before we decide * which request is currently active. */ intel_engine_stop_cs(engine); - spin_lock_irqsave(&engine->timeline.lock, flags); list_for_each_entry_from_reverse(request, &engine->timeline.requests, link) { @@ -1928,9 +1957,10 @@ execlists_reset_prepare(struct intel_engine_cs *engine) active = request; } - spin_unlock_irqrestore(&engine->timeline.lock, flags); } + spin_unlock_irqrestore(&engine->timeline.lock, flags); + return active; } -- GitLab From c9855a561afa5b21db7f2218f0b7baaa555fa90c Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Date: Mon, 25 Jun 2018 18:37:57 +0200 Subject: [PATCH 0585/1506] drm/i915: Block enabling FBC until flips have been completed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is a small race window in which FBC can be enabled after pre_plane_update is called, but before the page flip has been queued or completed. Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=103167 Link: https://patchwork.freedesktop.org/patch/msgid/20180625163758.10871-1-maarten.lankhorst@linux.intel.com Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_fbc.c | 35 ++++++++++---------------------- 2 files changed, 12 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 2b684f431c600..615ed807ea324 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -512,6 +512,7 @@ struct intel_fbc { bool enabled; bool active; + bool flip_pending; bool underrun_detected; struct work_struct underrun_work; diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index b431b6733cc15..9f9ea0b5452fe 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -924,13 +924,6 @@ static void intel_fbc_get_reg_params(struct intel_crtc *crtc, 32 * fbc->threshold) * 8; } -static bool intel_fbc_reg_params_equal(struct intel_fbc_reg_params *params1, - struct intel_fbc_reg_params *params2) -{ - /* We can use this since intel_fbc_get_reg_params() does a memset. */ - return memcmp(params1, params2, sizeof(*params1)) == 0; -} - void intel_fbc_pre_update(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state, struct intel_plane_state *plane_state) @@ -953,6 +946,7 @@ void intel_fbc_pre_update(struct intel_crtc *crtc, goto unlock; intel_fbc_update_state_cache(crtc, crtc_state, plane_state); + fbc->flip_pending = true; deactivate: intel_fbc_deactivate(dev_priv, reason); @@ -988,13 +982,15 @@ static void __intel_fbc_post_update(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); struct intel_fbc *fbc = &dev_priv->fbc; - struct intel_fbc_reg_params old_params; WARN_ON(!mutex_is_locked(&fbc->lock)); if (!fbc->enabled || fbc->crtc != crtc) return; + fbc->flip_pending = false; + WARN_ON(fbc->active); + if (!i915_modparams.enable_fbc) { intel_fbc_deactivate(dev_priv, "disabled at runtime per module param"); __intel_fbc_disable(dev_priv); @@ -1002,25 +998,16 @@ static void __intel_fbc_post_update(struct intel_crtc *crtc) return; } - if (!intel_fbc_can_activate(crtc)) { - WARN_ON(fbc->active); - return; - } - - old_params = fbc->params; intel_fbc_get_reg_params(crtc, &fbc->params); - /* If the scanout has not changed, don't modify the FBC settings. - * Note that we make the fundamental assumption that the fb->obj - * cannot be unpinned (and have its GTT offset and fence revoked) - * without first being decoupled from the scanout and FBC disabled. - */ - if (fbc->active && - intel_fbc_reg_params_equal(&old_params, &fbc->params)) + if (!intel_fbc_can_activate(crtc)) return; - intel_fbc_deactivate(dev_priv, "FBC enabled (active or scheduled)"); - intel_fbc_schedule_activation(crtc); + if (!fbc->busy_bits) { + intel_fbc_deactivate(dev_priv, "FBC enabled (active or scheduled)"); + intel_fbc_schedule_activation(crtc); + } else + intel_fbc_deactivate(dev_priv, "frontbuffer write"); } void intel_fbc_post_update(struct intel_crtc *crtc) @@ -1085,7 +1072,7 @@ void intel_fbc_flush(struct drm_i915_private *dev_priv, (frontbuffer_bits & intel_fbc_get_frontbuffer_bit(fbc))) { if (fbc->active) intel_fbc_recompress(dev_priv); - else + else if (!fbc->flip_pending) __intel_fbc_post_update(fbc->crtc); } -- GitLab From 457209595789a3acd57990e2e9dade95bbea8fba Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Date: Mon, 25 Jun 2018 18:37:58 +0200 Subject: [PATCH 0586/1506] drm/i915: Remove delayed FBC activation. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The only time we should start FBC is when we have waited a vblank after the atomic update. We've already forced a vblank wait by doing wait_for_flip_done before intel_post_plane_update(), so we don't need to wait a second time before enabling. Removing the worker simplifies the code and removes possible race conditions, like happening in 103167. Cc: Paulo Zanoni <paulo.r.zanoni@intel.com> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=103167 Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180625163758.10871-2-maarten.lankhorst@linux.intel.com Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> --- drivers/gpu/drm/i915/i915_debugfs.c | 5 -- drivers/gpu/drm/i915/i915_drv.h | 6 -- drivers/gpu/drm/i915/intel_fbc.c | 96 +---------------------------- 3 files changed, 1 insertion(+), 106 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index c400f42a54ec7..48a57c0636bf4 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1659,11 +1659,6 @@ static int i915_fbc_status(struct seq_file *m, void *unused) else seq_printf(m, "FBC disabled: %s\n", fbc->no_fbc_reason); - if (fbc->work.scheduled) - seq_printf(m, "FBC worker scheduled on vblank %llu, now %llu\n", - fbc->work.scheduled_vblank, - drm_crtc_vblank_count(&fbc->crtc->base)); - if (intel_fbc_is_active(dev_priv)) { u32 mask; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 615ed807ea324..ce7d063328842 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -580,12 +580,6 @@ struct intel_fbc { unsigned int gen9_wa_cfb_stride; } params; - struct intel_fbc_work { - bool scheduled; - u64 scheduled_vblank; - struct work_struct work; - } work; - const char *no_fbc_reason; }; diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 9f9ea0b5452fe..01d1d2088f048 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -399,89 +399,6 @@ bool intel_fbc_is_active(struct drm_i915_private *dev_priv) return dev_priv->fbc.active; } -static void intel_fbc_work_fn(struct work_struct *__work) -{ - struct drm_i915_private *dev_priv = - container_of(__work, struct drm_i915_private, fbc.work.work); - struct intel_fbc *fbc = &dev_priv->fbc; - struct intel_fbc_work *work = &fbc->work; - struct intel_crtc *crtc = fbc->crtc; - struct drm_vblank_crtc *vblank = &dev_priv->drm.vblank[crtc->pipe]; - - if (drm_crtc_vblank_get(&crtc->base)) { - /* CRTC is now off, leave FBC deactivated */ - mutex_lock(&fbc->lock); - work->scheduled = false; - mutex_unlock(&fbc->lock); - return; - } - -retry: - /* Delay the actual enabling to let pageflipping cease and the - * display to settle before starting the compression. Note that - * this delay also serves a second purpose: it allows for a - * vblank to pass after disabling the FBC before we attempt - * to modify the control registers. - * - * WaFbcWaitForVBlankBeforeEnable:ilk,snb - * - * It is also worth mentioning that since work->scheduled_vblank can be - * updated multiple times by the other threads, hitting the timeout is - * not an error condition. We'll just end up hitting the "goto retry" - * case below. - */ - wait_event_timeout(vblank->queue, - drm_crtc_vblank_count(&crtc->base) != work->scheduled_vblank, - msecs_to_jiffies(50)); - - mutex_lock(&fbc->lock); - - /* Were we cancelled? */ - if (!work->scheduled) - goto out; - - /* Were we delayed again while this function was sleeping? */ - if (drm_crtc_vblank_count(&crtc->base) == work->scheduled_vblank) { - mutex_unlock(&fbc->lock); - goto retry; - } - - intel_fbc_hw_activate(dev_priv); - - work->scheduled = false; - -out: - mutex_unlock(&fbc->lock); - drm_crtc_vblank_put(&crtc->base); -} - -static void intel_fbc_schedule_activation(struct intel_crtc *crtc) -{ - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - struct intel_fbc *fbc = &dev_priv->fbc; - struct intel_fbc_work *work = &fbc->work; - - WARN_ON(!mutex_is_locked(&fbc->lock)); - if (WARN_ON(!fbc->enabled)) - return; - - if (drm_crtc_vblank_get(&crtc->base)) { - DRM_ERROR("vblank not available for FBC on pipe %c\n", - pipe_name(crtc->pipe)); - return; - } - - /* It is useless to call intel_fbc_cancel_work() or cancel_work() in - * this function since we're not releasing fbc.lock, so it won't have an - * opportunity to grab it to discover that it was cancelled. So we just - * update the expected jiffy count. */ - work->scheduled = true; - work->scheduled_vblank = drm_crtc_vblank_count(&crtc->base); - drm_crtc_vblank_put(&crtc->base); - - schedule_work(&work->work); -} - static void intel_fbc_deactivate(struct drm_i915_private *dev_priv, const char *reason) { @@ -489,11 +406,6 @@ static void intel_fbc_deactivate(struct drm_i915_private *dev_priv, WARN_ON(!mutex_is_locked(&fbc->lock)); - /* Calling cancel_work() here won't help due to the fact that the work - * function grabs fbc->lock. Just set scheduled to false so the work - * function can know it was cancelled. */ - fbc->work.scheduled = false; - if (fbc->active) intel_fbc_hw_deactivate(dev_priv); @@ -1005,7 +917,7 @@ static void __intel_fbc_post_update(struct intel_crtc *crtc) if (!fbc->busy_bits) { intel_fbc_deactivate(dev_priv, "FBC enabled (active or scheduled)"); - intel_fbc_schedule_activation(crtc); + intel_fbc_hw_activate(dev_priv); } else intel_fbc_deactivate(dev_priv, "frontbuffer write"); } @@ -1212,8 +1124,6 @@ void intel_fbc_disable(struct intel_crtc *crtc) if (fbc->crtc == crtc) __intel_fbc_disable(dev_priv); mutex_unlock(&fbc->lock); - - cancel_work_sync(&fbc->work.work); } /** @@ -1235,8 +1145,6 @@ void intel_fbc_global_disable(struct drm_i915_private *dev_priv) __intel_fbc_disable(dev_priv); } mutex_unlock(&fbc->lock); - - cancel_work_sync(&fbc->work.work); } static void intel_fbc_underrun_work_fn(struct work_struct *work) @@ -1387,12 +1295,10 @@ void intel_fbc_init(struct drm_i915_private *dev_priv) { struct intel_fbc *fbc = &dev_priv->fbc; - INIT_WORK(&fbc->work.work, intel_fbc_work_fn); INIT_WORK(&fbc->underrun_work, intel_fbc_underrun_work_fn); mutex_init(&fbc->lock); fbc->enabled = false; fbc->active = false; - fbc->work.scheduled = false; if (need_fbc_vtd_wa(dev_priv)) mkwrite_device_info(dev_priv)->has_fbc = false; -- GitLab From 334bb8972a131e604a741e9b284d8867190c723e Mon Sep 17 00:00:00 2001 From: Hans de Goede <hdegoede@redhat.com> Date: Fri, 29 Jun 2018 11:46:19 +0200 Subject: [PATCH 0587/1506] console: dummycon: export dummycon_[un]register_output_notifier Export dummycon_[un]register_output_notifier, the fbcon code needs this and may be build as a module. Fixes: 83d83bebf401 ("console/fbcon: Add support for deferred console takeover") Cc: Stephen Rothwell <sfr@canb.auug.org.au> Reported-by: Stephen Rothwell <sfr@canb.auug.org.au> Signed-off-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com> --- drivers/video/console/dummycon.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c index 45ad925ad5f8f..0254251fdd79a 100644 --- a/drivers/video/console/dummycon.c +++ b/drivers/video/console/dummycon.c @@ -38,11 +38,13 @@ void dummycon_register_output_notifier(struct notifier_block *nb) if (dummycon_putc_called) nb->notifier_call(nb, 0, NULL); } +EXPORT_SYMBOL_GPL(dummycon_register_output_notifier); void dummycon_unregister_output_notifier(struct notifier_block *nb) { raw_notifier_chain_unregister(&dummycon_output_nh, nb); } +EXPORT_SYMBOL_GPL(dummycon_unregister_output_notifier); static void dummycon_putc(struct vc_data *vc, int c, int ypos, int xpos) { -- GitLab From d78e2bbf483faa48f060c2454c56c3ff9cd74573 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 29 Jun 2018 14:37:16 +0100 Subject: [PATCH 0588/1506] drm/i915/selftests: Mark up write into scratch vma We correctly attach the exclusive fetch for the scratch object when emitting a request that writes into it, but for completeness we should also declared the write to i915_vma_move_to_active() Reported-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180629133717.11761-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/selftests/i915_gem_context.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_context.c b/drivers/gpu/drm/i915/selftests/i915_gem_context.c index c0c26fae45c71..cc848ceeb3c31 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_context.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_context.c @@ -175,7 +175,7 @@ static int gpu_fill(struct drm_i915_gem_object *obj, i915_vma_unpin(batch); i915_vma_close(batch); - i915_vma_move_to_active(vma, rq, 0); + i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE); i915_vma_unpin(vma); reservation_object_lock(obj->resv, NULL); -- GitLab From be01de596ef65ad1fc66a795d45e7334d197e594 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 29 Jun 2018 14:37:17 +0100 Subject: [PATCH 0589/1506] drm/i915/selftests: Attach the fence to the object when making busy make_obj_busy() makes a dummy busy object, but didn't attach the fence to the reservation object, so it would not have registered as busy. For completeness, attach the dummy request as the exclusive fence and mark the object as written (in i915_vma_move_to_active) Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180629133717.11761-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/selftests/i915_gem_object.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_object.c b/drivers/gpu/drm/i915/selftests/i915_gem_object.c index 549707b9d7388..77dd7a510ea60 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_object.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_object.c @@ -454,7 +454,12 @@ static int make_obj_busy(struct drm_i915_gem_object *obj) return PTR_ERR(rq); } - i915_vma_move_to_active(vma, rq, 0); + i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE); + + reservation_object_lock(vma->resv, NULL); + reservation_object_add_excl_fence(vma->resv, &rq->fence); + reservation_object_unlock(vma->resv); + i915_request_add(rq); i915_gem_object_set_active_reference(obj); -- GitLab From 3e2b88cbd225f0867fee6ba63ffe3c38a2e98822 Mon Sep 17 00:00:00 2001 From: "Dirk Hohndel (VMware)" <dirk@hohndel.org> Date: Mon, 7 May 2018 01:16:19 +0200 Subject: [PATCH 0590/1506] drm: add SPDX idenitifier and clarify license This is dual licensed under GPL-2.0 or MIT. Signed-off-by: Dirk Hohndel (VMware) <dirk@hohndel.org> Signed-off-by: David Herrmann <dh.herrmann@gmail.com> Signed-off-by: David Airlie <airlied@linux.ie> Acked-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180506231626.115996-2-dirk@hohndel.org --- drivers/gpu/drm/drm_vma_manager.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/drm_vma_manager.c b/drivers/gpu/drm/drm_vma_manager.c index 23c749c05b5aa..a6b2fe36b0252 100644 --- a/drivers/gpu/drm/drm_vma_manager.c +++ b/drivers/gpu/drm/drm_vma_manager.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT /* * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA * Copyright (c) 2012 David Airlie <airlied@linux.ie> -- GitLab From 4f960dcf75421033b00052abcfc4454e4d302655 Mon Sep 17 00:00:00 2001 From: "Dirk Hohndel (VMware)" <dirk@hohndel.org> Date: Mon, 7 May 2018 01:16:21 +0200 Subject: [PATCH 0591/1506] drm: add SPDX identifier and clarify license This is dual licensed under GPL-2.0 or MIT. Acked-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Dirk Hohndel (VMware) <dirk@hohndel.org> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180506231626.115996-4-dirk@hohndel.org --- drivers/gpu/drm/drm_global.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_global.c b/drivers/gpu/drm/drm_global.c index b2dc21e33ae0d..5799e2782dd13 100644 --- a/drivers/gpu/drm/drm_global.c +++ b/drivers/gpu/drm/drm_global.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * * Copyright 2008-2009 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the -- GitLab From eee3dc56e22eb8bf54eab925bba30bd94ae403bd Mon Sep 17 00:00:00 2001 From: "Dirk Hohndel (VMware)" <dirk@hohndel.org> Date: Mon, 7 May 2018 01:16:22 +0200 Subject: [PATCH 0592/1506] drm/noveau: add SPDX identifier and clarify license This is dual licensed under GPL-2.0 or MIT. Acked-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Dirk Hohndel (VMware) <dirk@hohndel.org> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180506231626.115996-5-dirk@hohndel.org --- drivers/gpu/drm/nouveau/nouveau_ttm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c index 8c093ca4222e2..8edb9f2a42694 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ttm.c +++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c @@ -1,8 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT /* * Copyright (c) 2007-2008 Tungsten Graphics, Inc., Cedar Park, TX., USA, - * All Rights Reserved. * Copyright (c) 2009 VMware, Inc., Palo Alto, CA., USA, - * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), -- GitLab From a3be6f6c6e3e9fc93cf0ac19aae039c7135686e3 Mon Sep 17 00:00:00 2001 From: "Dirk Hohndel (VMware)" <dirk@hohndel.org> Date: Mon, 7 May 2018 01:16:25 +0200 Subject: [PATCH 0593/1506] drm/vmwgfx: add SPDX idenitifier and clarify license These files are licensed under GPL-2.0. Removing the MIT boilerplate as that really didn't make any sense for those two header files. Acked-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Dirk Hohndel (VMware) <dirk@hohndel.org> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180506231626.115996-8-dirk@hohndel.org --- drivers/gpu/drm/vmwgfx/Kconfig | 1 + .../vmwgfx/device_include/vmware_pack_begin.h | 25 +------------------ .../vmwgfx/device_include/vmware_pack_end.h | 25 +------------------ 3 files changed, 3 insertions(+), 48 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/Kconfig b/drivers/gpu/drm/vmwgfx/Kconfig index 8c308dac99c50..6b28a326f8bb2 100644 --- a/drivers/gpu/drm/vmwgfx/Kconfig +++ b/drivers/gpu/drm/vmwgfx/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 config DRM_VMWGFX tristate "DRM driver for VMware Virtual GPU" depends on DRM && PCI && X86 && MMU diff --git a/drivers/gpu/drm/vmwgfx/device_include/vmware_pack_begin.h b/drivers/gpu/drm/vmwgfx/device_include/vmware_pack_begin.h index 7e7b0ce34aa29..75308bd0d9705 100644 --- a/drivers/gpu/drm/vmwgfx/device_include/vmware_pack_begin.h +++ b/drivers/gpu/drm/vmwgfx/device_include/vmware_pack_begin.h @@ -1,25 +1,2 @@ -/********************************************************** - * Copyright 2015 VMware, Inc. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - **********************************************************/ +/* SPDX-License-Identifier: GPL-2.0 */ #include <linux/compiler.h> diff --git a/drivers/gpu/drm/vmwgfx/device_include/vmware_pack_end.h b/drivers/gpu/drm/vmwgfx/device_include/vmware_pack_end.h index e2e440ed3d442..e93d6f28b68ce 100644 --- a/drivers/gpu/drm/vmwgfx/device_include/vmware_pack_end.h +++ b/drivers/gpu/drm/vmwgfx/device_include/vmware_pack_end.h @@ -1,25 +1,2 @@ -/********************************************************** - * Copyright 2015 VMware, Inc. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - **********************************************************/ +/* SPDX-License-Identifier: GPL-2.0 */ __packed -- GitLab From dff96888860a9ebaa618be973b51f4d86aec1211 Mon Sep 17 00:00:00 2001 From: "Dirk Hohndel (VMware)" <dirk@hohndel.org> Date: Mon, 7 May 2018 01:16:26 +0200 Subject: [PATCH 0594/1506] drm/vmwgfx: add SPDX idenitifier and clarify license This is dual licensed under GPL-2.0 or MIT. vmwgfx_msg.h is the odd one out that is GPL-2.0+ or MIT. Acked-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Dirk Hohndel (VMware) <dirk@hohndel.org> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180506231626.115996-9-dirk@hohndel.org --- .../drm/vmwgfx/device_include/svga3d_caps.h | 3 +- .../drm/vmwgfx/device_include/svga3d_cmd.h | 3 +- .../vmwgfx/device_include/svga3d_devcaps.h | 3 +- .../gpu/drm/vmwgfx/device_include/svga3d_dx.h | 3 +- .../drm/vmwgfx/device_include/svga3d_limits.h | 3 +- .../drm/vmwgfx/device_include/svga3d_reg.h | 3 +- .../device_include/svga3d_surfacedefs.h | 4 +-- .../drm/vmwgfx/device_include/svga3d_types.h | 3 +- .../drm/vmwgfx/device_include/svga_escape.h | 3 +- .../drm/vmwgfx/device_include/svga_overlay.h | 3 +- .../gpu/drm/vmwgfx/device_include/svga_reg.h | 3 +- .../drm/vmwgfx/device_include/svga_types.h | 3 +- drivers/gpu/drm/vmwgfx/vmwgfx_binding.c | 4 +-- drivers/gpu/drm/vmwgfx/vmwgfx_binding.h | 4 +-- drivers/gpu/drm/vmwgfx/vmwgfx_blit.c | 3 +- drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c | 4 +-- drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c | 4 +-- drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c | 4 +-- drivers/gpu/drm/vmwgfx/vmwgfx_context.c | 4 +-- drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c | 4 +-- drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c | 4 +-- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 4 +-- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 4 +-- drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 4 +-- drivers/gpu/drm/vmwgfx/vmwgfx_fence.c | 4 +-- drivers/gpu/drm/vmwgfx/vmwgfx_fence.h | 4 +-- drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c | 4 +-- drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c | 4 +-- drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c | 4 +-- drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c | 4 +-- drivers/gpu/drm/vmwgfx/vmwgfx_irq.c | 4 +-- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 4 +-- drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 4 +-- drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 4 +-- drivers/gpu/drm/vmwgfx/vmwgfx_marker.c | 4 +-- drivers/gpu/drm/vmwgfx/vmwgfx_mob.c | 4 +-- drivers/gpu/drm/vmwgfx/vmwgfx_msg.c | 4 +-- drivers/gpu/drm/vmwgfx/vmwgfx_msg.h | 35 +++++++++++++------ drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c | 4 +-- drivers/gpu/drm/vmwgfx/vmwgfx_prime.c | 4 +-- drivers/gpu/drm/vmwgfx/vmwgfx_reg.h | 4 +-- drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 4 +-- drivers/gpu/drm/vmwgfx/vmwgfx_resource_priv.h | 4 +-- drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 4 +-- drivers/gpu/drm/vmwgfx/vmwgfx_shader.c | 4 +-- .../gpu/drm/vmwgfx/vmwgfx_simple_resource.c | 4 +-- drivers/gpu/drm/vmwgfx/vmwgfx_so.c | 4 +-- drivers/gpu/drm/vmwgfx/vmwgfx_so.h | 4 +-- drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 4 +-- drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 4 +-- drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c | 4 +-- drivers/gpu/drm/vmwgfx/vmwgfx_va.c | 4 +-- 52 files changed, 126 insertions(+), 101 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/device_include/svga3d_caps.h b/drivers/gpu/drm/vmwgfx/device_include/svga3d_caps.h index 9ce2466a5d007..69c4253fbfbb1 100644 --- a/drivers/gpu/drm/vmwgfx/device_include/svga3d_caps.h +++ b/drivers/gpu/drm/vmwgfx/device_include/svga3d_caps.h @@ -1,5 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0 OR MIT */ /********************************************************** - * Copyright 2007-2015 VMware, Inc. All rights reserved. + * Copyright 2007-2015 VMware, Inc. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation diff --git a/drivers/gpu/drm/vmwgfx/device_include/svga3d_cmd.h b/drivers/gpu/drm/vmwgfx/device_include/svga3d_cmd.h index 2dfd57c5f4633..3bf75978e1554 100644 --- a/drivers/gpu/drm/vmwgfx/device_include/svga3d_cmd.h +++ b/drivers/gpu/drm/vmwgfx/device_include/svga3d_cmd.h @@ -1,5 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0 OR MIT */ /********************************************************** - * Copyright 1998-2015 VMware, Inc. All rights reserved. + * Copyright 1998-2015 VMware, Inc. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation diff --git a/drivers/gpu/drm/vmwgfx/device_include/svga3d_devcaps.h b/drivers/gpu/drm/vmwgfx/device_include/svga3d_devcaps.h index c18b663f360f7..e1c0d94cc1e94 100644 --- a/drivers/gpu/drm/vmwgfx/device_include/svga3d_devcaps.h +++ b/drivers/gpu/drm/vmwgfx/device_include/svga3d_devcaps.h @@ -1,5 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0 OR MIT */ /********************************************************** - * Copyright 1998-2015 VMware, Inc. All rights reserved. + * Copyright 1998-2015 VMware, Inc. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation diff --git a/drivers/gpu/drm/vmwgfx/device_include/svga3d_dx.h b/drivers/gpu/drm/vmwgfx/device_include/svga3d_dx.h index 8c5ae608cfb4f..f4606d04556b8 100644 --- a/drivers/gpu/drm/vmwgfx/device_include/svga3d_dx.h +++ b/drivers/gpu/drm/vmwgfx/device_include/svga3d_dx.h @@ -1,5 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0 OR MIT */ /********************************************************** - * Copyright 2012-2015 VMware, Inc. All rights reserved. + * Copyright 2012-2015 VMware, Inc. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation diff --git a/drivers/gpu/drm/vmwgfx/device_include/svga3d_limits.h b/drivers/gpu/drm/vmwgfx/device_include/svga3d_limits.h index a1c36877ad552..8732490d45d59 100644 --- a/drivers/gpu/drm/vmwgfx/device_include/svga3d_limits.h +++ b/drivers/gpu/drm/vmwgfx/device_include/svga3d_limits.h @@ -1,5 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0 OR MIT */ /********************************************************** - * Copyright 2007-2015 VMware, Inc. All rights reserved. + * Copyright 2007-2015 VMware, Inc. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation diff --git a/drivers/gpu/drm/vmwgfx/device_include/svga3d_reg.h b/drivers/gpu/drm/vmwgfx/device_include/svga3d_reg.h index b44ce648f592d..bdfc404c91e3c 100644 --- a/drivers/gpu/drm/vmwgfx/device_include/svga3d_reg.h +++ b/drivers/gpu/drm/vmwgfx/device_include/svga3d_reg.h @@ -1,5 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0 OR MIT */ /********************************************************** - * Copyright 1998-2015 VMware, Inc. All rights reserved. + * Copyright 1998-2015 VMware, Inc. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation diff --git a/drivers/gpu/drm/vmwgfx/device_include/svga3d_surfacedefs.h b/drivers/gpu/drm/vmwgfx/device_include/svga3d_surfacedefs.h index babe7cb84fc21..b45e96309233c 100644 --- a/drivers/gpu/drm/vmwgfx/device_include/svga3d_surfacedefs.h +++ b/drivers/gpu/drm/vmwgfx/device_include/svga3d_surfacedefs.h @@ -1,7 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 OR MIT */ /************************************************************************** * - * Copyright © 2008-2015 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. + * Copyright 2008-2015 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the diff --git a/drivers/gpu/drm/vmwgfx/device_include/svga3d_types.h b/drivers/gpu/drm/vmwgfx/device_include/svga3d_types.h index 27b33ba884309..df63f24c2e10a 100644 --- a/drivers/gpu/drm/vmwgfx/device_include/svga3d_types.h +++ b/drivers/gpu/drm/vmwgfx/device_include/svga3d_types.h @@ -1,5 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0 OR MIT */ /********************************************************** - * Copyright 2012-2015 VMware, Inc. All rights reserved. + * Copyright 2012-2015 VMware, Inc. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation diff --git a/drivers/gpu/drm/vmwgfx/device_include/svga_escape.h b/drivers/gpu/drm/vmwgfx/device_include/svga_escape.h index 884b1d1fb85f3..acb41e28e46fb 100644 --- a/drivers/gpu/drm/vmwgfx/device_include/svga_escape.h +++ b/drivers/gpu/drm/vmwgfx/device_include/svga_escape.h @@ -1,5 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0 OR MIT */ /********************************************************** - * Copyright 2007-2015 VMware, Inc. All rights reserved. + * Copyright 2007-2015 VMware, Inc. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation diff --git a/drivers/gpu/drm/vmwgfx/device_include/svga_overlay.h b/drivers/gpu/drm/vmwgfx/device_include/svga_overlay.h index faf6d9b2b8913..e5385146e7fc3 100644 --- a/drivers/gpu/drm/vmwgfx/device_include/svga_overlay.h +++ b/drivers/gpu/drm/vmwgfx/device_include/svga_overlay.h @@ -1,5 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0 OR MIT */ /********************************************************** - * Copyright 2007-2015 VMware, Inc. All rights reserved. + * Copyright 2007-2015 VMware, Inc. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation diff --git a/drivers/gpu/drm/vmwgfx/device_include/svga_reg.h b/drivers/gpu/drm/vmwgfx/device_include/svga_reg.h index 88e72bf9a534a..847e3301c4786 100644 --- a/drivers/gpu/drm/vmwgfx/device_include/svga_reg.h +++ b/drivers/gpu/drm/vmwgfx/device_include/svga_reg.h @@ -1,5 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0 OR MIT */ /********************************************************** - * Copyright 1998-2015 VMware, Inc. All rights reserved. + * Copyright 1998-2015 VMware, Inc. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation diff --git a/drivers/gpu/drm/vmwgfx/device_include/svga_types.h b/drivers/gpu/drm/vmwgfx/device_include/svga_types.h index 2e8ba4df8de9e..53602a4e79579 100644 --- a/drivers/gpu/drm/vmwgfx/device_include/svga_types.h +++ b/drivers/gpu/drm/vmwgfx/device_include/svga_types.h @@ -1,5 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0 OR MIT */ /********************************************************** - * Copyright 2015 VMware, Inc. All rights reserved. + * Copyright 2015 VMware, Inc. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_binding.c b/drivers/gpu/drm/vmwgfx/vmwgfx_binding.c index 55d32ae43aa4a..0b9ee7fb45d6e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_binding.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_binding.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * Copyright © 2015 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. + * Copyright 2015 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_binding.h b/drivers/gpu/drm/vmwgfx/vmwgfx_binding.h index bf2e77ad5a209..6a2a9d69043b0 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_binding.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_binding.h @@ -1,7 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 OR MIT */ /************************************************************************** * - * Copyright © 2015 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. + * Copyright 2015 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_blit.c b/drivers/gpu/drm/vmwgfx/vmwgfx_blit.c index e8c94b19db7bc..fc6673cde2895 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_blit.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_blit.c @@ -1,6 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * Copyright © 2017 VMware, Inc., Palo Alto, CA., USA + * Copyright 2017 VMware, Inc., Palo Alto, CA., USA * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c index 21111fd091f95..02de216d55a11 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * Copyright © 2009-2015 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. + * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c index 9f45d5004caed..e7e4655d3f36b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * Copyright © 2015 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. + * Copyright 2015 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c index 36c7b6c839c0d..3b75af9bf85f3 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * Copyright © 2014-2015 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. + * Copyright 2014-2015 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_context.c b/drivers/gpu/drm/vmwgfx/vmwgfx_context.c index 3767ac335acae..750319d954583 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_context.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_context.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * Copyright © 2009-2015 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. + * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c index cbf54ea7b4c0e..df55e7d8b4cf5 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * Copyright © 2014-2015 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. + * Copyright 2014-2015 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c index d59d9dd16ebc6..df7d1c97eb824 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * Copyright © 2011-2015 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. + * Copyright 2011-2015 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 09cc721160c46..af88cb737be3c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * Copyright © 2009-2016 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. + * Copyright 2009-2016 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 5fcbe1620d50b..422eef114b98b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -1,7 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 OR MIT */ /************************************************************************** * - * Copyright © 2009-2015 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. + * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index c9d5cc237124e..47bb7e58a3680 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * Copyright © 2009 - 2015 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. + * Copyright 2009 - 2015 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c index 9ed544f8958f3..c2eeb677cdfcd 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * Copyright © 2011-2014 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. + * Copyright 2011-2014 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h index 20224dba9d8e0..c9382933c2b94 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h @@ -1,7 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 OR MIT */ /************************************************************************** * - * Copyright © 2011-2012 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. + * Copyright 2011-2012 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c index a1c68e6a689e3..d0fd147ef75f2 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * Copyright © 2009-2015 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. + * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c b/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c index 66ffa1d4759c1..007a0cc7f2322 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * Copyright © 2009-2015 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. + * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c b/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c index f2f9d88131f25..ddb1e9365a3e5 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * Copyright (c) 2007-2010 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. + * Copyright 2007-2010 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c index c5e8eae0dbe23..78fce406e1d44 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * Copyright © 2009-2015 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. + * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c index b9239ba067c48..c3ad4478266b4 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * Copyright © 2009-2015 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. + * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index ef96ba7432ade..6317672070cdc 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * Copyright © 2009-2015 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. + * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index 6b7c012719f13..27c41c2271206 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -1,7 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 OR MIT */ /************************************************************************** * - * Copyright © 2009-2015 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. + * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index 4a5907e3f5602..dc0cfda26b1b5 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * Copyright © 2009-2015 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. + * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_marker.c b/drivers/gpu/drm/vmwgfx/vmwgfx_marker.c index efd1ffd68185a..e53bc639a7549 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_marker.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_marker.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * Copyright (C) 2010 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. + * Copyright 2010 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c b/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c index d07c585e3c1df..0963d0438190e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * Copyright © 2012-2015 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. + * Copyright 2012-2015 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c index 21d746bdc922b..4437c41c585a6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c @@ -1,6 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT /* - * Copyright © 2016 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. + * Copyright 2016 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.h b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.h index 8545488aa0cfb..4907e50fb20a2 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.h @@ -1,16 +1,29 @@ -/* - * Copyright (C) 2016, VMware, Inc. +/* SPDX-License-Identifier: GPL-2.0+ OR MIT */ +/************************************************************************** + * + * Copyright 2016 VMware, Inc., Palo Alto, CA., USA + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. * - * 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. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. * - * 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. + ************************************************************************** * * Based on code from vmware.c and vmmouse.c. * Author: diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c index 222c9c2123a1e..3ced89e70a642 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * Copyright © 2009-2014 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. + * Copyright 2009-2014 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_prime.c b/drivers/gpu/drm/vmwgfx/vmwgfx_prime.c index 373bc6da2f843..0861c821a7fe3 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_prime.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_prime.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * Copyright © 2013 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. + * Copyright 2013 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_reg.h b/drivers/gpu/drm/vmwgfx/vmwgfx_reg.h index dce798053a967..e99f6cdbb0913 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_reg.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_reg.h @@ -1,7 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 OR MIT */ /************************************************************************** * - * Copyright © 2009-2014 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. + * Copyright 2009-2014 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index 6b3a942b18df4..3063a3e4bd401 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * Copyright © 2009-2015 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. + * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource_priv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_resource_priv.h index ac05968a832bc..a8c1c5ebd71d3 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource_priv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource_priv.h @@ -1,7 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 OR MIT */ /************************************************************************** * - * Copyright © 2012-2014 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. + * Copyright 2012-2014 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index 9798640cbfcd9..73cf3c6e1591f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * Copyright © 2011-2015 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. + * Copyright 2011-2015 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c index 73b8e9a163685..e3ba63da396d1 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * Copyright © 2009-2015 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. + * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_simple_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_simple_resource.c index a0cb310665cc5..6ebc5affde147 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_simple_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_simple_resource.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * Copyright © 2016 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. + * Copyright 2016 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_so.c b/drivers/gpu/drm/vmwgfx/vmwgfx_so.c index d3573c37c4365..e9b6b7baa0094 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_so.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_so.c @@ -1,6 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** - * Copyright © 2014-2015 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. + * Copyright 2014-2015 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_so.h b/drivers/gpu/drm/vmwgfx/vmwgfx_so.h index 268738387b5e3..b80c7252f2fd1 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_so.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_so.h @@ -1,6 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0 OR MIT */ /************************************************************************** - * Copyright © 2014-2015 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. + * Copyright 2014-2015 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index 152e96cb1c01a..a474d87b1af31 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT /****************************************************************************** * - * COPYRIGHT © 2014-2015 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. + * COPYRIGHT (C) 2014-2015 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c index b236c48bf265b..40a439797ae26 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * Copyright © 2009-2015 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. + * Copyright 2009-2015 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c index e771091d2cd3b..7b1e5a5cbd2c7 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * Copyright © 2009-2011 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. + * Copyright 2009-2011 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_va.c b/drivers/gpu/drm/vmwgfx/vmwgfx_va.c index b4162fd78600f..ebc1d83c34b40 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_va.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_va.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * Copyright © 2012-2016 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. + * Copyright 2012-2016 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the -- GitLab From 14d9deeb273c2bf4ec256589adabd8df65395d36 Mon Sep 17 00:00:00 2001 From: Eric Anholt <eric@anholt.net> Date: Wed, 20 Jun 2018 17:17:03 -0700 Subject: [PATCH 0595/1506] drm/v3d: Define the fourcc modifier for the Broadcom UIF format. This will be used by Mesa, and potentially other drivers in the future, to describe tiled buffers. Signed-off-by: Eric Anholt <eric@anholt.net> Link: https://patchwork.freedesktop.org/patch/msgid/20180621001703.13522-1-eric@anholt.net Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch> --- include/uapi/drm/drm_fourcc.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h index 64bf67abff7e3..d5e52350a3aae 100644 --- a/include/uapi/drm/drm_fourcc.h +++ b/include/uapi/drm/drm_fourcc.h @@ -464,6 +464,27 @@ extern "C" { #define DRM_FORMAT_MOD_BROADCOM_SAND256 \ DRM_FORMAT_MOD_BROADCOM_SAND256_COL_HEIGHT(0) +/* Broadcom UIF format + * + * This is the common format for the current Broadcom multimedia + * blocks, including V3D 3.x and newer, newer video codecs, and + * displays. + * + * The image consists of utiles (64b blocks), UIF blocks (2x2 utiles), + * and macroblocks (4x4 UIF blocks). Those 4x4 UIF block groups are + * stored in columns, with padding between the columns to ensure that + * moving from one column to the next doesn't hit the same SDRAM page + * bank. + * + * To calculate the padding, it is assumed that each hardware block + * and the software driving it knows the platform's SDRAM page size, + * number of banks, and XOR address, and that it's identical between + * all blocks using the format. This tiling modifier will use XOR as + * necessary to reduce the padding. If a hardware block can't do XOR, + * the assumption is that a no-XOR tiling modifier will be created. + */ +#define DRM_FORMAT_MOD_BROADCOM_UIF fourcc_mod_code(BROADCOM, 6) + #if defined(__cplusplus) } #endif -- GitLab From 491657a915601febfb9d0c253d843124438ae35d Mon Sep 17 00:00:00 2001 From: Eric Anholt <eric@anholt.net> Date: Thu, 21 Jun 2018 16:17:59 -0700 Subject: [PATCH 0596/1506] drm/vc4: Make DSI call into the bridge after the DSI link is enabled. This allows panels or bridges that need to send DSI commands during pre_enable() to successfully send them. We delay DISP0 (aka the actual display) enabling until after pre_enable so that pixels aren't streaming before then. v2: Just clear out the encoder->bridge value to disable the midlayer calls (idea by Andrzej Hajda). Signed-off-by: Eric Anholt <eric@anholt.net> Cc: Andrzej Hajda <a.hajda@samsung.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180621231759.29604-1-eric@anholt.net Reviewed-by: Andrzej Hajda <a.hajda@samsung.com> --- drivers/gpu/drm/vc4/vc4_dsi.c | 42 ++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c index 8aa8978351185..9c8e89372d1c0 100644 --- a/drivers/gpu/drm/vc4/vc4_dsi.c +++ b/drivers/gpu/drm/vc4/vc4_dsi.c @@ -814,7 +814,9 @@ static void vc4_dsi_encoder_disable(struct drm_encoder *encoder) struct vc4_dsi *dsi = vc4_encoder->dsi; struct device *dev = &dsi->pdev->dev; + drm_bridge_disable(dsi->bridge); vc4_dsi_ulps(dsi, true); + drm_bridge_post_disable(dsi->bridge); clk_disable_unprepare(dsi->pll_phy_clock); clk_disable_unprepare(dsi->escape_clock); @@ -1089,21 +1091,6 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder) /* Display reset sequence timeout */ DSI_PORT_WRITE(PR_TO_CNT, 100000); - if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) { - DSI_PORT_WRITE(DISP0_CTRL, - VC4_SET_FIELD(dsi->divider, - DSI_DISP0_PIX_CLK_DIV) | - VC4_SET_FIELD(dsi->format, DSI_DISP0_PFORMAT) | - VC4_SET_FIELD(DSI_DISP0_LP_STOP_PERFRAME, - DSI_DISP0_LP_STOP_CTRL) | - DSI_DISP0_ST_END | - DSI_DISP0_ENABLE); - } else { - DSI_PORT_WRITE(DISP0_CTRL, - DSI_DISP0_COMMAND_MODE | - DSI_DISP0_ENABLE); - } - /* Set up DISP1 for transferring long command payloads through * the pixfifo. */ @@ -1128,6 +1115,25 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder) vc4_dsi_ulps(dsi, false); + drm_bridge_pre_enable(dsi->bridge); + + if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) { + DSI_PORT_WRITE(DISP0_CTRL, + VC4_SET_FIELD(dsi->divider, + DSI_DISP0_PIX_CLK_DIV) | + VC4_SET_FIELD(dsi->format, DSI_DISP0_PFORMAT) | + VC4_SET_FIELD(DSI_DISP0_LP_STOP_PERFRAME, + DSI_DISP0_LP_STOP_CTRL) | + DSI_DISP0_ST_END | + DSI_DISP0_ENABLE); + } else { + DSI_PORT_WRITE(DISP0_CTRL, + DSI_DISP0_COMMAND_MODE | + DSI_DISP0_ENABLE); + } + + drm_bridge_enable(dsi->bridge); + if (debug_dump_regs) { DRM_INFO("DSI regs after:\n"); vc4_dsi_dump_regs(dsi); @@ -1639,6 +1645,12 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) dev_err(dev, "bridge attach failed: %d\n", ret); return ret; } + /* Disable the atomic helper calls into the bridge. We + * manually call the bridge pre_enable / enable / etc. calls + * from our driver, since we need to sequence them within the + * encoder's enable/disable paths. + */ + dsi->encoder->bridge = NULL; pm_runtime_enable(dev); -- GitLab From 1ea29bbd47cf5640fd67f8bcca1f934aa468c428 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko <michal.wajdeczko@intel.com> Date: Mon, 18 Jun 2018 11:18:20 +0000 Subject: [PATCH 0597/1506] drm/i915/guc: Print CTL params passed to Guc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While debugging we may want to examine params passed to GuC. v2: drop #ifdef DEBUG_GUC - Michal Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com> Cc: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com> Cc: Michel Thierry <michel.thierry@intel.com> Reviewed-by: Michel Thierry <michel.thierry@intel.com> #1 Cc: Michal Winiarski <michal.winiarski@intel.com> Reviewed-by: MichaÅ‚ Winiarski <michal.winiarski@intel.com> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20180618111821.47088-1-michal.wajdeczko@intel.com --- drivers/gpu/drm/i915/intel_guc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c index 53b43bc73c017..e12bd259df172 100644 --- a/drivers/gpu/drm/i915/intel_guc.c +++ b/drivers/gpu/drm/i915/intel_guc.c @@ -351,6 +351,9 @@ void intel_guc_init_params(struct intel_guc *guc) params[GUC_CTL_DEBUG] = guc_ctl_debug_flags(guc); params[GUC_CTL_CTXINFO] = guc_ctl_ctxinfo_flags(guc); + for (i = 0; i < GUC_CTL_MAX_DWORDS; i++) + DRM_DEBUG_DRIVER("param[%2d] = %#x\n", i, params[i]); + /* * All SOFT_SCRATCH registers are in FORCEWAKE_BLITTER domain and * they are power context saved so it's ok to release forcewake -- GitLab From e08015e7d6a4b5395e75cc286ab6400667c63dc0 Mon Sep 17 00:00:00 2001 From: Linus Walleij <linus.walleij@linaro.org> Date: Thu, 21 Jun 2018 20:44:50 +0200 Subject: [PATCH 0598/1506] drm/pl111: Support Nomadik LCDC variant The Nomadik has a variant of the PL110 known as "Color LCD Controller" LCDC. This variant has the same bit ordering as the DRM subsystem (in difference from the other variants) and adds a few bits for the control of 5551, 565 etc in the control register. Notably it also adds a packed RGB888 24BPP mode. We add support by detecting this variant and also adding a small plug-in that will mux the LCDC out if the ASIC happens to be muxed to the other graphics controller (they are mutually exclusive). Reviewed-by: Eric Anholt <eric@anholt.net> Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Link: https://patchwork.freedesktop.org/patch/msgid/20180621184450.25377-1-linus.walleij@linaro.org --- drivers/gpu/drm/pl111/Makefile | 1 + drivers/gpu/drm/pl111/pl111_display.c | 54 ++++++++++++++++++++++----- drivers/gpu/drm/pl111/pl111_drm.h | 5 +++ drivers/gpu/drm/pl111/pl111_drv.c | 44 ++++++++++++++++++++-- drivers/gpu/drm/pl111/pl111_nomadik.c | 36 ++++++++++++++++++ drivers/gpu/drm/pl111/pl111_nomadik.h | 18 +++++++++ 6 files changed, 145 insertions(+), 13 deletions(-) create mode 100644 drivers/gpu/drm/pl111/pl111_nomadik.c create mode 100644 drivers/gpu/drm/pl111/pl111_nomadik.h diff --git a/drivers/gpu/drm/pl111/Makefile b/drivers/gpu/drm/pl111/Makefile index 19a8189dc54f8..0c70f0e91d218 100644 --- a/drivers/gpu/drm/pl111/Makefile +++ b/drivers/gpu/drm/pl111/Makefile @@ -4,6 +4,7 @@ pl111_drm-y += pl111_display.o \ pl111_drv.o pl111_drm-$(CONFIG_ARCH_VEXPRESS) += pl111_vexpress.o +pl111_drm-$(CONFIG_ARCH_NOMADIK) += pl111_nomadik.o pl111_drm-$(CONFIG_DEBUG_FS) += pl111_debugfs.o obj-$(CONFIG_DRM_PL111) += pl111_drm.o diff --git a/drivers/gpu/drm/pl111/pl111_display.c b/drivers/gpu/drm/pl111/pl111_display.c index 19b0d006a54a4..a432eb7ad4454 100644 --- a/drivers/gpu/drm/pl111/pl111_display.c +++ b/drivers/gpu/drm/pl111/pl111_display.c @@ -223,48 +223,84 @@ static void pl111_display_enable(struct drm_simple_display_pipe *pipe, /* Hard-code TFT panel */ cntl = CNTL_LCDEN | CNTL_LCDTFT | CNTL_LCDVCOMP(1); + /* On the ST Micro variant, assume all 24 bits are connected */ + if (priv->variant->st_bitmux_control) + cntl |= CNTL_ST_CDWID_24; - /* Note that the the hardware's format reader takes 'r' from + /* + * Note that the the ARM hardware's format reader takes 'r' from * the low bit, while DRM formats list channels from high bit - * to low bit as you read left to right. + * to low bit as you read left to right. The ST Micro version of + * the PL110 (LCDC) however uses the standard DRM format. */ switch (fb->format->format) { + case DRM_FORMAT_BGR888: + /* Only supported on the ST Micro variant */ + if (priv->variant->st_bitmux_control) + cntl |= CNTL_ST_LCDBPP24_PACKED | CNTL_BGR; + break; + case DRM_FORMAT_RGB888: + /* Only supported on the ST Micro variant */ + if (priv->variant->st_bitmux_control) + cntl |= CNTL_ST_LCDBPP24_PACKED; + break; case DRM_FORMAT_ABGR8888: case DRM_FORMAT_XBGR8888: - cntl |= CNTL_LCDBPP24; + if (priv->variant->st_bitmux_control) + cntl |= CNTL_LCDBPP24 | CNTL_BGR; + else + cntl |= CNTL_LCDBPP24; break; case DRM_FORMAT_ARGB8888: case DRM_FORMAT_XRGB8888: - cntl |= CNTL_LCDBPP24 | CNTL_BGR; + if (priv->variant->st_bitmux_control) + cntl |= CNTL_LCDBPP24; + else + cntl |= CNTL_LCDBPP24 | CNTL_BGR; break; case DRM_FORMAT_BGR565: if (priv->variant->is_pl110) cntl |= CNTL_LCDBPP16; + else if (priv->variant->st_bitmux_control) + cntl |= CNTL_LCDBPP16 | CNTL_ST_1XBPP_565 | CNTL_BGR; else cntl |= CNTL_LCDBPP16_565; break; case DRM_FORMAT_RGB565: if (priv->variant->is_pl110) - cntl |= CNTL_LCDBPP16; + cntl |= CNTL_LCDBPP16 | CNTL_BGR; + else if (priv->variant->st_bitmux_control) + cntl |= CNTL_LCDBPP16 | CNTL_ST_1XBPP_565; else - cntl |= CNTL_LCDBPP16_565; - cntl |= CNTL_BGR; + cntl |= CNTL_LCDBPP16_565 | CNTL_BGR; break; case DRM_FORMAT_ABGR1555: case DRM_FORMAT_XBGR1555: cntl |= CNTL_LCDBPP16; + if (priv->variant->st_bitmux_control) + cntl |= CNTL_ST_1XBPP_5551 | CNTL_BGR; break; case DRM_FORMAT_ARGB1555: case DRM_FORMAT_XRGB1555: - cntl |= CNTL_LCDBPP16 | CNTL_BGR; + cntl |= CNTL_LCDBPP16; + if (priv->variant->st_bitmux_control) + cntl |= CNTL_ST_1XBPP_5551; + else + cntl |= CNTL_BGR; break; case DRM_FORMAT_ABGR4444: case DRM_FORMAT_XBGR4444: cntl |= CNTL_LCDBPP16_444; + if (priv->variant->st_bitmux_control) + cntl |= CNTL_ST_1XBPP_444 | CNTL_BGR; break; case DRM_FORMAT_ARGB4444: case DRM_FORMAT_XRGB4444: - cntl |= CNTL_LCDBPP16_444 | CNTL_BGR; + cntl |= CNTL_LCDBPP16_444; + if (priv->variant->st_bitmux_control) + cntl |= CNTL_ST_1XBPP_444; + else + cntl |= CNTL_BGR; break; default: WARN_ONCE(true, "Unknown FB format 0x%08x\n", diff --git a/drivers/gpu/drm/pl111/pl111_drm.h b/drivers/gpu/drm/pl111/pl111_drm.h index ce4501d0ab481..1aa015ccacefa 100644 --- a/drivers/gpu/drm/pl111/pl111_drm.h +++ b/drivers/gpu/drm/pl111/pl111_drm.h @@ -36,11 +36,14 @@ struct drm_minor; * struct pl111_variant_data - encodes IP differences * @name: the name of this variant * @is_pl110: this is the early PL110 variant + * @is_lcdc: this is the ST Microelectronics Nomadik LCDC variant * @external_bgr: this is the Versatile Pl110 variant with external * BGR/RGB routing * @broken_clockdivider: the clock divider is broken and we need to * use the supplied clock directly * @broken_vblank: the vblank IRQ is broken on this variant + * @st_bitmux_control: this variant is using the ST Micro bitmux + * extensions to the control register * @formats: array of supported pixel formats on this variant * @nformats: the length of the array of supported pixel formats * @fb_bpp: desired bits per pixel on the default framebuffer @@ -48,9 +51,11 @@ struct drm_minor; struct pl111_variant_data { const char *name; bool is_pl110; + bool is_lcdc; bool external_bgr; bool broken_clockdivider; bool broken_vblank; + bool st_bitmux_control; const u32 *formats; unsigned int nformats; unsigned int fb_bpp; diff --git a/drivers/gpu/drm/pl111/pl111_drv.c b/drivers/gpu/drm/pl111/pl111_drv.c index 454ff08046424..054b93689d944 100644 --- a/drivers/gpu/drm/pl111/pl111_drv.c +++ b/drivers/gpu/drm/pl111/pl111_drv.c @@ -75,6 +75,7 @@ #include "pl111_drm.h" #include "pl111_versatile.h" +#include "pl111_nomadik.h" #define DRIVER_DESC "DRM module for PL111" @@ -288,8 +289,8 @@ static int pl111_amba_probe(struct amba_device *amba_dev, priv->memory_bw = 0; } - /* The two variants swap this register */ - if (variant->is_pl110) { + /* The two main variants swap this register */ + if (variant->is_pl110 || variant->is_lcdc) { priv->ienb = CLCD_PL110_IENB; priv->ctrl = CLCD_PL110_CNTL; } else { @@ -308,6 +309,7 @@ static int pl111_amba_probe(struct amba_device *amba_dev, ret = pl111_versatile_init(dev, priv); if (ret) goto dev_unref; + pl111_nomadik_init(dev); /* turn off interrupts before requesting the irq */ writel(0, priv->regs + priv->ienb); @@ -400,16 +402,50 @@ static const struct pl111_variant_data pl111_variant = { .fb_bpp = 32, }; +static const u32 pl110_nomadik_pixel_formats[] = { + DRM_FORMAT_RGB888, + DRM_FORMAT_BGR888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_BGR565, + DRM_FORMAT_RGB565, + DRM_FORMAT_ABGR1555, + DRM_FORMAT_XBGR1555, + DRM_FORMAT_ARGB1555, + DRM_FORMAT_XRGB1555, + DRM_FORMAT_ABGR4444, + DRM_FORMAT_XBGR4444, + DRM_FORMAT_ARGB4444, + DRM_FORMAT_XRGB4444, +}; + +static const struct pl111_variant_data pl110_nomadik_variant = { + .name = "LCDC (PL110 Nomadik)", + .formats = pl110_nomadik_pixel_formats, + .nformats = ARRAY_SIZE(pl110_nomadik_pixel_formats), + .is_lcdc = true, + .st_bitmux_control = true, + .broken_vblank = true, + .fb_bpp = 16, +}; + static const struct amba_id pl111_id_table[] = { { .id = 0x00041110, .mask = 0x000fffff, - .data = (void*)&pl110_variant, + .data = (void *)&pl110_variant, + }, + { + .id = 0x00180110, + .mask = 0x00fffffe, + .data = (void *)&pl110_nomadik_variant, }, { .id = 0x00041111, .mask = 0x000fffff, - .data = (void*)&pl111_variant, + .data = (void *)&pl111_variant, }, {0, 0}, }; diff --git a/drivers/gpu/drm/pl111/pl111_nomadik.c b/drivers/gpu/drm/pl111/pl111_nomadik.c new file mode 100644 index 0000000000000..6f385e59be228 --- /dev/null +++ b/drivers/gpu/drm/pl111/pl111_nomadik.c @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0+ +#include <linux/device.h> +#include <linux/regmap.h> +#include <linux/mfd/syscon.h> +#include <linux/bitops.h> +#include <linux/module.h> +#include "pl111_nomadik.h" + +#define PMU_CTRL_OFFSET 0x0000 +#define PMU_CTRL_LCDNDIF BIT(26) + +void pl111_nomadik_init(struct device *dev) +{ + struct regmap *pmu_regmap; + + /* + * Just bail out of this is not found, we could be running + * multiplatform on something else than Nomadik. + */ + pmu_regmap = + syscon_regmap_lookup_by_compatible("stericsson,nomadik-pmu"); + if (IS_ERR(pmu_regmap)) + return; + + /* + * This bit in the PMU controller multiplexes the two graphics + * blocks found in the Nomadik STn8815. The other one is called + * MDIF (Master Display Interface) and gets muxed out here. + */ + regmap_update_bits(pmu_regmap, + PMU_CTRL_OFFSET, + PMU_CTRL_LCDNDIF, + 0); + dev_info(dev, "set Nomadik PMU mux to CLCD mode\n"); +} +EXPORT_SYMBOL_GPL(pl111_nomadik_init); diff --git a/drivers/gpu/drm/pl111/pl111_nomadik.h b/drivers/gpu/drm/pl111/pl111_nomadik.h new file mode 100644 index 0000000000000..19d663d463533 --- /dev/null +++ b/drivers/gpu/drm/pl111/pl111_nomadik.h @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0+ +#include <linux/device.h> + +#ifndef PL111_NOMADIK_H +#define PL111_NOMADIK_H +#endif + +#ifdef CONFIG_ARCH_NOMADIK + +void pl111_nomadik_init(struct device *dev); + +#else + +static inline void pl111_nomadik_init(struct device *dev) +{ +} + +#endif -- GitLab From 1b48b7202c43e41c9f05d39901567dbcad5dc307 Mon Sep 17 00:00:00 2001 From: Daniel Vetter <daniel.vetter@ffwll.ch> Date: Thu, 3 May 2018 16:25:49 +0200 Subject: [PATCH 0599/1506] dma-fence: remove fill_driver_data callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Noticed while I was typing docs. Entirely unused. v2: Remove reference in @timeline_value_str too. While at it clarify why timeline_value_str has a fence parameter - we don't have an explicit timeline structure unfortunately. Cc: Eric Anholt <eric@anholt.net> Reviewed-by: Eric Anholt <eric@anholt.net> Reviewed-by: Christian König <christian.koenig@amd.com> (v1) Cc: Christian König <christian.koenig@amd.com> (v1) Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180503142603.28513-2-daniel.vetter@ffwll.ch --- include/linux/dma-fence.h | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/include/linux/dma-fence.h b/include/linux/dma-fence.h index eb9b05aa5aea1..111aefe1c9564 100644 --- a/include/linux/dma-fence.h +++ b/include/linux/dma-fence.h @@ -217,17 +217,6 @@ struct dma_fence_ops { */ void (*release)(struct dma_fence *fence); - /** - * @fill_driver_data: - * - * Callback to fill in free-form debug info. - * - * Returns amount of bytes filled, or negative error on failure. - * - * This callback is optional. - */ - int (*fill_driver_data)(struct dma_fence *fence, void *data, int size); - /** * @fence_value_str: * @@ -242,8 +231,9 @@ struct dma_fence_ops { * @timeline_value_str: * * Fills in the current value of the timeline as a string, like the - * sequence number. This should match what @fill_driver_data prints for - * the most recently signalled fence (assuming no delayed signalling). + * sequence number. Note that the specific fence passed to this function + * should not matter, drivers should only use it to look up the + * corresponding timeline structures. */ void (*timeline_value_str)(struct dma_fence *fence, char *str, int size); -- GitLab From c701317a3eb8c012364a8d468f20eabf6df1ad77 Mon Sep 17 00:00:00 2001 From: Daniel Vetter <daniel.vetter@ffwll.ch> Date: Fri, 4 May 2018 16:10:34 +0200 Subject: [PATCH 0600/1506] dma-fence: Make ->enable_signaling optional MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Many drivers have a trivial implementation for ->enable_signaling. Let's make it optional by assuming that signalling is already available when the callback isn't present. v2: Don't do the trick to set the ENABLE_SIGNAL_BIT unconditionally, it results in an expensive spinlock take for everyone. Instead just check if the callback is present. Suggested by Maarten. Also move misplaced kerneldoc hunk to the right patch. Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Reviewed-by: Christian König <christian.koenig@amd.com> (v1) Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com> Cc: Sumit Semwal <sumit.semwal@linaro.org> Cc: Gustavo Padovan <gustavo@padovan.org> Cc: linux-media@vger.kernel.org Cc: linaro-mm-sig@lists.linaro.org Link: https://patchwork.freedesktop.org/patch/msgid/20180504141034.27727-1-daniel.vetter@ffwll.ch --- drivers/dma-buf/dma-fence.c | 9 +++++---- include/linux/dma-fence.h | 3 ++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c index 4edb9fd3cf479..dd01a1720be99 100644 --- a/drivers/dma-buf/dma-fence.c +++ b/drivers/dma-buf/dma-fence.c @@ -200,7 +200,8 @@ void dma_fence_enable_sw_signaling(struct dma_fence *fence) if (!test_and_set_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, &fence->flags) && - !test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) { + !test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags) && + fence->ops->enable_signaling) { trace_dma_fence_enable_signal(fence); spin_lock_irqsave(fence->lock, flags); @@ -260,7 +261,7 @@ int dma_fence_add_callback(struct dma_fence *fence, struct dma_fence_cb *cb, if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) ret = -ENOENT; - else if (!was_set) { + else if (!was_set && fence->ops->enable_signaling) { trace_dma_fence_enable_signal(fence); if (!fence->ops->enable_signaling(fence)) { @@ -388,7 +389,7 @@ dma_fence_default_wait(struct dma_fence *fence, bool intr, signed long timeout) if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) goto out; - if (!was_set) { + if (!was_set && fence->ops->enable_signaling) { trace_dma_fence_enable_signal(fence); if (!fence->ops->enable_signaling(fence)) { @@ -560,7 +561,7 @@ dma_fence_init(struct dma_fence *fence, const struct dma_fence_ops *ops, spinlock_t *lock, u64 context, unsigned seqno) { BUG_ON(!lock); - BUG_ON(!ops || !ops->wait || !ops->enable_signaling || + BUG_ON(!ops || !ops->wait || !ops->get_driver_name || !ops->get_timeline_name); kref_init(&fence->refcount); diff --git a/include/linux/dma-fence.h b/include/linux/dma-fence.h index 111aefe1c9564..c053d19e1e248 100644 --- a/include/linux/dma-fence.h +++ b/include/linux/dma-fence.h @@ -166,7 +166,8 @@ struct dma_fence_ops { * released when the fence is signalled (through e.g. the interrupt * handler). * - * This callback is mandatory. + * This callback is optional. If this callback is not present, then the + * driver must always have signaling enabled. */ bool (*enable_signaling)(struct dma_fence *fence); -- GitLab From 796422f227eef662256dcf74f609abd48cfd1cc9 Mon Sep 17 00:00:00 2001 From: Daniel Vetter <daniel.vetter@ffwll.ch> Date: Thu, 3 May 2018 16:25:51 +0200 Subject: [PATCH 0601/1506] dma-fence: Allow wait_any_timeout for all fences MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When this was introduced in commit a519435a96597d8cd96123246fea4ae5a6c90b02 Author: Christian König <christian.koenig@amd.com> Date: Tue Oct 20 16:34:16 2015 +0200 dma-buf/fence: add fence_wait_any_timeout function v2 there was a restriction added that this only works if the dma-fence uses the dma_fence_default_wait hook. Which works for amdgpu, which is the only caller. Well, until you share some buffers with e.g. i915, then you get an -EINVAL. But there's really no reason for this, because all drivers must support callbacks. The special ->wait hook is only as an optimization; if the driver needs to create a worker thread for an active callback, then it can avoid to do that if it knows that there's a process context available already. So ->wait is just an optimization, just using the logic in dma_fence_default_wait() should work for all drivers. Let's remove this restriction. Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com> Cc: Sumit Semwal <sumit.semwal@linaro.org> Cc: Gustavo Padovan <gustavo@padovan.org> Cc: linux-media@vger.kernel.org Cc: linaro-mm-sig@lists.linaro.org Cc: Christian König <christian.koenig@amd.com> Cc: Alex Deucher <alexander.deucher@amd.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180503142603.28513-4-daniel.vetter@ffwll.ch --- drivers/dma-buf/dma-fence.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c index dd01a1720be99..ea343f9921127 100644 --- a/drivers/dma-buf/dma-fence.c +++ b/drivers/dma-buf/dma-fence.c @@ -497,11 +497,6 @@ dma_fence_wait_any_timeout(struct dma_fence **fences, uint32_t count, for (i = 0; i < count; ++i) { struct dma_fence *fence = fences[i]; - if (fence->ops->wait != dma_fence_default_wait) { - ret = -EINVAL; - goto fence_rm_cb; - } - cb[i].task = current; if (dma_fence_add_callback(fence, &cb[i].base, dma_fence_default_wait_cb)) { -- GitLab From e67005e59a74613c2d5879f63eef70e6267bb452 Mon Sep 17 00:00:00 2001 From: Jani Nikula <jani.nikula@intel.com> Date: Fri, 29 Jun 2018 13:20:39 +0300 Subject: [PATCH 0602/1506] drm/i915: abstract and document register picking macros Try to describe what the pick variants do, and which to prefer. No functional changes. Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180629102039.2435-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index c30cfcd907546..7dc7746829225 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -139,19 +139,35 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) return !i915_mmio_reg_equal(reg, INVALID_MMIO_REG); } +/* + * Given the first two numbers __a and __b of arbitrarily many evenly spaced + * numbers, pick the 0-based __index'th value. + * + * Always prefer this over _PICK() if the numbers are evenly spaced. + */ +#define _PICK_EVEN(__index, __a, __b) ((__a) + (__index) * ((__b) - (__a))) + +/* + * Given the arbitrary numbers in varargs, pick the 0-based __index'th number. + * + * Always prefer _PICK_EVEN() over this if the numbers are evenly spaced. + */ #define _PICK(__index, ...) (((const u32 []){ __VA_ARGS__ })[__index]) -#define _PIPE(pipe, a, b) ((a) + (pipe) * ((b) - (a))) +/* + * Named helper wrappers around _PICK_EVEN() and _PICK(). + */ +#define _PIPE(pipe, a, b) _PICK_EVEN(pipe, a, b) #define _MMIO_PIPE(pipe, a, b) _MMIO(_PIPE(pipe, a, b)) -#define _PLANE(plane, a, b) _PIPE(plane, a, b) +#define _PLANE(plane, a, b) _PICK_EVEN(plane, a, b) #define _MMIO_PLANE(plane, a, b) _MMIO_PIPE(plane, a, b) -#define _TRANS(tran, a, b) ((a) + (tran) * ((b) - (a))) +#define _TRANS(tran, a, b) _PICK_EVEN(tran, a, b) #define _MMIO_TRANS(tran, a, b) _MMIO(_TRANS(tran, a, b)) -#define _PORT(port, a, b) ((a) + (port) * ((b) - (a))) +#define _PORT(port, a, b) _PICK_EVEN(port, a, b) #define _MMIO_PORT(port, a, b) _MMIO(_PORT(port, a, b)) #define _MMIO_PIPE3(pipe, a, b, c) _MMIO(_PICK(pipe, a, b, c)) #define _MMIO_PORT3(pipe, a, b, c) _MMIO(_PICK(pipe, a, b, c)) -#define _PLL(pll, a, b) ((a) + (pll) * ((b) - (a))) +#define _PLL(pll, a, b) _PICK_EVEN(pll, a, b) #define _MMIO_PLL(pll, a, b) _MMIO(_PLL(pll, a, b)) #define _PHY3(phy, ...) _PICK(phy, __VA_ARGS__) #define _MMIO_PHY3(phy, a, b, c) _MMIO(_PHY3(phy, a, b, c)) @@ -6874,7 +6890,7 @@ enum { #define _PS_ECC_STAT_2B 0x68AD0 #define _PS_ECC_STAT_1C 0x691D0 -#define _ID(id, a, b) ((a) + (id) * ((b) - (a))) +#define _ID(id, a, b) _PICK_EVEN(id, a, b) #define SKL_PS_CTRL(pipe, id) _MMIO_PIPE(pipe, \ _ID(id, _PS_1A_CTRL, _PS_2A_CTRL), \ _ID(id, _PS_1B_CTRL, _PS_2B_CTRL)) -- GitLab From e35a2f9aee31fb9e85ebbf4820481ce3f5e94db2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Tue, 26 Jun 2018 23:41:44 +0300 Subject: [PATCH 0603/1506] drm/atomic-helper: Use old/new state in drm_atomic_helper_commit_planes_on_crtc() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update drm_atomic_helper_commit_planes_on_crtc() to use explicit old/new states instead of relying on obj->state. Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180626204144.14769-1-ville.syrjala@linux.intel.com Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> --- drivers/gpu/drm/drm_atomic_helper.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 17baf5057132e..4f487ceffe684 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -2342,11 +2342,13 @@ drm_atomic_helper_commit_planes_on_crtc(struct drm_crtc_state *old_crtc_state) const struct drm_crtc_helper_funcs *crtc_funcs; struct drm_crtc *crtc = old_crtc_state->crtc; struct drm_atomic_state *old_state = old_crtc_state->state; + struct drm_crtc_state *new_crtc_state = + drm_atomic_get_new_crtc_state(old_state, crtc); struct drm_plane *plane; unsigned plane_mask; plane_mask = old_crtc_state->plane_mask; - plane_mask |= crtc->state->plane_mask; + plane_mask |= new_crtc_state->plane_mask; crtc_funcs = crtc->helper_private; if (crtc_funcs && crtc_funcs->atomic_begin) @@ -2355,6 +2357,8 @@ drm_atomic_helper_commit_planes_on_crtc(struct drm_crtc_state *old_crtc_state) drm_for_each_plane_mask(plane, crtc->dev, plane_mask) { struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(old_state, plane); + struct drm_plane_state *new_plane_state = + drm_atomic_get_new_plane_state(old_state, plane); const struct drm_plane_helper_funcs *plane_funcs; plane_funcs = plane->helper_private; @@ -2362,13 +2366,14 @@ drm_atomic_helper_commit_planes_on_crtc(struct drm_crtc_state *old_crtc_state) if (!old_plane_state || !plane_funcs) continue; - WARN_ON(plane->state->crtc && plane->state->crtc != crtc); + WARN_ON(new_plane_state->crtc && + new_plane_state->crtc != crtc); - if (drm_atomic_plane_disabling(old_plane_state, plane->state) && + if (drm_atomic_plane_disabling(old_plane_state, new_plane_state) && plane_funcs->atomic_disable) plane_funcs->atomic_disable(plane, old_plane_state); - else if (plane->state->crtc || - drm_atomic_plane_disabling(old_plane_state, plane->state)) + else if (new_plane_state->crtc || + drm_atomic_plane_disabling(old_plane_state, new_plane_state)) plane_funcs->atomic_update(plane, old_plane_state); } -- GitLab From 62f77ad0969594ee428043523bf28329df191b39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Tue, 26 Jun 2018 22:47:07 +0300 Subject: [PATCH 0604/1506] drm: Add drm_plane_mask() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add drm_plane_mask() which returns the 1<<index for the plane. We already have an identical drm_crtc_mask() for crtcs. Mostly performed with coccinelle: @@ @@ - (1<<drm_plane_index( + drm_plane_mask( ...) - ) @@ @@ - 1<<drm_plane_index( + drm_plane_mask( ...) @@ @@ - BIT(drm_plane_index( + drm_plane_mask( ...) - ) Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180626194716.12522-1-ville.syrjala@linux.intel.com Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> --- drivers/gpu/drm/drm_atomic.c | 4 ++-- drivers/gpu/drm/drm_framebuffer.c | 2 +- drivers/gpu/drm/drm_simple_kms_helper.c | 2 +- include/drm/drm_plane.h | 14 ++++++++++++-- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 178842380f758..684c9d3a1d6cb 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1581,7 +1581,7 @@ drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state, if (WARN_ON(IS_ERR(crtc_state))) return PTR_ERR(crtc_state); - crtc_state->plane_mask &= ~(1 << drm_plane_index(plane)); + crtc_state->plane_mask &= ~drm_plane_mask(plane); } plane_state->crtc = crtc; @@ -1591,7 +1591,7 @@ drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state, crtc); if (IS_ERR(crtc_state)) return PTR_ERR(crtc_state); - crtc_state->plane_mask |= (1 << drm_plane_index(plane)); + crtc_state->plane_mask |= drm_plane_mask(plane); } if (crtc) diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index ed90974a452a1..781af1d42d766 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -847,7 +847,7 @@ static int atomic_remove_fb(struct drm_framebuffer *fb) if (ret) goto unlock; - plane_mask |= BIT(drm_plane_index(plane)); + plane_mask |= drm_plane_mask(plane); } /* This list is only filled when disable_crtcs is set. */ diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c index 7a00455ca568b..9d87961da1dbc 100644 --- a/drivers/gpu/drm/drm_simple_kms_helper.c +++ b/drivers/gpu/drm/drm_simple_kms_helper.c @@ -52,7 +52,7 @@ static int drm_simple_kms_crtc_check(struct drm_crtc *crtc, struct drm_crtc_state *state) { bool has_primary = state->plane_mask & - BIT(drm_plane_index(crtc->primary)); + drm_plane_mask(crtc->primary); /* We always want to have an active plane with an active CRTC */ if (has_primary != state->enable) diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index 7d4d6c7f0afdb..cee9dfaaa740e 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -639,10 +639,20 @@ void drm_plane_cleanup(struct drm_plane *plane); * Given a registered plane, return the index of that plane within a DRM * device's list of planes. */ -static inline unsigned int drm_plane_index(struct drm_plane *plane) +static inline unsigned int drm_plane_index(const struct drm_plane *plane) { return plane->index; } + +/** + * drm_plane_mask - find the mask of a registered plane + * @plane: plane to find mask for + */ +static inline u32 drm_plane_mask(const struct drm_plane *plane) +{ + return 1 << drm_plane_index(plane); +} + struct drm_plane * drm_plane_from_index(struct drm_device *dev, int idx); void drm_plane_force_disable(struct drm_plane *plane); @@ -678,7 +688,7 @@ static inline struct drm_plane *drm_plane_find(struct drm_device *dev, */ #define drm_for_each_plane_mask(plane, dev, plane_mask) \ list_for_each_entry((plane), &(dev)->mode_config.plane_list, head) \ - for_each_if ((plane_mask) & (1 << drm_plane_index(plane))) + for_each_if ((plane_mask) & drm_plane_mask(plane)) /** * drm_for_each_legacy_plane - iterate over all planes for legacy userspace -- GitLab From 6a52193bd0dd683607793bea0caf6be94b32b333 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Tue, 26 Jun 2018 22:47:08 +0300 Subject: [PATCH 0605/1506] drm: Use drm_crtc_mask() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use drm_crtc_mask() where appropriate. Mostly performed with coccinelle: @@ @@ - (1<<drm_crtc_index( + drm_crtc_mask( ...) - ) @@ @@ - 1<<drm_crtc_index( + drm_crtc_mask( ...) @@ @@ - BIT(drm_crtc_index( + drm_crtc_mask( ...) - ) Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180626194716.12522-2-ville.syrjala@linux.intel.com Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> --- drivers/gpu/drm/drm_crtc.c | 4 ++-- drivers/gpu/drm/drm_simple_kms_helper.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index f45e7a8d4acd6..c762e75a2d94e 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -329,9 +329,9 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, crtc->primary = primary; crtc->cursor = cursor; if (primary && !primary->possible_crtcs) - primary->possible_crtcs = 1 << drm_crtc_index(crtc); + primary->possible_crtcs = drm_crtc_mask(crtc); if (cursor && !cursor->possible_crtcs) - cursor->possible_crtcs = 1 << drm_crtc_index(crtc); + cursor->possible_crtcs = drm_crtc_mask(crtc); ret = drm_crtc_crc_init(crtc); if (ret) { diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c index 9d87961da1dbc..b72fcf1e9605c 100644 --- a/drivers/gpu/drm/drm_simple_kms_helper.c +++ b/drivers/gpu/drm/drm_simple_kms_helper.c @@ -281,7 +281,7 @@ int drm_simple_display_pipe_init(struct drm_device *dev, if (ret) return ret; - encoder->possible_crtcs = 1 << drm_crtc_index(crtc); + encoder->possible_crtcs = drm_crtc_mask(crtc); ret = drm_encoder_init(dev, encoder, &drm_simple_kms_encoder_funcs, DRM_MODE_ENCODER_NONE, NULL); if (ret || !connector) -- GitLab From 6f3be036da5cf6b192966ebea250cf9c8b1fd4a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Tue, 26 Jun 2018 22:47:09 +0300 Subject: [PATCH 0606/1506] drm: Add drm_encoder_mask() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add drm_encoder_mask() which returns the 1<<index for the encoder. We already have an identical drm_crtc_mask() for crtcs. Mostly performed with coccinelle: @@ @@ - (1<<drm_encoder_index( + drm_encoder_mask( ...) - ) @@ @@ - 1<<drm_encoder_index( + drm_encoder_mask( ...) @@ @@ - BIT(drm_encoder_index( + drm_encoder_mask( ...) - ) Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180626194716.12522-3-ville.syrjala@linux.intel.com Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> --- drivers/gpu/drm/drm_atomic_helper.c | 10 +++++----- include/drm/drm_encoder.h | 16 ++++++++++++++-- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 4f487ceffe684..8008a7de2e100 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -121,7 +121,7 @@ static int handle_conflicting_encoders(struct drm_atomic_state *state, new_encoder = drm_atomic_helper_best_encoder(connector); if (new_encoder) { - if (encoder_mask & (1 << drm_encoder_index(new_encoder))) { + if (encoder_mask & drm_encoder_mask(new_encoder)) { DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] on [CONNECTOR:%d:%s] already assigned\n", new_encoder->base.id, new_encoder->name, connector->base.id, connector->name); @@ -129,7 +129,7 @@ static int handle_conflicting_encoders(struct drm_atomic_state *state, return -EINVAL; } - encoder_mask |= 1 << drm_encoder_index(new_encoder); + encoder_mask |= drm_encoder_mask(new_encoder); } } @@ -155,7 +155,7 @@ static int handle_conflicting_encoders(struct drm_atomic_state *state, continue; encoder = connector->state->best_encoder; - if (!encoder || !(encoder_mask & (1 << drm_encoder_index(encoder)))) + if (!encoder || !(encoder_mask & drm_encoder_mask(encoder))) continue; if (!disable_conflicting_encoders) { @@ -223,7 +223,7 @@ set_best_encoder(struct drm_atomic_state *state, crtc_state = drm_atomic_get_new_crtc_state(state, crtc); crtc_state->encoder_mask &= - ~(1 << drm_encoder_index(conn_state->best_encoder)); + ~drm_encoder_mask(conn_state->best_encoder); } } @@ -234,7 +234,7 @@ set_best_encoder(struct drm_atomic_state *state, crtc_state = drm_atomic_get_new_crtc_state(state, crtc); crtc_state->encoder_mask |= - 1 << drm_encoder_index(encoder); + drm_encoder_mask(encoder); } } diff --git a/include/drm/drm_encoder.h b/include/drm/drm_encoder.h index fb299696c7c41..4f597c0730b48 100644 --- a/include/drm/drm_encoder.h +++ b/include/drm/drm_encoder.h @@ -191,11 +191,23 @@ int drm_encoder_init(struct drm_device *dev, * Given a registered encoder, return the index of that encoder within a DRM * device's list of encoders. */ -static inline unsigned int drm_encoder_index(struct drm_encoder *encoder) +static inline unsigned int drm_encoder_index(const struct drm_encoder *encoder) { return encoder->index; } +/** + * drm_encoder_mask - find the mask of a registered ENCODER + * @encoder: encoder to find mask for + * + * Given a registered encoder, return the mask bit of that encoder for an + * encoder's possible_clones field. + */ +static inline u32 drm_encoder_mask(const struct drm_encoder *encoder) +{ + return 1 << drm_encoder_index(encoder); +} + /** * drm_encoder_crtc_ok - can a given crtc drive a given encoder? * @encoder: encoder to test @@ -241,7 +253,7 @@ void drm_encoder_cleanup(struct drm_encoder *encoder); */ #define drm_for_each_encoder_mask(encoder, dev, encoder_mask) \ list_for_each_entry((encoder), &(dev)->mode_config.encoder_list, head) \ - for_each_if ((encoder_mask) & (1 << drm_encoder_index(encoder))) + for_each_if ((encoder_mask) & drm_encoder_mask(encoder)) /** * drm_for_each_encoder - iterate over all encoders -- GitLab From 737057321f3c2d30b98fa8006b7af1869c32a68b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Tue, 26 Jun 2018 22:47:10 +0300 Subject: [PATCH 0607/1506] drm: Add drm_connector_mask() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add drm_connector_mask() which returns the 1<<index for the connector. We already have an identical drm_crtc_mask() for crtcs. Mostly performed with coccinelle: @@ @@ - (1<<drm_connector_index( + drm_connector_mask( ...) - ) @@ @@ - 1<<drm_connector_index( + drm_connector_mask( ...) @@ @@ - BIT(drm_connector_index( + drm_connector_mask( ...) - ) Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180626194716.12522-4-ville.syrjala@linux.intel.com Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> --- drivers/gpu/drm/drm_atomic.c | 6 +++--- include/drm/drm_connector.h | 8 +++++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 684c9d3a1d6cb..d5cefb1cb2a24 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1700,7 +1700,7 @@ drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state, conn_state->crtc); crtc_state->connector_mask &= - ~(1 << drm_connector_index(conn_state->connector)); + ~drm_connector_mask(conn_state->connector); drm_connector_put(conn_state->connector); conn_state->crtc = NULL; @@ -1712,7 +1712,7 @@ drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state, return PTR_ERR(crtc_state); crtc_state->connector_mask |= - 1 << drm_connector_index(conn_state->connector); + drm_connector_mask(conn_state->connector); drm_connector_get(conn_state->connector); conn_state->crtc = crtc; @@ -1839,7 +1839,7 @@ drm_atomic_add_affected_connectors(struct drm_atomic_state *state, */ drm_connector_list_iter_begin(state->dev, &conn_iter); drm_for_each_connector_iter(connector, &conn_iter) { - if (!(crtc_state->connector_mask & (1 << drm_connector_index(connector)))) + if (!(crtc_state->connector_mask & drm_connector_mask(connector))) continue; conn_state = drm_atomic_get_connector_state(state, connector); diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 14ab58ade87f6..bf0f0f0786d30 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -1030,11 +1030,17 @@ int drm_mode_connector_attach_encoder(struct drm_connector *connector, struct drm_encoder *encoder); void drm_connector_cleanup(struct drm_connector *connector); -static inline unsigned drm_connector_index(struct drm_connector *connector) + +static inline unsigned int drm_connector_index(const struct drm_connector *connector) { return connector->index; } +static inline u32 drm_connector_mask(const struct drm_connector *connector) +{ + return 1 << connector->index; +} + /** * drm_connector_lookup - lookup connector object * @dev: DRM device -- GitLab From 40560e26dc45e53ae05cce61804a31367f36a5e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Tue, 26 Jun 2018 22:47:11 +0300 Subject: [PATCH 0608/1506] drm/i915: Use drm_plane_mask() & co. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use drm_{plane,crtc,encoder,connector}_mask() where appropriate. Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180626194716.12522-5-ville.syrjala@linux.intel.com Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> --- drivers/gpu/drm/i915/intel_display.c | 14 +++++++------- drivers/gpu/drm/i915/intel_display.h | 4 ++-- drivers/gpu/drm/i915/intel_dpll_mgr.c | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2c8fef3ede543..694a4703042fe 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2756,10 +2756,10 @@ intel_set_plane_visible(struct intel_crtc_state *crtc_state, /* FIXME pre-g4x don't work like this */ if (visible) { - crtc_state->base.plane_mask |= BIT(drm_plane_index(&plane->base)); + crtc_state->base.plane_mask |= drm_plane_mask(&plane->base); crtc_state->active_planes |= BIT(plane->id); } else { - crtc_state->base.plane_mask &= ~BIT(drm_plane_index(&plane->base)); + crtc_state->base.plane_mask &= ~drm_plane_mask(&plane->base); crtc_state->active_planes &= ~BIT(plane->id); } @@ -11884,7 +11884,7 @@ verify_single_dpll_state(struct drm_i915_private *dev_priv, struct drm_crtc_state *new_state) { struct intel_dpll_hw_state dpll_hw_state; - unsigned crtc_mask; + unsigned int crtc_mask; bool active; memset(&dpll_hw_state, 0, sizeof(dpll_hw_state)); @@ -11911,7 +11911,7 @@ verify_single_dpll_state(struct drm_i915_private *dev_priv, return; } - crtc_mask = 1 << drm_crtc_index(crtc); + crtc_mask = drm_crtc_mask(crtc); if (new_state->active) I915_STATE_WARN(!(pll->active_mask & crtc_mask), @@ -11946,7 +11946,7 @@ verify_shared_dpll_state(struct drm_device *dev, struct drm_crtc *crtc, if (old_state->shared_dpll && old_state->shared_dpll != new_state->shared_dpll) { - unsigned crtc_mask = 1 << drm_crtc_index(crtc); + unsigned int crtc_mask = drm_crtc_mask(crtc); struct intel_shared_dpll *pll = old_state->shared_dpll; I915_STATE_WARN(pll->active_mask & crtc_mask, @@ -15608,9 +15608,9 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) * rely on the connector_mask being accurate. */ encoder->base.crtc->state->connector_mask |= - 1 << drm_connector_index(&connector->base); + drm_connector_mask(&connector->base); encoder->base.crtc->state->encoder_mask |= - 1 << drm_encoder_index(&encoder->base); + drm_encoder_mask(&encoder->base); } } else { diff --git a/drivers/gpu/drm/i915/intel_display.h b/drivers/gpu/drm/i915/intel_display.h index dfb02da73ac86..dd30cae5eb002 100644 --- a/drivers/gpu/drm/i915/intel_display.h +++ b/drivers/gpu/drm/i915/intel_display.h @@ -261,7 +261,7 @@ struct intel_link_m_n { &(dev)->mode_config.plane_list, \ base.head) \ for_each_if((plane_mask) & \ - BIT(drm_plane_index(&intel_plane->base))) + drm_plane_mask(&intel_plane->base))) #define for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) \ list_for_each_entry(intel_plane, \ @@ -278,7 +278,7 @@ struct intel_link_m_n { list_for_each_entry(intel_crtc, \ &(dev)->mode_config.crtc_list, \ base.head) \ - for_each_if((crtc_mask) & BIT(drm_crtc_index(&intel_crtc->base))) + for_each_if((crtc_mask) & drm_crtc_mask(&intel_crtc->base)) #define for_each_intel_encoder(dev, intel_encoder) \ list_for_each_entry(intel_encoder, \ diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c index 132fe63e042af..156f8e4cbe4c2 100644 --- a/drivers/gpu/drm/i915/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c @@ -163,8 +163,8 @@ void intel_enable_shared_dpll(struct intel_crtc *crtc) struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = to_i915(dev); struct intel_shared_dpll *pll = crtc->config->shared_dpll; - unsigned crtc_mask = 1 << drm_crtc_index(&crtc->base); - unsigned old_mask; + unsigned int crtc_mask = drm_crtc_mask(&crtc->base); + unsigned int old_mask; if (WARN_ON(pll == NULL)) return; @@ -207,7 +207,7 @@ void intel_disable_shared_dpll(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); struct intel_shared_dpll *pll = crtc->config->shared_dpll; - unsigned crtc_mask = 1 << drm_crtc_index(&crtc->base); + unsigned int crtc_mask = drm_crtc_mask(&crtc->base); /* PCH only available on ILK+ */ if (INTEL_GEN(dev_priv) < 5) -- GitLab From 2d4569fd8d8ee13a8556ed3dd8b2cd1dc45fd8bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Tue, 26 Jun 2018 22:47:12 +0300 Subject: [PATCH 0609/1506] drm/imx: Use drm_plane_mask() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use drm_plane_mask() where appropriate. Cc: Philipp Zabel <p.zabel@pengutronix.de> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180626194716.12522-6-ville.syrjala@linux.intel.com Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Acked-by: Philipp Zabel <p.zabel@pengutronix.de> --- drivers/gpu/drm/imx/ipuv3-crtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c index e83af0f2be869..21d002859ae0c 100644 --- a/drivers/gpu/drm/imx/ipuv3-crtc.c +++ b/drivers/gpu/drm/imx/ipuv3-crtc.c @@ -213,7 +213,7 @@ static bool ipu_crtc_mode_fixup(struct drm_crtc *crtc, static int ipu_crtc_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state) { - u32 primary_plane_mask = 1 << drm_plane_index(crtc->primary); + u32 primary_plane_mask = drm_plane_mask(crtc->primary); if (state->active && (primary_plane_mask & state->plane_mask) == 0) return -EINVAL; -- GitLab From dbf8f9e40e6f5fc39e2e6c4c8a392fe99189c4d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Tue, 26 Jun 2018 22:47:14 +0300 Subject: [PATCH 0610/1506] drm/sun4i: Use drm_crtc_mask() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use drm_crtc_mask() where appropriate. Cc: Maxime Ripard <maxime.ripard@bootlin.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180626194716.12522-8-ville.syrjala@linux.intel.com Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Acked-by: Maxime Ripard <maxime.ripard@bootlin.com> --- drivers/gpu/drm/sun4i/sun4i_crtc.c | 2 +- drivers/gpu/drm/sun4i/sun4i_lvds.c | 2 +- drivers/gpu/drm/sun4i/sun4i_rgb.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c index 2d7c57406715a..3eedf335a935c 100644 --- a/drivers/gpu/drm/sun4i/sun4i_crtc.c +++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c @@ -242,7 +242,7 @@ struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm, /* Set possible_crtcs to this crtc for overlay planes */ for (i = 0; planes[i]; i++) { - uint32_t possible_crtcs = BIT(drm_crtc_index(&scrtc->crtc)); + uint32_t possible_crtcs = drm_crtc_mask(&scrtc->crtc); struct drm_plane *plane = planes[i]; if (plane->type == DRM_PLANE_TYPE_OVERLAY) diff --git a/drivers/gpu/drm/sun4i/sun4i_lvds.c b/drivers/gpu/drm/sun4i/sun4i_lvds.c index be3f14d7746de..a69fe2e1f9d1d 100644 --- a/drivers/gpu/drm/sun4i/sun4i_lvds.c +++ b/drivers/gpu/drm/sun4i/sun4i_lvds.c @@ -136,7 +136,7 @@ int sun4i_lvds_init(struct drm_device *drm, struct sun4i_tcon *tcon) } /* The LVDS encoder can only work with the TCON channel 0 */ - lvds->encoder.possible_crtcs = BIT(drm_crtc_index(&tcon->crtc->crtc)); + lvds->encoder.possible_crtcs = drm_crtc_mask(&tcon->crtc->crtc); if (tcon->panel) { drm_connector_helper_add(&lvds->connector, diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c index f2fa1f210509e..96d21b07f8fca 100644 --- a/drivers/gpu/drm/sun4i/sun4i_rgb.c +++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c @@ -202,7 +202,7 @@ int sun4i_rgb_init(struct drm_device *drm, struct sun4i_tcon *tcon) } /* The RGB encoder can only work with the TCON channel 0 */ - rgb->encoder.possible_crtcs = BIT(drm_crtc_index(&tcon->crtc->crtc)); + rgb->encoder.possible_crtcs = drm_crtc_mask(&tcon->crtc->crtc); if (tcon->panel) { drm_connector_helper_add(&rgb->connector, -- GitLab From c0183a8eae1820173f410dada7e311295e6a8580 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Tue, 26 Jun 2018 22:47:15 +0300 Subject: [PATCH 0611/1506] drm/vc4: Use drm_crtc_mask() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use drm_crtc_mask() where appropriate. Cc: Eric Anholt <eric@anholt.net> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180626194716.12522-9-ville.syrjala@linux.intel.com Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Reviewed-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/vc4/vc4_crtc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index dcadf793ee806..d222358fa8a70 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -1081,7 +1081,7 @@ static int vc4_crtc_bind(struct device *dev, struct device *master, void *data) if (IS_ERR(plane)) continue; - plane->possible_crtcs = 1 << drm_crtc_index(crtc); + plane->possible_crtcs = drm_crtc_mask(crtc); } /* Set up the legacy cursor after overlay initialization, @@ -1090,7 +1090,7 @@ static int vc4_crtc_bind(struct device *dev, struct device *master, void *data) */ cursor_plane = vc4_plane_init(drm, DRM_PLANE_TYPE_CURSOR); if (!IS_ERR(cursor_plane)) { - cursor_plane->possible_crtcs = 1 << drm_crtc_index(crtc); + cursor_plane->possible_crtcs = drm_crtc_mask(crtc); crtc->cursor = cursor_plane; } @@ -1118,7 +1118,7 @@ static int vc4_crtc_bind(struct device *dev, struct device *master, void *data) err_destroy_planes: list_for_each_entry_safe(destroy_plane, temp, &drm->mode_config.plane_list, head) { - if (destroy_plane->possible_crtcs == 1 << drm_crtc_index(crtc)) + if (destroy_plane->possible_crtcs == drm_crtc_mask(crtc)) destroy_plane->funcs->destroy(destroy_plane); } err: -- GitLab From ea632725956d1dd7c4a10aa2449c672bbb22b2cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Tue, 26 Jun 2018 22:47:16 +0300 Subject: [PATCH 0612/1506] drm/vmwgfx: Use drm_plane_mask() & co. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use drm_{plane,connector}_mask() where appropriate. Cc: VMware Graphics <linux-graphics-maintainer@vmware.com> Cc: Sinclair Yeh <syeh@vmware.com> Cc: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180626194716.12522-10-ville.syrjala@linux.intel.com Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 6317672070cdc..bc5fbd39cf9af 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -535,9 +535,9 @@ int vmw_du_crtc_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *new_state) { struct vmw_display_unit *du = vmw_crtc_to_du(new_state->crtc); - int connector_mask = 1 << drm_connector_index(&du->connector); + int connector_mask = drm_connector_mask(&du->connector); bool has_primary = new_state->plane_mask & - BIT(drm_plane_index(crtc->primary)); + drm_plane_mask(crtc->primary); /* We always want to have an active plane with an active CRTC */ if (has_primary != new_state->enable) -- GitLab From 7e7367d3bc6cf27dd7e007e7897fcebfeff1ee8b Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Sat, 30 Jun 2018 10:05:09 +0100 Subject: [PATCH 0613/1506] drm/i915: Try GGTT mmapping whole object as partial If the whole object is already pinned by HW for use as scanout, we will fail to move it to the mappable region and so must resort to using a partial VMA covering the whole object. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=104513 Fixes: aa136d9d72c2 ("drm/i915: Convert partial ggtt vma to full ggtt if it spans the entire object") Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Matthew Auld <matthew.william.auld@gmail.com> Reviewed-by: Matthew Auld <matthew.william.auld@gmail.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180630090509.469-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 28 +++++++++++++++++----------- drivers/gpu/drm/i915/i915_vma.c | 2 +- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 8954db6ab083b..048b722cf27cf 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2006,7 +2006,6 @@ vm_fault_t i915_gem_fault(struct vm_fault *vmf) bool write = !!(vmf->flags & FAULT_FLAG_WRITE); struct i915_vma *vma; pgoff_t page_offset; - unsigned int flags; int ret; /* We don't use vmf->pgoff since that has the fake offset */ @@ -2042,27 +2041,34 @@ vm_fault_t i915_gem_fault(struct vm_fault *vmf) goto err_unlock; } - /* If the object is smaller than a couple of partial vma, it is - * not worth only creating a single partial vma - we may as well - * clear enough space for the full object. - */ - flags = PIN_MAPPABLE; - if (obj->base.size > 2 * MIN_CHUNK_PAGES << PAGE_SHIFT) - flags |= PIN_NONBLOCK | PIN_NONFAULT; /* Now pin it into the GTT as needed */ - vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, flags); + vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, + PIN_MAPPABLE | + PIN_NONBLOCK | + PIN_NONFAULT); if (IS_ERR(vma)) { /* Use a partial view if it is bigger than available space */ struct i915_ggtt_view view = compute_partial_view(obj, page_offset, MIN_CHUNK_PAGES); + unsigned int flags; - /* Userspace is now writing through an untracked VMA, abandon + flags = PIN_MAPPABLE; + if (view.type == I915_GGTT_VIEW_NORMAL) + flags |= PIN_NONBLOCK; /* avoid warnings for pinned */ + + /* + * Userspace is now writing through an untracked VMA, abandon * all hope that the hardware is able to track future writes. */ obj->frontbuffer_ggtt_origin = ORIGIN_CPU; - vma = i915_gem_object_ggtt_pin(obj, &view, 0, 0, PIN_MAPPABLE); + vma = i915_gem_object_ggtt_pin(obj, &view, 0, 0, flags); + if (IS_ERR(vma) && !view.type) { + flags = PIN_MAPPABLE; + view.type = I915_GGTT_VIEW_PARTIAL; + vma = i915_gem_object_ggtt_pin(obj, &view, 0, 0, flags); + } } if (IS_ERR(vma)) { ret = PTR_ERR(vma); diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c index d0e606e9b27a4..de2b6d65e865e 100644 --- a/drivers/gpu/drm/i915/i915_vma.c +++ b/drivers/gpu/drm/i915/i915_vma.c @@ -143,7 +143,7 @@ vma_create(struct drm_i915_gem_object *obj, obj->base.size >> PAGE_SHIFT)); vma->size = view->partial.size; vma->size <<= PAGE_SHIFT; - GEM_BUG_ON(vma->size >= obj->base.size); + GEM_BUG_ON(vma->size > obj->base.size); } else if (view->type == I915_GGTT_VIEW_ROTATED) { vma->size = intel_rotation_info_size(&view->rotated); vma->size <<= PAGE_SHIFT; -- GitLab From 00b062967f1524de25daf6578d9043b0bbe7c208 Mon Sep 17 00:00:00 2001 From: Vathsala Nagaraju <vathsala.nagaraju@intel.com> Date: Wed, 27 Jun 2018 13:38:30 +0530 Subject: [PATCH 0614/1506] drm/i915/psr: Add psr1 live status Prints live state of psr1.Extending the existing PSR2 live state function to cover psr1. Tested on KBL with psr2 and psr1 panel. v2: rebase v3: DK Rename psr2_live_status to psr_source_status. v4: DK Move EDP_PSR_STATUS_STATE_SHIFT below EDP_PSR_STATUS_STATE_MASK. Pass seq to psr_source_status, handle source status prints in psr_source_status. v5: Fixed CI warning messages v6: Remove extra space in the title before the colon.(DK) Rebase. (Jani) v7: Use tabs for indenting the values.(Jani) v8: Addressed dk's review comments. Cc: Rodrigo Vivi <rodrigo.vivi@intel.com> Cc: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Reviewed-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Signed-off-by: Vathsala Nagaraju <vathsala.nagaraju@intel.com> Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/1530086910-15914-1-git-send-email-vathsala.nagaraju@intel.com --- drivers/gpu/drm/i915/i915_debugfs.c | 72 +++++++++++++++++++---------- drivers/gpu/drm/i915/i915_reg.h | 1 + 2 files changed, 49 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 48a57c0636bf4..f6142d78ede4c 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2592,27 +2592,55 @@ static const struct file_operations i915_guc_log_relay_fops = { .release = i915_guc_log_relay_release, }; -static const char *psr2_live_status(u32 val) -{ - static const char * const live_status[] = { - "IDLE", - "CAPTURE", - "CAPTURE_FS", - "SLEEP", - "BUFON_FW", - "ML_UP", - "SU_STANDBY", - "FAST_SLEEP", - "DEEP_SLEEP", - "BUF_ON", - "TG_ON" - }; +static void +psr_source_status(struct drm_i915_private *dev_priv, struct seq_file *m) +{ + u32 val, psr_status; - val = (val & EDP_PSR2_STATUS_STATE_MASK) >> EDP_PSR2_STATUS_STATE_SHIFT; - if (val < ARRAY_SIZE(live_status)) - return live_status[val]; + if (dev_priv->psr.psr2_enabled) { + static const char * const live_status[] = { + "IDLE", + "CAPTURE", + "CAPTURE_FS", + "SLEEP", + "BUFON_FW", + "ML_UP", + "SU_STANDBY", + "FAST_SLEEP", + "DEEP_SLEEP", + "BUF_ON", + "TG_ON" + }; + psr_status = I915_READ(EDP_PSR2_STATUS); + val = (psr_status & EDP_PSR2_STATUS_STATE_MASK) >> + EDP_PSR2_STATUS_STATE_SHIFT; + if (val < ARRAY_SIZE(live_status)) { + seq_printf(m, "Source PSR status: 0x%x [%s]\n", + psr_status, live_status[val]); + return; + } + } else { + static const char * const live_status[] = { + "IDLE", + "SRDONACK", + "SRDENT", + "BUFOFF", + "BUFON", + "AUXACK", + "SRDOFFACK", + "SRDENT_ON", + }; + psr_status = I915_READ(EDP_PSR_STATUS); + val = (psr_status & EDP_PSR_STATUS_STATE_MASK) >> + EDP_PSR_STATUS_STATE_SHIFT; + if (val < ARRAY_SIZE(live_status)) { + seq_printf(m, "Source PSR status: 0x%x [%s]\n", + psr_status, live_status[val]); + return; + } + } - return "unknown"; + seq_printf(m, "Source PSR status: 0x%x [%s]\n", psr_status, "unknown"); } static const char *psr_sink_status(u8 val) @@ -2676,12 +2704,8 @@ static int i915_edp_psr_status(struct seq_file *m, void *data) seq_printf(m, "Performance_Counter: %u\n", psrperf); } - if (dev_priv->psr.psr2_enabled) { - u32 psr2 = I915_READ(EDP_PSR2_STATUS); - seq_printf(m, "EDP_PSR2_STATUS: %x [%s]\n", - psr2, psr2_live_status(psr2)); - } + psr_source_status(dev_priv, m); if (dev_priv->psr.enabled) { struct drm_dp_aux *aux = &dev_priv->psr.enabled->aux; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 7dc7746829225..69b9978d7dda8 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4133,6 +4133,7 @@ enum { #define EDP_PSR_STATUS _MMIO(dev_priv->psr_mmio_base + 0x40) #define EDP_PSR_STATUS_STATE_MASK (7 << 29) +#define EDP_PSR_STATUS_STATE_SHIFT 29 #define EDP_PSR_STATUS_STATE_IDLE (0 << 29) #define EDP_PSR_STATUS_STATE_SRDONACK (1 << 29) #define EDP_PSR_STATUS_STATE_SRDENT (2 << 29) -- GitLab From abdd322f680870dbe1942425d1fa2c74de4721f4 Mon Sep 17 00:00:00 2001 From: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Date: Wed, 27 Jun 2018 23:18:54 -0700 Subject: [PATCH 0615/1506] drm/i915: Remove unnecessary check for unsupported modifiers for NV12 There is already a check to allow only RGB8888 formats with CCS modifiers. Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180628061854.6430-1-dhinakaran.pandiyan@intel.com --- drivers/gpu/drm/i915/intel_display.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index fca72ce0b3b34..ce7646265b503 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -14478,11 +14478,6 @@ static int intel_framebuffer_init(struct intel_framebuffer *intel_fb, } break; case DRM_FORMAT_NV12: - if (mode_cmd->modifier[0] == I915_FORMAT_MOD_Y_TILED_CCS || - mode_cmd->modifier[0] == I915_FORMAT_MOD_Yf_TILED_CCS) { - DRM_DEBUG_KMS("RC not to be enabled with NV12\n"); - goto err; - } if (INTEL_GEN(dev_priv) < 9 || IS_SKYLAKE(dev_priv) || IS_BROXTON(dev_priv)) { DRM_DEBUG_KMS("unsupported pixel format: %s\n", -- GitLab From c43dbcbbcc8c515d4ececc7a996d5fc7286c28c3 Mon Sep 17 00:00:00 2001 From: Tarun Vyas <tarun.vyas@intel.com> Date: Wed, 27 Jun 2018 13:02:49 -0700 Subject: [PATCH 0616/1506] drm/i915/psr: Lockless version of psr_wait_for_idle This is a lockless version of the exisiting psr_wait_for_idle(). We want to wait for PSR to idle out inside intel_pipe_update_start. At the time of a pipe update, we should never race with any psr enable or disable code, which is a part of crtc enable/disable. The follow up patch will use this lockless wait inside pipe_update_ start to wait for PSR to idle out before checking for vblank evasion. We need to keep the wait in pipe_update_start to as less as it can be. So,we can live and flourish w/o taking any psr locks at all. Even if psr is never enabled, psr2_enabled will be false and this function will wait for PSR1 to idle out, which should just return immediately, so a very short (~1-2 usec) wait for cases where PSR is disabled. v2: Add comment to explain the 25msec timeout (DK) v3: Rename psr_wait_for_idle to __psr_wait_for_idle_locked to avoid naming conflicts and propagate err (if any) to the caller (Chris) v5: Form a series with the next patch v7: Better explain the need for lockless wait and increase the max timeout to handle refresh rates < 60 Hz (Daniel Vetter) v8: Rebase Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch> Reviewed-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Signed-off-by: Tarun Vyas <tarun.vyas@intel.com> Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180627200250.1515-1-tarun.vyas@intel.com --- drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_psr.c | 36 ++++++++++++++++++++++++++++++-- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 5a37db292d3a3..a8073eb02ffa6 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1921,6 +1921,7 @@ void intel_psr_compute_config(struct intel_dp *intel_dp, void intel_psr_irq_control(struct drm_i915_private *dev_priv, bool debug); void intel_psr_irq_handler(struct drm_i915_private *dev_priv, u32 psr_iir); void intel_psr_short_pulse(struct intel_dp *intel_dp); +int intel_psr_wait_for_idle(struct drm_i915_private *dev_priv); /* intel_runtime_pm.c */ int intel_power_domains_init(struct drm_i915_private *); diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 45f1cb7d6c043..23acc9ac8d4d0 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -717,7 +717,39 @@ void intel_psr_disable(struct intel_dp *intel_dp, cancel_work_sync(&dev_priv->psr.work); } -static bool psr_wait_for_idle(struct drm_i915_private *dev_priv) +int intel_psr_wait_for_idle(struct drm_i915_private *dev_priv) +{ + i915_reg_t reg; + u32 mask; + + /* + * The sole user right now is intel_pipe_update_start(), + * which won't race with psr_enable/disable, which is + * where psr2_enabled is written to. So, we don't need + * to acquire the psr.lock. More importantly, we want the + * latency inside intel_pipe_update_start() to be as low + * as possible, so no need to acquire psr.lock when it is + * not needed and will induce latencies in the atomic + * update path. + */ + if (dev_priv->psr.psr2_enabled) { + reg = EDP_PSR2_STATUS; + mask = EDP_PSR2_STATUS_STATE_MASK; + } else { + reg = EDP_PSR_STATUS; + mask = EDP_PSR_STATUS_STATE_MASK; + } + + /* + * Max time for PSR to idle = Inverse of the refresh rate + + * 6 ms of exit training time + 1.5 ms of aux channel + * handshake. 50 msec is defesive enough to cover everything. + */ + return intel_wait_for_register(dev_priv, reg, mask, + EDP_PSR_STATUS_STATE_IDLE, 50); +} + +static bool __psr_wait_for_idle_locked(struct drm_i915_private *dev_priv) { struct intel_dp *intel_dp; i915_reg_t reg; @@ -763,7 +795,7 @@ static void intel_psr_work(struct work_struct *work) * PSR might take some time to get fully disabled * and be ready for re-enable. */ - if (!psr_wait_for_idle(dev_priv)) + if (!__psr_wait_for_idle_locked(dev_priv)) goto unlock; /* -- GitLab From a608987970b929e250957e4e3fb891f1f10eff6f Mon Sep 17 00:00:00 2001 From: Tarun Vyas <tarun.vyas@intel.com> Date: Wed, 27 Jun 2018 13:02:50 -0700 Subject: [PATCH 0617/1506] drm/i915: Wait for PSR exit before checking for vblank evasion The PIPEDSL freezes on PSR entry and if PSR hasn't fully exited, then the pipe_update_start call schedules itself out to check back later. On ChromeOS-4.4 kernel, which is fairly up-to-date w.r.t drm/i915 but lags w.r.t core kernel code, hot plugging an external display triggers tons of "potential atomic update errors" in the dmesg, on *pipe A*. A closer analysis reveals that we try to read the scanline 3 times and eventually timeout, b/c PSR hasn't exited fully leading to a PIPEDSL stuck @ 1599. This issue is not seen on upstream kernels, b/c for *some* reason we loop inside intel_pipe_update start for ~2+ msec which in this case is more than enough to exit PSR fully, hence an *unstuck* PIPEDSL counter, hence no error. On the other hand, the ChromeOS kernel spends ~1.1 msec looping inside intel_pipe_update_start and hence errors out b/c the source is still in PSR. Regardless, we should wait for PSR exit (if PSR is disabled, we incur a ~1-2 usec penalty) before reading the PIPEDSL, b/c if we haven't fully exited PSR, then checking for vblank evasion isn't actually applicable. v4: Comment explaining psr_wait after enabling VBL interrupts (DK) v5: CAN_PSR() to handle platforms that don't support PSR. v6: Handle local_irq_disable on early return (Chris) Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch> Reviewed-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Signed-off-by: Tarun Vyas <tarun.vyas@intel.com> Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180627200250.1515-2-tarun.vyas@intel.com --- drivers/gpu/drm/i915/intel_sprite.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index d9e7f4fb5096c..e2328d0402d88 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -107,13 +107,21 @@ void intel_pipe_update_start(const struct intel_crtc_state *new_crtc_state) VBLANK_EVASION_TIME_US); max = vblank_start - 1; - local_irq_disable(); - if (min <= 0 || max <= 0) - return; + goto irq_disable; if (WARN_ON(drm_crtc_vblank_get(&crtc->base))) - return; + goto irq_disable; + + /* + * Wait for psr to idle out after enabling the VBL interrupts + * VBL interrupts will start the PSR exit and prevent a PSR + * re-entry as well. + */ + if (CAN_PSR(dev_priv) && intel_psr_wait_for_idle(dev_priv)) + DRM_ERROR("PSR idle timed out, atomic update may fail\n"); + + local_irq_disable(); crtc->debug.min_vbl = min; crtc->debug.max_vbl = max; @@ -171,6 +179,10 @@ void intel_pipe_update_start(const struct intel_crtc_state *new_crtc_state) crtc->debug.start_vbl_count = intel_crtc_get_vblank_counter(crtc); trace_i915_pipe_update_vblank_evaded(crtc); + return; + +irq_disable: + local_irq_disable(); } /** -- GitLab From ba6096311ba6aed28fec237038ec986c9bf9b8e9 Mon Sep 17 00:00:00 2001 From: Daniel Vetter <daniel.vetter@ffwll.ch> Date: Mon, 2 Jul 2018 11:10:23 +0200 Subject: [PATCH 0618/1506] drm: Fix hdmi connector content type property docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apparently didn't get carefully checked. Fixes: 50525c332b55 ("drm: content-type property for HDMI connector") Cc: Hans Verkuil <hans.verkuil@cisco.com> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Cc: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180702091023.695-1-daniel.vetter@ffwll.ch --- Documentation/gpu/drm-kms.rst | 2 +- drivers/gpu/drm/drm_connector.c | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index 4f6f113a7f5d5..514939433004a 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -527,7 +527,7 @@ Standard Connector Properties :doc: standard connector properties HDMI Specific Connector Properties ------------------------------ +---------------------------------- .. kernel-doc:: drivers/gpu/drm/drm_connector.c :doc: HDMI connector properties diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index 2f9ebddd178e1..b09b3a3e40246 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -1033,9 +1033,7 @@ EXPORT_SYMBOL(drm_mode_create_dvi_i_properties); * * Drivers can set up this property by calling * drm_connector_attach_content_type_property(). Decoding to - * infoframe values is done through - * drm_hdmi_get_content_type_from_property() and - * drm_hdmi_get_itc_bit_from_property(). + * infoframe values is done through drm_hdmi_avi_infoframe_content_type(). */ /** -- GitLab From 070473bcf703366e9acb14e172d5b6563cc07a26 Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Mon, 2 Jul 2018 17:21:23 +0100 Subject: [PATCH 0619/1506] drm: add missing ctx argument to plane transitional helpers In commits: 34a2ab5e0689 ("drm: Add acquire ctx parameter to ->update_plane") 1931529448bc ("drm: Add acquire ctx parameter to ->plane_disable") a pointer to a drm_modeset_acquire_ctx structure was added as an argument to the method prototypes. The transitional helpers are supposed to be directly plugged in as implementations of these methods, but doing so generates a warning. Add the missing argument. A number of buggy users were added for drm_plane_helper_disable() which need to be fixed up for this change, which we do by passing a NULL ctx argument. Fixes: 1931529448bc ("drm: Add acquire ctx parameter to ->plane_disable") Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/E1fa1Zr-0005gT-VF@rmk-PC.armlinux.org.uk --- drivers/gpu/drm/arc/arcpgu_crtc.c | 2 +- drivers/gpu/drm/arm/hdlcd_crtc.c | 2 +- drivers/gpu/drm/drm_plane_helper.c | 8 ++++++-- drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c | 2 +- drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c | 2 +- drivers/gpu/drm/sti/sti_cursor.c | 2 +- drivers/gpu/drm/sti/sti_gdp.c | 2 +- drivers/gpu/drm/sti/sti_hqvdp.c | 2 +- drivers/gpu/drm/vc4/vc4_plane.c | 2 +- drivers/gpu/drm/zte/zx_plane.c | 2 +- include/drm/drm_plane_helper.h | 6 ++++-- 11 files changed, 19 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/arc/arcpgu_crtc.c b/drivers/gpu/drm/arc/arcpgu_crtc.c index c3349b8fb58bc..965cda48dc13c 100644 --- a/drivers/gpu/drm/arc/arcpgu_crtc.c +++ b/drivers/gpu/drm/arc/arcpgu_crtc.c @@ -186,7 +186,7 @@ static const struct drm_plane_helper_funcs arc_pgu_plane_helper_funcs = { static void arc_pgu_plane_destroy(struct drm_plane *plane) { - drm_plane_helper_disable(plane); + drm_plane_helper_disable(plane, NULL); drm_plane_cleanup(plane); } diff --git a/drivers/gpu/drm/arm/hdlcd_crtc.c b/drivers/gpu/drm/arm/hdlcd_crtc.c index cf5cbd63ecdff..f3f08cd6e9efb 100644 --- a/drivers/gpu/drm/arm/hdlcd_crtc.c +++ b/drivers/gpu/drm/arm/hdlcd_crtc.c @@ -282,7 +282,7 @@ static const struct drm_plane_helper_funcs hdlcd_plane_helper_funcs = { static void hdlcd_plane_destroy(struct drm_plane *plane) { - drm_plane_helper_disable(plane); + drm_plane_helper_disable(plane, NULL); drm_plane_cleanup(plane); } diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index 2010794943bcc..621f17643bb07 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -440,6 +440,7 @@ int drm_plane_helper_commit(struct drm_plane *plane, * @src_y: y offset of @fb for panning * @src_w: width of source rectangle in @fb * @src_h: height of source rectangle in @fb + * @ctx: lock acquire context, not used here * * Provides a default plane update handler using the atomic plane update * functions. It is fully left to the driver to check plane constraints and @@ -455,7 +456,8 @@ int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h) + uint32_t src_w, uint32_t src_h, + struct drm_modeset_acquire_ctx *ctx) { struct drm_plane_state *plane_state; @@ -489,6 +491,7 @@ EXPORT_SYMBOL(drm_plane_helper_update); /** * drm_plane_helper_disable() - Transitional helper for plane disable * @plane: plane to disable + * @ctx: lock acquire context, not used here * * Provides a default plane disable handler using the atomic plane update * functions. It is fully left to the driver to check plane constraints and @@ -499,7 +502,8 @@ EXPORT_SYMBOL(drm_plane_helper_update); * RETURNS: * Zero on success, error code on failure */ -int drm_plane_helper_disable(struct drm_plane *plane) +int drm_plane_helper_disable(struct drm_plane *plane, + struct drm_modeset_acquire_ctx *ctx) { struct drm_plane_state *plane_state; struct drm_framebuffer *old_fb; diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c index 7b641fa6dc4d6..79ff653d8081e 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c @@ -68,7 +68,7 @@ static void mdp4_plane_destroy(struct drm_plane *plane) { struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane); - drm_plane_helper_disable(plane); + drm_plane_helper_disable(plane, NULL); drm_plane_cleanup(plane); kfree(mdp4_plane); diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c index c4f115fe96ff2..7d306c5acd096 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c @@ -46,7 +46,7 @@ static void mdp5_plane_destroy(struct drm_plane *plane) { struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); - drm_plane_helper_disable(plane); + drm_plane_helper_disable(plane, NULL); drm_plane_cleanup(plane); kfree(mdp5_plane); diff --git a/drivers/gpu/drm/sti/sti_cursor.c b/drivers/gpu/drm/sti/sti_cursor.c index df0a282b96152..57b870e1e6964 100644 --- a/drivers/gpu/drm/sti/sti_cursor.c +++ b/drivers/gpu/drm/sti/sti_cursor.c @@ -332,7 +332,7 @@ static void sti_cursor_destroy(struct drm_plane *drm_plane) { DRM_DEBUG_DRIVER("\n"); - drm_plane_helper_disable(drm_plane); + drm_plane_helper_disable(drm_plane, NULL); drm_plane_cleanup(drm_plane); } diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c index 49813d34bdf06..c32de6cbf0616 100644 --- a/drivers/gpu/drm/sti/sti_gdp.c +++ b/drivers/gpu/drm/sti/sti_gdp.c @@ -883,7 +883,7 @@ static void sti_gdp_destroy(struct drm_plane *drm_plane) { DRM_DEBUG_DRIVER("\n"); - drm_plane_helper_disable(drm_plane); + drm_plane_helper_disable(drm_plane, NULL); drm_plane_cleanup(drm_plane); } diff --git a/drivers/gpu/drm/sti/sti_hqvdp.c b/drivers/gpu/drm/sti/sti_hqvdp.c index 106be8c4e58b9..03ac3b4a44692 100644 --- a/drivers/gpu/drm/sti/sti_hqvdp.c +++ b/drivers/gpu/drm/sti/sti_hqvdp.c @@ -1260,7 +1260,7 @@ static void sti_hqvdp_destroy(struct drm_plane *drm_plane) { DRM_DEBUG_DRIVER("\n"); - drm_plane_helper_disable(drm_plane); + drm_plane_helper_disable(drm_plane, NULL); drm_plane_cleanup(drm_plane); } diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 8604fd2e7c5ae..9d7a36f148cfe 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -902,7 +902,7 @@ static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = { static void vc4_plane_destroy(struct drm_plane *plane) { - drm_plane_helper_disable(plane); + drm_plane_helper_disable(plane, NULL); drm_plane_cleanup(plane); } diff --git a/drivers/gpu/drm/zte/zx_plane.c b/drivers/gpu/drm/zte/zx_plane.c index d1931f5ea0b2e..ae8c53b4b261b 100644 --- a/drivers/gpu/drm/zte/zx_plane.c +++ b/drivers/gpu/drm/zte/zx_plane.c @@ -446,7 +446,7 @@ static const struct drm_plane_helper_funcs zx_gl_plane_helper_funcs = { static void zx_plane_destroy(struct drm_plane *plane) { - drm_plane_helper_disable(plane); + drm_plane_helper_disable(plane, NULL); drm_plane_cleanup(plane); } diff --git a/include/drm/drm_plane_helper.h b/include/drm/drm_plane_helper.h index 28d7ce620729d..26cee29347819 100644 --- a/include/drm/drm_plane_helper.h +++ b/include/drm/drm_plane_helper.h @@ -67,8 +67,10 @@ int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h); -int drm_plane_helper_disable(struct drm_plane *plane); + uint32_t src_w, uint32_t src_h, + struct drm_modeset_acquire_ctx *ctx); +int drm_plane_helper_disable(struct drm_plane *plane, + struct drm_modeset_acquire_ctx *ctx); /* For use by drm_crtc_helper.c */ int drm_plane_helper_commit(struct drm_plane *plane, -- GitLab From 55f036ca7e74b85e34958af3d22121c656796413 Mon Sep 17 00:00:00 2001 From: Peter Ziljstra <peterz@infradead.org> Date: Fri, 15 Jun 2018 10:07:12 +0200 Subject: [PATCH 0620/1506] locking: WW mutex cleanup Make the WW mutex code more readable by adding comments, splitting up functions and pointing out that we're actually using the Wait-Die algorithm. Cc: Ingo Molnar <mingo@redhat.com> Cc: Jonathan Corbet <corbet@lwn.net> Cc: Gustavo Padovan <gustavo@padovan.org> Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Cc: Sean Paul <seanpaul@chromium.org> Cc: David Airlie <airlied@linux.ie> Cc: Davidlohr Bueso <dave@stgolabs.net> Cc: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com> Cc: Josh Triplett <josh@joshtriplett.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Kate Stewart <kstewart@linuxfoundation.org> Cc: Philippe Ombredanne <pombredanne@nexb.com> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: linux-doc@vger.kernel.org Cc: linux-media@vger.kernel.org Cc: linaro-mm-sig@lists.linaro.org Co-authored-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Acked-by: Ingo Molnar <mingo@kernel.org> --- Documentation/locking/ww-mutex-design.txt | 12 +- include/linux/ww_mutex.h | 28 +-- kernel/locking/mutex.c | 202 +++++++++++++--------- 3 files changed, 145 insertions(+), 97 deletions(-) diff --git a/Documentation/locking/ww-mutex-design.txt b/Documentation/locking/ww-mutex-design.txt index 34c3a1b50b9ae..2fd7f2a2af214 100644 --- a/Documentation/locking/ww-mutex-design.txt +++ b/Documentation/locking/ww-mutex-design.txt @@ -32,10 +32,10 @@ the oldest task) wins, and the one with the higher reservation id (i.e. the younger task) unlocks all of the buffers that it has already locked, and then tries again. -In the RDBMS literature this deadlock handling approach is called wait/wound: +In the RDBMS literature this deadlock handling approach is called wait/die: The older tasks waits until it can acquire the contended lock. The younger tasks needs to back off and drop all the locks it is currently holding, i.e. the -younger task is wounded. +younger task dies. Concepts -------- @@ -56,9 +56,9 @@ Furthermore there are three different class of w/w lock acquire functions: * Normal lock acquisition with a context, using ww_mutex_lock. -* Slowpath lock acquisition on the contending lock, used by the wounded task - after having dropped all already acquired locks. These functions have the - _slow postfix. +* Slowpath lock acquisition on the contending lock, used by the task that just + killed its transaction after having dropped all already acquired locks. + These functions have the _slow postfix. From a simple semantics point-of-view the _slow functions are not strictly required, since simply calling the normal ww_mutex_lock functions on the @@ -220,7 +220,7 @@ mutexes are a natural fit for such a case for two reasons: Note that this approach differs in two important ways from the above methods: - Since the list of objects is dynamically constructed (and might very well be - different when retrying due to hitting the -EDEADLK wound condition) there's + different when retrying due to hitting the -EDEADLK die condition) there's no need to keep any object on a persistent list when it's not locked. We can therefore move the list_head into the object itself. - On the other hand the dynamic object list construction also means that the -EALREADY return diff --git a/include/linux/ww_mutex.h b/include/linux/ww_mutex.h index 39fda195bf788..f82fce2229c8d 100644 --- a/include/linux/ww_mutex.h +++ b/include/linux/ww_mutex.h @@ -6,7 +6,7 @@ * * Copyright (C) 2004, 2005, 2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com> * - * Wound/wait implementation: + * Wait/Die implementation: * Copyright (C) 2013 Canonical Ltd. * * This file contains the main data structure and API definitions. @@ -28,9 +28,9 @@ struct ww_class { struct ww_acquire_ctx { struct task_struct *task; unsigned long stamp; - unsigned acquired; + unsigned int acquired; #ifdef CONFIG_DEBUG_MUTEXES - unsigned done_acquire; + unsigned int done_acquire; struct ww_class *ww_class; struct ww_mutex *contending_lock; #endif @@ -38,8 +38,8 @@ struct ww_acquire_ctx { struct lockdep_map dep_map; #endif #ifdef CONFIG_DEBUG_WW_MUTEX_SLOWPATH - unsigned deadlock_inject_interval; - unsigned deadlock_inject_countdown; + unsigned int deadlock_inject_interval; + unsigned int deadlock_inject_countdown; #endif }; @@ -102,7 +102,7 @@ static inline void ww_mutex_init(struct ww_mutex *lock, * * Context-based w/w mutex acquiring can be done in any order whatsoever within * a given lock class. Deadlocks will be detected and handled with the - * wait/wound logic. + * wait/die logic. * * Mixing of context-based w/w mutex acquiring and single w/w mutex locking can * result in undetected deadlocks and is so forbidden. Mixing different contexts @@ -195,13 +195,13 @@ static inline void ww_acquire_fini(struct ww_acquire_ctx *ctx) * Lock the w/w mutex exclusively for this task. * * Deadlocks within a given w/w class of locks are detected and handled with the - * wait/wound algorithm. If the lock isn't immediately avaiable this function + * wait/die algorithm. If the lock isn't immediately available this function * will either sleep until it is (wait case). Or it selects the current context - * for backing off by returning -EDEADLK (wound case). Trying to acquire the + * for backing off by returning -EDEADLK (die case). Trying to acquire the * same lock with the same context twice is also detected and signalled by * returning -EALREADY. Returns 0 if the mutex was successfully acquired. * - * In the wound case the caller must release all currently held w/w mutexes for + * In the die case the caller must release all currently held w/w mutexes for * the given context and then wait for this contending lock to be available by * calling ww_mutex_lock_slow. Alternatively callers can opt to not acquire this * lock and proceed with trying to acquire further w/w mutexes (e.g. when @@ -226,14 +226,14 @@ extern int /* __must_check */ ww_mutex_lock(struct ww_mutex *lock, struct ww_acq * Lock the w/w mutex exclusively for this task. * * Deadlocks within a given w/w class of locks are detected and handled with the - * wait/wound algorithm. If the lock isn't immediately avaiable this function + * wait/die algorithm. If the lock isn't immediately available this function * will either sleep until it is (wait case). Or it selects the current context - * for backing off by returning -EDEADLK (wound case). Trying to acquire the + * for backing off by returning -EDEADLK (die case). Trying to acquire the * same lock with the same context twice is also detected and signalled by * returning -EALREADY. Returns 0 if the mutex was successfully acquired. If a * signal arrives while waiting for the lock then this function returns -EINTR. * - * In the wound case the caller must release all currently held w/w mutexes for + * In the die case the caller must release all currently held w/w mutexes for * the given context and then wait for this contending lock to be available by * calling ww_mutex_lock_slow_interruptible. Alternatively callers can opt to * not acquire this lock and proceed with trying to acquire further w/w mutexes @@ -256,7 +256,7 @@ extern int __must_check ww_mutex_lock_interruptible(struct ww_mutex *lock, * @lock: the mutex to be acquired * @ctx: w/w acquire context * - * Acquires a w/w mutex with the given context after a wound case. This function + * Acquires a w/w mutex with the given context after a die case. This function * will sleep until the lock becomes available. * * The caller must have released all w/w mutexes already acquired with the @@ -290,7 +290,7 @@ ww_mutex_lock_slow(struct ww_mutex *lock, struct ww_acquire_ctx *ctx) * @lock: the mutex to be acquired * @ctx: w/w acquire context * - * Acquires a w/w mutex with the given context after a wound case. This function + * Acquires a w/w mutex with the given context after a die case. This function * will sleep until the lock becomes available and returns 0 when the lock has * been acquired. If a signal arrives while waiting for the lock then this * function returns -EINTR. diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c index f44f658ae629b..cfe48419b7d06 100644 --- a/kernel/locking/mutex.c +++ b/kernel/locking/mutex.c @@ -244,6 +244,17 @@ void __sched mutex_lock(struct mutex *lock) EXPORT_SYMBOL(mutex_lock); #endif +/* + * Wait-Die: + * The newer transactions are killed when: + * It (the new transaction) makes a request for a lock being held + * by an older transaction. + */ + +/* + * Associate the ww_mutex @ww with the context @ww_ctx under which we acquired + * it. + */ static __always_inline void ww_mutex_lock_acquired(struct ww_mutex *ww, struct ww_acquire_ctx *ww_ctx) { @@ -282,26 +293,53 @@ ww_mutex_lock_acquired(struct ww_mutex *ww, struct ww_acquire_ctx *ww_ctx) DEBUG_LOCKS_WARN_ON(ww_ctx->ww_class != ww->ww_class); #endif ww_ctx->acquired++; + ww->ctx = ww_ctx; } +/* + * Determine if context @a is 'after' context @b. IOW, @a is a younger + * transaction than @b and depending on algorithm either needs to wait for + * @b or die. + */ static inline bool __sched __ww_ctx_stamp_after(struct ww_acquire_ctx *a, struct ww_acquire_ctx *b) { - return a->stamp - b->stamp <= LONG_MAX && - (a->stamp != b->stamp || a > b); + + return (signed long)(a->stamp - b->stamp) > 0; +} + +/* + * Wait-Die; wake a younger waiter context (when locks held) such that it can + * die. + * + * Among waiters with context, only the first one can have other locks acquired + * already (ctx->acquired > 0), because __ww_mutex_add_waiter() and + * __ww_mutex_check_kill() wake any but the earliest context. + */ +static bool __sched +__ww_mutex_die(struct mutex *lock, struct mutex_waiter *waiter, + struct ww_acquire_ctx *ww_ctx) +{ + if (waiter->ww_ctx->acquired > 0 && + __ww_ctx_stamp_after(waiter->ww_ctx, ww_ctx)) { + debug_mutex_wake_waiter(lock, waiter); + wake_up_process(waiter->task); + } + + return true; } /* - * Wake up any waiters that may have to back off when the lock is held by the - * given context. + * We just acquired @lock under @ww_ctx, if there are later contexts waiting + * behind us on the wait-list, check if they need to die. * - * Due to the invariants on the wait list, this can only affect the first - * waiter with a context. + * See __ww_mutex_add_waiter() for the list-order construction; basically the + * list is ordered by stamp, smallest (oldest) first. * * The current task must not be on the wait list. */ static void __sched -__ww_mutex_wakeup_for_backoff(struct mutex *lock, struct ww_acquire_ctx *ww_ctx) +__ww_mutex_check_waiters(struct mutex *lock, struct ww_acquire_ctx *ww_ctx) { struct mutex_waiter *cur; @@ -311,30 +349,23 @@ __ww_mutex_wakeup_for_backoff(struct mutex *lock, struct ww_acquire_ctx *ww_ctx) if (!cur->ww_ctx) continue; - if (cur->ww_ctx->acquired > 0 && - __ww_ctx_stamp_after(cur->ww_ctx, ww_ctx)) { - debug_mutex_wake_waiter(lock, cur); - wake_up_process(cur->task); - } - - break; + if (__ww_mutex_die(lock, cur, ww_ctx)) + break; } } /* - * After acquiring lock with fastpath or when we lost out in contested - * slowpath, set ctx and wake up any waiters so they can recheck. + * After acquiring lock with fastpath, where we do not hold wait_lock, set ctx + * and wake up any waiters so they can recheck. */ static __always_inline void ww_mutex_set_context_fastpath(struct ww_mutex *lock, struct ww_acquire_ctx *ctx) { ww_mutex_lock_acquired(lock, ctx); - lock->ctx = ctx; - /* * The lock->ctx update should be visible on all cores before - * the atomic read is done, otherwise contended waiters might be + * the WAITERS check is done, otherwise contended waiters might be * missed. The contended waiters will either see ww_ctx == NULL * and keep spinning, or it will acquire wait_lock, add itself * to waiter list and sleep. @@ -348,29 +379,14 @@ ww_mutex_set_context_fastpath(struct ww_mutex *lock, struct ww_acquire_ctx *ctx) return; /* - * Uh oh, we raced in fastpath, wake up everyone in this case, - * so they can see the new lock->ctx. + * Uh oh, we raced in fastpath, check if any of the waiters need to + * die. */ spin_lock(&lock->base.wait_lock); - __ww_mutex_wakeup_for_backoff(&lock->base, ctx); + __ww_mutex_check_waiters(&lock->base, ctx); spin_unlock(&lock->base.wait_lock); } -/* - * After acquiring lock in the slowpath set ctx. - * - * Unlike for the fast path, the caller ensures that waiters are woken up where - * necessary. - * - * Callers must hold the mutex wait_lock. - */ -static __always_inline void -ww_mutex_set_context_slowpath(struct ww_mutex *lock, struct ww_acquire_ctx *ctx) -{ - ww_mutex_lock_acquired(lock, ctx); - lock->ctx = ctx; -} - #ifdef CONFIG_MUTEX_SPIN_ON_OWNER static inline @@ -646,37 +662,73 @@ void __sched ww_mutex_unlock(struct ww_mutex *lock) } EXPORT_SYMBOL(ww_mutex_unlock); + +static __always_inline int __sched +__ww_mutex_kill(struct mutex *lock, struct ww_acquire_ctx *ww_ctx) +{ + if (ww_ctx->acquired > 0) { +#ifdef CONFIG_DEBUG_MUTEXES + struct ww_mutex *ww; + + ww = container_of(lock, struct ww_mutex, base); + DEBUG_LOCKS_WARN_ON(ww_ctx->contending_lock); + ww_ctx->contending_lock = ww; +#endif + return -EDEADLK; + } + + return 0; +} + + +/* + * Check whether we need to kill the transaction for the current lock acquire. + * + * Wait-Die: If we're trying to acquire a lock already held by an older + * context, kill ourselves. + * + * Since __ww_mutex_add_waiter() orders the wait-list on stamp, we only have to + * look at waiters before us in the wait-list. + */ static inline int __sched -__ww_mutex_lock_check_stamp(struct mutex *lock, struct mutex_waiter *waiter, - struct ww_acquire_ctx *ctx) +__ww_mutex_check_kill(struct mutex *lock, struct mutex_waiter *waiter, + struct ww_acquire_ctx *ctx) { struct ww_mutex *ww = container_of(lock, struct ww_mutex, base); struct ww_acquire_ctx *hold_ctx = READ_ONCE(ww->ctx); struct mutex_waiter *cur; + if (ctx->acquired == 0) + return 0; + if (hold_ctx && __ww_ctx_stamp_after(ctx, hold_ctx)) - goto deadlock; + return __ww_mutex_kill(lock, ctx); /* * If there is a waiter in front of us that has a context, then its - * stamp is earlier than ours and we must back off. + * stamp is earlier than ours and we must kill ourself. */ cur = waiter; list_for_each_entry_continue_reverse(cur, &lock->wait_list, list) { - if (cur->ww_ctx) - goto deadlock; + if (!cur->ww_ctx) + continue; + + return __ww_mutex_kill(lock, ctx); } return 0; - -deadlock: -#ifdef CONFIG_DEBUG_MUTEXES - DEBUG_LOCKS_WARN_ON(ctx->contending_lock); - ctx->contending_lock = ww; -#endif - return -EDEADLK; } +/* + * Add @waiter to the wait-list, keep the wait-list ordered by stamp, smallest + * first. Such that older contexts are preferred to acquire the lock over + * younger contexts. + * + * Waiters without context are interspersed in FIFO order. + * + * Furthermore, for Wait-Die kill ourself immediately when possible (there are + * older contexts already waiting) to avoid unnecessary waiting. + */ static inline int __sched __ww_mutex_add_waiter(struct mutex_waiter *waiter, struct mutex *lock, @@ -693,7 +745,7 @@ __ww_mutex_add_waiter(struct mutex_waiter *waiter, /* * Add the waiter before the first waiter with a higher stamp. * Waiters without a context are skipped to avoid starving - * them. + * them. Wait-Die waiters may die here. */ pos = &lock->wait_list; list_for_each_entry_reverse(cur, &lock->wait_list, list) { @@ -701,34 +753,27 @@ __ww_mutex_add_waiter(struct mutex_waiter *waiter, continue; if (__ww_ctx_stamp_after(ww_ctx, cur->ww_ctx)) { - /* Back off immediately if necessary. */ - if (ww_ctx->acquired > 0) { -#ifdef CONFIG_DEBUG_MUTEXES - struct ww_mutex *ww; + /* + * Wait-Die: if we find an older context waiting, there + * is no point in queueing behind it, as we'd have to + * die the moment it would acquire the lock. + */ + int ret = __ww_mutex_kill(lock, ww_ctx); - ww = container_of(lock, struct ww_mutex, base); - DEBUG_LOCKS_WARN_ON(ww_ctx->contending_lock); - ww_ctx->contending_lock = ww; -#endif - return -EDEADLK; - } + if (ret) + return ret; break; } pos = &cur->list; - /* - * Wake up the waiter so that it gets a chance to back - * off. - */ - if (cur->ww_ctx->acquired > 0) { - debug_mutex_wake_waiter(lock, cur); - wake_up_process(cur->task); - } + /* Wait-Die: ensure younger waiters die. */ + __ww_mutex_die(lock, cur, ww_ctx); } list_add_tail(&waiter->list, pos); + return 0; } @@ -772,7 +817,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, */ if (__mutex_trylock(lock)) { if (use_ww_ctx && ww_ctx) - __ww_mutex_wakeup_for_backoff(lock, ww_ctx); + __ww_mutex_check_waiters(lock, ww_ctx); goto skip_wait; } @@ -790,10 +835,13 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, waiter.ww_ctx = MUTEX_POISON_WW_CTX; #endif } else { - /* Add in stamp order, waking up waiters that must back off. */ + /* + * Add in stamp order, waking up waiters that must kill + * themselves. + */ ret = __ww_mutex_add_waiter(&waiter, lock, ww_ctx); if (ret) - goto err_early_backoff; + goto err_early_kill; waiter.ww_ctx = ww_ctx; } @@ -815,7 +863,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, goto acquired; /* - * Check for signals and wound conditions while holding + * Check for signals and kill conditions while holding * wait_lock. This ensures the lock cancellation is ordered * against mutex_unlock() and wake-ups do not go missing. */ @@ -824,8 +872,8 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, goto err; } - if (use_ww_ctx && ww_ctx && ww_ctx->acquired > 0) { - ret = __ww_mutex_lock_check_stamp(lock, &waiter, ww_ctx); + if (use_ww_ctx && ww_ctx) { + ret = __ww_mutex_check_kill(lock, &waiter, ww_ctx); if (ret) goto err; } @@ -870,7 +918,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, lock_acquired(&lock->dep_map, ip); if (use_ww_ctx && ww_ctx) - ww_mutex_set_context_slowpath(ww, ww_ctx); + ww_mutex_lock_acquired(ww, ww_ctx); spin_unlock(&lock->wait_lock); preempt_enable(); @@ -879,7 +927,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, err: __set_current_state(TASK_RUNNING); mutex_remove_waiter(lock, &waiter, current); -err_early_backoff: +err_early_kill: spin_unlock(&lock->wait_lock); debug_mutex_free_waiter(&waiter); mutex_release(&lock->dep_map, 1, ip); -- GitLab From 08295b3b5beec9aac0f7a9db86f0fc3792039da3 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom <thellstrom@vmware.com> Date: Fri, 15 Jun 2018 10:17:38 +0200 Subject: [PATCH 0621/1506] locking: Implement an algorithm choice for Wound-Wait mutexes The current Wound-Wait mutex algorithm is actually not Wound-Wait but Wait-Die. Implement also Wound-Wait as a per-ww-class choice. Wound-Wait is, contrary to Wait-Die a preemptive algorithm and is known to generate fewer backoffs. Testing reveals that this is true if the number of simultaneous contending transactions is small. As the number of simultaneous contending threads increases, Wait-Wound becomes inferior to Wait-Die in terms of elapsed time. Possibly due to the larger number of held locks of sleeping transactions. Update documentation and callers. Timings using git://people.freedesktop.org/~thomash/ww_mutex_test tag patch-18-06-15 Each thread runs 100000 batches of lock / unlock 800 ww mutexes randomly chosen out of 100000. Four core Intel x86_64: Algorithm #threads Rollbacks time Wound-Wait 4 ~100 ~17s. Wait-Die 4 ~150000 ~19s. Wound-Wait 16 ~360000 ~109s. Wait-Die 16 ~450000 ~82s. Cc: Ingo Molnar <mingo@redhat.com> Cc: Jonathan Corbet <corbet@lwn.net> Cc: Gustavo Padovan <gustavo@padovan.org> Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Cc: Sean Paul <seanpaul@chromium.org> Cc: David Airlie <airlied@linux.ie> Cc: Davidlohr Bueso <dave@stgolabs.net> Cc: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com> Cc: Josh Triplett <josh@joshtriplett.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Kate Stewart <kstewart@linuxfoundation.org> Cc: Philippe Ombredanne <pombredanne@nexb.com> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: linux-doc@vger.kernel.org Cc: linux-media@vger.kernel.org Cc: linaro-mm-sig@lists.linaro.org Co-authored-by: Peter Zijlstra <peterz@infradead.org> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> Acked-by: Ingo Molnar <mingo@kernel.org> --- Documentation/locking/ww-mutex-design.txt | 57 ++++++-- drivers/dma-buf/reservation.c | 2 +- drivers/gpu/drm/drm_modeset_lock.c | 2 +- include/linux/ww_mutex.h | 17 ++- kernel/locking/locktorture.c | 2 +- kernel/locking/mutex.c | 165 +++++++++++++++++++--- kernel/locking/test-ww_mutex.c | 2 +- lib/locking-selftest.c | 2 +- 8 files changed, 213 insertions(+), 36 deletions(-) diff --git a/Documentation/locking/ww-mutex-design.txt b/Documentation/locking/ww-mutex-design.txt index 2fd7f2a2af214..f0ed7c30e695d 100644 --- a/Documentation/locking/ww-mutex-design.txt +++ b/Documentation/locking/ww-mutex-design.txt @@ -1,4 +1,4 @@ -Wait/Wound Deadlock-Proof Mutex Design +Wound/Wait Deadlock-Proof Mutex Design ====================================== Please read mutex-design.txt first, as it applies to wait/wound mutexes too. @@ -32,10 +32,26 @@ the oldest task) wins, and the one with the higher reservation id (i.e. the younger task) unlocks all of the buffers that it has already locked, and then tries again. -In the RDBMS literature this deadlock handling approach is called wait/die: -The older tasks waits until it can acquire the contended lock. The younger tasks -needs to back off and drop all the locks it is currently holding, i.e. the -younger task dies. +In the RDBMS literature, a reservation ticket is associated with a transaction. +and the deadlock handling approach is called Wait-Die. The name is based on +the actions of a locking thread when it encounters an already locked mutex. +If the transaction holding the lock is younger, the locking transaction waits. +If the transaction holding the lock is older, the locking transaction backs off +and dies. Hence Wait-Die. +There is also another algorithm called Wound-Wait: +If the transaction holding the lock is younger, the locking transaction +wounds the transaction holding the lock, requesting it to die. +If the transaction holding the lock is older, it waits for the other +transaction. Hence Wound-Wait. +The two algorithms are both fair in that a transaction will eventually succeed. +However, the Wound-Wait algorithm is typically stated to generate fewer backoffs +compared to Wait-Die, but is, on the other hand, associated with more work than +Wait-Die when recovering from a backoff. Wound-Wait is also a preemptive +algorithm in that transactions are wounded by other transactions, and that +requires a reliable way to pick up up the wounded condition and preempt the +running transaction. Note that this is not the same as process preemption. A +Wound-Wait transaction is considered preempted when it dies (returning +-EDEADLK) following a wound. Concepts -------- @@ -47,10 +63,12 @@ Acquire context: To ensure eventual forward progress it is important the a task trying to acquire locks doesn't grab a new reservation id, but keeps the one it acquired when starting the lock acquisition. This ticket is stored in the acquire context. Furthermore the acquire context keeps track of debugging state -to catch w/w mutex interface abuse. +to catch w/w mutex interface abuse. An acquire context is representing a +transaction. W/w class: In contrast to normal mutexes the lock class needs to be explicit for -w/w mutexes, since it is required to initialize the acquire context. +w/w mutexes, since it is required to initialize the acquire context. The lock +class also specifies what algorithm to use, Wound-Wait or Wait-Die. Furthermore there are three different class of w/w lock acquire functions: @@ -90,6 +108,12 @@ provided. Usage ----- +The algorithm (Wait-Die vs Wound-Wait) is chosen by using either +DEFINE_WW_CLASS() (Wound-Wait) or DEFINE_WD_CLASS() (Wait-Die) +As a rough rule of thumb, use Wound-Wait iff you +expect the number of simultaneous competing transactions to be typically small, +and you want to reduce the number of rollbacks. + Three different ways to acquire locks within the same w/w class. Common definitions for methods #1 and #2: @@ -312,12 +336,23 @@ Design: We maintain the following invariants for the wait list: (1) Waiters with an acquire context are sorted by stamp order; waiters without an acquire context are interspersed in FIFO order. - (2) Among waiters with contexts, only the first one can have other locks - acquired already (ctx->acquired > 0). Note that this waiter may come - after other waiters without contexts in the list. + (2) For Wait-Die, among waiters with contexts, only the first one can have + other locks acquired already (ctx->acquired > 0). Note that this waiter + may come after other waiters without contexts in the list. + + The Wound-Wait preemption is implemented with a lazy-preemption scheme: + The wounded status of the transaction is checked only when there is + contention for a new lock and hence a true chance of deadlock. In that + situation, if the transaction is wounded, it backs off, clears the + wounded status and retries. A great benefit of implementing preemption in + this way is that the wounded transaction can identify a contending lock to + wait for before restarting the transaction. Just blindly restarting the + transaction would likely make the transaction end up in a situation where + it would have to back off again. In general, not much contention is expected. The locks are typically used to - serialize access to resources for devices. + serialize access to resources for devices, and optimization focus should + therefore be directed towards the uncontended cases. Lockdep: Special care has been taken to warn for as many cases of api abuse diff --git a/drivers/dma-buf/reservation.c b/drivers/dma-buf/reservation.c index 314eb1071cce7..20bf90f4ee632 100644 --- a/drivers/dma-buf/reservation.c +++ b/drivers/dma-buf/reservation.c @@ -46,7 +46,7 @@ * write-side updates. */ -DEFINE_WW_CLASS(reservation_ww_class); +DEFINE_WD_CLASS(reservation_ww_class); EXPORT_SYMBOL(reservation_ww_class); struct lock_class_key reservation_seqcount_class; diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c index 8a5100685875a..638be2eb67b44 100644 --- a/drivers/gpu/drm/drm_modeset_lock.c +++ b/drivers/gpu/drm/drm_modeset_lock.c @@ -70,7 +70,7 @@ * lists and lookup data structures. */ -static DEFINE_WW_CLASS(crtc_ww_class); +static DEFINE_WD_CLASS(crtc_ww_class); /** * drm_modeset_lock_all - take all modeset locks diff --git a/include/linux/ww_mutex.h b/include/linux/ww_mutex.h index f82fce2229c8d..3af7c0e03be54 100644 --- a/include/linux/ww_mutex.h +++ b/include/linux/ww_mutex.h @@ -8,6 +8,8 @@ * * Wait/Die implementation: * Copyright (C) 2013 Canonical Ltd. + * Choice of algorithm: + * Copyright (C) 2018 WMWare Inc. * * This file contains the main data structure and API definitions. */ @@ -23,12 +25,15 @@ struct ww_class { struct lock_class_key mutex_key; const char *acquire_name; const char *mutex_name; + unsigned int is_wait_die; }; struct ww_acquire_ctx { struct task_struct *task; unsigned long stamp; unsigned int acquired; + unsigned short wounded; + unsigned short is_wait_die; #ifdef CONFIG_DEBUG_MUTEXES unsigned int done_acquire; struct ww_class *ww_class; @@ -58,17 +63,21 @@ struct ww_mutex { # define __WW_CLASS_MUTEX_INITIALIZER(lockname, class) #endif -#define __WW_CLASS_INITIALIZER(ww_class) \ +#define __WW_CLASS_INITIALIZER(ww_class, _is_wait_die) \ { .stamp = ATOMIC_LONG_INIT(0) \ , .acquire_name = #ww_class "_acquire" \ - , .mutex_name = #ww_class "_mutex" } + , .mutex_name = #ww_class "_mutex" \ + , .is_wait_die = _is_wait_die } #define __WW_MUTEX_INITIALIZER(lockname, class) \ { .base = __MUTEX_INITIALIZER(lockname.base) \ __WW_CLASS_MUTEX_INITIALIZER(lockname, class) } +#define DEFINE_WD_CLASS(classname) \ + struct ww_class classname = __WW_CLASS_INITIALIZER(classname, 1) + #define DEFINE_WW_CLASS(classname) \ - struct ww_class classname = __WW_CLASS_INITIALIZER(classname) + struct ww_class classname = __WW_CLASS_INITIALIZER(classname, 0) #define DEFINE_WW_MUTEX(mutexname, ww_class) \ struct ww_mutex mutexname = __WW_MUTEX_INITIALIZER(mutexname, ww_class) @@ -123,6 +132,8 @@ static inline void ww_acquire_init(struct ww_acquire_ctx *ctx, ctx->task = current; ctx->stamp = atomic_long_inc_return_relaxed(&ww_class->stamp); ctx->acquired = 0; + ctx->wounded = false; + ctx->is_wait_die = ww_class->is_wait_die; #ifdef CONFIG_DEBUG_MUTEXES ctx->ww_class = ww_class; ctx->done_acquire = 0; diff --git a/kernel/locking/locktorture.c b/kernel/locking/locktorture.c index 8402b3349dca4..c28224347d690 100644 --- a/kernel/locking/locktorture.c +++ b/kernel/locking/locktorture.c @@ -365,7 +365,7 @@ static struct lock_torture_ops mutex_lock_ops = { }; #include <linux/ww_mutex.h> -static DEFINE_WW_CLASS(torture_ww_class); +static DEFINE_WD_CLASS(torture_ww_class); static DEFINE_WW_MUTEX(torture_ww_mutex_0, &torture_ww_class); static DEFINE_WW_MUTEX(torture_ww_mutex_1, &torture_ww_class); static DEFINE_WW_MUTEX(torture_ww_mutex_2, &torture_ww_class); diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c index cfe48419b7d06..1a81a1257b3f3 100644 --- a/kernel/locking/mutex.c +++ b/kernel/locking/mutex.c @@ -173,6 +173,21 @@ static inline bool __mutex_waiter_is_first(struct mutex *lock, struct mutex_wait return list_first_entry(&lock->wait_list, struct mutex_waiter, list) == waiter; } +/* + * Add @waiter to a given location in the lock wait_list and set the + * FLAG_WAITERS flag if it's the first waiter. + */ +static void __sched +__mutex_add_waiter(struct mutex *lock, struct mutex_waiter *waiter, + struct list_head *list) +{ + debug_mutex_add_waiter(lock, waiter, current); + + list_add_tail(&waiter->list, list); + if (__mutex_waiter_is_first(lock, waiter)) + __mutex_set_flag(lock, MUTEX_FLAG_WAITERS); +} + /* * Give up ownership to a specific task, when @task = NULL, this is equivalent * to a regular unlock. Sets PICKUP on a handoff, clears HANDOF, preserves @@ -249,6 +264,11 @@ EXPORT_SYMBOL(mutex_lock); * The newer transactions are killed when: * It (the new transaction) makes a request for a lock being held * by an older transaction. + * + * Wound-Wait: + * The newer transactions are wounded when: + * An older transaction makes a request for a lock being held by + * the newer transaction. */ /* @@ -320,6 +340,9 @@ static bool __sched __ww_mutex_die(struct mutex *lock, struct mutex_waiter *waiter, struct ww_acquire_ctx *ww_ctx) { + if (!ww_ctx->is_wait_die) + return false; + if (waiter->ww_ctx->acquired > 0 && __ww_ctx_stamp_after(waiter->ww_ctx, ww_ctx)) { debug_mutex_wake_waiter(lock, waiter); @@ -329,13 +352,65 @@ __ww_mutex_die(struct mutex *lock, struct mutex_waiter *waiter, return true; } +/* + * Wound-Wait; wound a younger @hold_ctx if it holds the lock. + * + * Wound the lock holder if there are waiters with older transactions than + * the lock holders. Even if multiple waiters may wound the lock holder, + * it's sufficient that only one does. + */ +static bool __ww_mutex_wound(struct mutex *lock, + struct ww_acquire_ctx *ww_ctx, + struct ww_acquire_ctx *hold_ctx) +{ + struct task_struct *owner = __mutex_owner(lock); + + lockdep_assert_held(&lock->wait_lock); + + /* + * Possible through __ww_mutex_add_waiter() when we race with + * ww_mutex_set_context_fastpath(). In that case we'll get here again + * through __ww_mutex_check_waiters(). + */ + if (!hold_ctx) + return false; + + /* + * Can have !owner because of __mutex_unlock_slowpath(), but if owner, + * it cannot go away because we'll have FLAG_WAITERS set and hold + * wait_lock. + */ + if (!owner) + return false; + + if (ww_ctx->acquired > 0 && __ww_ctx_stamp_after(hold_ctx, ww_ctx)) { + hold_ctx->wounded = 1; + + /* + * wake_up_process() paired with set_current_state() + * inserts sufficient barriers to make sure @owner either sees + * it's wounded in __ww_mutex_lock_check_stamp() or has a + * wakeup pending to re-read the wounded state. + */ + if (owner != current) + wake_up_process(owner); + + return true; + } + + return false; +} + /* * We just acquired @lock under @ww_ctx, if there are later contexts waiting - * behind us on the wait-list, check if they need to die. + * behind us on the wait-list, check if they need to die, or wound us. * * See __ww_mutex_add_waiter() for the list-order construction; basically the * list is ordered by stamp, smallest (oldest) first. * + * This relies on never mixing wait-die/wound-wait on the same wait-list; + * which is currently ensured by that being a ww_class property. + * * The current task must not be on the wait list. */ static void __sched @@ -349,7 +424,8 @@ __ww_mutex_check_waiters(struct mutex *lock, struct ww_acquire_ctx *ww_ctx) if (!cur->ww_ctx) continue; - if (__ww_mutex_die(lock, cur, ww_ctx)) + if (__ww_mutex_die(lock, cur, ww_ctx) || + __ww_mutex_wound(lock, cur->ww_ctx, ww_ctx)) break; } } @@ -370,17 +446,23 @@ ww_mutex_set_context_fastpath(struct ww_mutex *lock, struct ww_acquire_ctx *ctx) * and keep spinning, or it will acquire wait_lock, add itself * to waiter list and sleep. */ - smp_mb(); /* ^^^ */ + smp_mb(); /* See comments above and below. */ /* - * Check if lock is contended, if not there is nobody to wake up + * [W] ww->ctx = ctx [W] MUTEX_FLAG_WAITERS + * MB MB + * [R] MUTEX_FLAG_WAITERS [R] ww->ctx + * + * The memory barrier above pairs with the memory barrier in + * __ww_mutex_add_waiter() and makes sure we either observe ww->ctx + * and/or !empty list. */ if (likely(!(atomic_long_read(&lock->base.owner) & MUTEX_FLAG_WAITERS))) return; /* * Uh oh, we raced in fastpath, check if any of the waiters need to - * die. + * die or wound us. */ spin_lock(&lock->base.wait_lock); __ww_mutex_check_waiters(&lock->base, ctx); @@ -682,7 +764,9 @@ __ww_mutex_kill(struct mutex *lock, struct ww_acquire_ctx *ww_ctx) /* - * Check whether we need to kill the transaction for the current lock acquire. + * Check the wound condition for the current lock acquire. + * + * Wound-Wait: If we're wounded, kill ourself. * * Wait-Die: If we're trying to acquire a lock already held by an older * context, kill ourselves. @@ -701,6 +785,13 @@ __ww_mutex_check_kill(struct mutex *lock, struct mutex_waiter *waiter, if (ctx->acquired == 0) return 0; + if (!ctx->is_wait_die) { + if (ctx->wounded) + return __ww_mutex_kill(lock, ctx); + + return 0; + } + if (hold_ctx && __ww_ctx_stamp_after(ctx, hold_ctx)) return __ww_mutex_kill(lock, ctx); @@ -727,7 +818,8 @@ __ww_mutex_check_kill(struct mutex *lock, struct mutex_waiter *waiter, * Waiters without context are interspersed in FIFO order. * * Furthermore, for Wait-Die kill ourself immediately when possible (there are - * older contexts already waiting) to avoid unnecessary waiting. + * older contexts already waiting) to avoid unnecessary waiting and for + * Wound-Wait ensure we wound the owning context when it is younger. */ static inline int __sched __ww_mutex_add_waiter(struct mutex_waiter *waiter, @@ -736,16 +828,21 @@ __ww_mutex_add_waiter(struct mutex_waiter *waiter, { struct mutex_waiter *cur; struct list_head *pos; + bool is_wait_die; if (!ww_ctx) { - list_add_tail(&waiter->list, &lock->wait_list); + __mutex_add_waiter(lock, waiter, &lock->wait_list); return 0; } + is_wait_die = ww_ctx->is_wait_die; + /* * Add the waiter before the first waiter with a higher stamp. * Waiters without a context are skipped to avoid starving - * them. Wait-Die waiters may die here. + * them. Wait-Die waiters may die here. Wound-Wait waiters + * never die here, but they are sorted in stamp order and + * may wound the lock holder. */ pos = &lock->wait_list; list_for_each_entry_reverse(cur, &lock->wait_list, list) { @@ -758,10 +855,12 @@ __ww_mutex_add_waiter(struct mutex_waiter *waiter, * is no point in queueing behind it, as we'd have to * die the moment it would acquire the lock. */ - int ret = __ww_mutex_kill(lock, ww_ctx); + if (is_wait_die) { + int ret = __ww_mutex_kill(lock, ww_ctx); - if (ret) - return ret; + if (ret) + return ret; + } break; } @@ -772,7 +871,23 @@ __ww_mutex_add_waiter(struct mutex_waiter *waiter, __ww_mutex_die(lock, cur, ww_ctx); } - list_add_tail(&waiter->list, pos); + __mutex_add_waiter(lock, waiter, pos); + + /* + * Wound-Wait: if we're blocking on a mutex owned by a younger context, + * wound that such that we might proceed. + */ + if (!is_wait_die) { + struct ww_mutex *ww = container_of(lock, struct ww_mutex, base); + + /* + * See ww_mutex_set_context_fastpath(). Orders setting + * MUTEX_FLAG_WAITERS vs the ww->ctx load, + * such that either we or the fastpath will wound @ww->ctx. + */ + smp_mb(); + __ww_mutex_wound(lock, ww_ctx, ww->ctx); + } return 0; } @@ -796,6 +911,14 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, if (use_ww_ctx && ww_ctx) { if (unlikely(ww_ctx == READ_ONCE(ww->ctx))) return -EALREADY; + + /* + * Reset the wounded flag after a kill. No other process can + * race and wound us here since they can't have a valid owner + * pointer if we don't have any locks held. + */ + if (ww_ctx->acquired == 0) + ww_ctx->wounded = 0; } preempt_disable(); @@ -829,7 +952,8 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, if (!use_ww_ctx) { /* add waiting tasks to the end of the waitqueue (FIFO): */ - list_add_tail(&waiter.list, &lock->wait_list); + __mutex_add_waiter(lock, &waiter, &lock->wait_list); + #ifdef CONFIG_DEBUG_MUTEXES waiter.ww_ctx = MUTEX_POISON_WW_CTX; @@ -848,9 +972,6 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, waiter.task = current; - if (__mutex_waiter_is_first(lock, &waiter)) - __mutex_set_flag(lock, MUTEX_FLAG_WAITERS); - set_current_state(state); for (;;) { /* @@ -907,6 +1028,16 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, acquired: __set_current_state(TASK_RUNNING); + if (use_ww_ctx && ww_ctx) { + /* + * Wound-Wait; we stole the lock (!first_waiter), check the + * waiters as anyone might want to wound us. + */ + if (!ww_ctx->is_wait_die && + !__mutex_waiter_is_first(lock, &waiter)) + __ww_mutex_check_waiters(lock, ww_ctx); + } + mutex_remove_waiter(lock, &waiter, current); if (likely(list_empty(&lock->wait_list))) __mutex_clear_flag(lock, MUTEX_FLAGS); diff --git a/kernel/locking/test-ww_mutex.c b/kernel/locking/test-ww_mutex.c index 0e4cd64ad2c01..5b915b370d5a8 100644 --- a/kernel/locking/test-ww_mutex.c +++ b/kernel/locking/test-ww_mutex.c @@ -26,7 +26,7 @@ #include <linux/slab.h> #include <linux/ww_mutex.h> -static DEFINE_WW_CLASS(ww_class); +static DEFINE_WD_CLASS(ww_class); struct workqueue_struct *wq; struct test_mutex { diff --git a/lib/locking-selftest.c b/lib/locking-selftest.c index b5c1293ce1474..1e1bbf171eca4 100644 --- a/lib/locking-selftest.c +++ b/lib/locking-selftest.c @@ -29,7 +29,7 @@ */ static unsigned int debug_locks_verbose; -static DEFINE_WW_CLASS(ww_lockdep); +static DEFINE_WD_CLASS(ww_lockdep); static int __init setup_debug_locks_verbose(char *str) { -- GitLab From 07c13bb78c8b8a9cb6ee169659528945038d5e85 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom <thellstrom@vmware.com> Date: Thu, 14 Jun 2018 09:29:22 +0200 Subject: [PATCH 0622/1506] drm: Change deadlock-avoidance algorithm for the modeset locks. For modeset locks we don't expect a high number of contending transactions so change algorithm from Wait-Die to Wound-Wait. Cc: dri-devel@lists.freedesktop.org Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Acked-by: Ingo Molnar <mingo@kernel.org> --- drivers/gpu/drm/drm_modeset_lock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c index 638be2eb67b44..8a5100685875a 100644 --- a/drivers/gpu/drm/drm_modeset_lock.c +++ b/drivers/gpu/drm/drm_modeset_lock.c @@ -70,7 +70,7 @@ * lists and lookup data structures. */ -static DEFINE_WD_CLASS(crtc_ww_class); +static DEFINE_WW_CLASS(crtc_ww_class); /** * drm_modeset_lock_all - take all modeset locks -- GitLab From 418cc6ca06071e7b7d75c0d525d80a6f49a763d6 Mon Sep 17 00:00:00 2001 From: Daniel Vetter <daniel.vetter@ffwll.ch> Date: Thu, 3 May 2018 16:25:52 +0200 Subject: [PATCH 0623/1506] dma-fence: Make ->wait callback optional MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Almost everyone uses dma_fence_default_wait. v2: Also remove the BUG_ON(!ops->wait) (Chris). Reviewed-by: Christian König <christian.koenig@amd.com> (v1) Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Cc: Chris Wilson <chris@chris-wilson.co.uk> Cc: Sumit Semwal <sumit.semwal@linaro.org> Cc: Gustavo Padovan <gustavo@padovan.org> Cc: linux-media@vger.kernel.org Cc: linaro-mm-sig@lists.linaro.org Link: https://patchwork.freedesktop.org/patch/msgid/20180503142603.28513-5-daniel.vetter@ffwll.ch --- drivers/dma-buf/dma-fence-array.c | 1 - drivers/dma-buf/dma-fence.c | 8 +++++--- drivers/dma-buf/sw_sync.c | 1 - include/linux/dma-fence.h | 13 ++++++++----- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/drivers/dma-buf/dma-fence-array.c b/drivers/dma-buf/dma-fence-array.c index dd1edfb27b61a..a8c2544972518 100644 --- a/drivers/dma-buf/dma-fence-array.c +++ b/drivers/dma-buf/dma-fence-array.c @@ -104,7 +104,6 @@ const struct dma_fence_ops dma_fence_array_ops = { .get_timeline_name = dma_fence_array_get_timeline_name, .enable_signaling = dma_fence_array_enable_signaling, .signaled = dma_fence_array_signaled, - .wait = dma_fence_default_wait, .release = dma_fence_array_release, }; EXPORT_SYMBOL(dma_fence_array_ops); diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c index ea343f9921127..7a92f85a4cec8 100644 --- a/drivers/dma-buf/dma-fence.c +++ b/drivers/dma-buf/dma-fence.c @@ -158,7 +158,10 @@ dma_fence_wait_timeout(struct dma_fence *fence, bool intr, signed long timeout) return -EINVAL; trace_dma_fence_wait_start(fence); - ret = fence->ops->wait(fence, intr, timeout); + if (fence->ops->wait) + ret = fence->ops->wait(fence, intr, timeout); + else + ret = dma_fence_default_wait(fence, intr, timeout); trace_dma_fence_wait_end(fence); return ret; } @@ -556,8 +559,7 @@ dma_fence_init(struct dma_fence *fence, const struct dma_fence_ops *ops, spinlock_t *lock, u64 context, unsigned seqno) { BUG_ON(!lock); - BUG_ON(!ops || !ops->wait || - !ops->get_driver_name || !ops->get_timeline_name); + BUG_ON(!ops || !ops->get_driver_name || !ops->get_timeline_name); kref_init(&fence->refcount); fence->ops = ops; diff --git a/drivers/dma-buf/sw_sync.c b/drivers/dma-buf/sw_sync.c index 3d78ca89a6053..53c1d6d36a642 100644 --- a/drivers/dma-buf/sw_sync.c +++ b/drivers/dma-buf/sw_sync.c @@ -188,7 +188,6 @@ static const struct dma_fence_ops timeline_fence_ops = { .get_timeline_name = timeline_fence_get_timeline_name, .enable_signaling = timeline_fence_enable_signaling, .signaled = timeline_fence_signaled, - .wait = dma_fence_default_wait, .release = timeline_fence_release, .fence_value_str = timeline_fence_value_str, .timeline_value_str = timeline_fence_timeline_value_str, diff --git a/include/linux/dma-fence.h b/include/linux/dma-fence.h index c053d19e1e248..02dba8cd033d8 100644 --- a/include/linux/dma-fence.h +++ b/include/linux/dma-fence.h @@ -191,11 +191,14 @@ struct dma_fence_ops { /** * @wait: * - * Custom wait implementation, or dma_fence_default_wait. + * Custom wait implementation, defaults to dma_fence_default_wait() if + * not set. * - * Must not be NULL, set to dma_fence_default_wait for default implementation. - * the dma_fence_default_wait implementation should work for any fence, as long - * as enable_signaling works correctly. + * The dma_fence_default_wait implementation should work for any fence, as long + * as @enable_signaling works correctly. This hook allows drivers to + * have an optimized version for the case where a process context is + * already available, e.g. if @enable_signaling for the general case + * needs to set up a worker thread. * * Must return -ERESTARTSYS if the wait is intr = true and the wait was * interrupted, and remaining jiffies if fence has signaled, or 0 if wait @@ -203,7 +206,7 @@ struct dma_fence_ops { * which should be treated as if the fence is signaled. For example a hardware * lockup could be reported like that. * - * This callback is mandatory. + * This callback is optional. */ signed long (*wait)(struct dma_fence *fence, bool intr, signed long timeout); -- GitLab From 95f9e2636a60424c27dc16c7674a03feef9e1303 Mon Sep 17 00:00:00 2001 From: Daniel Vetter <daniel.vetter@ffwll.ch> Date: Thu, 3 May 2018 16:25:53 +0200 Subject: [PATCH 0624/1506] drm/amdgpu: Remove unecessary dma_fence_ops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dma_fence_default_wait is the default now. Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Cc: Alex Deucher <alexander.deucher@amd.com> Cc: "Christian König" <christian.koenig@amd.com> Cc: Monk Liu <Monk.Liu@amd.com> Cc: pding <Pixel.Ding@amd.com> Cc: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Cc: Evan Quan <evan.quan@amd.com> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Cc: Kees Cook <keescook@chromium.org> Link: https://patchwork.freedesktop.org/patch/msgid/20180503142603.28513-6-daniel.vetter@ffwll.ch --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_fence.c | 2 -- drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c | 1 - 2 files changed, 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_fence.c index 2c14025e5e768..574c1181ae9a2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_fence.c @@ -173,7 +173,5 @@ static const struct dma_fence_ops amdkfd_fence_ops = { .get_driver_name = amdkfd_fence_get_driver_name, .get_timeline_name = amdkfd_fence_get_timeline_name, .enable_signaling = amdkfd_fence_enable_signaling, - .signaled = NULL, - .wait = dma_fence_default_wait, .release = amdkfd_fence_release, }; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c index 39ec6b8890a1b..2e9db0ebe678e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c @@ -646,7 +646,6 @@ static const struct dma_fence_ops amdgpu_fence_ops = { .get_driver_name = amdgpu_fence_get_driver_name, .get_timeline_name = amdgpu_fence_get_timeline_name, .enable_signaling = amdgpu_fence_enable_signaling, - .wait = dma_fence_default_wait, .release = amdgpu_fence_release, }; -- GitLab From 99e227cb03970287958d05ed41589cc82383534d Mon Sep 17 00:00:00 2001 From: Daniel Vetter <daniel.vetter@ffwll.ch> Date: Thu, 3 May 2018 16:25:54 +0200 Subject: [PATCH 0625/1506] drm: Remove unecessary dma_fence_ops dma_fence_default_wait is the default now, same for the trivial enable_signaling implementation. Reviewed-by: Eric Anholt <eric@anholt.net> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Cc: Gustavo Padovan <gustavo@padovan.org> Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Cc: Sean Paul <seanpaul@chromium.org> Cc: David Airlie <airlied@linux.ie> Link: https://patchwork.freedesktop.org/patch/msgid/20180503142603.28513-7-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_crtc.c | 7 ------- drivers/gpu/drm/drm_syncobj.c | 1 - drivers/gpu/drm/scheduler/sched_fence.c | 11 ----------- 3 files changed, 19 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index c762e75a2d94e..a6906c4ab880f 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -225,16 +225,9 @@ static const char *drm_crtc_fence_get_timeline_name(struct dma_fence *fence) return crtc->timeline_name; } -static bool drm_crtc_fence_enable_signaling(struct dma_fence *fence) -{ - return true; -} - static const struct dma_fence_ops drm_crtc_fence_ops = { .get_driver_name = drm_crtc_fence_get_driver_name, .get_timeline_name = drm_crtc_fence_get_timeline_name, - .enable_signaling = drm_crtc_fence_enable_signaling, - .wait = dma_fence_default_wait, }; struct dma_fence *drm_crtc_create_fence(struct drm_crtc *crtc) diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c index d4f4ce4845296..adb3cb27d31e6 100644 --- a/drivers/gpu/drm/drm_syncobj.c +++ b/drivers/gpu/drm/drm_syncobj.c @@ -207,7 +207,6 @@ static const struct dma_fence_ops drm_syncobj_null_fence_ops = { .get_driver_name = drm_syncobj_null_fence_get_name, .get_timeline_name = drm_syncobj_null_fence_get_name, .enable_signaling = drm_syncobj_null_fence_enable_signaling, - .wait = dma_fence_default_wait, .release = NULL, }; diff --git a/drivers/gpu/drm/scheduler/sched_fence.c b/drivers/gpu/drm/scheduler/sched_fence.c index df4461648e3fe..45d9c3affbeac 100644 --- a/drivers/gpu/drm/scheduler/sched_fence.c +++ b/drivers/gpu/drm/scheduler/sched_fence.c @@ -81,11 +81,6 @@ static const char *drm_sched_fence_get_timeline_name(struct dma_fence *f) return (const char *)fence->sched->name; } -static bool drm_sched_fence_enable_signaling(struct dma_fence *f) -{ - return true; -} - /** * drm_sched_fence_free - free up the fence memory * @@ -134,18 +129,12 @@ static void drm_sched_fence_release_finished(struct dma_fence *f) const struct dma_fence_ops drm_sched_fence_ops_scheduled = { .get_driver_name = drm_sched_fence_get_driver_name, .get_timeline_name = drm_sched_fence_get_timeline_name, - .enable_signaling = drm_sched_fence_enable_signaling, - .signaled = NULL, - .wait = dma_fence_default_wait, .release = drm_sched_fence_release_scheduled, }; const struct dma_fence_ops drm_sched_fence_ops_finished = { .get_driver_name = drm_sched_fence_get_driver_name, .get_timeline_name = drm_sched_fence_get_timeline_name, - .enable_signaling = drm_sched_fence_enable_signaling, - .signaled = NULL, - .wait = dma_fence_default_wait, .release = drm_sched_fence_release_finished, }; -- GitLab From 51eebbc76b25c16e110d3a40a4f45b31e53b298e Mon Sep 17 00:00:00 2001 From: Daniel Vetter <daniel.vetter@ffwll.ch> Date: Thu, 3 May 2018 16:25:55 +0200 Subject: [PATCH 0626/1506] drm/etnaviv: Remove unecessary dma_fence_ops dma_fence_default_wait is the default now, same for the trivial enable_signaling implementation. Acked-by: Lucas Stach <l.stach@pengutronix.de> Reviewed-by: Christian Gmeiner <christian.gmeiner@gmail.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Cc: Lucas Stach <l.stach@pengutronix.de> Cc: Russell King <linux+etnaviv@armlinux.org.uk> Cc: Christian Gmeiner <christian.gmeiner@gmail.com> Cc: etnaviv@lists.freedesktop.org Link: https://patchwork.freedesktop.org/patch/msgid/20180503142603.28513-8-daniel.vetter@ffwll.ch --- drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index 686f6552db48d..19b09a59e30e7 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -1027,11 +1027,6 @@ static const char *etnaviv_fence_get_timeline_name(struct dma_fence *fence) return dev_name(f->gpu->dev); } -static bool etnaviv_fence_enable_signaling(struct dma_fence *fence) -{ - return true; -} - static bool etnaviv_fence_signaled(struct dma_fence *fence) { struct etnaviv_fence *f = to_etnaviv_fence(fence); @@ -1049,9 +1044,7 @@ static void etnaviv_fence_release(struct dma_fence *fence) static const struct dma_fence_ops etnaviv_fence_ops = { .get_driver_name = etnaviv_fence_get_driver_name, .get_timeline_name = etnaviv_fence_get_timeline_name, - .enable_signaling = etnaviv_fence_enable_signaling, .signaled = etnaviv_fence_signaled, - .wait = dma_fence_default_wait, .release = etnaviv_fence_release, }; -- GitLab From 93f8252bcbec8b810ce5f01184c10f4a6b8b86eb Mon Sep 17 00:00:00 2001 From: Daniel Vetter <daniel.vetter@ffwll.ch> Date: Thu, 3 May 2018 16:25:59 +0200 Subject: [PATCH 0627/1506] drm/qxl: Remove unecessary dma_fence_ops The trivial enable_signaling implementation matches the default code. v2: Fix up commit message to match patch better (Eric). Cc: Eric Anholt <eric@anholt.net> Reviewed-by: Eric Anholt <eric@anholt.net> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Cc: Dave Airlie <airlied@redhat.com> Cc: Gerd Hoffmann <kraxel@redhat.com> Cc: virtualization@lists.linux-foundation.org Link: https://patchwork.freedesktop.org/patch/msgid/20180503142603.28513-12-daniel.vetter@ffwll.ch --- drivers/gpu/drm/qxl/qxl_release.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/gpu/drm/qxl/qxl_release.c b/drivers/gpu/drm/qxl/qxl_release.c index 7cb214577275b..e37f0097f7441 100644 --- a/drivers/gpu/drm/qxl/qxl_release.c +++ b/drivers/gpu/drm/qxl/qxl_release.c @@ -50,12 +50,6 @@ static const char *qxl_get_timeline_name(struct dma_fence *fence) return "release"; } -static bool qxl_nop_signaling(struct dma_fence *fence) -{ - /* fences are always automatically signaled, so just pretend we did this.. */ - return true; -} - static long qxl_fence_wait(struct dma_fence *fence, bool intr, signed long timeout) { @@ -119,7 +113,6 @@ static long qxl_fence_wait(struct dma_fence *fence, bool intr, static const struct dma_fence_ops qxl_fence_ops = { .get_driver_name = qxl_get_driver_name, .get_timeline_name = qxl_get_timeline_name, - .enable_signaling = qxl_nop_signaling, .wait = qxl_fence_wait, }; -- GitLab From 144b09795528780d96491d70619ccbadac324e68 Mon Sep 17 00:00:00 2001 From: Daniel Vetter <daniel.vetter@ffwll.ch> Date: Fri, 4 May 2018 16:09:01 +0200 Subject: [PATCH 0628/1506] drm/vc4: Remove unecessary dma_fence_ops dma_fence_default_wait is the default now, same for the trivial enable_signaling implementation. v2: Also remove the relase hook, dma_fence_free is the default. Reviewed-by: Eric Anholt <eric@anholt.net> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Cc: Eric Anholt <eric@anholt.net> Link: https://patchwork.freedesktop.org/patch/msgid/20180504140901.27471-1-daniel.vetter@ffwll.ch --- drivers/gpu/drm/vc4/vc4_fence.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_fence.c b/drivers/gpu/drm/vc4/vc4_fence.c index dbf5a5a5d5f57..580214e2158c7 100644 --- a/drivers/gpu/drm/vc4/vc4_fence.c +++ b/drivers/gpu/drm/vc4/vc4_fence.c @@ -33,11 +33,6 @@ static const char *vc4_fence_get_timeline_name(struct dma_fence *fence) return "vc4-v3d"; } -static bool vc4_fence_enable_signaling(struct dma_fence *fence) -{ - return true; -} - static bool vc4_fence_signaled(struct dma_fence *fence) { struct vc4_fence *f = to_vc4_fence(fence); @@ -49,8 +44,5 @@ static bool vc4_fence_signaled(struct dma_fence *fence) const struct dma_fence_ops vc4_fence_ops = { .get_driver_name = vc4_fence_get_driver_name, .get_timeline_name = vc4_fence_get_timeline_name, - .enable_signaling = vc4_fence_enable_signaling, .signaled = vc4_fence_signaled, - .wait = dma_fence_default_wait, - .release = dma_fence_free, }; -- GitLab From 64e625cf53539fea4fcc5410d64c619fdbf3d225 Mon Sep 17 00:00:00 2001 From: Daniel Vetter <daniel.vetter@ffwll.ch> Date: Thu, 3 May 2018 16:26:02 +0200 Subject: [PATCH 0629/1506] drm/virtio: Remove unecessary dma_fence_ops dma_fence_default_wait is the default now, same for the trivial enable_signaling implementation. Reviewed-by: Eric Anholt <eric@anholt.net> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Cc: David Airlie <airlied@linux.ie> Cc: Gerd Hoffmann <kraxel@redhat.com> Cc: virtualization@lists.linux-foundation.org Link: https://patchwork.freedesktop.org/patch/msgid/20180503142603.28513-15-daniel.vetter@ffwll.ch --- drivers/gpu/drm/virtio/virtgpu_fence.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/gpu/drm/virtio/virtgpu_fence.c b/drivers/gpu/drm/virtio/virtgpu_fence.c index 23353521f903a..00c742a441bfc 100644 --- a/drivers/gpu/drm/virtio/virtgpu_fence.c +++ b/drivers/gpu/drm/virtio/virtgpu_fence.c @@ -36,11 +36,6 @@ static const char *virtio_get_timeline_name(struct dma_fence *f) return "controlq"; } -static bool virtio_enable_signaling(struct dma_fence *f) -{ - return true; -} - static bool virtio_signaled(struct dma_fence *f) { struct virtio_gpu_fence *fence = to_virtio_fence(f); @@ -67,9 +62,7 @@ static void virtio_timeline_value_str(struct dma_fence *f, char *str, int size) static const struct dma_fence_ops virtio_fence_ops = { .get_driver_name = virtio_get_driver_name, .get_timeline_name = virtio_get_timeline_name, - .enable_signaling = virtio_enable_signaling, .signaled = virtio_signaled, - .wait = dma_fence_default_wait, .fence_value_str = virtio_fence_value_str, .timeline_value_str = virtio_timeline_value_str, }; -- GitLab From a1de8d0a7e2cc79dad6d469901b3b5d4c94c4554 Mon Sep 17 00:00:00 2001 From: Dan Carpenter <dan.carpenter@oracle.com> Date: Tue, 3 Jul 2018 15:30:16 +0300 Subject: [PATCH 0630/1506] drm/i810: off by one in i810_dma_vertex() If vertex->idx == dma->buf_count then we end up reading one element beyond the end of the dma->buflist[] array. Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180703123015.kma7v7rwtdy4urce@kili.mountain --- drivers/gpu/drm/i810/i810_dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i810/i810_dma.c b/drivers/gpu/drm/i810/i810_dma.c index 576a417690d47..3b378936f5755 100644 --- a/drivers/gpu/drm/i810/i810_dma.c +++ b/drivers/gpu/drm/i810/i810_dma.c @@ -934,7 +934,7 @@ static int i810_dma_vertex(struct drm_device *dev, void *data, DRM_DEBUG("idx %d used %d discard %d\n", vertex->idx, vertex->used, vertex->discard); - if (vertex->idx < 0 || vertex->idx > dma->buf_count) + if (vertex->idx < 0 || vertex->idx >= dma->buf_count) return -EINVAL; i810_dma_dispatch_vertex(dev, -- GitLab From de10eba0f68a161f3176b710b6e27d291d48aac2 Mon Sep 17 00:00:00 2001 From: Dan Carpenter <dan.carpenter@oracle.com> Date: Tue, 3 Jul 2018 15:29:21 +0300 Subject: [PATCH 0631/1506] drm/vgem: off by one in vgem_gem_fault() If page_offset is == num_pages then we end up reading beyond the end of obj->pages[]. Fixes: af33a9190d02 ("drm/vgem: Enable dmabuf import interfaces") Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180703122921.brlfxl4vx2ybvrd2@kili.mountain --- drivers/gpu/drm/vgem/vgem_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vgem/vgem_drv.c b/drivers/gpu/drm/vgem/vgem_drv.c index c64a85950c829..0e5620f76ee09 100644 --- a/drivers/gpu/drm/vgem/vgem_drv.c +++ b/drivers/gpu/drm/vgem/vgem_drv.c @@ -74,7 +74,7 @@ static vm_fault_t vgem_gem_fault(struct vm_fault *vmf) num_pages = DIV_ROUND_UP(obj->base.size, PAGE_SIZE); - if (page_offset > num_pages) + if (page_offset >= num_pages) return VM_FAULT_SIGBUS; mutex_lock(&obj->pages_lock); -- GitLab From f1d34bfd70b1b4543a139ea28bad4c001c5f413d Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom <thellstrom@vmware.com> Date: Tue, 19 Jun 2018 15:02:16 +0200 Subject: [PATCH 0632/1506] drm/vmwgfx: Replace vmw_dma_buffer with vmw_buffer_object Initially vmware buffer objects were only used as DMA buffers, so the name DMA buffer was a natural one. However, currently they are used also as dumb buffers and MOBs backing guest backed objects so renaming them to buffer objects is logical. Particularly since there is a dmabuf subsystem in the kernel where a dma buffer means something completely different. This also renames user-space api structures and IOCTL names correspondingly, but the old names remain defined for now and the ABI hasn't changed. There are a couple of minor style changes to make checkpatch happy. Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Reviewed-by: Sinclair Yeh <syeh@vmware.com> Reviewed-by: Deepak Rawat <drawat@vmware.com> --- drivers/gpu/drm/vmwgfx/Makefile | 4 +- .../vmwgfx/{vmwgfx_dmabuf.c => vmwgfx_bo.c} | 58 ++-- drivers/gpu/drm/vmwgfx/vmwgfx_context.c | 10 +- drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c | 10 +- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 18 +- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 129 ++++---- drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 86 +++--- drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 16 +- drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c | 4 +- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 203 +++++++------ drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 58 ++-- drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 10 +- drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c | 24 +- drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 280 +++++++++--------- drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 100 +++---- drivers/gpu/drm/vmwgfx/vmwgfx_shader.c | 22 +- drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 64 ++-- drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 37 ++- .../{vmwgfx_buffer.c => vmwgfx_ttm_buffer.c} | 2 +- include/uapi/drm/vmwgfx_drm.h | 61 ++-- 20 files changed, 589 insertions(+), 607 deletions(-) rename drivers/gpu/drm/vmwgfx/{vmwgfx_dmabuf.c => vmwgfx_bo.c} (86%) rename drivers/gpu/drm/vmwgfx/{vmwgfx_buffer.c => vmwgfx_ttm_buffer.c} (99%) diff --git a/drivers/gpu/drm/vmwgfx/Makefile b/drivers/gpu/drm/vmwgfx/Makefile index 794cc9d5c9b09..09b2aa08363e6 100644 --- a/drivers/gpu/drm/vmwgfx/Makefile +++ b/drivers/gpu/drm/vmwgfx/Makefile @@ -1,9 +1,9 @@ # SPDX-License-Identifier: GPL-2.0 vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o vmwgfx_drv.o \ - vmwgfx_fb.o vmwgfx_ioctl.o vmwgfx_resource.o vmwgfx_buffer.o \ + vmwgfx_fb.o vmwgfx_ioctl.o vmwgfx_resource.o vmwgfx_ttm_buffer.o \ vmwgfx_fifo.o vmwgfx_irq.o vmwgfx_ldu.o vmwgfx_ttm_glue.o \ vmwgfx_overlay.o vmwgfx_marker.o vmwgfx_gmrid_manager.o \ - vmwgfx_fence.o vmwgfx_dmabuf.o vmwgfx_scrn.o vmwgfx_context.o \ + vmwgfx_fence.o vmwgfx_bo.o vmwgfx_scrn.o vmwgfx_context.o \ vmwgfx_surface.o vmwgfx_prime.o vmwgfx_mob.o vmwgfx_shader.o \ vmwgfx_cmdbuf_res.o vmwgfx_cmdbuf.o vmwgfx_stdu.o \ vmwgfx_cotable.o vmwgfx_so.o vmwgfx_binding.o vmwgfx_msg.o \ diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c similarity index 86% rename from drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c rename to drivers/gpu/drm/vmwgfx/vmwgfx_bo.c index d59d9dd16ebc6..f26f658cccdbf 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c @@ -32,7 +32,7 @@ /** - * vmw_dmabuf_pin_in_placement - Validate a buffer to placement. + * vmw_bo_pin_in_placement - Validate a buffer to placement. * * @dev_priv: Driver private. * @buf: DMA buffer to move. @@ -42,10 +42,10 @@ * Returns * -ERESTARTSYS if interrupted by a signal. */ -int vmw_dmabuf_pin_in_placement(struct vmw_private *dev_priv, - struct vmw_dma_buffer *buf, - struct ttm_placement *placement, - bool interruptible) +int vmw_bo_pin_in_placement(struct vmw_private *dev_priv, + struct vmw_buffer_object *buf, + struct ttm_placement *placement, + bool interruptible) { struct ttm_operation_ctx ctx = {interruptible, false }; struct ttm_buffer_object *bo = &buf->base; @@ -79,7 +79,7 @@ int vmw_dmabuf_pin_in_placement(struct vmw_private *dev_priv, } /** - * vmw_dmabuf_pin_in_vram_or_gmr - Move a buffer to vram or gmr. + * vmw_bo_pin_in_vram_or_gmr - Move a buffer to vram or gmr. * * This function takes the reservation_sem in write mode. * Flushes and unpins the query bo to avoid failures. @@ -92,9 +92,9 @@ int vmw_dmabuf_pin_in_placement(struct vmw_private *dev_priv, * Returns * -ERESTARTSYS if interrupted by a signal. */ -int vmw_dmabuf_pin_in_vram_or_gmr(struct vmw_private *dev_priv, - struct vmw_dma_buffer *buf, - bool interruptible) +int vmw_bo_pin_in_vram_or_gmr(struct vmw_private *dev_priv, + struct vmw_buffer_object *buf, + bool interruptible) { struct ttm_operation_ctx ctx = {interruptible, false }; struct ttm_buffer_object *bo = &buf->base; @@ -134,7 +134,7 @@ int vmw_dmabuf_pin_in_vram_or_gmr(struct vmw_private *dev_priv, } /** - * vmw_dmabuf_pin_in_vram - Move a buffer to vram. + * vmw_bo_pin_in_vram - Move a buffer to vram. * * This function takes the reservation_sem in write mode. * Flushes and unpins the query bo to avoid failures. @@ -146,16 +146,16 @@ int vmw_dmabuf_pin_in_vram_or_gmr(struct vmw_private *dev_priv, * Returns * -ERESTARTSYS if interrupted by a signal. */ -int vmw_dmabuf_pin_in_vram(struct vmw_private *dev_priv, - struct vmw_dma_buffer *buf, - bool interruptible) +int vmw_bo_pin_in_vram(struct vmw_private *dev_priv, + struct vmw_buffer_object *buf, + bool interruptible) { - return vmw_dmabuf_pin_in_placement(dev_priv, buf, &vmw_vram_placement, - interruptible); + return vmw_bo_pin_in_placement(dev_priv, buf, &vmw_vram_placement, + interruptible); } /** - * vmw_dmabuf_pin_in_start_of_vram - Move a buffer to start of vram. + * vmw_bo_pin_in_start_of_vram - Move a buffer to start of vram. * * This function takes the reservation_sem in write mode. * Flushes and unpins the query bo to avoid failures. @@ -167,9 +167,9 @@ int vmw_dmabuf_pin_in_vram(struct vmw_private *dev_priv, * Returns * -ERESTARTSYS if interrupted by a signal. */ -int vmw_dmabuf_pin_in_start_of_vram(struct vmw_private *dev_priv, - struct vmw_dma_buffer *buf, - bool interruptible) +int vmw_bo_pin_in_start_of_vram(struct vmw_private *dev_priv, + struct vmw_buffer_object *buf, + bool interruptible) { struct ttm_operation_ctx ctx = {interruptible, false }; struct ttm_buffer_object *bo = &buf->base; @@ -226,7 +226,7 @@ int vmw_dmabuf_pin_in_start_of_vram(struct vmw_private *dev_priv, } /** - * vmw_dmabuf_unpin - Unpin the buffer given buffer, does not move the buffer. + * vmw_bo_unpin - Unpin the buffer given buffer, does not move the buffer. * * This function takes the reservation_sem in write mode. * @@ -237,9 +237,9 @@ int vmw_dmabuf_pin_in_start_of_vram(struct vmw_private *dev_priv, * Returns * -ERESTARTSYS if interrupted by a signal. */ -int vmw_dmabuf_unpin(struct vmw_private *dev_priv, - struct vmw_dma_buffer *buf, - bool interruptible) +int vmw_bo_unpin(struct vmw_private *dev_priv, + struct vmw_buffer_object *buf, + bool interruptible) { struct ttm_buffer_object *bo = &buf->base; int ret; @@ -288,7 +288,7 @@ void vmw_bo_get_guest_ptr(const struct ttm_buffer_object *bo, * @pin: Whether to pin or unpin. * */ -void vmw_bo_pin_reserved(struct vmw_dma_buffer *vbo, bool pin) +void vmw_bo_pin_reserved(struct vmw_buffer_object *vbo, bool pin) { struct ttm_operation_ctx ctx = { false, true }; struct ttm_place pl; @@ -326,14 +326,14 @@ void vmw_bo_pin_reserved(struct vmw_dma_buffer *vbo, bool pin) /* - * vmw_dma_buffer_unmap - Tear down a cached buffer object map. + * vmw_buffer_object_unmap - Tear down a cached buffer object map. * * @vbo: The buffer object whose map we are tearing down. * * This function tears down a cached map set up using - * vmw_dma_buffer_map_and_cache(). + * vmw_buffer_object_map_and_cache(). */ -void vmw_dma_buffer_unmap(struct vmw_dma_buffer *vbo) +void vmw_buffer_object_unmap(struct vmw_buffer_object *vbo) { if (vbo->map.bo == NULL) return; @@ -343,7 +343,7 @@ void vmw_dma_buffer_unmap(struct vmw_dma_buffer *vbo) /* - * vmw_dma_buffer_map_and_cache - Map a buffer object and cache the map + * vmw_buffer_object_map_and_cache - Map a buffer object and cache the map * * @vbo: The buffer object to map * Return: A kernel virtual address or NULL if mapping failed. @@ -357,7 +357,7 @@ void vmw_dma_buffer_unmap(struct vmw_dma_buffer *vbo) * 3) Buffer object destruction * */ -void *vmw_dma_buffer_map_and_cache(struct vmw_dma_buffer *vbo) +void *vmw_buffer_object_map_and_cache(struct vmw_buffer_object *vbo) { struct ttm_buffer_object *bo = &vbo->base; bool not_used; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_context.c b/drivers/gpu/drm/vmwgfx/vmwgfx_context.c index 3767ac335acae..ff8acc74786cf 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_context.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_context.c @@ -38,7 +38,7 @@ struct vmw_user_context { struct vmw_cmdbuf_res_manager *man; struct vmw_resource *cotables[SVGA_COTABLE_DX10_MAX]; spinlock_t cotable_lock; - struct vmw_dma_buffer *dx_query_mob; + struct vmw_buffer_object *dx_query_mob; }; static void vmw_user_context_free(struct vmw_resource *res); @@ -900,7 +900,7 @@ vmw_context_binding_state(struct vmw_resource *ctx) * specified in the parameter. 0 otherwise. */ int vmw_context_bind_dx_query(struct vmw_resource *ctx_res, - struct vmw_dma_buffer *mob) + struct vmw_buffer_object *mob) { struct vmw_user_context *uctx = container_of(ctx_res, struct vmw_user_context, res); @@ -908,7 +908,7 @@ int vmw_context_bind_dx_query(struct vmw_resource *ctx_res, if (mob == NULL) { if (uctx->dx_query_mob) { uctx->dx_query_mob->dx_query_ctx = NULL; - vmw_dmabuf_unreference(&uctx->dx_query_mob); + vmw_bo_unreference(&uctx->dx_query_mob); uctx->dx_query_mob = NULL; } @@ -922,7 +922,7 @@ int vmw_context_bind_dx_query(struct vmw_resource *ctx_res, mob->dx_query_ctx = ctx_res; if (!uctx->dx_query_mob) - uctx->dx_query_mob = vmw_dmabuf_reference(mob); + uctx->dx_query_mob = vmw_bo_reference(mob); return 0; } @@ -932,7 +932,7 @@ int vmw_context_bind_dx_query(struct vmw_resource *ctx_res, * * @ctx_res: The context resource */ -struct vmw_dma_buffer * +struct vmw_buffer_object * vmw_context_get_dx_query_mob(struct vmw_resource *ctx_res) { struct vmw_user_context *uctx = diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c index cbf54ea7b4c0e..1052cd3cb7003 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c @@ -390,7 +390,7 @@ static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size) struct ttm_operation_ctx ctx = { false, false }; struct vmw_private *dev_priv = res->dev_priv; struct vmw_cotable *vcotbl = vmw_cotable(res); - struct vmw_dma_buffer *buf, *old_buf = res->backup; + struct vmw_buffer_object *buf, *old_buf = res->backup; struct ttm_buffer_object *bo, *old_bo = &res->backup->base; size_t old_size = res->backup_size; size_t old_size_read_back = vcotbl->size_read_back; @@ -415,8 +415,8 @@ static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size) if (!buf) return -ENOMEM; - ret = vmw_dmabuf_init(dev_priv, buf, new_size, &vmw_mob_ne_placement, - true, vmw_dmabuf_bo_free); + ret = vmw_bo_init(dev_priv, buf, new_size, &vmw_mob_ne_placement, + true, vmw_bo_bo_free); if (ret) { DRM_ERROR("Failed initializing new cotable MOB.\n"); return ret; @@ -482,7 +482,7 @@ static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size) /* Let go of the old mob. */ list_del(&res->mob_head); list_add_tail(&res->mob_head, &buf->res_list); - vmw_dmabuf_unreference(&old_buf); + vmw_bo_unreference(&old_buf); res->id = vcotbl->type; return 0; @@ -491,7 +491,7 @@ static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size) ttm_bo_kunmap(&old_map); out_wait: ttm_bo_unreserve(bo); - vmw_dmabuf_unreference(&buf); + vmw_bo_unreference(&buf); return ret; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 09cc721160c46..4f18304226bc4 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -153,9 +153,9 @@ static const struct drm_ioctl_desc vmw_ioctls[] = { VMW_IOCTL_DEF(VMW_GET_PARAM, vmw_getparam_ioctl, DRM_AUTH | DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_ALLOC_DMABUF, vmw_dmabuf_alloc_ioctl, + VMW_IOCTL_DEF(VMW_ALLOC_DMABUF, vmw_bo_alloc_ioctl, DRM_AUTH | DRM_RENDER_ALLOW), - VMW_IOCTL_DEF(VMW_UNREF_DMABUF, vmw_dmabuf_unref_ioctl, + VMW_IOCTL_DEF(VMW_UNREF_DMABUF, vmw_bo_unref_ioctl, DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_CURSOR_BYPASS, vmw_kms_cursor_bypass_ioctl, @@ -219,7 +219,7 @@ static const struct drm_ioctl_desc vmw_ioctls[] = { vmw_gb_surface_reference_ioctl, DRM_AUTH | DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_SYNCCPU, - vmw_user_dmabuf_synccpu_ioctl, + vmw_user_bo_synccpu_ioctl, DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_CREATE_EXTENDED_CONTEXT, vmw_extended_context_define_ioctl, @@ -321,7 +321,7 @@ static void vmw_print_capabilities(uint32_t capabilities) static int vmw_dummy_query_bo_create(struct vmw_private *dev_priv) { int ret; - struct vmw_dma_buffer *vbo; + struct vmw_buffer_object *vbo; struct ttm_bo_kmap_obj map; volatile SVGA3dQueryResult *result; bool dummy; @@ -335,9 +335,9 @@ static int vmw_dummy_query_bo_create(struct vmw_private *dev_priv) if (!vbo) return -ENOMEM; - ret = vmw_dmabuf_init(dev_priv, vbo, PAGE_SIZE, - &vmw_sys_ne_placement, false, - &vmw_dmabuf_bo_free); + ret = vmw_bo_init(dev_priv, vbo, PAGE_SIZE, + &vmw_sys_ne_placement, false, + &vmw_bo_bo_free); if (unlikely(ret != 0)) return ret; @@ -358,7 +358,7 @@ static int vmw_dummy_query_bo_create(struct vmw_private *dev_priv) if (unlikely(ret != 0)) { DRM_ERROR("Dummy query buffer map failed.\n"); - vmw_dmabuf_unreference(&vbo); + vmw_bo_unreference(&vbo); } else dev_priv->dummy_query_bo = vbo; @@ -460,7 +460,7 @@ static void vmw_release_device_early(struct vmw_private *dev_priv) BUG_ON(dev_priv->pinned_bo != NULL); - vmw_dmabuf_unreference(&dev_priv->dummy_query_bo); + vmw_bo_unreference(&dev_priv->dummy_query_bo); if (dev_priv->cman) vmw_cmdbuf_remove_pool(dev_priv->cman); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 5fcbe1620d50b..25c2f668ad6cc 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -86,7 +86,7 @@ struct vmw_fpriv { bool gb_aware; }; -struct vmw_dma_buffer { +struct vmw_buffer_object { struct ttm_buffer_object base; struct list_head res_list; s32 pin_count; @@ -120,7 +120,7 @@ struct vmw_resource { unsigned long backup_size; bool res_dirty; /* Protected by backup buffer reserved */ bool backup_dirty; /* Protected by backup buffer reserved */ - struct vmw_dma_buffer *backup; + struct vmw_buffer_object *backup; unsigned long backup_offset; unsigned long pin_count; /* Protected by resource reserved */ const struct vmw_res_func *func; @@ -304,7 +304,7 @@ struct vmw_sw_context{ uint32_t cmd_bounce_size; struct list_head resource_list; struct list_head ctx_resource_list; /* For contexts and cotables */ - struct vmw_dma_buffer *cur_query_bo; + struct vmw_buffer_object *cur_query_bo; struct list_head res_relocations; uint32_t *buf_start; struct vmw_res_cache_entry res_cache[vmw_res_max]; @@ -315,7 +315,7 @@ struct vmw_sw_context{ bool staged_bindings_inuse; struct list_head staged_cmd_res; struct vmw_resource_val_node *dx_ctx_node; - struct vmw_dma_buffer *dx_query_mob; + struct vmw_buffer_object *dx_query_mob; struct vmw_resource *dx_query_ctx; struct vmw_cmdbuf_res_manager *man; }; @@ -513,8 +513,8 @@ struct vmw_private { * are protected by the cmdbuf mutex. */ - struct vmw_dma_buffer *dummy_query_bo; - struct vmw_dma_buffer *pinned_bo; + struct vmw_buffer_object *dummy_query_bo; + struct vmw_buffer_object *pinned_bo; uint32_t query_cid; uint32_t query_cid_valid; bool dummy_query_bo_pinned; @@ -623,43 +623,43 @@ extern int vmw_user_lookup_handle(struct vmw_private *dev_priv, struct ttm_object_file *tfile, uint32_t handle, struct vmw_surface **out_surf, - struct vmw_dma_buffer **out_buf); + struct vmw_buffer_object **out_buf); extern int vmw_user_resource_lookup_handle( struct vmw_private *dev_priv, struct ttm_object_file *tfile, uint32_t handle, const struct vmw_user_resource_conv *converter, struct vmw_resource **p_res); -extern void vmw_dmabuf_bo_free(struct ttm_buffer_object *bo); -extern int vmw_dmabuf_init(struct vmw_private *dev_priv, - struct vmw_dma_buffer *vmw_bo, - size_t size, struct ttm_placement *placement, - bool interuptable, - void (*bo_free) (struct ttm_buffer_object *bo)); -extern int vmw_user_dmabuf_verify_access(struct ttm_buffer_object *bo, - struct ttm_object_file *tfile); -extern int vmw_user_dmabuf_alloc(struct vmw_private *dev_priv, - struct ttm_object_file *tfile, - uint32_t size, - bool shareable, - uint32_t *handle, - struct vmw_dma_buffer **p_dma_buf, - struct ttm_base_object **p_base); -extern int vmw_user_dmabuf_reference(struct ttm_object_file *tfile, - struct vmw_dma_buffer *dma_buf, - uint32_t *handle); -extern int vmw_dmabuf_alloc_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -extern int vmw_dmabuf_unref_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -extern int vmw_user_dmabuf_synccpu_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -extern uint32_t vmw_dmabuf_validate_node(struct ttm_buffer_object *bo, - uint32_t cur_validate_node); -extern void vmw_dmabuf_validate_clear(struct ttm_buffer_object *bo); -extern int vmw_user_dmabuf_lookup(struct ttm_object_file *tfile, - uint32_t id, struct vmw_dma_buffer **out, - struct ttm_base_object **base); +extern void vmw_bo_bo_free(struct ttm_buffer_object *bo); +extern int vmw_bo_init(struct vmw_private *dev_priv, + struct vmw_buffer_object *vmw_bo, + size_t size, struct ttm_placement *placement, + bool interuptable, + void (*bo_free)(struct ttm_buffer_object *bo)); +extern int vmw_user_bo_verify_access(struct ttm_buffer_object *bo, + struct ttm_object_file *tfile); +extern int vmw_user_bo_alloc(struct vmw_private *dev_priv, + struct ttm_object_file *tfile, + uint32_t size, + bool shareable, + uint32_t *handle, + struct vmw_buffer_object **p_dma_buf, + struct ttm_base_object **p_base); +extern int vmw_user_bo_reference(struct ttm_object_file *tfile, + struct vmw_buffer_object *dma_buf, + uint32_t *handle); +extern int vmw_bo_alloc_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int vmw_bo_unref_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int vmw_user_bo_synccpu_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern uint32_t vmw_bo_validate_node(struct ttm_buffer_object *bo, + uint32_t cur_validate_node); +extern void vmw_bo_validate_clear(struct ttm_buffer_object *bo); +extern int vmw_user_bo_lookup(struct ttm_object_file *tfile, + uint32_t id, struct vmw_buffer_object **out, + struct ttm_base_object **base); extern int vmw_stream_claim_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int vmw_stream_unref_ioctl(struct drm_device *dev, void *data, @@ -670,43 +670,43 @@ extern int vmw_user_stream_lookup(struct vmw_private *dev_priv, struct vmw_resource **out); extern void vmw_resource_unreserve(struct vmw_resource *res, bool switch_backup, - struct vmw_dma_buffer *new_backup, + struct vmw_buffer_object *new_backup, unsigned long new_backup_offset); extern void vmw_resource_move_notify(struct ttm_buffer_object *bo, struct ttm_mem_reg *mem); extern void vmw_query_move_notify(struct ttm_buffer_object *bo, struct ttm_mem_reg *mem); extern void vmw_resource_swap_notify(struct ttm_buffer_object *bo); -extern int vmw_query_readback_all(struct vmw_dma_buffer *dx_query_mob); +extern int vmw_query_readback_all(struct vmw_buffer_object *dx_query_mob); extern void vmw_fence_single_bo(struct ttm_buffer_object *bo, struct vmw_fence_obj *fence); extern void vmw_resource_evict_all(struct vmw_private *dev_priv); /** - * DMA buffer helper routines - vmwgfx_dmabuf.c + * Buffer object helper functions - vmwgfx_bo.c */ -extern int vmw_dmabuf_pin_in_placement(struct vmw_private *vmw_priv, - struct vmw_dma_buffer *bo, - struct ttm_placement *placement, +extern int vmw_bo_pin_in_placement(struct vmw_private *vmw_priv, + struct vmw_buffer_object *bo, + struct ttm_placement *placement, + bool interruptible); +extern int vmw_bo_pin_in_vram(struct vmw_private *dev_priv, + struct vmw_buffer_object *buf, + bool interruptible); +extern int vmw_bo_pin_in_vram_or_gmr(struct vmw_private *dev_priv, + struct vmw_buffer_object *buf, + bool interruptible); +extern int vmw_bo_pin_in_start_of_vram(struct vmw_private *vmw_priv, + struct vmw_buffer_object *bo, bool interruptible); -extern int vmw_dmabuf_pin_in_vram(struct vmw_private *dev_priv, - struct vmw_dma_buffer *buf, - bool interruptible); -extern int vmw_dmabuf_pin_in_vram_or_gmr(struct vmw_private *dev_priv, - struct vmw_dma_buffer *buf, - bool interruptible); -extern int vmw_dmabuf_pin_in_start_of_vram(struct vmw_private *vmw_priv, - struct vmw_dma_buffer *bo, - bool interruptible); -extern int vmw_dmabuf_unpin(struct vmw_private *vmw_priv, - struct vmw_dma_buffer *bo, - bool interruptible); +extern int vmw_bo_unpin(struct vmw_private *vmw_priv, + struct vmw_buffer_object *bo, + bool interruptible); extern void vmw_bo_get_guest_ptr(const struct ttm_buffer_object *buf, SVGAGuestPtr *ptr); -extern void vmw_bo_pin_reserved(struct vmw_dma_buffer *bo, bool pin); -extern void *vmw_dma_buffer_map_and_cache(struct vmw_dma_buffer *vbo); -extern void vmw_dma_buffer_unmap(struct vmw_dma_buffer *vbo); +extern void vmw_bo_pin_reserved(struct vmw_buffer_object *bo, bool pin); +extern void *vmw_buffer_object_map_and_cache(struct vmw_buffer_object *vbo); +extern void vmw_buffer_object_unmap(struct vmw_buffer_object *vbo); /** * Misc Ioctl functionality - vmwgfx_ioctl.c @@ -758,7 +758,7 @@ extern void vmw_ttm_global_release(struct vmw_private *dev_priv); extern int vmw_mmap(struct file *filp, struct vm_area_struct *vma); /** - * TTM buffer object driver - vmwgfx_buffer.c + * TTM buffer object driver - vmwgfx_ttm_buffer.c */ extern const size_t vmw_tt_size; @@ -1041,8 +1041,8 @@ vmw_context_binding_state(struct vmw_resource *ctx); extern void vmw_dx_context_scrub_cotables(struct vmw_resource *ctx, bool readback); extern int vmw_context_bind_dx_query(struct vmw_resource *ctx_res, - struct vmw_dma_buffer *mob); -extern struct vmw_dma_buffer * + struct vmw_buffer_object *mob); +extern struct vmw_buffer_object * vmw_context_get_dx_query_mob(struct vmw_resource *ctx_res); @@ -1243,9 +1243,9 @@ static inline struct vmw_surface *vmw_surface_reference(struct vmw_surface *srf) return srf; } -static inline void vmw_dmabuf_unreference(struct vmw_dma_buffer **buf) +static inline void vmw_bo_unreference(struct vmw_buffer_object **buf) { - struct vmw_dma_buffer *tmp_buf = *buf; + struct vmw_buffer_object *tmp_buf = *buf; *buf = NULL; if (tmp_buf != NULL) { @@ -1255,7 +1255,8 @@ static inline void vmw_dmabuf_unreference(struct vmw_dma_buffer **buf) } } -static inline struct vmw_dma_buffer *vmw_dmabuf_reference(struct vmw_dma_buffer *buf) +static inline struct vmw_buffer_object * +vmw_bo_reference(struct vmw_buffer_object *buf) { if (ttm_bo_reference(&buf->base)) return buf; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index c9d5cc237124e..a8b194655c402 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -92,7 +92,7 @@ struct vmw_resource_val_node { struct list_head head; struct drm_hash_item hash; struct vmw_resource *res; - struct vmw_dma_buffer *new_backup; + struct vmw_buffer_object *new_backup; struct vmw_ctx_binding_state *staged_bindings; unsigned long new_backup_offset; u32 first_usage : 1; @@ -126,9 +126,9 @@ static int vmw_resource_context_res_add(struct vmw_private *dev_priv, static int vmw_translate_mob_ptr(struct vmw_private *dev_priv, struct vmw_sw_context *sw_context, SVGAMobId *id, - struct vmw_dma_buffer **vmw_bo_p); + struct vmw_buffer_object **vmw_bo_p); static int vmw_bo_to_validate_list(struct vmw_sw_context *sw_context, - struct vmw_dma_buffer *vbo, + struct vmw_buffer_object *vbo, bool validate_as_mob, uint32_t *p_val_node); /** @@ -185,7 +185,7 @@ static void vmw_resources_unreserve(struct vmw_sw_context *sw_context, } vmw_resource_unreserve(res, switch_backup, val->new_backup, val->new_backup_offset); - vmw_dmabuf_unreference(&val->new_backup); + vmw_bo_unreference(&val->new_backup); } } @@ -423,7 +423,7 @@ static int vmw_resource_context_res_add(struct vmw_private *dev_priv, } if (dev_priv->has_dx && vmw_res_type(ctx) == vmw_res_dx_context) { - struct vmw_dma_buffer *dx_query_mob; + struct vmw_buffer_object *dx_query_mob; dx_query_mob = vmw_context_get_dx_query_mob(ctx); if (dx_query_mob) @@ -544,7 +544,7 @@ static int vmw_cmd_ok(struct vmw_private *dev_priv, * submission is reached. */ static int vmw_bo_to_validate_list(struct vmw_sw_context *sw_context, - struct vmw_dma_buffer *vbo, + struct vmw_buffer_object *vbo, bool validate_as_mob, uint32_t *p_val_node) { @@ -616,7 +616,7 @@ static int vmw_resources_reserve(struct vmw_sw_context *sw_context) return ret; if (res->backup) { - struct vmw_dma_buffer *vbo = res->backup; + struct vmw_buffer_object *vbo = res->backup; ret = vmw_bo_to_validate_list (sw_context, vbo, @@ -628,7 +628,7 @@ static int vmw_resources_reserve(struct vmw_sw_context *sw_context) } if (sw_context->dx_query_mob) { - struct vmw_dma_buffer *expected_dx_query_mob; + struct vmw_buffer_object *expected_dx_query_mob; expected_dx_query_mob = vmw_context_get_dx_query_mob(sw_context->dx_query_ctx); @@ -657,7 +657,7 @@ static int vmw_resources_validate(struct vmw_sw_context *sw_context) list_for_each_entry(val, &sw_context->resource_list, head) { struct vmw_resource *res = val->res; - struct vmw_dma_buffer *backup = res->backup; + struct vmw_buffer_object *backup = res->backup; ret = vmw_resource_validate(res); if (unlikely(ret != 0)) { @@ -668,7 +668,7 @@ static int vmw_resources_validate(struct vmw_sw_context *sw_context) /* Check if the resource switched backup buffer */ if (backup && res->backup && (backup != res->backup)) { - struct vmw_dma_buffer *vbo = res->backup; + struct vmw_buffer_object *vbo = res->backup; ret = vmw_bo_to_validate_list (sw_context, vbo, @@ -821,7 +821,7 @@ vmw_cmd_res_check(struct vmw_private *dev_priv, static int vmw_rebind_all_dx_query(struct vmw_resource *ctx_res) { struct vmw_private *dev_priv = ctx_res->dev_priv; - struct vmw_dma_buffer *dx_query_mob; + struct vmw_buffer_object *dx_query_mob; struct { SVGA3dCmdHeader header; SVGA3dCmdDXBindAllQuery body; @@ -1152,7 +1152,7 @@ static int vmw_cmd_present_check(struct vmw_private *dev_priv, * command batch. */ static int vmw_query_bo_switch_prepare(struct vmw_private *dev_priv, - struct vmw_dma_buffer *new_query_bo, + struct vmw_buffer_object *new_query_bo, struct vmw_sw_context *sw_context) { struct vmw_res_cache_entry *ctx_entry = @@ -1234,7 +1234,7 @@ static void vmw_query_bo_switch_commit(struct vmw_private *dev_priv, if (dev_priv->pinned_bo != sw_context->cur_query_bo) { if (dev_priv->pinned_bo) { vmw_bo_pin_reserved(dev_priv->pinned_bo, false); - vmw_dmabuf_unreference(&dev_priv->pinned_bo); + vmw_bo_unreference(&dev_priv->pinned_bo); } if (!sw_context->needs_post_query_barrier) { @@ -1256,7 +1256,7 @@ static void vmw_query_bo_switch_commit(struct vmw_private *dev_priv, dev_priv->query_cid = sw_context->last_query_ctx->id; dev_priv->query_cid_valid = true; dev_priv->pinned_bo = - vmw_dmabuf_reference(sw_context->cur_query_bo); + vmw_bo_reference(sw_context->cur_query_bo); } } } @@ -1282,15 +1282,14 @@ static void vmw_query_bo_switch_commit(struct vmw_private *dev_priv, static int vmw_translate_mob_ptr(struct vmw_private *dev_priv, struct vmw_sw_context *sw_context, SVGAMobId *id, - struct vmw_dma_buffer **vmw_bo_p) + struct vmw_buffer_object **vmw_bo_p) { - struct vmw_dma_buffer *vmw_bo = NULL; + struct vmw_buffer_object *vmw_bo = NULL; uint32_t handle = *id; struct vmw_relocation *reloc; int ret; - ret = vmw_user_dmabuf_lookup(sw_context->fp->tfile, handle, &vmw_bo, - NULL); + ret = vmw_user_bo_lookup(sw_context->fp->tfile, handle, &vmw_bo, NULL); if (unlikely(ret != 0)) { DRM_ERROR("Could not find or use MOB buffer.\n"); ret = -EINVAL; @@ -1316,7 +1315,7 @@ static int vmw_translate_mob_ptr(struct vmw_private *dev_priv, return 0; out_no_reloc: - vmw_dmabuf_unreference(&vmw_bo); + vmw_bo_unreference(&vmw_bo); *vmw_bo_p = NULL; return ret; } @@ -1343,15 +1342,14 @@ static int vmw_translate_mob_ptr(struct vmw_private *dev_priv, static int vmw_translate_guest_ptr(struct vmw_private *dev_priv, struct vmw_sw_context *sw_context, SVGAGuestPtr *ptr, - struct vmw_dma_buffer **vmw_bo_p) + struct vmw_buffer_object **vmw_bo_p) { - struct vmw_dma_buffer *vmw_bo = NULL; + struct vmw_buffer_object *vmw_bo = NULL; uint32_t handle = ptr->gmrId; struct vmw_relocation *reloc; int ret; - ret = vmw_user_dmabuf_lookup(sw_context->fp->tfile, handle, &vmw_bo, - NULL); + ret = vmw_user_bo_lookup(sw_context->fp->tfile, handle, &vmw_bo, NULL); if (unlikely(ret != 0)) { DRM_ERROR("Could not find or use GMR region.\n"); ret = -EINVAL; @@ -1376,7 +1374,7 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv, return 0; out_no_reloc: - vmw_dmabuf_unreference(&vmw_bo); + vmw_bo_unreference(&vmw_bo); *vmw_bo_p = NULL; return ret; } @@ -1447,7 +1445,7 @@ static int vmw_cmd_dx_bind_query(struct vmw_private *dev_priv, SVGA3dCmdDXBindQuery q; } *cmd; - struct vmw_dma_buffer *vmw_bo; + struct vmw_buffer_object *vmw_bo; int ret; @@ -1466,7 +1464,7 @@ static int vmw_cmd_dx_bind_query(struct vmw_private *dev_priv, sw_context->dx_query_mob = vmw_bo; sw_context->dx_query_ctx = sw_context->dx_ctx_node->res; - vmw_dmabuf_unreference(&vmw_bo); + vmw_bo_unreference(&vmw_bo); return ret; } @@ -1549,7 +1547,7 @@ static int vmw_cmd_end_gb_query(struct vmw_private *dev_priv, struct vmw_sw_context *sw_context, SVGA3dCmdHeader *header) { - struct vmw_dma_buffer *vmw_bo; + struct vmw_buffer_object *vmw_bo; struct vmw_query_cmd { SVGA3dCmdHeader header; SVGA3dCmdEndGBQuery q; @@ -1569,7 +1567,7 @@ static int vmw_cmd_end_gb_query(struct vmw_private *dev_priv, ret = vmw_query_bo_switch_prepare(dev_priv, vmw_bo, sw_context); - vmw_dmabuf_unreference(&vmw_bo); + vmw_bo_unreference(&vmw_bo); return ret; } @@ -1584,7 +1582,7 @@ static int vmw_cmd_end_query(struct vmw_private *dev_priv, struct vmw_sw_context *sw_context, SVGA3dCmdHeader *header) { - struct vmw_dma_buffer *vmw_bo; + struct vmw_buffer_object *vmw_bo; struct vmw_query_cmd { SVGA3dCmdHeader header; SVGA3dCmdEndQuery q; @@ -1623,7 +1621,7 @@ static int vmw_cmd_end_query(struct vmw_private *dev_priv, ret = vmw_query_bo_switch_prepare(dev_priv, vmw_bo, sw_context); - vmw_dmabuf_unreference(&vmw_bo); + vmw_bo_unreference(&vmw_bo); return ret; } @@ -1638,7 +1636,7 @@ static int vmw_cmd_wait_gb_query(struct vmw_private *dev_priv, struct vmw_sw_context *sw_context, SVGA3dCmdHeader *header) { - struct vmw_dma_buffer *vmw_bo; + struct vmw_buffer_object *vmw_bo; struct vmw_query_cmd { SVGA3dCmdHeader header; SVGA3dCmdWaitForGBQuery q; @@ -1656,7 +1654,7 @@ static int vmw_cmd_wait_gb_query(struct vmw_private *dev_priv, if (unlikely(ret != 0)) return ret; - vmw_dmabuf_unreference(&vmw_bo); + vmw_bo_unreference(&vmw_bo); return 0; } @@ -1671,7 +1669,7 @@ static int vmw_cmd_wait_query(struct vmw_private *dev_priv, struct vmw_sw_context *sw_context, SVGA3dCmdHeader *header) { - struct vmw_dma_buffer *vmw_bo; + struct vmw_buffer_object *vmw_bo; struct vmw_query_cmd { SVGA3dCmdHeader header; SVGA3dCmdWaitForQuery q; @@ -1708,7 +1706,7 @@ static int vmw_cmd_wait_query(struct vmw_private *dev_priv, if (unlikely(ret != 0)) return ret; - vmw_dmabuf_unreference(&vmw_bo); + vmw_bo_unreference(&vmw_bo); return 0; } @@ -1716,7 +1714,7 @@ static int vmw_cmd_dma(struct vmw_private *dev_priv, struct vmw_sw_context *sw_context, SVGA3dCmdHeader *header) { - struct vmw_dma_buffer *vmw_bo = NULL; + struct vmw_buffer_object *vmw_bo = NULL; struct vmw_surface *srf = NULL; struct vmw_dma_cmd { SVGA3dCmdHeader header; @@ -1768,7 +1766,7 @@ static int vmw_cmd_dma(struct vmw_private *dev_priv, header); out_no_surface: - vmw_dmabuf_unreference(&vmw_bo); + vmw_bo_unreference(&vmw_bo); return ret; } @@ -1887,7 +1885,7 @@ static int vmw_cmd_check_define_gmrfb(struct vmw_private *dev_priv, struct vmw_sw_context *sw_context, void *buf) { - struct vmw_dma_buffer *vmw_bo; + struct vmw_buffer_object *vmw_bo; int ret; struct { @@ -1901,7 +1899,7 @@ static int vmw_cmd_check_define_gmrfb(struct vmw_private *dev_priv, if (unlikely(ret != 0)) return ret; - vmw_dmabuf_unreference(&vmw_bo); + vmw_bo_unreference(&vmw_bo); return ret; } @@ -1928,7 +1926,7 @@ static int vmw_cmd_res_switch_backup(struct vmw_private *dev_priv, uint32_t *buf_id, unsigned long backup_offset) { - struct vmw_dma_buffer *dma_buf; + struct vmw_buffer_object *dma_buf; int ret; ret = vmw_translate_mob_ptr(dev_priv, sw_context, buf_id, &dma_buf); @@ -1939,7 +1937,7 @@ static int vmw_cmd_res_switch_backup(struct vmw_private *dev_priv, if (val_node->first_usage) val_node->no_buffer_needed = true; - vmw_dmabuf_unreference(&val_node->new_backup); + vmw_bo_unreference(&val_node->new_backup); val_node->new_backup = dma_buf; val_node->new_backup_offset = backup_offset; @@ -3701,8 +3699,8 @@ int vmw_validate_single_buffer(struct vmw_private *dev_priv, bool interruptible, bool validate_as_mob) { - struct vmw_dma_buffer *vbo = container_of(bo, struct vmw_dma_buffer, - base); + struct vmw_buffer_object *vbo = + container_of(bo, struct vmw_buffer_object, base); struct ttm_operation_ctx ctx = { interruptible, true }; int ret; @@ -4423,7 +4421,7 @@ void __vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv, ttm_bo_unref(&query_val.bo); ttm_bo_unref(&pinned_val.bo); - vmw_dmabuf_unreference(&dev_priv->pinned_bo); + vmw_bo_unreference(&dev_priv->pinned_bo); out_unlock: return; @@ -4432,7 +4430,7 @@ void __vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv, out_no_reserve: ttm_bo_unref(&query_val.bo); ttm_bo_unref(&pinned_val.bo); - vmw_dmabuf_unreference(&dev_priv->pinned_bo); + vmw_bo_unreference(&dev_priv->pinned_bo); } /** diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index 9b7e0aca5f847..dcde4985c5747 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -42,7 +42,7 @@ struct vmw_fb_par { void *vmalloc; struct mutex bo_mutex; - struct vmw_dma_buffer *vmw_bo; + struct vmw_buffer_object *vmw_bo; unsigned bo_size; struct drm_framebuffer *set_fb; struct drm_display_mode *set_mode; @@ -184,7 +184,7 @@ static void vmw_fb_dirty_flush(struct work_struct *work) struct drm_clip_rect clip; struct drm_framebuffer *cur_fb; u8 *src_ptr, *dst_ptr; - struct vmw_dma_buffer *vbo = par->vmw_bo; + struct vmw_buffer_object *vbo = par->vmw_bo; void *virtual; if (!READ_ONCE(par->dirty.active)) @@ -197,7 +197,7 @@ static void vmw_fb_dirty_flush(struct work_struct *work) (void) ttm_read_lock(&vmw_priv->reservation_sem, false); (void) ttm_bo_reserve(&vbo->base, false, false, NULL); - virtual = vmw_dma_buffer_map_and_cache(vbo); + virtual = vmw_buffer_object_map_and_cache(vbo); if (!virtual) goto out_unreserve; @@ -391,9 +391,9 @@ static void vmw_fb_imageblit(struct fb_info *info, const struct fb_image *image) */ static int vmw_fb_create_bo(struct vmw_private *vmw_priv, - size_t size, struct vmw_dma_buffer **out) + size_t size, struct vmw_buffer_object **out) { - struct vmw_dma_buffer *vmw_bo; + struct vmw_buffer_object *vmw_bo; int ret; (void) ttm_write_lock(&vmw_priv->reservation_sem, false); @@ -404,10 +404,10 @@ static int vmw_fb_create_bo(struct vmw_private *vmw_priv, goto err_unlock; } - ret = vmw_dmabuf_init(vmw_priv, vmw_bo, size, + ret = vmw_bo_init(vmw_priv, vmw_bo, size, &vmw_sys_placement, false, - &vmw_dmabuf_bo_free); + &vmw_bo_bo_free); if (unlikely(ret != 0)) goto err_unlock; /* init frees the buffer on failure */ @@ -491,7 +491,7 @@ static int vmw_fb_kms_detach(struct vmw_fb_par *par, } if (par->vmw_bo && detach_bo && unref_bo) - vmw_dmabuf_unreference(&par->vmw_bo); + vmw_bo_unreference(&par->vmw_bo); return 0; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c index c5e8eae0dbe23..5e0c8f775c926 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c @@ -377,8 +377,8 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data, } vfb = vmw_framebuffer_to_vfb(fb); - if (!vfb->dmabuf) { - DRM_ERROR("Framebuffer not dmabuf backed.\n"); + if (!vfb->bo) { + DRM_ERROR("Framebuffer not buffer backed.\n"); ret = -EINVAL; goto out_no_ttm_lock; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index ef96ba7432ade..7a32be0cef14a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -85,10 +85,10 @@ static int vmw_cursor_update_image(struct vmw_private *dev_priv, return 0; } -static int vmw_cursor_update_dmabuf(struct vmw_private *dev_priv, - struct vmw_dma_buffer *dmabuf, - u32 width, u32 height, - u32 hotspotX, u32 hotspotY) +static int vmw_cursor_update_bo(struct vmw_private *dev_priv, + struct vmw_buffer_object *bo, + u32 width, u32 height, + u32 hotspotX, u32 hotspotY) { struct ttm_bo_kmap_obj map; unsigned long kmap_offset; @@ -100,13 +100,13 @@ static int vmw_cursor_update_dmabuf(struct vmw_private *dev_priv, kmap_offset = 0; kmap_num = (width*height*4 + PAGE_SIZE - 1) >> PAGE_SHIFT; - ret = ttm_bo_reserve(&dmabuf->base, true, false, NULL); + ret = ttm_bo_reserve(&bo->base, true, false, NULL); if (unlikely(ret != 0)) { DRM_ERROR("reserve failed\n"); return -EINVAL; } - ret = ttm_bo_kmap(&dmabuf->base, kmap_offset, kmap_num, &map); + ret = ttm_bo_kmap(&bo->base, kmap_offset, kmap_num, &map); if (unlikely(ret != 0)) goto err_unreserve; @@ -116,7 +116,7 @@ static int vmw_cursor_update_dmabuf(struct vmw_private *dev_priv, ttm_bo_kunmap(&map); err_unreserve: - ttm_bo_unreserve(&dmabuf->base); + ttm_bo_unreserve(&bo->base); return ret; } @@ -352,13 +352,13 @@ vmw_du_cursor_plane_prepare_fb(struct drm_plane *plane, if (vps->surf) vmw_surface_unreference(&vps->surf); - if (vps->dmabuf) - vmw_dmabuf_unreference(&vps->dmabuf); + if (vps->bo) + vmw_bo_unreference(&vps->bo); if (fb) { - if (vmw_framebuffer_to_vfb(fb)->dmabuf) { - vps->dmabuf = vmw_framebuffer_to_vfbd(fb)->buffer; - vmw_dmabuf_reference(vps->dmabuf); + if (vmw_framebuffer_to_vfb(fb)->bo) { + vps->bo = vmw_framebuffer_to_vfbd(fb)->buffer; + vmw_bo_reference(vps->bo); } else { vps->surf = vmw_framebuffer_to_vfbs(fb)->surface; vmw_surface_reference(vps->surf); @@ -390,7 +390,7 @@ vmw_du_cursor_plane_atomic_update(struct drm_plane *plane, } du->cursor_surface = vps->surf; - du->cursor_dmabuf = vps->dmabuf; + du->cursor_bo = vps->bo; if (vps->surf) { du->cursor_age = du->cursor_surface->snooper.age; @@ -399,11 +399,11 @@ vmw_du_cursor_plane_atomic_update(struct drm_plane *plane, vps->surf->snooper.image, 64, 64, hotspot_x, hotspot_y); - } else if (vps->dmabuf) { - ret = vmw_cursor_update_dmabuf(dev_priv, vps->dmabuf, - plane->state->crtc_w, - plane->state->crtc_h, - hotspot_x, hotspot_y); + } else if (vps->bo) { + ret = vmw_cursor_update_bo(dev_priv, vps->bo, + plane->state->crtc_w, + plane->state->crtc_h, + hotspot_x, hotspot_y); } else { vmw_cursor_update_position(dev_priv, false, 0, 0); return; @@ -519,7 +519,7 @@ int vmw_du_cursor_plane_atomic_check(struct drm_plane *plane, ret = -EINVAL; } - if (!vmw_framebuffer_to_vfb(fb)->dmabuf) + if (!vmw_framebuffer_to_vfb(fb)->bo) surface = vmw_framebuffer_to_vfbs(fb)->surface; if (surface && !surface->snooper.image) { @@ -687,8 +687,8 @@ vmw_du_plane_duplicate_state(struct drm_plane *plane) if (vps->surf) (void) vmw_surface_reference(vps->surf); - if (vps->dmabuf) - (void) vmw_dmabuf_reference(vps->dmabuf); + if (vps->bo) + (void) vmw_bo_reference(vps->bo); state = &vps->base; @@ -745,8 +745,8 @@ vmw_du_plane_destroy_state(struct drm_plane *plane, if (vps->surf) vmw_surface_unreference(&vps->surf); - if (vps->dmabuf) - vmw_dmabuf_unreference(&vps->dmabuf); + if (vps->bo) + vmw_bo_unreference(&vps->bo); drm_atomic_helper_plane_destroy_state(plane, state); } @@ -902,12 +902,12 @@ static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer, /** * vmw_kms_readback - Perform a readback from the screen system to - * a dma-buffer backed framebuffer. + * a buffer-object backed framebuffer. * * @dev_priv: Pointer to the device private structure. * @file_priv: Pointer to a struct drm_file identifying the caller. * Must be set to NULL if @user_fence_rep is NULL. - * @vfb: Pointer to the dma-buffer backed framebuffer. + * @vfb: Pointer to the buffer-object backed framebuffer. * @user_fence_rep: User-space provided structure for fence information. * Must be set to non-NULL if @file_priv is non-NULL. * @vclips: Array of clip rects. @@ -951,7 +951,7 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, struct vmw_framebuffer **out, const struct drm_mode_fb_cmd2 *mode_cmd, - bool is_dmabuf_proxy) + bool is_bo_proxy) { struct drm_device *dev = dev_priv->dev; @@ -1019,7 +1019,7 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, drm_helper_mode_fill_fb_struct(dev, &vfbs->base.base, mode_cmd); vfbs->surface = vmw_surface_reference(surface); vfbs->base.user_handle = mode_cmd->handles[0]; - vfbs->is_dmabuf_proxy = is_dmabuf_proxy; + vfbs->is_bo_proxy = is_bo_proxy; *out = &vfbs->base; @@ -1038,30 +1038,30 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, } /* - * Dmabuf framebuffer code + * Buffer-object framebuffer code */ -static void vmw_framebuffer_dmabuf_destroy(struct drm_framebuffer *framebuffer) +static void vmw_framebuffer_bo_destroy(struct drm_framebuffer *framebuffer) { - struct vmw_framebuffer_dmabuf *vfbd = + struct vmw_framebuffer_bo *vfbd = vmw_framebuffer_to_vfbd(framebuffer); drm_framebuffer_cleanup(framebuffer); - vmw_dmabuf_unreference(&vfbd->buffer); + vmw_bo_unreference(&vfbd->buffer); if (vfbd->base.user_obj) ttm_base_object_unref(&vfbd->base.user_obj); kfree(vfbd); } -static int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer, - struct drm_file *file_priv, - unsigned flags, unsigned color, - struct drm_clip_rect *clips, - unsigned num_clips) +static int vmw_framebuffer_bo_dirty(struct drm_framebuffer *framebuffer, + struct drm_file *file_priv, + unsigned int flags, unsigned int color, + struct drm_clip_rect *clips, + unsigned int num_clips) { struct vmw_private *dev_priv = vmw_priv(framebuffer->dev); - struct vmw_framebuffer_dmabuf *vfbd = + struct vmw_framebuffer_bo *vfbd = vmw_framebuffer_to_vfbd(framebuffer); struct drm_clip_rect norect; int ret, increment = 1; @@ -1092,13 +1092,13 @@ static int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer, true, true, NULL); break; case vmw_du_screen_object: - ret = vmw_kms_sou_do_dmabuf_dirty(dev_priv, &vfbd->base, - clips, NULL, num_clips, - increment, true, NULL, NULL); + ret = vmw_kms_sou_do_bo_dirty(dev_priv, &vfbd->base, + clips, NULL, num_clips, + increment, true, NULL, NULL); break; case vmw_du_legacy: - ret = vmw_kms_ldu_do_dmabuf_dirty(dev_priv, &vfbd->base, 0, 0, - clips, num_clips, increment); + ret = vmw_kms_ldu_do_bo_dirty(dev_priv, &vfbd->base, 0, 0, + clips, num_clips, increment); break; default: ret = -EINVAL; @@ -1114,23 +1114,23 @@ static int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer, return ret; } -static const struct drm_framebuffer_funcs vmw_framebuffer_dmabuf_funcs = { - .destroy = vmw_framebuffer_dmabuf_destroy, - .dirty = vmw_framebuffer_dmabuf_dirty, +static const struct drm_framebuffer_funcs vmw_framebuffer_bo_funcs = { + .destroy = vmw_framebuffer_bo_destroy, + .dirty = vmw_framebuffer_bo_dirty, }; /** - * Pin the dmabuffer in a location suitable for access by the + * Pin the bofer in a location suitable for access by the * display system. */ static int vmw_framebuffer_pin(struct vmw_framebuffer *vfb) { struct vmw_private *dev_priv = vmw_priv(vfb->base.dev); - struct vmw_dma_buffer *buf; + struct vmw_buffer_object *buf; struct ttm_placement *placement; int ret; - buf = vfb->dmabuf ? vmw_framebuffer_to_vfbd(&vfb->base)->buffer : + buf = vfb->bo ? vmw_framebuffer_to_vfbd(&vfb->base)->buffer : vmw_framebuffer_to_vfbs(&vfb->base)->surface->res.backup; if (!buf) @@ -1139,12 +1139,12 @@ static int vmw_framebuffer_pin(struct vmw_framebuffer *vfb) switch (dev_priv->active_display_unit) { case vmw_du_legacy: vmw_overlay_pause_all(dev_priv); - ret = vmw_dmabuf_pin_in_start_of_vram(dev_priv, buf, false); + ret = vmw_bo_pin_in_start_of_vram(dev_priv, buf, false); vmw_overlay_resume_all(dev_priv); break; case vmw_du_screen_object: case vmw_du_screen_target: - if (vfb->dmabuf) { + if (vfb->bo) { if (dev_priv->capabilities & SVGA_CAP_3D) { /* * Use surface DMA to get content to @@ -1160,8 +1160,7 @@ static int vmw_framebuffer_pin(struct vmw_framebuffer *vfb) placement = &vmw_mob_placement; } - return vmw_dmabuf_pin_in_placement(dev_priv, buf, placement, - false); + return vmw_bo_pin_in_placement(dev_priv, buf, placement, false); default: return -EINVAL; } @@ -1172,36 +1171,36 @@ static int vmw_framebuffer_pin(struct vmw_framebuffer *vfb) static int vmw_framebuffer_unpin(struct vmw_framebuffer *vfb) { struct vmw_private *dev_priv = vmw_priv(vfb->base.dev); - struct vmw_dma_buffer *buf; + struct vmw_buffer_object *buf; - buf = vfb->dmabuf ? vmw_framebuffer_to_vfbd(&vfb->base)->buffer : + buf = vfb->bo ? vmw_framebuffer_to_vfbd(&vfb->base)->buffer : vmw_framebuffer_to_vfbs(&vfb->base)->surface->res.backup; if (WARN_ON(!buf)) return 0; - return vmw_dmabuf_unpin(dev_priv, buf, false); + return vmw_bo_unpin(dev_priv, buf, false); } /** - * vmw_create_dmabuf_proxy - create a proxy surface for the DMA buf + * vmw_create_bo_proxy - create a proxy surface for the buffer object * * @dev: DRM device * @mode_cmd: parameters for the new surface - * @dmabuf_mob: MOB backing the DMA buf + * @bo_mob: MOB backing the buffer object * @srf_out: newly created surface * - * When the content FB is a DMA buf, we create a surface as a proxy to the + * When the content FB is a buffer object, we create a surface as a proxy to the * same buffer. This way we can do a surface copy rather than a surface DMA. * This is a more efficient approach * * RETURNS: * 0 on success, error code otherwise */ -static int vmw_create_dmabuf_proxy(struct drm_device *dev, - const struct drm_mode_fb_cmd2 *mode_cmd, - struct vmw_dma_buffer *dmabuf_mob, - struct vmw_surface **srf_out) +static int vmw_create_bo_proxy(struct drm_device *dev, + const struct drm_mode_fb_cmd2 *mode_cmd, + struct vmw_buffer_object *bo_mob, + struct vmw_surface **srf_out) { uint32_t format; struct drm_vmw_size content_base_size = {0}; @@ -1258,8 +1257,8 @@ static int vmw_create_dmabuf_proxy(struct drm_device *dev, /* Reserve and switch the backing mob. */ mutex_lock(&res->dev_priv->cmdbuf_mutex); (void) vmw_resource_reserve(res, false, true); - vmw_dmabuf_unreference(&res->backup); - res->backup = vmw_dmabuf_reference(dmabuf_mob); + vmw_bo_unreference(&res->backup); + res->backup = vmw_bo_reference(bo_mob); res->backup_offset = 0; vmw_resource_unreserve(res, false, NULL, 0); mutex_unlock(&res->dev_priv->cmdbuf_mutex); @@ -1269,21 +1268,21 @@ static int vmw_create_dmabuf_proxy(struct drm_device *dev, -static int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv, - struct vmw_dma_buffer *dmabuf, - struct vmw_framebuffer **out, - const struct drm_mode_fb_cmd2 - *mode_cmd) +static int vmw_kms_new_framebuffer_bo(struct vmw_private *dev_priv, + struct vmw_buffer_object *bo, + struct vmw_framebuffer **out, + const struct drm_mode_fb_cmd2 + *mode_cmd) { struct drm_device *dev = dev_priv->dev; - struct vmw_framebuffer_dmabuf *vfbd; + struct vmw_framebuffer_bo *vfbd; unsigned int requested_size; struct drm_format_name_buf format_name; int ret; requested_size = mode_cmd->height * mode_cmd->pitches[0]; - if (unlikely(requested_size > dmabuf->base.num_pages * PAGE_SIZE)) { + if (unlikely(requested_size > bo->base.num_pages * PAGE_SIZE)) { DRM_ERROR("Screen buffer object size is too small " "for requested mode.\n"); return -EINVAL; @@ -1312,20 +1311,20 @@ static int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv, } drm_helper_mode_fill_fb_struct(dev, &vfbd->base.base, mode_cmd); - vfbd->base.dmabuf = true; - vfbd->buffer = vmw_dmabuf_reference(dmabuf); + vfbd->base.bo = true; + vfbd->buffer = vmw_bo_reference(bo); vfbd->base.user_handle = mode_cmd->handles[0]; *out = &vfbd->base; ret = drm_framebuffer_init(dev, &vfbd->base.base, - &vmw_framebuffer_dmabuf_funcs); + &vmw_framebuffer_bo_funcs); if (ret) goto out_err2; return 0; out_err2: - vmw_dmabuf_unreference(&dmabuf); + vmw_bo_unreference(&bo); kfree(vfbd); out_err1: return ret; @@ -1354,57 +1353,57 @@ vmw_kms_srf_ok(struct vmw_private *dev_priv, uint32_t width, uint32_t height) * vmw_kms_new_framebuffer - Create a new framebuffer. * * @dev_priv: Pointer to device private struct. - * @dmabuf: Pointer to dma buffer to wrap the kms framebuffer around. - * Either @dmabuf or @surface must be NULL. + * @bo: Pointer to buffer object to wrap the kms framebuffer around. + * Either @bo or @surface must be NULL. * @surface: Pointer to a surface to wrap the kms framebuffer around. - * Either @dmabuf or @surface must be NULL. - * @only_2d: No presents will occur to this dma buffer based framebuffer. This - * Helps the code to do some important optimizations. + * Either @bo or @surface must be NULL. + * @only_2d: No presents will occur to this buffer object based framebuffer. + * This helps the code to do some important optimizations. * @mode_cmd: Frame-buffer metadata. */ struct vmw_framebuffer * vmw_kms_new_framebuffer(struct vmw_private *dev_priv, - struct vmw_dma_buffer *dmabuf, + struct vmw_buffer_object *bo, struct vmw_surface *surface, bool only_2d, const struct drm_mode_fb_cmd2 *mode_cmd) { struct vmw_framebuffer *vfb = NULL; - bool is_dmabuf_proxy = false; + bool is_bo_proxy = false; int ret; /* * We cannot use the SurfaceDMA command in an non-accelerated VM, - * therefore, wrap the DMA buf in a surface so we can use the + * therefore, wrap the buffer object in a surface so we can use the * SurfaceCopy command. */ if (vmw_kms_srf_ok(dev_priv, mode_cmd->width, mode_cmd->height) && - dmabuf && only_2d && + bo && only_2d && mode_cmd->width > 64 && /* Don't create a proxy for cursor */ dev_priv->active_display_unit == vmw_du_screen_target) { - ret = vmw_create_dmabuf_proxy(dev_priv->dev, mode_cmd, - dmabuf, &surface); + ret = vmw_create_bo_proxy(dev_priv->dev, mode_cmd, + bo, &surface); if (ret) return ERR_PTR(ret); - is_dmabuf_proxy = true; + is_bo_proxy = true; } /* Create the new framebuffer depending one what we have */ if (surface) { ret = vmw_kms_new_framebuffer_surface(dev_priv, surface, &vfb, mode_cmd, - is_dmabuf_proxy); + is_bo_proxy); /* - * vmw_create_dmabuf_proxy() adds a reference that is no longer + * vmw_create_bo_proxy() adds a reference that is no longer * needed */ - if (is_dmabuf_proxy) + if (is_bo_proxy) vmw_surface_unreference(&surface); - } else if (dmabuf) { - ret = vmw_kms_new_framebuffer_dmabuf(dev_priv, dmabuf, &vfb, - mode_cmd); + } else if (bo) { + ret = vmw_kms_new_framebuffer_bo(dev_priv, bo, &vfb, + mode_cmd); } else { BUG(); } @@ -1430,7 +1429,7 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; struct vmw_framebuffer *vfb = NULL; struct vmw_surface *surface = NULL; - struct vmw_dma_buffer *bo = NULL; + struct vmw_buffer_object *bo = NULL; struct ttm_base_object *user_obj; int ret; @@ -1466,7 +1465,7 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, * End conditioned code. */ - /* returns either a dmabuf or surface */ + /* returns either a bo or surface */ ret = vmw_user_lookup_handle(dev_priv, tfile, mode_cmd->handles[0], &surface, &bo); @@ -1494,7 +1493,7 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, err_out: /* vmw_user_lookup_handle takes one ref so does new_fb */ if (bo) - vmw_dmabuf_unreference(&bo); + vmw_bo_unreference(&bo); if (surface) vmw_surface_unreference(&surface); @@ -2427,7 +2426,7 @@ int vmw_kms_helper_dirty(struct vmw_private *dev_priv, * interrupted by a signal. */ int vmw_kms_helper_buffer_prepare(struct vmw_private *dev_priv, - struct vmw_dma_buffer *buf, + struct vmw_buffer_object *buf, bool interruptible, bool validate_as_mob, bool for_cpu_blit) @@ -2459,7 +2458,7 @@ int vmw_kms_helper_buffer_prepare(struct vmw_private *dev_priv, * Helper to be used if an error forces the caller to undo the actions of * vmw_kms_helper_buffer_prepare. */ -void vmw_kms_helper_buffer_revert(struct vmw_dma_buffer *buf) +void vmw_kms_helper_buffer_revert(struct vmw_buffer_object *buf) { if (buf) ttm_bo_unreserve(&buf->base); @@ -2482,7 +2481,7 @@ void vmw_kms_helper_buffer_revert(struct vmw_dma_buffer *buf) */ void vmw_kms_helper_buffer_finish(struct vmw_private *dev_priv, struct drm_file *file_priv, - struct vmw_dma_buffer *buf, + struct vmw_buffer_object *buf, struct vmw_fence_obj **out_fence, struct drm_vmw_fence_rep __user * user_fence_rep) @@ -2522,7 +2521,7 @@ void vmw_kms_helper_resource_revert(struct vmw_validation_ctx *ctx) struct vmw_resource *res = ctx->res; vmw_kms_helper_buffer_revert(ctx->buf); - vmw_dmabuf_unreference(&ctx->buf); + vmw_bo_unreference(&ctx->buf); vmw_resource_unreserve(res, false, NULL, 0); mutex_unlock(&res->dev_priv->cmdbuf_mutex); } @@ -2567,7 +2566,7 @@ int vmw_kms_helper_resource_prepare(struct vmw_resource *res, if (ret) goto out_unreserve; - ctx->buf = vmw_dmabuf_reference(res->backup); + ctx->buf = vmw_bo_reference(res->backup); } ret = vmw_resource_validate(res); if (ret) @@ -2600,7 +2599,7 @@ void vmw_kms_helper_resource_finish(struct vmw_validation_ctx *ctx, vmw_kms_helper_buffer_finish(res->dev_priv, NULL, ctx->buf, out_fence, NULL); - vmw_dmabuf_unreference(&ctx->buf); + vmw_bo_unreference(&ctx->buf); vmw_resource_unreserve(res, false, NULL, 0); mutex_unlock(&res->dev_priv->cmdbuf_mutex); } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index 6b7c012719f13..ff1caed38f94e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -90,7 +90,7 @@ struct vmw_kms_dirty { #define vmw_framebuffer_to_vfbs(x) \ container_of(x, struct vmw_framebuffer_surface, base.base) #define vmw_framebuffer_to_vfbd(x) \ - container_of(x, struct vmw_framebuffer_dmabuf, base.base) + container_of(x, struct vmw_framebuffer_bo, base.base) /** * Base class for framebuffers @@ -102,7 +102,7 @@ struct vmw_framebuffer { struct drm_framebuffer base; int (*pin)(struct vmw_framebuffer *fb); int (*unpin)(struct vmw_framebuffer *fb); - bool dmabuf; + bool bo; struct ttm_base_object *user_obj; uint32_t user_handle; }; @@ -117,15 +117,15 @@ struct vmw_clip_rect { struct vmw_framebuffer_surface { struct vmw_framebuffer base; struct vmw_surface *surface; - struct vmw_dma_buffer *buffer; + struct vmw_buffer_object *buffer; struct list_head head; - bool is_dmabuf_proxy; /* true if this is proxy surface for DMA buf */ + bool is_bo_proxy; /* true if this is proxy surface for DMA buf */ }; -struct vmw_framebuffer_dmabuf { +struct vmw_framebuffer_bo { struct vmw_framebuffer base; - struct vmw_dma_buffer *buffer; + struct vmw_buffer_object *buffer; }; @@ -161,18 +161,18 @@ struct vmw_crtc_state { * * @base DRM plane object * @surf Display surface for STDU - * @dmabuf display dmabuf for SOU + * @bo display bo for SOU * @content_fb_type Used by STDU. - * @dmabuf_size Size of the dmabuf, used by Screen Object Display Unit + * @bo_size Size of the bo, used by Screen Object Display Unit * @pinned pin count for STDU display surface */ struct vmw_plane_state { struct drm_plane_state base; struct vmw_surface *surf; - struct vmw_dma_buffer *dmabuf; + struct vmw_buffer_object *bo; int content_fb_type; - unsigned long dmabuf_size; + unsigned long bo_size; int pinned; @@ -209,7 +209,7 @@ struct vmw_display_unit { struct drm_plane cursor; struct vmw_surface *cursor_surface; - struct vmw_dma_buffer *cursor_dmabuf; + struct vmw_buffer_object *cursor_bo; size_t cursor_age; int cursor_x; @@ -243,7 +243,7 @@ struct vmw_display_unit { struct vmw_validation_ctx { struct vmw_resource *res; - struct vmw_dma_buffer *buf; + struct vmw_buffer_object *buf; }; #define vmw_crtc_to_du(x) \ @@ -291,14 +291,14 @@ int vmw_kms_helper_dirty(struct vmw_private *dev_priv, struct vmw_kms_dirty *dirty); int vmw_kms_helper_buffer_prepare(struct vmw_private *dev_priv, - struct vmw_dma_buffer *buf, + struct vmw_buffer_object *buf, bool interruptible, bool validate_as_mob, bool for_cpu_blit); -void vmw_kms_helper_buffer_revert(struct vmw_dma_buffer *buf); +void vmw_kms_helper_buffer_revert(struct vmw_buffer_object *buf); void vmw_kms_helper_buffer_finish(struct vmw_private *dev_priv, struct drm_file *file_priv, - struct vmw_dma_buffer *buf, + struct vmw_buffer_object *buf, struct vmw_fence_obj **out_fence, struct drm_vmw_fence_rep __user * user_fence_rep); @@ -316,7 +316,7 @@ int vmw_kms_readback(struct vmw_private *dev_priv, uint32_t num_clips); struct vmw_framebuffer * vmw_kms_new_framebuffer(struct vmw_private *dev_priv, - struct vmw_dma_buffer *dmabuf, + struct vmw_buffer_object *bo, struct vmw_surface *surface, bool only_2d, const struct drm_mode_fb_cmd2 *mode_cmd); @@ -384,11 +384,11 @@ void vmw_du_connector_destroy_state(struct drm_connector *connector, */ int vmw_kms_ldu_init_display(struct vmw_private *dev_priv); int vmw_kms_ldu_close_display(struct vmw_private *dev_priv); -int vmw_kms_ldu_do_dmabuf_dirty(struct vmw_private *dev_priv, - struct vmw_framebuffer *framebuffer, - unsigned flags, unsigned color, - struct drm_clip_rect *clips, - unsigned num_clips, int increment); +int vmw_kms_ldu_do_bo_dirty(struct vmw_private *dev_priv, + struct vmw_framebuffer *framebuffer, + unsigned int flags, unsigned int color, + struct drm_clip_rect *clips, + unsigned int num_clips, int increment); int vmw_kms_update_proxy(struct vmw_resource *res, const struct drm_clip_rect *clips, unsigned num_clips, @@ -408,14 +408,14 @@ int vmw_kms_sou_do_surface_dirty(struct vmw_private *dev_priv, unsigned num_clips, int inc, struct vmw_fence_obj **out_fence, struct drm_crtc *crtc); -int vmw_kms_sou_do_dmabuf_dirty(struct vmw_private *dev_priv, - struct vmw_framebuffer *framebuffer, - struct drm_clip_rect *clips, - struct drm_vmw_rect *vclips, - unsigned num_clips, int increment, - bool interruptible, - struct vmw_fence_obj **out_fence, - struct drm_crtc *crtc); +int vmw_kms_sou_do_bo_dirty(struct vmw_private *dev_priv, + struct vmw_framebuffer *framebuffer, + struct drm_clip_rect *clips, + struct drm_vmw_rect *vclips, + unsigned int num_clips, int increment, + bool interruptible, + struct vmw_fence_obj **out_fence, + struct drm_crtc *crtc); int vmw_kms_sou_readback(struct vmw_private *dev_priv, struct drm_file *file_priv, struct vmw_framebuffer *vfb, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index 4a5907e3f5602..a2dd9a8292194 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -547,11 +547,11 @@ int vmw_kms_ldu_close_display(struct vmw_private *dev_priv) } -int vmw_kms_ldu_do_dmabuf_dirty(struct vmw_private *dev_priv, - struct vmw_framebuffer *framebuffer, - unsigned flags, unsigned color, - struct drm_clip_rect *clips, - unsigned num_clips, int increment) +int vmw_kms_ldu_do_bo_dirty(struct vmw_private *dev_priv, + struct vmw_framebuffer *framebuffer, + unsigned int flags, unsigned int color, + struct drm_clip_rect *clips, + unsigned int num_clips, int increment) { size_t fifo_size; int i; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c index 222c9c2123a1e..09420ef19ecbb 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c @@ -38,7 +38,7 @@ #define VMW_OVERLAY_CAP_MASK (SVGA_FIFO_CAP_VIDEO | SVGA_FIFO_CAP_ESCAPE) struct vmw_stream { - struct vmw_dma_buffer *buf; + struct vmw_buffer_object *buf; bool claimed; bool paused; struct drm_vmw_control_stream_arg saved; @@ -94,7 +94,7 @@ static inline void fill_flush(struct vmw_escape_video_flush *cmd, * -ERESTARTSYS if interrupted by a signal. */ static int vmw_overlay_send_put(struct vmw_private *dev_priv, - struct vmw_dma_buffer *buf, + struct vmw_buffer_object *buf, struct drm_vmw_control_stream_arg *arg, bool interruptible) { @@ -225,16 +225,16 @@ static int vmw_overlay_send_stop(struct vmw_private *dev_priv, * used with GMRs instead of being locked to vram. */ static int vmw_overlay_move_buffer(struct vmw_private *dev_priv, - struct vmw_dma_buffer *buf, + struct vmw_buffer_object *buf, bool pin, bool inter) { if (!pin) - return vmw_dmabuf_unpin(dev_priv, buf, inter); + return vmw_bo_unpin(dev_priv, buf, inter); if (dev_priv->active_display_unit == vmw_du_legacy) - return vmw_dmabuf_pin_in_vram(dev_priv, buf, inter); + return vmw_bo_pin_in_vram(dev_priv, buf, inter); - return vmw_dmabuf_pin_in_vram_or_gmr(dev_priv, buf, inter); + return vmw_bo_pin_in_vram_or_gmr(dev_priv, buf, inter); } /** @@ -278,7 +278,7 @@ static int vmw_overlay_stop(struct vmw_private *dev_priv, } if (!pause) { - vmw_dmabuf_unreference(&stream->buf); + vmw_bo_unreference(&stream->buf); stream->paused = false; } else { stream->paused = true; @@ -297,7 +297,7 @@ static int vmw_overlay_stop(struct vmw_private *dev_priv, * -ERESTARTSYS if interrupted. */ static int vmw_overlay_update_stream(struct vmw_private *dev_priv, - struct vmw_dma_buffer *buf, + struct vmw_buffer_object *buf, struct drm_vmw_control_stream_arg *arg, bool interruptible) { @@ -347,7 +347,7 @@ static int vmw_overlay_update_stream(struct vmw_private *dev_priv, } if (stream->buf != buf) - stream->buf = vmw_dmabuf_reference(buf); + stream->buf = vmw_bo_reference(buf); stream->saved = *arg; /* stream is no longer stopped/paused */ stream->paused = false; @@ -466,7 +466,7 @@ int vmw_overlay_ioctl(struct drm_device *dev, void *data, struct vmw_overlay *overlay = dev_priv->overlay_priv; struct drm_vmw_control_stream_arg *arg = (struct drm_vmw_control_stream_arg *)data; - struct vmw_dma_buffer *buf; + struct vmw_buffer_object *buf; struct vmw_resource *res; int ret; @@ -484,13 +484,13 @@ int vmw_overlay_ioctl(struct drm_device *dev, void *data, goto out_unlock; } - ret = vmw_user_dmabuf_lookup(tfile, arg->handle, &buf, NULL); + ret = vmw_user_bo_lookup(tfile, arg->handle, &buf, NULL); if (ret) goto out_unlock; ret = vmw_overlay_update_stream(dev_priv, buf, arg, true); - vmw_dmabuf_unreference(&buf); + vmw_bo_unreference(&buf); out_unlock: mutex_unlock(&overlay->mutex); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index 6b3a942b18df4..5aaf9ac65cba0 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -35,9 +35,9 @@ #define VMW_RES_EVICT_ERR_COUNT 10 -struct vmw_user_dma_buffer { +struct vmw_user_buffer_object { struct ttm_prime_object prime; - struct vmw_dma_buffer dma; + struct vmw_buffer_object vbo; }; struct vmw_bo_user_rep { @@ -45,17 +45,18 @@ struct vmw_bo_user_rep { uint64_t map_handle; }; -static inline struct vmw_dma_buffer * -vmw_dma_buffer(struct ttm_buffer_object *bo) +static inline struct vmw_buffer_object * +vmw_buffer_object(struct ttm_buffer_object *bo) { - return container_of(bo, struct vmw_dma_buffer, base); + return container_of(bo, struct vmw_buffer_object, base); } -static inline struct vmw_user_dma_buffer * -vmw_user_dma_buffer(struct ttm_buffer_object *bo) +static inline struct vmw_user_buffer_object * +vmw_user_buffer_object(struct ttm_buffer_object *bo) { - struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo); - return container_of(vmw_bo, struct vmw_user_dma_buffer, dma); + struct vmw_buffer_object *vmw_bo = vmw_buffer_object(bo); + + return container_of(vmw_bo, struct vmw_user_buffer_object, vbo); } struct vmw_resource *vmw_resource_reference(struct vmw_resource *res) @@ -116,7 +117,7 @@ static void vmw_resource_release(struct kref *kref) res->backup_dirty = false; list_del_init(&res->mob_head); ttm_bo_unreserve(bo); - vmw_dmabuf_unreference(&res->backup); + vmw_bo_unreference(&res->backup); } if (likely(res->hw_destroy != NULL)) { @@ -287,7 +288,7 @@ int vmw_user_resource_lookup_handle(struct vmw_private *dev_priv, } /** - * Helper function that looks either a surface or dmabuf. + * Helper function that looks either a surface or bo. * * The pointer this pointed at by out_surf and out_buf needs to be null. */ @@ -295,7 +296,7 @@ int vmw_user_lookup_handle(struct vmw_private *dev_priv, struct ttm_object_file *tfile, uint32_t handle, struct vmw_surface **out_surf, - struct vmw_dma_buffer **out_buf) + struct vmw_buffer_object **out_buf) { struct vmw_resource *res; int ret; @@ -311,7 +312,7 @@ int vmw_user_lookup_handle(struct vmw_private *dev_priv, } *out_surf = NULL; - ret = vmw_user_dmabuf_lookup(tfile, handle, out_buf, NULL); + ret = vmw_user_bo_lookup(tfile, handle, out_buf, NULL); return ret; } @@ -320,14 +321,14 @@ int vmw_user_lookup_handle(struct vmw_private *dev_priv, */ /** - * vmw_dmabuf_acc_size - Calculate the pinned memory usage of buffers + * vmw_bo_acc_size - Calculate the pinned memory usage of buffers * * @dev_priv: Pointer to a struct vmw_private identifying the device. * @size: The requested buffer size. * @user: Whether this is an ordinary dma buffer or a user dma buffer. */ -static size_t vmw_dmabuf_acc_size(struct vmw_private *dev_priv, size_t size, - bool user) +static size_t vmw_bo_acc_size(struct vmw_private *dev_priv, size_t size, + bool user) { static size_t struct_size, user_struct_size; size_t num_pages = PAGE_ALIGN(size) >> PAGE_SHIFT; @@ -337,9 +338,9 @@ static size_t vmw_dmabuf_acc_size(struct vmw_private *dev_priv, size_t size, size_t backend_size = ttm_round_pot(vmw_tt_size); struct_size = backend_size + - ttm_round_pot(sizeof(struct vmw_dma_buffer)); + ttm_round_pot(sizeof(struct vmw_buffer_object)); user_struct_size = backend_size + - ttm_round_pot(sizeof(struct vmw_user_dma_buffer)); + ttm_round_pot(sizeof(struct vmw_user_buffer_object)); } if (dev_priv->map_mode == vmw_dma_alloc_coherent) @@ -350,36 +351,36 @@ static size_t vmw_dmabuf_acc_size(struct vmw_private *dev_priv, size_t size, page_array_size; } -void vmw_dmabuf_bo_free(struct ttm_buffer_object *bo) +void vmw_bo_bo_free(struct ttm_buffer_object *bo) { - struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo); + struct vmw_buffer_object *vmw_bo = vmw_buffer_object(bo); - vmw_dma_buffer_unmap(vmw_bo); + vmw_buffer_object_unmap(vmw_bo); kfree(vmw_bo); } -static void vmw_user_dmabuf_destroy(struct ttm_buffer_object *bo) +static void vmw_user_bo_destroy(struct ttm_buffer_object *bo) { - struct vmw_user_dma_buffer *vmw_user_bo = vmw_user_dma_buffer(bo); + struct vmw_user_buffer_object *vmw_user_bo = vmw_user_buffer_object(bo); - vmw_dma_buffer_unmap(&vmw_user_bo->dma); + vmw_buffer_object_unmap(&vmw_user_bo->vbo); ttm_prime_object_kfree(vmw_user_bo, prime); } -int vmw_dmabuf_init(struct vmw_private *dev_priv, - struct vmw_dma_buffer *vmw_bo, - size_t size, struct ttm_placement *placement, - bool interruptible, - void (*bo_free) (struct ttm_buffer_object *bo)) +int vmw_bo_init(struct vmw_private *dev_priv, + struct vmw_buffer_object *vmw_bo, + size_t size, struct ttm_placement *placement, + bool interruptible, + void (*bo_free)(struct ttm_buffer_object *bo)) { struct ttm_bo_device *bdev = &dev_priv->bdev; size_t acc_size; int ret; - bool user = (bo_free == &vmw_user_dmabuf_destroy); + bool user = (bo_free == &vmw_user_bo_destroy); - BUG_ON(!bo_free && (!user && (bo_free != vmw_dmabuf_bo_free))); + WARN_ON_ONCE(!bo_free && (!user && (bo_free != vmw_bo_bo_free))); - acc_size = vmw_dmabuf_acc_size(dev_priv, size, user); + acc_size = vmw_bo_acc_size(dev_priv, size, user); memset(vmw_bo, 0, sizeof(*vmw_bo)); INIT_LIST_HEAD(&vmw_bo->res_list); @@ -391,9 +392,9 @@ int vmw_dmabuf_init(struct vmw_private *dev_priv, return ret; } -static void vmw_user_dmabuf_release(struct ttm_base_object **p_base) +static void vmw_user_bo_release(struct ttm_base_object **p_base) { - struct vmw_user_dma_buffer *vmw_user_bo; + struct vmw_user_buffer_object *vmw_user_bo; struct ttm_base_object *base = *p_base; struct ttm_buffer_object *bo; @@ -402,21 +403,22 @@ static void vmw_user_dmabuf_release(struct ttm_base_object **p_base) if (unlikely(base == NULL)) return; - vmw_user_bo = container_of(base, struct vmw_user_dma_buffer, + vmw_user_bo = container_of(base, struct vmw_user_buffer_object, prime.base); - bo = &vmw_user_bo->dma.base; + bo = &vmw_user_bo->vbo.base; ttm_bo_unref(&bo); } -static void vmw_user_dmabuf_ref_obj_release(struct ttm_base_object *base, - enum ttm_ref_type ref_type) +static void vmw_user_bo_ref_obj_release(struct ttm_base_object *base, + enum ttm_ref_type ref_type) { - struct vmw_user_dma_buffer *user_bo; - user_bo = container_of(base, struct vmw_user_dma_buffer, prime.base); + struct vmw_user_buffer_object *user_bo; + + user_bo = container_of(base, struct vmw_user_buffer_object, prime.base); switch (ref_type) { case TTM_REF_SYNCCPU_WRITE: - ttm_bo_synccpu_write_release(&user_bo->dma.base); + ttm_bo_synccpu_write_release(&user_bo->vbo.base); break; default: BUG(); @@ -424,7 +426,7 @@ static void vmw_user_dmabuf_ref_obj_release(struct ttm_base_object *base, } /** - * vmw_user_dmabuf_alloc - Allocate a user dma buffer + * vmw_user_bo_alloc - Allocate a user dma buffer * * @dev_priv: Pointer to a struct device private. * @tfile: Pointer to a struct ttm_object_file on which to register the user @@ -432,18 +434,18 @@ static void vmw_user_dmabuf_ref_obj_release(struct ttm_base_object *base, * @size: Size of the dma buffer. * @shareable: Boolean whether the buffer is shareable with other open files. * @handle: Pointer to where the handle value should be assigned. - * @p_dma_buf: Pointer to where the refcounted struct vmw_dma_buffer pointer + * @p_vbo: Pointer to where the refcounted struct vmw_buffer_object pointer * should be assigned. */ -int vmw_user_dmabuf_alloc(struct vmw_private *dev_priv, - struct ttm_object_file *tfile, - uint32_t size, - bool shareable, - uint32_t *handle, - struct vmw_dma_buffer **p_dma_buf, - struct ttm_base_object **p_base) +int vmw_user_bo_alloc(struct vmw_private *dev_priv, + struct ttm_object_file *tfile, + uint32_t size, + bool shareable, + uint32_t *handle, + struct vmw_buffer_object **p_vbo, + struct ttm_base_object **p_base) { - struct vmw_user_dma_buffer *user_bo; + struct vmw_user_buffer_object *user_bo; struct ttm_buffer_object *tmp; int ret; @@ -453,28 +455,28 @@ int vmw_user_dmabuf_alloc(struct vmw_private *dev_priv, return -ENOMEM; } - ret = vmw_dmabuf_init(dev_priv, &user_bo->dma, size, - (dev_priv->has_mob) ? - &vmw_sys_placement : - &vmw_vram_sys_placement, true, - &vmw_user_dmabuf_destroy); + ret = vmw_bo_init(dev_priv, &user_bo->vbo, size, + (dev_priv->has_mob) ? + &vmw_sys_placement : + &vmw_vram_sys_placement, true, + &vmw_user_bo_destroy); if (unlikely(ret != 0)) return ret; - tmp = ttm_bo_reference(&user_bo->dma.base); + tmp = ttm_bo_reference(&user_bo->vbo.base); ret = ttm_prime_object_init(tfile, size, &user_bo->prime, shareable, ttm_buffer_type, - &vmw_user_dmabuf_release, - &vmw_user_dmabuf_ref_obj_release); + &vmw_user_bo_release, + &vmw_user_bo_ref_obj_release); if (unlikely(ret != 0)) { ttm_bo_unref(&tmp); goto out_no_base_object; } - *p_dma_buf = &user_bo->dma; + *p_vbo = &user_bo->vbo; if (p_base) { *p_base = &user_bo->prime.base; kref_get(&(*p_base)->refcount); @@ -486,21 +488,21 @@ int vmw_user_dmabuf_alloc(struct vmw_private *dev_priv, } /** - * vmw_user_dmabuf_verify_access - verify access permissions on this + * vmw_user_bo_verify_access - verify access permissions on this * buffer object. * * @bo: Pointer to the buffer object being accessed * @tfile: Identifying the caller. */ -int vmw_user_dmabuf_verify_access(struct ttm_buffer_object *bo, +int vmw_user_bo_verify_access(struct ttm_buffer_object *bo, struct ttm_object_file *tfile) { - struct vmw_user_dma_buffer *vmw_user_bo; + struct vmw_user_buffer_object *vmw_user_bo; - if (unlikely(bo->destroy != vmw_user_dmabuf_destroy)) + if (unlikely(bo->destroy != vmw_user_bo_destroy)) return -EPERM; - vmw_user_bo = vmw_user_dma_buffer(bo); + vmw_user_bo = vmw_user_buffer_object(bo); /* Check that the caller has opened the object. */ if (likely(ttm_ref_object_exists(tfile, &vmw_user_bo->prime.base))) @@ -511,7 +513,7 @@ int vmw_user_dmabuf_verify_access(struct ttm_buffer_object *bo, } /** - * vmw_user_dmabuf_synccpu_grab - Grab a struct vmw_user_dma_buffer for cpu + * vmw_user_bo_synccpu_grab - Grab a struct vmw_user_buffer_object for cpu * access, idling previous GPU operations on the buffer and optionally * blocking it for further command submissions. * @@ -521,11 +523,11 @@ int vmw_user_dmabuf_verify_access(struct ttm_buffer_object *bo, * * A blocking grab will be automatically released when @tfile is closed. */ -static int vmw_user_dmabuf_synccpu_grab(struct vmw_user_dma_buffer *user_bo, +static int vmw_user_bo_synccpu_grab(struct vmw_user_buffer_object *user_bo, struct ttm_object_file *tfile, uint32_t flags) { - struct ttm_buffer_object *bo = &user_bo->dma.base; + struct ttm_buffer_object *bo = &user_bo->vbo.base; bool existed; int ret; @@ -550,20 +552,20 @@ static int vmw_user_dmabuf_synccpu_grab(struct vmw_user_dma_buffer *user_bo, ret = ttm_ref_object_add(tfile, &user_bo->prime.base, TTM_REF_SYNCCPU_WRITE, &existed, false); if (ret != 0 || existed) - ttm_bo_synccpu_write_release(&user_bo->dma.base); + ttm_bo_synccpu_write_release(&user_bo->vbo.base); return ret; } /** - * vmw_user_dmabuf_synccpu_release - Release a previous grab for CPU access, + * vmw_user_bo_synccpu_release - Release a previous grab for CPU access, * and unblock command submission on the buffer if blocked. * * @handle: Handle identifying the buffer object. * @tfile: Identifying the caller. * @flags: Flags indicating the type of release. */ -static int vmw_user_dmabuf_synccpu_release(uint32_t handle, +static int vmw_user_bo_synccpu_release(uint32_t handle, struct ttm_object_file *tfile, uint32_t flags) { @@ -575,7 +577,7 @@ static int vmw_user_dmabuf_synccpu_release(uint32_t handle, } /** - * vmw_user_dmabuf_synccpu_release - ioctl function implementing the synccpu + * vmw_user_bo_synccpu_release - ioctl function implementing the synccpu * functionality. * * @dev: Identifies the drm device. @@ -585,13 +587,13 @@ static int vmw_user_dmabuf_synccpu_release(uint32_t handle, * This function checks the ioctl arguments for validity and calls the * relevant synccpu functions. */ -int vmw_user_dmabuf_synccpu_ioctl(struct drm_device *dev, void *data, +int vmw_user_bo_synccpu_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_vmw_synccpu_arg *arg = (struct drm_vmw_synccpu_arg *) data; - struct vmw_dma_buffer *dma_buf; - struct vmw_user_dma_buffer *user_bo; + struct vmw_buffer_object *vbo; + struct vmw_user_buffer_object *user_bo; struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; struct ttm_base_object *buffer_base; int ret; @@ -606,15 +608,15 @@ int vmw_user_dmabuf_synccpu_ioctl(struct drm_device *dev, void *data, switch (arg->op) { case drm_vmw_synccpu_grab: - ret = vmw_user_dmabuf_lookup(tfile, arg->handle, &dma_buf, + ret = vmw_user_bo_lookup(tfile, arg->handle, &vbo, &buffer_base); if (unlikely(ret != 0)) return ret; - user_bo = container_of(dma_buf, struct vmw_user_dma_buffer, - dma); - ret = vmw_user_dmabuf_synccpu_grab(user_bo, tfile, arg->flags); - vmw_dmabuf_unreference(&dma_buf); + user_bo = container_of(vbo, struct vmw_user_buffer_object, + vbo); + ret = vmw_user_bo_synccpu_grab(user_bo, tfile, arg->flags); + vmw_bo_unreference(&vbo); ttm_base_object_unref(&buffer_base); if (unlikely(ret != 0 && ret != -ERESTARTSYS && ret != -EBUSY)) { @@ -624,8 +626,8 @@ int vmw_user_dmabuf_synccpu_ioctl(struct drm_device *dev, void *data, } break; case drm_vmw_synccpu_release: - ret = vmw_user_dmabuf_synccpu_release(arg->handle, tfile, - arg->flags); + ret = vmw_user_bo_synccpu_release(arg->handle, tfile, + arg->flags); if (unlikely(ret != 0)) { DRM_ERROR("Failed synccpu release on handle 0x%08x.\n", (unsigned int) arg->handle); @@ -640,15 +642,15 @@ int vmw_user_dmabuf_synccpu_ioctl(struct drm_device *dev, void *data, return 0; } -int vmw_dmabuf_alloc_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) +int vmw_bo_alloc_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) { struct vmw_private *dev_priv = vmw_priv(dev); union drm_vmw_alloc_dmabuf_arg *arg = (union drm_vmw_alloc_dmabuf_arg *)data; struct drm_vmw_alloc_dmabuf_req *req = &arg->req; struct drm_vmw_dmabuf_rep *rep = &arg->rep; - struct vmw_dma_buffer *dma_buf; + struct vmw_buffer_object *vbo; uint32_t handle; int ret; @@ -656,27 +658,27 @@ int vmw_dmabuf_alloc_ioctl(struct drm_device *dev, void *data, if (unlikely(ret != 0)) return ret; - ret = vmw_user_dmabuf_alloc(dev_priv, vmw_fpriv(file_priv)->tfile, - req->size, false, &handle, &dma_buf, - NULL); + ret = vmw_user_bo_alloc(dev_priv, vmw_fpriv(file_priv)->tfile, + req->size, false, &handle, &vbo, + NULL); if (unlikely(ret != 0)) - goto out_no_dmabuf; + goto out_no_bo; rep->handle = handle; - rep->map_handle = drm_vma_node_offset_addr(&dma_buf->base.vma_node); + rep->map_handle = drm_vma_node_offset_addr(&vbo->base.vma_node); rep->cur_gmr_id = handle; rep->cur_gmr_offset = 0; - vmw_dmabuf_unreference(&dma_buf); + vmw_bo_unreference(&vbo); -out_no_dmabuf: +out_no_bo: ttm_read_unlock(&dev_priv->reservation_sem); return ret; } -int vmw_dmabuf_unref_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) +int vmw_bo_unref_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) { struct drm_vmw_unref_dmabuf_arg *arg = (struct drm_vmw_unref_dmabuf_arg *)data; @@ -686,11 +688,11 @@ int vmw_dmabuf_unref_ioctl(struct drm_device *dev, void *data, TTM_REF_USAGE); } -int vmw_user_dmabuf_lookup(struct ttm_object_file *tfile, - uint32_t handle, struct vmw_dma_buffer **out, +int vmw_user_bo_lookup(struct ttm_object_file *tfile, + uint32_t handle, struct vmw_buffer_object **out, struct ttm_base_object **p_base) { - struct vmw_user_dma_buffer *vmw_user_bo; + struct vmw_user_buffer_object *vmw_user_bo; struct ttm_base_object *base; base = ttm_base_object_lookup(tfile, handle); @@ -707,28 +709,28 @@ int vmw_user_dmabuf_lookup(struct ttm_object_file *tfile, return -EINVAL; } - vmw_user_bo = container_of(base, struct vmw_user_dma_buffer, + vmw_user_bo = container_of(base, struct vmw_user_buffer_object, prime.base); - (void)ttm_bo_reference(&vmw_user_bo->dma.base); + (void)ttm_bo_reference(&vmw_user_bo->vbo.base); if (p_base) *p_base = base; else ttm_base_object_unref(&base); - *out = &vmw_user_bo->dma; + *out = &vmw_user_bo->vbo; return 0; } -int vmw_user_dmabuf_reference(struct ttm_object_file *tfile, - struct vmw_dma_buffer *dma_buf, +int vmw_user_bo_reference(struct ttm_object_file *tfile, + struct vmw_buffer_object *vbo, uint32_t *handle) { - struct vmw_user_dma_buffer *user_bo; + struct vmw_user_buffer_object *user_bo; - if (dma_buf->base.destroy != vmw_user_dmabuf_destroy) + if (vbo->base.destroy != vmw_user_bo_destroy) return -EINVAL; - user_bo = container_of(dma_buf, struct vmw_user_dma_buffer, dma); + user_bo = container_of(vbo, struct vmw_user_buffer_object, vbo); *handle = user_bo->prime.base.hash.key; return ttm_ref_object_add(tfile, &user_bo->prime.base, @@ -743,7 +745,7 @@ int vmw_user_dmabuf_reference(struct ttm_object_file *tfile, * @args: Pointer to a struct drm_mode_create_dumb structure * * This is a driver callback for the core drm create_dumb functionality. - * Note that this is very similar to the vmw_dmabuf_alloc ioctl, except + * Note that this is very similar to the vmw_bo_alloc ioctl, except * that the arguments have a different format. */ int vmw_dumb_create(struct drm_file *file_priv, @@ -751,7 +753,7 @@ int vmw_dumb_create(struct drm_file *file_priv, struct drm_mode_create_dumb *args) { struct vmw_private *dev_priv = vmw_priv(dev); - struct vmw_dma_buffer *dma_buf; + struct vmw_buffer_object *vbo; int ret; args->pitch = args->width * ((args->bpp + 7) / 8); @@ -761,14 +763,14 @@ int vmw_dumb_create(struct drm_file *file_priv, if (unlikely(ret != 0)) return ret; - ret = vmw_user_dmabuf_alloc(dev_priv, vmw_fpriv(file_priv)->tfile, + ret = vmw_user_bo_alloc(dev_priv, vmw_fpriv(file_priv)->tfile, args->size, false, &args->handle, - &dma_buf, NULL); + &vbo, NULL); if (unlikely(ret != 0)) - goto out_no_dmabuf; + goto out_no_bo; - vmw_dmabuf_unreference(&dma_buf); -out_no_dmabuf: + vmw_bo_unreference(&vbo); +out_no_bo: ttm_read_unlock(&dev_priv->reservation_sem); return ret; } @@ -788,15 +790,15 @@ int vmw_dumb_map_offset(struct drm_file *file_priv, uint64_t *offset) { struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; - struct vmw_dma_buffer *out_buf; + struct vmw_buffer_object *out_buf; int ret; - ret = vmw_user_dmabuf_lookup(tfile, handle, &out_buf, NULL); + ret = vmw_user_bo_lookup(tfile, handle, &out_buf, NULL); if (ret != 0) return -EINVAL; *offset = drm_vma_node_offset_addr(&out_buf->base.vma_node); - vmw_dmabuf_unreference(&out_buf); + vmw_bo_unreference(&out_buf); return 0; } @@ -829,7 +831,7 @@ static int vmw_resource_buf_alloc(struct vmw_resource *res, { unsigned long size = (res->backup_size + PAGE_SIZE - 1) & PAGE_MASK; - struct vmw_dma_buffer *backup; + struct vmw_buffer_object *backup; int ret; if (likely(res->backup)) { @@ -841,16 +843,16 @@ static int vmw_resource_buf_alloc(struct vmw_resource *res, if (unlikely(!backup)) return -ENOMEM; - ret = vmw_dmabuf_init(res->dev_priv, backup, res->backup_size, + ret = vmw_bo_init(res->dev_priv, backup, res->backup_size, res->func->backup_placement, interruptible, - &vmw_dmabuf_bo_free); + &vmw_bo_bo_free); if (unlikely(ret != 0)) - goto out_no_dmabuf; + goto out_no_bo; res->backup = backup; -out_no_dmabuf: +out_no_bo: return ret; } @@ -919,7 +921,7 @@ static int vmw_resource_do_validate(struct vmw_resource *res, */ void vmw_resource_unreserve(struct vmw_resource *res, bool switch_backup, - struct vmw_dma_buffer *new_backup, + struct vmw_buffer_object *new_backup, unsigned long new_backup_offset) { struct vmw_private *dev_priv = res->dev_priv; @@ -931,11 +933,11 @@ void vmw_resource_unreserve(struct vmw_resource *res, if (res->backup) { lockdep_assert_held(&res->backup->base.resv->lock.base); list_del_init(&res->mob_head); - vmw_dmabuf_unreference(&res->backup); + vmw_bo_unreference(&res->backup); } if (new_backup) { - res->backup = vmw_dmabuf_reference(new_backup); + res->backup = vmw_bo_reference(new_backup); lockdep_assert_held(&new_backup->base.resv->lock.base); list_add_tail(&res->mob_head, &new_backup->res_list); } else { @@ -1007,7 +1009,7 @@ vmw_resource_check_buffer(struct vmw_resource *res, out_no_reserve: ttm_bo_unref(&val_buf->bo); if (backup_dirty) - vmw_dmabuf_unreference(&res->backup); + vmw_bo_unreference(&res->backup); return ret; } @@ -1171,7 +1173,7 @@ int vmw_resource_validate(struct vmw_resource *res) goto out_no_validate; else if (!res->func->needs_backup && res->backup) { list_del_init(&res->mob_head); - vmw_dmabuf_unreference(&res->backup); + vmw_bo_unreference(&res->backup); } return 0; @@ -1230,22 +1232,22 @@ void vmw_fence_single_bo(struct ttm_buffer_object *bo, void vmw_resource_move_notify(struct ttm_buffer_object *bo, struct ttm_mem_reg *mem) { - struct vmw_dma_buffer *dma_buf; + struct vmw_buffer_object *vbo; if (mem == NULL) return; - if (bo->destroy != vmw_dmabuf_bo_free && - bo->destroy != vmw_user_dmabuf_destroy) + if (bo->destroy != vmw_bo_bo_free && + bo->destroy != vmw_user_bo_destroy) return; - dma_buf = container_of(bo, struct vmw_dma_buffer, base); + vbo = container_of(bo, struct vmw_buffer_object, base); /* * Kill any cached kernel maps before move. An optimization could * be to do this iff source or destination memory type is VRAM. */ - vmw_dma_buffer_unmap(dma_buf); + vmw_buffer_object_unmap(vbo); if (mem->mem_type != VMW_PL_MOB) { struct vmw_resource *res, *n; @@ -1254,7 +1256,7 @@ void vmw_resource_move_notify(struct ttm_buffer_object *bo, val_buf.bo = bo; val_buf.shared = false; - list_for_each_entry_safe(res, n, &dma_buf->res_list, mob_head) { + list_for_each_entry_safe(res, n, &vbo->res_list, mob_head) { if (unlikely(res->func->unbind == NULL)) continue; @@ -1277,12 +1279,12 @@ void vmw_resource_move_notify(struct ttm_buffer_object *bo, */ void vmw_resource_swap_notify(struct ttm_buffer_object *bo) { - if (bo->destroy != vmw_dmabuf_bo_free && - bo->destroy != vmw_user_dmabuf_destroy) + if (bo->destroy != vmw_bo_bo_free && + bo->destroy != vmw_user_bo_destroy) return; /* Kill any cached kernel maps before swapout */ - vmw_dma_buffer_unmap(vmw_dma_buffer(bo)); + vmw_buffer_object_unmap(vmw_buffer_object(bo)); } @@ -1294,7 +1296,7 @@ void vmw_resource_swap_notify(struct ttm_buffer_object *bo) * Read back cached states from the device if they exist. This function * assumings binding_mutex is held. */ -int vmw_query_readback_all(struct vmw_dma_buffer *dx_query_mob) +int vmw_query_readback_all(struct vmw_buffer_object *dx_query_mob) { struct vmw_resource *dx_query_ctx; struct vmw_private *dev_priv; @@ -1344,7 +1346,7 @@ int vmw_query_readback_all(struct vmw_dma_buffer *dx_query_mob) void vmw_query_move_notify(struct ttm_buffer_object *bo, struct ttm_mem_reg *mem) { - struct vmw_dma_buffer *dx_query_mob; + struct vmw_buffer_object *dx_query_mob; struct ttm_bo_device *bdev = bo->bdev; struct vmw_private *dev_priv; @@ -1353,7 +1355,7 @@ void vmw_query_move_notify(struct ttm_buffer_object *bo, mutex_lock(&dev_priv->binding_mutex); - dx_query_mob = container_of(bo, struct vmw_dma_buffer, base); + dx_query_mob = container_of(bo, struct vmw_buffer_object, base); if (mem == NULL || !dx_query_mob || !dx_query_mob->dx_query_ctx) { mutex_unlock(&dev_priv->binding_mutex); return; @@ -1481,7 +1483,7 @@ int vmw_resource_pin(struct vmw_resource *res, bool interruptible) goto out_no_reserve; if (res->pin_count == 0) { - struct vmw_dma_buffer *vbo = NULL; + struct vmw_buffer_object *vbo = NULL; if (res->backup) { vbo = res->backup; @@ -1539,7 +1541,7 @@ void vmw_resource_unpin(struct vmw_resource *res) WARN_ON(res->pin_count == 0); if (--res->pin_count == 0 && res->backup) { - struct vmw_dma_buffer *vbo = res->backup; + struct vmw_buffer_object *vbo = res->backup; (void) ttm_bo_reserve(&vbo->base, false, false, NULL); vmw_bo_pin_reserved(vbo, false); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index 9798640cbfcd9..74dfd4621b7e7 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -66,7 +66,7 @@ struct vmw_kms_sou_readback_blit { SVGAFifoCmdBlitScreenToGMRFB body; }; -struct vmw_kms_sou_dmabuf_blit { +struct vmw_kms_sou_bo_blit { uint32 header; SVGAFifoCmdBlitGMRFBToScreen body; }; @@ -83,7 +83,7 @@ struct vmw_screen_object_unit { struct vmw_display_unit base; unsigned long buffer_size; /**< Size of allocated buffer */ - struct vmw_dma_buffer *buffer; /**< Backing store buffer */ + struct vmw_buffer_object *buffer; /**< Backing store buffer */ bool defined; }; @@ -240,8 +240,8 @@ static void vmw_sou_crtc_mode_set_nofb(struct drm_crtc *crtc) } if (vfb) { - sou->buffer = vps->dmabuf; - sou->buffer_size = vps->dmabuf_size; + sou->buffer = vps->bo; + sou->buffer_size = vps->bo_size; ret = vmw_sou_fifo_create(dev_priv, sou, crtc->x, crtc->y, &crtc->mode); @@ -408,10 +408,10 @@ vmw_sou_primary_plane_cleanup_fb(struct drm_plane *plane, struct drm_crtc *crtc = plane->state->crtc ? plane->state->crtc : old_state->crtc; - if (vps->dmabuf) - vmw_dmabuf_unpin(vmw_priv(crtc->dev), vps->dmabuf, false); - vmw_dmabuf_unreference(&vps->dmabuf); - vps->dmabuf_size = 0; + if (vps->bo) + vmw_bo_unpin(vmw_priv(crtc->dev), vps->bo, false); + vmw_bo_unreference(&vps->bo); + vps->bo_size = 0; vmw_du_plane_cleanup_fb(plane, old_state); } @@ -440,8 +440,8 @@ vmw_sou_primary_plane_prepare_fb(struct drm_plane *plane, if (!new_fb) { - vmw_dmabuf_unreference(&vps->dmabuf); - vps->dmabuf_size = 0; + vmw_bo_unreference(&vps->bo); + vps->bo_size = 0; return 0; } @@ -449,22 +449,22 @@ vmw_sou_primary_plane_prepare_fb(struct drm_plane *plane, size = new_state->crtc_w * new_state->crtc_h * 4; dev_priv = vmw_priv(crtc->dev); - if (vps->dmabuf) { - if (vps->dmabuf_size == size) { + if (vps->bo) { + if (vps->bo_size == size) { /* * Note that this might temporarily up the pin-count * to 2, until cleanup_fb() is called. */ - return vmw_dmabuf_pin_in_vram(dev_priv, vps->dmabuf, + return vmw_bo_pin_in_vram(dev_priv, vps->bo, true); } - vmw_dmabuf_unreference(&vps->dmabuf); - vps->dmabuf_size = 0; + vmw_bo_unreference(&vps->bo); + vps->bo_size = 0; } - vps->dmabuf = kzalloc(sizeof(*vps->dmabuf), GFP_KERNEL); - if (!vps->dmabuf) + vps->bo = kzalloc(sizeof(*vps->bo), GFP_KERNEL); + if (!vps->bo) return -ENOMEM; vmw_svga_enable(dev_priv); @@ -473,22 +473,22 @@ vmw_sou_primary_plane_prepare_fb(struct drm_plane *plane, * resume the overlays, this is preferred to failing to alloc. */ vmw_overlay_pause_all(dev_priv); - ret = vmw_dmabuf_init(dev_priv, vps->dmabuf, size, + ret = vmw_bo_init(dev_priv, vps->bo, size, &vmw_vram_ne_placement, - false, &vmw_dmabuf_bo_free); + false, &vmw_bo_bo_free); vmw_overlay_resume_all(dev_priv); if (ret) { - vps->dmabuf = NULL; /* vmw_dmabuf_init frees on error */ + vps->bo = NULL; /* vmw_bo_init frees on error */ return ret; } - vps->dmabuf_size = size; + vps->bo_size = size; /* * TTM already thinks the buffer is pinned, but make sure the * pin_count is upped. */ - return vmw_dmabuf_pin_in_vram(dev_priv, vps->dmabuf, true); + return vmw_bo_pin_in_vram(dev_priv, vps->bo, true); } @@ -512,10 +512,10 @@ vmw_sou_primary_plane_atomic_update(struct drm_plane *plane, vclips.w = crtc->mode.hdisplay; vclips.h = crtc->mode.vdisplay; - if (vfb->dmabuf) - ret = vmw_kms_sou_do_dmabuf_dirty(dev_priv, vfb, NULL, - &vclips, 1, 1, true, - &fence, crtc); + if (vfb->bo) + ret = vmw_kms_sou_do_bo_dirty(dev_priv, vfb, NULL, + &vclips, 1, 1, true, + &fence, crtc); else ret = vmw_kms_sou_do_surface_dirty(dev_priv, vfb, NULL, &vclips, NULL, 0, 0, @@ -775,11 +775,11 @@ int vmw_kms_sou_init_display(struct vmw_private *dev_priv) return 0; } -static int do_dmabuf_define_gmrfb(struct vmw_private *dev_priv, +static int do_bo_define_gmrfb(struct vmw_private *dev_priv, struct vmw_framebuffer *framebuffer) { - struct vmw_dma_buffer *buf = - container_of(framebuffer, struct vmw_framebuffer_dmabuf, + struct vmw_buffer_object *buf = + container_of(framebuffer, struct vmw_framebuffer_bo, base)->buffer; int depth = framebuffer->base.format->depth; struct { @@ -970,13 +970,13 @@ int vmw_kms_sou_do_surface_dirty(struct vmw_private *dev_priv, } /** - * vmw_sou_dmabuf_fifo_commit - Callback to submit a set of readback clips. + * vmw_sou_bo_fifo_commit - Callback to submit a set of readback clips. * * @dirty: The closure structure. * * Commits a previously built command buffer of readback clips. */ -static void vmw_sou_dmabuf_fifo_commit(struct vmw_kms_dirty *dirty) +static void vmw_sou_bo_fifo_commit(struct vmw_kms_dirty *dirty) { if (!dirty->num_hits) { vmw_fifo_commit(dirty->dev_priv, 0); @@ -984,20 +984,20 @@ static void vmw_sou_dmabuf_fifo_commit(struct vmw_kms_dirty *dirty) } vmw_fifo_commit(dirty->dev_priv, - sizeof(struct vmw_kms_sou_dmabuf_blit) * + sizeof(struct vmw_kms_sou_bo_blit) * dirty->num_hits); } /** - * vmw_sou_dmabuf_clip - Callback to encode a readback cliprect. + * vmw_sou_bo_clip - Callback to encode a readback cliprect. * * @dirty: The closure structure * * Encodes a BLIT_GMRFB_TO_SCREEN cliprect. */ -static void vmw_sou_dmabuf_clip(struct vmw_kms_dirty *dirty) +static void vmw_sou_bo_clip(struct vmw_kms_dirty *dirty) { - struct vmw_kms_sou_dmabuf_blit *blit = dirty->cmd; + struct vmw_kms_sou_bo_blit *blit = dirty->cmd; blit += dirty->num_hits; blit->header = SVGA_CMD_BLIT_GMRFB_TO_SCREEN; @@ -1012,10 +1012,10 @@ static void vmw_sou_dmabuf_clip(struct vmw_kms_dirty *dirty) } /** - * vmw_kms_do_dmabuf_dirty - Dirty part of a dma-buffer backed framebuffer + * vmw_kms_do_bo_dirty - Dirty part of a buffer-object backed framebuffer * * @dev_priv: Pointer to the device private structure. - * @framebuffer: Pointer to the dma-buffer backed framebuffer. + * @framebuffer: Pointer to the buffer-object backed framebuffer. * @clips: Array of clip rects. * @vclips: Alternate array of clip rects. Either @clips or @vclips must * be NULL. @@ -1025,12 +1025,12 @@ static void vmw_sou_dmabuf_clip(struct vmw_kms_dirty *dirty) * @out_fence: If non-NULL, will return a ref-counted pointer to a * struct vmw_fence_obj. The returned fence pointer may be NULL in which * case the device has already synchronized. - * @crtc: If crtc is passed, perform dmabuf dirty on that crtc only. + * @crtc: If crtc is passed, perform bo dirty on that crtc only. * * Returns 0 on success, negative error code on failure. -ERESTARTSYS if * interrupted. */ -int vmw_kms_sou_do_dmabuf_dirty(struct vmw_private *dev_priv, +int vmw_kms_sou_do_bo_dirty(struct vmw_private *dev_priv, struct vmw_framebuffer *framebuffer, struct drm_clip_rect *clips, struct drm_vmw_rect *vclips, @@ -1039,8 +1039,8 @@ int vmw_kms_sou_do_dmabuf_dirty(struct vmw_private *dev_priv, struct vmw_fence_obj **out_fence, struct drm_crtc *crtc) { - struct vmw_dma_buffer *buf = - container_of(framebuffer, struct vmw_framebuffer_dmabuf, + struct vmw_buffer_object *buf = + container_of(framebuffer, struct vmw_framebuffer_bo, base)->buffer; struct vmw_kms_dirty dirty; int ret; @@ -1050,14 +1050,14 @@ int vmw_kms_sou_do_dmabuf_dirty(struct vmw_private *dev_priv, if (ret) return ret; - ret = do_dmabuf_define_gmrfb(dev_priv, framebuffer); + ret = do_bo_define_gmrfb(dev_priv, framebuffer); if (unlikely(ret != 0)) goto out_revert; dirty.crtc = crtc; - dirty.fifo_commit = vmw_sou_dmabuf_fifo_commit; - dirty.clip = vmw_sou_dmabuf_clip; - dirty.fifo_reserve_size = sizeof(struct vmw_kms_sou_dmabuf_blit) * + dirty.fifo_commit = vmw_sou_bo_fifo_commit; + dirty.clip = vmw_sou_bo_clip; + dirty.fifo_reserve_size = sizeof(struct vmw_kms_sou_bo_blit) * num_clips; ret = vmw_kms_helper_dirty(dev_priv, framebuffer, clips, vclips, 0, 0, num_clips, increment, &dirty); @@ -1116,12 +1116,12 @@ static void vmw_sou_readback_clip(struct vmw_kms_dirty *dirty) /** * vmw_kms_sou_readback - Perform a readback from the screen object system to - * a dma-buffer backed framebuffer. + * a buffer-object backed framebuffer. * * @dev_priv: Pointer to the device private structure. * @file_priv: Pointer to a struct drm_file identifying the caller. * Must be set to NULL if @user_fence_rep is NULL. - * @vfb: Pointer to the dma-buffer backed framebuffer. + * @vfb: Pointer to the buffer-object backed framebuffer. * @user_fence_rep: User-space provided structure for fence information. * Must be set to non-NULL if @file_priv is non-NULL. * @vclips: Array of clip rects. @@ -1139,8 +1139,8 @@ int vmw_kms_sou_readback(struct vmw_private *dev_priv, uint32_t num_clips, struct drm_crtc *crtc) { - struct vmw_dma_buffer *buf = - container_of(vfb, struct vmw_framebuffer_dmabuf, base)->buffer; + struct vmw_buffer_object *buf = + container_of(vfb, struct vmw_framebuffer_bo, base)->buffer; struct vmw_kms_dirty dirty; int ret; @@ -1149,7 +1149,7 @@ int vmw_kms_sou_readback(struct vmw_private *dev_priv, if (ret) return ret; - ret = do_dmabuf_define_gmrfb(dev_priv, vfb); + ret = do_bo_define_gmrfb(dev_priv, vfb); if (unlikely(ret != 0)) goto out_revert; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c index 73b8e9a163685..f6c939f3ff5e0 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c @@ -159,7 +159,7 @@ static int vmw_gb_shader_init(struct vmw_private *dev_priv, SVGA3dShaderType type, uint8_t num_input_sig, uint8_t num_output_sig, - struct vmw_dma_buffer *byte_code, + struct vmw_buffer_object *byte_code, void (*res_free) (struct vmw_resource *res)) { struct vmw_shader *shader = vmw_res_to_shader(res); @@ -178,7 +178,7 @@ static int vmw_gb_shader_init(struct vmw_private *dev_priv, res->backup_size = size; if (byte_code) { - res->backup = vmw_dmabuf_reference(byte_code); + res->backup = vmw_bo_reference(byte_code); res->backup_offset = offset; } shader->size = size; @@ -723,7 +723,7 @@ int vmw_shader_destroy_ioctl(struct drm_device *dev, void *data, } static int vmw_user_shader_alloc(struct vmw_private *dev_priv, - struct vmw_dma_buffer *buffer, + struct vmw_buffer_object *buffer, size_t shader_size, size_t offset, SVGA3dShaderType shader_type, @@ -801,7 +801,7 @@ static int vmw_user_shader_alloc(struct vmw_private *dev_priv, static struct vmw_resource *vmw_shader_alloc(struct vmw_private *dev_priv, - struct vmw_dma_buffer *buffer, + struct vmw_buffer_object *buffer, size_t shader_size, size_t offset, SVGA3dShaderType shader_type) @@ -862,12 +862,12 @@ static int vmw_shader_define(struct drm_device *dev, struct drm_file *file_priv, { struct vmw_private *dev_priv = vmw_priv(dev); struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; - struct vmw_dma_buffer *buffer = NULL; + struct vmw_buffer_object *buffer = NULL; SVGA3dShaderType shader_type; int ret; if (buffer_handle != SVGA3D_INVALID_ID) { - ret = vmw_user_dmabuf_lookup(tfile, buffer_handle, + ret = vmw_user_bo_lookup(tfile, buffer_handle, &buffer, NULL); if (unlikely(ret != 0)) { DRM_ERROR("Could not find buffer for shader " @@ -906,7 +906,7 @@ static int vmw_shader_define(struct drm_device *dev, struct drm_file *file_priv, ttm_read_unlock(&dev_priv->reservation_sem); out_bad_arg: - vmw_dmabuf_unreference(&buffer); + vmw_bo_unreference(&buffer); return ret; } @@ -983,7 +983,7 @@ int vmw_compat_shader_add(struct vmw_private *dev_priv, struct list_head *list) { struct ttm_operation_ctx ctx = { false, true }; - struct vmw_dma_buffer *buf; + struct vmw_buffer_object *buf; struct ttm_bo_kmap_obj map; bool is_iomem; int ret; @@ -997,8 +997,8 @@ int vmw_compat_shader_add(struct vmw_private *dev_priv, if (unlikely(!buf)) return -ENOMEM; - ret = vmw_dmabuf_init(dev_priv, buf, size, &vmw_sys_ne_placement, - true, vmw_dmabuf_bo_free); + ret = vmw_bo_init(dev_priv, buf, size, &vmw_sys_ne_placement, + true, vmw_bo_bo_free); if (unlikely(ret != 0)) goto out; @@ -1031,7 +1031,7 @@ int vmw_compat_shader_add(struct vmw_private *dev_priv, res, list); vmw_resource_unreference(&res); no_reserve: - vmw_dmabuf_unreference(&buf); + vmw_bo_unreference(&buf); out: return ret; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index 152e96cb1c01a..537df9034008b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -44,7 +44,7 @@ enum stdu_content_type { SAME_AS_DISPLAY = 0, SEPARATE_SURFACE, - SEPARATE_DMA + SEPARATE_BO }; /** @@ -58,7 +58,7 @@ enum stdu_content_type { * @bottom: Bottom side of bounding box. * @fb_left: Left side of the framebuffer/content bounding box * @fb_top: Top of the framebuffer/content bounding box - * @buf: DMA buffer when DMA-ing between buffer and screen targets. + * @buf: buffer object when DMA-ing between buffer and screen targets. * @sid: Surface ID when copying between surface and screen targets. */ struct vmw_stdu_dirty { @@ -68,7 +68,7 @@ struct vmw_stdu_dirty { s32 fb_left, fb_top; u32 pitch; union { - struct vmw_dma_buffer *buf; + struct vmw_buffer_object *buf; u32 sid; }; }; @@ -508,14 +508,14 @@ static int vmw_stdu_crtc_page_flip(struct drm_crtc *crtc, /** - * vmw_stdu_dmabuf_clip - Callback to encode a suface DMA command cliprect + * vmw_stdu_bo_clip - Callback to encode a suface DMA command cliprect * * @dirty: The closure structure. * * Encodes a surface DMA command cliprect and updates the bounding box * for the DMA. */ -static void vmw_stdu_dmabuf_clip(struct vmw_kms_dirty *dirty) +static void vmw_stdu_bo_clip(struct vmw_kms_dirty *dirty) { struct vmw_stdu_dirty *ddirty = container_of(dirty, struct vmw_stdu_dirty, base); @@ -543,14 +543,14 @@ static void vmw_stdu_dmabuf_clip(struct vmw_kms_dirty *dirty) } /** - * vmw_stdu_dmabuf_fifo_commit - Callback to fill in and submit a DMA command. + * vmw_stdu_bo_fifo_commit - Callback to fill in and submit a DMA command. * * @dirty: The closure structure. * * Fills in the missing fields in a DMA command, and optionally encodes * a screen target update command, depending on transfer direction. */ -static void vmw_stdu_dmabuf_fifo_commit(struct vmw_kms_dirty *dirty) +static void vmw_stdu_bo_fifo_commit(struct vmw_kms_dirty *dirty) { struct vmw_stdu_dirty *ddirty = container_of(dirty, struct vmw_stdu_dirty, base); @@ -594,13 +594,13 @@ static void vmw_stdu_dmabuf_fifo_commit(struct vmw_kms_dirty *dirty) /** - * vmw_stdu_dmabuf_cpu_clip - Callback to encode a CPU blit + * vmw_stdu_bo_cpu_clip - Callback to encode a CPU blit * * @dirty: The closure structure. * * This function calculates the bounding box for all the incoming clips. */ -static void vmw_stdu_dmabuf_cpu_clip(struct vmw_kms_dirty *dirty) +static void vmw_stdu_bo_cpu_clip(struct vmw_kms_dirty *dirty) { struct vmw_stdu_dirty *ddirty = container_of(dirty, struct vmw_stdu_dirty, base); @@ -624,14 +624,14 @@ static void vmw_stdu_dmabuf_cpu_clip(struct vmw_kms_dirty *dirty) /** - * vmw_stdu_dmabuf_cpu_commit - Callback to do a CPU blit from DMAbuf + * vmw_stdu_bo_cpu_commit - Callback to do a CPU blit from buffer object * * @dirty: The closure structure. * * For the special case when we cannot create a proxy surface in a * 2D VM, we have to do a CPU blit ourselves. */ -static void vmw_stdu_dmabuf_cpu_commit(struct vmw_kms_dirty *dirty) +static void vmw_stdu_bo_cpu_commit(struct vmw_kms_dirty *dirty) { struct vmw_stdu_dirty *ddirty = container_of(dirty, struct vmw_stdu_dirty, base); @@ -652,7 +652,7 @@ static void vmw_stdu_dmabuf_cpu_commit(struct vmw_kms_dirty *dirty) if (width == 0 || height == 0) return; - /* Assume we are blitting from Guest (dmabuf) to Host (display_srf) */ + /* Assume we are blitting from Guest (bo) to Host (display_srf) */ dst_pitch = stdu->display_srf->base_size.width * stdu->cpp; dst_bo = &stdu->display_srf->res.backup->base; dst_offset = ddirty->top * dst_pitch + ddirty->left * stdu->cpp; @@ -712,13 +712,13 @@ static void vmw_stdu_dmabuf_cpu_commit(struct vmw_kms_dirty *dirty) } /** - * vmw_kms_stdu_dma - Perform a DMA transfer between a dma-buffer backed + * vmw_kms_stdu_dma - Perform a DMA transfer between a buffer-object backed * framebuffer and the screen target system. * * @dev_priv: Pointer to the device private structure. * @file_priv: Pointer to a struct drm-file identifying the caller. May be * set to NULL, but then @user_fence_rep must also be set to NULL. - * @vfb: Pointer to the dma-buffer backed framebuffer. + * @vfb: Pointer to the buffer-object backed framebuffer. * @clips: Array of clip rects. Either @clips or @vclips must be NULL. * @vclips: Alternate array of clip rects. Either @clips or @vclips must * be NULL. @@ -747,8 +747,8 @@ int vmw_kms_stdu_dma(struct vmw_private *dev_priv, bool interruptible, struct drm_crtc *crtc) { - struct vmw_dma_buffer *buf = - container_of(vfb, struct vmw_framebuffer_dmabuf, base)->buffer; + struct vmw_buffer_object *buf = + container_of(vfb, struct vmw_framebuffer_bo, base)->buffer; struct vmw_stdu_dirty ddirty; int ret; bool cpu_blit = !(dev_priv->capabilities & SVGA_CAP_3D); @@ -770,8 +770,8 @@ int vmw_kms_stdu_dma(struct vmw_private *dev_priv, ddirty.fb_left = ddirty.fb_top = S32_MAX; ddirty.pitch = vfb->base.pitches[0]; ddirty.buf = buf; - ddirty.base.fifo_commit = vmw_stdu_dmabuf_fifo_commit; - ddirty.base.clip = vmw_stdu_dmabuf_clip; + ddirty.base.fifo_commit = vmw_stdu_bo_fifo_commit; + ddirty.base.clip = vmw_stdu_bo_clip; ddirty.base.fifo_reserve_size = sizeof(struct vmw_stdu_dma) + num_clips * sizeof(SVGA3dCopyBox) + sizeof(SVGA3dCmdSurfaceDMASuffix); @@ -780,8 +780,8 @@ int vmw_kms_stdu_dma(struct vmw_private *dev_priv, if (cpu_blit) { - ddirty.base.fifo_commit = vmw_stdu_dmabuf_cpu_commit; - ddirty.base.clip = vmw_stdu_dmabuf_cpu_clip; + ddirty.base.fifo_commit = vmw_stdu_bo_cpu_commit; + ddirty.base.clip = vmw_stdu_bo_cpu_clip; ddirty.base.fifo_reserve_size = 0; } @@ -927,7 +927,7 @@ int vmw_kms_stdu_surface_dirty(struct vmw_private *dev_priv, if (ret) return ret; - if (vfbs->is_dmabuf_proxy) { + if (vfbs->is_bo_proxy) { ret = vmw_kms_update_proxy(srf, clips, num_clips, inc); if (ret) goto out_finish; @@ -1075,7 +1075,7 @@ vmw_stdu_primary_plane_cleanup_fb(struct drm_plane *plane, * @new_state: info on the new plane state, including the FB * * This function allocates a new display surface if the content is - * backed by a DMA. The display surface is pinned here, and it'll + * backed by a buffer object. The display surface is pinned here, and it'll * be unpinned in .cleanup_fb() * * Returns 0 on success @@ -1105,13 +1105,13 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane, } vfb = vmw_framebuffer_to_vfb(new_fb); - new_vfbs = (vfb->dmabuf) ? NULL : vmw_framebuffer_to_vfbs(new_fb); + new_vfbs = (vfb->bo) ? NULL : vmw_framebuffer_to_vfbs(new_fb); if (new_vfbs && new_vfbs->surface->base_size.width == hdisplay && new_vfbs->surface->base_size.height == vdisplay) new_content_type = SAME_AS_DISPLAY; - else if (vfb->dmabuf) - new_content_type = SEPARATE_DMA; + else if (vfb->bo) + new_content_type = SEPARATE_BO; else new_content_type = SEPARATE_SURFACE; @@ -1124,10 +1124,10 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane, display_base_size.depth = 1; /* - * If content buffer is a DMA buf, then we have to construct - * surface info + * If content buffer is a buffer object, then we have to + * construct surface info */ - if (new_content_type == SEPARATE_DMA) { + if (new_content_type == SEPARATE_BO) { switch (new_fb->format->cpp[0]*8) { case 32: @@ -1212,12 +1212,12 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane, vps->content_fb_type = new_content_type; /* - * This should only happen if the DMA buf is too large to create a + * This should only happen if the buffer object is too large to create a * proxy surface for. - * If we are a 2D VM with a DMA buffer then we have to use CPU blit + * If we are a 2D VM with a buffer object then we have to use CPU blit * so cache these mappings */ - if (vps->content_fb_type == SEPARATE_DMA && + if (vps->content_fb_type == SEPARATE_BO && !(dev_priv->capabilities & SVGA_CAP_3D)) vps->cpp = new_fb->pitches[0] / new_fb->width; @@ -1276,7 +1276,7 @@ vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane, if (ret) DRM_ERROR("Failed to bind surface to STDU.\n"); - if (vfb->dmabuf) + if (vfb->bo) ret = vmw_kms_stdu_dma(dev_priv, NULL, vfb, NULL, NULL, &vclips, 1, 1, true, false, crtc); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c index b236c48bf265b..2b2e8aa7114a6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c @@ -842,12 +842,12 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, if (dev_priv->has_mob && req->shareable) { uint32_t backup_handle; - ret = vmw_user_dmabuf_alloc(dev_priv, tfile, - res->backup_size, - true, - &backup_handle, - &res->backup, - &user_srf->backup_base); + ret = vmw_user_bo_alloc(dev_priv, tfile, + res->backup_size, + true, + &backup_handle, + &res->backup, + &user_srf->backup_base); if (unlikely(ret != 0)) { vmw_resource_unreference(&res); goto out_unlock; @@ -1317,14 +1317,14 @@ int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data, if (req->buffer_handle != SVGA3D_INVALID_ID) { - ret = vmw_user_dmabuf_lookup(tfile, req->buffer_handle, - &res->backup, - &user_srf->backup_base); + ret = vmw_user_bo_lookup(tfile, req->buffer_handle, + &res->backup, + &user_srf->backup_base); if (ret == 0) { if (res->backup->base.num_pages * PAGE_SIZE < res->backup_size) { DRM_ERROR("Surface backup buffer is too small.\n"); - vmw_dmabuf_unreference(&res->backup); + vmw_bo_unreference(&res->backup); ret = -EINVAL; goto out_unlock; } else { @@ -1332,13 +1332,13 @@ int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data, } } } else if (req->drm_surface_flags & drm_vmw_surface_flag_create_buffer) - ret = vmw_user_dmabuf_alloc(dev_priv, tfile, - res->backup_size, - req->drm_surface_flags & - drm_vmw_surface_flag_shareable, - &backup_handle, - &res->backup, - &user_srf->backup_base); + ret = vmw_user_bo_alloc(dev_priv, tfile, + res->backup_size, + req->drm_surface_flags & + drm_vmw_surface_flag_shareable, + &backup_handle, + &res->backup, + &user_srf->backup_base); if (unlikely(ret != 0)) { vmw_resource_unreference(&res); @@ -1414,8 +1414,7 @@ int vmw_gb_surface_reference_ioctl(struct drm_device *dev, void *data, } mutex_lock(&dev_priv->cmdbuf_mutex); /* Protect res->backup */ - ret = vmw_user_dmabuf_reference(tfile, srf->res.backup, - &backup_handle); + ret = vmw_user_bo_reference(tfile, srf->res.backup, &backup_handle); mutex_unlock(&dev_priv->cmdbuf_mutex); if (unlikely(ret != 0)) { diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c similarity index 99% rename from drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c rename to drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c index 21111fd091f95..0931f43913b1e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c @@ -798,7 +798,7 @@ static int vmw_verify_access(struct ttm_buffer_object *bo, struct file *filp) struct ttm_object_file *tfile = vmw_fpriv((struct drm_file *)filp->private_data)->tfile; - return vmw_user_dmabuf_verify_access(bo, tfile); + return vmw_user_bo_verify_access(bo, tfile); } static int vmw_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) diff --git a/include/uapi/drm/vmwgfx_drm.h b/include/uapi/drm/vmwgfx_drm.h index 0bc784f5e0dbe..57115a5fe61a7 100644 --- a/include/uapi/drm/vmwgfx_drm.h +++ b/include/uapi/drm/vmwgfx_drm.h @@ -40,6 +40,7 @@ extern "C" { #define DRM_VMW_GET_PARAM 0 #define DRM_VMW_ALLOC_DMABUF 1 +#define DRM_VMW_ALLOC_BO 1 #define DRM_VMW_UNREF_DMABUF 2 #define DRM_VMW_HANDLE_CLOSE 2 #define DRM_VMW_CURSOR_BYPASS 3 @@ -356,9 +357,9 @@ struct drm_vmw_fence_rep { /*************************************************************************/ /** - * DRM_VMW_ALLOC_DMABUF + * DRM_VMW_ALLOC_BO * - * Allocate a DMA buffer that is visible also to the host. + * Allocate a buffer object that is visible also to the host. * NOTE: The buffer is * identified by a handle and an offset, which are private to the guest, but * useable in the command stream. The guest kernel may translate these @@ -366,27 +367,28 @@ struct drm_vmw_fence_rep { * be zero at all times, or it may disappear from the interface before it is * fixed. * - * The DMA buffer may stay user-space mapped in the guest at all times, + * The buffer object may stay user-space mapped in the guest at all times, * and is thus suitable for sub-allocation. * - * DMA buffers are mapped using the mmap() syscall on the drm device. + * Buffer objects are mapped using the mmap() syscall on the drm device. */ /** - * struct drm_vmw_alloc_dmabuf_req + * struct drm_vmw_alloc_bo_req * * @size: Required minimum size of the buffer. * - * Input data to the DRM_VMW_ALLOC_DMABUF Ioctl. + * Input data to the DRM_VMW_ALLOC_BO Ioctl. */ -struct drm_vmw_alloc_dmabuf_req { +struct drm_vmw_alloc_bo_req { __u32 size; __u32 pad64; }; +#define drm_vmw_alloc_dmabuf_req drm_vmw_alloc_bo_req /** - * struct drm_vmw_dmabuf_rep + * struct drm_vmw_bo_rep * * @map_handle: Offset to use in the mmap() call used to map the buffer. * @handle: Handle unique to this buffer. Used for unreferencing. @@ -395,50 +397,32 @@ struct drm_vmw_alloc_dmabuf_req { * @cur_gmr_offset: Offset to use in the command stream when this buffer is * referenced. See note above. * - * Output data from the DRM_VMW_ALLOC_DMABUF Ioctl. + * Output data from the DRM_VMW_ALLOC_BO Ioctl. */ -struct drm_vmw_dmabuf_rep { +struct drm_vmw_bo_rep { __u64 map_handle; __u32 handle; __u32 cur_gmr_id; __u32 cur_gmr_offset; __u32 pad64; }; +#define drm_vmw_dmabuf_rep drm_vmw_bo_rep /** - * union drm_vmw_dmabuf_arg + * union drm_vmw_alloc_bo_arg * * @req: Input data as described above. * @rep: Output data as described above. * - * Argument to the DRM_VMW_ALLOC_DMABUF Ioctl. + * Argument to the DRM_VMW_ALLOC_BO Ioctl. */ -union drm_vmw_alloc_dmabuf_arg { - struct drm_vmw_alloc_dmabuf_req req; - struct drm_vmw_dmabuf_rep rep; -}; - -/*************************************************************************/ -/** - * DRM_VMW_UNREF_DMABUF - Free a DMA buffer. - * - */ - -/** - * struct drm_vmw_unref_dmabuf_arg - * - * @handle: Handle indicating what buffer to free. Obtained from the - * DRM_VMW_ALLOC_DMABUF Ioctl. - * - * Argument to the DRM_VMW_UNREF_DMABUF Ioctl. - */ - -struct drm_vmw_unref_dmabuf_arg { - __u32 handle; - __u32 pad64; +union drm_vmw_alloc_bo_arg { + struct drm_vmw_alloc_bo_req req; + struct drm_vmw_bo_rep rep; }; +#define drm_vmw_alloc_dmabuf_arg drm_vmw_alloc_bo_arg /*************************************************************************/ /** @@ -1103,9 +1087,8 @@ union drm_vmw_extended_context_arg { * DRM_VMW_HANDLE_CLOSE - Close a user-space handle and release its * underlying resource. * - * Note that this ioctl is overlaid on the DRM_VMW_UNREF_DMABUF Ioctl. - * The ioctl arguments therefore need to be identical in layout. - * + * Note that this ioctl is overlaid on the deprecated DRM_VMW_UNREF_DMABUF + * Ioctl. */ /** @@ -1119,7 +1102,7 @@ struct drm_vmw_handle_close_arg { __u32 handle; __u32 pad64; }; - +#define drm_vmw_unref_dmabuf_arg drm_vmw_handle_close_arg #if defined(__cplusplus) } -- GitLab From e9431ea5076a913a3b350cf5f89eacf9375126b1 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom <thellstrom@vmware.com> Date: Tue, 19 Jun 2018 15:33:53 +0200 Subject: [PATCH 0633/1506] drm/vmwgfx: Move buffer object related code to vmwgfx_bo.c It makes more sense to have all the buffer object related code in a single file rather than splitting it up between the resource code and buffer object pinning utilities. Place all buffer object related code in vmwgfx_bo.c. Fix up headers and export resource functionality when needed in the buffer object code. Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Reviewed-by: Brian Paul <brianp@vmware.com> Reviewed-by: Sinclair Yeh <syeh@vmware.com> Reviewed-by: Deepak Rawat <drawat@vmware.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_bo.c | 816 ++++++++++++++++++++- drivers/gpu/drm/vmwgfx/vmwgfx_context.c | 4 +- drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c | 4 +- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 73 +- drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_mob.c | 6 +- drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 640 +--------------- drivers/gpu/drm/vmwgfx/vmwgfx_shader.c | 4 +- drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 4 +- drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c | 4 +- 11 files changed, 851 insertions(+), 708 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c index f26f658cccdbf..d950244798fe3 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c @@ -1,6 +1,6 @@ /************************************************************************** * - * Copyright © 2011-2015 VMware, Inc., Palo Alto, CA., USA + * Copyright © 2011-2018 VMware, Inc., Palo Alto, CA., USA * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -29,6 +29,51 @@ #include <drm/drmP.h> #include "vmwgfx_drv.h" +#include "drm/ttm/ttm_object.h" + + +/** + * struct vmw_user_buffer_object - User-space-visible buffer object + * + * @prime: The prime object providing user visibility. + * @vbo: The struct vmw_buffer_object + */ +struct vmw_user_buffer_object { + struct ttm_prime_object prime; + struct vmw_buffer_object vbo; +}; + + +/** + * vmw_buffer_object - Convert a struct ttm_buffer_object to a struct + * vmw_buffer_object. + * + * @bo: Pointer to the TTM buffer object. + * Return: Pointer to the struct vmw_buffer_object embedding the + * TTM buffer object. + */ +static struct vmw_buffer_object * +vmw_buffer_object(struct ttm_buffer_object *bo) +{ + return container_of(bo, struct vmw_buffer_object, base); +} + + +/** + * vmw_user_buffer_object - Convert a struct ttm_buffer_object to a struct + * vmw_user_buffer_object. + * + * @bo: Pointer to the TTM buffer object. + * Return: Pointer to the struct vmw_buffer_object embedding the TTM buffer + * object. + */ +static struct vmw_user_buffer_object * +vmw_user_buffer_object(struct ttm_buffer_object *bo) +{ + struct vmw_buffer_object *vmw_bo = vmw_buffer_object(bo); + + return container_of(vmw_bo, struct vmw_user_buffer_object, vbo); +} /** @@ -38,9 +83,8 @@ * @buf: DMA buffer to move. * @placement: The placement to pin it. * @interruptible: Use interruptible wait. - * - * Returns - * -ERESTARTSYS if interrupted by a signal. + * Return: Zero on success, Negative error code on failure. In particular + * -ERESTARTSYS if interrupted by a signal */ int vmw_bo_pin_in_placement(struct vmw_private *dev_priv, struct vmw_buffer_object *buf, @@ -78,6 +122,7 @@ int vmw_bo_pin_in_placement(struct vmw_private *dev_priv, return ret; } + /** * vmw_bo_pin_in_vram_or_gmr - Move a buffer to vram or gmr. * @@ -88,9 +133,8 @@ int vmw_bo_pin_in_placement(struct vmw_private *dev_priv, * @buf: DMA buffer to move. * @pin: Pin buffer if true. * @interruptible: Use interruptible wait. - * - * Returns - * -ERESTARTSYS if interrupted by a signal. + * Return: Zero on success, Negative error code on failure. In particular + * -ERESTARTSYS if interrupted by a signal */ int vmw_bo_pin_in_vram_or_gmr(struct vmw_private *dev_priv, struct vmw_buffer_object *buf, @@ -133,6 +177,7 @@ int vmw_bo_pin_in_vram_or_gmr(struct vmw_private *dev_priv, return ret; } + /** * vmw_bo_pin_in_vram - Move a buffer to vram. * @@ -142,9 +187,8 @@ int vmw_bo_pin_in_vram_or_gmr(struct vmw_private *dev_priv, * @dev_priv: Driver private. * @buf: DMA buffer to move. * @interruptible: Use interruptible wait. - * - * Returns - * -ERESTARTSYS if interrupted by a signal. + * Return: Zero on success, Negative error code on failure. In particular + * -ERESTARTSYS if interrupted by a signal */ int vmw_bo_pin_in_vram(struct vmw_private *dev_priv, struct vmw_buffer_object *buf, @@ -154,6 +198,7 @@ int vmw_bo_pin_in_vram(struct vmw_private *dev_priv, interruptible); } + /** * vmw_bo_pin_in_start_of_vram - Move a buffer to start of vram. * @@ -163,9 +208,8 @@ int vmw_bo_pin_in_vram(struct vmw_private *dev_priv, * @dev_priv: Driver private. * @buf: DMA buffer to pin. * @interruptible: Use interruptible wait. - * - * Returns - * -ERESTARTSYS if interrupted by a signal. + * Return: Zero on success, Negative error code on failure. In particular + * -ERESTARTSYS if interrupted by a signal */ int vmw_bo_pin_in_start_of_vram(struct vmw_private *dev_priv, struct vmw_buffer_object *buf, @@ -225,6 +269,7 @@ int vmw_bo_pin_in_start_of_vram(struct vmw_private *dev_priv, return ret; } + /** * vmw_bo_unpin - Unpin the buffer given buffer, does not move the buffer. * @@ -233,9 +278,8 @@ int vmw_bo_pin_in_start_of_vram(struct vmw_private *dev_priv, * @dev_priv: Driver private. * @buf: DMA buffer to unpin. * @interruptible: Use interruptible wait. - * - * Returns - * -ERESTARTSYS if interrupted by a signal. + * Return: Zero on success, Negative error code on failure. In particular + * -ERESTARTSYS if interrupted by a signal */ int vmw_bo_unpin(struct vmw_private *dev_priv, struct vmw_buffer_object *buf, @@ -325,25 +369,8 @@ void vmw_bo_pin_reserved(struct vmw_buffer_object *vbo, bool pin) } -/* - * vmw_buffer_object_unmap - Tear down a cached buffer object map. - * - * @vbo: The buffer object whose map we are tearing down. - * - * This function tears down a cached map set up using - * vmw_buffer_object_map_and_cache(). - */ -void vmw_buffer_object_unmap(struct vmw_buffer_object *vbo) -{ - if (vbo->map.bo == NULL) - return; - - ttm_bo_kunmap(&vbo->map); -} - - -/* - * vmw_buffer_object_map_and_cache - Map a buffer object and cache the map +/** + * vmw_bo_map_and_cache - Map a buffer object and cache the map * * @vbo: The buffer object to map * Return: A kernel virtual address or NULL if mapping failed. @@ -357,7 +384,7 @@ void vmw_buffer_object_unmap(struct vmw_buffer_object *vbo) * 3) Buffer object destruction * */ -void *vmw_buffer_object_map_and_cache(struct vmw_buffer_object *vbo) +void *vmw_bo_map_and_cache(struct vmw_buffer_object *vbo) { struct ttm_buffer_object *bo = &vbo->base; bool not_used; @@ -374,3 +401,720 @@ void *vmw_buffer_object_map_and_cache(struct vmw_buffer_object *vbo) return ttm_kmap_obj_virtual(&vbo->map, ¬_used); } + + +/** + * vmw_bo_unmap - Tear down a cached buffer object map. + * + * @vbo: The buffer object whose map we are tearing down. + * + * This function tears down a cached map set up using + * vmw_buffer_object_map_and_cache(). + */ +void vmw_bo_unmap(struct vmw_buffer_object *vbo) +{ + if (vbo->map.bo == NULL) + return; + + ttm_bo_kunmap(&vbo->map); +} + + +/** + * vmw_bo_acc_size - Calculate the pinned memory usage of buffers + * + * @dev_priv: Pointer to a struct vmw_private identifying the device. + * @size: The requested buffer size. + * @user: Whether this is an ordinary dma buffer or a user dma buffer. + */ +static size_t vmw_bo_acc_size(struct vmw_private *dev_priv, size_t size, + bool user) +{ + static size_t struct_size, user_struct_size; + size_t num_pages = PAGE_ALIGN(size) >> PAGE_SHIFT; + size_t page_array_size = ttm_round_pot(num_pages * sizeof(void *)); + + if (unlikely(struct_size == 0)) { + size_t backend_size = ttm_round_pot(vmw_tt_size); + + struct_size = backend_size + + ttm_round_pot(sizeof(struct vmw_buffer_object)); + user_struct_size = backend_size + + ttm_round_pot(sizeof(struct vmw_user_buffer_object)); + } + + if (dev_priv->map_mode == vmw_dma_alloc_coherent) + page_array_size += + ttm_round_pot(num_pages * sizeof(dma_addr_t)); + + return ((user) ? user_struct_size : struct_size) + + page_array_size; +} + + +/** + * vmw_bo_bo_free - vmw buffer object destructor + * + * @bo: Pointer to the embedded struct ttm_buffer_object + */ +void vmw_bo_bo_free(struct ttm_buffer_object *bo) +{ + struct vmw_buffer_object *vmw_bo = vmw_buffer_object(bo); + + vmw_bo_unmap(vmw_bo); + kfree(vmw_bo); +} + + +/** + * vmw_user_bo_destroy - vmw buffer object destructor + * + * @bo: Pointer to the embedded struct ttm_buffer_object + */ +static void vmw_user_bo_destroy(struct ttm_buffer_object *bo) +{ + struct vmw_user_buffer_object *vmw_user_bo = vmw_user_buffer_object(bo); + + vmw_bo_unmap(&vmw_user_bo->vbo); + ttm_prime_object_kfree(vmw_user_bo, prime); +} + + +/** + * vmw_bo_init - Initialize a vmw buffer object + * + * @dev_priv: Pointer to the device private struct + * @vmw_bo: Pointer to the struct vmw_buffer_object to initialize. + * @size: Buffer object size in bytes. + * @placement: Initial placement. + * @interruptible: Whether waits should be performed interruptible. + * @bo_free: The buffer object destructor. + * Returns: Zero on success, negative error code on error. + * + * Note that on error, the code will free the buffer object. + */ +int vmw_bo_init(struct vmw_private *dev_priv, + struct vmw_buffer_object *vmw_bo, + size_t size, struct ttm_placement *placement, + bool interruptible, + void (*bo_free)(struct ttm_buffer_object *bo)) +{ + struct ttm_bo_device *bdev = &dev_priv->bdev; + size_t acc_size; + int ret; + bool user = (bo_free == &vmw_user_bo_destroy); + + WARN_ON_ONCE(!bo_free && (!user && (bo_free != vmw_bo_bo_free))); + + acc_size = vmw_bo_acc_size(dev_priv, size, user); + memset(vmw_bo, 0, sizeof(*vmw_bo)); + + INIT_LIST_HEAD(&vmw_bo->res_list); + + ret = ttm_bo_init(bdev, &vmw_bo->base, size, + ttm_bo_type_device, placement, + 0, interruptible, acc_size, + NULL, NULL, bo_free); + return ret; +} + + +/** + * vmw_user_bo_release - TTM reference base object release callback for + * vmw user buffer objects + * + * @p_base: The TTM base object pointer about to be unreferenced. + * + * Clears the TTM base object pointer and drops the reference the + * base object has on the underlying struct vmw_buffer_object. + */ +static void vmw_user_bo_release(struct ttm_base_object **p_base) +{ + struct vmw_user_buffer_object *vmw_user_bo; + struct ttm_base_object *base = *p_base; + struct ttm_buffer_object *bo; + + *p_base = NULL; + + if (unlikely(base == NULL)) + return; + + vmw_user_bo = container_of(base, struct vmw_user_buffer_object, + prime.base); + bo = &vmw_user_bo->vbo.base; + ttm_bo_unref(&bo); +} + + +/** + * vmw_user_bo_ref_obj-release - TTM synccpu reference object release callback + * for vmw user buffer objects + * + * @base: Pointer to the TTM base object + * @ref_type: Reference type of the reference reaching zero. + * + * Called when user-space drops its last synccpu reference on the buffer + * object, Either explicitly or as part of a cleanup file close. + */ +static void vmw_user_bo_ref_obj_release(struct ttm_base_object *base, + enum ttm_ref_type ref_type) +{ + struct vmw_user_buffer_object *user_bo; + + user_bo = container_of(base, struct vmw_user_buffer_object, prime.base); + + switch (ref_type) { + case TTM_REF_SYNCCPU_WRITE: + ttm_bo_synccpu_write_release(&user_bo->vbo.base); + break; + default: + WARN_ONCE(true, "Undefined buffer object reference release.\n"); + } +} + + +/** + * vmw_user_bo_alloc - Allocate a user buffer object + * + * @dev_priv: Pointer to a struct device private. + * @tfile: Pointer to a struct ttm_object_file on which to register the user + * object. + * @size: Size of the buffer object. + * @shareable: Boolean whether the buffer is shareable with other open files. + * @handle: Pointer to where the handle value should be assigned. + * @p_vbo: Pointer to where the refcounted struct vmw_buffer_object pointer + * should be assigned. + * Return: Zero on success, negative error code on error. + */ +int vmw_user_bo_alloc(struct vmw_private *dev_priv, + struct ttm_object_file *tfile, + uint32_t size, + bool shareable, + uint32_t *handle, + struct vmw_buffer_object **p_vbo, + struct ttm_base_object **p_base) +{ + struct vmw_user_buffer_object *user_bo; + struct ttm_buffer_object *tmp; + int ret; + + user_bo = kzalloc(sizeof(*user_bo), GFP_KERNEL); + if (unlikely(!user_bo)) { + DRM_ERROR("Failed to allocate a buffer.\n"); + return -ENOMEM; + } + + ret = vmw_bo_init(dev_priv, &user_bo->vbo, size, + (dev_priv->has_mob) ? + &vmw_sys_placement : + &vmw_vram_sys_placement, true, + &vmw_user_bo_destroy); + if (unlikely(ret != 0)) + return ret; + + tmp = ttm_bo_reference(&user_bo->vbo.base); + ret = ttm_prime_object_init(tfile, + size, + &user_bo->prime, + shareable, + ttm_buffer_type, + &vmw_user_bo_release, + &vmw_user_bo_ref_obj_release); + if (unlikely(ret != 0)) { + ttm_bo_unref(&tmp); + goto out_no_base_object; + } + + *p_vbo = &user_bo->vbo; + if (p_base) { + *p_base = &user_bo->prime.base; + kref_get(&(*p_base)->refcount); + } + *handle = user_bo->prime.base.hash.key; + +out_no_base_object: + return ret; +} + + +/** + * vmw_user_bo_verify_access - verify access permissions on this + * buffer object. + * + * @bo: Pointer to the buffer object being accessed + * @tfile: Identifying the caller. + */ +int vmw_user_bo_verify_access(struct ttm_buffer_object *bo, + struct ttm_object_file *tfile) +{ + struct vmw_user_buffer_object *vmw_user_bo; + + if (unlikely(bo->destroy != vmw_user_bo_destroy)) + return -EPERM; + + vmw_user_bo = vmw_user_buffer_object(bo); + + /* Check that the caller has opened the object. */ + if (likely(ttm_ref_object_exists(tfile, &vmw_user_bo->prime.base))) + return 0; + + DRM_ERROR("Could not grant buffer access.\n"); + return -EPERM; +} + + +/** + * vmw_user_bo_synccpu_grab - Grab a struct vmw_user_buffer_object for cpu + * access, idling previous GPU operations on the buffer and optionally + * blocking it for further command submissions. + * + * @user_bo: Pointer to the buffer object being grabbed for CPU access + * @tfile: Identifying the caller. + * @flags: Flags indicating how the grab should be performed. + * Return: Zero on success, Negative error code on error. In particular, + * -EBUSY will be returned if a dontblock operation is requested and the + * buffer object is busy, and -ERESTARTSYS will be returned if a wait is + * interrupted by a signal. + * + * A blocking grab will be automatically released when @tfile is closed. + */ +static int vmw_user_bo_synccpu_grab(struct vmw_user_buffer_object *user_bo, + struct ttm_object_file *tfile, + uint32_t flags) +{ + struct ttm_buffer_object *bo = &user_bo->vbo.base; + bool existed; + int ret; + + if (flags & drm_vmw_synccpu_allow_cs) { + bool nonblock = !!(flags & drm_vmw_synccpu_dontblock); + long lret; + + lret = reservation_object_wait_timeout_rcu + (bo->resv, true, true, + nonblock ? 0 : MAX_SCHEDULE_TIMEOUT); + if (!lret) + return -EBUSY; + else if (lret < 0) + return lret; + return 0; + } + + ret = ttm_bo_synccpu_write_grab + (bo, !!(flags & drm_vmw_synccpu_dontblock)); + if (unlikely(ret != 0)) + return ret; + + ret = ttm_ref_object_add(tfile, &user_bo->prime.base, + TTM_REF_SYNCCPU_WRITE, &existed, false); + if (ret != 0 || existed) + ttm_bo_synccpu_write_release(&user_bo->vbo.base); + + return ret; +} + +/** + * vmw_user_bo_synccpu_release - Release a previous grab for CPU access, + * and unblock command submission on the buffer if blocked. + * + * @handle: Handle identifying the buffer object. + * @tfile: Identifying the caller. + * @flags: Flags indicating the type of release. + */ +static int vmw_user_bo_synccpu_release(uint32_t handle, + struct ttm_object_file *tfile, + uint32_t flags) +{ + if (!(flags & drm_vmw_synccpu_allow_cs)) + return ttm_ref_object_base_unref(tfile, handle, + TTM_REF_SYNCCPU_WRITE); + + return 0; +} + + +/** + * vmw_user_bo_synccpu_ioctl - ioctl function implementing the synccpu + * functionality. + * + * @dev: Identifies the drm device. + * @data: Pointer to the ioctl argument. + * @file_priv: Identifies the caller. + * Return: Zero on success, negative error code on error. + * + * This function checks the ioctl arguments for validity and calls the + * relevant synccpu functions. + */ +int vmw_user_bo_synccpu_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_vmw_synccpu_arg *arg = + (struct drm_vmw_synccpu_arg *) data; + struct vmw_buffer_object *vbo; + struct vmw_user_buffer_object *user_bo; + struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; + struct ttm_base_object *buffer_base; + int ret; + + if ((arg->flags & (drm_vmw_synccpu_read | drm_vmw_synccpu_write)) == 0 + || (arg->flags & ~(drm_vmw_synccpu_read | drm_vmw_synccpu_write | + drm_vmw_synccpu_dontblock | + drm_vmw_synccpu_allow_cs)) != 0) { + DRM_ERROR("Illegal synccpu flags.\n"); + return -EINVAL; + } + + switch (arg->op) { + case drm_vmw_synccpu_grab: + ret = vmw_user_bo_lookup(tfile, arg->handle, &vbo, + &buffer_base); + if (unlikely(ret != 0)) + return ret; + + user_bo = container_of(vbo, struct vmw_user_buffer_object, + vbo); + ret = vmw_user_bo_synccpu_grab(user_bo, tfile, arg->flags); + vmw_bo_unreference(&vbo); + ttm_base_object_unref(&buffer_base); + if (unlikely(ret != 0 && ret != -ERESTARTSYS && + ret != -EBUSY)) { + DRM_ERROR("Failed synccpu grab on handle 0x%08x.\n", + (unsigned int) arg->handle); + return ret; + } + break; + case drm_vmw_synccpu_release: + ret = vmw_user_bo_synccpu_release(arg->handle, tfile, + arg->flags); + if (unlikely(ret != 0)) { + DRM_ERROR("Failed synccpu release on handle 0x%08x.\n", + (unsigned int) arg->handle); + return ret; + } + break; + default: + DRM_ERROR("Invalid synccpu operation.\n"); + return -EINVAL; + } + + return 0; +} + + +/** + * vmw_bo_alloc_ioctl - ioctl function implementing the buffer object + * allocation functionality. + * + * @dev: Identifies the drm device. + * @data: Pointer to the ioctl argument. + * @file_priv: Identifies the caller. + * Return: Zero on success, negative error code on error. + * + * This function checks the ioctl arguments for validity and allocates a + * struct vmw_user_buffer_object bo. + */ +int vmw_bo_alloc_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct vmw_private *dev_priv = vmw_priv(dev); + union drm_vmw_alloc_dmabuf_arg *arg = + (union drm_vmw_alloc_dmabuf_arg *)data; + struct drm_vmw_alloc_dmabuf_req *req = &arg->req; + struct drm_vmw_dmabuf_rep *rep = &arg->rep; + struct vmw_buffer_object *vbo; + uint32_t handle; + int ret; + + ret = ttm_read_lock(&dev_priv->reservation_sem, true); + if (unlikely(ret != 0)) + return ret; + + ret = vmw_user_bo_alloc(dev_priv, vmw_fpriv(file_priv)->tfile, + req->size, false, &handle, &vbo, + NULL); + if (unlikely(ret != 0)) + goto out_no_bo; + + rep->handle = handle; + rep->map_handle = drm_vma_node_offset_addr(&vbo->base.vma_node); + rep->cur_gmr_id = handle; + rep->cur_gmr_offset = 0; + + vmw_bo_unreference(&vbo); + +out_no_bo: + ttm_read_unlock(&dev_priv->reservation_sem); + + return ret; +} + + +/** + * vmw_bo_unref_ioctl - Generic handle close ioctl. + * + * @dev: Identifies the drm device. + * @data: Pointer to the ioctl argument. + * @file_priv: Identifies the caller. + * Return: Zero on success, negative error code on error. + * + * This function checks the ioctl arguments for validity and closes a + * handle to a TTM base object, optionally freeing the object. + */ +int vmw_bo_unref_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_vmw_unref_dmabuf_arg *arg = + (struct drm_vmw_unref_dmabuf_arg *)data; + + return ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile, + arg->handle, + TTM_REF_USAGE); +} + + +/** + * vmw_user_bo_lookup - Look up a vmw user buffer object from a handle. + * + * @tfile: The TTM object file the handle is registered with. + * @handle: The user buffer object handle + * @out: Pointer to a where a pointer to the embedded + * struct vmw_buffer_object should be placed. + * @p_base: Pointer to where a pointer to the TTM base object should be + * placed, or NULL if no such pointer is required. + * Return: Zero on success, Negative error code on error. + * + * Both the output base object pointer and the vmw buffer object pointer + * will be refcounted. + */ +int vmw_user_bo_lookup(struct ttm_object_file *tfile, + uint32_t handle, struct vmw_buffer_object **out, + struct ttm_base_object **p_base) +{ + struct vmw_user_buffer_object *vmw_user_bo; + struct ttm_base_object *base; + + base = ttm_base_object_lookup(tfile, handle); + if (unlikely(base == NULL)) { + DRM_ERROR("Invalid buffer object handle 0x%08lx.\n", + (unsigned long)handle); + return -ESRCH; + } + + if (unlikely(ttm_base_object_type(base) != ttm_buffer_type)) { + ttm_base_object_unref(&base); + DRM_ERROR("Invalid buffer object handle 0x%08lx.\n", + (unsigned long)handle); + return -EINVAL; + } + + vmw_user_bo = container_of(base, struct vmw_user_buffer_object, + prime.base); + (void)ttm_bo_reference(&vmw_user_bo->vbo.base); + if (p_base) + *p_base = base; + else + ttm_base_object_unref(&base); + *out = &vmw_user_bo->vbo; + + return 0; +} + + +/** + * vmw_user_bo_reference - Open a handle to a vmw user buffer object. + * + * @tfile: The TTM object file to register the handle with. + * @vbo: The embedded vmw buffer object. + * @handle: Pointer to where the new handle should be placed. + * Return: Zero on success, Negative error code on error. + */ +int vmw_user_bo_reference(struct ttm_object_file *tfile, + struct vmw_buffer_object *vbo, + uint32_t *handle) +{ + struct vmw_user_buffer_object *user_bo; + + if (vbo->base.destroy != vmw_user_bo_destroy) + return -EINVAL; + + user_bo = container_of(vbo, struct vmw_user_buffer_object, vbo); + + *handle = user_bo->prime.base.hash.key; + return ttm_ref_object_add(tfile, &user_bo->prime.base, + TTM_REF_USAGE, NULL, false); +} + + +/** + * vmw_bo_fence_single - Utility function to fence a single TTM buffer + * object without unreserving it. + * + * @bo: Pointer to the struct ttm_buffer_object to fence. + * @fence: Pointer to the fence. If NULL, this function will + * insert a fence into the command stream.. + * + * Contrary to the ttm_eu version of this function, it takes only + * a single buffer object instead of a list, and it also doesn't + * unreserve the buffer object, which needs to be done separately. + */ +void vmw_bo_fence_single(struct ttm_buffer_object *bo, + struct vmw_fence_obj *fence) +{ + struct ttm_bo_device *bdev = bo->bdev; + + struct vmw_private *dev_priv = + container_of(bdev, struct vmw_private, bdev); + + if (fence == NULL) { + vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); + reservation_object_add_excl_fence(bo->resv, &fence->base); + dma_fence_put(&fence->base); + } else + reservation_object_add_excl_fence(bo->resv, &fence->base); +} + + +/** + * vmw_dumb_create - Create a dumb kms buffer + * + * @file_priv: Pointer to a struct drm_file identifying the caller. + * @dev: Pointer to the drm device. + * @args: Pointer to a struct drm_mode_create_dumb structure + * Return: Zero on success, negative error code on failure. + * + * This is a driver callback for the core drm create_dumb functionality. + * Note that this is very similar to the vmw_bo_alloc ioctl, except + * that the arguments have a different format. + */ +int vmw_dumb_create(struct drm_file *file_priv, + struct drm_device *dev, + struct drm_mode_create_dumb *args) +{ + struct vmw_private *dev_priv = vmw_priv(dev); + struct vmw_buffer_object *vbo; + int ret; + + args->pitch = args->width * ((args->bpp + 7) / 8); + args->size = args->pitch * args->height; + + ret = ttm_read_lock(&dev_priv->reservation_sem, true); + if (unlikely(ret != 0)) + return ret; + + ret = vmw_user_bo_alloc(dev_priv, vmw_fpriv(file_priv)->tfile, + args->size, false, &args->handle, + &vbo, NULL); + if (unlikely(ret != 0)) + goto out_no_bo; + + vmw_bo_unreference(&vbo); +out_no_bo: + ttm_read_unlock(&dev_priv->reservation_sem); + return ret; +} + + +/** + * vmw_dumb_map_offset - Return the address space offset of a dumb buffer + * + * @file_priv: Pointer to a struct drm_file identifying the caller. + * @dev: Pointer to the drm device. + * @handle: Handle identifying the dumb buffer. + * @offset: The address space offset returned. + * Return: Zero on success, negative error code on failure. + * + * This is a driver callback for the core drm dumb_map_offset functionality. + */ +int vmw_dumb_map_offset(struct drm_file *file_priv, + struct drm_device *dev, uint32_t handle, + uint64_t *offset) +{ + struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; + struct vmw_buffer_object *out_buf; + int ret; + + ret = vmw_user_bo_lookup(tfile, handle, &out_buf, NULL); + if (ret != 0) + return -EINVAL; + + *offset = drm_vma_node_offset_addr(&out_buf->base.vma_node); + vmw_bo_unreference(&out_buf); + return 0; +} + + +/** + * vmw_dumb_destroy - Destroy a dumb boffer + * + * @file_priv: Pointer to a struct drm_file identifying the caller. + * @dev: Pointer to the drm device. + * @handle: Handle identifying the dumb buffer. + * Return: Zero on success, negative error code on failure. + * + * This is a driver callback for the core drm dumb_destroy functionality. + */ +int vmw_dumb_destroy(struct drm_file *file_priv, + struct drm_device *dev, + uint32_t handle) +{ + return ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile, + handle, TTM_REF_USAGE); +} + + +/** + * vmw_bo_swap_notify - swapout notify callback. + * + * @bo: The buffer object to be swapped out. + */ +void vmw_bo_swap_notify(struct ttm_buffer_object *bo) +{ + /* Is @bo embedded in a struct vmw_buffer_object? */ + if (bo->destroy != vmw_bo_bo_free && + bo->destroy != vmw_user_bo_destroy) + return; + + /* Kill any cached kernel maps before swapout */ + vmw_bo_unmap(vmw_buffer_object(bo)); +} + + +/** + * vmw_bo_move_notify - TTM move_notify_callback + * + * @bo: The TTM buffer object about to move. + * @mem: The struct ttm_mem_reg indicating to what memory + * region the move is taking place. + * + * Detaches cached maps and device bindings that require that the + * buffer doesn't move. + */ +void vmw_bo_move_notify(struct ttm_buffer_object *bo, + struct ttm_mem_reg *mem) +{ + struct vmw_buffer_object *vbo; + + if (mem == NULL) + return; + + /* Make sure @bo is embedded in a struct vmw_buffer_object? */ + if (bo->destroy != vmw_bo_bo_free && + bo->destroy != vmw_user_bo_destroy) + return; + + vbo = container_of(bo, struct vmw_buffer_object, base); + + /* + * Kill any cached kernel maps before move. An optimization could + * be to do this iff source or destination memory type is in VRAM. + */ + vmw_bo_unmap(vbo); + + /* + * If we're moving a backup MOB out of MOB placement, then make sure we + * read back all resource content first, and unbind the MOB from + * the resource. + */ + if (mem->mem_type != VMW_PL_MOB) + vmw_resource_unbind_list(vbo); +} diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_context.c b/drivers/gpu/drm/vmwgfx/vmwgfx_context.c index ff8acc74786cf..d460a721eaeec 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_context.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_context.c @@ -424,7 +424,7 @@ static int vmw_gb_context_unbind(struct vmw_resource *res, (void) vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); - vmw_fence_single_bo(bo, fence); + vmw_bo_fence_single(bo, fence); if (likely(fence != NULL)) vmw_fence_obj_unreference(&fence); @@ -648,7 +648,7 @@ static int vmw_dx_context_unbind(struct vmw_resource *res, (void) vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); - vmw_fence_single_bo(bo, fence); + vmw_bo_fence_single(bo, fence); if (likely(fence != NULL)) vmw_fence_obj_unreference(&fence); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c index 1052cd3cb7003..980e6e7cd5923 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c @@ -324,7 +324,7 @@ static int vmw_cotable_unbind(struct vmw_resource *res, vmw_dx_context_scrub_cotables(vcotbl->ctx, readback); mutex_unlock(&dev_priv->binding_mutex); (void) vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); - vmw_fence_single_bo(bo, fence); + vmw_bo_fence_single(bo, fence); if (likely(fence != NULL)) vmw_fence_obj_unreference(&fence); @@ -367,7 +367,7 @@ static int vmw_cotable_readback(struct vmw_resource *res) } (void) vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); - vmw_fence_single_bo(&res->backup->base, fence); + vmw_bo_fence_single(&res->backup->base, fence); vmw_fence_obj_unreference(&fence); return 0; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 25c2f668ad6cc..769d72fabb56d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -630,36 +630,6 @@ extern int vmw_user_resource_lookup_handle( uint32_t handle, const struct vmw_user_resource_conv *converter, struct vmw_resource **p_res); -extern void vmw_bo_bo_free(struct ttm_buffer_object *bo); -extern int vmw_bo_init(struct vmw_private *dev_priv, - struct vmw_buffer_object *vmw_bo, - size_t size, struct ttm_placement *placement, - bool interuptable, - void (*bo_free)(struct ttm_buffer_object *bo)); -extern int vmw_user_bo_verify_access(struct ttm_buffer_object *bo, - struct ttm_object_file *tfile); -extern int vmw_user_bo_alloc(struct vmw_private *dev_priv, - struct ttm_object_file *tfile, - uint32_t size, - bool shareable, - uint32_t *handle, - struct vmw_buffer_object **p_dma_buf, - struct ttm_base_object **p_base); -extern int vmw_user_bo_reference(struct ttm_object_file *tfile, - struct vmw_buffer_object *dma_buf, - uint32_t *handle); -extern int vmw_bo_alloc_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -extern int vmw_bo_unref_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -extern int vmw_user_bo_synccpu_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -extern uint32_t vmw_bo_validate_node(struct ttm_buffer_object *bo, - uint32_t cur_validate_node); -extern void vmw_bo_validate_clear(struct ttm_buffer_object *bo); -extern int vmw_user_bo_lookup(struct ttm_object_file *tfile, - uint32_t id, struct vmw_buffer_object **out, - struct ttm_base_object **base); extern int vmw_stream_claim_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int vmw_stream_unref_ioctl(struct drm_device *dev, void *data, @@ -672,16 +642,11 @@ extern void vmw_resource_unreserve(struct vmw_resource *res, bool switch_backup, struct vmw_buffer_object *new_backup, unsigned long new_backup_offset); -extern void vmw_resource_move_notify(struct ttm_buffer_object *bo, - struct ttm_mem_reg *mem); extern void vmw_query_move_notify(struct ttm_buffer_object *bo, struct ttm_mem_reg *mem); -extern void vmw_resource_swap_notify(struct ttm_buffer_object *bo); extern int vmw_query_readback_all(struct vmw_buffer_object *dx_query_mob); -extern void vmw_fence_single_bo(struct ttm_buffer_object *bo, - struct vmw_fence_obj *fence); extern void vmw_resource_evict_all(struct vmw_private *dev_priv); - +extern void vmw_resource_unbind_list(struct vmw_buffer_object *vbo); /** * Buffer object helper functions - vmwgfx_bo.c @@ -705,8 +670,40 @@ extern int vmw_bo_unpin(struct vmw_private *vmw_priv, extern void vmw_bo_get_guest_ptr(const struct ttm_buffer_object *buf, SVGAGuestPtr *ptr); extern void vmw_bo_pin_reserved(struct vmw_buffer_object *bo, bool pin); -extern void *vmw_buffer_object_map_and_cache(struct vmw_buffer_object *vbo); -extern void vmw_buffer_object_unmap(struct vmw_buffer_object *vbo); +extern void vmw_bo_bo_free(struct ttm_buffer_object *bo); +extern int vmw_bo_init(struct vmw_private *dev_priv, + struct vmw_buffer_object *vmw_bo, + size_t size, struct ttm_placement *placement, + bool interuptable, + void (*bo_free)(struct ttm_buffer_object *bo)); +extern int vmw_user_bo_verify_access(struct ttm_buffer_object *bo, + struct ttm_object_file *tfile); +extern int vmw_user_bo_alloc(struct vmw_private *dev_priv, + struct ttm_object_file *tfile, + uint32_t size, + bool shareable, + uint32_t *handle, + struct vmw_buffer_object **p_dma_buf, + struct ttm_base_object **p_base); +extern int vmw_user_bo_reference(struct ttm_object_file *tfile, + struct vmw_buffer_object *dma_buf, + uint32_t *handle); +extern int vmw_bo_alloc_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int vmw_bo_unref_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int vmw_user_bo_synccpu_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int vmw_user_bo_lookup(struct ttm_object_file *tfile, + uint32_t id, struct vmw_buffer_object **out, + struct ttm_base_object **base); +extern void vmw_bo_fence_single(struct ttm_buffer_object *bo, + struct vmw_fence_obj *fence); +extern void *vmw_bo_map_and_cache(struct vmw_buffer_object *vbo); +extern void vmw_bo_unmap(struct vmw_buffer_object *vbo); +extern void vmw_bo_move_notify(struct ttm_buffer_object *bo, + struct ttm_mem_reg *mem); +extern void vmw_bo_swap_notify(struct ttm_buffer_object *bo); /** * Misc Ioctl functionality - vmwgfx_ioctl.c diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index dcde4985c5747..b913a56f34266 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -197,7 +197,7 @@ static void vmw_fb_dirty_flush(struct work_struct *work) (void) ttm_read_lock(&vmw_priv->reservation_sem, false); (void) ttm_bo_reserve(&vbo->base, false, false, NULL); - virtual = vmw_buffer_object_map_and_cache(vbo); + virtual = vmw_bo_map_and_cache(vbo); if (!virtual) goto out_unreserve; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 7a32be0cef14a..e7a7a2e73bbf0 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -2493,7 +2493,7 @@ void vmw_kms_helper_buffer_finish(struct vmw_private *dev_priv, ret = vmw_execbuf_fence_commands(file_priv, dev_priv, &fence, file_priv ? &handle : NULL); if (buf) - vmw_fence_single_bo(&buf->base, fence); + vmw_bo_fence_single(&buf->base, fence); if (file_priv) vmw_execbuf_copy_fence_user(dev_priv, vmw_fpriv(file_priv), ret, user_fence_rep, fence, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c b/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c index d07c585e3c1df..e44da7bb4861a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c @@ -225,7 +225,7 @@ static void vmw_takedown_otable_base(struct vmw_private *dev_priv, ret = ttm_bo_reserve(bo, false, true, NULL); BUG_ON(ret != 0); - vmw_fence_single_bo(bo, NULL); + vmw_bo_fence_single(bo, NULL); ttm_bo_unreserve(bo); } @@ -362,7 +362,7 @@ static void vmw_otable_batch_takedown(struct vmw_private *dev_priv, ret = ttm_bo_reserve(bo, false, true, NULL); BUG_ON(ret != 0); - vmw_fence_single_bo(bo, NULL); + vmw_bo_fence_single(bo, NULL); ttm_bo_unreserve(bo); ttm_bo_unref(&batch->otable_bo); @@ -620,7 +620,7 @@ void vmw_mob_unbind(struct vmw_private *dev_priv, vmw_fifo_commit(dev_priv, sizeof(*cmd)); } if (bo) { - vmw_fence_single_bo(bo, NULL); + vmw_bo_fence_single(bo, NULL); ttm_bo_unreserve(bo); } vmw_fifo_resource_dec(dev_priv); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index 5aaf9ac65cba0..6d2cad744f5dd 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -27,7 +27,6 @@ #include "vmwgfx_drv.h" #include <drm/vmwgfx_drm.h> -#include <drm/ttm/ttm_object.h> #include <drm/ttm/ttm_placement.h> #include <drm/drmP.h> #include "vmwgfx_resource_priv.h" @@ -35,30 +34,6 @@ #define VMW_RES_EVICT_ERR_COUNT 10 -struct vmw_user_buffer_object { - struct ttm_prime_object prime; - struct vmw_buffer_object vbo; -}; - -struct vmw_bo_user_rep { - uint32_t handle; - uint64_t map_handle; -}; - -static inline struct vmw_buffer_object * -vmw_buffer_object(struct ttm_buffer_object *bo) -{ - return container_of(bo, struct vmw_buffer_object, base); -} - -static inline struct vmw_user_buffer_object * -vmw_user_buffer_object(struct ttm_buffer_object *bo) -{ - struct vmw_buffer_object *vmw_bo = vmw_buffer_object(bo); - - return container_of(vmw_bo, struct vmw_user_buffer_object, vbo); -} - struct vmw_resource *vmw_resource_reference(struct vmw_resource *res) { kref_get(&res->kref); @@ -316,509 +291,6 @@ int vmw_user_lookup_handle(struct vmw_private *dev_priv, return ret; } -/** - * Buffer management. - */ - -/** - * vmw_bo_acc_size - Calculate the pinned memory usage of buffers - * - * @dev_priv: Pointer to a struct vmw_private identifying the device. - * @size: The requested buffer size. - * @user: Whether this is an ordinary dma buffer or a user dma buffer. - */ -static size_t vmw_bo_acc_size(struct vmw_private *dev_priv, size_t size, - bool user) -{ - static size_t struct_size, user_struct_size; - size_t num_pages = PAGE_ALIGN(size) >> PAGE_SHIFT; - size_t page_array_size = ttm_round_pot(num_pages * sizeof(void *)); - - if (unlikely(struct_size == 0)) { - size_t backend_size = ttm_round_pot(vmw_tt_size); - - struct_size = backend_size + - ttm_round_pot(sizeof(struct vmw_buffer_object)); - user_struct_size = backend_size + - ttm_round_pot(sizeof(struct vmw_user_buffer_object)); - } - - if (dev_priv->map_mode == vmw_dma_alloc_coherent) - page_array_size += - ttm_round_pot(num_pages * sizeof(dma_addr_t)); - - return ((user) ? user_struct_size : struct_size) + - page_array_size; -} - -void vmw_bo_bo_free(struct ttm_buffer_object *bo) -{ - struct vmw_buffer_object *vmw_bo = vmw_buffer_object(bo); - - vmw_buffer_object_unmap(vmw_bo); - kfree(vmw_bo); -} - -static void vmw_user_bo_destroy(struct ttm_buffer_object *bo) -{ - struct vmw_user_buffer_object *vmw_user_bo = vmw_user_buffer_object(bo); - - vmw_buffer_object_unmap(&vmw_user_bo->vbo); - ttm_prime_object_kfree(vmw_user_bo, prime); -} - -int vmw_bo_init(struct vmw_private *dev_priv, - struct vmw_buffer_object *vmw_bo, - size_t size, struct ttm_placement *placement, - bool interruptible, - void (*bo_free)(struct ttm_buffer_object *bo)) -{ - struct ttm_bo_device *bdev = &dev_priv->bdev; - size_t acc_size; - int ret; - bool user = (bo_free == &vmw_user_bo_destroy); - - WARN_ON_ONCE(!bo_free && (!user && (bo_free != vmw_bo_bo_free))); - - acc_size = vmw_bo_acc_size(dev_priv, size, user); - memset(vmw_bo, 0, sizeof(*vmw_bo)); - - INIT_LIST_HEAD(&vmw_bo->res_list); - - ret = ttm_bo_init(bdev, &vmw_bo->base, size, - ttm_bo_type_device, placement, - 0, interruptible, acc_size, - NULL, NULL, bo_free); - return ret; -} - -static void vmw_user_bo_release(struct ttm_base_object **p_base) -{ - struct vmw_user_buffer_object *vmw_user_bo; - struct ttm_base_object *base = *p_base; - struct ttm_buffer_object *bo; - - *p_base = NULL; - - if (unlikely(base == NULL)) - return; - - vmw_user_bo = container_of(base, struct vmw_user_buffer_object, - prime.base); - bo = &vmw_user_bo->vbo.base; - ttm_bo_unref(&bo); -} - -static void vmw_user_bo_ref_obj_release(struct ttm_base_object *base, - enum ttm_ref_type ref_type) -{ - struct vmw_user_buffer_object *user_bo; - - user_bo = container_of(base, struct vmw_user_buffer_object, prime.base); - - switch (ref_type) { - case TTM_REF_SYNCCPU_WRITE: - ttm_bo_synccpu_write_release(&user_bo->vbo.base); - break; - default: - BUG(); - } -} - -/** - * vmw_user_bo_alloc - Allocate a user dma buffer - * - * @dev_priv: Pointer to a struct device private. - * @tfile: Pointer to a struct ttm_object_file on which to register the user - * object. - * @size: Size of the dma buffer. - * @shareable: Boolean whether the buffer is shareable with other open files. - * @handle: Pointer to where the handle value should be assigned. - * @p_vbo: Pointer to where the refcounted struct vmw_buffer_object pointer - * should be assigned. - */ -int vmw_user_bo_alloc(struct vmw_private *dev_priv, - struct ttm_object_file *tfile, - uint32_t size, - bool shareable, - uint32_t *handle, - struct vmw_buffer_object **p_vbo, - struct ttm_base_object **p_base) -{ - struct vmw_user_buffer_object *user_bo; - struct ttm_buffer_object *tmp; - int ret; - - user_bo = kzalloc(sizeof(*user_bo), GFP_KERNEL); - if (unlikely(!user_bo)) { - DRM_ERROR("Failed to allocate a buffer.\n"); - return -ENOMEM; - } - - ret = vmw_bo_init(dev_priv, &user_bo->vbo, size, - (dev_priv->has_mob) ? - &vmw_sys_placement : - &vmw_vram_sys_placement, true, - &vmw_user_bo_destroy); - if (unlikely(ret != 0)) - return ret; - - tmp = ttm_bo_reference(&user_bo->vbo.base); - ret = ttm_prime_object_init(tfile, - size, - &user_bo->prime, - shareable, - ttm_buffer_type, - &vmw_user_bo_release, - &vmw_user_bo_ref_obj_release); - if (unlikely(ret != 0)) { - ttm_bo_unref(&tmp); - goto out_no_base_object; - } - - *p_vbo = &user_bo->vbo; - if (p_base) { - *p_base = &user_bo->prime.base; - kref_get(&(*p_base)->refcount); - } - *handle = user_bo->prime.base.hash.key; - -out_no_base_object: - return ret; -} - -/** - * vmw_user_bo_verify_access - verify access permissions on this - * buffer object. - * - * @bo: Pointer to the buffer object being accessed - * @tfile: Identifying the caller. - */ -int vmw_user_bo_verify_access(struct ttm_buffer_object *bo, - struct ttm_object_file *tfile) -{ - struct vmw_user_buffer_object *vmw_user_bo; - - if (unlikely(bo->destroy != vmw_user_bo_destroy)) - return -EPERM; - - vmw_user_bo = vmw_user_buffer_object(bo); - - /* Check that the caller has opened the object. */ - if (likely(ttm_ref_object_exists(tfile, &vmw_user_bo->prime.base))) - return 0; - - DRM_ERROR("Could not grant buffer access.\n"); - return -EPERM; -} - -/** - * vmw_user_bo_synccpu_grab - Grab a struct vmw_user_buffer_object for cpu - * access, idling previous GPU operations on the buffer and optionally - * blocking it for further command submissions. - * - * @user_bo: Pointer to the buffer object being grabbed for CPU access - * @tfile: Identifying the caller. - * @flags: Flags indicating how the grab should be performed. - * - * A blocking grab will be automatically released when @tfile is closed. - */ -static int vmw_user_bo_synccpu_grab(struct vmw_user_buffer_object *user_bo, - struct ttm_object_file *tfile, - uint32_t flags) -{ - struct ttm_buffer_object *bo = &user_bo->vbo.base; - bool existed; - int ret; - - if (flags & drm_vmw_synccpu_allow_cs) { - bool nonblock = !!(flags & drm_vmw_synccpu_dontblock); - long lret; - - lret = reservation_object_wait_timeout_rcu(bo->resv, true, true, - nonblock ? 0 : MAX_SCHEDULE_TIMEOUT); - if (!lret) - return -EBUSY; - else if (lret < 0) - return lret; - return 0; - } - - ret = ttm_bo_synccpu_write_grab - (bo, !!(flags & drm_vmw_synccpu_dontblock)); - if (unlikely(ret != 0)) - return ret; - - ret = ttm_ref_object_add(tfile, &user_bo->prime.base, - TTM_REF_SYNCCPU_WRITE, &existed, false); - if (ret != 0 || existed) - ttm_bo_synccpu_write_release(&user_bo->vbo.base); - - return ret; -} - -/** - * vmw_user_bo_synccpu_release - Release a previous grab for CPU access, - * and unblock command submission on the buffer if blocked. - * - * @handle: Handle identifying the buffer object. - * @tfile: Identifying the caller. - * @flags: Flags indicating the type of release. - */ -static int vmw_user_bo_synccpu_release(uint32_t handle, - struct ttm_object_file *tfile, - uint32_t flags) -{ - if (!(flags & drm_vmw_synccpu_allow_cs)) - return ttm_ref_object_base_unref(tfile, handle, - TTM_REF_SYNCCPU_WRITE); - - return 0; -} - -/** - * vmw_user_bo_synccpu_release - ioctl function implementing the synccpu - * functionality. - * - * @dev: Identifies the drm device. - * @data: Pointer to the ioctl argument. - * @file_priv: Identifies the caller. - * - * This function checks the ioctl arguments for validity and calls the - * relevant synccpu functions. - */ -int vmw_user_bo_synccpu_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_vmw_synccpu_arg *arg = - (struct drm_vmw_synccpu_arg *) data; - struct vmw_buffer_object *vbo; - struct vmw_user_buffer_object *user_bo; - struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; - struct ttm_base_object *buffer_base; - int ret; - - if ((arg->flags & (drm_vmw_synccpu_read | drm_vmw_synccpu_write)) == 0 - || (arg->flags & ~(drm_vmw_synccpu_read | drm_vmw_synccpu_write | - drm_vmw_synccpu_dontblock | - drm_vmw_synccpu_allow_cs)) != 0) { - DRM_ERROR("Illegal synccpu flags.\n"); - return -EINVAL; - } - - switch (arg->op) { - case drm_vmw_synccpu_grab: - ret = vmw_user_bo_lookup(tfile, arg->handle, &vbo, - &buffer_base); - if (unlikely(ret != 0)) - return ret; - - user_bo = container_of(vbo, struct vmw_user_buffer_object, - vbo); - ret = vmw_user_bo_synccpu_grab(user_bo, tfile, arg->flags); - vmw_bo_unreference(&vbo); - ttm_base_object_unref(&buffer_base); - if (unlikely(ret != 0 && ret != -ERESTARTSYS && - ret != -EBUSY)) { - DRM_ERROR("Failed synccpu grab on handle 0x%08x.\n", - (unsigned int) arg->handle); - return ret; - } - break; - case drm_vmw_synccpu_release: - ret = vmw_user_bo_synccpu_release(arg->handle, tfile, - arg->flags); - if (unlikely(ret != 0)) { - DRM_ERROR("Failed synccpu release on handle 0x%08x.\n", - (unsigned int) arg->handle); - return ret; - } - break; - default: - DRM_ERROR("Invalid synccpu operation.\n"); - return -EINVAL; - } - - return 0; -} - -int vmw_bo_alloc_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct vmw_private *dev_priv = vmw_priv(dev); - union drm_vmw_alloc_dmabuf_arg *arg = - (union drm_vmw_alloc_dmabuf_arg *)data; - struct drm_vmw_alloc_dmabuf_req *req = &arg->req; - struct drm_vmw_dmabuf_rep *rep = &arg->rep; - struct vmw_buffer_object *vbo; - uint32_t handle; - int ret; - - ret = ttm_read_lock(&dev_priv->reservation_sem, true); - if (unlikely(ret != 0)) - return ret; - - ret = vmw_user_bo_alloc(dev_priv, vmw_fpriv(file_priv)->tfile, - req->size, false, &handle, &vbo, - NULL); - if (unlikely(ret != 0)) - goto out_no_bo; - - rep->handle = handle; - rep->map_handle = drm_vma_node_offset_addr(&vbo->base.vma_node); - rep->cur_gmr_id = handle; - rep->cur_gmr_offset = 0; - - vmw_bo_unreference(&vbo); - -out_no_bo: - ttm_read_unlock(&dev_priv->reservation_sem); - - return ret; -} - -int vmw_bo_unref_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_vmw_unref_dmabuf_arg *arg = - (struct drm_vmw_unref_dmabuf_arg *)data; - - return ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile, - arg->handle, - TTM_REF_USAGE); -} - -int vmw_user_bo_lookup(struct ttm_object_file *tfile, - uint32_t handle, struct vmw_buffer_object **out, - struct ttm_base_object **p_base) -{ - struct vmw_user_buffer_object *vmw_user_bo; - struct ttm_base_object *base; - - base = ttm_base_object_lookup(tfile, handle); - if (unlikely(base == NULL)) { - pr_err("Invalid buffer object handle 0x%08lx\n", - (unsigned long)handle); - return -ESRCH; - } - - if (unlikely(ttm_base_object_type(base) != ttm_buffer_type)) { - ttm_base_object_unref(&base); - pr_err("Invalid buffer object handle 0x%08lx\n", - (unsigned long)handle); - return -EINVAL; - } - - vmw_user_bo = container_of(base, struct vmw_user_buffer_object, - prime.base); - (void)ttm_bo_reference(&vmw_user_bo->vbo.base); - if (p_base) - *p_base = base; - else - ttm_base_object_unref(&base); - *out = &vmw_user_bo->vbo; - - return 0; -} - -int vmw_user_bo_reference(struct ttm_object_file *tfile, - struct vmw_buffer_object *vbo, - uint32_t *handle) -{ - struct vmw_user_buffer_object *user_bo; - - if (vbo->base.destroy != vmw_user_bo_destroy) - return -EINVAL; - - user_bo = container_of(vbo, struct vmw_user_buffer_object, vbo); - - *handle = user_bo->prime.base.hash.key; - return ttm_ref_object_add(tfile, &user_bo->prime.base, - TTM_REF_USAGE, NULL, false); -} - -/** - * vmw_dumb_create - Create a dumb kms buffer - * - * @file_priv: Pointer to a struct drm_file identifying the caller. - * @dev: Pointer to the drm device. - * @args: Pointer to a struct drm_mode_create_dumb structure - * - * This is a driver callback for the core drm create_dumb functionality. - * Note that this is very similar to the vmw_bo_alloc ioctl, except - * that the arguments have a different format. - */ -int vmw_dumb_create(struct drm_file *file_priv, - struct drm_device *dev, - struct drm_mode_create_dumb *args) -{ - struct vmw_private *dev_priv = vmw_priv(dev); - struct vmw_buffer_object *vbo; - int ret; - - args->pitch = args->width * ((args->bpp + 7) / 8); - args->size = args->pitch * args->height; - - ret = ttm_read_lock(&dev_priv->reservation_sem, true); - if (unlikely(ret != 0)) - return ret; - - ret = vmw_user_bo_alloc(dev_priv, vmw_fpriv(file_priv)->tfile, - args->size, false, &args->handle, - &vbo, NULL); - if (unlikely(ret != 0)) - goto out_no_bo; - - vmw_bo_unreference(&vbo); -out_no_bo: - ttm_read_unlock(&dev_priv->reservation_sem); - return ret; -} - -/** - * vmw_dumb_map_offset - Return the address space offset of a dumb buffer - * - * @file_priv: Pointer to a struct drm_file identifying the caller. - * @dev: Pointer to the drm device. - * @handle: Handle identifying the dumb buffer. - * @offset: The address space offset returned. - * - * This is a driver callback for the core drm dumb_map_offset functionality. - */ -int vmw_dumb_map_offset(struct drm_file *file_priv, - struct drm_device *dev, uint32_t handle, - uint64_t *offset) -{ - struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; - struct vmw_buffer_object *out_buf; - int ret; - - ret = vmw_user_bo_lookup(tfile, handle, &out_buf, NULL); - if (ret != 0) - return -EINVAL; - - *offset = drm_vma_node_offset_addr(&out_buf->base.vma_node); - vmw_bo_unreference(&out_buf); - return 0; -} - -/** - * vmw_dumb_destroy - Destroy a dumb boffer - * - * @file_priv: Pointer to a struct drm_file identifying the caller. - * @dev: Pointer to the drm device. - * @handle: Handle identifying the dumb buffer. - * - * This is a driver callback for the core drm dumb_destroy functionality. - */ -int vmw_dumb_destroy(struct drm_file *file_priv, - struct drm_device *dev, - uint32_t handle) -{ - return ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile, - handle, TTM_REF_USAGE); -} - /** * vmw_resource_buf_alloc - Allocate a backup buffer for a resource. * @@ -1182,109 +654,39 @@ int vmw_resource_validate(struct vmw_resource *res) return ret; } -/** - * vmw_fence_single_bo - Utility function to fence a single TTM buffer - * object without unreserving it. - * - * @bo: Pointer to the struct ttm_buffer_object to fence. - * @fence: Pointer to the fence. If NULL, this function will - * insert a fence into the command stream.. - * - * Contrary to the ttm_eu version of this function, it takes only - * a single buffer object instead of a list, and it also doesn't - * unreserve the buffer object, which needs to be done separately. - */ -void vmw_fence_single_bo(struct ttm_buffer_object *bo, - struct vmw_fence_obj *fence) -{ - struct ttm_bo_device *bdev = bo->bdev; - - struct vmw_private *dev_priv = - container_of(bdev, struct vmw_private, bdev); - - if (fence == NULL) { - vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); - reservation_object_add_excl_fence(bo->resv, &fence->base); - dma_fence_put(&fence->base); - } else - reservation_object_add_excl_fence(bo->resv, &fence->base); -} /** - * vmw_resource_move_notify - TTM move_notify_callback + * vmw_resource_unbind_list * - * @bo: The TTM buffer object about to move. - * @mem: The struct ttm_mem_reg indicating to what memory - * region the move is taking place. + * @vbo: Pointer to the current backing MOB. * * Evicts the Guest Backed hardware resource if the backup * buffer is being moved out of MOB memory. - * Note that this function should not race with the resource - * validation code as long as it accesses only members of struct - * resource that remain static while bo::res is !NULL and - * while we have @bo reserved. struct resource::backup is *not* a - * static member. The resource validation code will take care - * to set @bo::res to NULL, while having @bo reserved when the - * buffer is no longer bound to the resource, so @bo:res can be - * used to determine whether there is a need to unbind and whether - * it is safe to unbind. + * Note that this function will not race with the resource + * validation code, since resource validation and eviction + * both require the backup buffer to be reserved. */ -void vmw_resource_move_notify(struct ttm_buffer_object *bo, - struct ttm_mem_reg *mem) +void vmw_resource_unbind_list(struct vmw_buffer_object *vbo) { - struct vmw_buffer_object *vbo; - - if (mem == NULL) - return; - - if (bo->destroy != vmw_bo_bo_free && - bo->destroy != vmw_user_bo_destroy) - return; - - vbo = container_of(bo, struct vmw_buffer_object, base); - - /* - * Kill any cached kernel maps before move. An optimization could - * be to do this iff source or destination memory type is VRAM. - */ - vmw_buffer_object_unmap(vbo); - if (mem->mem_type != VMW_PL_MOB) { - struct vmw_resource *res, *n; - struct ttm_validate_buffer val_buf; + struct vmw_resource *res, *next; + struct ttm_validate_buffer val_buf = { + .bo = &vbo->base, + .shared = false + }; - val_buf.bo = bo; - val_buf.shared = false; + lockdep_assert_held(&vbo->base.resv->lock.base); + list_for_each_entry_safe(res, next, &vbo->res_list, mob_head) { + if (!res->func->unbind) + continue; - list_for_each_entry_safe(res, n, &vbo->res_list, mob_head) { - - if (unlikely(res->func->unbind == NULL)) - continue; - - (void) res->func->unbind(res, true, &val_buf); - res->backup_dirty = true; - res->res_dirty = false; - list_del_init(&res->mob_head); - } - - (void) ttm_bo_wait(bo, false, false); + (void) res->func->unbind(res, true, &val_buf); + res->backup_dirty = true; + res->res_dirty = false; + list_del_init(&res->mob_head); } -} - - -/** - * vmw_resource_swap_notify - swapout notify callback. - * - * @bo: The buffer object to be swapped out. - */ -void vmw_resource_swap_notify(struct ttm_buffer_object *bo) -{ - if (bo->destroy != vmw_bo_bo_free && - bo->destroy != vmw_user_bo_destroy) - return; - /* Kill any cached kernel maps before swapout */ - vmw_buffer_object_unmap(vmw_buffer_object(bo)); + (void) ttm_bo_wait(&vbo->base, false, false); } @@ -1370,7 +772,7 @@ void vmw_query_move_notify(struct ttm_buffer_object *bo, /* Create a fence and attach the BO to it */ (void) vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); - vmw_fence_single_bo(bo, fence); + vmw_bo_fence_single(bo, fence); if (fence != NULL) vmw_fence_obj_unreference(&fence); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c index f6c939f3ff5e0..4ec1a91990d9a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c @@ -306,7 +306,7 @@ static int vmw_gb_shader_unbind(struct vmw_resource *res, (void) vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); - vmw_fence_single_bo(val_buf->bo, fence); + vmw_bo_fence_single(val_buf->bo, fence); if (likely(fence != NULL)) vmw_fence_obj_unreference(&fence); @@ -537,7 +537,7 @@ static int vmw_dx_shader_unbind(struct vmw_resource *res, (void) vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); - vmw_fence_single_bo(val_buf->bo, fence); + vmw_bo_fence_single(val_buf->bo, fence); if (likely(fence != NULL)) vmw_fence_obj_unreference(&fence); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c index 2b2e8aa7114a6..f2af536138031 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c @@ -468,7 +468,7 @@ static int vmw_legacy_srf_dma(struct vmw_resource *res, (void) vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); - vmw_fence_single_bo(val_buf->bo, fence); + vmw_bo_fence_single(val_buf->bo, fence); if (likely(fence != NULL)) vmw_fence_obj_unreference(&fence); @@ -1210,7 +1210,7 @@ static int vmw_gb_surface_unbind(struct vmw_resource *res, (void) vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); - vmw_fence_single_bo(val_buf->bo, fence); + vmw_bo_fence_single(val_buf->bo, fence); if (likely(fence != NULL)) vmw_fence_obj_unreference(&fence); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c index 0931f43913b1e..239e1edf09195 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c @@ -852,7 +852,7 @@ static void vmw_move_notify(struct ttm_buffer_object *bo, bool evict, struct ttm_mem_reg *mem) { - vmw_resource_move_notify(bo, mem); + vmw_bo_move_notify(bo, mem); vmw_query_move_notify(bo, mem); } @@ -864,7 +864,7 @@ static void vmw_move_notify(struct ttm_buffer_object *bo, */ static void vmw_swap_notify(struct ttm_buffer_object *bo) { - vmw_resource_swap_notify(bo); + vmw_bo_swap_notify(bo); (void) ttm_bo_wait(bo, false, false); } -- GitLab From 098d7d532bf78ea218b46c1d6887cbb43197ab4e Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom <thellstrom@vmware.com> Date: Tue, 19 Jun 2018 19:20:29 +0200 Subject: [PATCH 0634/1506] drm/vmwgfx: Optimize the buffer object swap_notify callback somewhat. Only try to unmap cached maps when the buffer is moved into or out from vram. Otherwise the underlying pages stay the same. Also when unbinding resources from MOBs about to move, make sure we're really moving out of MOB memory. Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Reviewed-by: Brian Paul <brianp@vmware.com> Reviewed-by: Sinclair Yeh <syeh@vmware.com> Reviewed-by: Deepak Rawat <drawat@vmware.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_bo.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c index d950244798fe3..87204ff67c090 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c @@ -1105,16 +1105,18 @@ void vmw_bo_move_notify(struct ttm_buffer_object *bo, vbo = container_of(bo, struct vmw_buffer_object, base); /* - * Kill any cached kernel maps before move. An optimization could - * be to do this iff source or destination memory type is in VRAM. + * Kill any cached kernel maps before move to or from VRAM. + * With other types of moves, the underlying pages stay the same, + * and the map can be kept. */ - vmw_bo_unmap(vbo); + if (mem->mem_type == TTM_PL_VRAM || bo->mem.mem_type == TTM_PL_VRAM) + vmw_bo_unmap(vbo); /* * If we're moving a backup MOB out of MOB placement, then make sure we * read back all resource content first, and unbind the MOB from * the resource. */ - if (mem->mem_type != VMW_PL_MOB) + if (mem->mem_type != VMW_PL_MOB && bo->mem.mem_type == VMW_PL_MOB) vmw_resource_unbind_list(vbo); } -- GitLab From 19f976ab01a6bb1f36384dd8cc743b88a6b7ebd6 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom <thellstrom@vmware.com> Date: Tue, 19 Jun 2018 19:22:16 +0200 Subject: [PATCH 0635/1506] drm/vmwgfx: Use blocking buffer object reserves when evicting resources Previously when evicting resources we were unconditionally calling ttm_eu_reserve_buffers with a NULL ww acquire context. That meant all buffer object reserves were done using trylock semantics. That makes sense when evicting during resource validation, because then there already are a number of buffers reserved and using waiting locks would cause lockdep errors. That's not the case when unconditionally evicting all resources as part of driver takedown or hibernation, so in that code path, make sure we have a ww acquire context to get waiting lock buffer object reserve semantics. Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Reviewed-by: Brian Paul <brianp@vmware.com> Reviewed-by: Sinclair Yeh <syeh@vmware.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 29 ++++++++++++++++-------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index 6d2cad744f5dd..3b2d9b6c50fc2 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -433,6 +433,7 @@ void vmw_resource_unreserve(struct vmw_resource *res, * for a resource and in that case, allocate * one, reserve and validate it. * + * @ticket: The ww aqcquire context to use, or NULL if trylocking. * @res: The resource for which to allocate a backup buffer. * @interruptible: Whether any sleeps during allocation should be * performed while interruptible. @@ -440,7 +441,8 @@ void vmw_resource_unreserve(struct vmw_resource *res, * reserved and validated backup buffer. */ static int -vmw_resource_check_buffer(struct vmw_resource *res, +vmw_resource_check_buffer(struct ww_acquire_ctx *ticket, + struct vmw_resource *res, bool interruptible, struct ttm_validate_buffer *val_buf) { @@ -459,7 +461,7 @@ vmw_resource_check_buffer(struct vmw_resource *res, val_buf->bo = ttm_bo_reference(&res->backup->base); val_buf->shared = false; list_add_tail(&val_buf->head, &val_list); - ret = ttm_eu_reserve_buffers(NULL, &val_list, interruptible, NULL); + ret = ttm_eu_reserve_buffers(ticket, &val_list, interruptible, NULL); if (unlikely(ret != 0)) goto out_no_reserve; @@ -477,7 +479,7 @@ vmw_resource_check_buffer(struct vmw_resource *res, return 0; out_no_validate: - ttm_eu_backoff_reservation(NULL, &val_list); + ttm_eu_backoff_reservation(ticket, &val_list); out_no_reserve: ttm_bo_unref(&val_buf->bo); if (backup_dirty) @@ -524,10 +526,12 @@ int vmw_resource_reserve(struct vmw_resource *res, bool interruptible, * vmw_resource_backoff_reservation - Unreserve and unreference a * backup buffer *. + * @ticket: The ww acquire ctx used for reservation. * @val_buf: Backup buffer information. */ static void -vmw_resource_backoff_reservation(struct ttm_validate_buffer *val_buf) +vmw_resource_backoff_reservation(struct ww_acquire_ctx *ticket, + struct ttm_validate_buffer *val_buf) { struct list_head val_list; @@ -536,7 +540,7 @@ vmw_resource_backoff_reservation(struct ttm_validate_buffer *val_buf) INIT_LIST_HEAD(&val_list); list_add_tail(&val_buf->head, &val_list); - ttm_eu_backoff_reservation(NULL, &val_list); + ttm_eu_backoff_reservation(ticket, &val_list); ttm_bo_unref(&val_buf->bo); } @@ -544,10 +548,12 @@ vmw_resource_backoff_reservation(struct ttm_validate_buffer *val_buf) * vmw_resource_do_evict - Evict a resource, and transfer its data * to a backup buffer. * + * @ticket: The ww acquire ticket to use, or NULL if trylocking. * @res: The resource to evict. * @interruptible: Whether to wait interruptible. */ -static int vmw_resource_do_evict(struct vmw_resource *res, bool interruptible) +static int vmw_resource_do_evict(struct ww_acquire_ctx *ticket, + struct vmw_resource *res, bool interruptible) { struct ttm_validate_buffer val_buf; const struct vmw_res_func *func = res->func; @@ -557,7 +563,7 @@ static int vmw_resource_do_evict(struct vmw_resource *res, bool interruptible) val_buf.bo = NULL; val_buf.shared = false; - ret = vmw_resource_check_buffer(res, interruptible, &val_buf); + ret = vmw_resource_check_buffer(ticket, res, interruptible, &val_buf); if (unlikely(ret != 0)) return ret; @@ -572,7 +578,7 @@ static int vmw_resource_do_evict(struct vmw_resource *res, bool interruptible) res->backup_dirty = true; res->res_dirty = false; out_no_unbind: - vmw_resource_backoff_reservation(&val_buf); + vmw_resource_backoff_reservation(ticket, &val_buf); return ret; } @@ -626,7 +632,8 @@ int vmw_resource_validate(struct vmw_resource *res) write_unlock(&dev_priv->resource_lock); - ret = vmw_resource_do_evict(evict_res, true); + /* Trylock backup buffers with a NULL ticket. */ + ret = vmw_resource_do_evict(NULL, evict_res, true); if (unlikely(ret != 0)) { write_lock(&dev_priv->resource_lock); list_add_tail(&evict_res->lru_head, lru_list); @@ -809,6 +816,7 @@ static void vmw_resource_evict_type(struct vmw_private *dev_priv, struct vmw_resource *evict_res; unsigned err_count = 0; int ret; + struct ww_acquire_ctx ticket; do { write_lock(&dev_priv->resource_lock); @@ -822,7 +830,8 @@ static void vmw_resource_evict_type(struct vmw_private *dev_priv, list_del_init(&evict_res->lru_head); write_unlock(&dev_priv->resource_lock); - ret = vmw_resource_do_evict(evict_res, false); + /* Wait lock backup buffers with a ticket. */ + ret = vmw_resource_do_evict(&ticket, evict_res, false); if (unlikely(ret != 0)) { write_lock(&dev_priv->resource_lock); list_add_tail(&evict_res->lru_head, lru_list); -- GitLab From b249cb4f6bc45485f631803b9762e443108a4b00 Mon Sep 17 00:00:00 2001 From: Sinclair Yeh <syeh@vmware.com> Date: Tue, 19 Jun 2018 19:46:58 +0200 Subject: [PATCH 0636/1506] drm/vmwgfx: Fix atomic mode set check vmw_kms_atomic_check_modeset() is currently checking config using the legacy state, which is updated after a commit has happened. This means vmw_kms_atomic_check_modeset() will reject an invalid config on the next update rather than the current one. Fix this by using the new states for config checking Signed-off-by: Sinclair Yeh <syeh@vmware.com> Reviewed-by: Deepak Rawat <drawat@vmware.com> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 40 +++++++++++++++++++---------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index e7a7a2e73bbf0..6b8541f9215d6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -1526,33 +1526,45 @@ static int vmw_kms_atomic_check_modeset(struct drm_device *dev, struct drm_atomic_state *state) { - struct drm_crtc_state *crtc_state; + struct drm_crtc_state *new_crtc_state; + struct drm_plane_state *new_plane_state; + struct drm_plane *plane; struct drm_crtc *crtc; struct vmw_private *dev_priv = vmw_priv(dev); - int i; + int i, ret, cpp = 0; - for_each_new_crtc_in_state(state, crtc, crtc_state, i) { - unsigned long requested_bb_mem = 0; + ret = drm_atomic_helper_check(dev, state); - if (dev_priv->active_display_unit == vmw_du_screen_target) { - struct drm_plane *plane = crtc->primary; - struct drm_plane_state *plane_state; + /* If this is not a STDU, then no more checking is necessary */ + if (ret || dev_priv->active_display_unit != vmw_du_screen_target) + return ret; - plane_state = drm_atomic_get_new_plane_state(state, plane); + for_each_new_plane_in_state(state, plane, new_plane_state, i) { + if (new_plane_state->fb) { + int current_cpp = new_plane_state->fb->pitches[0] / + new_plane_state->fb->width; - if (plane_state && plane_state->fb) { - int cpp = plane_state->fb->format->cpp[0]; + if (cpp == 0) + cpp = current_cpp; + else if (current_cpp != cpp) + return -EINVAL; + } + } - requested_bb_mem += crtc->mode.hdisplay * cpp * - crtc->mode.vdisplay; - } + for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) { + unsigned long requested_bb_mem = 0; + + if (drm_atomic_crtc_needs_modeset(new_crtc_state)) { + requested_bb_mem += new_crtc_state->mode.hdisplay * + new_crtc_state->mode.vdisplay * + cpp; if (requested_bb_mem > dev_priv->prim_bb_mem) return -EINVAL; } } - return drm_atomic_helper_check(dev, state); + return ret; } static const struct drm_mode_config_funcs vmw_kms_funcs = { -- GitLab From 0a80eb4c122fd6119f3a15910d7bb9e6e33c3661 Mon Sep 17 00:00:00 2001 From: Deepak Rawat <drawat@vmware.com> Date: Tue, 19 Jun 2018 19:51:15 +0200 Subject: [PATCH 0637/1506] drm/vmwgfx: Perform topology validation during atomic modeset. This patch adds display (primary) memory validation during modeset check. Display memory validation are applicable to both SOU and STDU, so allow both display unit to undergo this check. Also added check for SVGA_CAP_NO_BB_RESTRICTION capability which lifts bounding box restriction for STDU. Signed-off-by: Deepak Rawat <drawat@vmware.com> Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> --- .../gpu/drm/vmwgfx/device_include/svga_reg.h | 31 ++- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 184 ++++++++++++++---- 2 files changed, 177 insertions(+), 38 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/device_include/svga_reg.h b/drivers/gpu/drm/vmwgfx/device_include/svga_reg.h index 88e72bf9a534a..cdd48a3763db6 100644 --- a/drivers/gpu/drm/vmwgfx/device_include/svga_reg.h +++ b/drivers/gpu/drm/vmwgfx/device_include/svga_reg.h @@ -672,8 +672,34 @@ SVGASignedPoint; * SVGA_CAP_GBOBJECTS -- * Enable guest-backed objects and surfaces. * - * SVGA_CAP_CMD_BUFFERS_3 -- - * Enable support for command buffers in a mob. + * SVGA_CAP_DX -- + * Enable support for DX commands, and command buffers in a mob. + * + * SVGA_CAP_HP_CMD_QUEUE -- + * Enable support for the high priority command queue, and the + * ScreenCopy command. + * + * SVGA_CAP_NO_BB_RESTRICTION -- + * Allow ScreenTargets to be defined without regard to the 32-bpp + * bounding-box memory restrictions. ie: + * + * The summed memory usage of all screens (assuming they were defined as + * 32-bpp) must always be less than the value of the + * SVGA_REG_MAX_PRIMARY_MEM register. + * + * If this cap is not present, the 32-bpp bounding box around all screens + * must additionally be under the value of the SVGA_REG_MAX_PRIMARY_MEM + * register. + * + * If the cap is present, the bounding box restriction is lifted (and only + * the screen-sum limit applies). + * + * (Note that this is a slight lie... there is still a sanity limit on any + * dimension of the topology to be less than SVGA_SCREEN_ROOT_LIMIT, even + * when SVGA_CAP_NO_BB_RESTRICTION is present, but that should be + * large enough to express any possible topology without holes between + * monitors.) + * */ #define SVGA_CAP_NONE 0x00000000 @@ -699,6 +725,7 @@ SVGASignedPoint; #define SVGA_CAP_GBOBJECTS 0x08000000 #define SVGA_CAP_DX 0x10000000 #define SVGA_CAP_HP_CMD_QUEUE 0x20000000 +#define SVGA_CAP_NO_BB_RESTRICTION 0x40000000 #define SVGA_CAP_CMD_RESERVED 0x80000000 diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 6b8541f9215d6..a7c9a017fc3cb 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -1507,66 +1507,178 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, return &vfb->base; } +/** + * vmw_kms_check_display_memory - Validates display memory required for a + * topology + * @dev: DRM device + * @num_rects: number of drm_rect in rects + * @rects: array of drm_rect representing the topology to validate indexed by + * crtc index. + * + * Returns: + * 0 on success otherwise negative error code + */ +static int vmw_kms_check_display_memory(struct drm_device *dev, + uint32_t num_rects, + struct drm_rect *rects) +{ + struct vmw_private *dev_priv = vmw_priv(dev); + struct drm_mode_config *mode_config = &dev->mode_config; + struct drm_rect bounding_box = {0}; + u64 total_pixels = 0, pixel_mem, bb_mem; + int i; + + for (i = 0; i < num_rects; i++) { + /* + * Currently this check is limiting the topology within max + * texture/screentarget size. This should change in future when + * user-space support multiple fb with topology. + */ + if (rects[i].x1 < 0 || rects[i].y1 < 0 || + rects[i].x2 > mode_config->max_width || + rects[i].y2 > mode_config->max_height) { + DRM_ERROR("Invalid GUI layout.\n"); + return -EINVAL; + } + + /* Bounding box upper left is at (0,0). */ + if (rects[i].x2 > bounding_box.x2) + bounding_box.x2 = rects[i].x2; + + if (rects[i].y2 > bounding_box.y2) + bounding_box.y2 = rects[i].y2; + + total_pixels += (u64) drm_rect_width(&rects[i]) * + (u64) drm_rect_height(&rects[i]); + } + + /* Virtual svga device primary limits are always in 32-bpp. */ + pixel_mem = total_pixels * 4; + + /* + * For HV10 and below prim_bb_mem is vram size. When + * SVGA_REG_MAX_PRIMARY_BOUNDING_BOX_MEM is not present vram size is + * limit on primary bounding box + */ + if (pixel_mem > dev_priv->prim_bb_mem) { + DRM_ERROR("Combined output size too large.\n"); + return -EINVAL; + } + /* SVGA_CAP_NO_BB_RESTRICTION is available for STDU only. */ + if (dev_priv->active_display_unit != vmw_du_screen_target || + !(dev_priv->capabilities & SVGA_CAP_NO_BB_RESTRICTION)) { + bb_mem = (u64) bounding_box.x2 * bounding_box.y2 * 4; + + if (bb_mem > dev_priv->prim_bb_mem) { + DRM_ERROR("Topology is beyond supported limits.\n"); + return -EINVAL; + } + } + + return 0; +} /** - * vmw_kms_atomic_check_modeset- validate state object for modeset changes - * + * vmw_kms_check_topology - Validates topology in drm_atomic_state * @dev: DRM device * @state: the driver state object * - * This is a simple wrapper around drm_atomic_helper_check_modeset() for - * us to assign a value to mode->crtc_clock so that - * drm_calc_timestamping_constants() won't throw an error message - * - * RETURNS - * Zero for success or -errno + * Returns: + * 0 on success otherwise negative error code */ -static int -vmw_kms_atomic_check_modeset(struct drm_device *dev, - struct drm_atomic_state *state) +static int vmw_kms_check_topology(struct drm_device *dev, + struct drm_atomic_state *state) { - struct drm_crtc_state *new_crtc_state; - struct drm_plane_state *new_plane_state; - struct drm_plane *plane; + struct drm_crtc_state *old_crtc_state, *new_crtc_state; + struct drm_rect *rects; struct drm_crtc *crtc; - struct vmw_private *dev_priv = vmw_priv(dev); - int i, ret, cpp = 0; + uint32_t i; + int ret = 0; - ret = drm_atomic_helper_check(dev, state); + rects = kcalloc(dev->mode_config.num_crtc, sizeof(struct drm_rect), + GFP_KERNEL); + if (!rects) + return -ENOMEM; - /* If this is not a STDU, then no more checking is necessary */ - if (ret || dev_priv->active_display_unit != vmw_du_screen_target) - return ret; + drm_for_each_crtc(crtc, dev) { + struct vmw_display_unit *du = vmw_crtc_to_du(crtc); + struct drm_crtc_state *crtc_state = crtc->state; - for_each_new_plane_in_state(state, plane, new_plane_state, i) { - if (new_plane_state->fb) { - int current_cpp = new_plane_state->fb->pitches[0] / - new_plane_state->fb->width; + i = drm_crtc_index(crtc); - if (cpp == 0) - cpp = current_cpp; - else if (current_cpp != cpp) - return -EINVAL; + if (crtc_state && crtc_state->enable) { + /* + * There could be a race condition with update of gui_x/ + * gui_y. Those are protected by dev->mode_config.mutex. + */ + rects[i].x1 = du->gui_x; + rects[i].y1 = du->gui_y; + rects[i].x2 = du->gui_x + crtc_state->mode.hdisplay; + rects[i].y2 = du->gui_y + crtc_state->mode.vdisplay; } } - for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) { - unsigned long requested_bb_mem = 0; + /* Determine change to topology due to new atomic state */ + for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, + new_crtc_state, i) { + struct vmw_display_unit *du = vmw_crtc_to_du(crtc); + + if (!new_crtc_state->enable && old_crtc_state->enable) { + rects[i].x1 = 0; + rects[i].y1 = 0; + rects[i].x2 = 0; + rects[i].y2 = 0; + } - if (drm_atomic_crtc_needs_modeset(new_crtc_state)) { - requested_bb_mem += new_crtc_state->mode.hdisplay * - new_crtc_state->mode.vdisplay * - cpp; + if (new_crtc_state->enable) { + /* If display unit is not active cannot enable CRTC */ + if (!du->pref_active) { + ret = -EINVAL; + goto clean; + } - if (requested_bb_mem > dev_priv->prim_bb_mem) - return -EINVAL; + rects[i].x1 = du->gui_x; + rects[i].y1 = du->gui_y; + rects[i].x2 = du->gui_x + new_crtc_state->mode.hdisplay; + rects[i].y2 = du->gui_y + new_crtc_state->mode.vdisplay; } } + ret = vmw_kms_check_display_memory(dev, dev->mode_config.num_crtc, + rects); + +clean: + kfree(rects); return ret; } +/** + * vmw_kms_atomic_check_modeset- validate state object for modeset changes + * + * @dev: DRM device + * @state: the driver state object + * + * This is a simple wrapper around drm_atomic_helper_check_modeset() for + * us to assign a value to mode->crtc_clock so that + * drm_calc_timestamping_constants() won't throw an error message + * + * Returns: + * Zero for success or -errno + */ +static int +vmw_kms_atomic_check_modeset(struct drm_device *dev, + struct drm_atomic_state *state) +{ + int ret; + + ret = drm_atomic_helper_check(dev, state); + if (ret) + return ret; + + return vmw_kms_check_topology(dev, state); +} + static const struct drm_mode_config_funcs vmw_kms_funcs = { .fb_create = vmw_kms_fb_create, .atomic_check = vmw_kms_atomic_check_modeset, -- GitLab From 5e24133ea3dfb89fd0cf28cd7a845b66fa680b69 Mon Sep 17 00:00:00 2001 From: Deepak Rawat <drawat@vmware.com> Date: Wed, 20 Jun 2018 11:17:16 +0200 Subject: [PATCH 0638/1506] drm/vmwgfx: Use modeset display memory validation for layout ioctl Call the same display memory validation function which is used by modeset_check. This ensure consistency that kernel change preferred mode/topology only if supported. Also change the internal function to use drm_rect instead of drm_vmw_rect. Signed-off-by: Deepak Rawat <drawat@vmware.com> Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 120 ++++++++++++---------------- 1 file changed, 51 insertions(+), 69 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index a7c9a017fc3cb..387bb39de8397 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -1968,13 +1968,15 @@ void vmw_disable_vblank(struct drm_device *dev, unsigned int pipe) { } - -/* - * Small shared kms functions. +/** + * vmw_du_update_layout - Update the display unit with topology from resolution + * plugin and generate DRM uevent + * @dev_priv: device private + * @num_rects: number of drm_rect in rects + * @rects: toplogy to update */ - -static int vmw_du_update_layout(struct vmw_private *dev_priv, unsigned num, - struct drm_vmw_rect *rects) +static int vmw_du_update_layout(struct vmw_private *dev_priv, + unsigned int num_rects, struct drm_rect *rects) { struct drm_device *dev = dev_priv->dev; struct vmw_display_unit *du; @@ -1982,26 +1984,14 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv, unsigned num, mutex_lock(&dev->mode_config.mutex); -#if 0 - { - unsigned int i; - - DRM_INFO("%s: new layout ", __func__); - for (i = 0; i < num; i++) - DRM_INFO("(%i, %i %ux%u) ", rects[i].x, rects[i].y, - rects[i].w, rects[i].h); - DRM_INFO("\n"); - } -#endif - list_for_each_entry(con, &dev->mode_config.connector_list, head) { du = vmw_connector_to_du(con); - if (num > du->unit) { - du->pref_width = rects[du->unit].w; - du->pref_height = rects[du->unit].h; + if (num_rects > du->unit) { + du->pref_width = drm_rect_width(&rects[du->unit]); + du->pref_height = drm_rect_height(&rects[du->unit]); du->pref_active = true; - du->gui_x = rects[du->unit].x; - du->gui_y = rects[du->unit].y; + du->gui_x = rects[du->unit].x1; + du->gui_y = rects[du->unit].y1; drm_object_property_set_value (&con->base, dev->mode_config.suggested_x_property, du->gui_x); @@ -2322,7 +2312,25 @@ vmw_du_connector_atomic_get_property(struct drm_connector *connector, return 0; } - +/** + * vmw_kms_update_layout_ioctl - Handler for DRM_VMW_UPDATE_LAYOUT ioctl + * @dev: drm device for the ioctl + * @data: data pointer for the ioctl + * @file_priv: drm file for the ioctl call + * + * Update preferred topology of display unit as per ioctl request. The topology + * is expressed as array of drm_vmw_rect. + * e.g. + * [0 0 640 480] [640 0 800 600] [0 480 640 480] + * + * NOTE: + * The x and y offset (upper left) in drm_vmw_rect cannot be less than 0. Beside + * device limit on topology, x + w and y + h (lower right) cannot be greater + * than INT_MAX. So topology beyond these limits will return with error. + * + * Returns: + * Zero on success, negative errno on failure. + */ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -2331,15 +2339,12 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, (struct drm_vmw_update_layout_arg *)data; void __user *user_rects; struct drm_vmw_rect *rects; + struct drm_rect *drm_rects; unsigned rects_size; - int ret; - int i; - u64 total_pixels = 0; - struct drm_mode_config *mode_config = &dev->mode_config; - struct drm_vmw_rect bounding_box = {0}; + int ret, i; if (!arg->num_outputs) { - struct drm_vmw_rect def_rect = {0, 0, 800, 600}; + struct drm_rect def_rect = {0, 0, 800, 600}; vmw_du_update_layout(dev_priv, 1, &def_rect); return 0; } @@ -2358,52 +2363,29 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, goto out_free; } - for (i = 0; i < arg->num_outputs; ++i) { - if (rects[i].x < 0 || - rects[i].y < 0 || - rects[i].x + rects[i].w > mode_config->max_width || - rects[i].y + rects[i].h > mode_config->max_height) { - DRM_ERROR("Invalid GUI layout.\n"); - ret = -EINVAL; - goto out_free; - } - - /* - * bounding_box.w and bunding_box.h are used as - * lower-right coordinates - */ - if (rects[i].x + rects[i].w > bounding_box.w) - bounding_box.w = rects[i].x + rects[i].w; - - if (rects[i].y + rects[i].h > bounding_box.h) - bounding_box.h = rects[i].y + rects[i].h; + drm_rects = (struct drm_rect *)rects; - total_pixels += (u64) rects[i].w * (u64) rects[i].h; - } + for (i = 0; i < arg->num_outputs; i++) { + struct drm_vmw_rect curr_rect; - if (dev_priv->active_display_unit == vmw_du_screen_target) { - /* - * For Screen Targets, the limits for a toplogy are: - * 1. Bounding box (assuming 32bpp) must be < prim_bb_mem - * 2. Total pixels (assuming 32bpp) must be < prim_bb_mem - */ - u64 bb_mem = (u64) bounding_box.w * bounding_box.h * 4; - u64 pixel_mem = total_pixels * 4; - - if (bb_mem > dev_priv->prim_bb_mem) { - DRM_ERROR("Topology is beyond supported limits.\n"); - ret = -EINVAL; + /* Verify user-space for overflow as kernel use drm_rect */ + if ((rects[i].x + rects[i].w > INT_MAX) || + (rects[i].y + rects[i].h > INT_MAX)) { + ret = -ERANGE; goto out_free; } - if (pixel_mem > dev_priv->prim_bb_mem) { - DRM_ERROR("Combined output size too large\n"); - ret = -EINVAL; - goto out_free; - } + curr_rect = rects[i]; + drm_rects[i].x1 = curr_rect.x; + drm_rects[i].y1 = curr_rect.y; + drm_rects[i].x2 = curr_rect.x + curr_rect.w; + drm_rects[i].y2 = curr_rect.y + curr_rect.h; } - vmw_du_update_layout(dev_priv, arg->num_outputs, rects); + ret = vmw_kms_check_display_memory(dev, arg->num_outputs, drm_rects); + + if (ret == 0) + vmw_du_update_layout(dev_priv, arg->num_outputs, drm_rects); out_free: kfree(rects); -- GitLab From 7e14eabca82ec75da5200769989d396da46033ee Mon Sep 17 00:00:00 2001 From: Deepak Rawat <drawat@vmware.com> Date: Wed, 20 Jun 2018 11:23:55 +0200 Subject: [PATCH 0639/1506] drm/vmwgfx: Perform memory validations only when need full modeset. For cases when full modeset is not requested like page-flip, skip memory validation as the topology is not changed. Signed-off-by: Deepak Rawat <drawat@vmware.com> Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 387bb39de8397..3605ac1702c25 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -1670,13 +1670,32 @@ static int vmw_kms_atomic_check_modeset(struct drm_device *dev, struct drm_atomic_state *state) { - int ret; + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + bool need_modeset = false; + int i, ret; ret = drm_atomic_helper_check(dev, state); if (ret) return ret; - return vmw_kms_check_topology(dev, state); + if (!state->allow_modeset) + return ret; + + /* + * Legacy path do not set allow_modeset properly like + * @drm_atomic_helper_update_plane, This will result in unnecessary call + * to vmw_kms_check_topology. So extra set of check. + */ + for_each_new_crtc_in_state(state, crtc, crtc_state, i) { + if (drm_atomic_crtc_needs_modeset(crtc_state)) + need_modeset = true; + } + + if (need_modeset) + return vmw_kms_check_topology(dev, state); + + return ret; } static const struct drm_mode_config_funcs vmw_kms_funcs = { -- GitLab From 018f60b26602bb41b33139da3408224e36dfe02d Mon Sep 17 00:00:00 2001 From: Deepak Rawat <drawat@vmware.com> Date: Wed, 20 Jun 2018 11:26:59 +0200 Subject: [PATCH 0640/1506] drm/vmwgfx: Remove primary memory validation against mode while creating fb This validation is not required because user-space will send create_fb request once the memory is allocated. This check should be performed during mode-setting. Signed-off-by: Deepak Rawat <drawat@vmware.com> Reviewed-by: Sinclair Yeh <syeh@vmware.com> Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 3605ac1702c25..f0ae0b2ee2e6b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -1433,19 +1433,6 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, struct ttm_base_object *user_obj; int ret; - /** - * This code should be conditioned on Screen Objects not being used. - * If screen objects are used, we can allocate a GMR to hold the - * requested framebuffer. - */ - - if (!vmw_kms_validate_mode_vram(dev_priv, - mode_cmd->pitches[0], - mode_cmd->height)) { - DRM_ERROR("Requested mode exceed bounding box limit.\n"); - return ERR_PTR(-ENOMEM); - } - /* * Take a reference on the user object of the resource * backing the kms fb. This ensures that user-space handle -- GitLab From b89e5ff9eeeb8b1fe3d2d7477fb9e1c1aed5dd5b Mon Sep 17 00:00:00 2001 From: Deepak Rawat <drawat@vmware.com> Date: Wed, 20 Jun 2018 11:32:29 +0200 Subject: [PATCH 0641/1506] drm/vmwgfx: Use a mutex to protect gui positioning in vmw_display_unit To avoid race condition between update_layout ioctl and modeset ioctl for access to gui_x/y positioning added a new mutex requested_layout_mutex. Also used drm_for_each_connector_iter to iterate over connector list. Signed-off-by: Deepak Rawat <drawat@vmware.com> Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 1 + drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 9 +++++++ drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 38 ++++++++++++++++++++--------- 3 files changed, 37 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 4f18304226bc4..45dfff7733d6e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -644,6 +644,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) mutex_init(&dev_priv->cmdbuf_mutex); mutex_init(&dev_priv->release_mutex); mutex_init(&dev_priv->binding_mutex); + mutex_init(&dev_priv->requested_layout_mutex); mutex_init(&dev_priv->global_kms_state_mutex); rwlock_init(&dev_priv->resource_lock); ttm_lock_init(&dev_priv->reservation_sem); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 769d72fabb56d..a38318c3efe45 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -411,6 +411,15 @@ struct vmw_private { uint32_t num_displays; + /* + * Currently requested_layout_mutex is used to protect the gui + * positionig state in display unit. With that use case currently this + * mutex is only taken during layout ioctl and atomic check_modeset. + * Other display unit state can be protected with this mutex but that + * needs careful consideration. + */ + struct mutex requested_layout_mutex; + /* * Framebuffer info. */ diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index f0ae0b2ee2e6b..a592d10e5c763 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -1577,6 +1577,7 @@ static int vmw_kms_check_display_memory(struct drm_device *dev, static int vmw_kms_check_topology(struct drm_device *dev, struct drm_atomic_state *state) { + struct vmw_private *dev_priv = vmw_priv(dev); struct drm_crtc_state *old_crtc_state, *new_crtc_state; struct drm_rect *rects; struct drm_crtc *crtc; @@ -1588,6 +1589,8 @@ static int vmw_kms_check_topology(struct drm_device *dev, if (!rects) return -ENOMEM; + mutex_lock(&dev_priv->requested_layout_mutex); + drm_for_each_crtc(crtc, dev) { struct vmw_display_unit *du = vmw_crtc_to_du(crtc); struct drm_crtc_state *crtc_state = crtc->state; @@ -1595,10 +1598,6 @@ static int vmw_kms_check_topology(struct drm_device *dev, i = drm_crtc_index(crtc); if (crtc_state && crtc_state->enable) { - /* - * There could be a race condition with update of gui_x/ - * gui_y. Those are protected by dev->mode_config.mutex. - */ rects[i].x1 = du->gui_x; rects[i].y1 = du->gui_y; rects[i].x2 = du->gui_x + crtc_state->mode.hdisplay; @@ -1636,6 +1635,7 @@ static int vmw_kms_check_topology(struct drm_device *dev, rects); clean: + mutex_unlock(&dev_priv->requested_layout_mutex); kfree(rects); return ret; } @@ -1987,10 +1987,14 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv, struct drm_device *dev = dev_priv->dev; struct vmw_display_unit *du; struct drm_connector *con; + struct drm_connector_list_iter conn_iter; - mutex_lock(&dev->mode_config.mutex); - - list_for_each_entry(con, &dev->mode_config.connector_list, head) { + /* + * Currently only gui_x/y is protected with requested_layout_mutex. + */ + mutex_lock(&dev_priv->requested_layout_mutex); + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(con, &conn_iter) { du = vmw_connector_to_du(con); if (num_rects > du->unit) { du->pref_width = drm_rect_width(&rects[du->unit]); @@ -1998,6 +2002,21 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv, du->pref_active = true; du->gui_x = rects[du->unit].x1; du->gui_y = rects[du->unit].y1; + } else { + du->pref_width = 800; + du->pref_height = 600; + du->pref_active = false; + du->gui_x = 0; + du->gui_y = 0; + } + } + drm_connector_list_iter_end(&conn_iter); + mutex_unlock(&dev_priv->requested_layout_mutex); + + mutex_lock(&dev->mode_config.mutex); + list_for_each_entry(con, &dev->mode_config.connector_list, head) { + du = vmw_connector_to_du(con); + if (num_rects > du->unit) { drm_object_property_set_value (&con->base, dev->mode_config.suggested_x_property, du->gui_x); @@ -2005,9 +2024,6 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv, (&con->base, dev->mode_config.suggested_y_property, du->gui_y); } else { - du->pref_width = 800; - du->pref_height = 600; - du->pref_active = false; drm_object_property_set_value (&con->base, dev->mode_config.suggested_x_property, 0); @@ -2017,8 +2033,8 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv, } con->status = vmw_du_connector_detect(con, true); } - mutex_unlock(&dev->mode_config.mutex); + drm_sysfs_hotplug_event(dev); return 0; -- GitLab From 3e79ecdad8897dad4d311576989b6856dbcb958e Mon Sep 17 00:00:00 2001 From: Deepak Rawat <drawat@vmware.com> Date: Wed, 20 Jun 2018 11:34:26 +0200 Subject: [PATCH 0642/1506] drm/vmwgfx: Add gui_x/y to vmw_connector_state As gui_x/y positioning is display unit is protected by requested_layout_mutex adding vmw_connector_state copy of the same and modeset commit will refer the state copy to sync with modeset_check state. v2: Tested with CONFIG_PROVE_LOCKING enabled. Signed-off-by: Deepak Rawat <drawat@vmware.com> Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 37 +++++++++++++++++++-------- drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 18 +++++++++++++ drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 38 +++++++++++++++++----------- drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 29 +++++++++++++-------- 4 files changed, 86 insertions(+), 36 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index a592d10e5c763..0fb363458ab57 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -1609,26 +1609,43 @@ static int vmw_kms_check_topology(struct drm_device *dev, for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { struct vmw_display_unit *du = vmw_crtc_to_du(crtc); + struct drm_connector *connector; + struct drm_connector_state *conn_state; + struct vmw_connector_state *vmw_conn_state; if (!new_crtc_state->enable && old_crtc_state->enable) { rects[i].x1 = 0; rects[i].y1 = 0; rects[i].x2 = 0; rects[i].y2 = 0; + continue; } - if (new_crtc_state->enable) { - /* If display unit is not active cannot enable CRTC */ - if (!du->pref_active) { - ret = -EINVAL; - goto clean; - } + if (!du->pref_active) { + ret = -EINVAL; + goto clean; + } - rects[i].x1 = du->gui_x; - rects[i].y1 = du->gui_y; - rects[i].x2 = du->gui_x + new_crtc_state->mode.hdisplay; - rects[i].y2 = du->gui_y + new_crtc_state->mode.vdisplay; + /* + * For vmwgfx each crtc has only one connector attached and it + * is not changed so don't really need to check the + * crtc->connector_mask and iterate over it. + */ + connector = &du->connector; + conn_state = drm_atomic_get_connector_state(state, connector); + if (IS_ERR(conn_state)) { + ret = PTR_ERR(conn_state); + goto clean; } + + vmw_conn_state = vmw_connector_state_to_vcs(conn_state); + vmw_conn_state->gui_x = du->gui_x; + vmw_conn_state->gui_y = du->gui_y; + + rects[i].x1 = du->gui_x; + rects[i].y1 = du->gui_y; + rects[i].x2 = du->gui_x + new_crtc_state->mode.hdisplay; + rects[i].y2 = du->gui_y + new_crtc_state->mode.vdisplay; } ret = vmw_kms_check_display_memory(dev, dev->mode_config.num_crtc, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index ff1caed38f94e..1f2b01862652e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -192,6 +192,24 @@ struct vmw_connector_state { struct drm_connector_state base; bool is_implicit; + + /** + * @gui_x: + * + * vmwgfx connector property representing the x position of this display + * unit (connector is synonymous to display unit) in overall topology. + * This is what the device expect as xRoot while creating screen. + */ + int gui_x; + + /** + * @gui_y: + * + * vmwgfx connector property representing the y position of this display + * unit (connector is synonymous to display unit) in overall topology. + * This is what the device expect as yRoot while creating screen. + */ + int gui_y; }; /** diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index 74dfd4621b7e7..df21d5a6f84aa 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -109,7 +109,7 @@ static void vmw_sou_crtc_destroy(struct drm_crtc *crtc) */ static int vmw_sou_fifo_create(struct vmw_private *dev_priv, struct vmw_screen_object_unit *sou, - uint32_t x, uint32_t y, + int x, int y, struct drm_display_mode *mode) { size_t fifo_size; @@ -139,13 +139,8 @@ static int vmw_sou_fifo_create(struct vmw_private *dev_priv, (sou->base.unit == 0 ? SVGA_SCREEN_IS_PRIMARY : 0); cmd->obj.size.width = mode->hdisplay; cmd->obj.size.height = mode->vdisplay; - if (sou->base.is_implicit) { - cmd->obj.root.x = x; - cmd->obj.root.y = y; - } else { - cmd->obj.root.x = sou->base.gui_x; - cmd->obj.root.y = sou->base.gui_y; - } + cmd->obj.root.x = x; + cmd->obj.root.y = y; sou->base.set_gui_x = cmd->obj.root.x; sou->base.set_gui_y = cmd->obj.root.y; @@ -222,12 +217,11 @@ static void vmw_sou_crtc_mode_set_nofb(struct drm_crtc *crtc) struct vmw_plane_state *vps; int ret; - - sou = vmw_crtc_to_sou(crtc); + sou = vmw_crtc_to_sou(crtc); dev_priv = vmw_priv(crtc->dev); - ps = crtc->primary->state; - fb = ps->fb; - vps = vmw_plane_state_to_vps(ps); + ps = crtc->primary->state; + fb = ps->fb; + vps = vmw_plane_state_to_vps(ps); vfb = (fb) ? vmw_framebuffer_to_vfb(fb) : NULL; @@ -240,11 +234,25 @@ static void vmw_sou_crtc_mode_set_nofb(struct drm_crtc *crtc) } if (vfb) { + struct drm_connector_state *conn_state; + struct vmw_connector_state *vmw_conn_state; + int x, y; + sou->buffer = vps->bo; sou->buffer_size = vps->bo_size; - ret = vmw_sou_fifo_create(dev_priv, sou, crtc->x, crtc->y, - &crtc->mode); + if (sou->base.is_implicit) { + x = crtc->x; + y = crtc->y; + } else { + conn_state = sou->base.connector.state; + vmw_conn_state = vmw_connector_state_to_vcs(conn_state); + + x = vmw_conn_state->gui_x; + y = vmw_conn_state->gui_y; + } + + ret = vmw_sou_fifo_create(dev_priv, sou, x, y, &crtc->mode); if (ret) DRM_ERROR("Failed to define Screen Object %dx%d\n", crtc->x, crtc->y); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index 537df9034008b..15f2cb2a151b0 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -178,13 +178,9 @@ static int vmw_stdu_define_st(struct vmw_private *dev_priv, cmd->body.height = mode->vdisplay; cmd->body.flags = (0 == cmd->body.stid) ? SVGA_STFLAG_PRIMARY : 0; cmd->body.dpi = 0; - if (stdu->base.is_implicit) { - cmd->body.xRoot = crtc_x; - cmd->body.yRoot = crtc_y; - } else { - cmd->body.xRoot = stdu->base.gui_x; - cmd->body.yRoot = stdu->base.gui_y; - } + cmd->body.xRoot = crtc_x; + cmd->body.yRoot = crtc_y; + stdu->base.set_gui_x = cmd->body.xRoot; stdu->base.set_gui_y = cmd->body.yRoot; @@ -374,11 +370,14 @@ static void vmw_stdu_crtc_mode_set_nofb(struct drm_crtc *crtc) { struct vmw_private *dev_priv; struct vmw_screen_target_display_unit *stdu; - int ret; - + struct drm_connector_state *conn_state; + struct vmw_connector_state *vmw_conn_state; + int x, y, ret; - stdu = vmw_crtc_to_stdu(crtc); + stdu = vmw_crtc_to_stdu(crtc); dev_priv = vmw_priv(crtc->dev); + conn_state = stdu->base.connector.state; + vmw_conn_state = vmw_connector_state_to_vcs(conn_state); if (stdu->defined) { ret = vmw_stdu_bind_st(dev_priv, stdu, NULL); @@ -397,8 +396,16 @@ static void vmw_stdu_crtc_mode_set_nofb(struct drm_crtc *crtc) if (!crtc->state->enable) return; + if (stdu->base.is_implicit) { + x = crtc->x; + y = crtc->y; + } else { + x = vmw_conn_state->gui_x; + y = vmw_conn_state->gui_y; + } + vmw_svga_enable(dev_priv); - ret = vmw_stdu_define_st(dev_priv, stdu, &crtc->mode, crtc->x, crtc->y); + ret = vmw_stdu_define_st(dev_priv, stdu, &crtc->mode, x, y); if (ret) DRM_ERROR("Failed to define Screen Target of size %dx%d\n", -- GitLab From 3fbeccf8ceb1651b376a14bfe1005d518a4d8fa0 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom <thellstrom@vmware.com> Date: Wed, 20 Jun 2018 11:38:48 +0200 Subject: [PATCH 0643/1506] drm/vmwgfx: Improve on host message error messages Make sure the error messages are a bit more descriptive, so that a log reader may understand what's gone wrong. Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Reviewed-by: Brian Paul <brianp@vmware.com> Reviewed-by: Sinclair Yeh <syeh@vmware.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_msg.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c index 21d746bdc922b..a72268e970425 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c @@ -234,7 +234,7 @@ static int vmw_recv_msg(struct rpc_channel *channel, void **msg, if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0 || (HIGH_WORD(ecx) & MESSAGE_STATUS_HB) == 0) { - DRM_ERROR("Failed to get reply size\n"); + DRM_ERROR("Failed to get reply size for host message.\n"); return -EINVAL; } @@ -245,7 +245,7 @@ static int vmw_recv_msg(struct rpc_channel *channel, void **msg, reply_len = ebx; reply = kzalloc(reply_len + 1, GFP_KERNEL); if (!reply) { - DRM_ERROR("Cannot allocate memory for reply\n"); + DRM_ERROR("Cannot allocate memory for host message reply.\n"); return -ENOMEM; } @@ -338,7 +338,8 @@ int vmw_host_get_guestinfo(const char *guest_info_param, msg = kasprintf(GFP_KERNEL, "info-get %s", guest_info_param); if (!msg) { - DRM_ERROR("Cannot allocate memory to get %s", guest_info_param); + DRM_ERROR("Cannot allocate memory to get guest info \"%s\".", + guest_info_param); return -ENOMEM; } @@ -374,7 +375,7 @@ int vmw_host_get_guestinfo(const char *guest_info_param, out_open: *length = 0; kfree(msg); - DRM_ERROR("Failed to get %s", guest_info_param); + DRM_ERROR("Failed to get guest info \"%s\".", guest_info_param); return -EINVAL; } @@ -403,7 +404,7 @@ int vmw_host_log(const char *log) msg = kasprintf(GFP_KERNEL, "log %s", log); if (!msg) { - DRM_ERROR("Cannot allocate memory for log message\n"); + DRM_ERROR("Cannot allocate memory for host log message.\n"); return -ENOMEM; } @@ -422,7 +423,7 @@ int vmw_host_log(const char *log) vmw_close_channel(&channel); out_open: kfree(msg); - DRM_ERROR("Failed to send log\n"); + DRM_ERROR("Failed to send host log message.\n"); return -EINVAL; } -- GitLab From 14dba7178491e2bc411dc2e4542295709c1fb9e6 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom <thellstrom@vmware.com> Date: Wed, 20 Jun 2018 11:51:02 +0200 Subject: [PATCH 0644/1506] drm/vmwgfx: Reorganize the fence wait loop Reorganize the fence wait loop somewhat to make it look more like the examples in set_current_state() kerneldoc, and add some code comments. Also if we're about to time out, make sure we check again whether the fence is actually signaled. Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Reviewed-by: Brian Paul <brianp@vmware.com> Reviewed-by: Deepak Rawat <drawat@vmware.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_fence.c | 38 ++++++++++++++++++--------- 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c index 9ed544f8958f3..ea41d74d83419 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c @@ -175,7 +175,6 @@ static long vmw_fence_wait(struct dma_fence *f, bool intr, signed long timeout) struct vmw_private *dev_priv = fman->dev_priv; struct vmwgfx_wait_cb cb; long ret = timeout; - unsigned long irq_flags; if (likely(vmw_fence_obj_signaled(fence))) return timeout; @@ -183,7 +182,7 @@ static long vmw_fence_wait(struct dma_fence *f, bool intr, signed long timeout) vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC); vmw_seqno_waiter_add(dev_priv); - spin_lock_irqsave(f->lock, irq_flags); + spin_lock(f->lock); if (intr && signal_pending(current)) { ret = -ERESTARTSYS; @@ -194,30 +193,45 @@ static long vmw_fence_wait(struct dma_fence *f, bool intr, signed long timeout) cb.task = current; list_add(&cb.base.node, &f->cb_list); - while (ret > 0) { + for (;;) { __vmw_fences_update(fman); - if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &f->flags)) - break; + /* + * We can use the barrier free __set_current_state() since + * DMA_FENCE_FLAG_SIGNALED_BIT + wakeup is protected by the + * fence spinlock. + */ if (intr) __set_current_state(TASK_INTERRUPTIBLE); else __set_current_state(TASK_UNINTERRUPTIBLE); - spin_unlock_irqrestore(f->lock, irq_flags); - ret = schedule_timeout(ret); + if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &f->flags)) { + if (ret == 0 && timeout > 0) + ret = 1; + break; + } - spin_lock_irqsave(f->lock, irq_flags); - if (ret > 0 && intr && signal_pending(current)) + if (intr && signal_pending(current)) { ret = -ERESTARTSYS; - } + break; + } + if (ret == 0) + break; + + spin_unlock(f->lock); + + ret = schedule_timeout(ret); + + spin_lock(f->lock); + } + __set_current_state(TASK_RUNNING); if (!list_empty(&cb.base.node)) list_del(&cb.base.node); - __set_current_state(TASK_RUNNING); out: - spin_unlock_irqrestore(f->lock, irq_flags); + spin_unlock(f->lock); vmw_seqno_waiter_remove(dev_priv); -- GitLab From 6ff67ae759a0f839efeab40424c9dc544223f900 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom <thellstrom@vmware.com> Date: Thu, 21 Jun 2018 09:39:21 +0200 Subject: [PATCH 0645/1506] drm/vmwgfx: Fix host message module function declarations Make the host message module function declarations similar to the other declarations in vmwgfx_drv.h and include the header in vmwgfx_msg.c Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Reviewed-by: Deepak Rawat <drawat@vmware.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 11 +++++------ drivers/gpu/drm/vmwgfx/vmwgfx_msg.c | 1 + 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index a38318c3efe45..a3a0826958a14 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -1230,6 +1230,11 @@ int vmw_bo_cpu_blit(struct ttm_buffer_object *dst, u32 w, u32 h, struct vmw_diff_cpy *diff); +/* Host messaging -vmwgfx_msg.c: */ +int vmw_host_get_guestinfo(const char *guest_info_param, + char *buffer, size_t *length); +int vmw_host_log(const char *log); + /** * Inline helper functions */ @@ -1309,10 +1314,4 @@ static inline void vmw_mmio_write(u32 value, u32 *addr) { WRITE_ONCE(*addr, value); } - -/** - * Add vmw_msg module function - */ -extern int vmw_host_log(const char *log); - #endif diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c index a72268e970425..3549e6bd4178d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c @@ -31,6 +31,7 @@ #include <linux/frame.h> #include <asm/hypervisor.h> #include <drm/drmP.h> +#include "vmwgfx_drv.h" #include "vmwgfx_msg.h" -- GitLab From 812a954b787ab5a91d62e597a36351628b08d079 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom <thellstrom@vmware.com> Date: Thu, 21 Jun 2018 09:44:42 +0200 Subject: [PATCH 0646/1506] drm/vmwgfx: Remove an obsolete __le32 conversion We've long ago given up on enforcing the device format is always little endian, so remove a leftover conversion. Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Reviewed-by: Deepak Rawat <drawat@vmware.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c index f2af536138031..e90f8d39de535 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c @@ -1072,7 +1072,7 @@ static int vmw_gb_surface_create(struct vmw_resource *res) cmd2->header.size = cmd_len; cmd2->body.sid = srf->res.id; cmd2->body.surfaceFlags = srf->flags; - cmd2->body.format = cpu_to_le32(srf->format); + cmd2->body.format = srf->format; cmd2->body.numMipLevels = srf->mip_levels[0]; cmd2->body.multisampleCount = srf->multisample_count; cmd2->body.autogenFilter = srf->autogen_filter; @@ -1085,7 +1085,7 @@ static int vmw_gb_surface_create(struct vmw_resource *res) cmd->header.size = cmd_len; cmd->body.sid = srf->res.id; cmd->body.surfaceFlags = srf->flags; - cmd->body.format = cpu_to_le32(srf->format); + cmd->body.format = srf->format; cmd->body.numMipLevels = srf->mip_levels[0]; cmd->body.multisampleCount = srf->multisample_count; cmd->body.autogenFilter = srf->autogen_filter; -- GitLab From 38b7fb0b2ad1f2ba83bf9a8535cedb198a448ea4 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Tue, 3 Jul 2018 11:18:29 +0100 Subject: [PATCH 0647/1506] drm/i915/selftests: Release the struct_mutex to free the objects live_gtt is a very slow test to run, simply because it tries to allocate and use as much as the 48b address space as possibly can and in the process will try to own all of the system memory. This leads to resource exhaustion and CPU starvation; the latter impacts us when the NMI watchdog declares a task hung due to a mutex contention with ourselves. This we can prevent by releasing the struct_mutex and forcing our i915/rcu workers to run, and in particular flushing the freed object worker that is the cause for concern. References: https://bugs.freedesktop.org/show_bug.cgi?id=107094 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180703101829.7360-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/selftests/i915_gem_gtt.c | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c index a28ee0cc6a633..9578652fba249 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c @@ -32,6 +32,20 @@ #include "mock_drm.h" #include "mock_gem_device.h" +static void cleanup_freed_objects(struct drm_i915_private *i915) +{ + /* + * As we may hold onto the struct_mutex for inordinate lengths of + * time, the NMI khungtaskd detector may fire for the free objects + * worker. + */ + mutex_unlock(&i915->drm.struct_mutex); + + i915_gem_drain_freed_objects(i915); + + mutex_lock(&i915->drm.struct_mutex); +} + static void fake_free_pages(struct drm_i915_gem_object *obj, struct sg_table *pages) { @@ -291,6 +305,8 @@ static int lowlevel_hole(struct drm_i915_private *i915, i915_gem_object_put(obj); kfree(order); + + cleanup_freed_objects(i915); } return 0; @@ -519,6 +535,7 @@ static int fill_hole(struct drm_i915_private *i915, } close_object_list(&objects, vm); + cleanup_freed_objects(i915); } return 0; @@ -605,6 +622,8 @@ static int walk_hole(struct drm_i915_private *i915, i915_gem_object_put(obj); if (err) return err; + + cleanup_freed_objects(i915); } return 0; @@ -789,6 +808,8 @@ static int drunk_hole(struct drm_i915_private *i915, kfree(order); if (err) return err; + + cleanup_freed_objects(i915); } return 0; @@ -857,6 +878,7 @@ static int __shrink_hole(struct drm_i915_private *i915, } close_object_list(&objects, vm); + cleanup_freed_objects(i915); return err; } @@ -949,6 +971,7 @@ static int shrink_boom(struct drm_i915_private *i915, i915_gem_object_put(explode); memset(&vm->fault_attr, 0, sizeof(vm->fault_attr)); + cleanup_freed_objects(i915); } return 0; -- GitLab From 1f6f00238abf2bfa46f4d2c44cfc7512566f3685 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Tue, 3 Jul 2018 14:53:31 +0100 Subject: [PATCH 0648/1506] drm/i915/selftests: Drop struct_mutex around lowlevel pggtt allocation For a ppgtt that we are constructing, there is no struct_mutex dependence so skip it. In the process, also ping the scheduler frequently to try and avoid the NMI watchdog. v2: gen6 requires struct_mutex to clean up (currently) Suggested-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> References: https://bugs.freedesktop.org/show_bug.cgi?id=107094 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180703135331.12265-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/selftests/i915_gem_gtt.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c index 9578652fba249..a7956ecc3e1fe 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c @@ -156,12 +156,9 @@ static int igt_ppgtt_alloc(void *arg) if (!USES_PPGTT(dev_priv)) return 0; - mutex_lock(&dev_priv->drm.struct_mutex); ppgtt = __hw_ppgtt_create(dev_priv); - if (IS_ERR(ppgtt)) { - err = PTR_ERR(ppgtt); - goto err_unlock; - } + if (IS_ERR(ppgtt)) + return PTR_ERR(ppgtt); if (!ppgtt->vm.allocate_va_range) goto err_ppgtt_cleanup; @@ -180,6 +177,8 @@ static int igt_ppgtt_alloc(void *arg) goto err_ppgtt_cleanup; } + cond_resched(); + ppgtt->vm.clear_range(&ppgtt->vm, 0, size); } @@ -197,13 +196,15 @@ static int igt_ppgtt_alloc(void *arg) } goto err_ppgtt_cleanup; } + + cond_resched(); } err_ppgtt_cleanup: + mutex_lock(&dev_priv->drm.struct_mutex); ppgtt->vm.cleanup(&ppgtt->vm); - kfree(ppgtt); -err_unlock: mutex_unlock(&dev_priv->drm.struct_mutex); + kfree(ppgtt); return err; } -- GitLab From dc75e733308c3673d88664fe5e6b9478fa6bec4d Mon Sep 17 00:00:00 2001 From: Deepak Rawat <drawat@vmware.com> Date: Wed, 13 Jun 2018 13:53:28 -0700 Subject: [PATCH 0649/1506] drm/vmwgfx: Update the device headers This change updates the device headers to the latest device version. Where renaming affects the existing code, it's updated accordingly. Signed-off-by: Deepak Rawat <drawat@vmware.com> Reviewed-by: Sinclair Yeh <syeh@vmware.com> Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> --- .../drm/vmwgfx/device_include/svga3d_cmd.h | 230 +++- .../vmwgfx/device_include/svga3d_devcaps.h | 83 +- .../gpu/drm/vmwgfx/device_include/svga3d_dx.h | 297 +++-- .../drm/vmwgfx/device_include/svga3d_limits.h | 4 +- .../device_include/svga3d_surfacedefs.h | 1070 ++++++++++------- .../drm/vmwgfx/device_include/svga3d_types.h | 331 +++-- .../gpu/drm/vmwgfx/device_include/svga_reg.h | 177 ++- .../drm/vmwgfx/device_include/svga_types.h | 3 + drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 4 +- drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c | 15 +- 11 files changed, 1438 insertions(+), 778 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/device_include/svga3d_cmd.h b/drivers/gpu/drm/vmwgfx/device_include/svga3d_cmd.h index 2dfd57c5f4633..168bbf8373a57 100644 --- a/drivers/gpu/drm/vmwgfx/device_include/svga3d_cmd.h +++ b/drivers/gpu/drm/vmwgfx/device_include/svga3d_cmd.h @@ -46,10 +46,10 @@ * the SVGA3D protocol and remain reserved; they should not be used in the * future. * - * IDs between 1040 and 1999 (inclusive) are available for use by the + * IDs between 1040 and 2999 (inclusive) are available for use by the * current SVGA3D protocol. * - * FIFO clients other than SVGA3D should stay below 1000, or at 2000 + * FIFO clients other than SVGA3D should stay below 1000, or at 3000 * and up. */ @@ -89,19 +89,19 @@ typedef enum { SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN = 1069, SVGA_3D_CMD_SURFACE_DEFINE_V2 = 1070, SVGA_3D_CMD_GENERATE_MIPMAPS = 1071, - SVGA_3D_CMD_VIDEO_CREATE_DECODER = 1072, - SVGA_3D_CMD_VIDEO_DESTROY_DECODER = 1073, - SVGA_3D_CMD_VIDEO_CREATE_PROCESSOR = 1074, - SVGA_3D_CMD_VIDEO_DESTROY_PROCESSOR = 1075, - SVGA_3D_CMD_VIDEO_DECODE_START_FRAME = 1076, - SVGA_3D_CMD_VIDEO_DECODE_RENDER = 1077, - SVGA_3D_CMD_VIDEO_DECODE_END_FRAME = 1078, - SVGA_3D_CMD_VIDEO_PROCESS_FRAME = 1079, + SVGA_3D_CMD_DEAD4 = 1072, + SVGA_3D_CMD_DEAD5 = 1073, + SVGA_3D_CMD_DEAD6 = 1074, + SVGA_3D_CMD_DEAD7 = 1075, + SVGA_3D_CMD_DEAD8 = 1076, + SVGA_3D_CMD_DEAD9 = 1077, + SVGA_3D_CMD_DEAD10 = 1078, + SVGA_3D_CMD_DEAD11 = 1079, SVGA_3D_CMD_ACTIVATE_SURFACE = 1080, SVGA_3D_CMD_DEACTIVATE_SURFACE = 1081, SVGA_3D_CMD_SCREEN_DMA = 1082, - SVGA_3D_CMD_SET_UNITY_SURFACE_COOKIE = 1083, - SVGA_3D_CMD_OPEN_CONTEXT_SURFACE = 1084, + SVGA_3D_CMD_DEAD1 = 1083, + SVGA_3D_CMD_DEAD2 = 1084, SVGA_3D_CMD_LOGICOPS_BITBLT = 1085, SVGA_3D_CMD_LOGICOPS_TRANSBLT = 1086, @@ -217,7 +217,7 @@ typedef enum { SVGA_3D_CMD_DX_CLEAR_DEPTHSTENCIL_VIEW = 1177, SVGA_3D_CMD_DX_PRED_COPY_REGION = 1178, SVGA_3D_CMD_DX_PRED_COPY = 1179, - SVGA_3D_CMD_DX_STRETCHBLT = 1180, + SVGA_3D_CMD_DX_PRESENTBLT = 1180, SVGA_3D_CMD_DX_GENMIPS = 1181, SVGA_3D_CMD_DX_UPDATE_SUBRESOURCE = 1182, SVGA_3D_CMD_DX_READBACK_SUBRESOURCE = 1183, @@ -254,7 +254,7 @@ typedef enum { SVGA_3D_CMD_DX_READBACK_ALL_QUERY = 1214, SVGA_3D_CMD_DX_PRED_TRANSFER_FROM_BUFFER = 1215, SVGA_3D_CMD_DX_MOB_FENCE_64 = 1216, - SVGA_3D_CMD_DX_BIND_SHADER_ON_CONTEXT = 1217, + SVGA_3D_CMD_DX_BIND_ALL_SHADER = 1217, SVGA_3D_CMD_DX_HINT = 1218, SVGA_3D_CMD_DX_BUFFER_UPDATE = 1219, SVGA_3D_CMD_DX_SET_VS_CONSTANT_BUFFER_OFFSET = 1220, @@ -262,17 +262,47 @@ typedef enum { SVGA_3D_CMD_DX_SET_GS_CONSTANT_BUFFER_OFFSET = 1222, /* - * Reserve some IDs to be used for the DX11 shader types. + * Reserve some IDs to be used for the SM5 shader types. */ SVGA_3D_CMD_DX_RESERVED1 = 1223, SVGA_3D_CMD_DX_RESERVED2 = 1224, SVGA_3D_CMD_DX_RESERVED3 = 1225, - SVGA_3D_CMD_DX_MAX = 1226, - SVGA_3D_CMD_MAX = 1226, + SVGA_3D_CMD_DX_COND_BIND_ALL_SHADER = 1226, + SVGA_3D_CMD_DX_MAX = 1227, + + SVGA_3D_CMD_SCREEN_COPY = 1227, + + /* + * Reserve some IDs to be used for video. + */ + SVGA_3D_CMD_VIDEO_RESERVED1 = 1228, + SVGA_3D_CMD_VIDEO_RESERVED2 = 1229, + SVGA_3D_CMD_VIDEO_RESERVED3 = 1230, + SVGA_3D_CMD_VIDEO_RESERVED4 = 1231, + SVGA_3D_CMD_VIDEO_RESERVED5 = 1232, + SVGA_3D_CMD_VIDEO_RESERVED6 = 1233, + SVGA_3D_CMD_VIDEO_RESERVED7 = 1234, + SVGA_3D_CMD_VIDEO_RESERVED8 = 1235, + + SVGA_3D_CMD_GROW_OTABLE = 1236, + SVGA_3D_CMD_DX_GROW_COTABLE = 1237, + SVGA_3D_CMD_INTRA_SURFACE_COPY = 1238, + + SVGA_3D_CMD_DEFINE_GB_SURFACE_V3 = 1239, + + SVGA_3D_CMD_DX_RESOLVE_COPY = 1240, + SVGA_3D_CMD_DX_PRED_RESOLVE_COPY = 1241, + SVGA_3D_CMD_DX_PRED_CONVERT_REGION = 1242, + SVGA_3D_CMD_DX_PRED_CONVERT = 1243, + SVGA_3D_CMD_WHOLE_SURFACE_COPY = 1244, + + SVGA_3D_CMD_MAX = 1245, SVGA_3D_CMD_FUTURE_MAX = 3000 } SVGAFifo3dCmdId; +#define SVGA_NUM_3D_CMD (SVGA_3D_CMD_MAX - SVGA_3D_CMD_BASE) + /* * FIFO command format definitions: */ @@ -301,7 +331,7 @@ typedef #include "vmware_pack_begin.h" struct { uint32 sid; - SVGA3dSurfaceFlags surfaceFlags; + SVGA3dSurface1Flags surfaceFlags; SVGA3dSurfaceFormat format; /* * If surfaceFlags has SVGA3D_SURFACE_CUBEMAP bit set, all SVGA3dSurfaceFace @@ -327,7 +357,7 @@ typedef #include "vmware_pack_begin.h" struct { uint32 sid; - SVGA3dSurfaceFlags surfaceFlags; + SVGA3dSurface1Flags surfaceFlags; SVGA3dSurfaceFormat format; /* * If surfaceFlags has SVGA3D_SURFACE_CUBEMAP bit set, all SVGA3dSurfaceFace @@ -459,6 +489,28 @@ struct { #include "vmware_pack_end.h" SVGA3dCmdSurfaceCopy; /* SVGA_3D_CMD_SURFACE_COPY */ +/* + * Perform a surface copy within the same image. + * The src/dest boxes are allowed to overlap. + */ +typedef +#include "vmware_pack_begin.h" +struct { + SVGA3dSurfaceImageId surface; + SVGA3dCopyBox box; +} +#include "vmware_pack_end.h" +SVGA3dCmdIntraSurfaceCopy; /* SVGA_3D_CMD_INTRA_SURFACE_COPY */ + +typedef +#include "vmware_pack_begin.h" +struct { + uint32 srcSid; + uint32 destSid; +} +#include "vmware_pack_end.h" +SVGA3dCmdWholeSurfaceCopy; /* SVGA_3D_CMD_WHOLE_SURFACE_COPY */ + typedef #include "vmware_pack_begin.h" struct { @@ -772,6 +824,17 @@ struct { #include "vmware_pack_end.h" SVGA3dVertexElement; +/* + * Should the vertex element respect the stream value? The high bit of the + * stream should be set to indicate that the stream should be respected. If + * the high bit is not set, the stream will be ignored and replaced by the index + * of the position of the currently considered vertex element. + * + * All guests should set this bit and correctly specify the stream going + * forward. + */ +#define SVGA3D_VERTEX_ELEMENT_RESPECT_STREAM (1 << 7) + typedef #include "vmware_pack_begin.h" struct { @@ -1102,8 +1165,6 @@ struct { #include "vmware_pack_end.h" SVGA3dCmdGenerateMipmaps; /* SVGA_3D_CMD_GENERATE_MIPMAPS */ - - typedef #include "vmware_pack_begin.h" struct { @@ -1146,38 +1207,6 @@ struct SVGA3dCmdScreenDMA { #include "vmware_pack_end.h" SVGA3dCmdScreenDMA; /* SVGA_3D_CMD_SCREEN_DMA */ -/* - * Set Unity Surface Cookie - * - * Associates the supplied cookie with the surface id for use with - * Unity. This cookie is a hint from guest to host, there is no way - * for the guest to readback the cookie and the host is free to drop - * the cookie association at will. The default value for the cookie - * on all surfaces is 0. - */ - -typedef -#include "vmware_pack_begin.h" -struct SVGA3dCmdSetUnitySurfaceCookie { - uint32 sid; - uint64 cookie; -} -#include "vmware_pack_end.h" -SVGA3dCmdSetUnitySurfaceCookie; /* SVGA_3D_CMD_SET_UNITY_SURFACE_COOKIE */ - -/* - * Open a context-specific surface in a non-context-specific manner. - */ - -typedef -#include "vmware_pack_begin.h" -struct SVGA3dCmdOpenContextSurface { - uint32 sid; -} -#include "vmware_pack_end.h" -SVGA3dCmdOpenContextSurface; /* SVGA_3D_CMD_OPEN_CONTEXT_SURFACE */ - - /* * Logic ops */ @@ -1324,7 +1353,7 @@ typedef #include "vmware_pack_begin.h" struct { SVGA3dSurfaceFormat format; - SVGA3dSurfaceFlags surfaceFlags; + SVGA3dSurface1Flags surface1Flags; uint32 numMipLevels; uint32 multisampleCount; SVGA3dTextureFilter autogenFilter; @@ -1332,7 +1361,11 @@ struct { SVGAMobId mobid; uint32 arraySize; uint32 mobPitch; - uint32 pad[5]; + SVGA3dSurface2Flags surface2Flags; + uint8 multisamplePattern; + uint8 qualityLevel; + uint8 pad0[2]; + uint32 pad1[3]; } #include "vmware_pack_end.h" SVGAOTableSurfaceEntry; @@ -1360,7 +1393,8 @@ struct { SVGAOTableShaderEntry; #define SVGA3D_OTABLE_SHADER_ENTRY_SIZE (sizeof(SVGAOTableShaderEntry)) -#define SVGA_STFLAG_PRIMARY (1 << 0) +#define SVGA_STFLAG_PRIMARY (1 << 0) +#define SVGA_STFLAG_RESERVED (1 << 1) /* Added with cap SVGA_CAP_HP_CMD_QUEUE */ typedef uint32 SVGAScreenTargetFlags; typedef @@ -1528,6 +1562,25 @@ struct { #include "vmware_pack_end.h" SVGA3dCmdSetOTableBase64; /* SVGA_3D_CMD_SET_OTABLE_BASE64 */ +/* + * Guests using SVGA_3D_CMD_GROW_OTABLE are promising that + * the new OTable contains the same contents as the old one, except possibly + * for some new invalid entries at the end. + * + * (Otherwise, guests should use one of the SetOTableBase commands.) + */ +typedef +#include "vmware_pack_begin.h" +struct { + SVGAOTableType type; + PPN64 baseAddress; + uint32 sizeInBytes; + uint32 validSizeInBytes; + SVGAMobFormat ptDepth; +} +#include "vmware_pack_end.h" +SVGA3dCmdGrowOTable; /* SVGA_3D_CMD_GROW_OTABLE */ + typedef #include "vmware_pack_begin.h" struct { @@ -1615,7 +1668,7 @@ typedef #include "vmware_pack_begin.h" struct SVGA3dCmdDefineGBSurface { uint32 sid; - SVGA3dSurfaceFlags surfaceFlags; + SVGA3dSurface1Flags surfaceFlags; SVGA3dSurfaceFormat format; uint32 numMipLevels; uint32 multisampleCount; @@ -1625,6 +1678,45 @@ struct SVGA3dCmdDefineGBSurface { #include "vmware_pack_end.h" SVGA3dCmdDefineGBSurface; /* SVGA_3D_CMD_DEFINE_GB_SURFACE */ +/* + * Defines a guest-backed surface, adding the arraySize field. + */ +typedef +#include "vmware_pack_begin.h" +struct SVGA3dCmdDefineGBSurface_v2 { + uint32 sid; + SVGA3dSurface1Flags surfaceFlags; + SVGA3dSurfaceFormat format; + uint32 numMipLevels; + uint32 multisampleCount; + SVGA3dTextureFilter autogenFilter; + SVGA3dSize size; + uint32 arraySize; + uint32 pad; +} +#include "vmware_pack_end.h" +SVGA3dCmdDefineGBSurface_v2; /* SVGA_3D_CMD_DEFINE_GB_SURFACE_V2 */ + +/* + * Defines a guest-backed surface, adding the larger flags. + */ +typedef +#include "vmware_pack_begin.h" +struct SVGA3dCmdDefineGBSurface_v3 { + uint32 sid; + SVGA3dSurfaceAllFlags surfaceFlags; + SVGA3dSurfaceFormat format; + uint32 numMipLevels; + uint32 multisampleCount; + SVGA3dMSPattern multisamplePattern; + SVGA3dMSQualityLevel qualityLevel; + SVGA3dTextureFilter autogenFilter; + SVGA3dSize size; + uint32 arraySize; +} +#include "vmware_pack_end.h" +SVGA3dCmdDefineGBSurface_v3; /* SVGA_3D_CMD_DEFINE_GB_SURFACE_V3 */ + /* * Destroy a guest-backed surface. */ @@ -1672,7 +1764,7 @@ SVGA3dCmdBindGBSurfaceWithPitch; /* SVGA_3D_CMD_BIND_GB_SURFACE_WITH_PITCH */ typedef #include "vmware_pack_begin.h" -struct{ +struct SVGA3dCmdCondBindGBSurface { uint32 sid; SVGAMobId testMobid; SVGAMobId mobid; @@ -2066,6 +2158,26 @@ struct { uint32 mobOffset; } #include "vmware_pack_end.h" -SVGA3dCmdGBMobFence; /* SVGA_3D_CMD_GB_MOB_FENCE*/ +SVGA3dCmdGBMobFence; /* SVGA_3D_CMD_GB_MOB_FENCE */ + +typedef +#include "vmware_pack_begin.h" +struct { + uint32 stid; + SVGA3dSurfaceImageId dest; + + uint32 statusMobId; + uint32 statusMobOffset; + + /* Reserved fields */ + uint32 mustBeInvalidId; + uint32 mustBeZero; +} +#include "vmware_pack_end.h" +SVGA3dCmdScreenCopy; /* SVGA_3D_CMD_SCREEN_COPY */ + +#define SVGA_SCREEN_COPY_STATUS_FAILURE 0x00 +#define SVGA_SCREEN_COPY_STATUS_SUCCESS 0x01 +#define SVGA_SCREEN_COPY_STATUS_INVALID 0xFFFFFFFF #endif /* _SVGA3D_CMD_H_ */ diff --git a/drivers/gpu/drm/vmwgfx/device_include/svga3d_devcaps.h b/drivers/gpu/drm/vmwgfx/device_include/svga3d_devcaps.h index c18b663f360f7..e545013e65d67 100644 --- a/drivers/gpu/drm/vmwgfx/device_include/svga3d_devcaps.h +++ b/drivers/gpu/drm/vmwgfx/device_include/svga3d_devcaps.h @@ -229,9 +229,9 @@ typedef enum { SVGA3D_DEVCAP_DEAD2 = 94, /* - * Does the device support the DX commands? + * Does the device support DXContexts? */ - SVGA3D_DEVCAP_DX = 95, + SVGA3D_DEVCAP_DXCONTEXT = 95, /* * What is the maximum size of a texture array? @@ -241,21 +241,47 @@ typedef enum { SVGA3D_DEVCAP_MAX_TEXTURE_ARRAY_SIZE = 96, /* - * What is the maximum number of vertex buffers that can - * be used in the DXContext inputAssembly? + * What is the maximum number of vertex buffers or vertex input registers + * that can be expected to work correctly with a DXContext? + * + * The guest is allowed to set up to SVGA3D_DX_MAX_VERTEXBUFFERS, but + * anything in excess of this cap is not guaranteed to render correctly. + * + * Similarly, the guest can set up to SVGA3D_DX_MAX_VERTEXINPUTREGISTERS + * input registers without the SVGA3D_DEVCAP_SM4_1 cap, or + * SVGA3D_DX_SM41_MAX_VERTEXINPUTREGISTERS with the SVGA3D_DEVCAP_SM4_1, + * but only the registers up to this cap value are guaranteed to render + * correctly. + * + * If guest-drivers are able to expose a lower-limit, it's recommended + * that they clamp to this value. Otherwise, the host will make a + * best-effort on case-by-case basis if guests exceed this. */ SVGA3D_DEVCAP_DX_MAX_VERTEXBUFFERS = 97, /* - * What is the maximum number of constant buffers - * that can be expected to work correctly with a - * DX context? + * What is the maximum number of constant buffers that can be expected to + * work correctly with a DX context? + * + * The guest is allowed to set up to SVGA3D_DX_MAX_CONSTBUFFERS, but + * anything in excess of this cap is not guaranteed to render correctly. + * + * If guest-drivers are able to expose a lower-limit, it's recommended + * that they clamp to this value. Otherwise, the host will make a + * best-effort on case-by-case basis if guests exceed this. */ SVGA3D_DEVCAP_DX_MAX_CONSTANT_BUFFERS = 98, /* * Does the device support provoking vertex control? - * If zero, the first vertex will always be the provoking vertex. + * + * If this cap is present, the provokingVertexLast field in the + * rasterizer state is enabled. (Guests can then set it to FALSE, + * meaning that the first vertex is the provoking vertex, or TRUE, + * meaning that the last verteix is the provoking vertex.) + * + * If this cap is FALSE, then guests should set the provokingVertexLast + * to FALSE, otherwise rendering behavior is undefined. */ SVGA3D_DEVCAP_DX_PROVOKING_VERTEX = 99, @@ -281,7 +307,7 @@ typedef enum { SVGA3D_DEVCAP_DXFMT_BUMPU8V8 = 119, SVGA3D_DEVCAP_DXFMT_BUMPL6V5U5 = 120, SVGA3D_DEVCAP_DXFMT_BUMPX8L8V8U8 = 121, - SVGA3D_DEVCAP_DXFMT_BUMPL8V8U8 = 122, + SVGA3D_DEVCAP_DXFMT_FORMAT_DEAD1 = 122, SVGA3D_DEVCAP_DXFMT_ARGB_S10E5 = 123, SVGA3D_DEVCAP_DXFMT_ARGB_S23E8 = 124, SVGA3D_DEVCAP_DXFMT_A2R10G10B10 = 125, @@ -320,8 +346,8 @@ typedef enum { SVGA3D_DEVCAP_DXFMT_R32G32_SINT = 158, SVGA3D_DEVCAP_DXFMT_R32G8X24_TYPELESS = 159, SVGA3D_DEVCAP_DXFMT_D32_FLOAT_S8X24_UINT = 160, - SVGA3D_DEVCAP_DXFMT_R32_FLOAT_X8X24_TYPELESS = 161, - SVGA3D_DEVCAP_DXFMT_X32_TYPELESS_G8X24_UINT = 162, + SVGA3D_DEVCAP_DXFMT_R32_FLOAT_X8X24 = 161, + SVGA3D_DEVCAP_DXFMT_X32_G8X24_UINT = 162, SVGA3D_DEVCAP_DXFMT_R10G10B10A2_TYPELESS = 163, SVGA3D_DEVCAP_DXFMT_R10G10B10A2_UINT = 164, SVGA3D_DEVCAP_DXFMT_R11G11B10_FLOAT = 165, @@ -339,8 +365,8 @@ typedef enum { SVGA3D_DEVCAP_DXFMT_R32_SINT = 177, SVGA3D_DEVCAP_DXFMT_R24G8_TYPELESS = 178, SVGA3D_DEVCAP_DXFMT_D24_UNORM_S8_UINT = 179, - SVGA3D_DEVCAP_DXFMT_R24_UNORM_X8_TYPELESS = 180, - SVGA3D_DEVCAP_DXFMT_X24_TYPELESS_G8_UINT = 181, + SVGA3D_DEVCAP_DXFMT_R24_UNORM_X8 = 180, + SVGA3D_DEVCAP_DXFMT_X24_G8_UINT = 181, SVGA3D_DEVCAP_DXFMT_R8G8_TYPELESS = 182, SVGA3D_DEVCAP_DXFMT_R8G8_UNORM = 183, SVGA3D_DEVCAP_DXFMT_R8G8_UINT = 184, @@ -404,6 +430,17 @@ typedef enum { SVGA3D_DEVCAP_DXFMT_BC4_UNORM = 242, SVGA3D_DEVCAP_DXFMT_BC5_UNORM = 243, + /* + * Advertises shaderModel 4.1 support, independent blend-states, + * cube-map arrays, and a higher vertex input registers limit. + * + * (See documentation on SVGA3D_DEVCAP_DX_MAX_VERTEXBUFFERS.) + */ + SVGA3D_DEVCAP_SM41 = 244, + + SVGA3D_DEVCAP_MULTISAMPLE_2X = 245, + SVGA3D_DEVCAP_MULTISAMPLE_4X = 246, + SVGA3D_DEVCAP_MAX /* This must be the last index. */ } SVGA3dDevCapIndex; @@ -419,9 +456,7 @@ typedef enum { * MIPS: Does the format support mip levels? * ARRAY: Does the format support texture arrays? * VOLUME: Does the format support having volume? - * MULTISAMPLE_2: Does the format support 2x multisample? - * MULTISAMPLE_4: Does the format support 4x multisample? - * MULTISAMPLE_8: Does the format support 8x multisample? + * MULTISAMPLE: Does the format support multisample? */ #define SVGA3D_DXFMT_SUPPORTED (1 << 0) #define SVGA3D_DXFMT_SHADER_SAMPLE (1 << 1) @@ -432,20 +467,8 @@ typedef enum { #define SVGA3D_DXFMT_ARRAY (1 << 6) #define SVGA3D_DXFMT_VOLUME (1 << 7) #define SVGA3D_DXFMT_DX_VERTEX_BUFFER (1 << 8) -#define SVGADX_DXFMT_MULTISAMPLE_2 (1 << 9) -#define SVGADX_DXFMT_MULTISAMPLE_4 (1 << 10) -#define SVGADX_DXFMT_MULTISAMPLE_8 (1 << 11) -#define SVGADX_DXFMT_MAX (1 << 12) - -/* - * Convenience mask for any multisample capability. - * - * The multisample bits imply both load and render capability. - */ -#define SVGA3D_DXFMT_MULTISAMPLE ( \ - SVGADX_DXFMT_MULTISAMPLE_2 | \ - SVGADX_DXFMT_MULTISAMPLE_4 | \ - SVGADX_DXFMT_MULTISAMPLE_8 ) +#define SVGA3D_DXFMT_MULTISAMPLE (1 << 9) +#define SVGA3D_DXFMT_MAX (1 << 10) typedef union { Bool b; diff --git a/drivers/gpu/drm/vmwgfx/device_include/svga3d_dx.h b/drivers/gpu/drm/vmwgfx/device_include/svga3d_dx.h index 8c5ae608cfb4f..a5d3b6a686afd 100644 --- a/drivers/gpu/drm/vmwgfx/device_include/svga3d_dx.h +++ b/drivers/gpu/drm/vmwgfx/device_include/svga3d_dx.h @@ -56,6 +56,16 @@ typedef uint32 SVGA3dInputClassification; #define SVGA3D_RESOURCE_TYPE_MAX 7 typedef uint32 SVGA3dResourceType; +#define SVGA3D_COLOR_WRITE_ENABLE_RED (1 << 0) +#define SVGA3D_COLOR_WRITE_ENABLE_GREEN (1 << 1) +#define SVGA3D_COLOR_WRITE_ENABLE_BLUE (1 << 2) +#define SVGA3D_COLOR_WRITE_ENABLE_ALPHA (1 << 3) +#define SVGA3D_COLOR_WRITE_ENABLE_ALL (SVGA3D_COLOR_WRITE_ENABLE_RED | \ + SVGA3D_COLOR_WRITE_ENABLE_GREEN | \ + SVGA3D_COLOR_WRITE_ENABLE_BLUE | \ + SVGA3D_COLOR_WRITE_ENABLE_ALPHA) +typedef uint8 SVGA3dColorWriteEnable; + #define SVGA3D_DEPTH_WRITE_MASK_ZERO 0 #define SVGA3D_DEPTH_WRITE_MASK_ALL 1 typedef uint8 SVGA3dDepthWriteMask; @@ -88,17 +98,28 @@ typedef uint8 SVGA3dCullMode; #define SVGA3D_COMPARISON_MAX 9 typedef uint8 SVGA3dComparisonFunc; +/* + * SVGA3D_MULTISAMPLE_RAST_DISABLE disables MSAA for all primitives. + * SVGA3D_MULTISAMPLE_RAST_DISABLE_LINE, which is supported in SM41, + * disables MSAA for lines only. + */ +#define SVGA3D_MULTISAMPLE_RAST_DISABLE 0 +#define SVGA3D_MULTISAMPLE_RAST_ENABLE 1 +#define SVGA3D_MULTISAMPLE_RAST_DX_MAX 1 +#define SVGA3D_MULTISAMPLE_RAST_DISABLE_LINE 2 +#define SVGA3D_MULTISAMPLE_RAST_MAX 2 +typedef uint8 SVGA3dMultisampleRastEnable; + #define SVGA3D_DX_MAX_VERTEXBUFFERS 32 +#define SVGA3D_DX_MAX_VERTEXINPUTREGISTERS 16 +#define SVGA3D_DX_SM41_MAX_VERTEXINPUTREGISTERS 32 #define SVGA3D_DX_MAX_SOTARGETS 4 #define SVGA3D_DX_MAX_SRVIEWS 128 #define SVGA3D_DX_MAX_CONSTBUFFERS 16 #define SVGA3D_DX_MAX_SAMPLERS 16 -/* Id limits */ -static const uint32 SVGA3dBlendObjectCountPerContext = 4096; -static const uint32 SVGA3dDepthStencilObjectCountPerContext = 4096; +#define SVGA3D_DX_MAX_CONSTBUF_BINDING_SIZE (4096 * 4 * (uint32)sizeof(uint32)) -typedef uint32 SVGA3dSurfaceId; typedef uint32 SVGA3dShaderResourceViewId; typedef uint32 SVGA3dRenderTargetViewId; typedef uint32 SVGA3dDepthStencilViewId; @@ -192,20 +213,6 @@ struct SVGA3dCmdDXInvalidateContext { #include "vmware_pack_end.h" SVGA3dCmdDXInvalidateContext; /* SVGA_3D_CMD_DX_INVALIDATE_CONTEXT */ -typedef -#include "vmware_pack_begin.h" -struct SVGA3dReplyFormatData { - uint32 formatSupport; - uint32 msaa2xQualityLevels:5; - uint32 msaa4xQualityLevels:5; - uint32 msaa8xQualityLevels:5; - uint32 msaa16xQualityLevels:5; - uint32 msaa32xQualityLevels:5; - uint32 pad:7; -} -#include "vmware_pack_end.h" -SVGA3dReplyFormatData; - typedef #include "vmware_pack_begin.h" struct SVGA3dCmdDXSetSingleConstantBuffer { @@ -622,6 +629,28 @@ struct SVGA3dCmdDXPredCopy { #include "vmware_pack_end.h" SVGA3dCmdDXPredCopy; /* SVGA_3D_CMD_DX_PRED_COPY */ +typedef +#include "vmware_pack_begin.h" +struct SVGA3dCmdDXPredConvertRegion { + SVGA3dSurfaceId dstSid; + uint32 dstSubResource; + SVGA3dBox destBox; + SVGA3dSurfaceId srcSid; + uint32 srcSubResource; + SVGA3dBox srcBox; +} +#include "vmware_pack_end.h" +SVGA3dCmdDXPredConvertRegion; /* SVGA_3D_CMD_DX_PRED_CONVERT_REGION */ + +typedef +#include "vmware_pack_begin.h" +struct SVGA3dCmdDXPredConvert { + SVGA3dSurfaceId dstSid; + SVGA3dSurfaceId srcSid; +} +#include "vmware_pack_end.h" +SVGA3dCmdDXPredConvert; /* SVGA_3D_CMD_DX_PRED_CONVERT */ + typedef #include "vmware_pack_begin.h" struct SVGA3dCmdDXBufferCopy { @@ -635,23 +664,57 @@ struct SVGA3dCmdDXBufferCopy { SVGA3dCmdDXBufferCopy; /* SVGA_3D_CMD_DX_BUFFER_COPY */ -typedef uint32 SVGA3dDXStretchBltMode; -#define SVGADX_STRETCHBLT_LINEAR (1 << 0) -#define SVGADX_STRETCHBLT_FORCE_SRC_SRGB (1 << 1) +/* + * Perform a surface copy between a multisample, and a non-multisampled + * surface. + */ +typedef +#include "vmware_pack_begin.h" +struct { + SVGA3dSurfaceId dstSid; + uint32 dstSubResource; + SVGA3dSurfaceId srcSid; + uint32 srcSubResource; + SVGA3dSurfaceFormat copyFormat; +} +#include "vmware_pack_end.h" +SVGA3dCmdDXResolveCopy; /* SVGA_3D_CMD_DX_RESOLVE_COPY */ + +/* + * Perform a predicated surface copy between a multisample, and a + * non-multisampled surface. + */ +typedef +#include "vmware_pack_begin.h" +struct { + SVGA3dSurfaceId dstSid; + uint32 dstSubResource; + SVGA3dSurfaceId srcSid; + uint32 srcSubResource; + SVGA3dSurfaceFormat copyFormat; +} +#include "vmware_pack_end.h" +SVGA3dCmdDXPredResolveCopy; /* SVGA_3D_CMD_DX_PRED_RESOLVE_COPY */ + +typedef uint32 SVGA3dDXPresentBltMode; +#define SVGADX_PRESENTBLT_LINEAR (1 << 0) +#define SVGADX_PRESENTBLT_FORCE_SRC_SRGB (1 << 1) +#define SVGADX_PRESENTBLT_FORCE_SRC_XRBIAS (1 << 2) +#define SVGADX_PRESENTBLT_MODE_MAX (1 << 3) typedef #include "vmware_pack_begin.h" -struct SVGA3dCmdDXStretchBlt { +struct SVGA3dCmdDXPresentBlt { SVGA3dSurfaceId srcSid; uint32 srcSubResource; SVGA3dSurfaceId dstSid; uint32 destSubResource; SVGA3dBox boxSrc; SVGA3dBox boxDest; - SVGA3dDXStretchBltMode mode; + SVGA3dDXPresentBltMode mode; } #include "vmware_pack_end.h" -SVGA3dCmdDXStretchBlt; /* SVGA_3D_CMD_DX_STRETCHBLT */ +SVGA3dCmdDXPresentBlt; /* SVGA_3D_CMD_DX_PRESENTBLT*/ typedef #include "vmware_pack_begin.h" @@ -661,26 +724,6 @@ struct SVGA3dCmdDXGenMips { #include "vmware_pack_end.h" SVGA3dCmdDXGenMips; /* SVGA_3D_CMD_DX_GENMIPS */ -/* - * Defines a resource/DX surface. Resources share the surfaceId namespace. - * - */ -typedef -#include "vmware_pack_begin.h" -struct SVGA3dCmdDefineGBSurface_v2 { - uint32 sid; - SVGA3dSurfaceFlags surfaceFlags; - SVGA3dSurfaceFormat format; - uint32 numMipLevels; - uint32 multisampleCount; - SVGA3dTextureFilter autogenFilter; - SVGA3dSize size; - uint32 arraySize; - uint32 pad; -} -#include "vmware_pack_end.h" -SVGA3dCmdDefineGBSurface_v2; /* SVGA_3D_CMD_DEFINE_GB_SURFACE_V2 */ - /* * Update a sub-resource in a guest-backed resource. * (Inform the device that the guest-contents have been updated.) @@ -724,7 +767,8 @@ SVGA3dCmdDXInvalidateSubResource; /* SVGA_3D_CMD_DX_INVALIDATE_SUBRESOURCE */ /* * Raw byte wise transfer from a buffer surface into another surface - * of the requested box. + * of the requested box. Supported if 3d is enabled and SVGA_CAP_DX + * is set. This command does not take a context. */ typedef #include "vmware_pack_begin.h" @@ -773,6 +817,93 @@ struct SVGA3dCmdDXSurfaceCopyAndReadback { SVGA3dCmdDXSurfaceCopyAndReadback; /* SVGA_3D_CMD_DX_SURFACE_COPY_AND_READBACK */ +/* + * SVGA_DX_HINT_NONE: Does nothing. + * + * SVGA_DX_HINT_PREFETCH_OBJECT: + * SVGA_DX_HINT_PREEVICT_OBJECT: + * Consumes a SVGAObjectRef, and hints that the host should consider + * fetching/evicting the specified object. + * + * An id of SVGA3D_INVALID_ID can be used if the guest isn't sure + * what object was affected. (For instance, if the guest knows that + * it is about to evict a DXShader, but doesn't know precisely which one, + * the device can still use this to help limit it's search, or track + * how many page-outs have happened.) + * + * SVGA_DX_HINT_PREFETCH_COBJECT: + * SVGA_DX_HINT_PREEVICT_COBJECT: + * Same as the above, except they consume an SVGACObjectRef. + */ +typedef uint32 SVGADXHintId; +#define SVGA_DX_HINT_NONE 0 +#define SVGA_DX_HINT_PREFETCH_OBJECT 1 +#define SVGA_DX_HINT_PREEVICT_OBJECT 2 +#define SVGA_DX_HINT_PREFETCH_COBJECT 3 +#define SVGA_DX_HINT_PREEVICT_COBJECT 4 +#define SVGA_DX_HINT_MAX 5 + +typedef +#include "vmware_pack_begin.h" +struct SVGAObjectRef { + SVGAOTableType type; + uint32 id; +} +#include "vmware_pack_end.h" +SVGAObjectRef; + +typedef +#include "vmware_pack_begin.h" +struct SVGACObjectRef { + SVGACOTableType type; + uint32 cid; + uint32 id; +} +#include "vmware_pack_end.h" +SVGACObjectRef; + +typedef +#include "vmware_pack_begin.h" +struct SVGA3dCmdDXHint { + SVGADXHintId hintId; + + /* + * Followed by variable sized data depending on the hintId. + */ +} +#include "vmware_pack_end.h" +SVGA3dCmdDXHint; +/* SVGA_3D_CMD_DX_HINT */ + +typedef +#include "vmware_pack_begin.h" +struct SVGA3dCmdDXBufferUpdate { + SVGA3dSurfaceId sid; + uint32 x; + uint32 width; +} +#include "vmware_pack_end.h" +SVGA3dCmdDXBufferUpdate; +/* SVGA_3D_CMD_DX_BUFFER_UPDATE */ + +typedef +#include "vmware_pack_begin.h" +struct SVGA3dCmdDXSetConstantBufferOffset { + uint32 slot; + uint32 offsetInBytes; +} +#include "vmware_pack_end.h" +SVGA3dCmdDXSetConstantBufferOffset; + +typedef SVGA3dCmdDXSetConstantBufferOffset SVGA3dCmdDXSetVSConstantBufferOffset; +/* SVGA_3D_CMD_DX_SET_VS_CONSTANT_BUFFER_OFFSET */ + +typedef SVGA3dCmdDXSetConstantBufferOffset SVGA3dCmdDXSetPSConstantBufferOffset; +/* SVGA_3D_CMD_DX_SET_PS_CONSTANT_BUFFER_OFFSET */ + +typedef SVGA3dCmdDXSetConstantBufferOffset SVGA3dCmdDXSetGSConstantBufferOffset; +/* SVGA_3D_CMD_DX_SET_GS_CONSTANT_BUFFER_OFFSET */ + typedef #include "vmware_pack_begin.h" @@ -789,7 +920,7 @@ struct { uint32 firstArraySlice; uint32 mipLevels; uint32 arraySize; - } tex; + } tex; /* 1d, 2d, 3d, cube */ struct { uint32 firstElement; uint32 numElements; @@ -844,6 +975,7 @@ struct SVGA3dRenderTargetViewDesc { struct { uint32 firstElement; uint32 numElements; + uint32 padding0; } buffer; struct { uint32 mipSlice; @@ -964,9 +1096,6 @@ SVGA3dInputElementDesc; typedef #include "vmware_pack_begin.h" struct { - /* - * XXX: How many of these can there be? - */ uint32 elid; uint32 numDescs; SVGA3dInputElementDesc desc[32]; @@ -1007,7 +1136,7 @@ struct SVGA3dDXBlendStatePerRT { uint8 srcBlendAlpha; uint8 destBlendAlpha; uint8 blendOpAlpha; - uint8 renderTargetWriteMask; + SVGA3dColorWriteEnable renderTargetWriteMask; uint8 logicOpEnable; uint8 logicOp; uint16 pad0; @@ -1125,7 +1254,7 @@ struct { float slopeScaledDepthBias; uint8 depthClipEnable; uint8 scissorEnable; - uint8 multisampleEnable; + SVGA3dMultisampleRastEnable multisampleEnable; uint8 antialiasedLineEnable; float lineWidth; uint8 lineStippleEnable; @@ -1152,7 +1281,7 @@ struct SVGA3dCmdDXDefineRasterizerState { float slopeScaledDepthBias; uint8 depthClipEnable; uint8 scissorEnable; - uint8 multisampleEnable; + SVGA3dMultisampleRastEnable multisampleEnable; uint8 antialiasedLineEnable; float lineWidth; uint8 lineStippleEnable; @@ -1222,21 +1351,6 @@ struct SVGA3dCmdDXDestroySamplerState { #include "vmware_pack_end.h" SVGA3dCmdDXDestroySamplerState; /* SVGA_3D_CMD_DX_DESTROY_SAMPLER_STATE */ -/* - */ -typedef -#include "vmware_pack_begin.h" -struct SVGA3dSignatureEntry { - uint8 systemValue; - uint8 reg; /* register is a reserved word */ - uint16 mask; - uint8 registerComponentType; - uint8 minPrecision; - uint16 pad0; -} -#include "vmware_pack_end.h" -SVGA3dSignatureEntry; - typedef #include "vmware_pack_begin.h" struct SVGA3dCmdDXDefineShader { @@ -1254,12 +1368,7 @@ struct SVGACOTableDXShaderEntry { uint32 sizeInBytes; uint32 offsetInBytes; SVGAMobId mobid; - uint32 numInputSignatureEntries; - uint32 numOutputSignatureEntries; - - uint32 numPatchConstantSignatureEntries; - - uint32 pad; + uint32 pad[4]; } #include "vmware_pack_end.h" SVGACOTableDXShaderEntry; @@ -1283,6 +1392,25 @@ struct SVGA3dCmdDXBindShader { #include "vmware_pack_end.h" SVGA3dCmdDXBindShader; /* SVGA_3D_CMD_DX_BIND_SHADER */ +typedef +#include "vmware_pack_begin.h" +struct SVGA3dCmdDXBindAllShader { + uint32 cid; + SVGAMobId mobid; +} +#include "vmware_pack_end.h" +SVGA3dCmdDXBindAllShader; /* SVGA_3D_CMD_DX_BIND_ALL_SHADER */ + +typedef +#include "vmware_pack_begin.h" +struct SVGA3dCmdDXCondBindAllShader { + uint32 cid; + SVGAMobId testMobid; + SVGAMobId mobid; +} +#include "vmware_pack_end.h" +SVGA3dCmdDXCondBindAllShader; /* SVGA_3D_CMD_DX_COND_BIND_ALL_SHADER */ + /* * The maximum number of streamout decl's in each streamout entry. */ @@ -1356,7 +1484,6 @@ SVGA3dCmdDXMobFence64; /* SVGA_3D_CMD_DX_MOB_FENCE_64 */ * * This command allows the guest to bind a mob to a context-object table. */ - typedef #include "vmware_pack_begin.h" struct SVGA3dCmdDXSetCOTable { @@ -1368,6 +1495,26 @@ struct SVGA3dCmdDXSetCOTable { #include "vmware_pack_end.h" SVGA3dCmdDXSetCOTable; /* SVGA_3D_CMD_DX_SET_COTABLE */ +/* + * Guests using SVGA_3D_CMD_DX_GROW_COTABLE are promising that + * the new COTable contains the same contents as the old one, except possibly + * for some new invalid entries at the end. + * + * If there is an old cotable mob bound, it also has to still be valid. + * + * (Otherwise, guests should use the DXSetCOTableBase command.) + */ +typedef +#include "vmware_pack_begin.h" +struct SVGA3dCmdDXGrowCOTable { + uint32 cid; + uint32 mobid; + SVGACOTableType type; + uint32 validSizeInBytes; +} +#include "vmware_pack_end.h" +SVGA3dCmdDXGrowCOTable; /* SVGA_3D_CMD_DX_GROW_COTABLE */ + typedef #include "vmware_pack_begin.h" struct SVGA3dCmdDXReadbackCOTable { @@ -1471,7 +1618,7 @@ struct SVGADXContextMobFormat { SVGA3dQueryId queryID[SVGA3D_MAX_QUERY]; SVGA3dCOTableData cotables[SVGA_COTABLE_MAX]; - uint32 pad7[381]; + uint32 pad7[380]; } #include "vmware_pack_end.h" SVGADXContextMobFormat; diff --git a/drivers/gpu/drm/vmwgfx/device_include/svga3d_limits.h b/drivers/gpu/drm/vmwgfx/device_include/svga3d_limits.h index a1c36877ad552..2d462ab7cccf5 100644 --- a/drivers/gpu/drm/vmwgfx/device_include/svga3d_limits.h +++ b/drivers/gpu/drm/vmwgfx/device_include/svga3d_limits.h @@ -62,7 +62,9 @@ * Maximum size in dwords of shader text the SVGA device will allow. * Currently 8 MB. */ -#define SVGA3D_MAX_SHADER_MEMORY (8 * 1024 * 1024 / sizeof(uint32)) +#define SVGA3D_MAX_SHADER_MEMORY_BYTES (8 * 1024 * 1024) +#define SVGA3D_MAX_SHADER_MEMORY (SVGA3D_MAX_SHADER_MEMORY_BYTES / \ + sizeof(uint32)) #define SVGA3D_MAX_CLIP_PLANES 6 diff --git a/drivers/gpu/drm/vmwgfx/device_include/svga3d_surfacedefs.h b/drivers/gpu/drm/vmwgfx/device_include/svga3d_surfacedefs.h index babe7cb84fc21..6422e3899cdf0 100644 --- a/drivers/gpu/drm/vmwgfx/device_include/svga3d_surfacedefs.h +++ b/drivers/gpu/drm/vmwgfx/device_include/svga3d_surfacedefs.h @@ -25,189 +25,355 @@ * **************************************************************************/ -#include <linux/kernel.h> - -#ifdef __KERNEL__ - -#include <drm/vmwgfx_drm.h> -#define surf_size_struct struct drm_vmw_size - -#else /* __KERNEL__ */ +/* + * svga3d_surfacedefs.h -- + * + * Surface definitions and inlineable utilities for SVGA3d. + */ -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(_A) (sizeof(_A) / sizeof((_A)[0])) -#endif /* ARRAY_SIZE */ +#ifndef _SVGA3D_SURFACEDEFS_H_ +#define _SVGA3D_SURFACEDEFS_H_ -#define max_t(type, x, y) ((x) > (y) ? (x) : (y)) -#define surf_size_struct SVGA3dSize -#define u32 uint32 +#define INCLUDE_ALLOW_USERLEVEL +#define INCLUDE_ALLOW_MODULE +#include "includeCheck.h" -#endif /* __KERNEL__ */ +#include <linux/kernel.h> +#include <drm/vmwgfx_drm.h> #include "svga3d_reg.h" +#define surf_size_struct struct drm_vmw_size + /* - * enum svga3d_block_desc describes the active data channels in a block. - * - * There can be at-most four active channels in a block: - * 1. Red, bump W, luminance and depth are stored in the first channel. - * 2. Green, bump V and stencil are stored in the second channel. - * 3. Blue and bump U are stored in the third channel. - * 4. Alpha and bump Q are stored in the fourth channel. - * - * Block channels can be used to store compressed and buffer data: - * 1. For compressed formats, only the data channel is used and its size - * is equal to that of a singular block in the compression scheme. - * 2. For buffer formats, only the data channel is used and its size is - * exactly one byte in length. - * 3. In each case the bit depth represent the size of a singular block. - * - * Note: Compressed and IEEE formats do not use the bitMask structure. + * enum svga3d_block_desc - describes generic properties about formats. */ - enum svga3d_block_desc { - SVGA3DBLOCKDESC_NONE = 0, /* No channels are active */ - SVGA3DBLOCKDESC_BLUE = 1 << 0, /* Block with red channel - data */ - SVGA3DBLOCKDESC_U = 1 << 0, /* Block with bump U channel - data */ - SVGA3DBLOCKDESC_UV_VIDEO = 1 << 7, /* Block with alternating video - U and V */ - SVGA3DBLOCKDESC_GREEN = 1 << 1, /* Block with green channel - data */ - SVGA3DBLOCKDESC_V = 1 << 1, /* Block with bump V channel - data */ - SVGA3DBLOCKDESC_STENCIL = 1 << 1, /* Block with a stencil - channel */ - SVGA3DBLOCKDESC_RED = 1 << 2, /* Block with blue channel - data */ - SVGA3DBLOCKDESC_W = 1 << 2, /* Block with bump W channel - data */ - SVGA3DBLOCKDESC_LUMINANCE = 1 << 2, /* Block with luminance channel - data */ - SVGA3DBLOCKDESC_Y = 1 << 2, /* Block with video luminance - data */ - SVGA3DBLOCKDESC_DEPTH = 1 << 2, /* Block with depth channel */ - SVGA3DBLOCKDESC_ALPHA = 1 << 3, /* Block with an alpha - channel */ - SVGA3DBLOCKDESC_Q = 1 << 3, /* Block with bump Q channel - data */ - SVGA3DBLOCKDESC_BUFFER = 1 << 4, /* Block stores 1 byte of - data */ - SVGA3DBLOCKDESC_COMPRESSED = 1 << 5, /* Block stores n bytes of - data depending on the - compression method used */ - SVGA3DBLOCKDESC_IEEE_FP = 1 << 6, /* Block stores data in an IEEE - floating point - representation in - all channels */ - SVGA3DBLOCKDESC_PLANAR_YUV = 1 << 8, /* Three separate blocks store - data. */ - SVGA3DBLOCKDESC_U_VIDEO = 1 << 9, /* Block with U video data */ - SVGA3DBLOCKDESC_V_VIDEO = 1 << 10, /* Block with V video data */ - SVGA3DBLOCKDESC_EXP = 1 << 11, /* Shared exponent */ - SVGA3DBLOCKDESC_SRGB = 1 << 12, /* Data is in sRGB format */ - SVGA3DBLOCKDESC_2PLANAR_YUV = 1 << 13, /* 2 planes of Y, UV, - e.g., NV12. */ - SVGA3DBLOCKDESC_3PLANAR_YUV = 1 << 14, /* 3 planes of separate - Y, U, V, e.g., YV12. */ - - SVGA3DBLOCKDESC_RG = SVGA3DBLOCKDESC_RED | - SVGA3DBLOCKDESC_GREEN, - SVGA3DBLOCKDESC_RGB = SVGA3DBLOCKDESC_RG | - SVGA3DBLOCKDESC_BLUE, - SVGA3DBLOCKDESC_RGB_SRGB = SVGA3DBLOCKDESC_RGB | - SVGA3DBLOCKDESC_SRGB, - SVGA3DBLOCKDESC_RGBA = SVGA3DBLOCKDESC_RGB | - SVGA3DBLOCKDESC_ALPHA, - SVGA3DBLOCKDESC_RGBA_SRGB = SVGA3DBLOCKDESC_RGBA | - SVGA3DBLOCKDESC_SRGB, + /* Nothing special can be said about this format. */ + SVGA3DBLOCKDESC_NONE = 0, + + /* Format contains Blue/U data */ + SVGA3DBLOCKDESC_BLUE = 1 << 0, + SVGA3DBLOCKDESC_W = 1 << 0, + SVGA3DBLOCKDESC_BUMP_L = 1 << 0, + + /* Format contains Green/V data */ + SVGA3DBLOCKDESC_GREEN = 1 << 1, + SVGA3DBLOCKDESC_V = 1 << 1, + + /* Format contains Red/W/Luminance data */ + SVGA3DBLOCKDESC_RED = 1 << 2, + SVGA3DBLOCKDESC_U = 1 << 2, + SVGA3DBLOCKDESC_LUMINANCE = 1 << 2, + + /* Format contains Alpha/Q data */ + SVGA3DBLOCKDESC_ALPHA = 1 << 3, + SVGA3DBLOCKDESC_Q = 1 << 3, + + /* Format is a buffer */ + SVGA3DBLOCKDESC_BUFFER = 1 << 4, + + /* Format is compressed */ + SVGA3DBLOCKDESC_COMPRESSED = 1 << 5, + + /* Format uses IEEE floating point */ + SVGA3DBLOCKDESC_FP = 1 << 6, + + /* Three separate blocks store data. */ + SVGA3DBLOCKDESC_PLANAR_YUV = 1 << 7, + + /* 2 planes of Y, UV, e.g., NV12. */ + SVGA3DBLOCKDESC_2PLANAR_YUV = 1 << 8, + + /* 3 planes of separate Y, U, V, e.g., YV12. */ + SVGA3DBLOCKDESC_3PLANAR_YUV = 1 << 9, + + /* Block with a stencil channel */ + SVGA3DBLOCKDESC_STENCIL = 1 << 11, + + /* Typeless format */ + SVGA3DBLOCKDESC_TYPELESS = 1 << 12, + + /* Channels are signed integers */ + SVGA3DBLOCKDESC_SINT = 1 << 13, + + /* Channels are unsigned integers */ + SVGA3DBLOCKDESC_UINT = 1 << 14, + + /* Channels are normalized (when sampling) */ + SVGA3DBLOCKDESC_NORM = 1 << 15, + + /* Channels are in SRGB */ + SVGA3DBLOCKDESC_SRGB = 1 << 16, + + /* Shared exponent */ + SVGA3DBLOCKDESC_EXP = 1 << 17, + + /* Format contains color data. */ + SVGA3DBLOCKDESC_COLOR = 1 << 18, + /* Format contains depth data. */ + SVGA3DBLOCKDESC_DEPTH = 1 << 19, + /* Format contains bump data. */ + SVGA3DBLOCKDESC_BUMP = 1 << 20, + + /* Format contains YUV video data. */ + SVGA3DBLOCKDESC_YUV_VIDEO = 1 << 21, + + /* For mixed unsigned/signed formats. */ + SVGA3DBLOCKDESC_MIXED = 1 << 22, + + /* For distingushing CxV8U8. */ + SVGA3DBLOCKDESC_CX = 1 << 23, + + /* Different compressed format groups. */ + SVGA3DBLOCKDESC_BC1 = 1 << 24, + SVGA3DBLOCKDESC_BC2 = 1 << 25, + SVGA3DBLOCKDESC_BC3 = 1 << 26, + SVGA3DBLOCKDESC_BC4 = 1 << 27, + SVGA3DBLOCKDESC_BC5 = 1 << 28, + + SVGA3DBLOCKDESC_A_UINT = SVGA3DBLOCKDESC_ALPHA | + SVGA3DBLOCKDESC_UINT | + SVGA3DBLOCKDESC_COLOR, + SVGA3DBLOCKDESC_A_UNORM = SVGA3DBLOCKDESC_A_UINT | + SVGA3DBLOCKDESC_NORM, + SVGA3DBLOCKDESC_R_UINT = SVGA3DBLOCKDESC_RED | + SVGA3DBLOCKDESC_UINT | + SVGA3DBLOCKDESC_COLOR, + SVGA3DBLOCKDESC_R_UNORM = SVGA3DBLOCKDESC_R_UINT | + SVGA3DBLOCKDESC_NORM, + SVGA3DBLOCKDESC_R_SINT = SVGA3DBLOCKDESC_RED | + SVGA3DBLOCKDESC_SINT | + SVGA3DBLOCKDESC_COLOR, + SVGA3DBLOCKDESC_R_SNORM = SVGA3DBLOCKDESC_R_SINT | + SVGA3DBLOCKDESC_NORM, + SVGA3DBLOCKDESC_G_UINT = SVGA3DBLOCKDESC_GREEN | + SVGA3DBLOCKDESC_UINT | + SVGA3DBLOCKDESC_COLOR, + SVGA3DBLOCKDESC_RG_UINT = SVGA3DBLOCKDESC_RED | + SVGA3DBLOCKDESC_GREEN | + SVGA3DBLOCKDESC_UINT | + SVGA3DBLOCKDESC_COLOR, + SVGA3DBLOCKDESC_RG_UNORM = SVGA3DBLOCKDESC_RG_UINT | + SVGA3DBLOCKDESC_NORM, + SVGA3DBLOCKDESC_RG_SINT = SVGA3DBLOCKDESC_RED | + SVGA3DBLOCKDESC_GREEN | + SVGA3DBLOCKDESC_SINT | + SVGA3DBLOCKDESC_COLOR, + SVGA3DBLOCKDESC_RG_SNORM = SVGA3DBLOCKDESC_RG_SINT | + SVGA3DBLOCKDESC_NORM, + SVGA3DBLOCKDESC_RGB_UINT = SVGA3DBLOCKDESC_RED | + SVGA3DBLOCKDESC_GREEN | + SVGA3DBLOCKDESC_BLUE | + SVGA3DBLOCKDESC_UINT | + SVGA3DBLOCKDESC_COLOR, + SVGA3DBLOCKDESC_RGB_SINT = SVGA3DBLOCKDESC_RED | + SVGA3DBLOCKDESC_GREEN | + SVGA3DBLOCKDESC_BLUE | + SVGA3DBLOCKDESC_SINT | + SVGA3DBLOCKDESC_COLOR, + SVGA3DBLOCKDESC_RGB_UNORM = SVGA3DBLOCKDESC_RGB_UINT | + SVGA3DBLOCKDESC_NORM, + SVGA3DBLOCKDESC_RGB_UNORM_SRGB = SVGA3DBLOCKDESC_RGB_UNORM | + SVGA3DBLOCKDESC_SRGB, + SVGA3DBLOCKDESC_RGBA_UINT = SVGA3DBLOCKDESC_RED | + SVGA3DBLOCKDESC_GREEN | + SVGA3DBLOCKDESC_BLUE | + SVGA3DBLOCKDESC_ALPHA | + SVGA3DBLOCKDESC_UINT | + SVGA3DBLOCKDESC_COLOR, + SVGA3DBLOCKDESC_RGBA_UNORM = SVGA3DBLOCKDESC_RGBA_UINT | + SVGA3DBLOCKDESC_NORM, + SVGA3DBLOCKDESC_RGBA_UNORM_SRGB = SVGA3DBLOCKDESC_RGBA_UNORM | + SVGA3DBLOCKDESC_SRGB, + SVGA3DBLOCKDESC_RGBA_SINT = SVGA3DBLOCKDESC_RED | + SVGA3DBLOCKDESC_GREEN | + SVGA3DBLOCKDESC_BLUE | + SVGA3DBLOCKDESC_ALPHA | + SVGA3DBLOCKDESC_SINT | + SVGA3DBLOCKDESC_COLOR, + SVGA3DBLOCKDESC_RGBA_SNORM = SVGA3DBLOCKDESC_RGBA_SINT | + SVGA3DBLOCKDESC_NORM, + SVGA3DBLOCKDESC_RGBA_FP = SVGA3DBLOCKDESC_RED | + SVGA3DBLOCKDESC_GREEN | + SVGA3DBLOCKDESC_BLUE | + SVGA3DBLOCKDESC_ALPHA | + SVGA3DBLOCKDESC_FP | + SVGA3DBLOCKDESC_COLOR, SVGA3DBLOCKDESC_UV = SVGA3DBLOCKDESC_U | - SVGA3DBLOCKDESC_V, + SVGA3DBLOCKDESC_V | + SVGA3DBLOCKDESC_BUMP, SVGA3DBLOCKDESC_UVL = SVGA3DBLOCKDESC_UV | - SVGA3DBLOCKDESC_LUMINANCE, + SVGA3DBLOCKDESC_BUMP_L | + SVGA3DBLOCKDESC_MIXED | + SVGA3DBLOCKDESC_BUMP, SVGA3DBLOCKDESC_UVW = SVGA3DBLOCKDESC_UV | - SVGA3DBLOCKDESC_W, + SVGA3DBLOCKDESC_W | + SVGA3DBLOCKDESC_BUMP, SVGA3DBLOCKDESC_UVWA = SVGA3DBLOCKDESC_UVW | - SVGA3DBLOCKDESC_ALPHA, + SVGA3DBLOCKDESC_ALPHA | + SVGA3DBLOCKDESC_MIXED | + SVGA3DBLOCKDESC_BUMP, SVGA3DBLOCKDESC_UVWQ = SVGA3DBLOCKDESC_U | - SVGA3DBLOCKDESC_V | - SVGA3DBLOCKDESC_W | - SVGA3DBLOCKDESC_Q, - SVGA3DBLOCKDESC_LA = SVGA3DBLOCKDESC_LUMINANCE | - SVGA3DBLOCKDESC_ALPHA, + SVGA3DBLOCKDESC_V | + SVGA3DBLOCKDESC_W | + SVGA3DBLOCKDESC_Q | + SVGA3DBLOCKDESC_BUMP, + SVGA3DBLOCKDESC_L_UNORM = SVGA3DBLOCKDESC_LUMINANCE | + SVGA3DBLOCKDESC_UINT | + SVGA3DBLOCKDESC_NORM | + SVGA3DBLOCKDESC_COLOR, + SVGA3DBLOCKDESC_LA_UNORM = SVGA3DBLOCKDESC_LUMINANCE | + SVGA3DBLOCKDESC_ALPHA | + SVGA3DBLOCKDESC_UINT | + SVGA3DBLOCKDESC_NORM | + SVGA3DBLOCKDESC_COLOR, SVGA3DBLOCKDESC_R_FP = SVGA3DBLOCKDESC_RED | - SVGA3DBLOCKDESC_IEEE_FP, + SVGA3DBLOCKDESC_FP | + SVGA3DBLOCKDESC_COLOR, SVGA3DBLOCKDESC_RG_FP = SVGA3DBLOCKDESC_R_FP | - SVGA3DBLOCKDESC_GREEN, + SVGA3DBLOCKDESC_GREEN | + SVGA3DBLOCKDESC_COLOR, SVGA3DBLOCKDESC_RGB_FP = SVGA3DBLOCKDESC_RG_FP | - SVGA3DBLOCKDESC_BLUE, - SVGA3DBLOCKDESC_RGBA_FP = SVGA3DBLOCKDESC_RGB_FP | - SVGA3DBLOCKDESC_ALPHA, - SVGA3DBLOCKDESC_DS = SVGA3DBLOCKDESC_DEPTH | - SVGA3DBLOCKDESC_STENCIL, - SVGA3DBLOCKDESC_YUV = SVGA3DBLOCKDESC_UV_VIDEO | - SVGA3DBLOCKDESC_Y, + SVGA3DBLOCKDESC_BLUE | + SVGA3DBLOCKDESC_COLOR, + SVGA3DBLOCKDESC_YUV = SVGA3DBLOCKDESC_YUV_VIDEO | + SVGA3DBLOCKDESC_COLOR, SVGA3DBLOCKDESC_AYUV = SVGA3DBLOCKDESC_ALPHA | - SVGA3DBLOCKDESC_Y | - SVGA3DBLOCKDESC_U_VIDEO | - SVGA3DBLOCKDESC_V_VIDEO, - SVGA3DBLOCKDESC_RGBE = SVGA3DBLOCKDESC_RGB | - SVGA3DBLOCKDESC_EXP, - SVGA3DBLOCKDESC_COMPRESSED_SRGB = SVGA3DBLOCKDESC_COMPRESSED | - SVGA3DBLOCKDESC_SRGB, - SVGA3DBLOCKDESC_NV12 = SVGA3DBLOCKDESC_PLANAR_YUV | - SVGA3DBLOCKDESC_2PLANAR_YUV, - SVGA3DBLOCKDESC_YV12 = SVGA3DBLOCKDESC_PLANAR_YUV | - SVGA3DBLOCKDESC_3PLANAR_YUV, + SVGA3DBLOCKDESC_YUV_VIDEO | + SVGA3DBLOCKDESC_COLOR, + SVGA3DBLOCKDESC_RGB_EXP = SVGA3DBLOCKDESC_RED | + SVGA3DBLOCKDESC_GREEN | + SVGA3DBLOCKDESC_BLUE | + SVGA3DBLOCKDESC_EXP | + SVGA3DBLOCKDESC_COLOR, + + SVGA3DBLOCKDESC_COMP_TYPELESS = SVGA3DBLOCKDESC_COMPRESSED | + SVGA3DBLOCKDESC_TYPELESS, + SVGA3DBLOCKDESC_COMP_UNORM = SVGA3DBLOCKDESC_COMPRESSED | + SVGA3DBLOCKDESC_UINT | + SVGA3DBLOCKDESC_NORM | + SVGA3DBLOCKDESC_COLOR, + SVGA3DBLOCKDESC_COMP_SNORM = SVGA3DBLOCKDESC_COMPRESSED | + SVGA3DBLOCKDESC_SINT | + SVGA3DBLOCKDESC_NORM | + SVGA3DBLOCKDESC_COLOR, + SVGA3DBLOCKDESC_COMP_UNORM_SRGB = SVGA3DBLOCKDESC_COMP_UNORM | + SVGA3DBLOCKDESC_SRGB, + SVGA3DBLOCKDESC_BC1_COMP_TYPELESS = SVGA3DBLOCKDESC_BC1 | + SVGA3DBLOCKDESC_COMP_TYPELESS, + SVGA3DBLOCKDESC_BC1_COMP_UNORM = SVGA3DBLOCKDESC_BC1 | + SVGA3DBLOCKDESC_COMP_UNORM, + SVGA3DBLOCKDESC_BC1_COMP_UNORM_SRGB = SVGA3DBLOCKDESC_BC1_COMP_UNORM | + SVGA3DBLOCKDESC_SRGB, + SVGA3DBLOCKDESC_BC2_COMP_TYPELESS = SVGA3DBLOCKDESC_BC2 | + SVGA3DBLOCKDESC_COMP_TYPELESS, + SVGA3DBLOCKDESC_BC2_COMP_UNORM = SVGA3DBLOCKDESC_BC2 | + SVGA3DBLOCKDESC_COMP_UNORM, + SVGA3DBLOCKDESC_BC2_COMP_UNORM_SRGB = SVGA3DBLOCKDESC_BC2_COMP_UNORM | + SVGA3DBLOCKDESC_SRGB, + SVGA3DBLOCKDESC_BC3_COMP_TYPELESS = SVGA3DBLOCKDESC_BC3 | + SVGA3DBLOCKDESC_COMP_TYPELESS, + SVGA3DBLOCKDESC_BC3_COMP_UNORM = SVGA3DBLOCKDESC_BC3 | + SVGA3DBLOCKDESC_COMP_UNORM, + SVGA3DBLOCKDESC_BC3_COMP_UNORM_SRGB = SVGA3DBLOCKDESC_BC3_COMP_UNORM | + SVGA3DBLOCKDESC_SRGB, + SVGA3DBLOCKDESC_BC4_COMP_TYPELESS = SVGA3DBLOCKDESC_BC4 | + SVGA3DBLOCKDESC_COMP_TYPELESS, + SVGA3DBLOCKDESC_BC4_COMP_UNORM = SVGA3DBLOCKDESC_BC4 | + SVGA3DBLOCKDESC_COMP_UNORM, + SVGA3DBLOCKDESC_BC4_COMP_SNORM = SVGA3DBLOCKDESC_BC4 | + SVGA3DBLOCKDESC_COMP_SNORM, + SVGA3DBLOCKDESC_BC5_COMP_TYPELESS = SVGA3DBLOCKDESC_BC5 | + SVGA3DBLOCKDESC_COMP_TYPELESS, + SVGA3DBLOCKDESC_BC5_COMP_UNORM = SVGA3DBLOCKDESC_BC5 | + SVGA3DBLOCKDESC_COMP_UNORM, + SVGA3DBLOCKDESC_BC5_COMP_SNORM = SVGA3DBLOCKDESC_BC5 | + SVGA3DBLOCKDESC_COMP_SNORM, + + SVGA3DBLOCKDESC_NV12 = SVGA3DBLOCKDESC_YUV_VIDEO | + SVGA3DBLOCKDESC_PLANAR_YUV | + SVGA3DBLOCKDESC_2PLANAR_YUV | + SVGA3DBLOCKDESC_COLOR, + SVGA3DBLOCKDESC_YV12 = SVGA3DBLOCKDESC_YUV_VIDEO | + SVGA3DBLOCKDESC_PLANAR_YUV | + SVGA3DBLOCKDESC_3PLANAR_YUV | + SVGA3DBLOCKDESC_COLOR, + + SVGA3DBLOCKDESC_DEPTH_UINT = SVGA3DBLOCKDESC_DEPTH | + SVGA3DBLOCKDESC_UINT, + SVGA3DBLOCKDESC_DEPTH_UNORM = SVGA3DBLOCKDESC_DEPTH_UINT | + SVGA3DBLOCKDESC_NORM, + SVGA3DBLOCKDESC_DS = SVGA3DBLOCKDESC_DEPTH | + SVGA3DBLOCKDESC_STENCIL, + SVGA3DBLOCKDESC_DS_UINT = SVGA3DBLOCKDESC_DEPTH | + SVGA3DBLOCKDESC_STENCIL | + SVGA3DBLOCKDESC_UINT, + SVGA3DBLOCKDESC_DS_UNORM = SVGA3DBLOCKDESC_DS_UINT | + SVGA3DBLOCKDESC_NORM, + SVGA3DBLOCKDESC_DEPTH_FP = SVGA3DBLOCKDESC_DEPTH | + SVGA3DBLOCKDESC_FP, + + SVGA3DBLOCKDESC_UV_UINT = SVGA3DBLOCKDESC_UV | + SVGA3DBLOCKDESC_UINT, + SVGA3DBLOCKDESC_UV_SNORM = SVGA3DBLOCKDESC_UV | + SVGA3DBLOCKDESC_SINT | + SVGA3DBLOCKDESC_NORM, + SVGA3DBLOCKDESC_UVCX_SNORM = SVGA3DBLOCKDESC_UV_SNORM | + SVGA3DBLOCKDESC_CX, + SVGA3DBLOCKDESC_UVWQ_SNORM = SVGA3DBLOCKDESC_UVWQ | + SVGA3DBLOCKDESC_SINT | + SVGA3DBLOCKDESC_NORM, }; -/* - * SVGA3dSurfaceDesc describes the actual pixel data. - * - * This structure provides the following information: - * 1. Block description. - * 2. Dimensions of a block in the surface. - * 3. Size of block in bytes. - * 4. Bit depth of the pixel data. - * 5. Channel bit depths and masks (if applicable). - */ struct svga3d_channel_def { union { u8 blue; - u8 u; + u8 w_bump; + u8 l_bump; u8 uv_video; u8 u_video; }; union { u8 green; - u8 v; u8 stencil; + u8 v_bump; u8 v_video; }; union { u8 red; - u8 w; + u8 u_bump; u8 luminance; - u8 y; + u8 y_video; u8 depth; u8 data; }; union { u8 alpha; - u8 q; + u8 q_bump; u8 exp; }; }; +/* + * struct svga3d_surface_desc - describes the actual pixel data. + * + * @format: Format + * @block_desc: Block description + * @block_size: Dimensions in pixels of a block + * @bytes_per_block: Size of block in bytes + * @pitch_bytes_per_block: Size of a block in bytes for purposes of pitch + * @bit_depth: Channel bit depths + * @bit_offset: Channel bit masks (in bits offset from the start of the pointer) + */ struct svga3d_surface_desc { SVGA3dSurfaceFormat format; enum svga3d_block_desc block_desc; + surf_size_struct block_size; u32 bytes_per_block; u32 pitch_bytes_per_block; - u32 total_bit_depth; struct svga3d_channel_def bit_depth; struct svga3d_channel_def bit_offset; }; @@ -215,729 +381,728 @@ struct svga3d_surface_desc { static const struct svga3d_surface_desc svga3d_surface_descs[] = { {SVGA3D_FORMAT_INVALID, SVGA3DBLOCKDESC_NONE, {1, 1, 1}, 0, 0, - 0, {{0}, {0}, {0}, {0}}, + {{0}, {0}, {0}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_X8R8G8B8, SVGA3DBLOCKDESC_RGB, + {SVGA3D_X8R8G8B8, SVGA3DBLOCKDESC_RGB_UNORM, {1, 1, 1}, 4, 4, - 24, {{8}, {8}, {8}, {0}}, + {{8}, {8}, {8}, {0}}, {{0}, {8}, {16}, {24}}}, - {SVGA3D_A8R8G8B8, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_A8R8G8B8, SVGA3DBLOCKDESC_RGBA_UNORM, {1, 1, 1}, 4, 4, - 32, {{8}, {8}, {8}, {8}}, + {{8}, {8}, {8}, {8}}, {{0}, {8}, {16}, {24}}}, - {SVGA3D_R5G6B5, SVGA3DBLOCKDESC_RGB, + {SVGA3D_R5G6B5, SVGA3DBLOCKDESC_RGB_UNORM, {1, 1, 1}, 2, 2, - 16, {{5}, {6}, {5}, {0}}, + {{5}, {6}, {5}, {0}}, {{0}, {5}, {11}, {0}}}, - {SVGA3D_X1R5G5B5, SVGA3DBLOCKDESC_RGB, + {SVGA3D_X1R5G5B5, SVGA3DBLOCKDESC_RGB_UNORM, {1, 1, 1}, 2, 2, - 15, {{5}, {5}, {5}, {0}}, + {{5}, {5}, {5}, {0}}, {{0}, {5}, {10}, {0}}}, - {SVGA3D_A1R5G5B5, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_A1R5G5B5, SVGA3DBLOCKDESC_RGBA_UNORM, {1, 1, 1}, 2, 2, - 16, {{5}, {5}, {5}, {1}}, + {{5}, {5}, {5}, {1}}, {{0}, {5}, {10}, {15}}}, - {SVGA3D_A4R4G4B4, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_A4R4G4B4, SVGA3DBLOCKDESC_RGBA_UNORM, {1, 1, 1}, 2, 2, - 16, {{4}, {4}, {4}, {4}}, + {{4}, {4}, {4}, {4}}, {{0}, {4}, {8}, {12}}}, - {SVGA3D_Z_D32, SVGA3DBLOCKDESC_DEPTH, + {SVGA3D_Z_D32, SVGA3DBLOCKDESC_DEPTH_UNORM, {1, 1, 1}, 4, 4, - 32, {{0}, {0}, {32}, {0}}, + {{0}, {0}, {32}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_Z_D16, SVGA3DBLOCKDESC_DEPTH, + {SVGA3D_Z_D16, SVGA3DBLOCKDESC_DEPTH_UNORM, {1, 1, 1}, 2, 2, - 16, {{0}, {0}, {16}, {0}}, + {{0}, {0}, {16}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_Z_D24S8, SVGA3DBLOCKDESC_DS, + {SVGA3D_Z_D24S8, SVGA3DBLOCKDESC_DS_UNORM, {1, 1, 1}, 4, 4, - 32, {{0}, {8}, {24}, {0}}, - {{0}, {24}, {0}, {0}}}, + {{0}, {8}, {24}, {0}}, + {{0}, {0}, {8}, {0}}}, - {SVGA3D_Z_D15S1, SVGA3DBLOCKDESC_DS, + {SVGA3D_Z_D15S1, SVGA3DBLOCKDESC_DS_UNORM, {1, 1, 1}, 2, 2, - 16, {{0}, {1}, {15}, {0}}, - {{0}, {15}, {0}, {0}}}, + {{0}, {1}, {15}, {0}}, + {{0}, {0}, {1}, {0}}}, - {SVGA3D_LUMINANCE8, SVGA3DBLOCKDESC_LUMINANCE, + {SVGA3D_LUMINANCE8, SVGA3DBLOCKDESC_L_UNORM, {1, 1, 1}, 1, 1, - 8, {{0}, {0}, {8}, {0}}, + {{0}, {0}, {8}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_LUMINANCE4_ALPHA4, SVGA3DBLOCKDESC_LA, - {1 , 1, 1}, 1, 1, - 8, {{0}, {0}, {4}, {4}}, + {SVGA3D_LUMINANCE4_ALPHA4, SVGA3DBLOCKDESC_LA_UNORM, + {1, 1, 1}, 1, 1, + {{0}, {0}, {4}, {4}}, {{0}, {0}, {0}, {4}}}, - {SVGA3D_LUMINANCE16, SVGA3DBLOCKDESC_LUMINANCE, + {SVGA3D_LUMINANCE16, SVGA3DBLOCKDESC_L_UNORM, {1, 1, 1}, 2, 2, - 16, {{0}, {0}, {16}, {0}}, + {{0}, {0}, {16}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_LUMINANCE8_ALPHA8, SVGA3DBLOCKDESC_LA, + {SVGA3D_LUMINANCE8_ALPHA8, SVGA3DBLOCKDESC_LA_UNORM, {1, 1, 1}, 2, 2, - 16, {{0}, {0}, {8}, {8}}, + {{0}, {0}, {8}, {8}}, {{0}, {0}, {0}, {8}}}, - {SVGA3D_DXT1, SVGA3DBLOCKDESC_COMPRESSED, + {SVGA3D_DXT1, SVGA3DBLOCKDESC_BC1_COMP_UNORM, {4, 4, 1}, 8, 8, - 64, {{0}, {0}, {64}, {0}}, + {{0}, {0}, {64}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_DXT2, SVGA3DBLOCKDESC_COMPRESSED, + {SVGA3D_DXT2, SVGA3DBLOCKDESC_BC2_COMP_UNORM, {4, 4, 1}, 16, 16, - 128, {{0}, {0}, {128}, {0}}, + {{0}, {0}, {128}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_DXT3, SVGA3DBLOCKDESC_COMPRESSED, + {SVGA3D_DXT3, SVGA3DBLOCKDESC_BC2_COMP_UNORM, {4, 4, 1}, 16, 16, - 128, {{0}, {0}, {128}, {0}}, + {{0}, {0}, {128}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_DXT4, SVGA3DBLOCKDESC_COMPRESSED, + {SVGA3D_DXT4, SVGA3DBLOCKDESC_BC3_COMP_UNORM, {4, 4, 1}, 16, 16, - 128, {{0}, {0}, {128}, {0}}, + {{0}, {0}, {128}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_DXT5, SVGA3DBLOCKDESC_COMPRESSED, + {SVGA3D_DXT5, SVGA3DBLOCKDESC_BC3_COMP_UNORM, {4, 4, 1}, 16, 16, - 128, {{0}, {0}, {128}, {0}}, + {{0}, {0}, {128}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_BUMPU8V8, SVGA3DBLOCKDESC_UV, + {SVGA3D_BUMPU8V8, SVGA3DBLOCKDESC_UV_SNORM, {1, 1, 1}, 2, 2, - 16, {{0}, {0}, {8}, {8}}, - {{0}, {0}, {0}, {8}}}, + {{0}, {8}, {8}, {0}}, + {{0}, {8}, {0}, {0}}}, {SVGA3D_BUMPL6V5U5, SVGA3DBLOCKDESC_UVL, {1, 1, 1}, 2, 2, - 16, {{5}, {5}, {6}, {0}}, - {{11}, {6}, {0}, {0}}}, + {{6}, {5}, {5}, {0}}, + {{10}, {5}, {0}, {0}}}, {SVGA3D_BUMPX8L8V8U8, SVGA3DBLOCKDESC_UVL, {1, 1, 1}, 4, 4, - 32, {{8}, {8}, {8}, {0}}, + {{8}, {8}, {8}, {0}}, {{16}, {8}, {0}, {0}}}, - {SVGA3D_BUMPL8V8U8, SVGA3DBLOCKDESC_UVL, + {SVGA3D_FORMAT_DEAD1, SVGA3DBLOCKDESC_UVL, {1, 1, 1}, 3, 3, - 24, {{8}, {8}, {8}, {0}}, + {{8}, {8}, {8}, {0}}, {{16}, {8}, {0}, {0}}}, {SVGA3D_ARGB_S10E5, SVGA3DBLOCKDESC_RGBA_FP, {1, 1, 1}, 8, 8, - 64, {{16}, {16}, {16}, {16}}, + {{16}, {16}, {16}, {16}}, {{32}, {16}, {0}, {48}}}, {SVGA3D_ARGB_S23E8, SVGA3DBLOCKDESC_RGBA_FP, {1, 1, 1}, 16, 16, - 128, {{32}, {32}, {32}, {32}}, + {{32}, {32}, {32}, {32}}, {{64}, {32}, {0}, {96}}}, - {SVGA3D_A2R10G10B10, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_A2R10G10B10, SVGA3DBLOCKDESC_RGBA_UNORM, {1, 1, 1}, 4, 4, - 32, {{10}, {10}, {10}, {2}}, + {{10}, {10}, {10}, {2}}, {{0}, {10}, {20}, {30}}}, - {SVGA3D_V8U8, SVGA3DBLOCKDESC_UV, + {SVGA3D_V8U8, SVGA3DBLOCKDESC_UV_SNORM, {1, 1, 1}, 2, 2, - 16, {{8}, {8}, {0}, {0}}, - {{8}, {0}, {0}, {0}}}, + {{0}, {8}, {8}, {0}}, + {{0}, {8}, {0}, {0}}}, - {SVGA3D_Q8W8V8U8, SVGA3DBLOCKDESC_UVWQ, + {SVGA3D_Q8W8V8U8, SVGA3DBLOCKDESC_UVWQ_SNORM, {1, 1, 1}, 4, 4, - 32, {{8}, {8}, {8}, {8}}, - {{24}, {16}, {8}, {0}}}, + {{8}, {8}, {8}, {8}}, + {{16}, {8}, {0}, {24}}}, - {SVGA3D_CxV8U8, SVGA3DBLOCKDESC_UV, + {SVGA3D_CxV8U8, SVGA3DBLOCKDESC_UVCX_SNORM, {1, 1, 1}, 2, 2, - 16, {{8}, {8}, {0}, {0}}, - {{8}, {0}, {0}, {0}}}, + {{0}, {8}, {8}, {0}}, + {{0}, {8}, {0}, {0}}}, {SVGA3D_X8L8V8U8, SVGA3DBLOCKDESC_UVL, {1, 1, 1}, 4, 4, - 24, {{8}, {8}, {8}, {0}}, + {{8}, {8}, {8}, {0}}, {{16}, {8}, {0}, {0}}}, {SVGA3D_A2W10V10U10, SVGA3DBLOCKDESC_UVWA, {1, 1, 1}, 4, 4, - 32, {{10}, {10}, {10}, {2}}, - {{0}, {10}, {20}, {30}}}, + {{10}, {10}, {10}, {2}}, + {{20}, {10}, {0}, {30}}}, - {SVGA3D_ALPHA8, SVGA3DBLOCKDESC_ALPHA, + {SVGA3D_ALPHA8, SVGA3DBLOCKDESC_A_UNORM, {1, 1, 1}, 1, 1, - 8, {{0}, {0}, {0}, {8}}, + {{0}, {0}, {0}, {8}}, {{0}, {0}, {0}, {0}}}, {SVGA3D_R_S10E5, SVGA3DBLOCKDESC_R_FP, {1, 1, 1}, 2, 2, - 16, {{0}, {0}, {16}, {0}}, + {{0}, {0}, {16}, {0}}, {{0}, {0}, {0}, {0}}}, {SVGA3D_R_S23E8, SVGA3DBLOCKDESC_R_FP, {1, 1, 1}, 4, 4, - 32, {{0}, {0}, {32}, {0}}, + {{0}, {0}, {32}, {0}}, {{0}, {0}, {0}, {0}}}, {SVGA3D_RG_S10E5, SVGA3DBLOCKDESC_RG_FP, {1, 1, 1}, 4, 4, - 32, {{0}, {16}, {16}, {0}}, + {{0}, {16}, {16}, {0}}, {{0}, {16}, {0}, {0}}}, {SVGA3D_RG_S23E8, SVGA3DBLOCKDESC_RG_FP, {1, 1, 1}, 8, 8, - 64, {{0}, {32}, {32}, {0}}, + {{0}, {32}, {32}, {0}}, {{0}, {32}, {0}, {0}}}, {SVGA3D_BUFFER, SVGA3DBLOCKDESC_BUFFER, {1, 1, 1}, 1, 1, - 8, {{0}, {0}, {8}, {0}}, + {{0}, {0}, {8}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_Z_D24X8, SVGA3DBLOCKDESC_DEPTH, + {SVGA3D_Z_D24X8, SVGA3DBLOCKDESC_DEPTH_UNORM, {1, 1, 1}, 4, 4, - 32, {{0}, {0}, {24}, {0}}, - {{0}, {24}, {0}, {0}}}, + {{0}, {0}, {24}, {0}}, + {{0}, {0}, {8}, {0}}}, - {SVGA3D_V16U16, SVGA3DBLOCKDESC_UV, + {SVGA3D_V16U16, SVGA3DBLOCKDESC_UV_SNORM, {1, 1, 1}, 4, 4, - 32, {{16}, {16}, {0}, {0}}, - {{16}, {0}, {0}, {0}}}, + {{0}, {16}, {16}, {0}}, + {{0}, {16}, {0}, {0}}}, - {SVGA3D_G16R16, SVGA3DBLOCKDESC_RG, + {SVGA3D_G16R16, SVGA3DBLOCKDESC_RG_UNORM, {1, 1, 1}, 4, 4, - 32, {{0}, {16}, {16}, {0}}, - {{0}, {0}, {16}, {0}}}, + {{0}, {16}, {16}, {0}}, + {{0}, {16}, {0}, {0}}}, - {SVGA3D_A16B16G16R16, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_A16B16G16R16, SVGA3DBLOCKDESC_RGBA_UNORM, {1, 1, 1}, 8, 8, - 64, {{16}, {16}, {16}, {16}}, + {{16}, {16}, {16}, {16}}, {{32}, {16}, {0}, {48}}}, {SVGA3D_UYVY, SVGA3DBLOCKDESC_YUV, - {1, 1, 1}, 2, 2, - 16, {{8}, {0}, {8}, {0}}, + {2, 1, 1}, 4, 4, + {{8}, {0}, {8}, {0}}, {{0}, {0}, {8}, {0}}}, {SVGA3D_YUY2, SVGA3DBLOCKDESC_YUV, - {1, 1, 1}, 2, 2, - 16, {{8}, {0}, {8}, {0}}, + {2, 1, 1}, 4, 4, + {{8}, {0}, {8}, {0}}, {{8}, {0}, {0}, {0}}}, {SVGA3D_NV12, SVGA3DBLOCKDESC_NV12, {2, 2, 1}, 6, 2, - 48, {{0}, {0}, {48}, {0}}, + {{0}, {0}, {48}, {0}}, {{0}, {0}, {0}, {0}}}, {SVGA3D_AYUV, SVGA3DBLOCKDESC_AYUV, {1, 1, 1}, 4, 4, - 32, {{8}, {8}, {8}, {8}}, + {{8}, {8}, {8}, {8}}, {{0}, {8}, {16}, {24}}}, - {SVGA3D_R32G32B32A32_TYPELESS, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_R32G32B32A32_TYPELESS, SVGA3DBLOCKDESC_TYPELESS, {1, 1, 1}, 16, 16, - 128, {{32}, {32}, {32}, {32}}, + {{32}, {32}, {32}, {32}}, {{64}, {32}, {0}, {96}}}, - {SVGA3D_R32G32B32A32_UINT, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_R32G32B32A32_UINT, SVGA3DBLOCKDESC_RGBA_UINT, {1, 1, 1}, 16, 16, - 128, {{32}, {32}, {32}, {32}}, + {{32}, {32}, {32}, {32}}, {{64}, {32}, {0}, {96}}}, - {SVGA3D_R32G32B32A32_SINT, SVGA3DBLOCKDESC_UVWQ, + {SVGA3D_R32G32B32A32_SINT, SVGA3DBLOCKDESC_RGBA_SINT, {1, 1, 1}, 16, 16, - 128, {{32}, {32}, {32}, {32}}, + {{32}, {32}, {32}, {32}}, {{64}, {32}, {0}, {96}}}, - {SVGA3D_R32G32B32_TYPELESS, SVGA3DBLOCKDESC_RGB, + {SVGA3D_R32G32B32_TYPELESS, SVGA3DBLOCKDESC_TYPELESS, {1, 1, 1}, 12, 12, - 96, {{32}, {32}, {32}, {0}}, + {{32}, {32}, {32}, {0}}, {{64}, {32}, {0}, {0}}}, {SVGA3D_R32G32B32_FLOAT, SVGA3DBLOCKDESC_RGB_FP, {1, 1, 1}, 12, 12, - 96, {{32}, {32}, {32}, {0}}, + {{32}, {32}, {32}, {0}}, {{64}, {32}, {0}, {0}}}, - {SVGA3D_R32G32B32_UINT, SVGA3DBLOCKDESC_RGB, + {SVGA3D_R32G32B32_UINT, SVGA3DBLOCKDESC_RGB_UINT, {1, 1, 1}, 12, 12, - 96, {{32}, {32}, {32}, {0}}, + {{32}, {32}, {32}, {0}}, {{64}, {32}, {0}, {0}}}, - {SVGA3D_R32G32B32_SINT, SVGA3DBLOCKDESC_UVW, + {SVGA3D_R32G32B32_SINT, SVGA3DBLOCKDESC_RGB_SINT, {1, 1, 1}, 12, 12, - 96, {{32}, {32}, {32}, {0}}, + {{32}, {32}, {32}, {0}}, {{64}, {32}, {0}, {0}}}, - {SVGA3D_R16G16B16A16_TYPELESS, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_R16G16B16A16_TYPELESS, SVGA3DBLOCKDESC_TYPELESS, {1, 1, 1}, 8, 8, - 64, {{16}, {16}, {16}, {16}}, + {{16}, {16}, {16}, {16}}, {{32}, {16}, {0}, {48}}}, - {SVGA3D_R16G16B16A16_UINT, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_R16G16B16A16_UINT, SVGA3DBLOCKDESC_RGBA_UINT, {1, 1, 1}, 8, 8, - 64, {{16}, {16}, {16}, {16}}, + {{16}, {16}, {16}, {16}}, {{32}, {16}, {0}, {48}}}, - {SVGA3D_R16G16B16A16_SNORM, SVGA3DBLOCKDESC_UVWQ, + {SVGA3D_R16G16B16A16_SNORM, SVGA3DBLOCKDESC_RGBA_SNORM, {1, 1, 1}, 8, 8, - 64, {{16}, {16}, {16}, {16}}, + {{16}, {16}, {16}, {16}}, {{32}, {16}, {0}, {48}}}, - {SVGA3D_R16G16B16A16_SINT, SVGA3DBLOCKDESC_UVWQ, + {SVGA3D_R16G16B16A16_SINT, SVGA3DBLOCKDESC_RGBA_SINT, {1, 1, 1}, 8, 8, - 64, {{16}, {16}, {16}, {16}}, + {{16}, {16}, {16}, {16}}, {{32}, {16}, {0}, {48}}}, - {SVGA3D_R32G32_TYPELESS, SVGA3DBLOCKDESC_RG, + {SVGA3D_R32G32_TYPELESS, SVGA3DBLOCKDESC_TYPELESS, {1, 1, 1}, 8, 8, - 64, {{0}, {32}, {32}, {0}}, + {{0}, {32}, {32}, {0}}, {{0}, {32}, {0}, {0}}}, - {SVGA3D_R32G32_UINT, SVGA3DBLOCKDESC_RG, + {SVGA3D_R32G32_UINT, SVGA3DBLOCKDESC_RG_UINT, {1, 1, 1}, 8, 8, - 64, {{0}, {32}, {32}, {0}}, + {{0}, {32}, {32}, {0}}, {{0}, {32}, {0}, {0}}}, - {SVGA3D_R32G32_SINT, SVGA3DBLOCKDESC_UV, + {SVGA3D_R32G32_SINT, SVGA3DBLOCKDESC_RG_SINT, {1, 1, 1}, 8, 8, - 64, {{0}, {32}, {32}, {0}}, + {{0}, {32}, {32}, {0}}, {{0}, {32}, {0}, {0}}}, - {SVGA3D_R32G8X24_TYPELESS, SVGA3DBLOCKDESC_RG, + {SVGA3D_R32G8X24_TYPELESS, SVGA3DBLOCKDESC_TYPELESS, {1, 1, 1}, 8, 8, - 64, {{0}, {8}, {32}, {0}}, + {{0}, {8}, {32}, {0}}, {{0}, {32}, {0}, {0}}}, {SVGA3D_D32_FLOAT_S8X24_UINT, SVGA3DBLOCKDESC_DS, {1, 1, 1}, 8, 8, - 64, {{0}, {8}, {32}, {0}}, + {{0}, {8}, {32}, {0}}, {{0}, {32}, {0}, {0}}}, - {SVGA3D_R32_FLOAT_X8X24_TYPELESS, SVGA3DBLOCKDESC_R_FP, + {SVGA3D_R32_FLOAT_X8X24, SVGA3DBLOCKDESC_R_FP, {1, 1, 1}, 8, 8, - 64, {{0}, {0}, {32}, {0}}, + {{0}, {0}, {32}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_X32_TYPELESS_G8X24_UINT, SVGA3DBLOCKDESC_GREEN, + {SVGA3D_X32_G8X24_UINT, SVGA3DBLOCKDESC_G_UINT, {1, 1, 1}, 8, 8, - 64, {{0}, {8}, {0}, {0}}, + {{0}, {8}, {0}, {0}}, {{0}, {32}, {0}, {0}}}, - {SVGA3D_R10G10B10A2_TYPELESS, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_R10G10B10A2_TYPELESS, SVGA3DBLOCKDESC_TYPELESS, {1, 1, 1}, 4, 4, - 32, {{10}, {10}, {10}, {2}}, - {{0}, {10}, {20}, {30}}}, + {{10}, {10}, {10}, {2}}, + {{20}, {10}, {0}, {30}}}, - {SVGA3D_R10G10B10A2_UINT, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_R10G10B10A2_UINT, SVGA3DBLOCKDESC_RGBA_UINT, {1, 1, 1}, 4, 4, - 32, {{10}, {10}, {10}, {2}}, - {{0}, {10}, {20}, {30}}}, + {{10}, {10}, {10}, {2}}, + {{20}, {10}, {0}, {30}}}, {SVGA3D_R11G11B10_FLOAT, SVGA3DBLOCKDESC_RGB_FP, {1, 1, 1}, 4, 4, - 32, {{10}, {11}, {11}, {0}}, - {{0}, {10}, {21}, {0}}}, + {{10}, {11}, {11}, {0}}, + {{22}, {11}, {0}, {0}}}, - {SVGA3D_R8G8B8A8_TYPELESS, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_R8G8B8A8_TYPELESS, SVGA3DBLOCKDESC_TYPELESS, {1, 1, 1}, 4, 4, - 32, {{8}, {8}, {8}, {8}}, + {{8}, {8}, {8}, {8}}, {{16}, {8}, {0}, {24}}}, - {SVGA3D_R8G8B8A8_UNORM, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_R8G8B8A8_UNORM, SVGA3DBLOCKDESC_RGBA_UNORM, {1, 1, 1}, 4, 4, - 32, {{8}, {8}, {8}, {8}}, + {{8}, {8}, {8}, {8}}, {{16}, {8}, {0}, {24}}}, - {SVGA3D_R8G8B8A8_UNORM_SRGB, SVGA3DBLOCKDESC_RGBA_SRGB, + {SVGA3D_R8G8B8A8_UNORM_SRGB, SVGA3DBLOCKDESC_RGBA_UNORM_SRGB, {1, 1, 1}, 4, 4, - 32, {{8}, {8}, {8}, {8}}, + {{8}, {8}, {8}, {8}}, {{16}, {8}, {0}, {24}}}, - {SVGA3D_R8G8B8A8_UINT, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_R8G8B8A8_UINT, SVGA3DBLOCKDESC_RGBA_UINT, {1, 1, 1}, 4, 4, - 32, {{8}, {8}, {8}, {8}}, + {{8}, {8}, {8}, {8}}, {{16}, {8}, {0}, {24}}}, - {SVGA3D_R8G8B8A8_SINT, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_R8G8B8A8_SINT, SVGA3DBLOCKDESC_RGBA_SINT, {1, 1, 1}, 4, 4, - 32, {{8}, {8}, {8}, {8}}, + {{8}, {8}, {8}, {8}}, {{16}, {8}, {0}, {24}}}, - {SVGA3D_R16G16_TYPELESS, SVGA3DBLOCKDESC_RG, + {SVGA3D_R16G16_TYPELESS, SVGA3DBLOCKDESC_TYPELESS, {1, 1, 1}, 4, 4, - 32, {{0}, {16}, {16}, {0}}, + {{0}, {16}, {16}, {0}}, {{0}, {16}, {0}, {0}}}, - {SVGA3D_R16G16_UINT, SVGA3DBLOCKDESC_RG_FP, + {SVGA3D_R16G16_UINT, SVGA3DBLOCKDESC_RG_UINT, {1, 1, 1}, 4, 4, - 32, {{0}, {16}, {16}, {0}}, + {{0}, {16}, {16}, {0}}, {{0}, {16}, {0}, {0}}}, - {SVGA3D_R16G16_SINT, SVGA3DBLOCKDESC_UV, + {SVGA3D_R16G16_SINT, SVGA3DBLOCKDESC_RG_SINT, {1, 1, 1}, 4, 4, - 32, {{0}, {16}, {16}, {0}}, + {{0}, {16}, {16}, {0}}, {{0}, {16}, {0}, {0}}}, - {SVGA3D_R32_TYPELESS, SVGA3DBLOCKDESC_RED, + {SVGA3D_R32_TYPELESS, SVGA3DBLOCKDESC_TYPELESS, {1, 1, 1}, 4, 4, - 32, {{0}, {0}, {32}, {0}}, + {{0}, {0}, {32}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_D32_FLOAT, SVGA3DBLOCKDESC_DEPTH, + {SVGA3D_D32_FLOAT, SVGA3DBLOCKDESC_DEPTH_FP, {1, 1, 1}, 4, 4, - 32, {{0}, {0}, {32}, {0}}, + {{0}, {0}, {32}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_R32_UINT, SVGA3DBLOCKDESC_RED, + {SVGA3D_R32_UINT, SVGA3DBLOCKDESC_R_UINT, {1, 1, 1}, 4, 4, - 32, {{0}, {0}, {32}, {0}}, + {{0}, {0}, {32}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_R32_SINT, SVGA3DBLOCKDESC_RED, + {SVGA3D_R32_SINT, SVGA3DBLOCKDESC_R_SINT, {1, 1, 1}, 4, 4, - 32, {{0}, {0}, {32}, {0}}, + {{0}, {0}, {32}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_R24G8_TYPELESS, SVGA3DBLOCKDESC_RG, + {SVGA3D_R24G8_TYPELESS, SVGA3DBLOCKDESC_TYPELESS, {1, 1, 1}, 4, 4, - 32, {{0}, {8}, {24}, {0}}, + {{0}, {8}, {24}, {0}}, {{0}, {24}, {0}, {0}}}, - {SVGA3D_D24_UNORM_S8_UINT, SVGA3DBLOCKDESC_DS, + {SVGA3D_D24_UNORM_S8_UINT, SVGA3DBLOCKDESC_DS_UNORM, {1, 1, 1}, 4, 4, - 32, {{0}, {8}, {24}, {0}}, + {{0}, {8}, {24}, {0}}, {{0}, {24}, {0}, {0}}}, - {SVGA3D_R24_UNORM_X8_TYPELESS, SVGA3DBLOCKDESC_RED, + {SVGA3D_R24_UNORM_X8, SVGA3DBLOCKDESC_R_UNORM, {1, 1, 1}, 4, 4, - 32, {{0}, {0}, {24}, {0}}, + {{0}, {0}, {24}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_X24_TYPELESS_G8_UINT, SVGA3DBLOCKDESC_GREEN, + {SVGA3D_X24_G8_UINT, SVGA3DBLOCKDESC_G_UINT, {1, 1, 1}, 4, 4, - 32, {{0}, {8}, {0}, {0}}, + {{0}, {8}, {0}, {0}}, {{0}, {24}, {0}, {0}}}, - {SVGA3D_R8G8_TYPELESS, SVGA3DBLOCKDESC_RG, + {SVGA3D_R8G8_TYPELESS, SVGA3DBLOCKDESC_TYPELESS, {1, 1, 1}, 2, 2, - 16, {{0}, {8}, {8}, {0}}, + {{0}, {8}, {8}, {0}}, {{0}, {8}, {0}, {0}}}, - {SVGA3D_R8G8_UNORM, SVGA3DBLOCKDESC_RG, + {SVGA3D_R8G8_UNORM, SVGA3DBLOCKDESC_RG_UNORM, {1, 1, 1}, 2, 2, - 16, {{0}, {8}, {8}, {0}}, + {{0}, {8}, {8}, {0}}, {{0}, {8}, {0}, {0}}}, - {SVGA3D_R8G8_UINT, SVGA3DBLOCKDESC_RG, + {SVGA3D_R8G8_UINT, SVGA3DBLOCKDESC_RG_UINT, {1, 1, 1}, 2, 2, - 16, {{0}, {8}, {8}, {0}}, + {{0}, {8}, {8}, {0}}, {{0}, {8}, {0}, {0}}}, - {SVGA3D_R8G8_SINT, SVGA3DBLOCKDESC_UV, + {SVGA3D_R8G8_SINT, SVGA3DBLOCKDESC_RG_SINT, {1, 1, 1}, 2, 2, - 16, {{0}, {8}, {8}, {0}}, + {{0}, {8}, {8}, {0}}, {{0}, {8}, {0}, {0}}}, - {SVGA3D_R16_TYPELESS, SVGA3DBLOCKDESC_RED, + {SVGA3D_R16_TYPELESS, SVGA3DBLOCKDESC_TYPELESS, {1, 1, 1}, 2, 2, - 16, {{0}, {0}, {16}, {0}}, + {{0}, {0}, {16}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_R16_UNORM, SVGA3DBLOCKDESC_RED, + {SVGA3D_R16_UNORM, SVGA3DBLOCKDESC_R_UNORM, {1, 1, 1}, 2, 2, - 16, {{0}, {0}, {16}, {0}}, + {{0}, {0}, {16}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_R16_UINT, SVGA3DBLOCKDESC_RED, + {SVGA3D_R16_UINT, SVGA3DBLOCKDESC_R_UINT, {1, 1, 1}, 2, 2, - 16, {{0}, {0}, {16}, {0}}, + {{0}, {0}, {16}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_R16_SNORM, SVGA3DBLOCKDESC_U, + {SVGA3D_R16_SNORM, SVGA3DBLOCKDESC_R_SNORM, {1, 1, 1}, 2, 2, - 16, {{0}, {0}, {16}, {0}}, + {{0}, {0}, {16}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_R16_SINT, SVGA3DBLOCKDESC_U, + {SVGA3D_R16_SINT, SVGA3DBLOCKDESC_R_SINT, {1, 1, 1}, 2, 2, - 16, {{0}, {0}, {16}, {0}}, + {{0}, {0}, {16}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_R8_TYPELESS, SVGA3DBLOCKDESC_RED, + {SVGA3D_R8_TYPELESS, SVGA3DBLOCKDESC_TYPELESS, {1, 1, 1}, 1, 1, - 8, {{0}, {0}, {8}, {0}}, + {{0}, {0}, {8}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_R8_UNORM, SVGA3DBLOCKDESC_RED, + {SVGA3D_R8_UNORM, SVGA3DBLOCKDESC_R_UNORM, {1, 1, 1}, 1, 1, - 8, {{0}, {0}, {8}, {0}}, + {{0}, {0}, {8}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_R8_UINT, SVGA3DBLOCKDESC_RED, + {SVGA3D_R8_UINT, SVGA3DBLOCKDESC_R_UINT, {1, 1, 1}, 1, 1, - 8, {{0}, {0}, {8}, {0}}, + {{0}, {0}, {8}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_R8_SNORM, SVGA3DBLOCKDESC_U, + {SVGA3D_R8_SNORM, SVGA3DBLOCKDESC_R_SNORM, {1, 1, 1}, 1, 1, - 8, {{0}, {0}, {8}, {0}}, + {{0}, {0}, {8}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_R8_SINT, SVGA3DBLOCKDESC_U, + {SVGA3D_R8_SINT, SVGA3DBLOCKDESC_R_SINT, {1, 1, 1}, 1, 1, - 8, {{0}, {0}, {8}, {0}}, + {{0}, {0}, {8}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_P8, SVGA3DBLOCKDESC_RED, + {SVGA3D_P8, SVGA3DBLOCKDESC_NONE, {1, 1, 1}, 1, 1, - 8, {{0}, {0}, {8}, {0}}, + {{0}, {0}, {8}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_R9G9B9E5_SHAREDEXP, SVGA3DBLOCKDESC_RGBE, + {SVGA3D_R9G9B9E5_SHAREDEXP, SVGA3DBLOCKDESC_RGB_EXP, {1, 1, 1}, 4, 4, - 32, {{9}, {9}, {9}, {5}}, + {{9}, {9}, {9}, {5}}, {{18}, {9}, {0}, {27}}}, - {SVGA3D_R8G8_B8G8_UNORM, SVGA3DBLOCKDESC_RG, - {1, 1, 1}, 2, 2, - 16, {{0}, {8}, {8}, {0}}, - {{0}, {8}, {0}, {0}}}, + {SVGA3D_R8G8_B8G8_UNORM, SVGA3DBLOCKDESC_NONE, + {2, 1, 1}, 4, 4, + {{0}, {8}, {8}, {0}}, + {{0}, {0}, {8}, {0}}}, - {SVGA3D_G8R8_G8B8_UNORM, SVGA3DBLOCKDESC_RG, - {1, 1, 1}, 2, 2, - 16, {{0}, {8}, {8}, {0}}, + {SVGA3D_G8R8_G8B8_UNORM, SVGA3DBLOCKDESC_NONE, + {2, 1, 1}, 4, 4, + {{0}, {8}, {8}, {0}}, {{0}, {8}, {0}, {0}}}, - {SVGA3D_BC1_TYPELESS, SVGA3DBLOCKDESC_COMPRESSED, + {SVGA3D_BC1_TYPELESS, SVGA3DBLOCKDESC_BC1_COMP_TYPELESS, {4, 4, 1}, 8, 8, - 64, {{0}, {0}, {64}, {0}}, + {{0}, {0}, {64}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_BC1_UNORM_SRGB, SVGA3DBLOCKDESC_COMPRESSED_SRGB, + {SVGA3D_BC1_UNORM_SRGB, SVGA3DBLOCKDESC_BC1_COMP_UNORM_SRGB, {4, 4, 1}, 8, 8, - 64, {{0}, {0}, {64}, {0}}, + {{0}, {0}, {64}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_BC2_TYPELESS, SVGA3DBLOCKDESC_COMPRESSED, + {SVGA3D_BC2_TYPELESS, SVGA3DBLOCKDESC_BC2_COMP_TYPELESS, {4, 4, 1}, 16, 16, - 128, {{0}, {0}, {128}, {0}}, + {{0}, {0}, {128}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_BC2_UNORM_SRGB, SVGA3DBLOCKDESC_COMPRESSED_SRGB, + {SVGA3D_BC2_UNORM_SRGB, SVGA3DBLOCKDESC_BC2_COMP_UNORM_SRGB, {4, 4, 1}, 16, 16, - 128, {{0}, {0}, {128}, {0}}, + {{0}, {0}, {128}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_BC3_TYPELESS, SVGA3DBLOCKDESC_COMPRESSED, + {SVGA3D_BC3_TYPELESS, SVGA3DBLOCKDESC_BC3_COMP_TYPELESS, {4, 4, 1}, 16, 16, - 128, {{0}, {0}, {128}, {0}}, + {{0}, {0}, {128}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_BC3_UNORM_SRGB, SVGA3DBLOCKDESC_COMPRESSED_SRGB, + {SVGA3D_BC3_UNORM_SRGB, SVGA3DBLOCKDESC_BC3_COMP_UNORM_SRGB, {4, 4, 1}, 16, 16, - 128, {{0}, {0}, {128}, {0}}, + {{0}, {0}, {128}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_BC4_TYPELESS, SVGA3DBLOCKDESC_COMPRESSED, + {SVGA3D_BC4_TYPELESS, SVGA3DBLOCKDESC_BC4_COMP_TYPELESS, {4, 4, 1}, 8, 8, - 64, {{0}, {0}, {64}, {0}}, + {{0}, {0}, {64}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_ATI1, SVGA3DBLOCKDESC_COMPRESSED, + {SVGA3D_ATI1, SVGA3DBLOCKDESC_BC4_COMP_UNORM, {4, 4, 1}, 8, 8, - 64, {{0}, {0}, {64}, {0}}, + {{0}, {0}, {64}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_BC4_SNORM, SVGA3DBLOCKDESC_COMPRESSED, + {SVGA3D_BC4_SNORM, SVGA3DBLOCKDESC_BC4_COMP_SNORM, {4, 4, 1}, 8, 8, - 64, {{0}, {0}, {64}, {0}}, + {{0}, {0}, {64}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_BC5_TYPELESS, SVGA3DBLOCKDESC_COMPRESSED, + {SVGA3D_BC5_TYPELESS, SVGA3DBLOCKDESC_BC5_COMP_TYPELESS, {4, 4, 1}, 16, 16, - 128, {{0}, {0}, {128}, {0}}, + {{0}, {0}, {128}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_ATI2, SVGA3DBLOCKDESC_COMPRESSED, + {SVGA3D_ATI2, SVGA3DBLOCKDESC_BC5_COMP_UNORM, {4, 4, 1}, 16, 16, - 128, {{0}, {0}, {128}, {0}}, + {{0}, {0}, {128}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_BC5_SNORM, SVGA3DBLOCKDESC_COMPRESSED, + {SVGA3D_BC5_SNORM, SVGA3DBLOCKDESC_BC5_COMP_SNORM, {4, 4, 1}, 16, 16, - 128, {{0}, {0}, {128}, {0}}, + {{0}, {0}, {128}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_R10G10B10_XR_BIAS_A2_UNORM, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_R10G10B10_XR_BIAS_A2_UNORM, SVGA3DBLOCKDESC_RGBA_UNORM, {1, 1, 1}, 4, 4, - 32, {{10}, {10}, {10}, {2}}, - {{0}, {10}, {20}, {30}}}, + {{10}, {10}, {10}, {2}}, + {{20}, {10}, {0}, {30}}}, - {SVGA3D_B8G8R8A8_TYPELESS, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_B8G8R8A8_TYPELESS, SVGA3DBLOCKDESC_TYPELESS, {1, 1, 1}, 4, 4, - 32, {{8}, {8}, {8}, {8}}, + {{8}, {8}, {8}, {8}}, {{0}, {8}, {16}, {24}}}, - {SVGA3D_B8G8R8A8_UNORM_SRGB, SVGA3DBLOCKDESC_RGBA_SRGB, + {SVGA3D_B8G8R8A8_UNORM_SRGB, SVGA3DBLOCKDESC_RGBA_UNORM_SRGB, {1, 1, 1}, 4, 4, - 32, {{8}, {8}, {8}, {8}}, + {{8}, {8}, {8}, {8}}, {{0}, {8}, {16}, {24}}}, - {SVGA3D_B8G8R8X8_TYPELESS, SVGA3DBLOCKDESC_RGB, + {SVGA3D_B8G8R8X8_TYPELESS, SVGA3DBLOCKDESC_TYPELESS, {1, 1, 1}, 4, 4, - 24, {{8}, {8}, {8}, {0}}, + {{8}, {8}, {8}, {0}}, {{0}, {8}, {16}, {24}}}, - {SVGA3D_B8G8R8X8_UNORM_SRGB, SVGA3DBLOCKDESC_RGB_SRGB, + {SVGA3D_B8G8R8X8_UNORM_SRGB, SVGA3DBLOCKDESC_RGB_UNORM_SRGB, {1, 1, 1}, 4, 4, - 24, {{8}, {8}, {8}, {0}}, + {{8}, {8}, {8}, {0}}, {{0}, {8}, {16}, {24}}}, - {SVGA3D_Z_DF16, SVGA3DBLOCKDESC_DEPTH, + {SVGA3D_Z_DF16, SVGA3DBLOCKDESC_DEPTH_UNORM, {1, 1, 1}, 2, 2, - 16, {{0}, {0}, {16}, {0}}, + {{0}, {0}, {16}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_Z_DF24, SVGA3DBLOCKDESC_DEPTH, + {SVGA3D_Z_DF24, SVGA3DBLOCKDESC_DEPTH_UNORM, {1, 1, 1}, 4, 4, - 32, {{0}, {8}, {24}, {0}}, - {{0}, {24}, {0}, {0}}}, + {{0}, {0}, {24}, {0}}, + {{0}, {0}, {8}, {0}}}, - {SVGA3D_Z_D24S8_INT, SVGA3DBLOCKDESC_DS, + {SVGA3D_Z_D24S8_INT, SVGA3DBLOCKDESC_DS_UNORM, {1, 1, 1}, 4, 4, - 32, {{0}, {8}, {24}, {0}}, - {{0}, {24}, {0}, {0}}}, + {{0}, {8}, {24}, {0}}, + {{0}, {0}, {8}, {0}}}, {SVGA3D_YV12, SVGA3DBLOCKDESC_YV12, {2, 2, 1}, 6, 2, - 48, {{0}, {0}, {48}, {0}}, + {{0}, {0}, {48}, {0}}, {{0}, {0}, {0}, {0}}}, {SVGA3D_R32G32B32A32_FLOAT, SVGA3DBLOCKDESC_RGBA_FP, {1, 1, 1}, 16, 16, - 128, {{32}, {32}, {32}, {32}}, + {{32}, {32}, {32}, {32}}, {{64}, {32}, {0}, {96}}}, {SVGA3D_R16G16B16A16_FLOAT, SVGA3DBLOCKDESC_RGBA_FP, {1, 1, 1}, 8, 8, - 64, {{16}, {16}, {16}, {16}}, + {{16}, {16}, {16}, {16}}, {{32}, {16}, {0}, {48}}}, - {SVGA3D_R16G16B16A16_UNORM, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_R16G16B16A16_UNORM, SVGA3DBLOCKDESC_RGBA_UNORM, {1, 1, 1}, 8, 8, - 64, {{16}, {16}, {16}, {16}}, + {{16}, {16}, {16}, {16}}, {{32}, {16}, {0}, {48}}}, {SVGA3D_R32G32_FLOAT, SVGA3DBLOCKDESC_RG_FP, {1, 1, 1}, 8, 8, - 64, {{0}, {32}, {32}, {0}}, + {{0}, {32}, {32}, {0}}, {{0}, {32}, {0}, {0}}}, - {SVGA3D_R10G10B10A2_UNORM, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_R10G10B10A2_UNORM, SVGA3DBLOCKDESC_RGBA_UNORM, {1, 1, 1}, 4, 4, - 32, {{10}, {10}, {10}, {2}}, - {{0}, {10}, {20}, {30}}}, + {{10}, {10}, {10}, {2}}, + {{20}, {10}, {0}, {30}}}, - {SVGA3D_R8G8B8A8_SNORM, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_R8G8B8A8_SNORM, SVGA3DBLOCKDESC_RGBA_SNORM, {1, 1, 1}, 4, 4, - 32, {{8}, {8}, {8}, {8}}, - {{24}, {16}, {8}, {0}}}, + {{8}, {8}, {8}, {8}}, + {{16}, {8}, {0}, {24}}}, {SVGA3D_R16G16_FLOAT, SVGA3DBLOCKDESC_RG_FP, {1, 1, 1}, 4, 4, - 32, {{0}, {16}, {16}, {0}}, + {{0}, {16}, {16}, {0}}, {{0}, {16}, {0}, {0}}}, - {SVGA3D_R16G16_UNORM, SVGA3DBLOCKDESC_RG, + {SVGA3D_R16G16_UNORM, SVGA3DBLOCKDESC_RG_UNORM, {1, 1, 1}, 4, 4, - 32, {{0}, {16}, {16}, {0}}, - {{0}, {0}, {16}, {0}}}, + {{0}, {16}, {16}, {0}}, + {{0}, {16}, {0}, {0}}}, - {SVGA3D_R16G16_SNORM, SVGA3DBLOCKDESC_RG, + {SVGA3D_R16G16_SNORM, SVGA3DBLOCKDESC_RG_SNORM, {1, 1, 1}, 4, 4, - 32, {{16}, {16}, {0}, {0}}, - {{16}, {0}, {0}, {0}}}, + {{0}, {16}, {16}, {0}}, + {{0}, {16}, {0}, {0}}}, {SVGA3D_R32_FLOAT, SVGA3DBLOCKDESC_R_FP, {1, 1, 1}, 4, 4, - 32, {{0}, {0}, {32}, {0}}, + {{0}, {0}, {32}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_R8G8_SNORM, SVGA3DBLOCKDESC_RG, + {SVGA3D_R8G8_SNORM, SVGA3DBLOCKDESC_RG_SNORM, {1, 1, 1}, 2, 2, - 16, {{8}, {8}, {0}, {0}}, - {{8}, {0}, {0}, {0}}}, + {{0}, {8}, {8}, {0}}, + {{0}, {8}, {0}, {0}}}, {SVGA3D_R16_FLOAT, SVGA3DBLOCKDESC_R_FP, {1, 1, 1}, 2, 2, - 16, {{0}, {0}, {16}, {0}}, + {{0}, {0}, {16}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_D16_UNORM, SVGA3DBLOCKDESC_DEPTH, + {SVGA3D_D16_UNORM, SVGA3DBLOCKDESC_DEPTH_UNORM, {1, 1, 1}, 2, 2, - 16, {{0}, {0}, {16}, {0}}, + {{0}, {0}, {16}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_A8_UNORM, SVGA3DBLOCKDESC_ALPHA, + {SVGA3D_A8_UNORM, SVGA3DBLOCKDESC_A_UNORM, {1, 1, 1}, 1, 1, - 8, {{0}, {0}, {0}, {8}}, + {{0}, {0}, {0}, {8}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_BC1_UNORM, SVGA3DBLOCKDESC_COMPRESSED, + {SVGA3D_BC1_UNORM, SVGA3DBLOCKDESC_BC1_COMP_UNORM, {4, 4, 1}, 8, 8, - 64, {{0}, {0}, {64}, {0}}, + {{0}, {0}, {64}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_BC2_UNORM, SVGA3DBLOCKDESC_COMPRESSED, + {SVGA3D_BC2_UNORM, SVGA3DBLOCKDESC_BC2_COMP_UNORM, {4, 4, 1}, 16, 16, - 128, {{0}, {0}, {128}, {0}}, + {{0}, {0}, {128}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_BC3_UNORM, SVGA3DBLOCKDESC_COMPRESSED, + {SVGA3D_BC3_UNORM, SVGA3DBLOCKDESC_BC3_COMP_UNORM, {4, 4, 1}, 16, 16, - 128, {{0}, {0}, {128}, {0}}, + {{0}, {0}, {128}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_B5G6R5_UNORM, SVGA3DBLOCKDESC_RGB, + {SVGA3D_B5G6R5_UNORM, SVGA3DBLOCKDESC_RGB_UNORM, {1, 1, 1}, 2, 2, - 16, {{5}, {6}, {5}, {0}}, + {{5}, {6}, {5}, {0}}, {{0}, {5}, {11}, {0}}}, - {SVGA3D_B5G5R5A1_UNORM, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_B5G5R5A1_UNORM, SVGA3DBLOCKDESC_RGBA_UNORM, {1, 1, 1}, 2, 2, - 16, {{5}, {5}, {5}, {1}}, + {{5}, {5}, {5}, {1}}, {{0}, {5}, {10}, {15}}}, - {SVGA3D_B8G8R8A8_UNORM, SVGA3DBLOCKDESC_RGBA, + {SVGA3D_B8G8R8A8_UNORM, SVGA3DBLOCKDESC_RGBA_UNORM, {1, 1, 1}, 4, 4, - 32, {{8}, {8}, {8}, {8}}, + {{8}, {8}, {8}, {8}}, {{0}, {8}, {16}, {24}}}, - {SVGA3D_B8G8R8X8_UNORM, SVGA3DBLOCKDESC_RGB, + {SVGA3D_B8G8R8X8_UNORM, SVGA3DBLOCKDESC_RGB_UNORM, {1, 1, 1}, 4, 4, - 24, {{8}, {8}, {8}, {0}}, + {{8}, {8}, {8}, {0}}, {{0}, {8}, {16}, {24}}}, - {SVGA3D_BC4_UNORM, SVGA3DBLOCKDESC_COMPRESSED, + {SVGA3D_BC4_UNORM, SVGA3DBLOCKDESC_BC4_COMP_UNORM, {4, 4, 1}, 8, 8, - 64, {{0}, {0}, {64}, {0}}, + {{0}, {0}, {64}, {0}}, {{0}, {0}, {0}, {0}}}, - {SVGA3D_BC5_UNORM, SVGA3DBLOCKDESC_COMPRESSED, + {SVGA3D_BC5_UNORM, SVGA3DBLOCKDESC_BC5_COMP_UNORM, {4, 4, 1}, 16, 16, - 128, {{0}, {0}, {128}, {0}}, + {{0}, {0}, {128}, {0}}, {{0}, {0}, {0}, {0}}}, - }; static inline u32 clamped_umul32(u32 a, u32 b) @@ -946,6 +1111,10 @@ static inline u32 clamped_umul32(u32 a, u32 b) return (tmp > (uint64_t) ((u32) -1)) ? (u32) -1 : tmp; } +/** + * svga3dsurface_get_desc - Look up the appropriate SVGA3dSurfaceDesc for the + * given format. + */ static inline const struct svga3d_surface_desc * svga3dsurface_get_desc(SVGA3dSurfaceFormat format) { @@ -955,23 +1124,10 @@ svga3dsurface_get_desc(SVGA3dSurfaceFormat format) return &svga3d_surface_descs[SVGA3D_FORMAT_INVALID]; } -/* - *---------------------------------------------------------------------- - * - * svga3dsurface_get_mip_size -- - * - * Given a base level size and the mip level, compute the size of - * the mip level. - * - * Results: - * See above. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- +/** + * svga3dsurface_get_mip_size - Given a base level size and the mip level, + * compute the size of the mip level. */ - static inline surf_size_struct svga3dsurface_get_mip_size(surf_size_struct base_level, u32 mip_level) { @@ -1018,28 +1174,17 @@ svga3dsurface_calculate_pitch(const struct svga3d_surface_desc *desc, return pitch; } -/* - *----------------------------------------------------------------------------- - * - * svga3dsurface_get_image_buffer_size -- - * - * Return the number of bytes of buffer space required to store - * one image of a surface, optionally using the specified pitch. - * - * If pitch is zero, it is assumed that rows are tightly packed. - * - * This function is overflow-safe. If the result would have - * overflowed, instead we return MAX_UINT32. +/** + * svga3dsurface_get_image_buffer_size - Calculates image buffer size. * - * Results: - * Byte count. + * Return the number of bytes of buffer space required to store one image of a + * surface, optionally using the specified pitch. * - * Side effects: - * None. + * If pitch is zero, it is assumed that rows are tightly packed. * - *----------------------------------------------------------------------------- + * This function is overflow-safe. If the result would have overflowed, instead + * we return MAX_UINT32. */ - static inline u32 svga3dsurface_get_image_buffer_size(const struct svga3d_surface_desc *desc, const surf_size_struct *size, @@ -1067,6 +1212,9 @@ svga3dsurface_get_image_buffer_size(const struct svga3d_surface_desc *desc, return total_size; } +/** + * svga3dsurface_get_serialized_size - Get the serialized size for the image. + */ static inline u32 svga3dsurface_get_serialized_size(SVGA3dSurfaceFormat format, surf_size_struct base_level_size, @@ -1206,3 +1354,5 @@ svga3dsurface_is_screen_target_format(SVGA3dSurfaceFormat format) } return svga3dsurface_is_dx_screen_target_format(format); } + +#endif /* _SVGA3D_SURFACEDEFS_H_ */ diff --git a/drivers/gpu/drm/vmwgfx/device_include/svga3d_types.h b/drivers/gpu/drm/vmwgfx/device_include/svga3d_types.h index 27b33ba884309..309904e7cfd37 100644 --- a/drivers/gpu/drm/vmwgfx/device_include/svga3d_types.h +++ b/drivers/gpu/drm/vmwgfx/device_include/svga3d_types.h @@ -44,9 +44,21 @@ #define SVGA3D_INVALID_ID ((uint32)-1) +typedef uint8 SVGABool8; /* 8-bit Bool definition */ typedef uint32 SVGA3dBool; /* 32-bit Bool definition */ typedef uint32 SVGA3dColor; /* a, r, g, b */ +typedef uint32 SVGA3dSurfaceId; + +typedef +#include "vmware_pack_begin.h" +struct { + uint32 numerator; + uint32 denominator; +} +#include "vmware_pack_end.h" +SVGA3dFraction64; + typedef #include "vmware_pack_begin.h" struct SVGA3dCopyRect { @@ -145,7 +157,7 @@ typedef enum SVGA3dSurfaceFormat { SVGA3D_BUMPU8V8 = 20, SVGA3D_BUMPL6V5U5 = 21, SVGA3D_BUMPX8L8V8U8 = 22, - SVGA3D_BUMPL8V8U8 = 23, + SVGA3D_FORMAT_DEAD1 = 23, SVGA3D_ARGB_S10E5 = 24, /* 16-bit floating-point ARGB */ SVGA3D_ARGB_S23E8 = 25, /* 32-bit floating-point ARGB */ @@ -204,8 +216,8 @@ typedef enum SVGA3dSurfaceFormat { SVGA3D_R32G32_SINT = 59, SVGA3D_R32G8X24_TYPELESS = 60, SVGA3D_D32_FLOAT_S8X24_UINT = 61, - SVGA3D_R32_FLOAT_X8X24_TYPELESS = 62, - SVGA3D_X32_TYPELESS_G8X24_UINT = 63, + SVGA3D_R32_FLOAT_X8X24 = 62, + SVGA3D_X32_G8X24_UINT = 63, SVGA3D_R10G10B10A2_TYPELESS = 64, SVGA3D_R10G10B10A2_UINT = 65, SVGA3D_R11G11B10_FLOAT = 66, @@ -223,8 +235,8 @@ typedef enum SVGA3dSurfaceFormat { SVGA3D_R32_SINT = 78, SVGA3D_R24G8_TYPELESS = 79, SVGA3D_D24_UNORM_S8_UINT = 80, - SVGA3D_R24_UNORM_X8_TYPELESS = 81, - SVGA3D_X24_TYPELESS_G8_UINT = 82, + SVGA3D_R24_UNORM_X8 = 81, + SVGA3D_X24_G8_UINT = 82, SVGA3D_R8G8_TYPELESS = 83, SVGA3D_R8G8_UNORM = 84, SVGA3D_R8G8_UINT = 85, @@ -296,92 +308,114 @@ typedef enum SVGA3dSurfaceFormat { SVGA3D_FORMAT_MAX } SVGA3dSurfaceFormat; -typedef enum SVGA3dSurfaceFlags { - SVGA3D_SURFACE_CUBEMAP = (1 << 0), +/* + * SVGA3d Surface Flags -- + */ +#define SVGA3D_SURFACE_CUBEMAP (1 << 0) - /* - * HINT flags are not enforced by the device but are useful for - * performance. - */ - SVGA3D_SURFACE_HINT_STATIC = (1 << 1), - SVGA3D_SURFACE_HINT_DYNAMIC = (1 << 2), - SVGA3D_SURFACE_HINT_INDEXBUFFER = (1 << 3), - SVGA3D_SURFACE_HINT_VERTEXBUFFER = (1 << 4), - SVGA3D_SURFACE_HINT_TEXTURE = (1 << 5), - SVGA3D_SURFACE_HINT_RENDERTARGET = (1 << 6), - SVGA3D_SURFACE_HINT_DEPTHSTENCIL = (1 << 7), - SVGA3D_SURFACE_HINT_WRITEONLY = (1 << 8), - SVGA3D_SURFACE_MASKABLE_ANTIALIAS = (1 << 9), - SVGA3D_SURFACE_AUTOGENMIPMAPS = (1 << 10), - SVGA3D_SURFACE_DECODE_RENDERTARGET = (1 << 11), +/* + * HINT flags are not enforced by the device but are useful for + * performance. + */ +#define SVGA3D_SURFACE_HINT_STATIC (CONST64U(1) << 1) +#define SVGA3D_SURFACE_HINT_DYNAMIC (CONST64U(1) << 2) +#define SVGA3D_SURFACE_HINT_INDEXBUFFER (CONST64U(1) << 3) +#define SVGA3D_SURFACE_HINT_VERTEXBUFFER (CONST64U(1) << 4) +#define SVGA3D_SURFACE_HINT_TEXTURE (CONST64U(1) << 5) +#define SVGA3D_SURFACE_HINT_RENDERTARGET (CONST64U(1) << 6) +#define SVGA3D_SURFACE_HINT_DEPTHSTENCIL (CONST64U(1) << 7) +#define SVGA3D_SURFACE_HINT_WRITEONLY (CONST64U(1) << 8) +#define SVGA3D_SURFACE_MASKABLE_ANTIALIAS (CONST64U(1) << 9) +#define SVGA3D_SURFACE_AUTOGENMIPMAPS (CONST64U(1) << 10) + +#define SVGA3D_SURFACE_DECODE_RENDERTARGET (CONST64U(1) << 11) - /* - * Is this surface using a base-level pitch for it's mob backing? - * - * This flag is not intended to be set by guest-drivers, but is instead - * set by the device when the surface is bound to a mob with a specified - * pitch. - */ - SVGA3D_SURFACE_MOB_PITCH = (1 << 12), +/* + * Is this surface using a base-level pitch for it's mob backing? + * + * This flag is not intended to be set by guest-drivers, but is instead + * set by the device when the surface is bound to a mob with a specified + * pitch. + */ +#define SVGA3D_SURFACE_MOB_PITCH (CONST64U(1) << 12) - SVGA3D_SURFACE_INACTIVE = (1 << 13), - SVGA3D_SURFACE_HINT_RT_LOCKABLE = (1 << 14), - SVGA3D_SURFACE_VOLUME = (1 << 15), +#define SVGA3D_SURFACE_INACTIVE (CONST64U(1) << 13) +#define SVGA3D_SURFACE_HINT_RT_LOCKABLE (CONST64U(1) << 14) +#define SVGA3D_SURFACE_VOLUME (CONST64U(1) << 15) - /* - * Required to be set on a surface to bind it to a screen target. - */ - SVGA3D_SURFACE_SCREENTARGET = (1 << 16), +/* + * Required to be set on a surface to bind it to a screen target. + */ +#define SVGA3D_SURFACE_SCREENTARGET (CONST64U(1) << 16) - /* - * Align images in the guest-backing mob to 16-bytes. - */ - SVGA3D_SURFACE_ALIGN16 = (1 << 17), +/* + * Align images in the guest-backing mob to 16-bytes. + */ +#define SVGA3D_SURFACE_ALIGN16 (CONST64U(1) << 17) - SVGA3D_SURFACE_1D = (1 << 18), - SVGA3D_SURFACE_ARRAY = (1 << 19), +#define SVGA3D_SURFACE_1D (CONST64U(1) << 18) +#define SVGA3D_SURFACE_ARRAY (CONST64U(1) << 19) - /* - * Bind flags. - * These are enforced for any surface defined with DefineGBSurface_v2. - */ - SVGA3D_SURFACE_BIND_VERTEX_BUFFER = (1 << 20), - SVGA3D_SURFACE_BIND_INDEX_BUFFER = (1 << 21), - SVGA3D_SURFACE_BIND_CONSTANT_BUFFER = (1 << 22), - SVGA3D_SURFACE_BIND_SHADER_RESOURCE = (1 << 23), - SVGA3D_SURFACE_BIND_RENDER_TARGET = (1 << 24), - SVGA3D_SURFACE_BIND_DEPTH_STENCIL = (1 << 25), - SVGA3D_SURFACE_BIND_STREAM_OUTPUT = (1 << 26), +/* + * Bind flags. + * These are enforced for any surface defined with DefineGBSurface_v2. + */ +#define SVGA3D_SURFACE_BIND_VERTEX_BUFFER (CONST64U(1) << 20) +#define SVGA3D_SURFACE_BIND_INDEX_BUFFER (CONST64U(1) << 21) +#define SVGA3D_SURFACE_BIND_CONSTANT_BUFFER (CONST64U(1) << 22) +#define SVGA3D_SURFACE_BIND_SHADER_RESOURCE (CONST64U(1) << 23) +#define SVGA3D_SURFACE_BIND_RENDER_TARGET (CONST64U(1) << 24) +#define SVGA3D_SURFACE_BIND_DEPTH_STENCIL (CONST64U(1) << 25) +#define SVGA3D_SURFACE_BIND_STREAM_OUTPUT (CONST64U(1) << 26) - /* - * A note on staging flags: - * - * The STAGING flags notes that the surface will not be used directly by the - * drawing pipeline, i.e. that it will not be bound to any bind point. - * Staging surfaces may be used by copy operations to move data in and out - * of other surfaces. - * - * The HINT_INDIRECT_UPDATE flag suggests that the surface will receive - * updates indirectly, i.e. the surface will not be updated directly, but - * will receive copies from staging surfaces. - */ - SVGA3D_SURFACE_STAGING_UPLOAD = (1 << 27), - SVGA3D_SURFACE_STAGING_DOWNLOAD = (1 << 28), - SVGA3D_SURFACE_HINT_INDIRECT_UPDATE = (1 << 29), +/* + * The STAGING flags notes that the surface will not be used directly by the + * drawing pipeline, i.e. that it will not be bound to any bind point. + * Staging surfaces may be used by copy operations to move data in and out + * of other surfaces. No bind flags may be set on surfaces with this flag. + * + * The HINT_INDIRECT_UPDATE flag suggests that the surface will receive + * updates indirectly, i.e. the surface will not be updated directly, but + * will receive copies from staging surfaces. + */ +#define SVGA3D_SURFACE_STAGING_UPLOAD (CONST64U(1) << 27) +#define SVGA3D_SURFACE_STAGING_DOWNLOAD (CONST64U(1) << 28) +#define SVGA3D_SURFACE_HINT_INDIRECT_UPDATE (CONST64U(1) << 29) - /* - * Setting this flag allow this surface to be used with the - * SVGA_3D_CMD_DX_TRANSFER_FROM_BUFFER command. It is only valid for - * buffer surfaces, an no bind flags are allowed to be set on surfaces - * with this flag. - */ - SVGA3D_SURFACE_TRANSFER_FROM_BUFFER = (1 << 30), +/* + * Setting this flag allow this surface to be used with the + * SVGA_3D_CMD_DX_TRANSFER_FROM_BUFFER command. It is only valid for + * buffer surfaces, and no bind flags are allowed to be set on surfaces + * with this flag. + */ +#define SVGA3D_SURFACE_TRANSFER_FROM_BUFFER (CONST64U(1) << 30) - /* - * Marker for the last defined bit. - */ - SVGA3D_SURFACE_FLAG_MAX = (1 << 31), -} SVGA3dSurfaceFlags; +/* + * Reserved for video operations. + */ +#define SVGA3D_SURFACE_RESERVED1 (CONST64U(1) << 31) + +/* + * Specifies that a surface is multisample, and therefore requires the full + * mob-backing to store all the samples. + */ +#define SVGA3D_SURFACE_MULTISAMPLE (CONST64U(1) << 32) + +#define SVGA3D_SURFACE_FLAG_MAX (CONST64U(1) << 33) + +/* + * Surface flags types: + * + * SVGA3dSurface1Flags: Lower 32-bits of flags. + * SVGA3dSurface2Flags: Upper 32-bits of flags. + * SVGA3dSurfaceAllFlags: Full 64-bits of flags. + */ +typedef uint32 SVGA3dSurface1Flags; +typedef uint32 SVGA3dSurface2Flags; +typedef uint64 SVGA3dSurfaceAllFlags; + +#define SVGA3D_SURFACE_FLAGS1_MASK ((uint64_t)MAX_UINT32) +#define SVGA3D_SURFACE_FLAGS2_MASK (MAX_UINT64 & ~SVGA3D_SURFACE_FLAGS1_MASK) #define SVGA3D_SURFACE_HB_DISALLOWED_MASK \ ( SVGA3D_SURFACE_MOB_PITCH | \ @@ -392,29 +426,41 @@ typedef enum SVGA3dSurfaceFlags { SVGA3D_SURFACE_STAGING_UPLOAD | \ SVGA3D_SURFACE_STAGING_DOWNLOAD | \ SVGA3D_SURFACE_HINT_INDIRECT_UPDATE | \ - SVGA3D_SURFACE_TRANSFER_FROM_BUFFER \ + SVGA3D_SURFACE_TRANSFER_FROM_BUFFER | \ + SVGA3D_SURFACE_MULTISAMPLE \ + ) + +#define SVGA3D_SURFACE_HB_PRESENT_DISALLOWED_MASK \ + ( SVGA3D_SURFACE_1D | \ + SVGA3D_SURFACE_MULTISAMPLE \ ) #define SVGA3D_SURFACE_2D_DISALLOWED_MASK \ ( SVGA3D_SURFACE_CUBEMAP | \ SVGA3D_SURFACE_MASKABLE_ANTIALIAS | \ SVGA3D_SURFACE_AUTOGENMIPMAPS | \ - SVGA3D_SURFACE_DECODE_RENDERTARGET | \ SVGA3D_SURFACE_VOLUME | \ SVGA3D_SURFACE_1D | \ - SVGA3D_SURFACE_ARRAY | \ SVGA3D_SURFACE_BIND_VERTEX_BUFFER | \ SVGA3D_SURFACE_BIND_INDEX_BUFFER | \ SVGA3D_SURFACE_BIND_CONSTANT_BUFFER | \ SVGA3D_SURFACE_BIND_DEPTH_STENCIL | \ SVGA3D_SURFACE_BIND_STREAM_OUTPUT | \ - SVGA3D_SURFACE_TRANSFER_FROM_BUFFER \ + SVGA3D_SURFACE_TRANSFER_FROM_BUFFER | \ + SVGA3D_SURFACE_MULTISAMPLE \ + ) + +#define SVGA3D_SURFACE_BASICOPS_DISALLOWED_MASK \ + ( SVGA3D_SURFACE_CUBEMAP | \ + SVGA3D_SURFACE_AUTOGENMIPMAPS | \ + SVGA3D_SURFACE_VOLUME | \ + SVGA3D_SURFACE_1D | \ + SVGA3D_SURFACE_MULTISAMPLE \ ) #define SVGA3D_SURFACE_SCREENTARGET_DISALLOWED_MASK \ ( SVGA3D_SURFACE_CUBEMAP | \ SVGA3D_SURFACE_AUTOGENMIPMAPS | \ - SVGA3D_SURFACE_DECODE_RENDERTARGET | \ SVGA3D_SURFACE_VOLUME | \ SVGA3D_SURFACE_1D | \ SVGA3D_SURFACE_BIND_VERTEX_BUFFER | \ @@ -426,12 +472,36 @@ typedef enum SVGA3dSurfaceFlags { SVGA3D_SURFACE_STAGING_UPLOAD | \ SVGA3D_SURFACE_STAGING_DOWNLOAD | \ SVGA3D_SURFACE_HINT_INDIRECT_UPDATE | \ - SVGA3D_SURFACE_TRANSFER_FROM_BUFFER \ + SVGA3D_SURFACE_TRANSFER_FROM_BUFFER | \ + SVGA3D_SURFACE_MULTISAMPLE \ + ) + +#define SVGA3D_SURFACE_BUFFER_DISALLOWED_MASK \ + ( SVGA3D_SURFACE_CUBEMAP | \ + SVGA3D_SURFACE_AUTOGENMIPMAPS | \ + SVGA3D_SURFACE_VOLUME | \ + SVGA3D_SURFACE_1D | \ + SVGA3D_SURFACE_MASKABLE_ANTIALIAS | \ + SVGA3D_SURFACE_ARRAY | \ + SVGA3D_SURFACE_MULTISAMPLE | \ + SVGA3D_SURFACE_MOB_PITCH \ + ) + +#define SVGA3D_SURFACE_MULTISAMPLE_DISALLOWED_MASK \ + ( SVGA3D_SURFACE_CUBEMAP | \ + SVGA3D_SURFACE_AUTOGENMIPMAPS | \ + SVGA3D_SURFACE_VOLUME | \ + SVGA3D_SURFACE_1D | \ + SVGA3D_SURFACE_SCREENTARGET | \ + SVGA3D_SURFACE_MOB_PITCH \ ) #define SVGA3D_SURFACE_DX_ONLY_MASK \ ( SVGA3D_SURFACE_BIND_STREAM_OUTPUT | \ + SVGA3D_SURFACE_STAGING_UPLOAD | \ + SVGA3D_SURFACE_STAGING_DOWNLOAD | \ SVGA3D_SURFACE_TRANSFER_FROM_BUFFER \ + ) #define SVGA3D_SURFACE_STAGING_MASK \ ( SVGA3D_SURFACE_STAGING_UPLOAD | \ @@ -487,7 +557,7 @@ typedef enum { /* * Indicates that this format can be converted to any RGB format for which - * SVGA3DFORMAT_OP_MEMBEROFGROUP_ARGB is specified + * SVGA3DFORMAT_OP_MEMBEROFGROUP_ARGB is specified. */ SVGA3DFORMAT_OP_CONVERT_TO_ARGB = 0x00002000, @@ -498,22 +568,22 @@ typedef enum { /* * Indicated that this format can be read as an SRGB texture (meaning that the - * sampler will linearize the looked up data) + * sampler will linearize the looked up data). */ SVGA3DFORMAT_OP_SRGBREAD = 0x00008000, /* - * Indicates that this format can be used in the bumpmap instructions + * Indicates that this format can be used in the bumpmap instructions. */ SVGA3DFORMAT_OP_BUMPMAP = 0x00010000, /* - * Indicates that this format can be sampled by the displacement map sampler + * Indicates that this format can be sampled by the displacement map sampler. */ SVGA3DFORMAT_OP_DMAP = 0x00020000, /* - * Indicates that this format cannot be used with texture filtering + * Indicates that this format cannot be used with texture filtering. */ SVGA3DFORMAT_OP_NOFILTER = 0x00040000, @@ -530,18 +600,18 @@ typedef enum { SVGA3DFORMAT_OP_SRGBWRITE = 0x00100000, /* - * Indicates that this format cannot be used with alpha blending + * Indicates that this format cannot be used with alpha blending. */ SVGA3DFORMAT_OP_NOALPHABLEND = 0x00200000, /* * Indicates that the device can auto-generated sublevels for resources - * of this format + * of this format. */ SVGA3DFORMAT_OP_AUTOGENMIPMAP = 0x00400000, /* - * Indicates that this format can be used by vertex texture sampler + * Indicates that this format can be used by vertex texture sampler. */ SVGA3DFORMAT_OP_VERTEXTEXTURE = 0x00800000, @@ -1501,7 +1571,6 @@ union SVGADXQueryResultUnion { #include "vmware_pack_end.h" SVGADXQueryResultUnion; - typedef enum { SVGA3D_QUERYSTATE_PENDING = 0, /* Query is not finished yet */ SVGA3D_QUERYSTATE_SUCCEEDED = 1, /* Completed successfully */ @@ -1533,9 +1602,9 @@ typedef struct { union { struct { - uint16 function; /* SVGA3dFogFunction */ - uint8 type; /* SVGA3dFogType */ - uint8 base; /* SVGA3dFogBase */ + uint16 function; /* SVGA3dFogFunction */ + uint8 type; /* SVGA3dFogType */ + uint8 base; /* SVGA3dFogBase */ }; uint32 uintValue; }; @@ -1547,17 +1616,25 @@ SVGA3dFogMode; * Uniquely identify one image (a 1D/2D/3D array) from a surface. This * is a surface ID as well as face/mipmap indices. */ - typedef #include "vmware_pack_begin.h" struct SVGA3dSurfaceImageId { - uint32 sid; - uint32 face; - uint32 mipmap; + uint32 sid; + uint32 face; + uint32 mipmap; } #include "vmware_pack_end.h" SVGA3dSurfaceImageId; +typedef +#include "vmware_pack_begin.h" +struct SVGA3dSubSurfaceId { + uint32 sid; + uint32 subResourceId; +} +#include "vmware_pack_end.h" +SVGA3dSubSurfaceId; + typedef #include "vmware_pack_begin.h" struct { @@ -1582,13 +1659,18 @@ typedef enum { SVGA_OTABLE_DX9_MAX = 5, SVGA_OTABLE_DXCONTEXT = 5, - SVGA_OTABLE_MAX = 6 -} SVGAOTableType; + SVGA_OTABLE_DX_MAX = 6, -/* - * Deprecated. - */ -#define SVGA_OTABLE_COUNT 4 + SVGA_OTABLE_RESERVED1 = 6, + SVGA_OTABLE_RESERVED2 = 7, + + /* + * Additions to this table need to be tied to HW-version features and + * checkpointed accordingly. + */ + SVGA_OTABLE_DEVEL_MAX = 8, + SVGA_OTABLE_MAX = 8 +} SVGAOTableType; typedef enum { SVGA_COTABLE_MIN = 0, @@ -1605,7 +1687,7 @@ typedef enum { SVGA_COTABLE_DXSHADER = 10, SVGA_COTABLE_DX10_MAX = 11, SVGA_COTABLE_UAVIEW = 11, - SVGA_COTABLE_MAX + SVGA_COTABLE_MAX = 12, } SVGACOTableType; /* @@ -1626,8 +1708,37 @@ typedef enum SVGAMobFormat { SVGA3D_MOBFMT_PREDX_MAX = 7, SVGA3D_MOBFMT_EMPTY = 7, SVGA3D_MOBFMT_MAX, + + /* + * This isn't actually used by the guest, but is a mob-format used + * internally by the SVGA device (and is therefore not binary compatible). + */ + SVGA3D_MOBFMT_HB, } SVGAMobFormat; #define SVGA3D_MOB_EMPTY_BASE 1 +/* + * Multisample pattern types. + */ + +typedef enum SVGA3dMSPattern { + SVGA3D_MS_PATTERN_NONE = 0, + SVGA3D_MS_PATTERN_MIN = 0, + SVGA3D_MS_PATTERN_STANDARD = 1, + SVGA3D_MS_PATTERN_CENTER = 2, + SVGA3D_MS_PATTERN_MAX = 3, +} SVGA3dMSPattern; + +/* + * Precision settings for each sample. + */ + +typedef enum SVGA3dMSQualityLevel { + SVGA3D_MS_QUALITY_NONE = 0, + SVGA3D_MS_QUALITY_MIN = 0, + SVGA3D_MS_QUALITY_FULL = 1, + SVGA3D_MS_QUALITY_MAX = 2, +} SVGA3dMSQualityLevel; + #endif /* _SVGA3D_TYPES_H_ */ diff --git a/drivers/gpu/drm/vmwgfx/device_include/svga_reg.h b/drivers/gpu/drm/vmwgfx/device_include/svga_reg.h index cdd48a3763db6..ab8ea6b3cdb1f 100644 --- a/drivers/gpu/drm/vmwgfx/device_include/svga_reg.h +++ b/drivers/gpu/drm/vmwgfx/device_include/svga_reg.h @@ -63,16 +63,26 @@ typedef uint32 SVGAMobId; #define SVGA_MAX_BITS_PER_PIXEL 32 #define SVGA_MAX_DEPTH 24 #define SVGA_MAX_DISPLAYS 10 +#define SVGA_MAX_SCREEN_SIZE 8192 +#define SVGA_SCREEN_ROOT_LIMIT (SVGA_MAX_SCREEN_SIZE * SVGA_MAX_DISPLAYS) + /* * Legal values for the SVGA_REG_CURSOR_ON register in old-fashioned * cursor bypass mode. This is still supported, but no new guest * drivers should use it. */ -#define SVGA_CURSOR_ON_HIDE 0x0 /* Must be 0 to maintain backward compatibility */ -#define SVGA_CURSOR_ON_SHOW 0x1 /* Must be 1 to maintain backward compatibility */ -#define SVGA_CURSOR_ON_REMOVE_FROM_FB 0x2 /* Remove the cursor from the framebuffer because we need to see what's under it */ -#define SVGA_CURSOR_ON_RESTORE_TO_FB 0x3 /* Put the cursor back in the framebuffer so the user can see it */ +#define SVGA_CURSOR_ON_HIDE 0x0 +#define SVGA_CURSOR_ON_SHOW 0x1 + +/* + * Remove the cursor from the framebuffer + * because we need to see what's under it + */ +#define SVGA_CURSOR_ON_REMOVE_FROM_FB 0x2 + +/* Put the cursor back in the framebuffer so the user can see it */ +#define SVGA_CURSOR_ON_RESTORE_TO_FB 0x3 /* * The maximum framebuffer size that can traced for guests unless the @@ -101,7 +111,10 @@ typedef uint32 SVGAMobId; #define SVGA_VERSION_0 0 #define SVGA_ID_0 SVGA_MAKE_ID(SVGA_VERSION_0) -/* "Invalid" value for all SVGA IDs. (Version ID, screen object ID, surface ID...) */ +/* + * "Invalid" value for all SVGA IDs. + * (Version ID, screen object ID, surface ID...) + */ #define SVGA_ID_INVALID 0xFFFFFFFF /* Port offsets, relative to BAR0 */ @@ -154,7 +167,7 @@ enum { SVGA_REG_CONFIG_DONE = 20, /* Set when memory area configured */ SVGA_REG_SYNC = 21, /* See "FIFO Synchronization Registers" */ SVGA_REG_BUSY = 22, /* See "FIFO Synchronization Registers" */ - SVGA_REG_GUEST_ID = 23, /* Set guest OS identifier */ + SVGA_REG_GUEST_ID = 23, /* (Deprecated) */ SVGA_REG_CURSOR_ID = 24, /* (Deprecated) */ SVGA_REG_CURSOR_X = 25, /* (Deprecated) */ SVGA_REG_CURSOR_Y = 26, /* (Deprecated) */ @@ -186,7 +199,14 @@ enum { SVGA_REG_MEMORY_SIZE = 47, /* Total dedicated device memory excluding FIFO */ SVGA_REG_COMMAND_LOW = 48, /* Lower 32 bits and submits commands */ SVGA_REG_COMMAND_HIGH = 49, /* Upper 32 bits of command buffer PA */ - SVGA_REG_MAX_PRIMARY_BOUNDING_BOX_MEM = 50, /* Max primary memory */ + + /* + * Max primary memory. + * See SVGA_CAP_NO_BB_RESTRICTION. + */ + SVGA_REG_MAX_PRIMARY_MEM = 50, + SVGA_REG_MAX_PRIMARY_BOUNDING_BOX_MEM = 50, + SVGA_REG_SUGGESTED_GBOBJECT_MEM_SIZE_KB = 51, /* Sugested limit on mob mem */ SVGA_REG_DEV_CAP = 52, /* Write dev cap index, read value */ SVGA_REG_CMD_PREPEND_LOW = 53, @@ -194,7 +214,10 @@ enum { SVGA_REG_SCREENTARGET_MAX_WIDTH = 55, SVGA_REG_SCREENTARGET_MAX_HEIGHT = 56, SVGA_REG_MOB_MAX_SIZE = 57, - SVGA_REG_TOP = 58, /* Must be 1 more than the last register */ + SVGA_REG_BLANK_SCREEN_TARGETS = 58, + SVGA_REG_CAP2 = 59, + SVGA_REG_DEVEL_CAP = 60, + SVGA_REG_TOP = 61, /* Must be 1 more than the last register */ SVGA_PALETTE_BASE = 1024, /* Base of SVGA color map */ /* Next 768 (== 256*3) registers exist for colormap */ @@ -392,6 +415,7 @@ typedef enum { SVGA_CB_CONTEXT_0 = 0x0, SVGA_CB_CONTEXT_1 = 0x1, /* Supported with SVGA_CAP_HP_CMD_QUEUE */ SVGA_CB_CONTEXT_MAX = 0x2, + SVGA_CB_CONTEXT_HP_MAX = 0x2, } SVGACBContext; @@ -448,6 +472,18 @@ typedef enum { * due to an error. No IRQ is raised. */ SVGA_CB_STATUS_SUBMISSION_ERROR = 6, + + /* + * Written by the host when the host finished a + * SVGA_DC_CMD_ASYNC_STOP_QUEUE request for this command buffer + * queue. The offset of the first byte not processed is stored in + * the errorOffset field of the command buffer header. All guest + * visible side effects of commands till that point are guaranteed + * to be finished before this is written. The + * SVGA_IRQFLAG_COMMAND_BUFFER IRQ is raised as long as the + * SVGA_CB_FLAG_NO_IRQ is not set. + */ + SVGA_CB_STATUS_PARTIAL_COMPLETE = 7, } SVGACBStatus; typedef enum { @@ -460,8 +496,8 @@ typedef enum { typedef #include "vmware_pack_begin.h" struct { - volatile SVGACBStatus status; - volatile uint32 errorOffset; + volatile SVGACBStatus status; /* Modified by device. */ + volatile uint32 errorOffset; /* Modified by device. */ uint64 id; SVGACBFlags flags; uint32 length; @@ -472,7 +508,9 @@ struct { uint32 mobOffset; } mob; } ptr; - uint32 offset; /* Valid if CMD_BUFFERS_2 cap set, must be zero otherwise */ + uint32 offset; /* Valid if CMD_BUFFERS_2 cap set, must be zero otherwise, + * modified by device. + */ uint32 dxContext; /* Valid if DX_CONTEXT flag set, must be zero otherwise */ uint32 mustBeZero[6]; } @@ -483,20 +521,26 @@ typedef enum { SVGA_DC_CMD_NOP = 0, SVGA_DC_CMD_START_STOP_CONTEXT = 1, SVGA_DC_CMD_PREEMPT = 2, - SVGA_DC_CMD_MAX = 3, - SVGA_DC_CMD_FORCE_UINT = MAX_UINT32, + SVGA_DC_CMD_START_QUEUE = 3, /* Requires SVGA_CAP_HP_CMD_QUEUE */ + SVGA_DC_CMD_ASYNC_STOP_QUEUE = 4, /* Requires SVGA_CAP_HP_CMD_QUEUE */ + SVGA_DC_CMD_EMPTY_CONTEXT_QUEUE = 5, /* Requires SVGA_CAP_HP_CMD_QUEUE */ + SVGA_DC_CMD_MAX = 6, } SVGADeviceContextCmdId; -typedef struct { +/* + * Starts or stops both SVGA_CB_CONTEXT_0 and SVGA_CB_CONTEXT_1. + */ + +typedef struct SVGADCCmdStartStop { uint32 enable; - SVGACBContext context; + SVGACBContext context; /* Must be zero */ } SVGADCCmdStartStop; /* * SVGADCCmdPreempt -- * * This command allows the guest to request that all command buffers - * on the specified context be preempted that can be. After execution + * on SVGA_CB_CONTEXT_0 be preempted that can be. After execution * of this command all command buffers that were preempted will * already have SVGA_CB_STATUS_PREEMPTED written into the status * field. The device might still be processing a command buffer, @@ -506,11 +550,68 @@ typedef struct { * command buffer header set to zero. */ -typedef struct { - SVGACBContext context; +typedef struct SVGADCCmdPreempt { + SVGACBContext context; /* Must be zero */ uint32 ignoreIDZero; } SVGADCCmdPreempt; +/* + * Starts the requested command buffer processing queue. Valid only + * if the SVGA_CAP_HP_CMD_QUEUE cap is set. + * + * For a command queue to be considered runnable it must be enabled + * and any corresponding higher priority queues must also be enabled. + * For example in order for command buffers to be processed on + * SVGA_CB_CONTEXT_0 both SVGA_CB_CONTEXT_0 and SVGA_CB_CONTEXT_1 must + * be enabled. But for commands to be runnable on SVGA_CB_CONTEXT_1 + * only that queue must be enabled. + */ + +typedef struct SVGADCCmdStartQueue { + SVGACBContext context; +} SVGADCCmdStartQueue; + +/* + * Requests the SVGA device to stop processing the requested command + * buffer queue as soon as possible. The guest knows the stop has + * completed when one of the following happens. + * + * 1) A command buffer status of SVGA_CB_STATUS_PARTIAL_COMPLETE is returned + * 2) A command buffer error is encountered with would stop the queue + * regardless of the async stop request. + * 3) All command buffers that have been submitted complete successfully. + * 4) The stop completes synchronously if no command buffers are + * active on the queue when it is issued. + * + * If the command queue is not in a runnable state there is no + * guarentee this async stop will finish. For instance if the high + * priority queue is not enabled and a stop is requested on the low + * priority queue, the high priority queue must be reenabled to + * guarantee that the async stop will finish. + * + * This command along with SVGA_DC_CMD_EMPTY_CONTEXT_QUEUE can be used + * to implement mid command buffer preemption. + * + * Valid only if the SVGA_CAP_HP_CMD_QUEUE cap is set. + */ + +typedef struct SVGADCCmdAsyncStopQueue { + SVGACBContext context; +} SVGADCCmdAsyncStopQueue; + +/* + * Requests the SVGA device to throw away any full command buffers on + * the requested command queue that have not been started. For a + * driver to know which command buffers were thrown away a driver + * should only issue this command when the queue is stopped, for + * whatever reason. + */ + +typedef struct SVGADCCmdEmptyQueue { + SVGACBContext context; +} SVGADCCmdEmptyQueue; + + /* * SVGAGMRImageFormat -- * @@ -536,7 +637,7 @@ typedef struct SVGAGMRImageFormat { struct { uint32 bitsPerPixel : 8; uint32 colorDepth : 8; - uint32 reserved : 16; /* Must be zero */ + uint32 reserved : 16; /* Must be zero */ }; uint32 value; @@ -700,6 +801,8 @@ SVGASignedPoint; * large enough to express any possible topology without holes between * monitors.) * + * SVGA_CAP_CAP2_REGISTER -- + * If this cap is present, the SVGA_REG_CAP2 register is supported. */ #define SVGA_CAP_NONE 0x00000000 @@ -726,8 +829,29 @@ SVGASignedPoint; #define SVGA_CAP_DX 0x10000000 #define SVGA_CAP_HP_CMD_QUEUE 0x20000000 #define SVGA_CAP_NO_BB_RESTRICTION 0x40000000 +#define SVGA_CAP_CAP2_REGISTER 0x80000000 -#define SVGA_CAP_CMD_RESERVED 0x80000000 +/* + * The SVGA_REG_CAP2 register is an additional set of SVGA capability bits. + * + * SVGA_CAP2_GROW_OTABLE -- + * Allow the GrowOTable/DXGrowCOTable commands. + * + * SVGA_CAP2_INTRA_SURFACE_COPY -- + * Allow the IntraSurfaceCopy command. + * + * SVGA_CAP2_DX2 -- + * Allow the DefineGBSurface_v3, WholeSurfaceCopy. + * + * SVGA_CAP2_RESERVED -- + * Reserve the last bit for extending the SVGA capabilities to some + * future mechanisms. + */ +#define SVGA_CAP2_NONE 0x00000000 +#define SVGA_CAP2_GROW_OTABLE 0x00000001 +#define SVGA_CAP2_INTRA_SURFACE_COPY 0x00000002 +#define SVGA_CAP2_DX2 0x00000004 +#define SVGA_CAP2_RESERVED 0x80000000 /* @@ -749,7 +873,8 @@ typedef enum { SVGABackdoorCapDeviceCaps = 0, SVGABackdoorCapFifoCaps = 1, SVGABackdoorCap3dHWVersion = 2, - SVGABackdoorCapMax = 3, + SVGABackdoorCapDeviceCaps2 = 3, + SVGABackdoorCapMax = 4, } SVGABackdoorCapType; @@ -1941,16 +2066,6 @@ SVGAFifoCmdRemapGMR2; #define SVGA_VRAM_SIZE_W2K (64 * 1024 * 1024) /* 64 MB */ -/* - * To simplify autoDetect display configuration, support a minimum of - * two 1920x1200 monitors, 32bpp, side-by-side, optionally rotated: - * numDisplays = 2 - * maxWidth = numDisplay * 1920 = 3840 - * maxHeight = rotated width of single monitor = 1920 - * vramSize = maxWidth * maxHeight * 4 = 29491200 - */ -#define SVGA_VRAM_SIZE_AUTODETECT (32 * 1024 * 1024) - #if defined(VMX86_SERVER) #define SVGA_VRAM_SIZE (4 * 1024 * 1024) #define SVGA_VRAM_SIZE_3D (64 * 1024 * 1024) diff --git a/drivers/gpu/drm/vmwgfx/device_include/svga_types.h b/drivers/gpu/drm/vmwgfx/device_include/svga_types.h index 2e8ba4df8de9e..2ba15f1318581 100644 --- a/drivers/gpu/drm/vmwgfx/device_include/svga_types.h +++ b/drivers/gpu/drm/vmwgfx/device_include/svga_types.h @@ -40,7 +40,10 @@ typedef uint64 PPN64; typedef bool Bool; +#define MAX_UINT64 U64_MAX #define MAX_UINT32 U32_MAX #define MAX_UINT16 U16_MAX +#define CONST64U(x) x##ULL + #endif diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 45dfff7733d6e..1128420de2c0b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -884,7 +884,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) if (dev_priv->has_mob) { spin_lock(&dev_priv->cap_lock); - vmw_write(dev_priv, SVGA_REG_DEV_CAP, SVGA3D_DEVCAP_DX); + vmw_write(dev_priv, SVGA_REG_DEV_CAP, SVGA3D_DEVCAP_DXCONTEXT); dev_priv->has_dx = !!vmw_read(dev_priv, SVGA_REG_DEV_CAP); spin_unlock(&dev_priv->cap_lock); } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index a8b194655c402..2d6efc36288f8 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -3230,9 +3230,9 @@ static const struct vmw_cmd_entry vmw_cmd_entries[SVGA_3D_CMD_MAX] = { false, false, false), VMW_CMD_DEF(SVGA_3D_CMD_SCREEN_DMA, &vmw_cmd_invalid, false, false, false), - VMW_CMD_DEF(SVGA_3D_CMD_SET_UNITY_SURFACE_COOKIE, &vmw_cmd_invalid, + VMW_CMD_DEF(SVGA_3D_CMD_DEAD1, &vmw_cmd_invalid, false, false, false), - VMW_CMD_DEF(SVGA_3D_CMD_OPEN_CONTEXT_SURFACE, &vmw_cmd_invalid, + VMW_CMD_DEF(SVGA_3D_CMD_DEAD2, &vmw_cmd_invalid, false, false, false), VMW_CMD_DEF(SVGA_3D_CMD_LOGICOPS_BITBLT, &vmw_cmd_invalid, false, false, false), diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c index 5e0c8f775c926..6872c7ee8a080 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c @@ -122,15 +122,12 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data, static u32 vmw_mask_multisample(unsigned int cap, u32 fmt_value) { - /* If the header is updated, update the format test as well! */ - BUILD_BUG_ON(SVGA3D_DEVCAP_DXFMT_BC5_UNORM + 1 != SVGA3D_DEVCAP_MAX); - - if (cap >= SVGA3D_DEVCAP_DXFMT_X8R8G8B8 && - cap <= SVGA3D_DEVCAP_DXFMT_BC5_UNORM) - fmt_value &= ~(SVGADX_DXFMT_MULTISAMPLE_2 | - SVGADX_DXFMT_MULTISAMPLE_4 | - SVGADX_DXFMT_MULTISAMPLE_8); - else if (cap == SVGA3D_DEVCAP_MULTISAMPLE_MASKABLESAMPLES) + /* + * A version of user-space exists which use MULTISAMPLE_MASKABLESAMPLES + * to check the sample count supported by virtual device. Since there + * never was support for multisample count for backing MOB return 0. + */ + if (cap == SVGA3D_DEVCAP_MULTISAMPLE_MASKABLESAMPLES) return 0; return fmt_value; -- GitLab From 4dd3cdb281f7a3200234ed2bcaae79af15f120d2 Mon Sep 17 00:00:00 2001 From: Daniel Vetter <daniel.vetter@ffwll.ch> Date: Wed, 4 Jul 2018 11:29:09 +0200 Subject: [PATCH 0650/1506] dma-fence: Polish kernel-doc for dma-fence.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Intro section that links to how this is exposed to userspace. - Lots more hyperlinks. - Minor clarifications and style polish v2: Add misplaced hunk of kerneldoc from a different patch. Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Cc: Sumit Semwal <sumit.semwal@linaro.org> Cc: Gustavo Padovan <gustavo@padovan.org> Cc: linux-media@vger.kernel.org Cc: linaro-mm-sig@lists.linaro.org Link: https://patchwork.freedesktop.org/patch/msgid/20180704092909.6599-6-daniel.vetter@ffwll.ch --- Documentation/driver-api/dma-buf.rst | 6 ++ drivers/dma-buf/dma-fence.c | 147 +++++++++++++++++++-------- 2 files changed, 109 insertions(+), 44 deletions(-) diff --git a/Documentation/driver-api/dma-buf.rst b/Documentation/driver-api/dma-buf.rst index dc384f2f7f34c..b541e97c7ab1a 100644 --- a/Documentation/driver-api/dma-buf.rst +++ b/Documentation/driver-api/dma-buf.rst @@ -130,6 +130,12 @@ Reservation Objects DMA Fences ---------- +.. kernel-doc:: drivers/dma-buf/dma-fence.c + :doc: DMA fences overview + +DMA Fences Functions Reference +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + .. kernel-doc:: drivers/dma-buf/dma-fence.c :export: diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c index 7a92f85a4cec8..1551ca7df3941 100644 --- a/drivers/dma-buf/dma-fence.c +++ b/drivers/dma-buf/dma-fence.c @@ -38,12 +38,43 @@ EXPORT_TRACEPOINT_SYMBOL(dma_fence_enable_signal); */ static atomic64_t dma_fence_context_counter = ATOMIC64_INIT(0); +/** + * DOC: DMA fences overview + * + * DMA fences, represented by &struct dma_fence, are the kernel internal + * synchronization primitive for DMA operations like GPU rendering, video + * encoding/decoding, or displaying buffers on a screen. + * + * A fence is initialized using dma_fence_init() and completed using + * dma_fence_signal(). Fences are associated with a context, allocated through + * dma_fence_context_alloc(), and all fences on the same context are + * fully ordered. + * + * Since the purposes of fences is to facilitate cross-device and + * cross-application synchronization, there's multiple ways to use one: + * + * - Individual fences can be exposed as a &sync_file, accessed as a file + * descriptor from userspace, created by calling sync_file_create(). This is + * called explicit fencing, since userspace passes around explicit + * synchronization points. + * + * - Some subsystems also have their own explicit fencing primitives, like + * &drm_syncobj. Compared to &sync_file, a &drm_syncobj allows the underlying + * fence to be updated. + * + * - Then there's also implicit fencing, where the synchronization points are + * implicitly passed around as part of shared &dma_buf instances. Such + * implicit fences are stored in &struct reservation_object through the + * &dma_buf.resv pointer. + */ + /** * dma_fence_context_alloc - allocate an array of fence contexts - * @num: [in] amount of contexts to allocate + * @num: amount of contexts to allocate * - * This function will return the first index of the number of fences allocated. - * The fence context is used for setting fence->context to a unique number. + * This function will return the first index of the number of fence contexts + * allocated. The fence context is used for setting &dma_fence.context to a + * unique number by passing the context to dma_fence_init(). */ u64 dma_fence_context_alloc(unsigned num) { @@ -59,10 +90,14 @@ EXPORT_SYMBOL(dma_fence_context_alloc); * Signal completion for software callbacks on a fence, this will unblock * dma_fence_wait() calls and run all the callbacks added with * dma_fence_add_callback(). Can be called multiple times, but since a fence - * can only go from unsignaled to signaled state, it will only be effective - * the first time. + * can only go from the unsignaled to the signaled state and not back, it will + * only be effective the first time. + * + * Unlike dma_fence_signal(), this function must be called with &dma_fence.lock + * held. * - * Unlike dma_fence_signal, this function must be called with fence->lock held. + * Returns 0 on success and a negative error value when @fence has been + * signalled already. */ int dma_fence_signal_locked(struct dma_fence *fence) { @@ -102,8 +137,11 @@ EXPORT_SYMBOL(dma_fence_signal_locked); * Signal completion for software callbacks on a fence, this will unblock * dma_fence_wait() calls and run all the callbacks added with * dma_fence_add_callback(). Can be called multiple times, but since a fence - * can only go from unsignaled to signaled state, it will only be effective - * the first time. + * can only go from the unsignaled to the signaled state and not back, it will + * only be effective the first time. + * + * Returns 0 on success and a negative error value when @fence has been + * signalled already. */ int dma_fence_signal(struct dma_fence *fence) { @@ -136,9 +174,9 @@ EXPORT_SYMBOL(dma_fence_signal); /** * dma_fence_wait_timeout - sleep until the fence gets signaled * or until timeout elapses - * @fence: [in] the fence to wait on - * @intr: [in] if true, do an interruptible wait - * @timeout: [in] timeout value in jiffies, or MAX_SCHEDULE_TIMEOUT + * @fence: the fence to wait on + * @intr: if true, do an interruptible wait + * @timeout: timeout value in jiffies, or MAX_SCHEDULE_TIMEOUT * * Returns -ERESTARTSYS if interrupted, 0 if the wait timed out, or the * remaining timeout in jiffies on success. Other error values may be @@ -148,6 +186,8 @@ EXPORT_SYMBOL(dma_fence_signal); * directly or indirectly (buf-mgr between reservation and committing) * holds a reference to the fence, otherwise the fence might be * freed before return, resulting in undefined behavior. + * + * See also dma_fence_wait() and dma_fence_wait_any_timeout(). */ signed long dma_fence_wait_timeout(struct dma_fence *fence, bool intr, signed long timeout) @@ -167,6 +207,13 @@ dma_fence_wait_timeout(struct dma_fence *fence, bool intr, signed long timeout) } EXPORT_SYMBOL(dma_fence_wait_timeout); +/** + * dma_fence_release - default relese function for fences + * @kref: &dma_fence.recfount + * + * This is the default release functions for &dma_fence. Drivers shouldn't call + * this directly, but instead call dma_fence_put(). + */ void dma_fence_release(struct kref *kref) { struct dma_fence *fence = @@ -184,6 +231,13 @@ void dma_fence_release(struct kref *kref) } EXPORT_SYMBOL(dma_fence_release); +/** + * dma_fence_free - default release function for &dma_fence. + * @fence: fence to release + * + * This is the default implementation for &dma_fence_ops.release. It calls + * kfree_rcu() on @fence. + */ void dma_fence_free(struct dma_fence *fence) { kfree_rcu(fence, rcu); @@ -192,10 +246,11 @@ EXPORT_SYMBOL(dma_fence_free); /** * dma_fence_enable_sw_signaling - enable signaling on fence - * @fence: [in] the fence to enable + * @fence: the fence to enable * - * this will request for sw signaling to be enabled, to make the fence - * complete as soon as possible + * This will request for sw signaling to be enabled, to make the fence + * complete as soon as possible. This calls &dma_fence_ops.enable_signaling + * internally. */ void dma_fence_enable_sw_signaling(struct dma_fence *fence) { @@ -220,24 +275,24 @@ EXPORT_SYMBOL(dma_fence_enable_sw_signaling); /** * dma_fence_add_callback - add a callback to be called when the fence * is signaled - * @fence: [in] the fence to wait on - * @cb: [in] the callback to register - * @func: [in] the function to call + * @fence: the fence to wait on + * @cb: the callback to register + * @func: the function to call * - * cb will be initialized by dma_fence_add_callback, no initialization + * @cb will be initialized by dma_fence_add_callback(), no initialization * by the caller is required. Any number of callbacks can be registered * to a fence, but a callback can only be registered to one fence at a time. * * Note that the callback can be called from an atomic context. If * fence is already signaled, this function will return -ENOENT (and - * *not* call the callback) + * *not* call the callback). * * Add a software callback to the fence. Same restrictions apply to - * refcount as it does to dma_fence_wait, however the caller doesn't need to - * keep a refcount to fence afterwards: when software access is enabled, - * the creator of the fence is required to keep the fence alive until - * after it signals with dma_fence_signal. The callback itself can be called - * from irq context. + * refcount as it does to dma_fence_wait(), however the caller doesn't need to + * keep a refcount to fence afterward dma_fence_add_callback() has returned: + * when software access is enabled, the creator of the fence is required to keep + * the fence alive until after it signals with dma_fence_signal(). The callback + * itself can be called from irq context. * * Returns 0 in case of success, -ENOENT if the fence is already signaled * and -EINVAL in case of error. @@ -286,7 +341,7 @@ EXPORT_SYMBOL(dma_fence_add_callback); /** * dma_fence_get_status - returns the status upon completion - * @fence: [in] the dma_fence to query + * @fence: the dma_fence to query * * This wraps dma_fence_get_status_locked() to return the error status * condition on a signaled fence. See dma_fence_get_status_locked() for more @@ -311,8 +366,8 @@ EXPORT_SYMBOL(dma_fence_get_status); /** * dma_fence_remove_callback - remove a callback from the signaling list - * @fence: [in] the fence to wait on - * @cb: [in] the callback to remove + * @fence: the fence to wait on + * @cb: the callback to remove * * Remove a previously queued callback from the fence. This function returns * true if the callback is successfully removed, or false if the fence has @@ -323,6 +378,9 @@ EXPORT_SYMBOL(dma_fence_get_status); * doing, since deadlocks and race conditions could occur all too easily. For * this reason, it should only ever be done on hardware lockup recovery, * with a reference held to the fence. + * + * Behaviour is undefined if @cb has not been added to @fence using + * dma_fence_add_callback() beforehand. */ bool dma_fence_remove_callback(struct dma_fence *fence, struct dma_fence_cb *cb) @@ -359,9 +417,9 @@ dma_fence_default_wait_cb(struct dma_fence *fence, struct dma_fence_cb *cb) /** * dma_fence_default_wait - default sleep until the fence gets signaled * or until timeout elapses - * @fence: [in] the fence to wait on - * @intr: [in] if true, do an interruptible wait - * @timeout: [in] timeout value in jiffies, or MAX_SCHEDULE_TIMEOUT + * @fence: the fence to wait on + * @intr: if true, do an interruptible wait + * @timeout: timeout value in jiffies, or MAX_SCHEDULE_TIMEOUT * * Returns -ERESTARTSYS if interrupted, 0 if the wait timed out, or the * remaining timeout in jiffies on success. If timeout is zero the value one is @@ -454,12 +512,12 @@ dma_fence_test_signaled_any(struct dma_fence **fences, uint32_t count, /** * dma_fence_wait_any_timeout - sleep until any fence gets signaled * or until timeout elapses - * @fences: [in] array of fences to wait on - * @count: [in] number of fences to wait on - * @intr: [in] if true, do an interruptible wait - * @timeout: [in] timeout value in jiffies, or MAX_SCHEDULE_TIMEOUT - * @idx: [out] the first signaled fence index, meaningful only on - * positive return + * @fences: array of fences to wait on + * @count: number of fences to wait on + * @intr: if true, do an interruptible wait + * @timeout: timeout value in jiffies, or MAX_SCHEDULE_TIMEOUT + * @idx: used to store the first signaled fence index, meaningful only on + * positive return * * Returns -EINVAL on custom fence wait implementation, -ERESTARTSYS if * interrupted, 0 if the wait timed out, or the remaining timeout in jiffies @@ -468,6 +526,8 @@ dma_fence_test_signaled_any(struct dma_fence **fences, uint32_t count, * Synchronous waits for the first fence in the array to be signaled. The * caller needs to hold a reference to all fences in the array, otherwise a * fence might be freed before return, resulting in undefined behavior. + * + * See also dma_fence_wait() and dma_fence_wait_timeout(). */ signed long dma_fence_wait_any_timeout(struct dma_fence **fences, uint32_t count, @@ -540,19 +600,18 @@ EXPORT_SYMBOL(dma_fence_wait_any_timeout); /** * dma_fence_init - Initialize a custom fence. - * @fence: [in] the fence to initialize - * @ops: [in] the dma_fence_ops for operations on this fence - * @lock: [in] the irqsafe spinlock to use for locking this fence - * @context: [in] the execution context this fence is run on - * @seqno: [in] a linear increasing sequence number for this context + * @fence: the fence to initialize + * @ops: the dma_fence_ops for operations on this fence + * @lock: the irqsafe spinlock to use for locking this fence + * @context: the execution context this fence is run on + * @seqno: a linear increasing sequence number for this context * * Initializes an allocated fence, the caller doesn't have to keep its * refcount after committing with this fence, but it will need to hold a - * refcount again if dma_fence_ops.enable_signaling gets called. This can - * be used for other implementing other types of fence. + * refcount again if &dma_fence_ops.enable_signaling gets called. * * context and seqno are used for easy comparison between fences, allowing - * to check which fence is later by simply using dma_fence_later. + * to check which fence is later by simply using dma_fence_later(). */ void dma_fence_init(struct dma_fence *fence, const struct dma_fence_ops *ops, -- GitLab From 968d72e6a5105a18fe17c0a8b4ef2951d0eb42dd Mon Sep 17 00:00:00 2001 From: Dan Carpenter <dan.carpenter@oracle.com> Date: Wed, 4 Jul 2018 12:48:10 +0300 Subject: [PATCH 0651/1506] drm/savage: off by one in savage_bci_cmdbuf() The > should be >= here so that we don't read beyond the end of the dma->buflist[] array. Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180704094810.whrgn6jxe7uibnfv@kili.mountain --- drivers/gpu/drm/savage/savage_state.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/savage/savage_state.c b/drivers/gpu/drm/savage/savage_state.c index 2db89bed52e80..7559a820bd435 100644 --- a/drivers/gpu/drm/savage/savage_state.c +++ b/drivers/gpu/drm/savage/savage_state.c @@ -971,7 +971,7 @@ int savage_bci_cmdbuf(struct drm_device *dev, void *data, struct drm_file *file_ LOCK_TEST_WITH_RETURN(dev, file_priv); if (dma && dma->buflist) { - if (cmdbuf->dma_idx > dma->buf_count) { + if (cmdbuf->dma_idx >= dma->buf_count) { DRM_ERROR ("vertex buffer index %u out of range (0-%u)\n", cmdbuf->dma_idx, dma->buf_count - 1); -- GitLab From c51756d56e20a12476e4e192b332fac39c1550ca Mon Sep 17 00:00:00 2001 From: Kees Cook <keescook@chromium.org> Date: Fri, 29 Jun 2018 11:47:40 -0700 Subject: [PATCH 0652/1506] drm/sun4i: Remove VLA usage In the quest to remove all stack VLA usage from the kernel[1], this switches to using a kmalloc allocation and moves all the size calculations to the start to do an allocation. If an upper bounds on the mode timing calculations could be determined, a fixed stack size could be used instead. [1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com Signed-off-by: Kees Cook <keescook@chromium.org> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180629184740.GA37415@beast --- drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 107 +++++++++++++++---------- 1 file changed, 64 insertions(+), 43 deletions(-) diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c index d4e7d16a2514e..da9814f94d008 100644 --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c @@ -13,6 +13,7 @@ #include <linux/pm_runtime.h> #include <linux/regmap.h> #include <linux/reset.h> +#include <linux/slab.h> #include <linux/phy/phy.h> @@ -247,10 +248,8 @@ static u16 sun6i_dsi_crc_compute(u8 const *buffer, size_t len) return crc_ccitt(0xffff, buffer, len); } -static u16 sun6i_dsi_crc_repeat_compute(u8 pd, size_t len) +static u16 sun6i_dsi_crc_repeat(u8 pd, u8 *buffer, size_t len) { - u8 buffer[len]; - memset(buffer, pd, len); return sun6i_dsi_crc_compute(buffer, len); @@ -274,11 +273,11 @@ static u32 sun6i_dsi_build_blk0_pkt(u8 vc, u16 wc) wc & 0xff, wc >> 8); } -static u32 sun6i_dsi_build_blk1_pkt(u16 pd, size_t len) +static u32 sun6i_dsi_build_blk1_pkt(u16 pd, u8 *buffer, size_t len) { u32 val = SUN6I_DSI_BLK_PD(pd); - return val | SUN6I_DSI_BLK_PF(sun6i_dsi_crc_repeat_compute(pd, len)); + return val | SUN6I_DSI_BLK_PF(sun6i_dsi_crc_repeat(pd, buffer, len)); } static void sun6i_dsi_inst_abort(struct sun6i_dsi *dsi) @@ -452,6 +451,54 @@ static void sun6i_dsi_setup_timings(struct sun6i_dsi *dsi, struct mipi_dsi_device *device = dsi->device; unsigned int Bpp = mipi_dsi_pixel_format_to_bpp(device->format) / 8; u16 hbp, hfp, hsa, hblk, vblk; + size_t bytes; + u8 *buffer; + + /* Do all timing calculations up front to allocate buffer space */ + + /* + * A sync period is composed of a blanking packet (4 bytes + + * payload + 2 bytes) and a sync event packet (4 bytes). Its + * minimal size is therefore 10 bytes + */ +#define HSA_PACKET_OVERHEAD 10 + hsa = max((unsigned int)HSA_PACKET_OVERHEAD, + (mode->hsync_end - mode->hsync_start) * Bpp - HSA_PACKET_OVERHEAD); + + /* + * The backporch is set using a blanking packet (4 bytes + + * payload + 2 bytes). Its minimal size is therefore 6 bytes + */ +#define HBP_PACKET_OVERHEAD 6 + hbp = max((unsigned int)HBP_PACKET_OVERHEAD, + (mode->hsync_start - mode->hdisplay) * Bpp - HBP_PACKET_OVERHEAD); + + /* + * The frontporch is set using a blanking packet (4 bytes + + * payload + 2 bytes). Its minimal size is therefore 6 bytes + */ +#define HFP_PACKET_OVERHEAD 6 + hfp = max((unsigned int)HFP_PACKET_OVERHEAD, + (mode->htotal - mode->hsync_end) * Bpp - HFP_PACKET_OVERHEAD); + + /* + * hblk seems to be the line + porches length. + */ + hblk = mode->htotal * Bpp - hsa; + + /* + * And I'm not entirely sure what vblk is about. The driver in + * Allwinner BSP is using a rather convoluted calculation + * there only for 4 lanes. However, using 0 (the !4 lanes + * case) even with a 4 lanes screen seems to work... + */ + vblk = 0; + + /* How many bytes do we need to send all payloads? */ + bytes = max_t(size_t, max(max(hfp, hblk), max(hsa, hbp)), vblk); + buffer = kmalloc(bytes, GFP_KERNEL); + if (WARN_ON(!buffer)) + return; regmap_write(dsi->regs, SUN6I_DSI_BASIC_CTL_REG, 0); @@ -485,63 +532,37 @@ static void sun6i_dsi_setup_timings(struct sun6i_dsi *dsi, SUN6I_DSI_BASIC_SIZE1_VACT(mode->vdisplay) | SUN6I_DSI_BASIC_SIZE1_VT(mode->vtotal)); - /* - * A sync period is composed of a blanking packet (4 bytes + - * payload + 2 bytes) and a sync event packet (4 bytes). Its - * minimal size is therefore 10 bytes - */ -#define HSA_PACKET_OVERHEAD 10 - hsa = max((unsigned int)HSA_PACKET_OVERHEAD, - (mode->hsync_end - mode->hsync_start) * Bpp - HSA_PACKET_OVERHEAD); + /* sync */ regmap_write(dsi->regs, SUN6I_DSI_BLK_HSA0_REG, sun6i_dsi_build_blk0_pkt(device->channel, hsa)); regmap_write(dsi->regs, SUN6I_DSI_BLK_HSA1_REG, - sun6i_dsi_build_blk1_pkt(0, hsa)); + sun6i_dsi_build_blk1_pkt(0, buffer, hsa)); - /* - * The backporch is set using a blanking packet (4 bytes + - * payload + 2 bytes). Its minimal size is therefore 6 bytes - */ -#define HBP_PACKET_OVERHEAD 6 - hbp = max((unsigned int)HBP_PACKET_OVERHEAD, - (mode->hsync_start - mode->hdisplay) * Bpp - HBP_PACKET_OVERHEAD); + /* backporch */ regmap_write(dsi->regs, SUN6I_DSI_BLK_HBP0_REG, sun6i_dsi_build_blk0_pkt(device->channel, hbp)); regmap_write(dsi->regs, SUN6I_DSI_BLK_HBP1_REG, - sun6i_dsi_build_blk1_pkt(0, hbp)); + sun6i_dsi_build_blk1_pkt(0, buffer, hbp)); - /* - * The frontporch is set using a blanking packet (4 bytes + - * payload + 2 bytes). Its minimal size is therefore 6 bytes - */ -#define HFP_PACKET_OVERHEAD 6 - hfp = max((unsigned int)HFP_PACKET_OVERHEAD, - (mode->htotal - mode->hsync_end) * Bpp - HFP_PACKET_OVERHEAD); + /* frontporch */ regmap_write(dsi->regs, SUN6I_DSI_BLK_HFP0_REG, sun6i_dsi_build_blk0_pkt(device->channel, hfp)); regmap_write(dsi->regs, SUN6I_DSI_BLK_HFP1_REG, - sun6i_dsi_build_blk1_pkt(0, hfp)); + sun6i_dsi_build_blk1_pkt(0, buffer, hfp)); - /* - * hblk seems to be the line + porches length. - */ - hblk = mode->htotal * Bpp - hsa; + /* hblk */ regmap_write(dsi->regs, SUN6I_DSI_BLK_HBLK0_REG, sun6i_dsi_build_blk0_pkt(device->channel, hblk)); regmap_write(dsi->regs, SUN6I_DSI_BLK_HBLK1_REG, - sun6i_dsi_build_blk1_pkt(0, hblk)); + sun6i_dsi_build_blk1_pkt(0, buffer, hblk)); - /* - * And I'm not entirely sure what vblk is about. The driver in - * Allwinner BSP is using a rather convoluted calculation - * there only for 4 lanes. However, using 0 (the !4 lanes - * case) even with a 4 lanes screen seems to work... - */ - vblk = 0; + /* vblk */ regmap_write(dsi->regs, SUN6I_DSI_BLK_VBLK0_REG, sun6i_dsi_build_blk0_pkt(device->channel, vblk)); regmap_write(dsi->regs, SUN6I_DSI_BLK_VBLK1_REG, - sun6i_dsi_build_blk1_pkt(0, vblk)); + sun6i_dsi_build_blk1_pkt(0, buffer, vblk)); + + kfree(buffer); } static int sun6i_dsi_start(struct sun6i_dsi *dsi, -- GitLab From 0ba7c51a6fd80a89236f6ceb52e63f8a7f62bfd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Thu, 14 Jun 2018 20:56:25 +0300 Subject: [PATCH 0653/1506] drm/i915: Fix hotplug irq ack on i965/g4x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just like with PIPESTAT, the edge triggered IIR on i965/g4x also causes problems for hotplug interrupts. To make sure we don't get the IIR port interrupt bit stuck low with the ISR bit high we must force an edge in ISR. Unfortunately we can't borrow the PIPESTAT trick and toggle the enable bits in PORT_HOTPLUG_EN as that act itself generates hotplug interrupts. Instead we just have to loop until we've cleared PORT_HOTPLUG_STAT, or we just give up and WARN. v2: Don't frob with PORT_HOTPLUG_EN Cc: stable@vger.kernel.org Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180614175625.1615-1-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak <imre.deak@intel.com> --- drivers/gpu/drm/i915/i915_irq.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 435a4444314ca..c59aa0737079b 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2069,10 +2069,38 @@ static void valleyview_pipestat_irq_handler(struct drm_i915_private *dev_priv, static u32 i9xx_hpd_irq_ack(struct drm_i915_private *dev_priv) { - u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); + u32 hotplug_status = 0, hotplug_status_mask; + int i; + + if (IS_G4X(dev_priv) || + IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) + hotplug_status_mask = HOTPLUG_INT_STATUS_G4X | + DP_AUX_CHANNEL_MASK_INT_STATUS_G4X; + else + hotplug_status_mask = HOTPLUG_INT_STATUS_I915; - if (hotplug_status) + /* + * We absolutely have to clear all the pending interrupt + * bits in PORT_HOTPLUG_STAT. Otherwise the ISR port + * interrupt bit won't have an edge, and the i965/g4x + * edge triggered IIR will not notice that an interrupt + * is still pending. We can't use PORT_HOTPLUG_EN to + * guarantee the edge as the act of toggling the enable + * bits can itself generate a new hotplug interrupt :( + */ + for (i = 0; i < 10; i++) { + u32 tmp = I915_READ(PORT_HOTPLUG_STAT) & hotplug_status_mask; + + if (tmp == 0) + return hotplug_status; + + hotplug_status |= tmp; I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); + } + + WARN_ONCE(1, + "PORT_HOTPLUG_STAT did not clear (0x%08x)\n", + I915_READ(PORT_HOTPLUG_STAT)); return hotplug_status; } -- GitLab From 78c357dd3fcf51de61a0b8db3abdb8ed5aea6dd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Mon, 11 Jun 2018 23:02:57 +0300 Subject: [PATCH 0654/1506] drm/i915: Fix pre-ILK error interrupt ack MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adjust the EIR clearing to cope with the edge triggered IIR on i965/g4x. To guarantee an edge in the ISR master error bit we temporarily mask everything in EMR. As some of the EIR bits can't even be directly cleared we also borrow a trick from i915_clear_error_registers() and permanently mask any bit that remains high. No real thought given to how we might unmask them again once the cause for the error has been clered. I suppose on pre-g4x GPU reset will reinitialize EMR from scratch. Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180611200258.27121-3-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak <imre.deak@intel.com> --- drivers/gpu/drm/i915/i915_irq.c | 105 +++++++++++++++++++++++++++++--- drivers/gpu/drm/i915/i915_reg.h | 1 - 2 files changed, 96 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index c59aa0737079b..7fb493b7aa742 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -3279,7 +3279,7 @@ static void i915_clear_error_registers(struct drm_i915_private *dev_priv) */ DRM_DEBUG_DRIVER("EIR stuck: 0x%08x, masking\n", eir); I915_WRITE(EMR, I915_READ(EMR) | eir); - I915_WRITE(IIR, I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT); + I915_WRITE(IIR, I915_MASTER_ERROR_INTERRUPT); } } @@ -4406,6 +4406,81 @@ static int i8xx_irq_postinstall(struct drm_device *dev) return 0; } +static void i8xx_error_irq_ack(struct drm_i915_private *dev_priv, + u16 *eir, u16 *eir_stuck) +{ + u16 emr; + + *eir = I915_READ16(EIR); + + if (*eir) + I915_WRITE16(EIR, *eir); + + *eir_stuck = I915_READ16(EIR); + if (*eir_stuck == 0) + return; + + /* + * Toggle all EMR bits to make sure we get an edge + * in the ISR master error bit if we don't clear + * all the EIR bits. Otherwise the edge triggered + * IIR on i965/g4x wouldn't notice that an interrupt + * is still pending. Also some EIR bits can't be + * cleared except by handling the underlying error + * (or by a GPU reset) so we mask any bit that + * remains set. + */ + emr = I915_READ16(EMR); + I915_WRITE16(EMR, 0xffff); + I915_WRITE16(EMR, emr | *eir_stuck); +} + +static void i8xx_error_irq_handler(struct drm_i915_private *dev_priv, + u16 eir, u16 eir_stuck) +{ + DRM_DEBUG("Master Error: EIR 0x%04x\n", eir); + + if (eir_stuck) + DRM_DEBUG_DRIVER("EIR stuck: 0x%04x, masked\n", eir_stuck); +} + +static void i9xx_error_irq_ack(struct drm_i915_private *dev_priv, + u32 *eir, u32 *eir_stuck) +{ + u32 emr; + + *eir = I915_READ(EIR); + + I915_WRITE(EIR, *eir); + + *eir_stuck = I915_READ(EIR); + if (*eir_stuck == 0) + return; + + /* + * Toggle all EMR bits to make sure we get an edge + * in the ISR master error bit if we don't clear + * all the EIR bits. Otherwise the edge triggered + * IIR on i965/g4x wouldn't notice that an interrupt + * is still pending. Also some EIR bits can't be + * cleared except by handling the underlying error + * (or by a GPU reset) so we mask any bit that + * remains set. + */ + emr = I915_READ(EMR); + I915_WRITE(EMR, 0xffffffff); + I915_WRITE(EMR, emr | *eir_stuck); +} + +static void i9xx_error_irq_handler(struct drm_i915_private *dev_priv, + u32 eir, u32 eir_stuck) +{ + DRM_DEBUG("Master Error, EIR 0x%08x\n", eir); + + if (eir_stuck) + DRM_DEBUG_DRIVER("EIR stuck: 0x%08x, masked\n", eir_stuck); +} + static irqreturn_t i8xx_irq_handler(int irq, void *arg) { struct drm_device *dev = arg; @@ -4420,6 +4495,7 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg) do { u32 pipe_stats[I915_MAX_PIPES] = {}; + u16 eir = 0, eir_stuck = 0; u16 iir; iir = I915_READ16(IIR); @@ -4432,13 +4508,16 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg) * signalled in iir */ i9xx_pipestat_irq_ack(dev_priv, iir, pipe_stats); + if (iir & I915_MASTER_ERROR_INTERRUPT) + i8xx_error_irq_ack(dev_priv, &eir, &eir_stuck); + I915_WRITE16(IIR, iir); if (iir & I915_USER_INTERRUPT) notify_ring(dev_priv->engine[RCS]); - if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) - DRM_DEBUG("Command parser error, iir 0x%08x\n", iir); + if (iir & I915_MASTER_ERROR_INTERRUPT) + i8xx_error_irq_handler(dev_priv, eir, eir_stuck); i8xx_pipestat_irq_handler(dev_priv, iir, pipe_stats); } while (0); @@ -4519,6 +4598,7 @@ static irqreturn_t i915_irq_handler(int irq, void *arg) do { u32 pipe_stats[I915_MAX_PIPES] = {}; + u32 eir = 0, eir_stuck = 0; u32 hotplug_status = 0; u32 iir; @@ -4536,13 +4616,16 @@ static irqreturn_t i915_irq_handler(int irq, void *arg) * signalled in iir */ i9xx_pipestat_irq_ack(dev_priv, iir, pipe_stats); + if (iir & I915_MASTER_ERROR_INTERRUPT) + i9xx_error_irq_ack(dev_priv, &eir, &eir_stuck); + I915_WRITE(IIR, iir); if (iir & I915_USER_INTERRUPT) notify_ring(dev_priv->engine[RCS]); - if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) - DRM_DEBUG("Command parser error, iir 0x%08x\n", iir); + if (iir & I915_MASTER_ERROR_INTERRUPT) + i9xx_error_irq_handler(dev_priv, eir, eir_stuck); if (hotplug_status) i9xx_hpd_irq_handler(dev_priv, hotplug_status); @@ -4596,14 +4679,14 @@ static int i965_irq_postinstall(struct drm_device *dev) I915_DISPLAY_PORT_INTERRUPT | I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | - I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT); + I915_MASTER_ERROR_INTERRUPT); enable_mask = I915_ASLE_INTERRUPT | I915_DISPLAY_PORT_INTERRUPT | I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | - I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT | + I915_MASTER_ERROR_INTERRUPT | I915_USER_INTERRUPT; if (IS_G4X(dev_priv)) @@ -4663,6 +4746,7 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) do { u32 pipe_stats[I915_MAX_PIPES] = {}; + u32 eir = 0, eir_stuck = 0; u32 hotplug_status = 0; u32 iir; @@ -4679,6 +4763,9 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) * signalled in iir */ i9xx_pipestat_irq_ack(dev_priv, iir, pipe_stats); + if (iir & I915_MASTER_ERROR_INTERRUPT) + i9xx_error_irq_ack(dev_priv, &eir, &eir_stuck); + I915_WRITE(IIR, iir); if (iir & I915_USER_INTERRUPT) @@ -4687,8 +4774,8 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) if (iir & I915_BSD_USER_INTERRUPT) notify_ring(dev_priv->engine[VCS]); - if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) - DRM_DEBUG("Command parser error, iir 0x%08x\n", iir); + if (iir & I915_MASTER_ERROR_INTERRUPT) + i9xx_error_irq_handler(dev_priv, eir, eir_stuck); if (hotplug_status) i9xx_hpd_irq_handler(dev_priv, hotplug_status); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 69b9978d7dda8..097000520a80f 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2871,7 +2871,6 @@ enum i915_power_well_id { #define I915_DISPLAY_PORT_INTERRUPT (1 << 17) #define I915_DISPLAY_PIPE_C_HBLANK_INTERRUPT (1 << 16) #define I915_MASTER_ERROR_INTERRUPT (1 << 15) -#define I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT (1 << 15) #define I915_DISPLAY_PIPE_B_HBLANK_INTERRUPT (1 << 14) #define I915_GMCH_THERMAL_SENSOR_EVENT_INTERRUPT (1 << 14) /* p-state */ #define I915_DISPLAY_PIPE_A_HBLANK_INTERRUPT (1 << 13) -- GitLab From 16659bc53a027f8e4bce6393476849e2bda8b8fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Mon, 11 Jun 2018 23:02:58 +0300 Subject: [PATCH 0655/1506] drm/i915: Unmask and enable master error interrupt on gen2/3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For whatever reason we only unmask and enable the master error interrut on gen4. With the EIR handling fixed let's do that on gen2/3 as well. Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180611200258.27121-4-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak <imre.deak@intel.com> --- drivers/gpu/drm/i915/i915_irq.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 7fb493b7aa742..2fcc00b069154 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -4387,11 +4387,13 @@ static int i8xx_irq_postinstall(struct drm_device *dev) /* Unmask the interrupts that we always want on. */ dev_priv->irq_mask = ~(I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | - I915_DISPLAY_PIPE_B_EVENT_INTERRUPT); + I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | + I915_MASTER_ERROR_INTERRUPT); enable_mask = I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | + I915_MASTER_ERROR_INTERRUPT | I915_USER_INTERRUPT; GEN2_IRQ_INIT(, dev_priv->irq_mask, enable_mask); @@ -4555,12 +4557,14 @@ static int i915_irq_postinstall(struct drm_device *dev) dev_priv->irq_mask = ~(I915_ASLE_INTERRUPT | I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | - I915_DISPLAY_PIPE_B_EVENT_INTERRUPT); + I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | + I915_MASTER_ERROR_INTERRUPT); enable_mask = I915_ASLE_INTERRUPT | I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | + I915_MASTER_ERROR_INTERRUPT | I915_USER_INTERRUPT; if (I915_HAS_HOTPLUG(dev_priv)) { -- GitLab From 63fd659fb1a52262a37293a9a034a912a2406b26 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Wed, 4 Jul 2018 19:55:18 +0100 Subject: [PATCH 0656/1506] drm/i915/gtt: Pull global wc page stash under its own locking Currently, the wc-stash used for providing flushed WC pages ready for constructing the page directories is assumed to be protected by the struct_mutex. However, we want to remove this global lock and so must install a replacement global lock for accessing the global wc-stash (the per-vm stash continues to be guarded by the vm). We need to push ahead on this patch due to an oversight in hastily removing the struct_mutex guard around the igt_ppgtt_alloc selftest. No matter, it will prove very useful (i.e. will be required) in the near future. v2: Restore the onstack stash so that we can drop the vm->mutex in future across the allocation. v3: Restore the lost pagevec_init of the onstack allocation, and repaint function names. v4: Reorder init so that we don't try and use i915_address_space before it is ininitialised. Fixes: 1f6f00238abf ("drm/i915/selftests: Drop struct_mutex around lowlevel pggtt allocation") Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180704185518.4193-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_gem_context.c | 2 +- drivers/gpu/drm/i915/i915_gem_gtt.c | 210 +++++++++++------- drivers/gpu/drm/i915/i915_gem_gtt.h | 10 +- drivers/gpu/drm/i915/selftests/huge_pages.c | 2 +- drivers/gpu/drm/i915/selftests/i915_gem_gtt.c | 2 +- drivers/gpu/drm/i915/selftests/mock_gtt.c | 2 +- 7 files changed, 144 insertions(+), 86 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ce7d063328842..4f9191ab3e126 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -952,7 +952,7 @@ struct i915_gem_mm { /** * Small stash of WC pages */ - struct pagevec wc_stash; + struct pagestash wc_stash; /** * tmpfs instance used for shmem backed objects diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index ccf463ab6562f..985ef70d9416d 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -374,7 +374,7 @@ i915_gem_create_context(struct drm_i915_private *dev_priv, if (USES_FULL_PPGTT(dev_priv)) { struct i915_hw_ppgtt *ppgtt; - ppgtt = i915_ppgtt_create(dev_priv, file_priv, ctx->name); + ppgtt = i915_ppgtt_create(dev_priv, file_priv); if (IS_ERR(ppgtt)) { DRM_DEBUG_DRIVER("PPGTT setup failed (%ld)\n", PTR_ERR(ppgtt)); diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index ba1aed07d6dce..5fb2995905792 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -375,37 +375,70 @@ static gen6_pte_t iris_pte_encode(dma_addr_t addr, return pte; } +static void stash_init(struct pagestash *stash) +{ + pagevec_init(&stash->pvec); + spin_lock_init(&stash->lock); +} + +static struct page *stash_pop_page(struct pagestash *stash) +{ + struct page *page = NULL; + + spin_lock(&stash->lock); + if (likely(stash->pvec.nr)) + page = stash->pvec.pages[--stash->pvec.nr]; + spin_unlock(&stash->lock); + + return page; +} + +static void stash_push_pagevec(struct pagestash *stash, struct pagevec *pvec) +{ + int nr; + + spin_lock_nested(&stash->lock, SINGLE_DEPTH_NESTING); + + nr = min_t(int, pvec->nr, pagevec_space(&stash->pvec)); + memcpy(stash->pvec.pages + stash->pvec.nr, + pvec->pages + pvec->nr - nr, + sizeof(pvec->pages[0]) * nr); + stash->pvec.nr += nr; + + spin_unlock(&stash->lock); + + pvec->nr -= nr; +} + static struct page *vm_alloc_page(struct i915_address_space *vm, gfp_t gfp) { - struct pagevec *pvec = &vm->free_pages; - struct pagevec stash; + struct pagevec stack; + struct page *page; if (I915_SELFTEST_ONLY(should_fail(&vm->fault_attr, 1))) i915_gem_shrink_all(vm->i915); - if (likely(pvec->nr)) - return pvec->pages[--pvec->nr]; + page = stash_pop_page(&vm->free_pages); + if (page) + return page; if (!vm->pt_kmap_wc) return alloc_page(gfp); - /* A placeholder for a specific mutex to guard the WC stash */ - lockdep_assert_held(&vm->i915->drm.struct_mutex); - /* Look in our global stash of WC pages... */ - pvec = &vm->i915->mm.wc_stash; - if (likely(pvec->nr)) - return pvec->pages[--pvec->nr]; + page = stash_pop_page(&vm->i915->mm.wc_stash); + if (page) + return page; /* - * Otherwise batch allocate pages to amoritize cost of set_pages_wc. + * Otherwise batch allocate pages to amortize cost of set_pages_wc. * * We have to be careful as page allocation may trigger the shrinker * (via direct reclaim) which will fill up the WC stash underneath us. * So we add our WB pages into a temporary pvec on the stack and merge * them into the WC stash after all the allocations are complete. */ - pagevec_init(&stash); + pagevec_init(&stack); do { struct page *page; @@ -413,59 +446,67 @@ static struct page *vm_alloc_page(struct i915_address_space *vm, gfp_t gfp) if (unlikely(!page)) break; - stash.pages[stash.nr++] = page; - } while (stash.nr < pagevec_space(pvec)); + stack.pages[stack.nr++] = page; + } while (pagevec_space(&stack)); - if (stash.nr) { - int nr = min_t(int, stash.nr, pagevec_space(pvec)); - struct page **pages = stash.pages + stash.nr - nr; + if (stack.nr && !set_pages_array_wc(stack.pages, stack.nr)) { + page = stack.pages[--stack.nr]; - if (nr && !set_pages_array_wc(pages, nr)) { - memcpy(pvec->pages + pvec->nr, - pages, sizeof(pages[0]) * nr); - pvec->nr += nr; - stash.nr -= nr; - } + /* Merge spare WC pages to the global stash */ + stash_push_pagevec(&vm->i915->mm.wc_stash, &stack); + + /* Push any surplus WC pages onto the local VM stash */ + if (stack.nr) + stash_push_pagevec(&vm->free_pages, &stack); + } - pagevec_release(&stash); + /* Return unwanted leftovers */ + if (unlikely(stack.nr)) { + WARN_ON_ONCE(set_pages_array_wb(stack.pages, stack.nr)); + __pagevec_release(&stack); } - return likely(pvec->nr) ? pvec->pages[--pvec->nr] : NULL; + return page; } static void vm_free_pages_release(struct i915_address_space *vm, bool immediate) { - struct pagevec *pvec = &vm->free_pages; + struct pagevec *pvec = &vm->free_pages.pvec; + struct pagevec stack; + lockdep_assert_held(&vm->free_pages.lock); GEM_BUG_ON(!pagevec_count(pvec)); if (vm->pt_kmap_wc) { - struct pagevec *stash = &vm->i915->mm.wc_stash; - - /* When we use WC, first fill up the global stash and then + /* + * When we use WC, first fill up the global stash and then * only if full immediately free the overflow. */ + stash_push_pagevec(&vm->i915->mm.wc_stash, pvec); - lockdep_assert_held(&vm->i915->drm.struct_mutex); - if (pagevec_space(stash)) { - do { - stash->pages[stash->nr++] = - pvec->pages[--pvec->nr]; - if (!pvec->nr) - return; - } while (pagevec_space(stash)); - - /* As we have made some room in the VM's free_pages, - * we can wait for it to fill again. Unless we are - * inside i915_address_space_fini() and must - * immediately release the pages! - */ - if (!immediate) - return; - } + /* + * As we have made some room in the VM's free_pages, + * we can wait for it to fill again. Unless we are + * inside i915_address_space_fini() and must + * immediately release the pages! + */ + if (pvec->nr <= (immediate ? 0 : PAGEVEC_SIZE - 1)) + return; + /* + * We have to drop the lock to allow ourselves to sleep, + * so take a copy of the pvec and clear the stash for + * others to use it as we sleep. + */ + stack = *pvec; + pagevec_reinit(pvec); + spin_unlock(&vm->free_pages.lock); + + pvec = &stack; set_pages_array_wb(pvec->pages, pvec->nr); + + spin_lock(&vm->free_pages.lock); } __pagevec_release(pvec); @@ -481,8 +522,38 @@ static void vm_free_page(struct i915_address_space *vm, struct page *page) * unconditional might_sleep() for everybody. */ might_sleep(); - if (!pagevec_add(&vm->free_pages, page)) + spin_lock(&vm->free_pages.lock); + if (!pagevec_add(&vm->free_pages.pvec, page)) vm_free_pages_release(vm, false); + spin_unlock(&vm->free_pages.lock); +} + +static void i915_address_space_init(struct i915_address_space *vm, + struct drm_i915_private *dev_priv) +{ + GEM_BUG_ON(!vm->total); + drm_mm_init(&vm->mm, 0, vm->total); + vm->mm.head_node.color = I915_COLOR_UNEVICTABLE; + + stash_init(&vm->free_pages); + + INIT_LIST_HEAD(&vm->active_list); + INIT_LIST_HEAD(&vm->inactive_list); + INIT_LIST_HEAD(&vm->unbound_list); + + list_add_tail(&vm->global_link, &dev_priv->vm_list); +} + +static void i915_address_space_fini(struct i915_address_space *vm) +{ + spin_lock(&vm->free_pages.lock); + if (pagevec_count(&vm->free_pages.pvec)) + vm_free_pages_release(vm, true); + GEM_BUG_ON(pagevec_count(&vm->free_pages.pvec)); + spin_unlock(&vm->free_pages.lock); + + drm_mm_takedown(&vm->mm); + list_del(&vm->global_link); } static int __setup_page_dma(struct i915_address_space *vm, @@ -1562,6 +1633,8 @@ static struct i915_hw_ppgtt *gen8_ppgtt_create(struct drm_i915_private *i915) if (!ppgtt) return ERR_PTR(-ENOMEM); + kref_init(&ppgtt->ref); + ppgtt->vm.i915 = i915; ppgtt->vm.dma = &i915->drm.pdev->dev; @@ -1569,6 +1642,8 @@ static struct i915_hw_ppgtt *gen8_ppgtt_create(struct drm_i915_private *i915) 1ULL << 48 : 1ULL << 32; + i915_address_space_init(&ppgtt->vm, i915); + /* There are only few exceptions for gen >=6. chv and bxt. * And we are not sure about the latter so play safe for now. */ @@ -2068,11 +2143,15 @@ static struct i915_hw_ppgtt *gen6_ppgtt_create(struct drm_i915_private *i915) if (!ppgtt) return ERR_PTR(-ENOMEM); + kref_init(&ppgtt->base.ref); + ppgtt->base.vm.i915 = i915; ppgtt->base.vm.dma = &i915->drm.pdev->dev; ppgtt->base.vm.total = I915_PDES * GEN6_PTES * PAGE_SIZE; + i915_address_space_init(&ppgtt->base.vm, i915); + ppgtt->base.vm.allocate_va_range = gen6_alloc_va_range; ppgtt->base.vm.clear_range = gen6_ppgtt_clear_range; ppgtt->base.vm.insert_entries = gen6_ppgtt_insert_entries; @@ -2105,30 +2184,6 @@ static struct i915_hw_ppgtt *gen6_ppgtt_create(struct drm_i915_private *i915) return ERR_PTR(err); } -static void i915_address_space_init(struct i915_address_space *vm, - struct drm_i915_private *dev_priv, - const char *name) -{ - drm_mm_init(&vm->mm, 0, vm->total); - vm->mm.head_node.color = I915_COLOR_UNEVICTABLE; - - INIT_LIST_HEAD(&vm->active_list); - INIT_LIST_HEAD(&vm->inactive_list); - INIT_LIST_HEAD(&vm->unbound_list); - - list_add_tail(&vm->global_link, &dev_priv->vm_list); - pagevec_init(&vm->free_pages); -} - -static void i915_address_space_fini(struct i915_address_space *vm) -{ - if (pagevec_count(&vm->free_pages)) - vm_free_pages_release(vm, true); - - drm_mm_takedown(&vm->mm); - list_del(&vm->global_link); -} - static void gtt_write_workarounds(struct drm_i915_private *dev_priv) { /* This function is for gtt related workarounds. This function is @@ -2199,8 +2254,7 @@ __hw_ppgtt_create(struct drm_i915_private *i915) struct i915_hw_ppgtt * i915_ppgtt_create(struct drm_i915_private *i915, - struct drm_i915_file_private *fpriv, - const char *name) + struct drm_i915_file_private *fpriv) { struct i915_hw_ppgtt *ppgtt; @@ -2208,8 +2262,6 @@ i915_ppgtt_create(struct drm_i915_private *i915, if (IS_ERR(ppgtt)) return ppgtt; - kref_init(&ppgtt->ref); - i915_address_space_init(&ppgtt->vm, i915, name); ppgtt->vm.file = fpriv; trace_i915_ppgtt_create(&ppgtt->vm); @@ -2788,7 +2840,7 @@ int i915_gem_init_aliasing_ppgtt(struct drm_i915_private *i915) struct i915_hw_ppgtt *ppgtt; int err; - ppgtt = i915_ppgtt_create(i915, ERR_PTR(-EPERM), "[alias]"); + ppgtt = i915_ppgtt_create(i915, ERR_PTR(-EPERM)); if (IS_ERR(ppgtt)) return PTR_ERR(ppgtt); @@ -2918,7 +2970,7 @@ void i915_ggtt_cleanup_hw(struct drm_i915_private *dev_priv) ggtt->vm.cleanup(&ggtt->vm); - pvec = &dev_priv->mm.wc_stash; + pvec = &dev_priv->mm.wc_stash.pvec; if (pvec->nr) { set_pages_array_wb(pvec->pages, pvec->nr); __pagevec_release(pvec); @@ -3518,6 +3570,8 @@ int i915_ggtt_init_hw(struct drm_i915_private *dev_priv) struct i915_ggtt *ggtt = &dev_priv->ggtt; int ret; + stash_init(&dev_priv->mm.wc_stash); + INIT_LIST_HEAD(&dev_priv->vm_list); /* Note that we use page colouring to enforce a guard page at the @@ -3526,7 +3580,7 @@ int i915_ggtt_init_hw(struct drm_i915_private *dev_priv) * and beyond the end of the GTT if we do not provide a guard. */ mutex_lock(&dev_priv->drm.struct_mutex); - i915_address_space_init(&ggtt->vm, dev_priv, "[global]"); + i915_address_space_init(&ggtt->vm, dev_priv); if (!HAS_LLC(dev_priv) && !USES_PPGTT(dev_priv)) ggtt->vm.mm.color_adjust = i915_gtt_color_adjust; mutex_unlock(&dev_priv->drm.struct_mutex); diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index 9a4824cae68d2..f298e72b79ca2 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -270,6 +270,11 @@ struct i915_vma_ops { void (*clear_pages)(struct i915_vma *vma); }; +struct pagestash { + spinlock_t lock; + struct pagevec pvec; +}; + struct i915_address_space { struct drm_mm mm; struct drm_i915_private *i915; @@ -324,7 +329,7 @@ struct i915_address_space { */ struct list_head unbound_list; - struct pagevec free_pages; + struct pagestash free_pages; bool pt_kmap_wc; /* FIXME: Need a more generic return type */ @@ -615,8 +620,7 @@ void i915_ggtt_cleanup_hw(struct drm_i915_private *dev_priv); int i915_ppgtt_init_hw(struct drm_i915_private *dev_priv); void i915_ppgtt_release(struct kref *kref); struct i915_hw_ppgtt *i915_ppgtt_create(struct drm_i915_private *dev_priv, - struct drm_i915_file_private *fpriv, - const char *name); + struct drm_i915_file_private *fpriv); void i915_ppgtt_close(struct i915_address_space *vm); static inline void i915_ppgtt_get(struct i915_hw_ppgtt *ppgtt) { diff --git a/drivers/gpu/drm/i915/selftests/huge_pages.c b/drivers/gpu/drm/i915/selftests/huge_pages.c index b5e87fcdcdae4..39699939587da 100644 --- a/drivers/gpu/drm/i915/selftests/huge_pages.c +++ b/drivers/gpu/drm/i915/selftests/huge_pages.c @@ -1694,7 +1694,7 @@ int i915_gem_huge_page_mock_selftests(void) dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(39)); mutex_lock(&dev_priv->drm.struct_mutex); - ppgtt = i915_ppgtt_create(dev_priv, ERR_PTR(-ENODEV), "mock"); + ppgtt = i915_ppgtt_create(dev_priv, ERR_PTR(-ENODEV)); if (IS_ERR(ppgtt)) { err = PTR_ERR(ppgtt); goto out_unlock; diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c index a7956ecc3e1fe..4bfb0537f9be7 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c @@ -1004,7 +1004,7 @@ static int exercise_ppgtt(struct drm_i915_private *dev_priv, return PTR_ERR(file); mutex_lock(&dev_priv->drm.struct_mutex); - ppgtt = i915_ppgtt_create(dev_priv, file->driver_priv, "mock"); + ppgtt = i915_ppgtt_create(dev_priv, file->driver_priv); if (IS_ERR(ppgtt)) { err = PTR_ERR(ppgtt); goto out_unlock; diff --git a/drivers/gpu/drm/i915/selftests/mock_gtt.c b/drivers/gpu/drm/i915/selftests/mock_gtt.c index 6a7f4da7b523e..0da5b8c6d9126 100644 --- a/drivers/gpu/drm/i915/selftests/mock_gtt.c +++ b/drivers/gpu/drm/i915/selftests/mock_gtt.c @@ -124,7 +124,7 @@ void mock_init_ggtt(struct drm_i915_private *i915) ggtt->vm.vma_ops.set_pages = ggtt_set_pages; ggtt->vm.vma_ops.clear_pages = clear_pages; - i915_address_space_init(&ggtt->vm, i915, "global"); + i915_address_space_init(&ggtt->vm, i915); } void mock_fini_ggtt(struct drm_i915_private *i915) -- GitLab From cef08fdc743c4211aeba69dd23408093d59da241 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 5 Jul 2018 07:56:51 +0100 Subject: [PATCH 0657/1506] drm/i915: Remove defunct i915->vm_list No longer used and can be removed. One less global that currently demands struct_mutex protection. References: e9e7dc4144cd ("drm/i915/gtt: Make gen6 page directories evictable") Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180705065653.20449-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_drv.h | 1 - drivers/gpu/drm/i915/i915_gem_gtt.c | 5 ----- drivers/gpu/drm/i915/i915_gem_gtt.h | 1 - drivers/gpu/drm/i915/selftests/mock_gtt.c | 3 --- 4 files changed, 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 4f9191ab3e126..e236016eef7bb 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1744,7 +1744,6 @@ struct drm_i915_private { struct drm_atomic_state *modeset_restore_state; struct drm_modeset_acquire_ctx reset_ctx; - struct list_head vm_list; /* Global list of all address spaces */ struct i915_ggtt ggtt; /* VM representing the global address space */ struct i915_gem_mm mm; diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 5fb2995905792..a9330de886f8c 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -540,8 +540,6 @@ static void i915_address_space_init(struct i915_address_space *vm, INIT_LIST_HEAD(&vm->active_list); INIT_LIST_HEAD(&vm->inactive_list); INIT_LIST_HEAD(&vm->unbound_list); - - list_add_tail(&vm->global_link, &dev_priv->vm_list); } static void i915_address_space_fini(struct i915_address_space *vm) @@ -553,7 +551,6 @@ static void i915_address_space_fini(struct i915_address_space *vm) spin_unlock(&vm->free_pages.lock); drm_mm_takedown(&vm->mm); - list_del(&vm->global_link); } static int __setup_page_dma(struct i915_address_space *vm, @@ -3572,8 +3569,6 @@ int i915_ggtt_init_hw(struct drm_i915_private *dev_priv) stash_init(&dev_priv->mm.wc_stash); - INIT_LIST_HEAD(&dev_priv->vm_list); - /* Note that we use page colouring to enforce a guard page at the * end of the address space. This is required as the CS may prefetch * beyond the end of the batch buffer, across the page boundary, diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index f298e72b79ca2..feda45dfd4811 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -288,7 +288,6 @@ struct i915_address_space { * assign blame. */ struct drm_i915_file_private *file; - struct list_head global_link; u64 total; /* size addr space maps (ex. 2GB for ggtt) */ u64 reserved; /* size addr space reserved */ diff --git a/drivers/gpu/drm/i915/selftests/mock_gtt.c b/drivers/gpu/drm/i915/selftests/mock_gtt.c index 0da5b8c6d9126..07df5c399ec11 100644 --- a/drivers/gpu/drm/i915/selftests/mock_gtt.c +++ b/drivers/gpu/drm/i915/selftests/mock_gtt.c @@ -74,7 +74,6 @@ mock_ppgtt(struct drm_i915_private *i915, INIT_LIST_HEAD(&ppgtt->vm.inactive_list); INIT_LIST_HEAD(&ppgtt->vm.unbound_list); - INIT_LIST_HEAD(&ppgtt->vm.global_link); drm_mm_init(&ppgtt->vm.mm, 0, ppgtt->vm.total); ppgtt->vm.clear_range = nop_clear_range; @@ -106,8 +105,6 @@ void mock_init_ggtt(struct drm_i915_private *i915) { struct i915_ggtt *ggtt = &i915->ggtt; - INIT_LIST_HEAD(&i915->vm_list); - ggtt->vm.i915 = i915; ggtt->gmadr = (struct resource) DEFINE_RES_MEM(0, 2048 * PAGE_SIZE); -- GitLab From eae4c9445354602926ff7cc4702c2516e2485a94 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 5 Jul 2018 07:56:52 +0100 Subject: [PATCH 0658/1506] drm/i915/selftests: Use full release for local ppgtt allocation We can now use the full release mechanism (i915_ppgtt_put) for our local ppgtt allocation in igt_ppgtt_alloc. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180705065653.20449-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/selftests/i915_gem_gtt.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c index 4bfb0537f9be7..e108fe4e0fd94 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c @@ -202,9 +202,8 @@ static int igt_ppgtt_alloc(void *arg) err_ppgtt_cleanup: mutex_lock(&dev_priv->drm.struct_mutex); - ppgtt->vm.cleanup(&ppgtt->vm); + i915_ppgtt_put(ppgtt); mutex_unlock(&dev_priv->drm.struct_mutex); - kfree(ppgtt); return err; } -- GitLab From 0f17d5dd2199555830482b638a5fc8bf915f2f10 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 5 Jul 2018 07:56:53 +0100 Subject: [PATCH 0659/1506] drm/i915/selftests: Replace open-coded i915_address_space_init() Use i915_address_space_init() rather than open-code it inside mock_ppgtt() as we will forget to keep it in sync. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180705065653.20449-3-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/selftests/mock_gtt.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/selftests/mock_gtt.c b/drivers/gpu/drm/i915/selftests/mock_gtt.c index 07df5c399ec11..a140ea5c3a7c5 100644 --- a/drivers/gpu/drm/i915/selftests/mock_gtt.c +++ b/drivers/gpu/drm/i915/selftests/mock_gtt.c @@ -70,11 +70,7 @@ mock_ppgtt(struct drm_i915_private *i915, ppgtt->vm.total = round_down(U64_MAX, PAGE_SIZE); ppgtt->vm.file = ERR_PTR(-ENODEV); - INIT_LIST_HEAD(&ppgtt->vm.active_list); - INIT_LIST_HEAD(&ppgtt->vm.inactive_list); - INIT_LIST_HEAD(&ppgtt->vm.unbound_list); - - drm_mm_init(&ppgtt->vm.mm, 0, ppgtt->vm.total); + i915_address_space_init(&ppgtt->vm, i915); ppgtt->vm.clear_range = nop_clear_range; ppgtt->vm.insert_page = mock_insert_page; -- GitLab From a132b5a5081ca106193a02e0835e01db7c4055ec Mon Sep 17 00:00:00 2001 From: Sjoerd Simons <sjoerd.simons@collabora.co.uk> Date: Fri, 30 Mar 2018 15:15:53 +0200 Subject: [PATCH 0660/1506] drm/tilcdc: Defer probe if there are no connectors During probe there may not be any connectors yet if e.g. the panel failed or hasn't been probed yet. I hitting this in practice the panels probing was being delayed due to using a gpio backlight. Fix this by returning -EPROBE_DEFER so the probing will be retried. Signed-off-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk> Signed-off-by: Jyri Sarha <jsarha@ti.com> --- drivers/gpu/drm/tilcdc/tilcdc_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index b8a5e4ed22e6d..0fb300d41a09c 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -378,7 +378,7 @@ static int tilcdc_init(struct drm_driver *ddrv, struct device *dev) if (!priv->external_connector && ((priv->num_encoders == 0) || (priv->num_connectors == 0))) { dev_err(dev, "no encoders/connectors found\n"); - ret = -ENXIO; + ret = -EPROBE_DEFER; goto init_failed; } -- GitLab From 1c7c5fd916a0ff66501467f1e8e79d3ff8eca112 Mon Sep 17 00:00:00 2001 From: Haneen Mohammed <hamohammed.sa@gmail.com> Date: Mon, 14 May 2018 17:33:46 +0300 Subject: [PATCH 0661/1506] drm/vkms: Introduce basic VKMS driver This patch introduces Virtual Kernel Mode-Setting (VKMS) driver. It creates a very basic kms driver with 1 crtc/encoder/connector/plane. VKMS driver would be useful for testing, or for running X (or similar) on headless machines and be able to still use the GPU. Thus it enables a virtual display without the need for hardware display capability. Signed-off-by: Haneen Mohammed <hamohammed.sa@gmail.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180514143346.GA21695@haneen-vb --- drivers/gpu/drm/Kconfig | 6 ++ drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/vkms/Makefile | 3 + drivers/gpu/drm/vkms/vkms_drv.c | 146 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/vkms/vkms_drv.h | 13 +++ 5 files changed, 169 insertions(+) create mode 100644 drivers/gpu/drm/vkms/Makefile create mode 100644 drivers/gpu/drm/vkms/vkms_drv.c create mode 100644 drivers/gpu/drm/vkms/vkms_drv.h diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 2a72d2feb76d3..7db3d82cbb27f 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -213,6 +213,12 @@ config DRM_VGEM as used by Mesa's software renderer for enhanced performance. If M is selected the module will be called vgem. +config DRM_VKMS + tristate "Virtual KMS" + depends on DRM + help + Choose this option to get a virtual kernal mode-setting driver. + If M is selected the module will be called vkms. source "drivers/gpu/drm/exynos/Kconfig" diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 69c13517ea3a6..6ae535ca09141 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -69,6 +69,7 @@ obj-$(CONFIG_DRM_SAVAGE)+= savage/ obj-$(CONFIG_DRM_VMWGFX)+= vmwgfx/ obj-$(CONFIG_DRM_VIA) +=via/ obj-$(CONFIG_DRM_VGEM) += vgem/ +obj-$(CONFIG_DRM_VKMS) += vkms/ obj-$(CONFIG_DRM_NOUVEAU) +=nouveau/ obj-$(CONFIG_DRM_EXYNOS) +=exynos/ obj-$(CONFIG_DRM_ROCKCHIP) +=rockchip/ diff --git a/drivers/gpu/drm/vkms/Makefile b/drivers/gpu/drm/vkms/Makefile new file mode 100644 index 0000000000000..2aef948d3a343 --- /dev/null +++ b/drivers/gpu/drm/vkms/Makefile @@ -0,0 +1,3 @@ +vkms-y := vkms_drv.o + +obj-$(CONFIG_DRM_VKMS) += vkms.o diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c new file mode 100644 index 0000000000000..b1df08ed23a0c --- /dev/null +++ b/drivers/gpu/drm/vkms/vkms_drv.c @@ -0,0 +1,146 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/module.h> +#include <drm/drmP.h> +#include <drm/drm_gem.h> +#include <drm/drm_crtc_helper.h> +#include "vkms_drv.h" + +#define DRIVER_NAME "vkms" +#define DRIVER_DESC "Virtual Kernel Mode Setting" +#define DRIVER_DATE "20180514" +#define DRIVER_MAJOR 1 +#define DRIVER_MINOR 0 + +static struct vkms_device *vkms_device; + +static const struct file_operations vkms_driver_fops = { + .owner = THIS_MODULE, + .open = drm_open, + .mmap = drm_gem_mmap, + .unlocked_ioctl = drm_ioctl, + .compat_ioctl = drm_compat_ioctl, + .poll = drm_poll, + .read = drm_read, + .llseek = no_llseek, + .release = drm_release, +}; + +static void vkms_release(struct drm_device *dev) +{ + struct vkms_device *vkms = container_of(dev, struct vkms_device, drm); + + platform_device_unregister(vkms->platform); + drm_mode_config_cleanup(&vkms->drm); + drm_dev_fini(&vkms->drm); +} + +struct drm_driver vkms_driver = { + .driver_features = DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_GEM, + .release = vkms_release, + .fops = &vkms_driver_fops, + + .name = DRIVER_NAME, + .desc = DRIVER_DESC, + .date = DRIVER_DATE, + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, +}; + +static const u32 vkms_formats[] = { + DRM_FORMAT_XRGB8888, +}; + +static void vkms_connector_destroy(struct drm_connector *connector) +{ + drm_connector_unregister(connector); + drm_connector_cleanup(connector); +} + +static const struct drm_connector_funcs vkms_connector_funcs = { + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = vkms_connector_destroy, +}; + +static int __init vkms_init(void) +{ + int ret; + + vkms_device = kzalloc(sizeof(*vkms_device), GFP_KERNEL); + if (!vkms_device) + return -ENOMEM; + + ret = drm_dev_init(&vkms_device->drm, &vkms_driver, NULL); + if (ret) + goto out_free; + + vkms_device->platform = + platform_device_register_simple(DRIVER_NAME, -1, NULL, 0); + if (IS_ERR(vkms_device->platform)) { + ret = PTR_ERR(vkms_device->platform); + goto out_fini; + } + + drm_mode_config_init(&vkms_device->drm); + + ret = drm_connector_init(&vkms_device->drm, &vkms_device->connector, + &vkms_connector_funcs, + DRM_MODE_CONNECTOR_VIRTUAL); + if (ret < 0) { + DRM_ERROR("Failed to init connector\n"); + goto out_unregister; + } + + ret = drm_simple_display_pipe_init(&vkms_device->drm, + &vkms_device->pipe, + NULL, + vkms_formats, + ARRAY_SIZE(vkms_formats), + NULL, + &vkms_device->connector); + if (ret < 0) { + DRM_ERROR("Cannot setup simple display pipe\n"); + goto out_unregister; + } + + ret = drm_dev_register(&vkms_device->drm, 0); + if (ret) + goto out_unregister; + + drm_connector_register(&vkms_device->connector); + + return 0; + +out_unregister: + platform_device_unregister(vkms_device->platform); +out_fini: + drm_dev_fini(&vkms_device->drm); +out_free: + kfree(vkms_device); + + return ret; +} + +static void __exit vkms_exit(void) +{ + if (!vkms_device) { + DRM_INFO("vkms_device is NULL.\n"); + return; + } + + drm_dev_unregister(&vkms_device->drm); + drm_dev_put(&vkms_device->drm); + + kfree(vkms_device); +} + +module_init(vkms_init); +module_exit(vkms_exit); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h new file mode 100644 index 0000000000000..c77c5bf5032ac --- /dev/null +++ b/drivers/gpu/drm/vkms/vkms_drv.h @@ -0,0 +1,13 @@ +#ifndef _VKMS_DRV_H_ +#define _VKMS_DRV_H_ + +#include <drm/drm_simple_kms_helper.h> + +struct vkms_device { + struct drm_device drm; + struct platform_device *platform; + struct drm_simple_display_pipe pipe; + struct drm_connector connector; +}; + +#endif /* _VKMS_DRV_H_ */ -- GitLab From 41111ce17ee7277cb7451e8a21e319220afc130d Mon Sep 17 00:00:00 2001 From: kbuild test robot <lkp@intel.com> Date: Tue, 15 May 2018 19:30:52 +0800 Subject: [PATCH 0662/1506] drm/vkms: vkms_driver can be static Fixes: 58d8108f080c ("drm/vkms: Introduce basic VKMS driver") Signed-off-by: Fengguang Wu <fengguang.wu@intel.com> Acked-by: Haneen Mohammed <hamohammed.sa@gmail.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180515113052.GA111532@lkp-ib04 --- drivers/gpu/drm/vkms/vkms_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c index b1df08ed23a0c..35517b09538ed 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.c +++ b/drivers/gpu/drm/vkms/vkms_drv.c @@ -40,7 +40,7 @@ static void vkms_release(struct drm_device *dev) drm_dev_fini(&vkms->drm); } -struct drm_driver vkms_driver = { +static struct drm_driver vkms_driver = { .driver_features = DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_GEM, .release = vkms_release, .fops = &vkms_driver_fops, -- GitLab From c04372ea4abd83ec6c86083f2afe9322515ee293 Mon Sep 17 00:00:00 2001 From: Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com> Date: Wed, 16 May 2018 20:55:36 -0300 Subject: [PATCH 0663/1506] drm/vkms: Add mode_config initialization Initialize minimum and maximum width and height of the frame buffers with default values. Signed-off-by: Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com> Reviewed-by: Haneen Mohammed <hamohammed.sa@gmail.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.com> Link: https://patchwork.freedesktop.org/patch/msgid/75c55df671f24b037f9172700b479f4bb2fa7c92.1526514457.git.rodrigosiqueiramelo@gmail.com --- drivers/gpu/drm/vkms/vkms_drv.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c index 35517b09538ed..aec3f180f96d1 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.c +++ b/drivers/gpu/drm/vkms/vkms_drv.c @@ -9,6 +9,7 @@ #include <drm/drmP.h> #include <drm/drm_gem.h> #include <drm/drm_crtc_helper.h> +#include <drm/drm_atomic_helper.h> #include "vkms_drv.h" #define DRIVER_NAME "vkms" @@ -17,6 +18,12 @@ #define DRIVER_MAJOR 1 #define DRIVER_MINOR 0 +#define XRES_MIN 32 +#define YRES_MIN 32 + +#define XRES_MAX 8192 +#define YRES_MAX 8192 + static struct vkms_device *vkms_device; static const struct file_operations vkms_driver_fops = { @@ -67,6 +74,11 @@ static const struct drm_connector_funcs vkms_connector_funcs = { .destroy = vkms_connector_destroy, }; +static const struct drm_mode_config_funcs vkms_mode_funcs = { + .atomic_check = drm_atomic_helper_check, + .atomic_commit = drm_atomic_helper_commit, +}; + static int __init vkms_init(void) { int ret; @@ -87,6 +99,11 @@ static int __init vkms_init(void) } drm_mode_config_init(&vkms_device->drm); + vkms_device->drm.mode_config.funcs = &vkms_mode_funcs; + vkms_device->drm.mode_config.min_width = XRES_MIN; + vkms_device->drm.mode_config.min_height = YRES_MIN; + vkms_device->drm.mode_config.max_width = XRES_MAX; + vkms_device->drm.mode_config.max_height = YRES_MAX; ret = drm_connector_init(&vkms_device->drm, &vkms_device->connector, &vkms_connector_funcs, -- GitLab From 854502fa0a38dc77c9e855c95d239a8fd50a9b13 Mon Sep 17 00:00:00 2001 From: Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com> Date: Wed, 16 May 2018 20:56:21 -0300 Subject: [PATCH 0664/1506] drm/vkms: Add basic CRTC initialization This commit adds the essential infrastructure for around CRTCs which is composed of: a new data struct for output data information, a function for creating planes, and a simple encoder attached to the connector. Finally, due to the introduction of a new initialization function, connectors were moved from vkms_drv.c to vkms_display.c. Signed-off-by: Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com> Reviewed-by: Haneen Mohammed <hamohammed.sa@gmail.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.com> Link: https://patchwork.freedesktop.org/patch/msgid/b6e27bc6a54f5cb340658fa5969f7b48fbfbf1b7.1526514457.git.rodrigosiqueiramelo@gmail.com --- drivers/gpu/drm/vkms/Makefile | 2 +- drivers/gpu/drm/vkms/vkms_crtc.c | 35 ++++++++++++ drivers/gpu/drm/vkms/vkms_drv.c | 60 ++++++-------------- drivers/gpu/drm/vkms/vkms_drv.h | 24 +++++++- drivers/gpu/drm/vkms/vkms_output.c | 91 ++++++++++++++++++++++++++++++ drivers/gpu/drm/vkms/vkms_plane.c | 46 +++++++++++++++ 6 files changed, 211 insertions(+), 47 deletions(-) create mode 100644 drivers/gpu/drm/vkms/vkms_crtc.c create mode 100644 drivers/gpu/drm/vkms/vkms_output.c create mode 100644 drivers/gpu/drm/vkms/vkms_plane.c diff --git a/drivers/gpu/drm/vkms/Makefile b/drivers/gpu/drm/vkms/Makefile index 2aef948d3a343..3f774a6a9c581 100644 --- a/drivers/gpu/drm/vkms/Makefile +++ b/drivers/gpu/drm/vkms/Makefile @@ -1,3 +1,3 @@ -vkms-y := vkms_drv.o +vkms-y := vkms_drv.o vkms_plane.o vkms_output.o vkms_crtc.o obj-$(CONFIG_DRM_VKMS) += vkms.o diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c b/drivers/gpu/drm/vkms/vkms_crtc.c new file mode 100644 index 0000000000000..bf76cd39ece79 --- /dev/null +++ b/drivers/gpu/drm/vkms/vkms_crtc.c @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include "vkms_drv.h" +#include <drm/drm_atomic_helper.h> +#include <drm/drm_crtc_helper.h> + +static const struct drm_crtc_funcs vkms_crtc_funcs = { + .set_config = drm_atomic_helper_set_config, + .destroy = drm_crtc_cleanup, + .page_flip = drm_atomic_helper_page_flip, + .reset = drm_atomic_helper_crtc_reset, + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, +}; + +int vkms_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, + struct drm_plane *primary, struct drm_plane *cursor) +{ + int ret; + + ret = drm_crtc_init_with_planes(dev, crtc, primary, cursor, + &vkms_crtc_funcs, NULL); + if (ret) { + DRM_ERROR("Failed to init CRTC\n"); + return ret; + } + + return ret; +} diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c index aec3f180f96d1..070613e329340 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.c +++ b/drivers/gpu/drm/vkms/vkms_drv.c @@ -6,7 +6,6 @@ */ #include <linux/module.h> -#include <drm/drmP.h> #include <drm/drm_gem.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_atomic_helper.h> @@ -59,25 +58,24 @@ static struct drm_driver vkms_driver = { .minor = DRIVER_MINOR, }; -static const u32 vkms_formats[] = { - DRM_FORMAT_XRGB8888, +static const struct drm_mode_config_funcs vkms_mode_funcs = { + .atomic_check = drm_atomic_helper_check, + .atomic_commit = drm_atomic_helper_commit, }; -static void vkms_connector_destroy(struct drm_connector *connector) +static int vkms_modeset_init(struct vkms_device *vkmsdev) { - drm_connector_unregister(connector); - drm_connector_cleanup(connector); -} + struct drm_device *dev = &vkmsdev->drm; -static const struct drm_connector_funcs vkms_connector_funcs = { - .fill_modes = drm_helper_probe_single_connector_modes, - .destroy = vkms_connector_destroy, -}; + drm_mode_config_init(dev); + dev->mode_config.funcs = &vkms_mode_funcs; + dev->mode_config.min_width = XRES_MIN; + dev->mode_config.min_height = YRES_MIN; + dev->mode_config.max_width = XRES_MAX; + dev->mode_config.max_height = YRES_MAX; -static const struct drm_mode_config_funcs vkms_mode_funcs = { - .atomic_check = drm_atomic_helper_check, - .atomic_commit = drm_atomic_helper_commit, -}; + return vkms_output_init(vkmsdev); +} static int __init vkms_init(void) { @@ -98,48 +96,24 @@ static int __init vkms_init(void) goto out_fini; } - drm_mode_config_init(&vkms_device->drm); - vkms_device->drm.mode_config.funcs = &vkms_mode_funcs; - vkms_device->drm.mode_config.min_width = XRES_MIN; - vkms_device->drm.mode_config.min_height = YRES_MIN; - vkms_device->drm.mode_config.max_width = XRES_MAX; - vkms_device->drm.mode_config.max_height = YRES_MAX; - - ret = drm_connector_init(&vkms_device->drm, &vkms_device->connector, - &vkms_connector_funcs, - DRM_MODE_CONNECTOR_VIRTUAL); - if (ret < 0) { - DRM_ERROR("Failed to init connector\n"); - goto out_unregister; - } - - ret = drm_simple_display_pipe_init(&vkms_device->drm, - &vkms_device->pipe, - NULL, - vkms_formats, - ARRAY_SIZE(vkms_formats), - NULL, - &vkms_device->connector); - if (ret < 0) { - DRM_ERROR("Cannot setup simple display pipe\n"); + ret = vkms_modeset_init(vkms_device); + if (ret) goto out_unregister; - } ret = drm_dev_register(&vkms_device->drm, 0); if (ret) goto out_unregister; - drm_connector_register(&vkms_device->connector); - return 0; out_unregister: platform_device_unregister(vkms_device->platform); + out_fini: drm_dev_fini(&vkms_device->drm); + out_free: kfree(vkms_device); - return ret; } diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h index c77c5bf5032ac..b0f9d2e61a422 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.h +++ b/drivers/gpu/drm/vkms/vkms_drv.h @@ -1,13 +1,31 @@ #ifndef _VKMS_DRV_H_ #define _VKMS_DRV_H_ -#include <drm/drm_simple_kms_helper.h> +#include <drm/drmP.h> +#include <drm/drm.h> +#include <drm/drm_encoder.h> + +static const u32 vkms_formats[] = { + DRM_FORMAT_XRGB8888, +}; + +struct vkms_output { + struct drm_crtc crtc; + struct drm_encoder encoder; + struct drm_connector connector; +}; struct vkms_device { struct drm_device drm; struct platform_device *platform; - struct drm_simple_display_pipe pipe; - struct drm_connector connector; + struct vkms_output output; }; +int vkms_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, + struct drm_plane *primary, struct drm_plane *cursor); + +int vkms_output_init(struct vkms_device *vkmsdev); + +struct drm_plane *vkms_plane_init(struct vkms_device *vkmsdev); + #endif /* _VKMS_DRV_H_ */ diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c new file mode 100644 index 0000000000000..48143eac3c12e --- /dev/null +++ b/drivers/gpu/drm/vkms/vkms_output.c @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include "vkms_drv.h" +#include <drm/drm_crtc_helper.h> + +static void vkms_connector_destroy(struct drm_connector *connector) +{ + drm_connector_unregister(connector); + drm_connector_cleanup(connector); +} + +static const struct drm_connector_funcs vkms_connector_funcs = { + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = vkms_connector_destroy, +}; + +static const struct drm_encoder_funcs vkms_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +int vkms_output_init(struct vkms_device *vkmsdev) +{ + struct vkms_output *output = &vkmsdev->output; + struct drm_device *dev = &vkmsdev->drm; + struct drm_connector *connector = &output->connector; + struct drm_encoder *encoder = &output->encoder; + struct drm_crtc *crtc = &output->crtc; + struct drm_plane *primary; + int ret; + + primary = vkms_plane_init(vkmsdev); + if (IS_ERR(primary)) + return PTR_ERR(primary); + + ret = vkms_crtc_init(dev, crtc, primary, NULL); + if (ret) + goto err_crtc; + + ret = drm_connector_init(dev, connector, &vkms_connector_funcs, + DRM_MODE_CONNECTOR_VIRTUAL); + if (ret) { + DRM_ERROR("Failed to init connector\n"); + goto err_connector; + } + + ret = drm_connector_register(connector); + if (ret) { + DRM_ERROR("Failed to register connector\n"); + goto err_connector_register; + } + + ret = drm_encoder_init(dev, encoder, &vkms_encoder_funcs, + DRM_MODE_ENCODER_VIRTUAL, NULL); + if (ret) { + DRM_ERROR("Failed to init encoder\n"); + goto err_encoder; + } + encoder->possible_crtcs = 1; + + ret = drm_mode_connector_attach_encoder(connector, encoder); + if (ret) { + DRM_ERROR("Failed to attach connector to encoder\n"); + goto err_attach; + } + + drm_mode_config_reset(dev); + + return 0; + +err_attach: + drm_encoder_cleanup(encoder); + +err_encoder: + drm_connector_unregister(connector); + +err_connector_register: + drm_connector_cleanup(connector); + +err_connector: + drm_crtc_cleanup(crtc); + +err_crtc: + drm_plane_cleanup(primary); + return ret; +} diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_plane.c new file mode 100644 index 0000000000000..2c25b1d6ab5be --- /dev/null +++ b/drivers/gpu/drm/vkms/vkms_plane.c @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include "vkms_drv.h" +#include <drm/drm_plane_helper.h> +#include <drm/drm_atomic_helper.h> + +static const struct drm_plane_funcs vkms_plane_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, +}; + +struct drm_plane *vkms_plane_init(struct vkms_device *vkmsdev) +{ + struct drm_device *dev = &vkmsdev->drm; + struct drm_plane *plane; + const u32 *formats; + int ret, nformats; + + plane = kzalloc(sizeof(*plane), GFP_KERNEL); + if (!plane) + return ERR_PTR(-ENOMEM); + + formats = vkms_formats; + nformats = ARRAY_SIZE(vkms_formats); + + ret = drm_universal_plane_init(dev, plane, 0, + &vkms_plane_funcs, + formats, nformats, + NULL, DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) { + kfree(plane); + return ERR_PTR(ret); + } + + return plane; +} -- GitLab From c91b007ed137c8497fa89993cc6757a8e81ff99b Mon Sep 17 00:00:00 2001 From: Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com> Date: Wed, 16 May 2018 20:56:40 -0300 Subject: [PATCH 0665/1506] drm/vkms: Add extra information about vkms Add the following additional information: authors and description in Kconfig. Signed-off-by: Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com> Reviewed-by: Haneen Mohammed <hamohammed.sa@gmail.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.com> Link: https://patchwork.freedesktop.org/patch/msgid/180770375b0537f1ba1857bdb7fdc71dd201882e.1526514457.git.rodrigosiqueiramelo@gmail.com --- drivers/gpu/drm/Kconfig | 8 ++++++-- drivers/gpu/drm/vkms/vkms_drv.c | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 7db3d82cbb27f..10f9f01123ead 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -214,10 +214,14 @@ config DRM_VGEM If M is selected the module will be called vgem. config DRM_VKMS - tristate "Virtual KMS" + tristate "Virtual KMS (EXPERIMENTAL)" depends on DRM + default n help - Choose this option to get a virtual kernal mode-setting driver. + Virtual Kernel Mode-Setting (VKMS) is used for testing or for + running GPU in a headless machines. Choose this option to get + a VKMS. + If M is selected the module will be called vkms. source "drivers/gpu/drm/exynos/Kconfig" diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c index 070613e329340..740a4cbfed91c 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.c +++ b/drivers/gpu/drm/vkms/vkms_drv.c @@ -133,5 +133,7 @@ static void __exit vkms_exit(void) module_init(vkms_init); module_exit(vkms_exit); +MODULE_AUTHOR("Haneen Mohammed <hamohammed.sa@gmail.com>"); +MODULE_AUTHOR("Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com>"); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -- GitLab From 27efd2566cb89b7909366dbb88add8fb1e3d24e2 Mon Sep 17 00:00:00 2001 From: Madhav Chauhan <madhav.chauhan@intel.com> Date: Thu, 5 Jul 2018 18:31:48 +0530 Subject: [PATCH 0666/1506] drm/i915/icl: Define register for DSI PLL This patch adds the new registers and corresponding bit definitions which will be used for programming/enable DSI PLL. v2: Review comments from Jani N - Fix spaces while defining ICL_ESC_CLK_DIV_MASK - Define shift and mask for bitfields. Signed-off-by: Madhav Chauhan <madhav.chauhan@intel.com> Reviewed-by: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/1530795727-28644-2-git-send-email-madhav.chauhan@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 097000520a80f..dc953ee7e3b3a 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -9538,6 +9538,21 @@ enum skl_power_gate { #define MIPIO_TXESC_CLK_DIV2 _MMIO(0x160008) #define GLK_TX_ESC_CLK_DIV2_MASK 0x3FF +#define _ICL_DSI_ESC_CLK_DIV0 0x6b090 +#define _ICL_DSI_ESC_CLK_DIV1 0x6b890 +#define ICL_DSI_ESC_CLK_DIV(port) _MMIO_PORT((port), \ + _ICL_DSI_ESC_CLK_DIV0, \ + _ICL_DSI_ESC_CLK_DIV1) +#define _ICL_DPHY_ESC_CLK_DIV0 0x162190 +#define _ICL_DPHY_ESC_CLK_DIV1 0x6C190 +#define ICL_DPHY_ESC_CLK_DIV(port) _MMIO_PORT((port), \ + _ICL_DPHY_ESC_CLK_DIV0, \ + _ICL_DPHY_ESC_CLK_DIV1) +#define ICL_BYTE_CLK_PER_ESC_CLK_MASK (0x1f << 16) +#define ICL_BYTE_CLK_PER_ESC_CLK_SHIFT 16 +#define ICL_ESC_CLK_DIV_MASK 0x1ff +#define ICL_ESC_CLK_DIV_SHIFT 0 + /* Gen4+ Timestamp and Pipe Frame time stamp registers */ #define GEN4_TIMESTAMP _MMIO(0x2358) #define ILK_TIMESTAMP_HI _MMIO(0x70070) -- GitLab From f0d759f038dcced7dfb756dc54c224f09ad062a2 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" <gustavo@embeddedor.com> Date: Thu, 28 Jun 2018 17:35:41 -0500 Subject: [PATCH 0667/1506] drm/i915: Mark expected switch fall-throughs In preparation to enabling -Wimplicit-fallthrough, mark switch cases where we are expecting to fall through. Addresses-Coverity-ID: 141432 Addresses-Coverity-ID: 141433 Addresses-Coverity-ID: 141434 Addresses-Coverity-ID: 141435 Addresses-Coverity-ID: 141436 Addresses-Coverity-ID: 1357360 Addresses-Coverity-ID: 1357403 Addresses-Coverity-ID: 1357433 Addresses-Coverity-ID: 1392622 Addresses-Coverity-ID: 1415273 Addresses-Coverity-ID: 1435752 Addresses-Coverity-ID: 1441500 Addresses-Coverity-ID: 1454596 Signed-off-by: Gustavo A. R. Silva <gustavo@embeddedor.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180628223541.GA17665@embeddedor.com --- drivers/gpu/drm/i915/i915_gem.c | 1 + drivers/gpu/drm/i915/i915_gem_stolen.c | 1 + drivers/gpu/drm/i915/intel_cdclk.c | 5 +++++ drivers/gpu/drm/i915/intel_ddi.c | 1 + drivers/gpu/drm/i915/intel_display.c | 2 ++ drivers/gpu/drm/i915/intel_dpll_mgr.c | 3 +++ drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_engine_cs.c | 1 + drivers/gpu/drm/i915/intel_runtime_pm.c | 1 + drivers/gpu/drm/i915/intel_sdvo.c | 6 ++++++ 10 files changed, 22 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 048b722cf27cf..0c0a1a959d0bd 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2120,6 +2120,7 @@ vm_fault_t i915_gem_fault(struct vm_fault *vmf) */ if (!i915_terminally_wedged(&dev_priv->gpu_error)) return VM_FAULT_SIGBUS; + /* else: fall through */ case -EAGAIN: /* * EAGAIN means the gpu is hung and we'll wait for the error diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index 79a347295e006..055f8687776d0 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -254,6 +254,7 @@ static void vlv_get_stolen_reserved(struct drm_i915_private *dev_priv, switch (reg_val & GEN7_STOLEN_RESERVED_SIZE_MASK) { default: MISSING_CASE(reg_val & GEN7_STOLEN_RESERVED_SIZE_MASK); + /* fall through */ case GEN7_STOLEN_RESERVED_1M: *size = 1024 * 1024; break; diff --git a/drivers/gpu/drm/i915/intel_cdclk.c b/drivers/gpu/drm/i915/intel_cdclk.c index bf9433d7964dc..29075c7634280 100644 --- a/drivers/gpu/drm/i915/intel_cdclk.c +++ b/drivers/gpu/drm/i915/intel_cdclk.c @@ -316,6 +316,7 @@ static void pnv_get_cdclk(struct drm_i915_private *dev_priv, break; default: DRM_ERROR("Unknown pnv display core clock 0x%04x\n", gcfgc); + /* fall through */ case GC_DISPLAY_CLOCK_133_MHZ_PNV: cdclk_state->cdclk = 133333; break; @@ -1797,6 +1798,7 @@ static int icl_calc_cdclk(int min_cdclk, unsigned int ref) switch (ref) { default: MISSING_CASE(ref); + /* fall through */ case 24000: ranges = ranges_24; break; @@ -1824,6 +1826,7 @@ static int icl_calc_cdclk_pll_vco(struct drm_i915_private *dev_priv, int cdclk) switch (cdclk) { default: MISSING_CASE(cdclk); + /* fall through */ case 307200: case 556800: case 652800: @@ -1896,6 +1899,7 @@ static u8 icl_calc_voltage_level(int cdclk) return 1; default: MISSING_CASE(cdclk); + /* fall through */ case 652800: case 648000: return 2; @@ -1913,6 +1917,7 @@ static void icl_get_cdclk(struct drm_i915_private *dev_priv, switch (val & ICL_DSSM_CDCLK_PLL_REFCLK_MASK) { default: MISSING_CASE(val); + /* fall through */ case ICL_DSSM_CDCLK_PLL_REFCLK_24MHz: cdclk_state->ref = 24000; break; diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 0319825b725ba..c74b01a52082b 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1069,6 +1069,7 @@ static uint32_t icl_pll_to_ddi_pll_sel(struct intel_encoder *encoder, switch (id) { default: MISSING_CASE(id); + /* fall through */ case DPLL_ID_ICL_DPLL0: case DPLL_ID_ICL_DPLL1: return DDI_CLK_SEL_NONE; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ce7646265b503..12102224f47ae 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9360,6 +9360,7 @@ static bool hsw_get_transcoder_state(struct intel_crtc *crtc, switch (tmp & TRANS_DDI_EDP_INPUT_MASK) { default: WARN(1, "unknown pipe linked to edp transcoder\n"); + /* fall through */ case TRANS_DDI_EDP_INPUT_A_ONOFF: case TRANS_DDI_EDP_INPUT_A_ON: trans_edp_pipe = PIPE_A; @@ -11024,6 +11025,7 @@ static bool check_digital_port_conflicts(struct drm_atomic_state *state) case INTEL_OUTPUT_DDI: if (WARN_ON(!HAS_DDI(to_i915(dev)))) break; + /* else: fall through */ case INTEL_OUTPUT_DP: case INTEL_OUTPUT_HDMI: case INTEL_OUTPUT_EDP: diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c index 57342364fd305..058696b7d6c37 100644 --- a/drivers/gpu/drm/i915/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c @@ -2566,6 +2566,7 @@ int icl_calc_dp_combo_pll_link(struct drm_i915_private *dev_priv, switch (index) { default: MISSING_CASE(index); + /* fall through */ case 0: link_clock = 540000; break; @@ -2639,6 +2640,7 @@ static bool icl_mg_pll_find_divisors(int clock_khz, bool is_dp, bool use_ssc, switch (div1) { default: MISSING_CASE(div1); + /* fall through */ case 2: hsdiv = 0; break; @@ -2903,6 +2905,7 @@ static i915_reg_t icl_pll_id_to_enable_reg(enum intel_dpll_id id) switch (id) { default: MISSING_CASE(id); + /* fall through */ case DPLL_ID_ICL_DPLL0: case DPLL_ID_ICL_DPLL1: return CNL_DPLL_ENABLE(id); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index a8073eb02ffa6..cdfdebc11ef80 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1253,6 +1253,7 @@ enc_to_dig_port(struct drm_encoder *encoder) switch (intel_encoder->type) { case INTEL_OUTPUT_DDI: WARN_ON(!HAS_DDI(to_i915(encoder->dev))); + /* fall through */ case INTEL_OUTPUT_DP: case INTEL_OUTPUT_EDP: case INTEL_OUTPUT_HDMI: diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index 01862884a4360..478c928912c4c 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -229,6 +229,7 @@ __intel_engine_context_size(struct drm_i915_private *dev_priv, u8 class) break; default: MISSING_CASE(class); + /* fall through */ case VIDEO_DECODE_CLASS: case VIDEO_ENHANCEMENT_CLASS: case COPY_ENGINE_CLASS: diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index d81b2cfe1c5ed..6b5aa3b074ecc 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -3212,6 +3212,7 @@ static void cnl_set_procmon_ref_values(struct drm_i915_private *dev_priv, switch (val & (PROCESS_INFO_MASK | VOLTAGE_INFO_MASK)) { default: MISSING_CASE(val); + /* fall through */ case VOLTAGE_INFO_0_85V | PROCESS_INFO_DOT_0: procmon = &cnl_procmon_values[PROCMON_0_85V_DOT_0]; break; diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 9d9229a1f36cc..36f81a96b8f64 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1340,6 +1340,7 @@ static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder, switch (crtc_state->pixel_multiplier) { default: WARN(1, "unknown pixel multiplier specified\n"); + /* fall through */ case 1: rate = SDVO_CLOCK_RATE_MULT_1X; break; case 2: rate = SDVO_CLOCK_RATE_MULT_2X; break; case 4: rate = SDVO_CLOCK_RATE_MULT_4X; break; @@ -2316,14 +2317,19 @@ intel_sdvo_guess_ddc_bus(struct intel_sdvo *sdvo) switch (sdvo->controlled_output) { case SDVO_OUTPUT_LVDS1: mask |= SDVO_OUTPUT_LVDS1; + /* fall through */ case SDVO_OUTPUT_LVDS0: mask |= SDVO_OUTPUT_LVDS0; + /* fall through */ case SDVO_OUTPUT_TMDS1: mask |= SDVO_OUTPUT_TMDS1; + /* fall through */ case SDVO_OUTPUT_TMDS0: mask |= SDVO_OUTPUT_TMDS0; + /* fall through */ case SDVO_OUTPUT_RGB1: mask |= SDVO_OUTPUT_RGB1; + /* fall through */ case SDVO_OUTPUT_RGB0: mask |= SDVO_OUTPUT_RGB0; break; -- GitLab From 0d99889109892396a8164bf6dd178e36d3fe3166 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Thu, 28 Jun 2018 16:13:07 +0300 Subject: [PATCH 0668/1506] drm/fb-helper: Eliminate the .best_encoder() usage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using the .best_encoder() hook to figure out whether a given connector+crtc combo will work, let's instead do what userspace does and just iterate over all the encoders for the connector, and then check each crtc against each encoder's possible_crtcs bitmask. v2: Avoid oopsing on NULL encoders (Daniel) s/connector_crtc_ok/connector_has_possible_crtc/ Cc: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Cc: Harry Wentland <harry.wentland@amd.com> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Suggested-by: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180628131315.14156-2-ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_fb_helper.c | 41 +++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index cab14f2533840..b37f06317d517 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -2323,6 +2323,27 @@ static bool drm_target_preferred(struct drm_fb_helper *fb_helper, return true; } +static bool connector_has_possible_crtc(struct drm_connector *connector, + struct drm_crtc *crtc) +{ + int i; + + for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { + struct drm_encoder *encoder; + + if (connector->encoder_ids[i] == 0) + break; + + encoder = drm_encoder_find(connector->dev, NULL, + connector->encoder_ids[i]); + + if (encoder->possible_crtcs & drm_crtc_mask(crtc)) + return true; + } + + return false; +} + static int drm_pick_crtcs(struct drm_fb_helper *fb_helper, struct drm_fb_helper_crtc **best_crtcs, struct drm_display_mode **modes, @@ -2331,7 +2352,6 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper, int c, o; struct drm_connector *connector; const struct drm_connector_helper_funcs *connector_funcs; - struct drm_encoder *encoder; int my_score, best_score, score; struct drm_fb_helper_crtc **crtcs, *crtc; struct drm_fb_helper_connector *fb_helper_conn; @@ -2362,20 +2382,6 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper, connector_funcs = connector->helper_private; - /* - * If the DRM device implements atomic hooks and ->best_encoder() is - * NULL we fallback to the default drm_atomic_helper_best_encoder() - * helper. - */ - if (drm_drv_uses_atomic_modeset(fb_helper->dev) && - !connector_funcs->best_encoder) - encoder = drm_atomic_helper_best_encoder(connector); - else - encoder = connector_funcs->best_encoder(connector); - - if (!encoder) - goto out; - /* * select a crtc for this connector and then attempt to configure * remaining connectors @@ -2383,7 +2389,8 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper, for (c = 0; c < fb_helper->crtc_count; c++) { crtc = &fb_helper->crtc_info[c]; - if ((encoder->possible_crtcs & (1 << c)) == 0) + if (!connector_has_possible_crtc(connector, + crtc->mode_set.crtc)) continue; for (o = 0; o < n; o++) @@ -2410,7 +2417,7 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper, sizeof(struct drm_fb_helper_crtc *)); } } -out: + kfree(crtcs); return best_score; } -- GitLab From 20431c05ae682ff2ad387945738fc129d9751d6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Thu, 28 Jun 2018 16:13:08 +0300 Subject: [PATCH 0669/1506] drm/i915: Nuke intel_mst_best_encoder() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With the fb-helper no longer relying on the non-atomic .best_encoder() we can eliminate the hook from the MST encoder. Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Cc: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180628131315.14156-3-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/intel_dp_mst.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index 5890500a3a8b6..0f012fbe34ebd 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -403,20 +403,10 @@ static struct drm_encoder *intel_mst_atomic_best_encoder(struct drm_connector *c return &intel_dp->mst_encoders[crtc->pipe]->base.base; } -static struct drm_encoder *intel_mst_best_encoder(struct drm_connector *connector) -{ - struct intel_connector *intel_connector = to_intel_connector(connector); - struct intel_dp *intel_dp = intel_connector->mst_port; - if (!intel_dp) - return NULL; - return &intel_dp->mst_encoders[0]->base.base; -} - static const struct drm_connector_helper_funcs intel_dp_mst_connector_helper_funcs = { .get_modes = intel_dp_mst_get_modes, .mode_valid = intel_dp_mst_mode_valid, .atomic_best_encoder = intel_mst_atomic_best_encoder, - .best_encoder = intel_mst_best_encoder, .atomic_check = intel_dp_mst_atomic_check, }; -- GitLab From 83aefbb887b59df0b3520965c3701e01deacfc52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Thu, 28 Jun 2018 16:13:09 +0300 Subject: [PATCH 0670/1506] drm: Add drm_connector_for_each_possible_encoder() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a convenience macro for iterating connector->encoder_ids[]. Isolates the users from the implementation details. Note that we don't seem to pass the file_priv down to drm_encoder_find() because encoders apparently don't get leased. No idea why drm_encoder_finc() even takes the file_priv actually. Also use ARRAY_SIZE() when populating the array to avoid spreading knowledge about the array size all over. v2: Hide the drm_encoder_find() in the macro, and rename the macro appropriately (Daniel) v3: Fix kernel docs (Daniel) Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180628131315.14156-4-ville.syrjala@linux.intel.com Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> --- drivers/gpu/drm/drm_connector.c | 21 +++++++++------------ drivers/gpu/drm/drm_fb_helper.c | 11 ++--------- drivers/gpu/drm/drm_probe_helper.c | 10 +++------- include/drm/drm_connector.h | 13 +++++++++++++ 4 files changed, 27 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index b09b3a3e40246..7387c0377e513 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -321,7 +321,7 @@ int drm_mode_connector_attach_encoder(struct drm_connector *connector, if (WARN_ON(connector->encoder)) return -EINVAL; - for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { + for (i = 0; i < ARRAY_SIZE(connector->encoder_ids); i++) { if (connector->encoder_ids[i] == 0) { connector->encoder_ids[i] = encoder->base.id; return 0; @@ -1706,22 +1706,19 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, if (!connector) return -ENOENT; - for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) - if (connector->encoder_ids[i] != 0) - encoders_count++; + drm_connector_for_each_possible_encoder(connector, encoder, i) + encoders_count++; if ((out_resp->count_encoders >= encoders_count) && encoders_count) { copied = 0; encoder_ptr = (uint32_t __user *)(unsigned long)(out_resp->encoders_ptr); - for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { - if (connector->encoder_ids[i] != 0) { - if (put_user(connector->encoder_ids[i], - encoder_ptr + copied)) { - ret = -EFAULT; - goto out; - } - copied++; + + drm_connector_for_each_possible_encoder(connector, encoder, i) { + if (put_user(encoder->base.id, encoder_ptr + copied)) { + ret = -EFAULT; + goto out; } + copied++; } } out_resp->count_encoders = encoders_count; diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index b37f06317d517..d697c1c4a0678 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -2326,17 +2326,10 @@ static bool drm_target_preferred(struct drm_fb_helper *fb_helper, static bool connector_has_possible_crtc(struct drm_connector *connector, struct drm_crtc *crtc) { + struct drm_encoder *encoder; int i; - for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { - struct drm_encoder *encoder; - - if (connector->encoder_ids[i] == 0) - break; - - encoder = drm_encoder_find(connector->dev, NULL, - connector->encoder_ids[i]); - + drm_connector_for_each_possible_encoder(connector, encoder, i) { if (encoder->possible_crtcs & drm_crtc_mask(crtc)) return true; } diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 527743394150a..1a901fe9e23e7 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -88,9 +88,9 @@ drm_mode_validate_pipeline(struct drm_display_mode *mode, struct drm_connector *connector) { struct drm_device *dev = connector->dev; - uint32_t *ids = connector->encoder_ids; enum drm_mode_status ret = MODE_OK; - unsigned int i; + struct drm_encoder *encoder; + int i; /* Step 1: Validate against connector */ ret = drm_connector_mode_valid(connector, mode); @@ -98,13 +98,9 @@ drm_mode_validate_pipeline(struct drm_display_mode *mode, return ret; /* Step 2: Validate against encoders and crtcs */ - for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { - struct drm_encoder *encoder = drm_encoder_find(dev, NULL, ids[i]); + drm_connector_for_each_possible_encoder(connector, encoder, i) { struct drm_crtc *crtc; - if (!encoder) - continue; - ret = drm_encoder_mode_valid(encoder, mode); if (ret != MODE_OK) { /* No point in continuing for crtc check as this encoder diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index bf0f0f0786d30..bd6f30cf07559 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -1199,4 +1199,17 @@ void drm_connector_list_iter_end(struct drm_connector_list_iter *iter); #define drm_for_each_connector_iter(connector, iter) \ while ((connector = drm_connector_list_iter_next(iter))) +/** + * drm_connector_for_each_possible_encoder - iterate connector's possible encoders + * @connector: &struct drm_connector pointer + * @encoder: &struct drm_encoder pointer used as cursor + * @__i: int iteration cursor, for macro-internal use + */ +#define drm_connector_for_each_possible_encoder(connector, encoder, __i) \ + for ((__i) = 0; (__i) < ARRAY_SIZE((connector)->encoder_ids) && \ + (connector)->encoder_ids[(__i)] != 0; (__i)++) \ + for_each_if((encoder) = \ + drm_encoder_find((connector)->dev, NULL, \ + (connector)->encoder_ids[(__i)])) \ + #endif -- GitLab From 98c0e348c09575edccdd63e9d2938f090b0d8739 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Thu, 28 Jun 2018 16:13:10 +0300 Subject: [PATCH 0671/1506] drm/amdgpu: Use drm_connector_for_each_possible_encoder() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use drm_connector_for_each_possible_encoder() for iterating connector->encoder_ids[]. A bit more convenient not having to deal with the implementation details. v2: Replace drm_for_each_connector_encoder_ids() with drm_connector_for_each_possible_encoder() (Daniel) Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Cc: Alex Deucher <alexander.deucher@amd.com> Cc: "Christian König" <christian.koenig@amd.com> Cc: "David (ChunMing) Zhou" <David1.Zhou@amd.com> Cc: Harry Wentland <harry.wentland@amd.com> Cc: amd-gfx@lists.freedesktop.org Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180628131315.14156-5-ville.syrjala@linux.intel.com --- .../gpu/drm/amd/amdgpu/amdgpu_connectors.c | 81 +++++-------------- drivers/gpu/drm/amd/amdgpu/dce_virtual.c | 15 +--- 2 files changed, 25 insertions(+), 71 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c index 8e66851eb427b..881f7cb7ae6e6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c @@ -212,30 +212,21 @@ static void amdgpu_connector_update_scratch_regs(struct drm_connector *connector, enum drm_connector_status status) { - struct drm_encoder *best_encoder = NULL; - struct drm_encoder *encoder = NULL; + struct drm_encoder *best_encoder; + struct drm_encoder *encoder; const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; bool connected; int i; best_encoder = connector_funcs->best_encoder(connector); - for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { - if (connector->encoder_ids[i] == 0) - break; - - encoder = drm_encoder_find(connector->dev, NULL, - connector->encoder_ids[i]); - if (!encoder) - continue; - + drm_connector_for_each_possible_encoder(connector, encoder, i) { if ((encoder == best_encoder) && (status == connector_status_connected)) connected = true; else connected = false; amdgpu_atombios_encoder_set_bios_scratch_regs(connector, encoder, connected); - } } @@ -246,17 +237,11 @@ amdgpu_connector_find_encoder(struct drm_connector *connector, struct drm_encoder *encoder; int i; - for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { - if (connector->encoder_ids[i] == 0) - break; - encoder = drm_encoder_find(connector->dev, NULL, - connector->encoder_ids[i]); - if (!encoder) - continue; - + drm_connector_for_each_possible_encoder(connector, encoder, i) { if (encoder->encoder_type == encoder_type) return encoder; } + return NULL; } @@ -360,11 +345,13 @@ static int amdgpu_connector_ddc_get_modes(struct drm_connector *connector) static struct drm_encoder * amdgpu_connector_best_single_encoder(struct drm_connector *connector) { - int enc_id = connector->encoder_ids[0]; + struct drm_encoder *encoder; + int i; + + /* pick the first one */ + drm_connector_for_each_possible_encoder(connector, encoder, i) + return encoder; - /* pick the encoder ids */ - if (enc_id) - return drm_encoder_find(connector->dev, NULL, enc_id); return NULL; } @@ -985,9 +972,8 @@ amdgpu_connector_dvi_detect(struct drm_connector *connector, bool force) struct drm_device *dev = connector->dev; struct amdgpu_device *adev = dev->dev_private; struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); - struct drm_encoder *encoder = NULL; const struct drm_encoder_helper_funcs *encoder_funcs; - int i, r; + int r; enum drm_connector_status ret = connector_status_disconnected; bool dret = false, broken_edid = false; @@ -1077,14 +1063,10 @@ amdgpu_connector_dvi_detect(struct drm_connector *connector, bool force) /* find analog encoder */ if (amdgpu_connector->dac_load_detect) { - for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { - if (connector->encoder_ids[i] == 0) - break; - - encoder = drm_encoder_find(connector->dev, NULL, connector->encoder_ids[i]); - if (!encoder) - continue; + struct drm_encoder *encoder; + int i; + drm_connector_for_each_possible_encoder(connector, encoder, i) { if (encoder->encoder_type != DRM_MODE_ENCODER_DAC && encoder->encoder_type != DRM_MODE_ENCODER_TVDAC) continue; @@ -1132,18 +1114,11 @@ amdgpu_connector_dvi_detect(struct drm_connector *connector, bool force) static struct drm_encoder * amdgpu_connector_dvi_encoder(struct drm_connector *connector) { - int enc_id = connector->encoder_ids[0]; struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); struct drm_encoder *encoder; int i; - for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { - if (connector->encoder_ids[i] == 0) - break; - - encoder = drm_encoder_find(connector->dev, NULL, connector->encoder_ids[i]); - if (!encoder) - continue; + drm_connector_for_each_possible_encoder(connector, encoder, i) { if (amdgpu_connector->use_digital == true) { if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS) return encoder; @@ -1158,8 +1133,9 @@ amdgpu_connector_dvi_encoder(struct drm_connector *connector) /* then check use digitial */ /* pick the first one */ - if (enc_id) - return drm_encoder_find(connector->dev, NULL, enc_id); + drm_connector_for_each_possible_encoder(connector, encoder, i) + return encoder; + return NULL; } @@ -1296,15 +1272,7 @@ u16 amdgpu_connector_encoder_get_dp_bridge_encoder_id(struct drm_connector *conn struct amdgpu_encoder *amdgpu_encoder; int i; - for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { - if (connector->encoder_ids[i] == 0) - break; - - encoder = drm_encoder_find(connector->dev, NULL, - connector->encoder_ids[i]); - if (!encoder) - continue; - + drm_connector_for_each_possible_encoder(connector, encoder, i) { amdgpu_encoder = to_amdgpu_encoder(encoder); switch (amdgpu_encoder->encoder_id) { @@ -1326,14 +1294,7 @@ static bool amdgpu_connector_encoder_is_hbr2(struct drm_connector *connector) int i; bool found = false; - for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { - if (connector->encoder_ids[i] == 0) - break; - encoder = drm_encoder_find(connector->dev, NULL, - connector->encoder_ids[i]); - if (!encoder) - continue; - + drm_connector_for_each_possible_encoder(connector, encoder, i) { amdgpu_encoder = to_amdgpu_encoder(encoder); if (amdgpu_encoder->caps & ATOM_ENCODER_CAP_RECORD_HBR2) found = true; diff --git a/drivers/gpu/drm/amd/amdgpu/dce_virtual.c b/drivers/gpu/drm/amd/amdgpu/dce_virtual.c index dbf2ccd0c7447..016f150931731 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_virtual.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_virtual.c @@ -269,25 +269,18 @@ static int dce_virtual_early_init(void *handle) static struct drm_encoder * dce_virtual_encoder(struct drm_connector *connector) { - int enc_id = connector->encoder_ids[0]; struct drm_encoder *encoder; int i; - for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { - if (connector->encoder_ids[i] == 0) - break; - - encoder = drm_encoder_find(connector->dev, NULL, connector->encoder_ids[i]); - if (!encoder) - continue; - + drm_connector_for_each_possible_encoder(connector, encoder, i) { if (encoder->encoder_type == DRM_MODE_ENCODER_VIRTUAL) return encoder; } /* pick the first one */ - if (enc_id) - return drm_encoder_find(connector->dev, NULL, enc_id); + drm_connector_for_each_possible_encoder(connector, encoder, i) + return encoder; + return NULL; } -- GitLab From ddba766dd07e67d0ca70b632d3bbac72234b547e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Mon, 2 Jul 2018 18:29:27 +0300 Subject: [PATCH 0672/1506] drm/nouveau: Use drm_connector_for_each_possible_encoder() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use drm_connector_for_each_possible_encoder() for iterating connector->encoder_ids[]. A bit more convenient not having to deal with the implementation details. v2: Replace drm_for_each_connector_encoder_ids() with drm_connector_for_each_possible_encoder() (Daniel) v3: Initialize nv_encoder to NULL to shut up gcc/smatch Cc: Dan Carpenter <dan.carpenter@oracle.com> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Cc: Ben Skeggs <bskeggs@redhat.com> Cc: nouveau@lists.freedesktop.org Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180702152927.13351-1-ville.syrjala@linux.intel.com --- drivers/gpu/drm/nouveau/nouveau_connector.c | 23 ++++----------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 7b557c3543079..bb46c1d489cf4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -363,19 +363,11 @@ module_param_named(hdmimhz, nouveau_hdmimhz, int, 0400); struct nouveau_encoder * find_encoder(struct drm_connector *connector, int type) { - struct drm_device *dev = connector->dev; struct nouveau_encoder *nv_encoder; struct drm_encoder *enc; - int i, id; - - for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { - id = connector->encoder_ids[i]; - if (!id) - break; + int i; - enc = drm_encoder_find(dev, NULL, id); - if (!enc) - continue; + drm_connector_for_each_possible_encoder(connector, enc, i) { nv_encoder = nouveau_encoder(enc); if (type == DCB_OUTPUT_ANY || @@ -420,7 +412,7 @@ nouveau_connector_ddc_detect(struct drm_connector *connector) struct nouveau_connector *nv_connector = nouveau_connector(connector); struct nouveau_drm *drm = nouveau_drm(dev); struct nvkm_gpio *gpio = nvxx_gpio(&drm->client.device); - struct nouveau_encoder *nv_encoder; + struct nouveau_encoder *nv_encoder = NULL; struct drm_encoder *encoder; int i, panel = -ENODEV; @@ -436,14 +428,7 @@ nouveau_connector_ddc_detect(struct drm_connector *connector) } } - for (i = 0; nv_encoder = NULL, i < DRM_CONNECTOR_MAX_ENCODER; i++) { - int id = connector->encoder_ids[i]; - if (id == 0) - break; - - encoder = drm_encoder_find(dev, NULL, id); - if (!encoder) - continue; + drm_connector_for_each_possible_encoder(connector, encoder, i) { nv_encoder = nouveau_encoder(encoder); if (nv_encoder->dcb->type == DCB_OUTPUT_DP) { -- GitLab From 7b71ca249b265fe69ab3152a15bc6c305554a7da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Thu, 28 Jun 2018 16:13:12 +0300 Subject: [PATCH 0673/1506] drm/radeon: Use drm_connector_for_each_possible_encoder() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use drm_connector_for_each_possible_encoder() for iterating connector->encoder_ids[]. A bit more convenient not having to deal with the implementation details. v2: Replace drm_for_each_connector_encoder_ids() with drm_connector_for_each_possible_encoder() (Daniel) Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Cc: Alex Deucher <alexander.deucher@amd.com> Cc: "Christian König" <christian.koenig@amd.com> Cc: "David (ChunMing) Zhou" <David1.Zhou@amd.com> Cc: Harry Wentland <harry.wentland@amd.com> Cc: amd-gfx@lists.freedesktop.org Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180628131315.14156-7-ville.syrjala@linux.intel.com --- drivers/gpu/drm/radeon/radeon_connectors.c | 90 +++++++--------------- 1 file changed, 26 insertions(+), 64 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 2aea2bdff99bc..0655698f29566 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -244,23 +244,15 @@ radeon_connector_update_scratch_regs(struct drm_connector *connector, enum drm_c { struct drm_device *dev = connector->dev; struct radeon_device *rdev = dev->dev_private; - struct drm_encoder *best_encoder = NULL; - struct drm_encoder *encoder = NULL; + struct drm_encoder *best_encoder; + struct drm_encoder *encoder; const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; bool connected; int i; best_encoder = connector_funcs->best_encoder(connector); - for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { - if (connector->encoder_ids[i] == 0) - break; - - encoder = drm_encoder_find(connector->dev, NULL, - connector->encoder_ids[i]); - if (!encoder) - continue; - + drm_connector_for_each_possible_encoder(connector, encoder, i) { if ((encoder == best_encoder) && (status == connector_status_connected)) connected = true; else @@ -270,7 +262,6 @@ radeon_connector_update_scratch_regs(struct drm_connector *connector, enum drm_c radeon_atombios_connected_scratch_regs(connector, encoder, connected); else radeon_combios_connected_scratch_regs(connector, encoder, connected); - } } @@ -279,17 +270,11 @@ static struct drm_encoder *radeon_find_encoder(struct drm_connector *connector, struct drm_encoder *encoder; int i; - for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { - if (connector->encoder_ids[i] == 0) - break; - - encoder = drm_encoder_find(connector->dev, NULL, connector->encoder_ids[i]); - if (!encoder) - continue; - + drm_connector_for_each_possible_encoder(connector, encoder, i) { if (encoder->encoder_type == encoder_type) return encoder; } + return NULL; } @@ -393,10 +378,13 @@ static int radeon_ddc_get_modes(struct drm_connector *connector) static struct drm_encoder *radeon_best_single_encoder(struct drm_connector *connector) { - int enc_id = connector->encoder_ids[0]; - /* pick the encoder ids */ - if (enc_id) - return drm_encoder_find(connector->dev, NULL, enc_id); + struct drm_encoder *encoder; + int i; + + /* pick the first one */ + drm_connector_for_each_possible_encoder(connector, encoder, i) + return encoder; + return NULL; } @@ -436,19 +424,19 @@ radeon_connector_analog_encoder_conflict_solve(struct drm_connector *connector, struct drm_device *dev = connector->dev; struct drm_connector *conflict; struct radeon_connector *radeon_conflict; - int i; list_for_each_entry(conflict, &dev->mode_config.connector_list, head) { + struct drm_encoder *enc; + int i; + if (conflict == connector) continue; radeon_conflict = to_radeon_connector(conflict); - for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { - if (conflict->encoder_ids[i] == 0) - break; + drm_connector_for_each_possible_encoder(conflict, enc, i) { /* if the IDs match */ - if (conflict->encoder_ids[i] == encoder->base.id) { + if (enc == encoder) { if (conflict->status != connector_status_connected) continue; @@ -1256,7 +1244,7 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) struct radeon_connector *radeon_connector = to_radeon_connector(connector); struct drm_encoder *encoder = NULL; const struct drm_encoder_helper_funcs *encoder_funcs; - int i, r; + int r; enum drm_connector_status ret = connector_status_disconnected; bool dret = false, broken_edid = false; @@ -1374,15 +1362,9 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) /* find analog encoder */ if (radeon_connector->dac_load_detect) { - for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { - if (connector->encoder_ids[i] == 0) - break; - - encoder = drm_encoder_find(connector->dev, NULL, - connector->encoder_ids[i]); - if (!encoder) - continue; + int i; + drm_connector_for_each_possible_encoder(connector, encoder, i) { if (encoder->encoder_type != DRM_MODE_ENCODER_DAC && encoder->encoder_type != DRM_MODE_ENCODER_TVDAC) continue; @@ -1458,18 +1440,11 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) /* okay need to be smart in here about which encoder to pick */ static struct drm_encoder *radeon_dvi_encoder(struct drm_connector *connector) { - int enc_id = connector->encoder_ids[0]; struct radeon_connector *radeon_connector = to_radeon_connector(connector); struct drm_encoder *encoder; int i; - for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { - if (connector->encoder_ids[i] == 0) - break; - - encoder = drm_encoder_find(connector->dev, NULL, connector->encoder_ids[i]); - if (!encoder) - continue; + drm_connector_for_each_possible_encoder(connector, encoder, i) { if (radeon_connector->use_digital == true) { if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS) return encoder; @@ -1484,8 +1459,9 @@ static struct drm_encoder *radeon_dvi_encoder(struct drm_connector *connector) /* then check use digitial */ /* pick the first one */ - if (enc_id) - return drm_encoder_find(connector->dev, NULL, enc_id); + drm_connector_for_each_possible_encoder(connector, encoder, i) + return encoder; + return NULL; } @@ -1628,14 +1604,7 @@ u16 radeon_connector_encoder_get_dp_bridge_encoder_id(struct drm_connector *conn struct radeon_encoder *radeon_encoder; int i; - for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { - if (connector->encoder_ids[i] == 0) - break; - - encoder = drm_encoder_find(connector->dev, NULL, connector->encoder_ids[i]); - if (!encoder) - continue; - + drm_connector_for_each_possible_encoder(connector, encoder, i) { radeon_encoder = to_radeon_encoder(encoder); switch (radeon_encoder->encoder_id) { @@ -1657,14 +1626,7 @@ static bool radeon_connector_encoder_is_hbr2(struct drm_connector *connector) int i; bool found = false; - for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { - if (connector->encoder_ids[i] == 0) - break; - - encoder = drm_encoder_find(connector->dev, NULL, connector->encoder_ids[i]); - if (!encoder) - continue; - + drm_connector_for_each_possible_encoder(connector, encoder, i) { radeon_encoder = to_radeon_encoder(encoder); if (radeon_encoder->caps & ATOM_ENCODER_CAP_RECORD_HBR2) found = true; -- GitLab From 38cb8d96933eb07231073efdcd24a6ffa43b23e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Thu, 28 Jun 2018 16:13:13 +0300 Subject: [PATCH 0674/1506] drm: Add drm_connector_has_possible_encoder() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a small helper for checking whether a connector and encoder are associated with each other. Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180628131315.14156-8-ville.syrjala@linux.intel.com Reviewed-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/drm_connector.c | 23 +++++++++++++++++++++++ include/drm/drm_connector.h | 3 +++ 2 files changed, 26 insertions(+) diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index 7387c0377e513..5ada0640de5ad 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -331,6 +331,29 @@ int drm_mode_connector_attach_encoder(struct drm_connector *connector, } EXPORT_SYMBOL(drm_mode_connector_attach_encoder); +/** + * drm_connector_has_possible_encoder - check if the connector and encoder are assosicated with each other + * @connector: the connector + * @encoder: the encoder + * + * Returns: + * True if @encoder is one of the possible encoders for @connector. + */ +bool drm_connector_has_possible_encoder(struct drm_connector *connector, + struct drm_encoder *encoder) +{ + struct drm_encoder *enc; + int i; + + drm_connector_for_each_possible_encoder(connector, enc, i) { + if (enc == encoder) + return true; + } + + return false; +} +EXPORT_SYMBOL(drm_connector_has_possible_encoder); + static void drm_mode_remove(struct drm_connector *connector, struct drm_display_mode *mode) { diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index bd6f30cf07559..ad397dfc042b1 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -1187,6 +1187,9 @@ struct drm_connector * drm_connector_list_iter_next(struct drm_connector_list_iter *iter); void drm_connector_list_iter_end(struct drm_connector_list_iter *iter); +bool drm_connector_has_possible_encoder(struct drm_connector *connector, + struct drm_encoder *encoder); + /** * drm_for_each_connector_iter - connector_list iterator macro * @connector: &struct drm_connector pointer used as cursor -- GitLab From f8222409d1ac7a53de4c89db5a6dc268d523f6c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Thu, 28 Jun 2018 16:13:14 +0300 Subject: [PATCH 0675/1506] drm/msm: Use drm_connector_has_possible_encoder() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use drm_connector_has_possible_encoder() for checking whether the encoder has an associated connector. v2: Replace the drm_for_each_connector_encoder_ids() loop with a simple drm_connector_has_possible_encoder() call Cc: Rob Clark <robdclark@gmail.com> Cc: linux-arm-msm@vger.kernel.org Cc: freedreno@lists.freedesktop.org Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180628131315.14156-9-ville.syrjala@linux.intel.com Reviewed-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/msm/dsi/dsi_manager.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c index 4cb1cb68878b0..4beba3f7d0678 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c @@ -751,12 +751,8 @@ struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id) connector_list = &dev->mode_config.connector_list; list_for_each_entry(connector, connector_list, head) { - int i; - - for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { - if (connector->encoder_ids[i] == encoder->base.id) - return connector; - } + if (drm_connector_has_possible_encoder(connector, encoder)) + return connector; } return ERR_PTR(-ENODEV); -- GitLab From 0b7510d15e14ba628ab9bacd6516e3f6a35ba21f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Thu, 28 Jun 2018 16:13:15 +0300 Subject: [PATCH 0676/1506] drm/tilcdc: Use drm_connector_has_possible_encoder() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use drm_connector_has_possible_encoder() for checking whether the encoder has an associated connector. v2: Replace the drm_for_each_connector_encoder_ids() loop with a simple drm_connector_has_possible_encoder() call Cc: Jyri Sarha <jsarha@ti.com> Cc: Tomi Valkeinen <tomi.valkeinen@ti.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180628131315.14156-10-ville.syrjala@linux.intel.com Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Acked-by: Jyri Sarha <jsarha@ti.com> --- drivers/gpu/drm/tilcdc/tilcdc_external.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/tilcdc/tilcdc_external.c b/drivers/gpu/drm/tilcdc/tilcdc_external.c index d651bdd6597e6..b4eaf9bc87f8e 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_external.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_external.c @@ -103,12 +103,11 @@ struct drm_connector *tilcdc_encoder_find_connector(struct drm_device *ddev, struct drm_encoder *encoder) { struct drm_connector *connector; - int i; - list_for_each_entry(connector, &ddev->mode_config.connector_list, head) - for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) - if (connector->encoder_ids[i] == encoder->base.id) - return connector; + list_for_each_entry(connector, &ddev->mode_config.connector_list, head) { + if (drm_connector_has_possible_encoder(connector, encoder)) + return connector; + } dev_err(ddev->dev, "No connector found for %s encoder (id %d)\n", encoder->name, encoder->base.id); -- GitLab From 846c87a068f4b72e200357b899ca4dcc92ef42c4 Mon Sep 17 00:00:00 2001 From: Liviu Dudau <Liviu.Dudau@arm.com> Date: Wed, 29 Mar 2017 17:42:34 +0100 Subject: [PATCH 0677/1506] drm: mali-dp: Add support for writeback on DP550/DP650 Mali-DP display processors are able to write the composition result to a memory buffer via the SE. Add entry points in the HAL for enabling/disabling this feature, and implement support for it on DP650 and DP550. DP500 acts differently and so is omitted from this change. Changes since v3: - Fix missing vsync interrupt for DP550 Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com> Signed-off-by: Brian Starkey <brian.starkey@arm.com> [rebased and fixed conflicts] Signed-off-by: Mihail Atanassov <mihail.atanassov@arm.com> --- drivers/gpu/drm/arm/malidp_hw.c | 55 +++++++++++++++++++++++++++++-- drivers/gpu/drm/arm/malidp_hw.h | 17 ++++++++++ drivers/gpu/drm/arm/malidp_regs.h | 15 +++++++++ 3 files changed, 85 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c index 069783e715f17..461e62653a36d 100644 --- a/drivers/gpu/drm/arm/malidp_hw.c +++ b/drivers/gpu/drm/arm/malidp_hw.c @@ -588,6 +588,49 @@ static long malidp550_se_calc_mclk(struct malidp_hw_device *hwdev, return ret; } +static int malidp550_enable_memwrite(struct malidp_hw_device *hwdev, + dma_addr_t *addrs, s32 *pitches, + int num_planes, u16 w, u16 h, u32 fmt_id) +{ + u32 base = MALIDP550_SE_MEMWRITE_BASE; + u32 de_base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK); + + /* enable the scaling engine block */ + malidp_hw_setbits(hwdev, MALIDP_SCALE_ENGINE_EN, de_base + MALIDP_DE_DISPLAY_FUNC); + + malidp_hw_write(hwdev, fmt_id, base + MALIDP_MW_FORMAT); + switch (num_planes) { + case 2: + malidp_hw_write(hwdev, lower_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_LOW); + malidp_hw_write(hwdev, upper_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_HIGH); + malidp_hw_write(hwdev, pitches[1], base + MALIDP_MW_P2_STRIDE); + /* fall through */ + case 1: + malidp_hw_write(hwdev, lower_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_LOW); + malidp_hw_write(hwdev, upper_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_HIGH); + malidp_hw_write(hwdev, pitches[0], base + MALIDP_MW_P1_STRIDE); + break; + default: + WARN(1, "Invalid number of planes"); + } + + malidp_hw_write(hwdev, MALIDP_DE_H_ACTIVE(w) | MALIDP_DE_V_ACTIVE(h), + MALIDP550_SE_MEMWRITE_OUT_SIZE); + malidp_hw_setbits(hwdev, MALIDP550_SE_MEMWRITE_ONESHOT | MALIDP_SE_MEMWRITE_EN, + MALIDP550_SE_CONTROL); + + return 0; +} + +static void malidp550_disable_memwrite(struct malidp_hw_device *hwdev) +{ + u32 base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK); + + malidp_hw_clearbits(hwdev, MALIDP550_SE_MEMWRITE_ONESHOT | MALIDP_SE_MEMWRITE_EN, + MALIDP550_SE_CONTROL); + malidp_hw_clearbits(hwdev, MALIDP_SCALE_ENGINE_EN, base + MALIDP_DE_DISPLAY_FUNC); +} + static int malidp650_query_hw(struct malidp_hw_device *hwdev) { u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID); @@ -674,9 +717,11 @@ const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = { .se_irq_map = { .irq_mask = MALIDP550_SE_IRQ_EOW | MALIDP550_SE_IRQ_AXI_ERR, + .vsync_irq = MALIDP550_SE_IRQ_EOW, }, .dc_irq_map = { - .irq_mask = MALIDP550_DC_IRQ_CONF_VALID, + .irq_mask = MALIDP550_DC_IRQ_CONF_VALID | + MALIDP550_DC_IRQ_SE, .vsync_irq = MALIDP550_DC_IRQ_CONF_VALID, }, .pixel_formats = malidp550_de_formats, @@ -692,6 +737,8 @@ const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = { .rotmem_required = malidp550_rotmem_required, .se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs, .se_calc_mclk = malidp550_se_calc_mclk, + .enable_memwrite = malidp550_enable_memwrite, + .disable_memwrite = malidp550_disable_memwrite, .features = 0, }, [MALIDP_650] = { @@ -712,9 +759,11 @@ const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = { .se_irq_map = { .irq_mask = MALIDP550_SE_IRQ_EOW | MALIDP550_SE_IRQ_AXI_ERR, + .vsync_irq = MALIDP550_SE_IRQ_EOW, }, .dc_irq_map = { - .irq_mask = MALIDP550_DC_IRQ_CONF_VALID, + .irq_mask = MALIDP550_DC_IRQ_CONF_VALID | + MALIDP550_DC_IRQ_SE, .vsync_irq = MALIDP550_DC_IRQ_CONF_VALID, }, .pixel_formats = malidp550_de_formats, @@ -730,6 +779,8 @@ const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = { .rotmem_required = malidp550_rotmem_required, .se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs, .se_calc_mclk = malidp550_se_calc_mclk, + .enable_memwrite = malidp550_enable_memwrite, + .disable_memwrite = malidp550_disable_memwrite, .features = 0, }, }; diff --git a/drivers/gpu/drm/arm/malidp_hw.h b/drivers/gpu/drm/arm/malidp_hw.h index b5dd6c73ec9f2..72cc22f828360 100644 --- a/drivers/gpu/drm/arm/malidp_hw.h +++ b/drivers/gpu/drm/arm/malidp_hw.h @@ -177,6 +177,23 @@ struct malidp_hw { long (*se_calc_mclk)(struct malidp_hw_device *hwdev, struct malidp_se_config *se_config, struct videomode *vm); + /** + * Enable writing to memory the content of the next frame + * @param hwdev - malidp_hw_device structure containing the HW description + * @param addrs - array of addresses for each plane + * @param pitches - array of pitches for each plane + * @param num_planes - number of planes to be written + * @param w - width of the output frame + * @param h - height of the output frame + * @param fmt_id - internal format ID of output buffer + */ + int (*enable_memwrite)(struct malidp_hw_device *hwdev, dma_addr_t *addrs, + s32 *pitches, int num_planes, u16 w, u16 h, u32 fmt_id); + + /* + * Disable the writing to memory of the next frame's content. + */ + void (*disable_memwrite)(struct malidp_hw_device *hwdev); u8 features; }; diff --git a/drivers/gpu/drm/arm/malidp_regs.h b/drivers/gpu/drm/arm/malidp_regs.h index 149024fb44327..e2b2c496225e3 100644 --- a/drivers/gpu/drm/arm/malidp_regs.h +++ b/drivers/gpu/drm/arm/malidp_regs.h @@ -66,6 +66,8 @@ #define MALIDP_DISP_FUNC_GAMMA (1 << 0) #define MALIDP_DISP_FUNC_CADJ (1 << 4) #define MALIDP_DISP_FUNC_ILACED (1 << 8) +#define MALIDP_SCALE_ENGINE_EN (1 << 16) +#define MALIDP_SE_MEMWRITE_EN (2 << 5) /* register offsets for IRQ management */ #define MALIDP_REG_STATUS 0x00000 @@ -153,6 +155,16 @@ (((x) & MALIDP_SE_ENH_LIMIT_MASK) << 16) #define MALIDP_SE_ENH_COEFF0 0x04 + +/* register offsets relative to MALIDP5x0_SE_MEMWRITE_BASE */ +#define MALIDP_MW_FORMAT 0x00000 +#define MALIDP_MW_P1_STRIDE 0x00004 +#define MALIDP_MW_P2_STRIDE 0x00008 +#define MALIDP_MW_P1_PTR_LOW 0x0000c +#define MALIDP_MW_P1_PTR_HIGH 0x00010 +#define MALIDP_MW_P2_PTR_LOW 0x0002c +#define MALIDP_MW_P2_PTR_HIGH 0x00030 + /* register offsets and bits specific to DP500 */ #define MALIDP500_ADDR_SPACE_SIZE 0x01000 #define MALIDP500_DC_BASE 0x00000 @@ -217,6 +229,9 @@ #define MALIDP550_DE_PERF_BASE 0x00500 #define MALIDP550_SE_BASE 0x08000 #define MALIDP550_SE_CONTROL 0x08010 +#define MALIDP550_SE_MEMWRITE_ONESHOT (1 << 7) +#define MALIDP550_SE_MEMWRITE_OUT_SIZE 0x08030 +#define MALIDP550_SE_MEMWRITE_BASE 0x08100 #define MALIDP550_DC_BASE 0x0c000 #define MALIDP550_DC_CONTROL 0x0c010 #define MALIDP550_DC_CONFIG_REQ (1 << 16) -- GitLab From a67bbbe225c281f441533d55cd9dce5c2ae207a5 Mon Sep 17 00:00:00 2001 From: Brian Starkey <brian.starkey@arm.com> Date: Wed, 29 Mar 2017 17:42:35 +0100 Subject: [PATCH 0678/1506] drm: mali-dp: Add RGB writeback formats for DP550/DP650 Add a layer bit for the SE memory-write, and add it to the pixel format matrix for DP550/DP650. Signed-off-by: Brian Starkey <brian.starkey@arm.com> [rebased and fixed conflicts] Signed-off-by: Mihail Atanassov <mihail.atanassov@arm.com> Signed-off-by: Liviu Dudau <liviu.dudau@arm.com> --- drivers/gpu/drm/arm/malidp_hw.c | 22 +++++++++++----------- drivers/gpu/drm/arm/malidp_hw.h | 1 + 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c index 461e62653a36d..c98b3e02dd547 100644 --- a/drivers/gpu/drm/arm/malidp_hw.c +++ b/drivers/gpu/drm/arm/malidp_hw.c @@ -47,27 +47,27 @@ static const struct malidp_format_id malidp500_de_formats[] = { #define MALIDP_COMMON_FORMATS \ /* fourcc, layers supporting the format, internal id */ \ - { DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 0) }, \ - { DRM_FORMAT_ABGR2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 1) }, \ - { DRM_FORMAT_RGBA1010102, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 2) }, \ - { DRM_FORMAT_BGRA1010102, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 3) }, \ + { DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(0, 0) }, \ + { DRM_FORMAT_ABGR2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(0, 1) }, \ + { DRM_FORMAT_RGBA1010102, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(0, 2) }, \ + { DRM_FORMAT_BGRA1010102, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(0, 3) }, \ { DRM_FORMAT_ARGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 0) }, \ { DRM_FORMAT_ABGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 1) }, \ { DRM_FORMAT_RGBA8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 2) }, \ { DRM_FORMAT_BGRA8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 3) }, \ - { DRM_FORMAT_XRGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 0) }, \ - { DRM_FORMAT_XBGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 1) }, \ - { DRM_FORMAT_RGBX8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 2) }, \ - { DRM_FORMAT_BGRX8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 3) }, \ - { DRM_FORMAT_RGB888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(3, 0) }, \ - { DRM_FORMAT_BGR888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(3, 1) }, \ + { DRM_FORMAT_XRGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART | SE_MEMWRITE, MALIDP_ID(2, 0) }, \ + { DRM_FORMAT_XBGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART | SE_MEMWRITE, MALIDP_ID(2, 1) }, \ + { DRM_FORMAT_RGBX8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART | SE_MEMWRITE, MALIDP_ID(2, 2) }, \ + { DRM_FORMAT_BGRX8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART | SE_MEMWRITE, MALIDP_ID(2, 3) }, \ + { DRM_FORMAT_RGB888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(3, 0) }, \ + { DRM_FORMAT_BGR888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(3, 1) }, \ { DRM_FORMAT_RGBA5551, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 0) }, \ { DRM_FORMAT_ABGR1555, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 1) }, \ { DRM_FORMAT_RGB565, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 2) }, \ { DRM_FORMAT_BGR565, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 3) }, \ { DRM_FORMAT_YUYV, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 2) }, \ { DRM_FORMAT_UYVY, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 3) }, \ - { DRM_FORMAT_NV12, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 6) }, \ + { DRM_FORMAT_NV12, DE_VIDEO1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(5, 6) }, \ { DRM_FORMAT_YUV420, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 7) } static const struct malidp_format_id malidp550_de_formats[] = { diff --git a/drivers/gpu/drm/arm/malidp_hw.h b/drivers/gpu/drm/arm/malidp_hw.h index 72cc22f828360..a242e97cf6428 100644 --- a/drivers/gpu/drm/arm/malidp_hw.h +++ b/drivers/gpu/drm/arm/malidp_hw.h @@ -33,6 +33,7 @@ enum { DE_GRAPHICS2 = BIT(2), /* used only in DP500 */ DE_VIDEO2 = BIT(3), DE_SMART = BIT(4), + SE_MEMWRITE = BIT(5), }; struct malidp_format_id { -- GitLab From 1cb3cbe732d9bedd4046bbeb2726d1699cdfabce Mon Sep 17 00:00:00 2001 From: Liviu Dudau <Liviu.Dudau@arm.com> Date: Tue, 10 Apr 2018 17:25:57 +0100 Subject: [PATCH 0679/1506] drm/mali-dp: Add writeback support for DP500. Mali DP500 behaves differently from the rest of the Mali DP IP, in that it does not have a one-shot mode and keeps writing the content of the current frame to the provided memory area until stopped. As a way of emulating the one-shot behaviour, we are going to use the CVAL interrupt that is being raised at the start of each frame, during prefetch phase, to act as End-of-Write signal, but with a twist: we are going to disable the memory write engine right after we're notified that it has been enabled, using the knowledge that the bit controlling the enabling will only be acted upon on the next vblank/prefetch. CVAL interrupt will fire durint the next prefetch phase every time the global CVAL bit gets set, so we need a state byte to track the memory write enabling. We also need to pay attention during the disabling of the memory write engine as that requires the CVAL bit to be set in the control register, but we don't want to do that during an atomic commit, as it will write into the hardware a partial state. Reviewed-by: Brian Starkey <brian.starkey@arm.com> Signed-off-by: Liviu Dudau <liviu.dudau@arm.com> --- drivers/gpu/drm/arm/malidp_drv.c | 16 ++++-- drivers/gpu/drm/arm/malidp_drv.h | 4 ++ drivers/gpu/drm/arm/malidp_hw.c | 82 +++++++++++++++++++++++++++++-- drivers/gpu/drm/arm/malidp_hw.h | 5 +- drivers/gpu/drm/arm/malidp_regs.h | 3 +- 5 files changed, 101 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c index 0a788d76ed5f0..ab2d27e8bdd97 100644 --- a/drivers/gpu/drm/arm/malidp_drv.c +++ b/drivers/gpu/drm/arm/malidp_drv.c @@ -170,14 +170,15 @@ static int malidp_set_and_wait_config_valid(struct drm_device *drm) struct malidp_hw_device *hwdev = malidp->dev; int ret; - atomic_set(&malidp->config_valid, 0); hwdev->hw->set_config_valid(hwdev); /* don't wait for config_valid flag if we are in config mode */ - if (hwdev->hw->in_config_mode(hwdev)) + if (hwdev->hw->in_config_mode(hwdev)) { + atomic_set(&malidp->config_valid, MALIDP_CONFIG_VALID_DONE); return 0; + } ret = wait_event_interruptible_timeout(malidp->wq, - atomic_read(&malidp->config_valid) == 1, + atomic_read(&malidp->config_valid) == MALIDP_CONFIG_VALID_DONE, msecs_to_jiffies(MALIDP_CONF_VALID_TIMEOUT)); return (ret > 0) ? 0 : -ETIMEDOUT; @@ -216,12 +217,19 @@ static void malidp_atomic_commit_hw_done(struct drm_atomic_state *state) static void malidp_atomic_commit_tail(struct drm_atomic_state *state) { struct drm_device *drm = state->dev; + struct malidp_drm *malidp = drm->dev_private; struct drm_crtc *crtc; struct drm_crtc_state *old_crtc_state; int i; pm_runtime_get_sync(drm->dev); + /* + * set config_valid to a special value to let IRQ handlers + * know that we are updating registers + */ + atomic_set(&malidp->config_valid, MALIDP_CONFIG_START); + drm_atomic_helper_commit_modeset_disables(drm, state); for_each_old_crtc_in_state(state, crtc, old_crtc_state, i) { @@ -588,7 +596,7 @@ static int malidp_bind(struct device *dev) out_depth = (out_depth << 8) | (output_width[i] & 0xf); malidp_hw_write(hwdev, out_depth, hwdev->hw->map.out_depth_base); - atomic_set(&malidp->config_valid, 0); + atomic_set(&malidp->config_valid, MALIDP_CONFIG_VALID_INIT); init_waitqueue_head(&malidp->wq); ret = malidp_init(drm); diff --git a/drivers/gpu/drm/arm/malidp_drv.h b/drivers/gpu/drm/arm/malidp_drv.h index c70989b933874..e8c41cf1b5bd2 100644 --- a/drivers/gpu/drm/arm/malidp_drv.h +++ b/drivers/gpu/drm/arm/malidp_drv.h @@ -18,6 +18,10 @@ #include <drm/drmP.h> #include "malidp_hw.h" +#define MALIDP_CONFIG_VALID_INIT 0 +#define MALIDP_CONFIG_VALID_DONE 1 +#define MALIDP_CONFIG_START 0xd0 + struct malidp_drm { struct malidp_hw_device *dev; struct drm_crtc crtc; diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c index c98b3e02dd547..0f6290b2f768f 100644 --- a/drivers/gpu/drm/arm/malidp_hw.c +++ b/drivers/gpu/drm/arm/malidp_hw.c @@ -22,6 +22,13 @@ #include "malidp_drv.h" #include "malidp_hw.h" +enum { + MW_NOT_ENABLED = 0, /* SE writeback not enabled */ + MW_ONESHOT, /* SE in one-shot mode for writeback */ + MW_START, /* SE started writeback */ + MW_STOP, /* SE finished writeback */ +}; + static const struct malidp_format_id malidp500_de_formats[] = { /* fourcc, layers supporting the format, internal id */ { DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 0 }, @@ -368,6 +375,51 @@ static long malidp500_se_calc_mclk(struct malidp_hw_device *hwdev, return ret; } +static int malidp500_enable_memwrite(struct malidp_hw_device *hwdev, + dma_addr_t *addrs, s32 *pitches, + int num_planes, u16 w, u16 h, u32 fmt_id) +{ + u32 base = MALIDP500_SE_MEMWRITE_BASE; + u32 de_base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK); + + /* enable the scaling engine block */ + malidp_hw_setbits(hwdev, MALIDP_SCALE_ENGINE_EN, de_base + MALIDP_DE_DISPLAY_FUNC); + + hwdev->mw_state = MW_START; + + malidp_hw_write(hwdev, fmt_id, base + MALIDP_MW_FORMAT); + switch (num_planes) { + case 2: + malidp_hw_write(hwdev, lower_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_LOW); + malidp_hw_write(hwdev, upper_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_HIGH); + malidp_hw_write(hwdev, pitches[1], base + MALIDP_MW_P2_STRIDE); + /* fall through */ + case 1: + malidp_hw_write(hwdev, lower_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_LOW); + malidp_hw_write(hwdev, upper_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_HIGH); + malidp_hw_write(hwdev, pitches[0], base + MALIDP_MW_P1_STRIDE); + break; + default: + WARN(1, "Invalid number of planes"); + } + + malidp_hw_write(hwdev, MALIDP_DE_H_ACTIVE(w) | MALIDP_DE_V_ACTIVE(h), + MALIDP500_SE_MEMWRITE_OUT_SIZE); + malidp_hw_setbits(hwdev, MALIDP_SE_MEMWRITE_EN, MALIDP500_SE_CONTROL); + + return 0; +} + +static void malidp500_disable_memwrite(struct malidp_hw_device *hwdev) +{ + u32 base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK); + + if (hwdev->mw_state == MW_START) + hwdev->mw_state = MW_STOP; + malidp_hw_clearbits(hwdev, MALIDP_SE_MEMWRITE_EN, MALIDP500_SE_CONTROL); + malidp_hw_clearbits(hwdev, MALIDP_SCALE_ENGINE_EN, base + MALIDP_DE_DISPLAY_FUNC); +} + static int malidp550_query_hw(struct malidp_hw_device *hwdev) { u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID); @@ -598,6 +650,8 @@ static int malidp550_enable_memwrite(struct malidp_hw_device *hwdev, /* enable the scaling engine block */ malidp_hw_setbits(hwdev, MALIDP_SCALE_ENGINE_EN, de_base + MALIDP_DE_DISPLAY_FUNC); + hwdev->mw_state = MW_ONESHOT; + malidp_hw_write(hwdev, fmt_id, base + MALIDP_MW_FORMAT); switch (num_planes) { case 2: @@ -678,8 +732,9 @@ const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = { }, .se_irq_map = { .irq_mask = MALIDP500_SE_IRQ_CONF_MODE | + MALIDP500_SE_IRQ_CONF_VALID | MALIDP500_SE_IRQ_GLOBAL, - .vsync_irq = 0, + .vsync_irq = MALIDP500_SE_IRQ_CONF_VALID, }, .dc_irq_map = { .irq_mask = MALIDP500_DE_IRQ_CONF_VALID, @@ -698,6 +753,8 @@ const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = { .rotmem_required = malidp500_rotmem_required, .se_set_scaling_coeffs = malidp500_se_set_scaling_coeffs, .se_calc_mclk = malidp500_se_calc_mclk, + .enable_memwrite = malidp500_enable_memwrite, + .disable_memwrite = malidp500_disable_memwrite, .features = MALIDP_DEVICE_LV_HAS_3_STRIDES, }, [MALIDP_550] = { @@ -842,7 +899,7 @@ static irqreturn_t malidp_de_irq(int irq, void *arg) malidp->event = NULL; spin_unlock(&drm->event_lock); } - atomic_set(&malidp->config_valid, 1); + atomic_set(&malidp->config_valid, MALIDP_CONFIG_VALID_DONE); ret = IRQ_WAKE_THREAD; } @@ -936,7 +993,25 @@ static irqreturn_t malidp_se_irq(int irq, void *arg) mask = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_MASKIRQ); status = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_STATUS); status &= mask; - /* ToDo: status decoding and firing up of VSYNC and page flip events */ + + if (status & se->vsync_irq) { + switch (hwdev->mw_state) { + case MW_STOP: + /* disable writeback after stop */ + hwdev->mw_state = MW_NOT_ENABLED; + break; + case MW_START: + /* writeback started, need to emulate one-shot mode */ + hw->disable_memwrite(hwdev); + /* + * only set config_valid HW bit if there is no + * other update in progress + */ + if (atomic_read(&malidp->config_valid) != MALIDP_CONFIG_START) + hw->set_config_valid(hwdev); + break; + } + } malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, status); @@ -966,6 +1041,7 @@ int malidp_se_irq_init(struct drm_device *drm, int irq) return ret; } + hwdev->mw_state = MW_NOT_ENABLED; malidp_hw_enable_irq(hwdev, MALIDP_SE_BLOCK, hwdev->hw->map.se_irq_map.irq_mask); diff --git a/drivers/gpu/drm/arm/malidp_hw.h b/drivers/gpu/drm/arm/malidp_hw.h index a242e97cf6428..c479738b81af5 100644 --- a/drivers/gpu/drm/arm/malidp_hw.h +++ b/drivers/gpu/drm/arm/malidp_hw.h @@ -178,7 +178,7 @@ struct malidp_hw { long (*se_calc_mclk)(struct malidp_hw_device *hwdev, struct malidp_se_config *se_config, struct videomode *vm); - /** + /* * Enable writing to memory the content of the next frame * @param hwdev - malidp_hw_device structure containing the HW description * @param addrs - array of addresses for each plane @@ -232,6 +232,9 @@ struct malidp_hw_device { /* track the device PM state */ bool pm_suspended; + /* track the SE memory writeback state */ + u8 mw_state; + /* size of memory used for rotating layers, up to two banks available */ u32 rotation_memory[2]; }; diff --git a/drivers/gpu/drm/arm/malidp_regs.h b/drivers/gpu/drm/arm/malidp_regs.h index e2b2c496225e3..93b198f3af864 100644 --- a/drivers/gpu/drm/arm/malidp_regs.h +++ b/drivers/gpu/drm/arm/malidp_regs.h @@ -198,7 +198,8 @@ #define MALIDP500_DE_LG2_PTR_BASE 0x0031c #define MALIDP500_SE_BASE 0x00c00 #define MALIDP500_SE_CONTROL 0x00c0c -#define MALIDP500_SE_PTR_BASE 0x00e0c +#define MALIDP500_SE_MEMWRITE_OUT_SIZE 0x00c2c +#define MALIDP500_SE_MEMWRITE_BASE 0x00e00 #define MALIDP500_DC_IRQ_BASE 0x00f00 #define MALIDP500_CONFIG_VALID 0x00f00 #define MALIDP500_CONFIG_ID 0x00fd4 -- GitLab From 09368e32a97587d4e118b800c206b4c86b4db845 Mon Sep 17 00:00:00 2001 From: Liviu Dudau <Liviu.Dudau@arm.com> Date: Thu, 12 Apr 2018 18:13:26 +0100 Subject: [PATCH 0680/1506] drm/mali-dp: Add RGB writeback formats for DP500. Annotate the pixel format matrix for DP500 with the memory-write flag for formats that are supported by the SE memwrite engine. Reviewed-by: Brian Starkey <brian.starkey@arm.com> Signed-off-by: Liviu Dudau <liviu.dudau@arm.com> --- drivers/gpu/drm/arm/malidp_hw.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c index 0f6290b2f768f..36c7e910069a8 100644 --- a/drivers/gpu/drm/arm/malidp_hw.c +++ b/drivers/gpu/drm/arm/malidp_hw.c @@ -31,12 +31,12 @@ enum { static const struct malidp_format_id malidp500_de_formats[] = { /* fourcc, layers supporting the format, internal id */ - { DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 0 }, - { DRM_FORMAT_ABGR2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 1 }, + { DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2 | SE_MEMWRITE, 0 }, + { DRM_FORMAT_ABGR2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2 | SE_MEMWRITE, 1 }, { DRM_FORMAT_ARGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 2 }, { DRM_FORMAT_ABGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 3 }, - { DRM_FORMAT_XRGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 4 }, - { DRM_FORMAT_XBGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 5 }, + { DRM_FORMAT_XRGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2 | SE_MEMWRITE, 4 }, + { DRM_FORMAT_XBGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2 | SE_MEMWRITE, 5 }, { DRM_FORMAT_RGB888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 6 }, { DRM_FORMAT_BGR888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 7 }, { DRM_FORMAT_RGBA5551, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 8 }, @@ -45,7 +45,7 @@ static const struct malidp_format_id malidp500_de_formats[] = { { DRM_FORMAT_BGR565, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 11 }, { DRM_FORMAT_UYVY, DE_VIDEO1, 12 }, { DRM_FORMAT_YUYV, DE_VIDEO1, 13 }, - { DRM_FORMAT_NV12, DE_VIDEO1, 14 }, + { DRM_FORMAT_NV12, DE_VIDEO1 | SE_MEMWRITE, 14 }, { DRM_FORMAT_YUV420, DE_VIDEO1, 15 }, }; -- GitLab From 8cbc5caf36ef7a299b5cbedf55f27fd898d700bf Mon Sep 17 00:00:00 2001 From: Brian Starkey <brian.starkey@arm.com> Date: Thu, 2 Nov 2017 16:49:51 +0000 Subject: [PATCH 0681/1506] drm: mali-dp: Add writeback connector Mali-DP has a memory writeback engine which can be used to write the composition result to a memory buffer. Expose this functionality as a DRM writeback connector on supported hardware. Changes since v1: Daniel Vetter: - Don't require a modeset when writeback routing changes - Make writeback connector always disconnected Changes since v2: - Rebase onto new drm_writeback_connector - Add reset callback, allocating subclassed state Daniel Vetter: - Squash out-fence support into this commit Gustavo Padovan: - Don't signal fence directly from driver (and drop malidp_mw_job) Changes since v3: - Modifications to fit with Mali-DP commit tail changes Signed-off-by: Brian Starkey <brian.starkey@arm.com> [rebased and fixed conflicts] Signed-off-by: Mihail Atanassov <mihail.atanassov@arm.com> Signed-off-by: Liviu Dudau <liviu.dudau@arm.com> --- drivers/gpu/drm/arm/Makefile | 1 + drivers/gpu/drm/arm/malidp_crtc.c | 10 ++ drivers/gpu/drm/arm/malidp_drv.c | 19 ++- drivers/gpu/drm/arm/malidp_drv.h | 3 + drivers/gpu/drm/arm/malidp_hw.c | 5 + drivers/gpu/drm/arm/malidp_mw.c | 250 ++++++++++++++++++++++++++++++ drivers/gpu/drm/arm/malidp_mw.h | 14 ++ drivers/gpu/drm/drm_atomic.c | 4 + 8 files changed, 301 insertions(+), 5 deletions(-) create mode 100644 drivers/gpu/drm/arm/malidp_mw.c create mode 100644 drivers/gpu/drm/arm/malidp_mw.h diff --git a/drivers/gpu/drm/arm/Makefile b/drivers/gpu/drm/arm/Makefile index bb8b158ff90d0..3bf31d1a4722c 100644 --- a/drivers/gpu/drm/arm/Makefile +++ b/drivers/gpu/drm/arm/Makefile @@ -1,4 +1,5 @@ hdlcd-y := hdlcd_drv.o hdlcd_crtc.o obj-$(CONFIG_DRM_HDLCD) += hdlcd.o mali-dp-y := malidp_drv.o malidp_hw.o malidp_planes.o malidp_crtc.o +mali-dp-y += malidp_mw.o obj-$(CONFIG_DRM_MALI_DISPLAY) += mali-dp.o diff --git a/drivers/gpu/drm/arm/malidp_crtc.c b/drivers/gpu/drm/arm/malidp_crtc.c index fcc62bc60f6a7..ef44202fb43f8 100644 --- a/drivers/gpu/drm/arm/malidp_crtc.c +++ b/drivers/gpu/drm/arm/malidp_crtc.c @@ -411,6 +411,16 @@ static int malidp_crtc_atomic_check(struct drm_crtc *crtc, } } + /* If only the writeback routing has changed, we don't need a modeset */ + if (state->connectors_changed) { + u32 old_mask = crtc->state->connector_mask; + u32 new_mask = state->connector_mask; + + if ((old_mask ^ new_mask) == + (1 << drm_connector_index(&malidp->mw_connector.base))) + state->connectors_changed = false; + } + ret = malidp_crtc_atomic_check_gamma(crtc, state); ret = ret ? ret : malidp_crtc_atomic_check_ctm(crtc, state); ret = ret ? ret : malidp_crtc_atomic_check_scaling(crtc, state); diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c index ab2d27e8bdd97..e58a759fd3be3 100644 --- a/drivers/gpu/drm/arm/malidp_drv.c +++ b/drivers/gpu/drm/arm/malidp_drv.c @@ -31,6 +31,7 @@ #include <drm/drm_of.h> #include "malidp_drv.h" +#include "malidp_mw.h" #include "malidp_regs.h" #include "malidp_hw.h" @@ -238,7 +239,9 @@ static void malidp_atomic_commit_tail(struct drm_atomic_state *state) malidp_atomic_commit_se_config(crtc, old_crtc_state); } - drm_atomic_helper_commit_planes(drm, state, 0); + drm_atomic_helper_commit_planes(drm, state, DRM_PLANE_COMMIT_ACTIVE_ONLY); + + malidp_mw_atomic_commit(drm, state); drm_atomic_helper_commit_modeset_enables(drm, state); @@ -276,12 +279,18 @@ static int malidp_init(struct drm_device *drm) drm->mode_config.helper_private = &malidp_mode_config_helpers; ret = malidp_crtc_init(drm); - if (ret) { - drm_mode_config_cleanup(drm); - return ret; - } + if (ret) + goto crtc_fail; + + ret = malidp_mw_connector_init(drm); + if (ret) + goto crtc_fail; return 0; + +crtc_fail: + drm_mode_config_cleanup(drm); + return ret; } static void malidp_fini(struct drm_device *drm) diff --git a/drivers/gpu/drm/arm/malidp_drv.h b/drivers/gpu/drm/arm/malidp_drv.h index e8c41cf1b5bd2..5febd4b43e058 100644 --- a/drivers/gpu/drm/arm/malidp_drv.h +++ b/drivers/gpu/drm/arm/malidp_drv.h @@ -13,6 +13,8 @@ #ifndef __MALIDP_DRV_H__ #define __MALIDP_DRV_H__ +#include <drm/drm_writeback.h> +#include <drm/drm_encoder.h> #include <linux/mutex.h> #include <linux/wait.h> #include <drm/drmP.h> @@ -25,6 +27,7 @@ struct malidp_drm { struct malidp_hw_device *dev; struct drm_crtc crtc; + struct drm_writeback_connector mw_connector; wait_queue_head_t wq; struct drm_pending_vblank_event *event; atomic_t config_valid; diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c index 36c7e910069a8..449b7ef0a77f9 100644 --- a/drivers/gpu/drm/arm/malidp_hw.c +++ b/drivers/gpu/drm/arm/malidp_hw.c @@ -21,6 +21,7 @@ #include "malidp_drv.h" #include "malidp_hw.h" +#include "malidp_mw.h" enum { MW_NOT_ENABLED = 0, /* SE writeback not enabled */ @@ -996,7 +997,11 @@ static irqreturn_t malidp_se_irq(int irq, void *arg) if (status & se->vsync_irq) { switch (hwdev->mw_state) { + case MW_ONESHOT: + drm_writeback_signal_completion(&malidp->mw_connector, 0); + break; case MW_STOP: + drm_writeback_signal_completion(&malidp->mw_connector, 0); /* disable writeback after stop */ hwdev->mw_state = MW_NOT_ENABLED; break; diff --git a/drivers/gpu/drm/arm/malidp_mw.c b/drivers/gpu/drm/arm/malidp_mw.c new file mode 100644 index 0000000000000..cfd718e7e97c1 --- /dev/null +++ b/drivers/gpu/drm/arm/malidp_mw.c @@ -0,0 +1,250 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * (C) COPYRIGHT 2016 ARM Limited. All rights reserved. + * Author: Brian Starkey <brian.starkey@arm.com> + * + * ARM Mali DP Writeback connector implementation + */ +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_helper.h> +#include <drm/drm_crtc.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_gem_cma_helper.h> +#include <drm/drmP.h> +#include <drm/drm_writeback.h> + +#include "malidp_drv.h" +#include "malidp_hw.h" +#include "malidp_mw.h" + +#define to_mw_state(_state) (struct malidp_mw_connector_state *)(_state) + +struct malidp_mw_connector_state { + struct drm_connector_state base; + dma_addr_t addrs[2]; + s32 pitches[2]; + u8 format; + u8 n_planes; +}; + +static int malidp_mw_connector_get_modes(struct drm_connector *connector) +{ + struct drm_device *dev = connector->dev; + + return drm_add_modes_noedid(connector, dev->mode_config.max_width, + dev->mode_config.max_height); +} + +static enum drm_mode_status +malidp_mw_connector_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + struct drm_device *dev = connector->dev; + struct drm_mode_config *mode_config = &dev->mode_config; + int w = mode->hdisplay, h = mode->vdisplay; + + if ((w < mode_config->min_width) || (w > mode_config->max_width)) + return MODE_BAD_HVALUE; + + if ((h < mode_config->min_height) || (h > mode_config->max_height)) + return MODE_BAD_VVALUE; + + return MODE_OK; +} + +const struct drm_connector_helper_funcs malidp_mw_connector_helper_funcs = { + .get_modes = malidp_mw_connector_get_modes, + .mode_valid = malidp_mw_connector_mode_valid, +}; + +static void malidp_mw_connector_reset(struct drm_connector *connector) +{ + struct malidp_mw_connector_state *mw_state = + kzalloc(sizeof(*mw_state), GFP_KERNEL); + + if (connector->state) + __drm_atomic_helper_connector_destroy_state(connector->state); + + kfree(connector->state); + __drm_atomic_helper_connector_reset(connector, &mw_state->base); +} + +static enum drm_connector_status +malidp_mw_connector_detect(struct drm_connector *connector, bool force) +{ + return connector_status_disconnected; +} + +static void malidp_mw_connector_destroy(struct drm_connector *connector) +{ + drm_connector_cleanup(connector); +} + +static struct drm_connector_state * +malidp_mw_connector_duplicate_state(struct drm_connector *connector) +{ + struct malidp_mw_connector_state *mw_state; + + if (WARN_ON(!connector->state)) + return NULL; + + mw_state = kzalloc(sizeof(*mw_state), GFP_KERNEL); + if (!mw_state) + return NULL; + + /* No need to preserve any of our driver-local data */ + __drm_atomic_helper_connector_duplicate_state(connector, &mw_state->base); + + return &mw_state->base; +} + +static const struct drm_connector_funcs malidp_mw_connector_funcs = { + .reset = malidp_mw_connector_reset, + .detect = malidp_mw_connector_detect, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = malidp_mw_connector_destroy, + .atomic_duplicate_state = malidp_mw_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +}; + +static int +malidp_mw_encoder_atomic_check(struct drm_encoder *encoder, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct malidp_mw_connector_state *mw_state = to_mw_state(conn_state); + struct malidp_drm *malidp = encoder->dev->dev_private; + struct drm_framebuffer *fb; + int i, n_planes; + + if (!conn_state->writeback_job || !conn_state->writeback_job->fb) + return 0; + + fb = conn_state->writeback_job->fb; + if ((fb->width != crtc_state->mode.hdisplay) || + (fb->height != crtc_state->mode.vdisplay)) { + DRM_DEBUG_KMS("Invalid framebuffer size %ux%u\n", + fb->width, fb->height); + return -EINVAL; + } + + mw_state->format = + malidp_hw_get_format_id(&malidp->dev->hw->map, SE_MEMWRITE, + fb->format->format); + if (mw_state->format == MALIDP_INVALID_FORMAT_ID) { + struct drm_format_name_buf format_name; + + DRM_DEBUG_KMS("Invalid pixel format %s\n", + drm_get_format_name(fb->format->format, + &format_name)); + return -EINVAL; + } + + n_planes = drm_format_num_planes(fb->format->format); + for (i = 0; i < n_planes; i++) { + struct drm_gem_cma_object *obj = drm_fb_cma_get_gem_obj(fb, i); + /* memory write buffers are never rotated */ + u8 alignment = malidp_hw_get_pitch_align(malidp->dev, 0); + + if (fb->pitches[i] & (alignment - 1)) { + DRM_DEBUG_KMS("Invalid pitch %u for plane %d\n", + fb->pitches[i], i); + return -EINVAL; + } + mw_state->pitches[i] = fb->pitches[i]; + mw_state->addrs[i] = obj->paddr + fb->offsets[i]; + } + mw_state->n_planes = n_planes; + + return 0; +} + +static const struct drm_encoder_helper_funcs malidp_mw_encoder_helper_funcs = { + .atomic_check = malidp_mw_encoder_atomic_check, +}; + +static u32 *get_writeback_formats(struct malidp_drm *malidp, int *n_formats) +{ + const struct malidp_hw_regmap *map = &malidp->dev->hw->map; + u32 *formats; + int n, i; + + formats = kcalloc(map->n_pixel_formats, sizeof(*formats), + GFP_KERNEL); + if (!formats) + return NULL; + + for (n = 0, i = 0; i < map->n_pixel_formats; i++) { + if (map->pixel_formats[i].layer & SE_MEMWRITE) + formats[n++] = map->pixel_formats[i].format; + } + + *n_formats = n; + + return formats; +} + +int malidp_mw_connector_init(struct drm_device *drm) +{ + struct malidp_drm *malidp = drm->dev_private; + u32 *formats; + int ret, n_formats; + + if (!malidp->dev->hw->enable_memwrite) + return 0; + + malidp->mw_connector.encoder.possible_crtcs = 1 << drm_crtc_index(&malidp->crtc); + drm_connector_helper_add(&malidp->mw_connector.base, + &malidp_mw_connector_helper_funcs); + + formats = get_writeback_formats(malidp, &n_formats); + if (!formats) + return -ENOMEM; + + ret = drm_writeback_connector_init(drm, &malidp->mw_connector, + &malidp_mw_connector_funcs, + &malidp_mw_encoder_helper_funcs, + formats, n_formats); + kfree(formats); + if (ret) + return ret; + + return 0; +} + +void malidp_mw_atomic_commit(struct drm_device *drm, + struct drm_atomic_state *old_state) +{ + struct malidp_drm *malidp = drm->dev_private; + struct drm_writeback_connector *mw_conn = &malidp->mw_connector; + struct drm_connector_state *conn_state = mw_conn->base.state; + struct malidp_hw_device *hwdev = malidp->dev; + struct malidp_mw_connector_state *mw_state; + + if (!conn_state) + return; + + mw_state = to_mw_state(conn_state); + + if (conn_state->writeback_job && conn_state->writeback_job->fb) { + struct drm_framebuffer *fb = conn_state->writeback_job->fb; + + DRM_DEV_DEBUG_DRIVER(drm->dev, + "Enable memwrite %ux%u:%d %pad fmt: %u\n", + fb->width, fb->height, + mw_state->pitches[0], + &mw_state->addrs[0], + mw_state->format); + + drm_writeback_queue_job(mw_conn, conn_state->writeback_job); + conn_state->writeback_job = NULL; + + hwdev->hw->enable_memwrite(hwdev, mw_state->addrs, + mw_state->pitches, mw_state->n_planes, + fb->width, fb->height, mw_state->format); + } else { + DRM_DEV_DEBUG_DRIVER(drm->dev, "Disable memwrite\n"); + hwdev->hw->disable_memwrite(hwdev); + } +} diff --git a/drivers/gpu/drm/arm/malidp_mw.h b/drivers/gpu/drm/arm/malidp_mw.h new file mode 100644 index 0000000000000..19a007676a1db --- /dev/null +++ b/drivers/gpu/drm/arm/malidp_mw.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * (C) COPYRIGHT 2016 ARM Limited. All rights reserved. + * Author: Brian Starkey <brian.starkey@arm.com> + * + */ + +#ifndef __MALIDP_MW_H__ +#define __MALIDP_MW_H__ + +int malidp_mw_connector_init(struct drm_device *drm); +void malidp_mw_atomic_commit(struct drm_device *drm, + struct drm_atomic_state *old_state); +#endif diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 178842380f758..965be21b82809 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1436,6 +1436,10 @@ static void drm_atomic_connector_print_state(struct drm_printer *p, drm_printf(p, "connector[%u]: %s\n", connector->base.id, connector->name); drm_printf(p, "\tcrtc=%s\n", state->crtc ? state->crtc->name : "(null)"); + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + if (state->writeback_job && state->writeback_job->fb) + drm_printf(p, "\tfb=%d\n", state->writeback_job->fb->base.id); + if (connector->funcs->atomic_print_state) connector->funcs->atomic_print_state(p, state); } -- GitLab From 0735cfdf0af4d4ffc3743fb75b9ad929dfd37206 Mon Sep 17 00:00:00 2001 From: Liviu Dudau <Liviu.Dudau@arm.com> Date: Fri, 15 Jun 2018 16:56:09 +0100 Subject: [PATCH 0682/1506] drm/mali-dp: Improve writeback handling for DP500. Mali DP500 operates in continuous writeback mode (writes frame content until stopped) and it needs special handling in order to behave like a one-shot writeback engine. The original state machine added for DP500 was a bit fragile, as it did not handle correctly cases where a new atomic commit was in progress when the SE IRQ happens and it would commit some partial updates. Improve the handling by adding a parameter to the set_config_valid() function to clear the config valid bit in hardware before starting a new commit and by introducing a MW_RESTART state in the writeback state machine to cater for the case where a new writeback commit gets submitted while the last one is still being active. Reported-by: Brian Starkey <brian.starkey@arm.com> Reviewed-by: Brian Starkey <brian.starkey@arm.com> Signed-off-by: Liviu Dudau <liviu.dudau@arm.com> --- drivers/gpu/drm/arm/malidp_drv.c | 3 ++- drivers/gpu/drm/arm/malidp_hw.c | 39 +++++++++++++++++++++++--------- drivers/gpu/drm/arm/malidp_hw.h | 11 +++++---- 3 files changed, 36 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c index e58a759fd3be3..078b232c91ab3 100644 --- a/drivers/gpu/drm/arm/malidp_drv.c +++ b/drivers/gpu/drm/arm/malidp_drv.c @@ -171,7 +171,7 @@ static int malidp_set_and_wait_config_valid(struct drm_device *drm) struct malidp_hw_device *hwdev = malidp->dev; int ret; - hwdev->hw->set_config_valid(hwdev); + hwdev->hw->set_config_valid(hwdev, 1); /* don't wait for config_valid flag if we are in config mode */ if (hwdev->hw->in_config_mode(hwdev)) { atomic_set(&malidp->config_valid, MALIDP_CONFIG_VALID_DONE); @@ -230,6 +230,7 @@ static void malidp_atomic_commit_tail(struct drm_atomic_state *state) * know that we are updating registers */ atomic_set(&malidp->config_valid, MALIDP_CONFIG_START); + malidp->dev->hw->set_config_valid(malidp->dev, 0); drm_atomic_helper_commit_modeset_disables(drm, state); diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c index 449b7ef0a77f9..b5c645cf4d1c0 100644 --- a/drivers/gpu/drm/arm/malidp_hw.c +++ b/drivers/gpu/drm/arm/malidp_hw.c @@ -27,7 +27,8 @@ enum { MW_NOT_ENABLED = 0, /* SE writeback not enabled */ MW_ONESHOT, /* SE in one-shot mode for writeback */ MW_START, /* SE started writeback */ - MW_STOP, /* SE finished writeback */ + MW_RESTART, /* SE will start another writeback after this one */ + MW_STOP, /* SE needs to stop after this writeback */ }; static const struct malidp_format_id malidp500_de_formats[] = { @@ -231,9 +232,12 @@ static bool malidp500_in_config_mode(struct malidp_hw_device *hwdev) return false; } -static void malidp500_set_config_valid(struct malidp_hw_device *hwdev) +static void malidp500_set_config_valid(struct malidp_hw_device *hwdev, u8 value) { - malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID); + if (value) + malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID); + else + malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID); } static void malidp500_modeset(struct malidp_hw_device *hwdev, struct videomode *mode) @@ -386,7 +390,11 @@ static int malidp500_enable_memwrite(struct malidp_hw_device *hwdev, /* enable the scaling engine block */ malidp_hw_setbits(hwdev, MALIDP_SCALE_ENGINE_EN, de_base + MALIDP_DE_DISPLAY_FUNC); - hwdev->mw_state = MW_START; + /* restart the writeback if already enabled */ + if (hwdev->mw_state != MW_NOT_ENABLED) + hwdev->mw_state = MW_RESTART; + else + hwdev->mw_state = MW_START; malidp_hw_write(hwdev, fmt_id, base + MALIDP_MW_FORMAT); switch (num_planes) { @@ -415,7 +423,7 @@ static void malidp500_disable_memwrite(struct malidp_hw_device *hwdev) { u32 base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK); - if (hwdev->mw_state == MW_START) + if (hwdev->mw_state == MW_START || hwdev->mw_state == MW_RESTART) hwdev->mw_state = MW_STOP; malidp_hw_clearbits(hwdev, MALIDP_SE_MEMWRITE_EN, MALIDP500_SE_CONTROL); malidp_hw_clearbits(hwdev, MALIDP_SCALE_ENGINE_EN, base + MALIDP_DE_DISPLAY_FUNC); @@ -500,9 +508,12 @@ static bool malidp550_in_config_mode(struct malidp_hw_device *hwdev) return false; } -static void malidp550_set_config_valid(struct malidp_hw_device *hwdev) +static void malidp550_set_config_valid(struct malidp_hw_device *hwdev, u8 value) { - malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID); + if (value) + malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID); + else + malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID); } static void malidp550_modeset(struct malidp_hw_device *hwdev, struct videomode *mode) @@ -1005,15 +1016,21 @@ static irqreturn_t malidp_se_irq(int irq, void *arg) /* disable writeback after stop */ hwdev->mw_state = MW_NOT_ENABLED; break; + case MW_RESTART: + drm_writeback_signal_completion(&malidp->mw_connector, 0); + /* fall through to a new start */ case MW_START: /* writeback started, need to emulate one-shot mode */ hw->disable_memwrite(hwdev); /* - * only set config_valid HW bit if there is no - * other update in progress + * only set config_valid HW bit if there is no other update + * in progress or if we raced ahead of the DE IRQ handler + * and config_valid flag will not be update until later */ - if (atomic_read(&malidp->config_valid) != MALIDP_CONFIG_START) - hw->set_config_valid(hwdev); + status = malidp_hw_read(hwdev, hw->map.dc_base + MALIDP_REG_STATUS); + if ((atomic_read(&malidp->config_valid) != MALIDP_CONFIG_START) || + (status & hw->map.dc_irq_map.vsync_irq)) + hw->set_config_valid(hwdev, 1); break; } } diff --git a/drivers/gpu/drm/arm/malidp_hw.h b/drivers/gpu/drm/arm/malidp_hw.h index c479738b81af5..bd41aa6974a06 100644 --- a/drivers/gpu/drm/arm/malidp_hw.h +++ b/drivers/gpu/drm/arm/malidp_hw.h @@ -152,12 +152,13 @@ struct malidp_hw { bool (*in_config_mode)(struct malidp_hw_device *hwdev); /* - * Set configuration valid flag for hardware parameters that can - * be changed outside the configuration mode. Hardware will use - * the new settings when config valid is set after the end of the - * current buffer scanout + * Set/clear configuration valid flag for hardware parameters that can + * be changed outside the configuration mode to the given value. + * Hardware will use the new settings when config valid is set, + * after the end of the current buffer scanout, and will ignore + * any new values for those parameters if config valid flag is cleared */ - void (*set_config_valid)(struct malidp_hw_device *hwdev); + void (*set_config_valid)(struct malidp_hw_device *hwdev, u8 value); /* * Set a new mode in hardware. Requires the hardware to be in -- GitLab From 613c5c7fc8152866a798c52a5944e4b437b526f5 Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe <alexandru-cosmin.gheorghe@arm.com> Date: Tue, 15 May 2018 11:18:50 +0100 Subject: [PATCH 0683/1506] drm: mali-dp: Add debugfs file for reporting internal errors Status register contains a lot of bits for reporting internal errors inside Mali DP. Currently, we just silently ignore all of the errors, that doesn't help when we are investigating different bugs, especially on the FPGA models which have a lot of constraints, so we could easily end up in AXI or underrun errors. Add a new file called debug that contains an aggregate of the errors reported by the Mali DP hardware. E.g: [root@alarm ~]# cat /sys/kernel/debug/dri/1/debug [DE] num_errors : 167 [DE] last_error_status : 0x00000001 [DE] last_error_vblank : 385 [SE] num_errors : 3 [SE] last_error_status : 0x00e23001 [SE] last_error_vblank : 201 Changes since v2: - Add lock to protect the errors stats. - Add possibility to reset the error stats by writing anything to the debug file. Signed-off-by: Alexandru Gheorghe <alexandru-cosmin.gheorghe@arm.com> Acked-by: Liviu Dudau <liviu.dudau@arm.com> Signed-off-by: Liviu Dudau <liviu.dudau@arm.com> --- drivers/gpu/drm/arm/malidp_drv.c | 104 ++++++++++++++++++++++++++++++ drivers/gpu/drm/arm/malidp_drv.h | 19 ++++++ drivers/gpu/drm/arm/malidp_hw.c | 46 +++++++++++-- drivers/gpu/drm/arm/malidp_hw.h | 1 + drivers/gpu/drm/arm/malidp_regs.h | 6 ++ 5 files changed, 169 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c index 078b232c91ab3..9b710f6999ed3 100644 --- a/drivers/gpu/drm/arm/malidp_drv.c +++ b/drivers/gpu/drm/arm/malidp_drv.c @@ -17,6 +17,7 @@ #include <linux/of_graph.h> #include <linux/of_reserved_mem.h> #include <linux/pm_runtime.h> +#include <linux/debugfs.h> #include <drm/drmP.h> #include <drm/drm_atomic.h> @@ -344,6 +345,106 @@ static int malidp_dumb_create(struct drm_file *file_priv, return drm_gem_cma_dumb_create_internal(file_priv, drm, args); } +#ifdef CONFIG_DEBUG_FS + +static void malidp_error_stats_init(struct malidp_error_stats *error_stats) +{ + error_stats->num_errors = 0; + error_stats->last_error_status = 0; + error_stats->last_error_vblank = -1; +} + +void malidp_error(struct malidp_drm *malidp, + struct malidp_error_stats *error_stats, u32 status, + u64 vblank) +{ + unsigned long irqflags; + + spin_lock_irqsave(&malidp->errors_lock, irqflags); + error_stats->last_error_status = status; + error_stats->last_error_vblank = vblank; + error_stats->num_errors++; + spin_unlock_irqrestore(&malidp->errors_lock, irqflags); +} + +void malidp_error_stats_dump(const char *prefix, + struct malidp_error_stats error_stats, + struct seq_file *m) +{ + seq_printf(m, "[%s] num_errors : %d\n", prefix, + error_stats.num_errors); + seq_printf(m, "[%s] last_error_status : 0x%08x\n", prefix, + error_stats.last_error_status); + seq_printf(m, "[%s] last_error_vblank : %lld\n", prefix, + error_stats.last_error_vblank); +} + +static int malidp_show_stats(struct seq_file *m, void *arg) +{ + struct drm_device *drm = m->private; + struct malidp_drm *malidp = drm->dev_private; + unsigned long irqflags; + struct malidp_error_stats de_errors, se_errors; + + spin_lock_irqsave(&malidp->errors_lock, irqflags); + de_errors = malidp->de_errors; + se_errors = malidp->se_errors; + spin_unlock_irqrestore(&malidp->errors_lock, irqflags); + malidp_error_stats_dump("DE", de_errors, m); + malidp_error_stats_dump("SE", se_errors, m); + return 0; +} + +static int malidp_debugfs_open(struct inode *inode, struct file *file) +{ + return single_open(file, malidp_show_stats, inode->i_private); +} + +static ssize_t malidp_debugfs_write(struct file *file, const char __user *ubuf, + size_t len, loff_t *offp) +{ + struct seq_file *m = file->private_data; + struct drm_device *drm = m->private; + struct malidp_drm *malidp = drm->dev_private; + unsigned long irqflags; + + spin_lock_irqsave(&malidp->errors_lock, irqflags); + malidp_error_stats_init(&malidp->de_errors); + malidp_error_stats_init(&malidp->se_errors); + spin_unlock_irqrestore(&malidp->errors_lock, irqflags); + return len; +} + +static const struct file_operations malidp_debugfs_fops = { + .owner = THIS_MODULE, + .open = malidp_debugfs_open, + .read = seq_read, + .write = malidp_debugfs_write, + .llseek = seq_lseek, + .release = single_release, +}; + +static int malidp_debugfs_init(struct drm_minor *minor) +{ + struct malidp_drm *malidp = minor->dev->dev_private; + struct dentry *dentry = NULL; + + malidp_error_stats_init(&malidp->de_errors); + malidp_error_stats_init(&malidp->se_errors); + spin_lock_init(&malidp->errors_lock); + dentry = debugfs_create_file("debug", + S_IRUGO | S_IWUSR, + minor->debugfs_root, minor->dev, + &malidp_debugfs_fops); + if (!dentry) { + DRM_ERROR("Cannot create debug file\n"); + return -ENOMEM; + } + return 0; +} + +#endif //CONFIG_DEBUG_FS + static struct drm_driver malidp_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_PRIME, @@ -360,6 +461,9 @@ static struct drm_driver malidp_driver = { .gem_prime_vmap = drm_gem_cma_prime_vmap, .gem_prime_vunmap = drm_gem_cma_prime_vunmap, .gem_prime_mmap = drm_gem_cma_prime_mmap, +#ifdef CONFIG_DEBUG_FS + .debugfs_init = malidp_debugfs_init, +#endif .fops = &fops, .name = "mali-dp", .desc = "ARM Mali Display Processor driver", diff --git a/drivers/gpu/drm/arm/malidp_drv.h b/drivers/gpu/drm/arm/malidp_drv.h index 5febd4b43e058..e3eb0cb1f385d 100644 --- a/drivers/gpu/drm/arm/malidp_drv.h +++ b/drivers/gpu/drm/arm/malidp_drv.h @@ -17,6 +17,7 @@ #include <drm/drm_encoder.h> #include <linux/mutex.h> #include <linux/wait.h> +#include <linux/spinlock.h> #include <drm/drmP.h> #include "malidp_hw.h" @@ -24,6 +25,12 @@ #define MALIDP_CONFIG_VALID_DONE 1 #define MALIDP_CONFIG_START 0xd0 +struct malidp_error_stats { + s32 num_errors; + u32 last_error_status; + s64 last_error_vblank; +}; + struct malidp_drm { struct malidp_hw_device *dev; struct drm_crtc crtc; @@ -32,6 +39,12 @@ struct malidp_drm { struct drm_pending_vblank_event *event; atomic_t config_valid; u32 core_id; +#ifdef CONFIG_DEBUG_FS + struct malidp_error_stats de_errors; + struct malidp_error_stats se_errors; + /* Protects errors stats */ + spinlock_t errors_lock; +#endif }; #define crtc_to_malidp_device(x) container_of(x, struct malidp_drm, crtc) @@ -69,6 +82,12 @@ struct malidp_crtc_state { int malidp_de_planes_init(struct drm_device *drm); int malidp_crtc_init(struct drm_device *drm); +#ifdef CONFIG_DEBUG_FS +void malidp_error(struct malidp_drm *malidp, + struct malidp_error_stats *error_stats, u32 status, + u64 vblank); +#endif + /* often used combination of rotational bits */ #define MALIDP_ROTATED_MASK (DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270) diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c index b5c645cf4d1c0..3dfad2f97c2a7 100644 --- a/drivers/gpu/drm/arm/malidp_hw.c +++ b/drivers/gpu/drm/arm/malidp_hw.c @@ -741,12 +741,18 @@ const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = { MALIDP500_DE_IRQ_VSYNC | MALIDP500_DE_IRQ_GLOBAL, .vsync_irq = MALIDP500_DE_IRQ_VSYNC, + .err_mask = MALIDP_DE_IRQ_UNDERRUN | + MALIDP500_DE_IRQ_AXI_ERR | + MALIDP500_DE_IRQ_SATURATION, }, .se_irq_map = { .irq_mask = MALIDP500_SE_IRQ_CONF_MODE | MALIDP500_SE_IRQ_CONF_VALID | MALIDP500_SE_IRQ_GLOBAL, .vsync_irq = MALIDP500_SE_IRQ_CONF_VALID, + .err_mask = MALIDP500_SE_IRQ_INIT_BUSY | + MALIDP500_SE_IRQ_AXI_ERROR | + MALIDP500_SE_IRQ_OVERRUN, }, .dc_irq_map = { .irq_mask = MALIDP500_DE_IRQ_CONF_VALID, @@ -782,11 +788,16 @@ const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = { .irq_mask = MALIDP_DE_IRQ_UNDERRUN | MALIDP550_DE_IRQ_VSYNC, .vsync_irq = MALIDP550_DE_IRQ_VSYNC, + .err_mask = MALIDP_DE_IRQ_UNDERRUN | + MALIDP550_DE_IRQ_SATURATION | + MALIDP550_DE_IRQ_AXI_ERR, }, .se_irq_map = { - .irq_mask = MALIDP550_SE_IRQ_EOW | - MALIDP550_SE_IRQ_AXI_ERR, + .irq_mask = MALIDP550_SE_IRQ_EOW, .vsync_irq = MALIDP550_SE_IRQ_EOW, + .err_mask = MALIDP550_SE_IRQ_AXI_ERR | + MALIDP550_SE_IRQ_OVR | + MALIDP550_SE_IRQ_IBSY, }, .dc_irq_map = { .irq_mask = MALIDP550_DC_IRQ_CONF_VALID | @@ -824,11 +835,21 @@ const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = { MALIDP650_DE_IRQ_DRIFT | MALIDP550_DE_IRQ_VSYNC, .vsync_irq = MALIDP550_DE_IRQ_VSYNC, + .err_mask = MALIDP_DE_IRQ_UNDERRUN | + MALIDP650_DE_IRQ_DRIFT | + MALIDP550_DE_IRQ_SATURATION | + MALIDP550_DE_IRQ_AXI_ERR | + MALIDP650_DE_IRQ_ACEV1 | + MALIDP650_DE_IRQ_ACEV2 | + MALIDP650_DE_IRQ_ACEG | + MALIDP650_DE_IRQ_AXIEP, }, .se_irq_map = { - .irq_mask = MALIDP550_SE_IRQ_EOW | - MALIDP550_SE_IRQ_AXI_ERR, + .irq_mask = MALIDP550_SE_IRQ_EOW, .vsync_irq = MALIDP550_SE_IRQ_EOW, + .err_mask = MALIDP550_SE_IRQ_AXI_ERR | + MALIDP550_SE_IRQ_OVR | + MALIDP550_SE_IRQ_IBSY, }, .dc_irq_map = { .irq_mask = MALIDP550_DC_IRQ_CONF_VALID | @@ -920,10 +941,17 @@ static irqreturn_t malidp_de_irq(int irq, void *arg) return ret; mask = malidp_hw_read(hwdev, MALIDP_REG_MASKIRQ); - status &= mask; + /* keep the status of the enabled interrupts, plus the error bits */ + status &= (mask | de->err_mask); if ((status & de->vsync_irq) && malidp->crtc.enabled) drm_crtc_handle_vblank(&malidp->crtc); +#ifdef CONFIG_DEBUG_FS + if (status & de->err_mask) { + malidp_error(malidp, &malidp->de_errors, status, + drm_crtc_vblank_count(&malidp->crtc)); + } +#endif malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, status); return (ret == IRQ_NONE) ? IRQ_HANDLED : ret; @@ -999,11 +1027,15 @@ static irqreturn_t malidp_se_irq(int irq, void *arg) return IRQ_NONE; status = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_STATUS); - if (!(status & se->irq_mask)) + if (!(status & (se->irq_mask | se->err_mask))) return IRQ_NONE; +#ifdef CONFIG_DEBUG_FS + if (status & se->err_mask) + malidp_error(malidp, &malidp->se_errors, status, + drm_crtc_vblank_count(&malidp->crtc)); +#endif mask = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_MASKIRQ); - status = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_STATUS); status &= mask; if (status & se->vsync_irq) { diff --git a/drivers/gpu/drm/arm/malidp_hw.h b/drivers/gpu/drm/arm/malidp_hw.h index bd41aa6974a06..5b99445433a28 100644 --- a/drivers/gpu/drm/arm/malidp_hw.h +++ b/drivers/gpu/drm/arm/malidp_hw.h @@ -53,6 +53,7 @@ struct malidp_format_id { struct malidp_irq_map { u32 irq_mask; /* mask of IRQs that can be enabled in the block */ u32 vsync_irq; /* IRQ bit used for signaling during VSYNC */ + u32 err_mask; /* mask of bits that represent errors */ }; struct malidp_layer { diff --git a/drivers/gpu/drm/arm/malidp_regs.h b/drivers/gpu/drm/arm/malidp_regs.h index 93b198f3af864..3579d36b2a717 100644 --- a/drivers/gpu/drm/arm/malidp_regs.h +++ b/drivers/gpu/drm/arm/malidp_regs.h @@ -53,6 +53,8 @@ #define MALIDP550_DE_IRQ_AXI_ERR (1 << 16) #define MALIDP550_SE_IRQ_EOW (1 << 0) #define MALIDP550_SE_IRQ_AXI_ERR (1 << 16) +#define MALIDP550_SE_IRQ_OVR (1 << 17) +#define MALIDP550_SE_IRQ_IBSY (1 << 18) #define MALIDP550_DC_IRQ_CONF_VALID (1 << 0) #define MALIDP550_DC_IRQ_CONF_MODE (1 << 4) #define MALIDP550_DC_IRQ_CONF_ACTIVE (1 << 16) @@ -60,6 +62,10 @@ #define MALIDP550_DC_IRQ_SE (1 << 24) #define MALIDP650_DE_IRQ_DRIFT (1 << 4) +#define MALIDP650_DE_IRQ_ACEV1 (1 << 17) +#define MALIDP650_DE_IRQ_ACEV2 (1 << 18) +#define MALIDP650_DE_IRQ_ACEG (1 << 19) +#define MALIDP650_DE_IRQ_AXIEP (1 << 28) /* bit masks that are common between products */ #define MALIDP_CFG_VALID (1 << 0) -- GitLab From 62862cfbb18d10c5f8409f4c8e49c4bbaaf18d3a Mon Sep 17 00:00:00 2001 From: Ayan Kumar Halder <ayan.halder@arm.com> Date: Tue, 15 May 2018 17:04:15 +0100 Subject: [PATCH 0684/1506] drm/arm/malidp: Modified the prototype of malidp irq de-initializers Malidp uses two interrupts ie 1. se_irq - used for memory writeback. and 2. de_irq - used for display output. 'struct drm_device' is being replaced with 'struct malidp_hw_device' as the function argument. The reason being the dependency of malidp_de_irq_fini on 'struct drm_device' needs to be removed so as to enable it to call from functions which receives 'struct malidp_hw_device' as argument. Furthermore, there is no way to retrieve 'struct drm_device' from 'struct malidp_hw_device'. Signed-off-by: Ayan Kumar Halder <ayan.halder@arm.com> Acked-by: Liviu Dudau <liviu.dudau@arm.com> Signed-off-by: Liviu Dudau <liviu.dudau@arm.com> --- drivers/gpu/drm/arm/malidp_drv.c | 13 ++++++++----- drivers/gpu/drm/arm/malidp_hw.c | 10 ++-------- drivers/gpu/drm/arm/malidp_hw.h | 4 ++-- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c index 9b710f6999ed3..16fa089fa8be5 100644 --- a/drivers/gpu/drm/arm/malidp_drv.c +++ b/drivers/gpu/drm/arm/malidp_drv.c @@ -304,6 +304,8 @@ static int malidp_irq_init(struct platform_device *pdev) { int irq_de, irq_se, ret = 0; struct drm_device *drm = dev_get_drvdata(&pdev->dev); + struct malidp_drm *malidp = drm->dev_private; + struct malidp_hw_device *hwdev = malidp->dev; /* fetch the interrupts from DT */ irq_de = platform_get_irq_byname(pdev, "DE"); @@ -323,7 +325,7 @@ static int malidp_irq_init(struct platform_device *pdev) ret = malidp_se_irq_init(drm, irq_se); if (ret) { - malidp_de_irq_fini(drm); + malidp_de_irq_fini(hwdev); return ret; } @@ -763,8 +765,8 @@ static int malidp_bind(struct device *dev) fbdev_fail: pm_runtime_get_sync(dev); vblank_fail: - malidp_se_irq_fini(drm); - malidp_de_irq_fini(drm); + malidp_se_irq_fini(hwdev); + malidp_de_irq_fini(hwdev); drm->irq_enabled = false; irq_init_fail: drm_atomic_helper_shutdown(drm); @@ -794,14 +796,15 @@ static void malidp_unbind(struct device *dev) { struct drm_device *drm = dev_get_drvdata(dev); struct malidp_drm *malidp = drm->dev_private; + struct malidp_hw_device *hwdev = malidp->dev; drm_dev_unregister(drm); drm_fb_cma_fbdev_fini(drm); drm_kms_helper_poll_fini(drm); pm_runtime_get_sync(dev); drm_crtc_vblank_off(&malidp->crtc); - malidp_se_irq_fini(drm); - malidp_de_irq_fini(drm); + malidp_se_irq_fini(hwdev); + malidp_de_irq_fini(hwdev); drm->irq_enabled = false; drm_atomic_helper_shutdown(drm); component_unbind_all(dev, drm); diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c index 3dfad2f97c2a7..e30a25ceea2c9 100644 --- a/drivers/gpu/drm/arm/malidp_hw.c +++ b/drivers/gpu/drm/arm/malidp_hw.c @@ -998,11 +998,8 @@ int malidp_de_irq_init(struct drm_device *drm, int irq) return 0; } -void malidp_de_irq_fini(struct drm_device *drm) +void malidp_de_irq_fini(struct malidp_hw_device *hwdev) { - struct malidp_drm *malidp = drm->dev_private; - struct malidp_hw_device *hwdev = malidp->dev; - malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, hwdev->hw->map.de_irq_map.irq_mask); malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK, @@ -1102,11 +1099,8 @@ int malidp_se_irq_init(struct drm_device *drm, int irq) return 0; } -void malidp_se_irq_fini(struct drm_device *drm) +void malidp_se_irq_fini(struct malidp_hw_device *hwdev) { - struct malidp_drm *malidp = drm->dev_private; - struct malidp_hw_device *hwdev = malidp->dev; - malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK, hwdev->hw->map.se_irq_map.irq_mask); } diff --git a/drivers/gpu/drm/arm/malidp_hw.h b/drivers/gpu/drm/arm/malidp_hw.h index 5b99445433a28..8304d7763b8db 100644 --- a/drivers/gpu/drm/arm/malidp_hw.h +++ b/drivers/gpu/drm/arm/malidp_hw.h @@ -302,9 +302,9 @@ static inline void malidp_hw_enable_irq(struct malidp_hw_device *hwdev, } int malidp_de_irq_init(struct drm_device *drm, int irq); -void malidp_de_irq_fini(struct drm_device *drm); +void malidp_de_irq_fini(struct malidp_hw_device *hwdev); int malidp_se_irq_init(struct drm_device *drm, int irq); -void malidp_se_irq_fini(struct drm_device *drm); +void malidp_se_irq_fini(struct malidp_hw_device *hwdev); u8 malidp_hw_get_format_id(const struct malidp_hw_regmap *map, u8 layer_id, u32 format); -- GitLab From ff8fc26a764acdf5e0a2f86430bcb96c7b4eebec Mon Sep 17 00:00:00 2001 From: Ayan Kumar Halder <ayan.halder@arm.com> Date: Tue, 15 May 2018 17:04:16 +0100 Subject: [PATCH 0685/1506] drm/arm/malidp: Split malidp interrupt initialization functions. Malidp uses two interrupts ie 1. se_irq - used for memory writeback. and 2. de_irq - used for display output. Extract the hardware initialization part from malidp interrupt registration ie (malidp_de_irq_init()/ malidp_se_irq_init()) into a separate function (ie malidp_de_irq_hw_init()/malidp_se_irq_hw_init()) which will be later invoked from runtime_pm_resume function when it needs to re-enable the interrupts. Signed-off-by: Ayan Kumar Halder <ayan.halder@arm.com> Acked-by: Liviu Dudau <liviu.dudau@arm.com> Signed-off-by: Liviu Dudau <liviu.dudau@arm.com> --- drivers/gpu/drm/arm/malidp_hw.c | 38 +++++++++++++++++++++++++-------- drivers/gpu/drm/arm/malidp_hw.h | 2 ++ 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c index e30a25ceea2c9..47fc112ee32e3 100644 --- a/drivers/gpu/drm/arm/malidp_hw.c +++ b/drivers/gpu/drm/arm/malidp_hw.c @@ -967,6 +967,23 @@ static irqreturn_t malidp_de_irq_thread_handler(int irq, void *arg) return IRQ_HANDLED; } +void malidp_de_irq_hw_init(struct malidp_hw_device *hwdev) +{ + /* ensure interrupts are disabled */ + malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff); + malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff); + malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff); + malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff); + + /* first enable the DC block IRQs */ + malidp_hw_enable_irq(hwdev, MALIDP_DC_BLOCK, + hwdev->hw->map.dc_irq_map.irq_mask); + + /* now enable the DE block IRQs */ + malidp_hw_enable_irq(hwdev, MALIDP_DE_BLOCK, + hwdev->hw->map.de_irq_map.irq_mask); +} + int malidp_de_irq_init(struct drm_device *drm, int irq) { struct malidp_drm *malidp = drm->dev_private; @@ -987,13 +1004,7 @@ int malidp_de_irq_init(struct drm_device *drm, int irq) return ret; } - /* first enable the DC block IRQs */ - malidp_hw_enable_irq(hwdev, MALIDP_DC_BLOCK, - hwdev->hw->map.dc_irq_map.irq_mask); - - /* now enable the DE block IRQs */ - malidp_hw_enable_irq(hwdev, MALIDP_DE_BLOCK, - hwdev->hw->map.de_irq_map.irq_mask); + malidp_de_irq_hw_init(hwdev); return 0; } @@ -1069,6 +1080,16 @@ static irqreturn_t malidp_se_irq(int irq, void *arg) return IRQ_HANDLED; } +void malidp_se_irq_hw_init(struct malidp_hw_device *hwdev) +{ + /* ensure interrupts are disabled */ + malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff); + malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff); + + malidp_hw_enable_irq(hwdev, MALIDP_SE_BLOCK, + hwdev->hw->map.se_irq_map.irq_mask); +} + static irqreturn_t malidp_se_irq_thread_handler(int irq, void *arg) { return IRQ_HANDLED; @@ -1093,8 +1114,7 @@ int malidp_se_irq_init(struct drm_device *drm, int irq) } hwdev->mw_state = MW_NOT_ENABLED; - malidp_hw_enable_irq(hwdev, MALIDP_SE_BLOCK, - hwdev->hw->map.se_irq_map.irq_mask); + malidp_se_irq_hw_init(hwdev); return 0; } diff --git a/drivers/gpu/drm/arm/malidp_hw.h b/drivers/gpu/drm/arm/malidp_hw.h index 8304d7763b8db..f5b3eab8398ba 100644 --- a/drivers/gpu/drm/arm/malidp_hw.h +++ b/drivers/gpu/drm/arm/malidp_hw.h @@ -302,6 +302,8 @@ static inline void malidp_hw_enable_irq(struct malidp_hw_device *hwdev, } int malidp_de_irq_init(struct drm_device *drm, int irq); +void malidp_se_irq_hw_init(struct malidp_hw_device *hwdev); +void malidp_de_irq_hw_init(struct malidp_hw_device *hwdev); void malidp_de_irq_fini(struct malidp_hw_device *hwdev); int malidp_se_irq_init(struct drm_device *drm, int irq); void malidp_se_irq_fini(struct malidp_hw_device *hwdev); -- GitLab From fbcc454e8a350b929cb04fbcfdfa72fab37acf38 Mon Sep 17 00:00:00 2001 From: Ayan Kumar Halder <ayan.halder@arm.com> Date: Tue, 15 May 2018 17:04:17 +0100 Subject: [PATCH 0686/1506] drm/arm/malidp: Enable/disable interrupts in runtime pm Display and scaling engine interrupts need to be disabled when the runtime pm invokes malidp_runtime_pm_suspend(). Conversely, they need to be enabled in malidp_runtime_pm_resume(). This patch depends on: https://lkml.org/lkml/2017/5/15/695 Reported-by: Alexandru-Cosmin Gheorghe <Alexandru-Cosmin.Gheorghe@arm.com> Signed-off-by: Alexandru-Cosmin Gheorghe <Alexandru-Cosmin.Gheorghe@arm.com> Signed-off-by: Ayan Kumar Halder <ayan.halder@arm.com> Acked-by: Liviu Dudau <liviu.dudau@arm.com> Signed-off-by: Liviu Dudau <liviu.dudau@arm.com> --- drivers/gpu/drm/arm/malidp_drv.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c index 16fa089fa8be5..125be226bf6c9 100644 --- a/drivers/gpu/drm/arm/malidp_drv.c +++ b/drivers/gpu/drm/arm/malidp_drv.c @@ -582,6 +582,8 @@ static int malidp_runtime_pm_suspend(struct device *dev) /* we can only suspend if the hardware is in config mode */ WARN_ON(!hwdev->hw->in_config_mode(hwdev)); + malidp_se_irq_fini(hwdev); + malidp_de_irq_fini(hwdev); hwdev->pm_suspended = true; clk_disable_unprepare(hwdev->mclk); clk_disable_unprepare(hwdev->aclk); @@ -600,6 +602,8 @@ static int malidp_runtime_pm_resume(struct device *dev) clk_prepare_enable(hwdev->aclk); clk_prepare_enable(hwdev->mclk); hwdev->pm_suspended = false; + malidp_de_irq_hw_init(hwdev); + malidp_se_irq_hw_init(hwdev); return 0; } -- GitLab From f877006d5db49f3615fcee4bd5eb1a56c053d419 Mon Sep 17 00:00:00 2001 From: Ayan Kumar Halder <ayan.halder@arm.com> Date: Tue, 15 May 2018 17:04:18 +0100 Subject: [PATCH 0687/1506] drm/arm/malidp: Set the output_depth register in modeset One needs to store the value of the OUTPUT_DEPTH that one has parsed from device tree, so that it can be restored on system resume. This value is set in the modeset function as this gets reset when the system suspends. Signed-off-by: Ayan Kumar Halder <ayan.halder@arm.com> Acked-by: Liviu Dudau <liviu.dudau@arm.com> Signed-off-by: Liviu Dudau <liviu.dudau@arm.com> --- drivers/gpu/drm/arm/malidp_drv.c | 1 + drivers/gpu/drm/arm/malidp_hw.c | 4 ++++ drivers/gpu/drm/arm/malidp_hw.h | 1 + 3 files changed, 6 insertions(+) diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c index 125be226bf6c9..7237b98be5ebc 100644 --- a/drivers/gpu/drm/arm/malidp_drv.c +++ b/drivers/gpu/drm/arm/malidp_drv.c @@ -715,6 +715,7 @@ static int malidp_bind(struct device *dev) for (i = 0; i < MAX_OUTPUT_CHANNELS; i++) out_depth = (out_depth << 8) | (output_width[i] & 0xf); malidp_hw_write(hwdev, out_depth, hwdev->hw->map.out_depth_base); + hwdev->output_color_depth = out_depth; atomic_set(&malidp->config_valid, MALIDP_CONFIG_VALID_INIT); init_waitqueue_head(&malidp->wq); diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c index 47fc112ee32e3..c94a4422e0e91 100644 --- a/drivers/gpu/drm/arm/malidp_hw.c +++ b/drivers/gpu/drm/arm/malidp_hw.c @@ -244,6 +244,8 @@ static void malidp500_modeset(struct malidp_hw_device *hwdev, struct videomode * { u32 val = 0; + malidp_hw_write(hwdev, hwdev->output_color_depth, + hwdev->hw->map.out_depth_base); malidp_hw_clearbits(hwdev, MALIDP500_DC_CLEAR_MASK, MALIDP500_DC_CONTROL); if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH) val |= MALIDP500_HSYNCPOL; @@ -520,6 +522,8 @@ static void malidp550_modeset(struct malidp_hw_device *hwdev, struct videomode * { u32 val = MALIDP_DE_DEFAULT_PREFETCH_START; + malidp_hw_write(hwdev, hwdev->output_color_depth, + hwdev->hw->map.out_depth_base); malidp_hw_write(hwdev, val, MALIDP550_DE_CONTROL); /* * Mali-DP550 and Mali-DP650 encode the background color like this: diff --git a/drivers/gpu/drm/arm/malidp_hw.h b/drivers/gpu/drm/arm/malidp_hw.h index f5b3eab8398ba..ad2e96915d44a 100644 --- a/drivers/gpu/drm/arm/malidp_hw.h +++ b/drivers/gpu/drm/arm/malidp_hw.h @@ -230,6 +230,7 @@ struct malidp_hw_device { u8 min_line_size; u16 max_line_size; + u32 output_color_depth; /* track the device PM state */ bool pm_suspended; -- GitLab From e368fc75c190a4ad5853e4ec5a0c8acf86bd5119 Mon Sep 17 00:00:00 2001 From: Ayan Kumar Halder <ayan.halder@arm.com> Date: Tue, 15 May 2018 17:04:19 +0100 Subject: [PATCH 0688/1506] drm/arm/malidp: Added the late system pm functions malidp_pm_suspend_late checks if the runtime status is not suspended and if so, invokes malidp_runtime_pm_suspend which disables the display engine/core interrupts and the clocks. It sets the runtime status as suspended. The difference between suspend() and suspend_late() is as follows:- 1. suspend() makes the device quiescent. In our case, we invoke the DRM helper which disables the CRTC. This would have invoked runtime pm suspend but the system suspend process disables runtime pm. 2. suspend_late() It continues the suspend operations of the drm device which was started by suspend(). In our case, it performs the same functionality as runtime_suspend(). The complimentary functions are resume() and resume_early(). In the case of resume_early(), we invoke malidp_runtime_pm_resume() which enables the clocks and the interrupts. It sets the runtime status as active. If the device was in runtime suspend mode before system suspend was called, pm_runtime_work() will put the device back in runtime suspended mode( after the complete system has been resumed). Signed-off-by: Ayan Kumar Halder <ayan.halder@arm.com> Acked-by: Liviu Dudau <liviu.dudau@arm.com> Signed-off-by: Liviu Dudau <liviu.dudau@arm.com> --- drivers/gpu/drm/arm/malidp_drv.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c index 7237b98be5ebc..5b72605573913 100644 --- a/drivers/gpu/drm/arm/malidp_drv.c +++ b/drivers/gpu/drm/arm/malidp_drv.c @@ -882,8 +882,25 @@ static int __maybe_unused malidp_pm_resume(struct device *dev) return 0; } +static int __maybe_unused malidp_pm_suspend_late(struct device *dev) +{ + if (!pm_runtime_status_suspended(dev)) { + malidp_runtime_pm_suspend(dev); + pm_runtime_set_suspended(dev); + } + return 0; +} + +static int __maybe_unused malidp_pm_resume_early(struct device *dev) +{ + malidp_runtime_pm_resume(dev); + pm_runtime_set_active(dev); + return 0; +} + static const struct dev_pm_ops malidp_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(malidp_pm_suspend, malidp_pm_resume) \ + SET_LATE_SYSTEM_SLEEP_PM_OPS(malidp_pm_suspend_late, malidp_pm_resume_early) \ SET_RUNTIME_PM_OPS(malidp_runtime_pm_suspend, malidp_runtime_pm_resume, NULL) }; -- GitLab From bb9e8755a4259a306cd1691b4e17c4c485d81c9e Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 5 Jul 2018 16:47:56 +0100 Subject: [PATCH 0689/1506] drm/i915/selftests: Fixup recursive MI_BB_START for gen3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's no magic bit0 in MI_BB_START for gen3, it's the same dword length parameter as elsewhere and needs to be zero. v2: Same bug in both live_requests and live_hanghcheck. References: https://bugs.freedesktop.org/show_bug.cgi?id=107132 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20180705154756.5533-1-chris@chris-wilson.co.uk Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> --- drivers/gpu/drm/i915/selftests/i915_request.c | 5 +---- drivers/gpu/drm/i915/selftests/intel_hangcheck.c | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/selftests/i915_request.c b/drivers/gpu/drm/i915/selftests/i915_request.c index 521ae4a90ddfb..e44aa3335d9ed 100644 --- a/drivers/gpu/drm/i915/selftests/i915_request.c +++ b/drivers/gpu/drm/i915/selftests/i915_request.c @@ -594,11 +594,8 @@ static struct i915_vma *recursive_batch(struct drm_i915_private *i915) } else if (gen >= 6) { *cmd++ = MI_BATCH_BUFFER_START | 1 << 8; *cmd++ = lower_32_bits(vma->node.start); - } else if (gen >= 4) { - *cmd++ = MI_BATCH_BUFFER_START | MI_BATCH_GTT; - *cmd++ = lower_32_bits(vma->node.start); } else { - *cmd++ = MI_BATCH_BUFFER_START | MI_BATCH_GTT | 1; + *cmd++ = MI_BATCH_BUFFER_START | MI_BATCH_GTT; *cmd++ = lower_32_bits(vma->node.start); } *cmd++ = MI_BATCH_BUFFER_END; /* terminate early in case of error */ diff --git a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c index fe7d3190ebfee..72547aa24538c 100644 --- a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c +++ b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c @@ -193,7 +193,7 @@ static int emit_recurse_batch(struct hang *h, batch += 1024 / sizeof(*batch); *batch++ = MI_ARB_CHECK; - *batch++ = MI_BATCH_BUFFER_START | 2 << 6 | 1; + *batch++ = MI_BATCH_BUFFER_START | 2 << 6; *batch++ = lower_32_bits(vma->node.start); } *batch++ = MI_BATCH_BUFFER_END; /* not reached */ -- GitLab From 408633d2e740221204100efb9c3eed71f39aacd0 Mon Sep 17 00:00:00 2001 From: Souptick Joarder <jrdr.linux@gmail.com> Date: Wed, 4 Jul 2018 20:25:57 +0530 Subject: [PATCH 0690/1506] drm/v3d: use new return type vm_fault_t in v3d_gem_fault Instead of converting an errno into a vm_fault_t ourselves, use vmf_insert_mixed() which returns a vm_fault_t directly. Signed-off-by: Souptick Joarder <jrdr.linux@gmail.com> Signed-off-by: Eric Anholt <eric@anholt.net> Link: https://patchwork.freedesktop.org/patch/msgid/20180704145556.GA11036@jordon-HP-15-Notebook-PC Reviewed-by: Matthew Wilcox <willy@infradead.org> --- drivers/gpu/drm/v3d/v3d_bo.c | 28 +++++----------------------- drivers/gpu/drm/v3d/v3d_drv.h | 3 ++- 2 files changed, 7 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/v3d/v3d_bo.c b/drivers/gpu/drm/v3d/v3d_bo.c index 7b1e2a549a71f..54d96518a1316 100644 --- a/drivers/gpu/drm/v3d/v3d_bo.c +++ b/drivers/gpu/drm/v3d/v3d_bo.c @@ -227,37 +227,19 @@ v3d_set_mmap_vma_flags(struct vm_area_struct *vma) vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); } -int v3d_gem_fault(struct vm_fault *vmf) +vm_fault_t v3d_gem_fault(struct vm_fault *vmf) { struct vm_area_struct *vma = vmf->vma; struct drm_gem_object *obj = vma->vm_private_data; struct v3d_bo *bo = to_v3d_bo(obj); - unsigned long pfn; + pfn_t pfn; pgoff_t pgoff; - int ret; /* We don't use vmf->pgoff since that has the fake offset: */ pgoff = (vmf->address - vma->vm_start) >> PAGE_SHIFT; - pfn = page_to_pfn(bo->pages[pgoff]); - - ret = vm_insert_mixed(vma, vmf->address, __pfn_to_pfn_t(pfn, PFN_DEV)); - - switch (ret) { - case -EAGAIN: - case 0: - case -ERESTARTSYS: - case -EINTR: - case -EBUSY: - /* - * EBUSY is ok: this just means that another thread - * already did the job. - */ - return VM_FAULT_NOPAGE; - case -ENOMEM: - return VM_FAULT_OOM; - default: - return VM_FAULT_SIGBUS; - } + pfn = __pfn_to_pfn_t(page_to_pfn(bo->pages[pgoff]), PFN_DEV); + + return vmf_insert_mixed(vma, vmf->address, pfn); } int v3d_mmap(struct file *filp, struct vm_area_struct *vma) diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h index f32ac8c98f371..282763c9c7f6b 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.h +++ b/drivers/gpu/drm/v3d/v3d_drv.h @@ -2,6 +2,7 @@ /* Copyright (C) 2015-2018 Broadcom */ #include <linux/reservation.h> +#include <linux/mm_types.h> #include <drm/drmP.h> #include <drm/drm_encoder.h> #include <drm/drm_gem.h> @@ -252,7 +253,7 @@ int v3d_mmap_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int v3d_get_bo_offset_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -int v3d_gem_fault(struct vm_fault *vmf); +vm_fault_t v3d_gem_fault(struct vm_fault *vmf); int v3d_mmap(struct file *filp, struct vm_area_struct *vma); struct reservation_object *v3d_prime_res_obj(struct drm_gem_object *obj); int v3d_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma); -- GitLab From 624bb0c08b8298cbc6a16f9c68edc93f767716ec Mon Sep 17 00:00:00 2001 From: Eric Anholt <eric@anholt.net> Date: Tue, 3 Jul 2018 10:05:12 -0700 Subject: [PATCH 0691/1506] drm/v3d: Delay the scheduler timeout if we're still making progress. GTF-GLES2.gtf.GL.acos.acos_float_vert_xvary submits jobs that take 4 seconds at maximum resolution, but we still want to reset quickly if a job is really hung. Sample the CL's current address and the return address (since we call into tile lists repeatedly) and if either has changed then assume we've made progress. Signed-off-by: Eric Anholt <eric@anholt.net> Cc: Lucas Stach <l.stach@pengutronix.de> Link: https://patchwork.freedesktop.org/patch/msgid/20180703170515.6298-1-eric@anholt.net Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Acked-by: Daniel Vetter <daniel@ffwll.ch> --- drivers/gpu/drm/v3d/v3d_drv.h | 2 ++ drivers/gpu/drm/v3d/v3d_regs.h | 1 + drivers/gpu/drm/v3d/v3d_sched.c | 18 ++++++++++++++++++ 3 files changed, 21 insertions(+) diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h index 282763c9c7f6b..e6fed696ad869 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.h +++ b/drivers/gpu/drm/v3d/v3d_drv.h @@ -184,6 +184,8 @@ struct v3d_job { /* GPU virtual addresses of the start/end of the CL job. */ u32 start, end; + + u32 timedout_ctca, timedout_ctra; }; struct v3d_exec_info { diff --git a/drivers/gpu/drm/v3d/v3d_regs.h b/drivers/gpu/drm/v3d/v3d_regs.h index fc13282dfc2f0..854046565989e 100644 --- a/drivers/gpu/drm/v3d/v3d_regs.h +++ b/drivers/gpu/drm/v3d/v3d_regs.h @@ -222,6 +222,7 @@ #define V3D_CLE_CTNCA(n) (V3D_CLE_CT0CA + 4 * n) #define V3D_CLE_CT0RA 0x00118 #define V3D_CLE_CT1RA 0x0011c +#define V3D_CLE_CTNRA(n) (V3D_CLE_CT0RA + 4 * n) #define V3D_CLE_CT0LC 0x00120 #define V3D_CLE_CT1LC 0x00124 #define V3D_CLE_CT0PC 0x00128 diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c index 808bc901f567f..00667c733dca0 100644 --- a/drivers/gpu/drm/v3d/v3d_sched.c +++ b/drivers/gpu/drm/v3d/v3d_sched.c @@ -153,7 +153,25 @@ v3d_job_timedout(struct drm_sched_job *sched_job) struct v3d_job *job = to_v3d_job(sched_job); struct v3d_exec_info *exec = job->exec; struct v3d_dev *v3d = exec->v3d; + enum v3d_queue job_q = job == &exec->bin ? V3D_BIN : V3D_RENDER; enum v3d_queue q; + u32 ctca = V3D_CORE_READ(0, V3D_CLE_CTNCA(job_q)); + u32 ctra = V3D_CORE_READ(0, V3D_CLE_CTNRA(job_q)); + + /* If the current address or return address have changed, then + * the GPU has probably made progress and we should delay the + * reset. This could fail if the GPU got in an infinite loop + * in the CL, but that is pretty unlikely outside of an i-g-t + * testcase. + */ + if (job->timedout_ctca != ctca || job->timedout_ctra != ctra) { + job->timedout_ctca = ctca; + job->timedout_ctra = ctra; + + schedule_delayed_work(&job->base.work_tdr, + job->base.sched->timeout); + return; + } mutex_lock(&v3d->reset_lock); -- GitLab From e0d018119ae82cbde32c1d4f8e9b8d8f43a3c88a Mon Sep 17 00:00:00 2001 From: Eric Anholt <eric@anholt.net> Date: Tue, 3 Jul 2018 10:05:13 -0700 Subject: [PATCH 0692/1506] drm/v3d: Remove unnecessary dma_fence_ops. The dma-fence core as of commit 418cc6ca0607 ("dma-fence: Make ->wait callback optional") provides appropriate defaults for these methods. Signed-off-by: Eric Anholt <eric@anholt.net> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180703170515.6298-2-eric@anholt.net Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Acked-by: Daniel Vetter <daniel@ffwll.ch> --- drivers/gpu/drm/v3d/v3d_fence.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/drivers/gpu/drm/v3d/v3d_fence.c b/drivers/gpu/drm/v3d/v3d_fence.c index bfe31a89668bd..50bfcf9a8a1ac 100644 --- a/drivers/gpu/drm/v3d/v3d_fence.c +++ b/drivers/gpu/drm/v3d/v3d_fence.c @@ -35,19 +35,7 @@ static const char *v3d_fence_get_timeline_name(struct dma_fence *fence) return "v3d-render"; } -static bool v3d_fence_enable_signaling(struct dma_fence *fence) -{ - return true; -} - const struct dma_fence_ops v3d_fence_ops = { .get_driver_name = v3d_fence_get_driver_name, .get_timeline_name = v3d_fence_get_timeline_name, - .enable_signaling = v3d_fence_enable_signaling, - /* Each of our fences gets signaled as complete by the IRQ - * handler, so we rely on the core's tracking of signaling. - */ - .signaled = NULL, - .wait = dma_fence_default_wait, - .release = dma_fence_free, }; -- GitLab From 2dd4f211e70728af386684d912b964b62d5fa15f Mon Sep 17 00:00:00 2001 From: Eric Anholt <eric@anholt.net> Date: Tue, 3 Jul 2018 10:05:14 -0700 Subject: [PATCH 0693/1506] drm/v3d: Add missing v3d documentation structure. This was a failure of "git add" on my part -- we already referenced the doc from drivers.rst. Signed-off-by: Eric Anholt <eric@anholt.net> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180703170515.6298-3-eric@anholt.net Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Acked-by: Daniel Vetter <daniel@ffwll.ch> --- Documentation/gpu/v3d.rst | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 Documentation/gpu/v3d.rst diff --git a/Documentation/gpu/v3d.rst b/Documentation/gpu/v3d.rst new file mode 100644 index 0000000000000..543f7fbf526e3 --- /dev/null +++ b/Documentation/gpu/v3d.rst @@ -0,0 +1,28 @@ +===================================== + drm/v3d Broadcom V3D Graphics Driver +===================================== + +.. kernel-doc:: drivers/gpu/drm/v3d/v3d_drv.c + :doc: Broadcom V3D Graphics Driver + +GPU buffer object (BO) management +--------------------------------- + +.. kernel-doc:: drivers/gpu/drm/v3d/v3d_bo.c + :doc: V3D GEM BO management support + +Address space management +=========================================== +.. kernel-doc:: drivers/gpu/drm/v3d/v3d_mmu.c + :doc: Broadcom V3D MMU + +GPU Scheduling +=========================================== +.. kernel-doc:: drivers/gpu/drm/v3d/v3d_sched.c + :doc: Broadcom V3D scheduling + +Interrupts +-------------- + +.. kernel-doc:: drivers/gpu/drm/v3d/v3d_irq.c + :doc: Interrupt management for the V3D engine -- GitLab From a65020d0a65da69f504b5ee4d43d255d0875999e Mon Sep 17 00:00:00 2001 From: Eric Anholt <eric@anholt.net> Date: Tue, 3 Jul 2018 10:05:15 -0700 Subject: [PATCH 0694/1506] drm/v3d: Fix a grammar nit in the scheduler docs. Signed-off-by: Eric Anholt <eric@anholt.net> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180703170515.6298-4-eric@anholt.net Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Acked-by: Daniel Vetter <daniel@ffwll.ch> --- drivers/gpu/drm/v3d/v3d_sched.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c index 00667c733dca0..a5501581d96b3 100644 --- a/drivers/gpu/drm/v3d/v3d_sched.c +++ b/drivers/gpu/drm/v3d/v3d_sched.c @@ -14,8 +14,8 @@ * to the HW only when it has completed the last one, instead of * filling up the CT[01]Q FIFOs with jobs. Similarly, we use * v3d_job_dependency() to manage the dependency between bin and - * render, instead of having the clients submit jobs with using the - * HW's semaphores to interlock between them. + * render, instead of having the clients submit jobs using the HW's + * semaphores to interlock between them. */ #include <linux/kthread.h> -- GitLab From 9757973f41b52cd8fa7850100b8b0ae85261bcc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Thu, 21 Jun 2018 20:46:58 +0300 Subject: [PATCH 0695/1506] drm/i915: Remove pointless if-else from sdvo code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The return value is a bool so we can just return the result of the biwise AND. The compiler will take care of the rest. Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180621174658.18823-1-ville.syrjala@linux.intel.com Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> --- drivers/gpu/drm/i915/intel_sdvo.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 36f81a96b8f64..5417c54f67da6 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1401,10 +1401,7 @@ static bool intel_sdvo_connector_get_hw_state(struct intel_connector *connector) intel_sdvo_get_active_outputs(intel_sdvo, &active_outputs); - if (active_outputs & intel_sdvo_connector->output_flag) - return true; - else - return false; + return active_outputs & intel_sdvo_connector->output_flag; } bool intel_sdvo_port_enabled(struct drm_i915_private *dev_priv, -- GitLab From ca52bea9fa8007f837ab4685b98979bbffc33416 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Fri, 15 Jun 2018 20:07:34 +0300 Subject: [PATCH 0696/1506] drm/atomic-helper: Use bitwise or for filling a bitmask MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using += to set the bits in a mask looks funny. It works in this case because we never set the same bit twice. But let's switch to |= to make this look more regular. Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180615170734.2774-1-ville.syrjala@linux.intel.com Reviewed-by: Eric Anholt <eric@anholt.net> --- drivers/gpu/drm/drm_atomic_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 8008a7de2e100..7787e0e6bbc6b 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -645,7 +645,7 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, if (ret) return ret; - connectors_mask += BIT(i); + connectors_mask |= BIT(i); } /* -- GitLab From 73d8e5fba54f400cd5fe48517dbe6776fb16c2ad Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 5 Jul 2018 18:15:23 +0100 Subject: [PATCH 0697/1506] drm/i915/selftests: Detect unknown swizzling correctly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit i915_gem_detect_bit_6_swizzle() tries to hide unknown swizzling from userspace (and ourselves) leaving us with the only clue inside i915->quirks & QUIRK_PIN_SWIZZLED_PAGES. If we see this bit set, it means that we really have no clue as to what the swizzle pattern is being used in any one page and so cannot compute what the reference value should be in our tiling selftests. We have to skip the test. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=107133 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180705171523.18462-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/selftests/i915_gem_object.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_object.c b/drivers/gpu/drm/i915/selftests/i915_gem_object.c index 77dd7a510ea60..8851532689680 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_object.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_object.c @@ -347,6 +347,14 @@ static int igt_partial_tiling(void *arg) unsigned int pitch; struct tile tile; + if (i915->quirks & QUIRK_PIN_SWIZZLED_PAGES) + /* + * The swizzling pattern is actually unknown as it + * varies based on physical address of each page. + * See i915_gem_detect_bit_6_swizzle(). + */ + break; + tile.tiling = tiling; switch (tiling) { case I915_TILING_X: @@ -357,8 +365,8 @@ static int igt_partial_tiling(void *arg) break; } - if (tile.swizzle == I915_BIT_6_SWIZZLE_UNKNOWN || - tile.swizzle == I915_BIT_6_SWIZZLE_9_10_17) + GEM_BUG_ON(tile.swizzle == I915_BIT_6_SWIZZLE_UNKNOWN); + if (tile.swizzle == I915_BIT_6_SWIZZLE_9_10_17) continue; if (INTEL_GEN(i915) <= 2) { -- GitLab From a315f232f44e685397639649fe559325424d32d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Tue, 19 Jun 2018 10:45:03 +0200 Subject: [PATCH 0698/1506] drm/amdgpu: band aid validating VM PTs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Always validating the VM PTs takes to much time. Only always validate the per VM BOs for now. Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Junwei Zhang <Jerry.Zhang@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 422d1a434db40..590db78b8c725 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -1082,7 +1082,7 @@ int amdgpu_vm_update_directories(struct amdgpu_device *adev, struct amdgpu_vm_bo_base, vm_status); bo_base->moved = false; - list_move(&bo_base->vm_status, &vm->idle); + list_del_init(&bo_base->vm_status); bo = bo_base->bo->parent; if (!bo) -- GitLab From b374d82dca4721c534eb940b599dd4d45ba3a18f Mon Sep 17 00:00:00 2001 From: Tom St Denis <tom.stdenis@amd.com> Date: Wed, 20 Jun 2018 07:55:39 -0400 Subject: [PATCH 0699/1506] drm/amd/amdgpu: Add a GPU_LOAD entry to sysfs (v3) This adds what should be a stable interface to read GPU load from userspace. (v2): Fix comments and name of file per recommendations. (v3): Add chapter to amdgpu.rst as well. Signed-off-by: Tom St Denis <tom.stdenis@amd.com> Acked-by: Slava Abramov <slava.abramov@amd.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- Documentation/gpu/amdgpu.rst | 5 ++++ drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | 40 ++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/Documentation/gpu/amdgpu.rst b/Documentation/gpu/amdgpu.rst index e52d0ce186fe4..765c2a32938f3 100644 --- a/Documentation/gpu/amdgpu.rst +++ b/Documentation/gpu/amdgpu.rst @@ -115,3 +115,8 @@ pp_power_profile_mode .. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c :doc: pp_power_profile_mode +busy_percent +~~~~~~~~~~~~ + +.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c + :doc: busy_percent diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c index 113edffb59601..fdb3998219154 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c @@ -918,6 +918,36 @@ static ssize_t amdgpu_set_pp_power_profile_mode(struct device *dev, return -EINVAL; } +/** + * DOC: busy_percent + * + * The amdgpu driver provides a sysfs API for reading how busy the GPU + * is as a percentage. The file gpu_busy_percent is used for this. + * The SMU firmware computes a percentage of load based on the + * aggregate activity level in the IP cores. + */ +static ssize_t amdgpu_get_busy_percent(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = ddev->dev_private; + int r, value, size = sizeof(value); + + /* sanity check PP is enabled */ + if (!(adev->powerplay.pp_funcs && + adev->powerplay.pp_funcs->read_sensor)) + return -EINVAL; + + /* read the IP busy sensor */ + r = amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_LOAD, + (void *)&value, &size); + if (r) + return r; + + return snprintf(buf, PAGE_SIZE, "%d\n", value); +} + static DEVICE_ATTR(power_dpm_state, S_IRUGO | S_IWUSR, amdgpu_get_dpm_state, amdgpu_set_dpm_state); static DEVICE_ATTR(power_dpm_force_performance_level, S_IRUGO | S_IWUSR, amdgpu_get_dpm_forced_performance_level, @@ -951,6 +981,8 @@ static DEVICE_ATTR(pp_power_profile_mode, S_IRUGO | S_IWUSR, static DEVICE_ATTR(pp_od_clk_voltage, S_IRUGO | S_IWUSR, amdgpu_get_pp_od_clk_voltage, amdgpu_set_pp_od_clk_voltage); +static DEVICE_ATTR(gpu_busy_percent, S_IRUGO, + amdgpu_get_busy_percent, NULL); static ssize_t amdgpu_hwmon_show_temp(struct device *dev, struct device_attribute *attr, @@ -1854,6 +1886,13 @@ int amdgpu_pm_sysfs_init(struct amdgpu_device *adev) "pp_od_clk_voltage\n"); return ret; } + ret = device_create_file(adev->dev, + &dev_attr_gpu_busy_percent); + if (ret) { + DRM_ERROR("failed to create device file " + "gpu_busy_level\n"); + return ret; + } ret = amdgpu_debugfs_pm_init(adev); if (ret) { DRM_ERROR("Failed to register debugfs file for dpm!\n"); @@ -1889,6 +1928,7 @@ void amdgpu_pm_sysfs_fini(struct amdgpu_device *adev) &dev_attr_pp_power_profile_mode); device_remove_file(adev->dev, &dev_attr_pp_od_clk_voltage); + device_remove_file(adev->dev, &dev_attr_gpu_busy_percent); } void amdgpu_pm_compute_clocks(struct amdgpu_device *adev) -- GitLab From d9e222b460b195a47b30fd9057fbb131fcbd7bac Mon Sep 17 00:00:00 2001 From: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Date: Mon, 18 Jun 2018 11:15:10 -0400 Subject: [PATCH 0700/1506] drm/amdgpu: Polish SQ IH. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switch to using reg fields defines istead of magic values. Add SH_ID and PRIV fields reading for instr. and err cases. Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Acked-by: Christian König <christian.koenig@amd.com> Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 36 +++++++++++++++------------ 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index 807ee0dd623ce..1d99a4205958a 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -6961,10 +6961,11 @@ static int gfx_v8_0_sq_irq(struct amdgpu_device *adev, { u8 enc, se_id; char type[20]; + unsigned ih_data = entry->src_data[0]; - /* Parse all fields according to SQ_INTERRUPT* registers */ - enc = (entry->src_data[0] >> 26) & 0x3; - se_id = (entry->src_data[0] >> 24) & 0x3; + + enc = REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_CMN, ENCODING); + se_id = REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_CMN, SE_ID); switch (enc) { case 0: @@ -6974,14 +6975,14 @@ static int gfx_v8_0_sq_irq(struct amdgpu_device *adev, "reg_timestamp %d, thread_trace_buff_full %d," "wlt %d, thread_trace %d.\n", se_id, - (entry->src_data[0] >> 7) & 0x1, - (entry->src_data[0] >> 6) & 0x1, - (entry->src_data[0] >> 5) & 0x1, - (entry->src_data[0] >> 4) & 0x1, - (entry->src_data[0] >> 3) & 0x1, - (entry->src_data[0] >> 2) & 0x1, - (entry->src_data[0] >> 1) & 0x1, - entry->src_data[0] & 0x1 + REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_AUTO, IMMED_OVERFLOW), + REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_AUTO, HOST_REG_OVERFLOW), + REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_AUTO, HOST_CMD_OVERFLOW), + REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_AUTO, CMD_TIMESTAMP), + REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_AUTO, REG_TIMESTAMP), + REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_AUTO, THREAD_TRACE_BUF_FULL), + REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_AUTO, WLT), + REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_AUTO, THREAD_TRACE) ); break; case 1: @@ -6994,12 +6995,15 @@ static int gfx_v8_0_sq_irq(struct amdgpu_device *adev, DRM_INFO( "SQ %s detected: " - "se_id %d, cu_id %d, simd_id %d, wave_id %d, vm_id %d\n", + "se_id %d, cu_id %d, simd_id %d, wave_id %d, vm_id %d\n" + "trap %s, sh_id %d. ", type, se_id, - (entry->src_data[0] >> 20) & 0xf, - (entry->src_data[0] >> 18) & 0x3, - (entry->src_data[0] >> 14) & 0xf, - (entry->src_data[0] >> 10) & 0xf + REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, CU_ID), + REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, SIMD_ID), + REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, WAVE_ID), + REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, VM_ID), + REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, PRIV) ? "true" : "false", + REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, SH_ID) ); break; default: -- GitLab From 9bdc2092b488bc81aa5409b4d6fc931c5bea1094 Mon Sep 17 00:00:00 2001 From: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Date: Tue, 19 Jun 2018 10:27:53 -0400 Subject: [PATCH 0701/1506] drm/amdgpu: Add parsing SQ_EDC_INFO to SQ IH v3. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Access to SQ_EDC_INFO requires selecting register instance and hence mutex lock when accessing GRBM_GFX_INDEX for which a work is schedueled from IH. But SQ interrupt can be raised on many instances at once which means queuing work will usually succeed for the first one but fail for the rest since the work takes time to process. To avoid losing info about other interrupt instances call the parsing function directly from high IRQ when current work hasn't finished and avoid accessing SQ_EDC_INFO in that case. v2: Simplify high IRQ and BH handlers synchronization using work_pending. Remove {READ,WRITE}_ONCE notations since smp_{r,w}mb are implicit compiler barriers. v3: Remove exlicit memory barriers as scedule_work has r/w barriers. Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Acked-by: Christian König <christian.koenig@amd.com> Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 7 +++ drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 82 ++++++++++++++++++++++----- 2 files changed, 76 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 71b9b861f60e5..fb17838114c33 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -930,6 +930,11 @@ struct amdgpu_ngg { bool init; }; +struct sq_work { + struct work_struct work; + unsigned ih_data; +}; + struct amdgpu_gfx { struct mutex gpu_clock_mutex; struct amdgpu_gfx_config config; @@ -970,6 +975,8 @@ struct amdgpu_gfx { struct amdgpu_irq_src priv_inst_irq; struct amdgpu_irq_src cp_ecc_error_irq; struct amdgpu_irq_src sq_irq; + struct sq_work sq_work; + /* gfx status */ uint32_t gfx_current_status; /* ce ram size*/ diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index 1d99a4205958a..4201f3dfaecec 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -704,6 +704,17 @@ static const u32 stoney_mgcg_cgcg_init[] = mmCGTS_SM_CTRL_REG, 0xffffffff, 0x96940200, }; + +static const char * const sq_edc_source_names[] = { + "SQ_EDC_INFO_SOURCE_INVALID: No EDC error has occurred", + "SQ_EDC_INFO_SOURCE_INST: EDC source is Instruction Fetch", + "SQ_EDC_INFO_SOURCE_SGPR: EDC source is SGPR or SQC data return", + "SQ_EDC_INFO_SOURCE_VGPR: EDC source is VGPR", + "SQ_EDC_INFO_SOURCE_LDS: EDC source is LDS", + "SQ_EDC_INFO_SOURCE_GDS: EDC source is GDS", + "SQ_EDC_INFO_SOURCE_TA: EDC source is TA", +}; + static void gfx_v8_0_set_ring_funcs(struct amdgpu_device *adev); static void gfx_v8_0_set_irq_funcs(struct amdgpu_device *adev); static void gfx_v8_0_set_gds_init(struct amdgpu_device *adev); @@ -2006,6 +2017,8 @@ static int gfx_v8_0_compute_ring_init(struct amdgpu_device *adev, int ring_id, return 0; } +static void gfx_v8_0_sq_irq_work_func(struct work_struct *work); + static int gfx_v8_0_sw_init(void *handle) { int i, j, k, r, ring_id; @@ -2069,6 +2082,8 @@ static int gfx_v8_0_sw_init(void *handle) return r; } + INIT_WORK(&adev->gfx.sq_work.work, gfx_v8_0_sq_irq_work_func); + adev->gfx.gfx_current_status = AMDGPU_GFX_NORMAL_MODE; gfx_v8_0_scratch_init(adev); @@ -6955,14 +6970,11 @@ static int gfx_v8_0_cp_ecc_error_irq(struct amdgpu_device *adev, return 0; } -static int gfx_v8_0_sq_irq(struct amdgpu_device *adev, - struct amdgpu_irq_src *source, - struct amdgpu_iv_entry *entry) +static void gfx_v8_0_parse_sq_irq(struct amdgpu_device *adev, unsigned ih_data) { - u8 enc, se_id; + u32 enc, se_id, sh_id, cu_id; char type[20]; - unsigned ih_data = entry->src_data[0]; - + int sq_edc_source = -1; enc = REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_CMN, ENCODING); se_id = REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_CMN, SE_ID); @@ -6988,6 +7000,24 @@ static int gfx_v8_0_sq_irq(struct amdgpu_device *adev, case 1: case 2: + cu_id = REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, CU_ID); + sh_id = REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, SH_ID); + + /* + * This function can be called either directly from ISR + * or from BH in which case we can access SQ_EDC_INFO + * instance + */ + if (in_task()) { + mutex_lock(&adev->grbm_idx_mutex); + gfx_v8_0_select_se_sh(adev, se_id, sh_id, cu_id); + + sq_edc_source = REG_GET_FIELD(RREG32(mmSQ_EDC_INFO), SQ_EDC_INFO, SOURCE); + + gfx_v8_0_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff); + mutex_unlock(&adev->grbm_idx_mutex); + } + if (enc == 1) sprintf(type, "instruction intr"); else @@ -6995,20 +7025,46 @@ static int gfx_v8_0_sq_irq(struct amdgpu_device *adev, DRM_INFO( "SQ %s detected: " - "se_id %d, cu_id %d, simd_id %d, wave_id %d, vm_id %d\n" - "trap %s, sh_id %d. ", - type, se_id, - REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, CU_ID), + "se_id %d, sh_id %d, cu_id %d, simd_id %d, wave_id %d, vm_id %d " + "trap %s, sq_ed_info.source %s.\n", + type, se_id, sh_id, cu_id, REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, SIMD_ID), REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, WAVE_ID), REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, VM_ID), REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, PRIV) ? "true" : "false", - REG_GET_FIELD(ih_data, SQ_INTERRUPT_WORD_WAVE, SH_ID) - ); + (sq_edc_source != -1) ? sq_edc_source_names[sq_edc_source] : "unavailable" + ); break; default: DRM_ERROR("SQ invalid encoding type\n."); - return -EINVAL; + } +} + +static void gfx_v8_0_sq_irq_work_func(struct work_struct *work) +{ + + struct amdgpu_device *adev = container_of(work, struct amdgpu_device, gfx.sq_work.work); + struct sq_work *sq_work = container_of(work, struct sq_work, work); + + gfx_v8_0_parse_sq_irq(adev, sq_work->ih_data); +} + +static int gfx_v8_0_sq_irq(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + struct amdgpu_iv_entry *entry) +{ + unsigned ih_data = entry->src_data[0]; + + /* + * Try to submit work so SQ_EDC_INFO can be accessed from + * BH. If previous work submission hasn't finished yet + * just print whatever info is possible directly from the ISR. + */ + if (work_pending(&adev->gfx.sq_work.work)) { + gfx_v8_0_parse_sq_irq(adev, ih_data); + } else { + adev->gfx.sq_work.ih_data = ih_data; + schedule_work(&adev->gfx.sq_work.work); } return 0; -- GitLab From a25ca1625dd4ecc89c20bb9082b325490f3f78f2 Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexander.deucher@amd.com> Date: Fri, 22 Jun 2018 15:00:26 -0500 Subject: [PATCH 0702/1506] Revert "drm/amdgpu: avoid sleep while executing atombios table (V2)" This reverts commit 8f4805a265fd710a2827b2c0e10c08ef2b526870. This change was mistakenly committed and should have been dropped with the rest of the series. Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/atom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/atom.c b/drivers/gpu/drm/amd/amdgpu/atom.c index b18c31a701e22..e9934de1b9cf8 100644 --- a/drivers/gpu/drm/amd/amdgpu/atom.c +++ b/drivers/gpu/drm/amd/amdgpu/atom.c @@ -1221,7 +1221,7 @@ static int amdgpu_atom_execute_table_locked(struct atom_context *ctx, int index, ectx.abort = false; ectx.last_jump = 0; if (ws) - ectx.ws = kcalloc(4, ws, GFP_ATOMIC); + ectx.ws = kcalloc(4, ws, GFP_KERNEL); else ectx.ws = NULL; -- GitLab From 765b26836430e9d9ebef95fced42dd167b4ccad6 Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Date: Wed, 23 May 2018 13:16:50 -0400 Subject: [PATCH 0703/1506] drm/amd/display: replace clocks_value struct with dc_clocks This will avoid structs with duplicate information. Also removes pixel clock voltage request. This has no effect since pixel clock does not affect dcn voltage and this function only matters for dcn. Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/display/dc/calcs/dcn_calcs.c | 34 +++++++------- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 8 ++-- drivers/gpu/drm/amd/display/dc/dc.h | 5 ++ .../gpu/drm/amd/display/dc/dce/dce_clocks.c | 46 +++++++------------ .../display/dc/dce110/dce110_hw_sequencer.c | 18 +------- .../gpu/drm/amd/display/dc/inc/dcn_calcs.h | 2 +- .../drm/amd/display/dc/inc/hw/display_clock.h | 22 ++------- 7 files changed, 49 insertions(+), 86 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c index 49a4ea45466d3..d8a31650e8562 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c @@ -1145,10 +1145,10 @@ static unsigned int dcn_find_normalized_clock_vdd_Level( switch (clocks_type) { case DM_PP_CLOCK_TYPE_DISPLAY_CLK: - if (clocks_in_khz > dc->dcn_soc->max_dispclk_vmax0p9*1000) { + /*if (clocks_in_khz > dc->dcn_soc->max_dispclk_vmax0p9*1000) { vdd_level = dcn_bw_v_max0p91; - BREAK_TO_DEBUGGER(); - } else if (clocks_in_khz > dc->dcn_soc->max_dispclk_vnom0p8*1000) { + //BREAK_TO_DEBUGGER(); + } else*/ if (clocks_in_khz > dc->dcn_soc->max_dispclk_vnom0p8*1000) { vdd_level = dcn_bw_v_max0p9; } else if (clocks_in_khz > dc->dcn_soc->max_dispclk_vmid0p72*1000) { vdd_level = dcn_bw_v_nom0p8; @@ -1158,10 +1158,10 @@ static unsigned int dcn_find_normalized_clock_vdd_Level( vdd_level = dcn_bw_v_min0p65; break; case DM_PP_CLOCK_TYPE_DISPLAYPHYCLK: - if (clocks_in_khz > dc->dcn_soc->phyclkv_max0p9*1000) { + /*if (clocks_in_khz > dc->dcn_soc->phyclkv_max0p9*1000) { vdd_level = dcn_bw_v_max0p91; BREAK_TO_DEBUGGER(); - } else if (clocks_in_khz > dc->dcn_soc->phyclkv_nom0p8*1000) { + } else*/ if (clocks_in_khz > dc->dcn_soc->phyclkv_nom0p8*1000) { vdd_level = dcn_bw_v_max0p9; } else if (clocks_in_khz > dc->dcn_soc->phyclkv_mid0p72*1000) { vdd_level = dcn_bw_v_nom0p8; @@ -1172,10 +1172,10 @@ static unsigned int dcn_find_normalized_clock_vdd_Level( break; case DM_PP_CLOCK_TYPE_DPPCLK: - if (clocks_in_khz > dc->dcn_soc->max_dppclk_vmax0p9*1000) { + /*if (clocks_in_khz > dc->dcn_soc->max_dppclk_vmax0p9*1000) { vdd_level = dcn_bw_v_max0p91; BREAK_TO_DEBUGGER(); - } else if (clocks_in_khz > dc->dcn_soc->max_dppclk_vnom0p8*1000) { + } else*/ if (clocks_in_khz > dc->dcn_soc->max_dppclk_vnom0p8*1000) { vdd_level = dcn_bw_v_max0p9; } else if (clocks_in_khz > dc->dcn_soc->max_dppclk_vmid0p72*1000) { vdd_level = dcn_bw_v_nom0p8; @@ -1189,10 +1189,10 @@ static unsigned int dcn_find_normalized_clock_vdd_Level( { unsigned factor = (ddr4_dram_factor_single_Channel * dc->dcn_soc->number_of_channels); - if (clocks_in_khz > dc->dcn_soc->fabric_and_dram_bandwidth_vmax0p9*1000000/factor) { + /*if (clocks_in_khz > dc->dcn_soc->fabric_and_dram_bandwidth_vmax0p9*1000000/factor) { vdd_level = dcn_bw_v_max0p91; BREAK_TO_DEBUGGER(); - } else if (clocks_in_khz > dc->dcn_soc->fabric_and_dram_bandwidth_vnom0p8*1000000/factor) { + } else */if (clocks_in_khz > dc->dcn_soc->fabric_and_dram_bandwidth_vnom0p8*1000000/factor) { vdd_level = dcn_bw_v_max0p9; } else if (clocks_in_khz > dc->dcn_soc->fabric_and_dram_bandwidth_vmid0p72*1000000/factor) { vdd_level = dcn_bw_v_nom0p8; @@ -1204,10 +1204,10 @@ static unsigned int dcn_find_normalized_clock_vdd_Level( break; case DM_PP_CLOCK_TYPE_DCFCLK: - if (clocks_in_khz > dc->dcn_soc->dcfclkv_max0p9*1000) { + /*if (clocks_in_khz > dc->dcn_soc->dcfclkv_max0p9*1000) { vdd_level = dcn_bw_v_max0p91; BREAK_TO_DEBUGGER(); - } else if (clocks_in_khz > dc->dcn_soc->dcfclkv_nom0p8*1000) { + } else */if (clocks_in_khz > dc->dcn_soc->dcfclkv_nom0p8*1000) { vdd_level = dcn_bw_v_max0p9; } else if (clocks_in_khz > dc->dcn_soc->dcfclkv_mid0p72*1000) { vdd_level = dcn_bw_v_nom0p8; @@ -1225,27 +1225,27 @@ static unsigned int dcn_find_normalized_clock_vdd_Level( unsigned int dcn_find_dcfclk_suits_all( const struct dc *dc, - struct clocks_value *clocks) + struct dc_clocks *clocks) { unsigned vdd_level, vdd_level_temp; unsigned dcf_clk; /*find a common supported voltage level*/ vdd_level = dcn_find_normalized_clock_vdd_Level( - dc, DM_PP_CLOCK_TYPE_DISPLAY_CLK, clocks->dispclk_in_khz); + dc, DM_PP_CLOCK_TYPE_DISPLAY_CLK, clocks->dispclk_khz); vdd_level_temp = dcn_find_normalized_clock_vdd_Level( - dc, DM_PP_CLOCK_TYPE_DISPLAYPHYCLK, clocks->phyclk_in_khz); + dc, DM_PP_CLOCK_TYPE_DISPLAYPHYCLK, clocks->phyclk_khz); vdd_level = dcn_bw_max(vdd_level, vdd_level_temp); vdd_level_temp = dcn_find_normalized_clock_vdd_Level( - dc, DM_PP_CLOCK_TYPE_DPPCLK, clocks->dppclk_in_khz); + dc, DM_PP_CLOCK_TYPE_DPPCLK, clocks->dppclk_khz); vdd_level = dcn_bw_max(vdd_level, vdd_level_temp); vdd_level_temp = dcn_find_normalized_clock_vdd_Level( - dc, DM_PP_CLOCK_TYPE_MEMORY_CLK, clocks->dcfclock_in_khz); + dc, DM_PP_CLOCK_TYPE_MEMORY_CLK, clocks->fclk_khz); vdd_level = dcn_bw_max(vdd_level, vdd_level_temp); vdd_level_temp = dcn_find_normalized_clock_vdd_Level( - dc, DM_PP_CLOCK_TYPE_DCFCLK, clocks->dcfclock_in_khz); + dc, DM_PP_CLOCK_TYPE_DCFCLK, clocks->dcfclk_khz); /*find that level conresponding dcfclk*/ vdd_level = dcn_bw_max(vdd_level, vdd_level_temp); 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 08b7ee526f0fe..6155a5c7bd368 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -1290,15 +1290,13 @@ static enum dc_status enable_link_dp( state->dis_clk, DM_PP_CLOCKS_STATE_NOMINAL); } else { uint32_t dp_phyclk_in_khz; - const struct clocks_value clocks_value = - state->dis_clk->cur_clocks_value; + const struct dc_clocks clocks_value = + state->dis_clk->clks; /* 27mhz = 27000000hz= 27000khz */ dp_phyclk_in_khz = link_settings.link_rate * 27000; - if (((clocks_value.max_non_dp_phyclk_in_khz != 0) && - (dp_phyclk_in_khz > clocks_value.max_non_dp_phyclk_in_khz)) || - (dp_phyclk_in_khz > clocks_value.max_dp_phyclk_in_khz)) { + if (dp_phyclk_in_khz > clocks_value.phyclk_khz) { state->dis_clk->funcs->apply_clock_voltage_request( state->dis_clk, DM_PP_CLOCK_TYPE_DISPLAYPHYCLK, diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 7ebce7669eea5..8ba90a75d1284 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -186,6 +186,10 @@ enum wm_report_mode { WM_REPORT_OVERRIDE = 1, }; +/* + * For any clocks that may differ per pipe + * only the max is stored in this structure + */ struct dc_clocks { int dispclk_khz; int max_supported_dppclk_khz; @@ -194,6 +198,7 @@ struct dc_clocks { int socclk_khz; int dcfclk_deep_sleep_khz; int fclk_khz; + int phyclk_khz; }; struct dc_debug { diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c index 8a581c67bf2d1..b749a20a0c3de 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c @@ -560,11 +560,9 @@ static bool dce_apply_clock_voltage_request( switch (clocks_type) { case DM_PP_CLOCK_TYPE_DISPLAY_CLK: - case DM_PP_CLOCK_TYPE_PIXELCLK: case DM_PP_CLOCK_TYPE_DISPLAYPHYCLK: break; default: - BREAK_TO_DEBUGGER(); return false; } @@ -575,31 +573,22 @@ static bool dce_apply_clock_voltage_request( if (pre_mode_set) { switch (clocks_type) { case DM_PP_CLOCK_TYPE_DISPLAY_CLK: - if (clocks_in_khz > clk->cur_clocks_value.dispclk_in_khz) { - clk->cur_clocks_value.dispclk_notify_pplib_done = true; + if (clocks_in_khz > clk->clks.dispclk_khz) { + clk->dispclk_notify_pplib_done = true; send_request = true; } else - clk->cur_clocks_value.dispclk_notify_pplib_done = false; + clk->dispclk_notify_pplib_done = false; /* no matter incrase or decrase clock, update current clock value */ - clk->cur_clocks_value.dispclk_in_khz = clocks_in_khz; - break; - case DM_PP_CLOCK_TYPE_PIXELCLK: - if (clocks_in_khz > clk->cur_clocks_value.max_pixelclk_in_khz) { - clk->cur_clocks_value.pixelclk_notify_pplib_done = true; - send_request = true; - } else - clk->cur_clocks_value.pixelclk_notify_pplib_done = false; - /* no matter incrase or decrase clock, update current clock value */ - clk->cur_clocks_value.max_pixelclk_in_khz = clocks_in_khz; + clk->clks.dispclk_khz = clocks_in_khz; break; case DM_PP_CLOCK_TYPE_DISPLAYPHYCLK: - if (clocks_in_khz > clk->cur_clocks_value.max_non_dp_phyclk_in_khz) { - clk->cur_clocks_value.phyclk_notigy_pplib_done = true; + if (clocks_in_khz > clk->clks.phyclk_khz) { + clk->phyclk_notify_pplib_done = true; send_request = true; } else - clk->cur_clocks_value.phyclk_notigy_pplib_done = false; + clk->phyclk_notify_pplib_done = false; /* no matter incrase or decrase clock, update current clock value */ - clk->cur_clocks_value.max_non_dp_phyclk_in_khz = clocks_in_khz; + clk->clks.phyclk_khz = clocks_in_khz; break; default: ASSERT(0); @@ -609,16 +598,14 @@ static bool dce_apply_clock_voltage_request( } else { switch (clocks_type) { case DM_PP_CLOCK_TYPE_DISPLAY_CLK: - if (!clk->cur_clocks_value.dispclk_notify_pplib_done) - send_request = true; - break; - case DM_PP_CLOCK_TYPE_PIXELCLK: - if (!clk->cur_clocks_value.pixelclk_notify_pplib_done) + if (!clk->dispclk_notify_pplib_done) send_request = true; + clk->dispclk_notify_pplib_done = true; break; case DM_PP_CLOCK_TYPE_DISPLAYPHYCLK: - if (!clk->cur_clocks_value.phyclk_notigy_pplib_done) + if (!clk->phyclk_notify_pplib_done) send_request = true; + clk->phyclk_notify_pplib_done = true; break; default: ASSERT(0); @@ -627,20 +614,21 @@ static bool dce_apply_clock_voltage_request( } if (send_request) { #if defined(CONFIG_DRM_AMD_DC_DCN1_0) - if (clk->ctx->dce_version >= DCN_VERSION_1_0) { + if (clk->ctx->dce_version >= DCN_VERSION_1_0 + ) { struct dc *core_dc = clk->ctx->dc; /*use dcfclk request voltage*/ clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DCFCLK; clock_voltage_req.clocks_in_khz = - dcn_find_dcfclk_suits_all(core_dc, &clk->cur_clocks_value); + dcn_find_dcfclk_suits_all(core_dc, &clk->clks); } #endif dm_pp_apply_clock_for_voltage_request( clk->ctx, &clock_voltage_req); } if (update_dp_phyclk && (clocks_in_khz > - clk->cur_clocks_value.max_dp_phyclk_in_khz)) - clk->cur_clocks_value.max_dp_phyclk_in_khz = clocks_in_khz; + clk->clks.phyclk_khz)) + clk->clks.phyclk_khz = clocks_in_khz; return true; } 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 353ffcbdf5ba6..ddc8ffda90678 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 @@ -1818,21 +1818,14 @@ static void apply_min_clocks( context->dis_clk->funcs->apply_clock_voltage_request( context->dis_clk, DM_PP_CLOCK_TYPE_DISPLAY_CLK, - context->dis_clk->cur_clocks_value.dispclk_in_khz, - pre_mode_set, - false); - - context->dis_clk->funcs->apply_clock_voltage_request( - context->dis_clk, - DM_PP_CLOCK_TYPE_PIXELCLK, - context->dis_clk->cur_clocks_value.max_pixelclk_in_khz, + context->dis_clk->clks.dispclk_khz, pre_mode_set, false); context->dis_clk->funcs->apply_clock_voltage_request( context->dis_clk, DM_PP_CLOCK_TYPE_DISPLAYPHYCLK, - context->dis_clk->cur_clocks_value.max_non_dp_phyclk_in_khz, + context->dis_clk->clks.phyclk_khz, pre_mode_set, false); return; @@ -1859,13 +1852,6 @@ static void apply_min_clocks( pre_mode_set, false); - context->dis_clk->funcs->apply_clock_voltage_request( - context->dis_clk, - DM_PP_CLOCK_TYPE_PIXELCLK, - req_clocks.pixel_clk_khz, - pre_mode_set, - false); - context->dis_clk->funcs->apply_clock_voltage_request( context->dis_clk, DM_PP_CLOCK_TYPE_DISPLAYPHYCLK, diff --git a/drivers/gpu/drm/amd/display/dc/inc/dcn_calcs.h b/drivers/gpu/drm/amd/display/dc/inc/dcn_calcs.h index 132d18d4b2938..ddbb673caa08e 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/dcn_calcs.h +++ b/drivers/gpu/drm/amd/display/dc/inc/dcn_calcs.h @@ -625,7 +625,7 @@ bool dcn_validate_bandwidth( unsigned int dcn_find_dcfclk_suits_all( const struct dc *dc, - struct clocks_value *clocks); + struct dc_clocks *clocks); void dcn_bw_update_from_pplib(struct dc *dc); void dcn_bw_notify_pplib_of_wm_ranges(struct dc *dc); diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/display_clock.h b/drivers/gpu/drm/amd/display/dc/inc/hw/display_clock.h index f5f69cd81f6fd..6b9ca5562de99 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/display_clock.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/display_clock.h @@ -27,23 +27,7 @@ #define __DISPLAY_CLOCK_H__ #include "dm_services_types.h" - - -struct clocks_value { - int dispclk_in_khz; - int max_pixelclk_in_khz; - int max_non_dp_phyclk_in_khz; - int max_dp_phyclk_in_khz; - bool dispclk_notify_pplib_done; - bool pixelclk_notify_pplib_done; - bool phyclk_notigy_pplib_done; - int dcfclock_in_khz; - int dppclk_in_khz; - int mclk_in_khz; - int phyclk_in_khz; - int common_vdd_level; -}; - +#include "dc.h" /* Structure containing all state-dependent clocks * (dependent on "enum clocks_state") */ @@ -56,9 +40,11 @@ struct display_clock { struct dc_context *ctx; const struct display_clock_funcs *funcs; + bool dispclk_notify_pplib_done; + bool phyclk_notify_pplib_done; enum dm_pp_clocks_state max_clks_state; enum dm_pp_clocks_state cur_min_clks_state; - struct clocks_value cur_clocks_value; + struct dc_clocks clks; }; struct display_clock_funcs { -- GitLab From fab55d61b9f04693abc6fdbc92e3fdf3872915b1 Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Date: Wed, 23 May 2018 16:21:54 -0400 Subject: [PATCH 0704/1506] drm/amd/display: redesign dce/dcn clock voltage update request The goal of this change is to move clock programming and voltage requests to a single function. As of this change only dce is affected. Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/display/dc/calcs/dcn_calcs.c | 22 +- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 30 +- .../gpu/drm/amd/display/dc/dce/dce_clocks.c | 279 ++++++++++-------- .../gpu/drm/amd/display/dc/dce/dce_clocks.h | 6 +- .../display/dc/dce100/dce100_hw_sequencer.c | 49 ++- .../display/dc/dce110/dce110_hw_sequencer.c | 150 ++-------- .../display/dc/dce110/dce110_hw_sequencer.h | 4 + .../amd/display/dc/dcn10/dcn10_hw_sequencer.c | 9 +- .../drm/amd/display/dc/dcn10/dcn10_resource.c | 2 +- .../drm/amd/display/dc/inc/hw/display_clock.h | 21 +- 10 files changed, 250 insertions(+), 322 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c index d8a31650e8562..2b70ac67e6c28 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c @@ -1145,10 +1145,10 @@ static unsigned int dcn_find_normalized_clock_vdd_Level( switch (clocks_type) { case DM_PP_CLOCK_TYPE_DISPLAY_CLK: - /*if (clocks_in_khz > dc->dcn_soc->max_dispclk_vmax0p9*1000) { + if (clocks_in_khz > dc->dcn_soc->max_dispclk_vmax0p9*1000) { vdd_level = dcn_bw_v_max0p91; - //BREAK_TO_DEBUGGER(); - } else*/ if (clocks_in_khz > dc->dcn_soc->max_dispclk_vnom0p8*1000) { + BREAK_TO_DEBUGGER(); + } else if (clocks_in_khz > dc->dcn_soc->max_dispclk_vnom0p8*1000) { vdd_level = dcn_bw_v_max0p9; } else if (clocks_in_khz > dc->dcn_soc->max_dispclk_vmid0p72*1000) { vdd_level = dcn_bw_v_nom0p8; @@ -1158,10 +1158,10 @@ static unsigned int dcn_find_normalized_clock_vdd_Level( vdd_level = dcn_bw_v_min0p65; break; case DM_PP_CLOCK_TYPE_DISPLAYPHYCLK: - /*if (clocks_in_khz > dc->dcn_soc->phyclkv_max0p9*1000) { + if (clocks_in_khz > dc->dcn_soc->phyclkv_max0p9*1000) { vdd_level = dcn_bw_v_max0p91; BREAK_TO_DEBUGGER(); - } else*/ if (clocks_in_khz > dc->dcn_soc->phyclkv_nom0p8*1000) { + } else if (clocks_in_khz > dc->dcn_soc->phyclkv_nom0p8*1000) { vdd_level = dcn_bw_v_max0p9; } else if (clocks_in_khz > dc->dcn_soc->phyclkv_mid0p72*1000) { vdd_level = dcn_bw_v_nom0p8; @@ -1172,10 +1172,10 @@ static unsigned int dcn_find_normalized_clock_vdd_Level( break; case DM_PP_CLOCK_TYPE_DPPCLK: - /*if (clocks_in_khz > dc->dcn_soc->max_dppclk_vmax0p9*1000) { + if (clocks_in_khz > dc->dcn_soc->max_dppclk_vmax0p9*1000) { vdd_level = dcn_bw_v_max0p91; BREAK_TO_DEBUGGER(); - } else*/ if (clocks_in_khz > dc->dcn_soc->max_dppclk_vnom0p8*1000) { + } else if (clocks_in_khz > dc->dcn_soc->max_dppclk_vnom0p8*1000) { vdd_level = dcn_bw_v_max0p9; } else if (clocks_in_khz > dc->dcn_soc->max_dppclk_vmid0p72*1000) { vdd_level = dcn_bw_v_nom0p8; @@ -1189,10 +1189,10 @@ static unsigned int dcn_find_normalized_clock_vdd_Level( { unsigned factor = (ddr4_dram_factor_single_Channel * dc->dcn_soc->number_of_channels); - /*if (clocks_in_khz > dc->dcn_soc->fabric_and_dram_bandwidth_vmax0p9*1000000/factor) { + if (clocks_in_khz > dc->dcn_soc->fabric_and_dram_bandwidth_vmax0p9*1000000/factor) { vdd_level = dcn_bw_v_max0p91; BREAK_TO_DEBUGGER(); - } else */if (clocks_in_khz > dc->dcn_soc->fabric_and_dram_bandwidth_vnom0p8*1000000/factor) { + } else if (clocks_in_khz > dc->dcn_soc->fabric_and_dram_bandwidth_vnom0p8*1000000/factor) { vdd_level = dcn_bw_v_max0p9; } else if (clocks_in_khz > dc->dcn_soc->fabric_and_dram_bandwidth_vmid0p72*1000000/factor) { vdd_level = dcn_bw_v_nom0p8; @@ -1204,10 +1204,10 @@ static unsigned int dcn_find_normalized_clock_vdd_Level( break; case DM_PP_CLOCK_TYPE_DCFCLK: - /*if (clocks_in_khz > dc->dcn_soc->dcfclkv_max0p9*1000) { + if (clocks_in_khz > dc->dcn_soc->dcfclkv_max0p9*1000) { vdd_level = dcn_bw_v_max0p91; BREAK_TO_DEBUGGER(); - } else */if (clocks_in_khz > dc->dcn_soc->dcfclkv_nom0p8*1000) { + } else if (clocks_in_khz > dc->dcn_soc->dcfclkv_nom0p8*1000) { vdd_level = dcn_bw_v_max0p9; } else if (clocks_in_khz > dc->dcn_soc->dcfclkv_mid0p72*1000) { vdd_level = dcn_bw_v_nom0p8; 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 6155a5c7bd368..779d1926a756c 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -1284,27 +1284,15 @@ static enum dc_status enable_link_dp( max_link_rate = LINK_RATE_HIGH3; if (link_settings.link_rate == max_link_rate) { - if (state->dis_clk->funcs->set_min_clocks_state) { - if (state->dis_clk->cur_min_clks_state < DM_PP_CLOCKS_STATE_NOMINAL) - state->dis_clk->funcs->set_min_clocks_state( - state->dis_clk, DM_PP_CLOCKS_STATE_NOMINAL); - } else { - uint32_t dp_phyclk_in_khz; - const struct dc_clocks clocks_value = - state->dis_clk->clks; - - /* 27mhz = 27000000hz= 27000khz */ - dp_phyclk_in_khz = link_settings.link_rate * 27000; - - if (dp_phyclk_in_khz > clocks_value.phyclk_khz) { - state->dis_clk->funcs->apply_clock_voltage_request( - state->dis_clk, - DM_PP_CLOCK_TYPE_DISPLAYPHYCLK, - dp_phyclk_in_khz, - false, - true); - } - } + struct dc_clocks clocks = state->bw.dcn.calc_clk; + + /* dce/dcn compat, do not update dispclk */ + clocks.dispclk_khz = 0; + /* 27mhz = 27000000hz= 27000khz */ + clocks.phyclk_khz = link_settings.link_rate * 27000; + + state->dis_clk->funcs->update_clocks( + state->dis_clk, &clocks, false); } dp_enable_link_phy( diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c index b749a20a0c3de..d3bbac85dff18 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c @@ -275,7 +275,7 @@ static int dce_clocks_get_dp_ref_freq_wrkaround(struct display_clock *clk) } static enum dm_pp_clocks_state dce_get_required_clocks_state( struct display_clock *clk, - struct state_dependent_clocks *req_clocks) + struct dc_clocks *req_clocks) { struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(clk); int i; @@ -286,48 +286,25 @@ static enum dm_pp_clocks_state dce_get_required_clocks_state( * all required clocks */ for (i = clk->max_clks_state; i >= DM_PP_CLOCKS_STATE_ULTRA_LOW; i--) - if (req_clocks->display_clk_khz > + if (req_clocks->dispclk_khz > clk_dce->max_clks_by_state[i].display_clk_khz - || req_clocks->pixel_clk_khz > + || req_clocks->phyclk_khz > clk_dce->max_clks_by_state[i].pixel_clk_khz) break; low_req_clk = i + 1; if (low_req_clk > clk->max_clks_state) { - DC_LOG_WARNING("%s: clocks unsupported disp_clk %d pix_clk %d", - __func__, - req_clocks->display_clk_khz, - req_clocks->pixel_clk_khz); - low_req_clk = DM_PP_CLOCKS_STATE_INVALID; + /* set max clock state for high phyclock, invalid on exceeding display clock */ + if (clk_dce->max_clks_by_state[clk->max_clks_state].display_clk_khz + < req_clocks->dispclk_khz) + low_req_clk = DM_PP_CLOCKS_STATE_INVALID; + else + low_req_clk = clk->max_clks_state; } return low_req_clk; } -static bool dce_clock_set_min_clocks_state( - struct display_clock *clk, - enum dm_pp_clocks_state clocks_state) -{ - struct dm_pp_power_level_change_request level_change_req = { - clocks_state }; - - if (clocks_state > clk->max_clks_state) { - /*Requested state exceeds max supported state.*/ - DC_LOG_WARNING("Requested state exceeds max supported state"); - return false; - } else if (clocks_state == clk->cur_min_clks_state) { - /*if we're trying to set the same state, we can just return - * since nothing needs to be done*/ - return true; - } - - /* get max clock state from PPLIB */ - if (dm_pp_apply_power_level_change_request(clk->ctx, &level_change_req)) - clk->cur_min_clks_state = clocks_state; - - return true; -} - static int dce_set_clock( struct display_clock *clk, int requested_clk_khz) @@ -488,8 +465,6 @@ static void dce_clock_read_integrated_info(struct dce_disp_clk *clk_dce) if (!debug->disable_dfs_bypass && bp->integrated_info) if (bp->integrated_info->gpu_cap_info & DFS_BYPASS_ENABLE) clk_dce->dfs_bypass_enabled = true; - - clk_dce->use_max_disp_clk = debug->max_disp_clk; } static void dce_clock_read_ss_info(struct dce_disp_clk *clk_dce) @@ -548,117 +523,160 @@ static void dce_clock_read_ss_info(struct dce_disp_clk *clk_dce) } } -static bool dce_apply_clock_voltage_request( - struct display_clock *clk, - enum dm_pp_clock_type clocks_type, - int clocks_in_khz, - bool pre_mode_set, - bool update_dp_phyclk) +static void dce12_update_clocks(struct display_clock *dccg, + struct dc_clocks *new_clocks, + bool safe_to_lower) { - bool send_request = false; struct dm_pp_clock_for_voltage_req clock_voltage_req = {0}; - switch (clocks_type) { - case DM_PP_CLOCK_TYPE_DISPLAY_CLK: - case DM_PP_CLOCK_TYPE_DISPLAYPHYCLK: - break; - default: - return false; + if ((new_clocks->dispclk_khz < dccg->clks.dispclk_khz && safe_to_lower) + || new_clocks->dispclk_khz > dccg->clks.dispclk_khz) { + clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DISPLAY_CLK; + clock_voltage_req.clocks_in_khz = new_clocks->dispclk_khz; + dccg->funcs->set_dispclk(dccg, new_clocks->dispclk_khz); + dccg->clks.dispclk_khz = new_clocks->dispclk_khz; + + dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req); } - clock_voltage_req.clk_type = clocks_type; - clock_voltage_req.clocks_in_khz = clocks_in_khz; - - /* to pplib */ - if (pre_mode_set) { - switch (clocks_type) { - case DM_PP_CLOCK_TYPE_DISPLAY_CLK: - if (clocks_in_khz > clk->clks.dispclk_khz) { - clk->dispclk_notify_pplib_done = true; - send_request = true; - } else - clk->dispclk_notify_pplib_done = false; - /* no matter incrase or decrase clock, update current clock value */ - clk->clks.dispclk_khz = clocks_in_khz; - break; - case DM_PP_CLOCK_TYPE_DISPLAYPHYCLK: - if (clocks_in_khz > clk->clks.phyclk_khz) { - clk->phyclk_notify_pplib_done = true; - send_request = true; - } else - clk->phyclk_notify_pplib_done = false; - /* no matter incrase or decrase clock, update current clock value */ - clk->clks.phyclk_khz = clocks_in_khz; - break; - default: - ASSERT(0); - break; - } + if ((new_clocks->phyclk_khz < dccg->clks.phyclk_khz && safe_to_lower) + || new_clocks->phyclk_khz > dccg->clks.phyclk_khz) { + clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DISPLAYPHYCLK; + clock_voltage_req.clocks_in_khz = new_clocks->phyclk_khz; + dccg->clks.phyclk_khz = new_clocks->phyclk_khz; - } else { - switch (clocks_type) { - case DM_PP_CLOCK_TYPE_DISPLAY_CLK: - if (!clk->dispclk_notify_pplib_done) - send_request = true; - clk->dispclk_notify_pplib_done = true; - break; - case DM_PP_CLOCK_TYPE_DISPLAYPHYCLK: - if (!clk->phyclk_notify_pplib_done) - send_request = true; - clk->phyclk_notify_pplib_done = true; - break; - default: - ASSERT(0); - break; - } + dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req); } - if (send_request) { -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) - if (clk->ctx->dce_version >= DCN_VERSION_1_0 +} + +static void dcn_update_clocks(struct display_clock *dccg, + struct dc_clocks *new_clocks, + bool safe_to_lower) +{ + struct dm_pp_clock_for_voltage_req clock_voltage_req = {0}; + bool send_request_to_increase = false; + bool send_request_to_lower = false; + + if (new_clocks->dispclk_khz > dccg->clks.dispclk_khz + || new_clocks->phyclk_khz > dccg->clks.phyclk_khz + || new_clocks->fclk_khz > dccg->clks.fclk_khz + || new_clocks->dcfclk_khz > dccg->clks.dcfclk_khz) + send_request_to_increase = true; + +#ifdef CONFIG_DRM_AMD_DC_DCN1_0 + if (send_request_to_increase ) { - struct dc *core_dc = clk->ctx->dc; - /*use dcfclk request voltage*/ - clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DCFCLK; - clock_voltage_req.clocks_in_khz = - dcn_find_dcfclk_suits_all(core_dc, &clk->clks); - } + struct dc *core_dc = dccg->ctx->dc; + + /*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(core_dc, new_clocks); + dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req); + } #endif - dm_pp_apply_clock_for_voltage_request( - clk->ctx, &clock_voltage_req); + + if ((new_clocks->dispclk_khz < dccg->clks.dispclk_khz && safe_to_lower) + || new_clocks->dispclk_khz > dccg->clks.dispclk_khz) { + clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DISPLAY_CLK; + clock_voltage_req.clocks_in_khz = new_clocks->dispclk_khz; + /* TODO: ramp up - dccg->funcs->set_dispclk(dccg, new_clocks->dispclk_khz);*/ + dccg->clks.dispclk_khz = new_clocks->dispclk_khz; + + dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req); + send_request_to_lower = true; } - if (update_dp_phyclk && (clocks_in_khz > - clk->clks.phyclk_khz)) - clk->clks.phyclk_khz = clocks_in_khz; - return true; + if ((new_clocks->phyclk_khz < dccg->clks.phyclk_khz && safe_to_lower) + || new_clocks->phyclk_khz > dccg->clks.phyclk_khz) { + dccg->clks.phyclk_khz = new_clocks->phyclk_khz; + clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DISPLAYPHYCLK; + clock_voltage_req.clocks_in_khz = new_clocks->phyclk_khz; + + dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req); + send_request_to_lower = true; + } + + if ((new_clocks->fclk_khz < dccg->clks.fclk_khz && safe_to_lower) + || new_clocks->fclk_khz > dccg->clks.fclk_khz) { + dccg->clks.phyclk_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; + + dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req); + send_request_to_lower = true; + } + + if ((new_clocks->dcfclk_khz < dccg->clks.dcfclk_khz && safe_to_lower) + || new_clocks->dcfclk_khz > dccg->clks.dcfclk_khz) { + dccg->clks.phyclk_khz = new_clocks->dcfclk_khz; + clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DCFCLK; + clock_voltage_req.clocks_in_khz = new_clocks->dcfclk_khz; + + send_request_to_lower = true; + } + +#ifdef CONFIG_DRM_AMD_DC_DCN1_0 + if (!send_request_to_increase && send_request_to_lower + ) { + struct dc *core_dc = dccg->ctx->dc; + + /*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(core_dc, new_clocks); + dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req); + } +#endif +} + +static void dce_update_clocks(struct display_clock *dccg, + struct dc_clocks *new_clocks, + bool safe_to_lower) +{ + struct dm_pp_power_level_change_request level_change_req; + + level_change_req.power_level = dce_get_required_clocks_state(dccg, new_clocks); + /* get max clock state from PPLIB */ + if ((level_change_req.power_level < dccg->cur_min_clks_state && safe_to_lower) + || level_change_req.power_level > dccg->cur_min_clks_state) { + if (dm_pp_apply_power_level_change_request(dccg->ctx, &level_change_req)) + dccg->cur_min_clks_state = level_change_req.power_level; + } + + if ((new_clocks->dispclk_khz < dccg->clks.dispclk_khz && safe_to_lower) + || new_clocks->dispclk_khz > dccg->clks.dispclk_khz) { + dccg->funcs->set_dispclk(dccg, new_clocks->dispclk_khz); + dccg->clks.dispclk_khz = new_clocks->dispclk_khz; + } } +static const struct display_clock_funcs dcn_funcs = { + .get_dp_ref_clk_frequency = dce_clocks_get_dp_ref_freq_wrkaround, + .set_dispclk = dce112_set_clock, + .update_clocks = dcn_update_clocks +}; static const struct display_clock_funcs dce120_funcs = { .get_dp_ref_clk_frequency = dce_clocks_get_dp_ref_freq_wrkaround, - .apply_clock_voltage_request = dce_apply_clock_voltage_request, - .set_clock = dce112_set_clock + .set_dispclk = dce112_set_clock, + .update_clocks = dce12_update_clocks }; static const struct display_clock_funcs dce112_funcs = { .get_dp_ref_clk_frequency = dce_clocks_get_dp_ref_freq, - .get_required_clocks_state = dce_get_required_clocks_state, - .set_min_clocks_state = dce_clock_set_min_clocks_state, - .set_clock = dce112_set_clock + .set_dispclk = dce112_set_clock, + .update_clocks = dce_update_clocks }; static const struct display_clock_funcs dce110_funcs = { .get_dp_ref_clk_frequency = dce_clocks_get_dp_ref_freq, - .get_required_clocks_state = dce_get_required_clocks_state, - .set_min_clocks_state = dce_clock_set_min_clocks_state, - .set_clock = dce_psr_set_clock + .set_dispclk = dce_psr_set_clock, + .update_clocks = dce_update_clocks }; static const struct display_clock_funcs dce_funcs = { .get_dp_ref_clk_frequency = dce_clocks_get_dp_ref_freq, - .get_required_clocks_state = dce_get_required_clocks_state, - .set_min_clocks_state = dce_clock_set_min_clocks_state, - .set_clock = dce_set_clock + .set_dispclk = dce_set_clock, + .update_clocks = dce_update_clocks }; static void dce_disp_clk_construct( @@ -785,7 +803,6 @@ struct display_clock *dce112_disp_clk_create( struct display_clock *dce120_disp_clk_create(struct dc_context *ctx) { struct dce_disp_clk *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL); - struct dm_pp_clock_levels_with_voltage clk_level_info = {0}; if (clk_dce == NULL) { BREAK_TO_DEBUGGER(); @@ -801,15 +818,23 @@ struct display_clock *dce120_disp_clk_create(struct dc_context *ctx) clk_dce->base.funcs = &dce120_funcs; - /* new in dce120 */ - if (!ctx->dc->debug.disable_pplib_clock_request && - dm_pp_get_clock_levels_by_type_with_voltage( - ctx, DM_PP_CLOCK_TYPE_DISPLAY_CLK, &clk_level_info) - && clk_level_info.num_levels) - clk_dce->max_displ_clk_in_khz = - clk_level_info.data[clk_level_info.num_levels - 1].clocks_in_khz; - else - clk_dce->max_displ_clk_in_khz = 1133000; + return &clk_dce->base; +} + +struct display_clock *dcn_disp_clk_create(struct dc_context *ctx) +{ + struct dce_disp_clk *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL); + + if (clk_dce == NULL) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + /* TODO strip out useful stuff out of dce constructor */ + dce_disp_clk_construct( + clk_dce, ctx, NULL, NULL, NULL); + + clk_dce->base.funcs = &dcn_funcs; return &clk_dce->base; } diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h index 0e717e0dc8f02..f9b002015255d 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h @@ -91,7 +91,6 @@ struct dce_disp_clk { struct state_dependent_clocks max_clks_by_state[DM_PP_CLOCKS_MAX_STATES]; struct dce_divider_range divider_ranges[DIVIDER_RANGE_MAX]; - bool use_max_disp_clk; int dentist_vco_freq_khz; /* Cache the status of DFS-bypass feature*/ @@ -106,9 +105,6 @@ struct dce_disp_clk { int dprefclk_ss_percentage; /* DPREFCLK SS percentage Divider (100 or 1000) */ int dprefclk_ss_divider; - - /* max disp_clk from PPLIB for max validation display clock*/ - int max_displ_clk_in_khz; }; @@ -132,6 +128,8 @@ struct display_clock *dce112_disp_clk_create( struct display_clock *dce120_disp_clk_create(struct dc_context *ctx); +struct display_clock *dcn_disp_clk_create(struct dc_context *ctx); + void dce_disp_clk_destroy(struct display_clock **disp_clk); #endif /* _DCE_CLOCKS_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c index 41f83ecd7469b..aabf7ca9b2410 100644 --- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c @@ -125,17 +125,54 @@ static void dce100_pplib_apply_display_requirements( dc->prev_display_config = *pp_display_cfg; } +/* unit: in_khz before mode set, get pixel clock from context. ASIC register + * may not be programmed yet + */ +static uint32_t get_max_pixel_clock_for_all_paths( + struct dc *dc, + struct dc_state *context) +{ + uint32_t max_pix_clk = 0; + int i; + + for (i = 0; i < MAX_PIPES; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + if (pipe_ctx->stream == NULL) + continue; + + /* do not check under lay */ + if (pipe_ctx->top_pipe) + continue; + + if (pipe_ctx->stream_res.pix_clk_params.requested_pix_clk > max_pix_clk) + max_pix_clk = + pipe_ctx->stream_res.pix_clk_params.requested_pix_clk; + } + + if (max_pix_clk == 0) + ASSERT(0); + + return max_pix_clk; +} + void dce100_set_bandwidth( struct dc *dc, struct dc_state *context, bool decrease_allowed) { - if (decrease_allowed || context->bw.dce.dispclk_khz > dc->current_state->bw.dce.dispclk_khz) { - dc->res_pool->display_clock->funcs->set_clock( - dc->res_pool->display_clock, - context->bw.dce.dispclk_khz * 115 / 100); - dc->current_state->bw.dce.dispclk_khz = context->bw.dce.dispclk_khz; - } + struct dc_clocks req_clks; + + req_clks.dispclk_khz = context->bw.dce.dispclk_khz * 115 / 100; + req_clks.phyclk_khz = get_max_pixel_clock_for_all_paths(dc, context); + + dce110_set_safe_displaymarks(&context->res_ctx, dc->res_pool); + + dc->res_pool->display_clock->funcs->update_clocks( + dc->res_pool->display_clock, + &req_clks, + decrease_allowed); + dce100_pplib_apply_display_requirements(dc, context); } 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 ddc8ffda90678..02aa0a2ec8750 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 @@ -1663,7 +1663,7 @@ static void dce110_set_displaymarks( } } -static void set_safe_displaymarks( +void dce110_set_safe_displaymarks( struct resource_context *res_ctx, const struct resource_pool *pool) { @@ -1755,23 +1755,15 @@ static void set_static_screen_control(struct pipe_ctx **pipe_ctx, } /* unit: in_khz before mode set, get pixel clock from context. ASIC register - * may not be programmed yet. - * TODO: after mode set, pre_mode_set = false, - * may read PLL register to get pixel clock + * may not be programmed yet */ static uint32_t get_max_pixel_clock_for_all_paths( struct dc *dc, - struct dc_state *context, - bool pre_mode_set) + struct dc_state *context) { uint32_t max_pix_clk = 0; int i; - if (!pre_mode_set) { - /* TODO: read ASIC register to get pixel clock */ - ASSERT(0); - } - for (i = 0; i < MAX_PIPES; i++) { struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; @@ -1793,74 +1785,6 @@ static uint32_t get_max_pixel_clock_for_all_paths( return max_pix_clk; } -/* - * Find clock state based on clock requested. if clock value is 0, simply - * set clock state as requested without finding clock state by clock value - */ - -static void apply_min_clocks( - struct dc *dc, - struct dc_state *context, - enum dm_pp_clocks_state *clocks_state, - bool pre_mode_set) -{ - struct state_dependent_clocks req_clocks = {0}; - - if (!pre_mode_set) { - /* set clock_state without verification */ - if (context->dis_clk->funcs->set_min_clocks_state) { - context->dis_clk->funcs->set_min_clocks_state( - context->dis_clk, *clocks_state); - return; - } - - /* TODO: This is incorrect. Figure out how to fix. */ - context->dis_clk->funcs->apply_clock_voltage_request( - context->dis_clk, - DM_PP_CLOCK_TYPE_DISPLAY_CLK, - context->dis_clk->clks.dispclk_khz, - pre_mode_set, - false); - - context->dis_clk->funcs->apply_clock_voltage_request( - context->dis_clk, - DM_PP_CLOCK_TYPE_DISPLAYPHYCLK, - context->dis_clk->clks.phyclk_khz, - pre_mode_set, - false); - return; - } - - /* get the required state based on state dependent clocks: - * display clock and pixel clock - */ - req_clocks.display_clk_khz = context->bw.dce.dispclk_khz; - - req_clocks.pixel_clk_khz = get_max_pixel_clock_for_all_paths( - dc, context, true); - - if (context->dis_clk->funcs->get_required_clocks_state) { - *clocks_state = context->dis_clk->funcs->get_required_clocks_state( - context->dis_clk, &req_clocks); - context->dis_clk->funcs->set_min_clocks_state( - context->dis_clk, *clocks_state); - } else { - context->dis_clk->funcs->apply_clock_voltage_request( - context->dis_clk, - DM_PP_CLOCK_TYPE_DISPLAY_CLK, - req_clocks.display_clk_khz, - pre_mode_set, - false); - - context->dis_clk->funcs->apply_clock_voltage_request( - context->dis_clk, - DM_PP_CLOCK_TYPE_DISPLAYPHYCLK, - req_clocks.pixel_clk_khz, - pre_mode_set, - false); - } -} - /* * Check if FBC can be enabled */ @@ -2079,7 +2003,6 @@ enum dc_status dce110_apply_ctx_to_hw( struct dc_bios *dcb = dc->ctx->dc_bios; enum dc_status status; int i; - enum dm_pp_clocks_state clocks_state = DM_PP_CLOCKS_STATE_INVALID; /* Reset old context */ /* look up the targets that have been removed since last commit */ @@ -2113,54 +2036,10 @@ enum dc_status dce110_apply_ctx_to_hw( PIPE_GATING_CONTROL_DISABLE); } - set_safe_displaymarks(&context->res_ctx, dc->res_pool); - if (dc->fbc_compressor) dc->fbc_compressor->funcs->disable_fbc(dc->fbc_compressor); - /*TODO: when pplib works*/ - apply_min_clocks(dc, context, &clocks_state, true); - -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) - if (dc->ctx->dce_version >= DCN_VERSION_1_0) { - if (context->bw.dcn.calc_clk.fclk_khz - > dc->current_state->bw.dcn.cur_clk.fclk_khz) { - struct dm_pp_clock_for_voltage_req clock; - - clock.clk_type = DM_PP_CLOCK_TYPE_FCLK; - clock.clocks_in_khz = context->bw.dcn.calc_clk.fclk_khz; - dm_pp_apply_clock_for_voltage_request(dc->ctx, &clock); - dc->current_state->bw.dcn.cur_clk.fclk_khz = clock.clocks_in_khz; - context->bw.dcn.cur_clk.fclk_khz = clock.clocks_in_khz; - } - if (context->bw.dcn.calc_clk.dcfclk_khz - > dc->current_state->bw.dcn.cur_clk.dcfclk_khz) { - struct dm_pp_clock_for_voltage_req clock; - - clock.clk_type = DM_PP_CLOCK_TYPE_DCFCLK; - clock.clocks_in_khz = context->bw.dcn.calc_clk.dcfclk_khz; - dm_pp_apply_clock_for_voltage_request(dc->ctx, &clock); - dc->current_state->bw.dcn.cur_clk.dcfclk_khz = clock.clocks_in_khz; - context->bw.dcn.cur_clk.dcfclk_khz = clock.clocks_in_khz; - } - if (context->bw.dcn.calc_clk.dispclk_khz - > dc->current_state->bw.dcn.cur_clk.dispclk_khz) { - dc->res_pool->display_clock->funcs->set_clock( - dc->res_pool->display_clock, - context->bw.dcn.calc_clk.dispclk_khz); - dc->current_state->bw.dcn.cur_clk.dispclk_khz = - context->bw.dcn.calc_clk.dispclk_khz; - context->bw.dcn.cur_clk.dispclk_khz = - context->bw.dcn.calc_clk.dispclk_khz; - } - } else -#endif - if (context->bw.dce.dispclk_khz - > dc->current_state->bw.dce.dispclk_khz) { - dc->res_pool->display_clock->funcs->set_clock( - dc->res_pool->display_clock, - context->bw.dce.dispclk_khz * 115 / 100); - } + dc->hwss.set_bandwidth(dc, context, false); dce110_setup_audio_dto(dc, context); @@ -2191,7 +2070,7 @@ enum dc_status dce110_apply_ctx_to_hw( } /* to save power */ - apply_min_clocks(dc, context, &clocks_state, false); + dc->hwss.set_bandwidth(dc, context, true); dcb->funcs->set_scratch_critical_state(dcb, false); @@ -2680,15 +2559,20 @@ static void dce110_set_bandwidth( struct dc_state *context, bool decrease_allowed) { - dce110_set_displaymarks(dc, context); + struct dc_clocks req_clks; - if (decrease_allowed || context->bw.dce.dispclk_khz > dc->current_state->bw.dce.dispclk_khz) { - dc->res_pool->display_clock->funcs->set_clock( - dc->res_pool->display_clock, - context->bw.dce.dispclk_khz * 115 / 100); - dc->current_state->bw.dce.dispclk_khz = context->bw.dce.dispclk_khz; - } + req_clks.dispclk_khz = context->bw.dce.dispclk_khz * 115 / 100; + req_clks.phyclk_khz = get_max_pixel_clock_for_all_paths(dc, context); + + if (decrease_allowed) + dce110_set_displaymarks(dc, context); + else + dce110_set_safe_displaymarks(&context->res_ctx, dc->res_pool); + dc->res_pool->display_clock->funcs->update_clocks( + dc->res_pool->display_clock, + &req_clks, + decrease_allowed); pplib_apply_display_requirements(dc, context); } diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h index f48d5a68d2386..d6db3dbd90153 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h @@ -60,6 +60,10 @@ void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context); void dce110_power_down(struct dc *dc); +void dce110_set_safe_displaymarks( + struct resource_context *res_ctx, + const struct resource_pool *pool); + void dce110_fill_display_configs( const struct dc_state *context, struct dm_pp_display_configuration *pp_display_cfg); 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 03eb736a312ff..7f1a7ec9ff5f6 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 @@ -2424,7 +2424,7 @@ static void ramp_up_dispclk_with_dpp(struct dc *dc, struct dc_state *context) int dispclk_to_dpp_threshold = determine_dppclk_threshold(dc, context); /* set disp clk to dpp clk threshold */ - dc->res_pool->display_clock->funcs->set_clock( + dc->res_pool->display_clock->funcs->set_dispclk( dc->res_pool->display_clock, dispclk_to_dpp_threshold); @@ -2443,7 +2443,7 @@ static void ramp_up_dispclk_with_dpp(struct dc *dc, struct dc_state *context) /* If target clk not same as dppclk threshold, set to target clock */ if (dispclk_to_dpp_threshold != context->bw.dcn.calc_clk.dispclk_khz) { - dc->res_pool->display_clock->funcs->set_clock( + dc->res_pool->display_clock->funcs->set_dispclk( dc->res_pool->display_clock, context->bw.dcn.calc_clk.dispclk_khz); } @@ -2473,6 +2473,11 @@ static void dcn10_set_bandwidth( if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) return; + dc->res_pool->display_clock->funcs->update_clocks( + dc->res_pool->display_clock, + &context->bw.dcn.calc_clk, + decrease_allowed); + if (should_set_clock( decrease_allowed, context->bw.dcn.calc_clk.dcfclk_khz, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c index 2da325ce781bc..870eb0aabcc9e 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c @@ -1072,7 +1072,7 @@ static bool construct( } } - pool->base.display_clock = dce120_disp_clk_create(ctx); + pool->base.display_clock = dcn_disp_clk_create(ctx); if (pool->base.display_clock == NULL) { dm_error("DC: failed to create display clock!\n"); BREAK_TO_DEBUGGER(); diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/display_clock.h b/drivers/gpu/drm/amd/display/dc/inc/hw/display_clock.h index 6b9ca5562de99..8ce106f156476 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/display_clock.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/display_clock.h @@ -40,32 +40,19 @@ struct display_clock { struct dc_context *ctx; const struct display_clock_funcs *funcs; - bool dispclk_notify_pplib_done; - bool phyclk_notify_pplib_done; enum dm_pp_clocks_state max_clks_state; enum dm_pp_clocks_state cur_min_clks_state; struct dc_clocks clks; }; struct display_clock_funcs { - int (*set_clock)(struct display_clock *disp_clk, + void (*update_clocks)(struct display_clock *dccg, + struct dc_clocks *new_clocks, + bool safe_to_lower); + int (*set_dispclk)(struct display_clock *disp_clk, int requested_clock_khz); - enum dm_pp_clocks_state (*get_required_clocks_state)( - struct display_clock *disp_clk, - struct state_dependent_clocks *req_clocks); - - bool (*set_min_clocks_state)(struct display_clock *disp_clk, - enum dm_pp_clocks_state dm_pp_clocks_state); - int (*get_dp_ref_clk_frequency)(struct display_clock *disp_clk); - - bool (*apply_clock_voltage_request)( - struct display_clock *disp_clk, - enum dm_pp_clock_type clocks_type, - int clocks_in_khz, - bool pre_mode_set, - bool update_dp_phyclk); }; #endif /* __DISPLAY_CLOCK_H__ */ -- GitLab From 6ca11246180a6e5e6b5b668545c2575b304c9f7f Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Date: Wed, 23 May 2018 16:44:26 -0400 Subject: [PATCH 0705/1506] drm/amd/display: rename display clock block to dccg Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/display/dc/core/dc_resource.c | 2 +- .../gpu/drm/amd/display/dc/dce/dce_clocks.c | 78 +++++++++---------- .../gpu/drm/amd/display/dc/dce/dce_clocks.h | 16 ++-- .../display/dc/dce100/dce100_hw_sequencer.c | 4 +- .../amd/display/dc/dce100/dce100_resource.c | 10 +-- .../display/dc/dce110/dce110_hw_sequencer.c | 4 +- .../amd/display/dc/dce110/dce110_resource.c | 10 +-- .../amd/display/dc/dce112/dce112_resource.c | 10 +-- .../amd/display/dc/dce120/dce120_resource.c | 12 +-- .../drm/amd/display/dc/dce80/dce80_resource.c | 22 +++--- .../amd/display/dc/dcn10/dcn10_hw_sequencer.c | 12 +-- .../drm/amd/display/dc/dcn10/dcn10_resource.c | 8 +- .../gpu/drm/amd/display/dc/inc/core_types.h | 4 +- .../drm/amd/display/dc/inc/hw/display_clock.h | 8 +- 14 files changed, 100 insertions(+), 100 deletions(-) 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 fca22550417a9..c5fc5250e2bfc 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -1948,7 +1948,7 @@ void dc_resource_state_construct( const struct dc *dc, struct dc_state *dst_ctx) { - dst_ctx->dis_clk = dc->res_pool->display_clock; + dst_ctx->dis_clk = dc->res_pool->dccg; } enum dc_status dc_validate_global_state( diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c index d3bbac85dff18..890a3ec68d49e 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c @@ -38,7 +38,7 @@ #include "dal_asic_id.h" #define TO_DCE_CLOCKS(clocks)\ - container_of(clocks, struct dce_disp_clk, base) + container_of(clocks, struct dce_dccg, base) #define REG(reg) \ (clk_dce->regs->reg) @@ -187,9 +187,9 @@ static int dce_divider_range_get_divider( return div; } -static int dce_clocks_get_dp_ref_freq(struct display_clock *clk) +static int dce_clocks_get_dp_ref_freq(struct dccg *clk) { - struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(clk); + struct dce_dccg *clk_dce = TO_DCE_CLOCKS(clk); int dprefclk_wdivider; int dprefclk_src_sel; int dp_ref_clk_khz = 600000; @@ -250,9 +250,9 @@ static int dce_clocks_get_dp_ref_freq(struct display_clock *clk) * or CLK0_CLK11 by SMU. For DCE120, it is wlays 600Mhz. Will re-visit * clock implementation */ -static int dce_clocks_get_dp_ref_freq_wrkaround(struct display_clock *clk) +static int dce_clocks_get_dp_ref_freq_wrkaround(struct dccg *clk) { - struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(clk); + struct dce_dccg *clk_dce = TO_DCE_CLOCKS(clk); int dp_ref_clk_khz = 600000; if (clk_dce->ss_on_dprefclk && clk_dce->dprefclk_ss_divider != 0) { @@ -274,10 +274,10 @@ static int dce_clocks_get_dp_ref_freq_wrkaround(struct display_clock *clk) return dp_ref_clk_khz; } static enum dm_pp_clocks_state dce_get_required_clocks_state( - struct display_clock *clk, + struct dccg *clk, struct dc_clocks *req_clocks) { - struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(clk); + struct dce_dccg *clk_dce = TO_DCE_CLOCKS(clk); int i; enum dm_pp_clocks_state low_req_clk; @@ -306,10 +306,10 @@ static enum dm_pp_clocks_state dce_get_required_clocks_state( } static int dce_set_clock( - struct display_clock *clk, + struct dccg *clk, int requested_clk_khz) { - struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(clk); + struct dce_dccg *clk_dce = TO_DCE_CLOCKS(clk); struct bp_pixel_clock_parameters pxl_clk_params = { 0 }; struct dc_bios *bp = clk->ctx->dc_bios; int actual_clock = requested_clk_khz; @@ -341,10 +341,10 @@ static int dce_set_clock( } static int dce_psr_set_clock( - struct display_clock *clk, + struct dccg *clk, int requested_clk_khz) { - struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(clk); + struct dce_dccg *clk_dce = TO_DCE_CLOCKS(clk); struct dc_context *ctx = clk_dce->base.ctx; struct dc *core_dc = ctx->dc; struct dmcu *dmcu = core_dc->res_pool->dmcu; @@ -357,10 +357,10 @@ static int dce_psr_set_clock( } static int dce112_set_clock( - struct display_clock *clk, + struct dccg *clk, int requested_clk_khz) { - struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(clk); + struct dce_dccg *clk_dce = TO_DCE_CLOCKS(clk); struct bp_set_dce_clock_parameters dce_clk_params; struct dc_bios *bp = clk->ctx->dc_bios; struct dc *core_dc = clk->ctx->dc; @@ -409,7 +409,7 @@ static int dce112_set_clock( return actual_clock; } -static void dce_clock_read_integrated_info(struct dce_disp_clk *clk_dce) +static void dce_clock_read_integrated_info(struct dce_dccg *clk_dce) { struct dc_debug *debug = &clk_dce->base.ctx->dc->debug; struct dc_bios *bp = clk_dce->base.ctx->dc_bios; @@ -467,7 +467,7 @@ static void dce_clock_read_integrated_info(struct dce_disp_clk *clk_dce) clk_dce->dfs_bypass_enabled = true; } -static void dce_clock_read_ss_info(struct dce_disp_clk *clk_dce) +static void dce_clock_read_ss_info(struct dce_dccg *clk_dce) { struct dc_bios *bp = clk_dce->base.ctx->dc_bios; int ss_info_num = bp->funcs->get_ss_entry_number( @@ -523,7 +523,7 @@ static void dce_clock_read_ss_info(struct dce_disp_clk *clk_dce) } } -static void dce12_update_clocks(struct display_clock *dccg, +static void dce12_update_clocks(struct dccg *dccg, struct dc_clocks *new_clocks, bool safe_to_lower) { @@ -549,7 +549,7 @@ static void dce12_update_clocks(struct display_clock *dccg, } } -static void dcn_update_clocks(struct display_clock *dccg, +static void dcn_update_clocks(struct dccg *dccg, struct dc_clocks *new_clocks, bool safe_to_lower) { @@ -628,7 +628,7 @@ static void dcn_update_clocks(struct display_clock *dccg, #endif } -static void dce_update_clocks(struct display_clock *dccg, +static void dce_update_clocks(struct dccg *dccg, struct dc_clocks *new_clocks, bool safe_to_lower) { @@ -679,14 +679,14 @@ static const struct display_clock_funcs dce_funcs = { .update_clocks = dce_update_clocks }; -static void dce_disp_clk_construct( - struct dce_disp_clk *clk_dce, +static void dce_dccg_construct( + struct dce_dccg *clk_dce, struct dc_context *ctx, const struct dce_disp_clk_registers *regs, const struct dce_disp_clk_shift *clk_shift, const struct dce_disp_clk_mask *clk_mask) { - struct display_clock *base = &clk_dce->base; + struct dccg *base = &clk_dce->base; base->ctx = ctx; base->funcs = &dce_funcs; @@ -727,13 +727,13 @@ static void dce_disp_clk_construct( DIVIDER_RANGE_MAX_DIVIDER_ID); } -struct display_clock *dce_disp_clk_create( +struct dccg *dce_dccg_create( struct dc_context *ctx, const struct dce_disp_clk_registers *regs, const struct dce_disp_clk_shift *clk_shift, const struct dce_disp_clk_mask *clk_mask) { - struct dce_disp_clk *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL); + struct dce_dccg *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL); if (clk_dce == NULL) { BREAK_TO_DEBUGGER(); @@ -744,19 +744,19 @@ struct display_clock *dce_disp_clk_create( dce80_max_clks_by_state, sizeof(dce80_max_clks_by_state)); - dce_disp_clk_construct( + dce_dccg_construct( clk_dce, ctx, regs, clk_shift, clk_mask); return &clk_dce->base; } -struct display_clock *dce110_disp_clk_create( +struct dccg *dce110_dccg_create( struct dc_context *ctx, const struct dce_disp_clk_registers *regs, const struct dce_disp_clk_shift *clk_shift, const struct dce_disp_clk_mask *clk_mask) { - struct dce_disp_clk *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL); + struct dce_dccg *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL); if (clk_dce == NULL) { BREAK_TO_DEBUGGER(); @@ -767,7 +767,7 @@ struct display_clock *dce110_disp_clk_create( dce110_max_clks_by_state, sizeof(dce110_max_clks_by_state)); - dce_disp_clk_construct( + dce_dccg_construct( clk_dce, ctx, regs, clk_shift, clk_mask); clk_dce->base.funcs = &dce110_funcs; @@ -775,13 +775,13 @@ struct display_clock *dce110_disp_clk_create( return &clk_dce->base; } -struct display_clock *dce112_disp_clk_create( +struct dccg *dce112_dccg_create( struct dc_context *ctx, const struct dce_disp_clk_registers *regs, const struct dce_disp_clk_shift *clk_shift, const struct dce_disp_clk_mask *clk_mask) { - struct dce_disp_clk *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL); + struct dce_dccg *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL); if (clk_dce == NULL) { BREAK_TO_DEBUGGER(); @@ -792,7 +792,7 @@ struct display_clock *dce112_disp_clk_create( dce112_max_clks_by_state, sizeof(dce112_max_clks_by_state)); - dce_disp_clk_construct( + dce_dccg_construct( clk_dce, ctx, regs, clk_shift, clk_mask); clk_dce->base.funcs = &dce112_funcs; @@ -800,9 +800,9 @@ struct display_clock *dce112_disp_clk_create( return &clk_dce->base; } -struct display_clock *dce120_disp_clk_create(struct dc_context *ctx) +struct dccg *dce120_dccg_create(struct dc_context *ctx) { - struct dce_disp_clk *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL); + struct dce_dccg *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL); if (clk_dce == NULL) { BREAK_TO_DEBUGGER(); @@ -813,7 +813,7 @@ struct display_clock *dce120_disp_clk_create(struct dc_context *ctx) dce120_max_clks_by_state, sizeof(dce120_max_clks_by_state)); - dce_disp_clk_construct( + dce_dccg_construct( clk_dce, ctx, NULL, NULL, NULL); clk_dce->base.funcs = &dce120_funcs; @@ -821,9 +821,9 @@ struct display_clock *dce120_disp_clk_create(struct dc_context *ctx) return &clk_dce->base; } -struct display_clock *dcn_disp_clk_create(struct dc_context *ctx) +struct dccg *dcn_dccg_create(struct dc_context *ctx) { - struct dce_disp_clk *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL); + struct dce_dccg *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL); if (clk_dce == NULL) { BREAK_TO_DEBUGGER(); @@ -831,7 +831,7 @@ struct display_clock *dcn_disp_clk_create(struct dc_context *ctx) } /* TODO strip out useful stuff out of dce constructor */ - dce_disp_clk_construct( + dce_dccg_construct( clk_dce, ctx, NULL, NULL, NULL); clk_dce->base.funcs = &dcn_funcs; @@ -839,10 +839,10 @@ struct display_clock *dcn_disp_clk_create(struct dc_context *ctx) return &clk_dce->base; } -void dce_disp_clk_destroy(struct display_clock **disp_clk) +void dce_dccg_destroy(struct dccg **dccg) { - struct dce_disp_clk *clk_dce = TO_DCE_CLOCKS(*disp_clk); + struct dce_dccg *clk_dce = TO_DCE_CLOCKS(*dccg); kfree(clk_dce); - *disp_clk = NULL; + *dccg = NULL; } diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h index f9b002015255d..c695b9c9bcb55 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h @@ -82,8 +82,8 @@ struct dce_divider_range { int did_max; }; -struct dce_disp_clk { - struct display_clock base; +struct dce_dccg { + struct dccg base; const struct dce_disp_clk_registers *regs; const struct dce_disp_clk_shift *clk_shift; const struct dce_disp_clk_mask *clk_mask; @@ -108,28 +108,28 @@ struct dce_disp_clk { }; -struct display_clock *dce_disp_clk_create( +struct dccg *dce_dccg_create( struct dc_context *ctx, const struct dce_disp_clk_registers *regs, const struct dce_disp_clk_shift *clk_shift, const struct dce_disp_clk_mask *clk_mask); -struct display_clock *dce110_disp_clk_create( +struct dccg *dce110_dccg_create( struct dc_context *ctx, const struct dce_disp_clk_registers *regs, const struct dce_disp_clk_shift *clk_shift, const struct dce_disp_clk_mask *clk_mask); -struct display_clock *dce112_disp_clk_create( +struct dccg *dce112_dccg_create( struct dc_context *ctx, const struct dce_disp_clk_registers *regs, const struct dce_disp_clk_shift *clk_shift, const struct dce_disp_clk_mask *clk_mask); -struct display_clock *dce120_disp_clk_create(struct dc_context *ctx); +struct dccg *dce120_dccg_create(struct dc_context *ctx); -struct display_clock *dcn_disp_clk_create(struct dc_context *ctx); +struct dccg *dcn_dccg_create(struct dc_context *ctx); -void dce_disp_clk_destroy(struct display_clock **disp_clk); +void dce_dccg_destroy(struct dccg **dccg); #endif /* _DCE_CLOCKS_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c index aabf7ca9b2410..ec3221333011b 100644 --- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c @@ -168,8 +168,8 @@ void dce100_set_bandwidth( dce110_set_safe_displaymarks(&context->res_ctx, dc->res_pool); - dc->res_pool->display_clock->funcs->update_clocks( - dc->res_pool->display_clock, + dc->res_pool->dccg->funcs->update_clocks( + dc->res_pool->dccg, &req_clks, decrease_allowed); diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c index 38ec0d609297f..856d3fe8e6a0f 100644 --- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c @@ -644,8 +644,8 @@ static void destruct(struct dce110_resource_pool *pool) dce_aud_destroy(&pool->base.audios[i]); } - if (pool->base.display_clock != NULL) - dce_disp_clk_destroy(&pool->base.display_clock); + if (pool->base.dccg != NULL) + dce_dccg_destroy(&pool->base.dccg); if (pool->base.abm != NULL) dce_abm_destroy(&pool->base.abm); @@ -817,11 +817,11 @@ static bool construct( } } - pool->base.display_clock = dce_disp_clk_create(ctx, + pool->base.dccg = dce_dccg_create(ctx, &disp_clk_regs, &disp_clk_shift, &disp_clk_mask); - if (pool->base.display_clock == NULL) { + if (pool->base.dccg == NULL) { dm_error("DC: failed to create display clock!\n"); BREAK_TO_DEBUGGER(); goto res_create_fail; @@ -851,7 +851,7 @@ static bool construct( * max_clock_state */ if (dm_pp_get_static_clocks(ctx, &static_clk_info)) - pool->base.display_clock->max_clks_state = + pool->base.dccg->max_clks_state = static_clk_info.max_clocks_state; { struct irq_service_init_data init_data; 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 02aa0a2ec8750..34eb7a33851b2 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 @@ -2569,8 +2569,8 @@ static void dce110_set_bandwidth( else dce110_set_safe_displaymarks(&context->res_ctx, dc->res_pool); - dc->res_pool->display_clock->funcs->update_clocks( - dc->res_pool->display_clock, + dc->res_pool->dccg->funcs->update_clocks( + dc->res_pool->dccg, &req_clks, decrease_allowed); pplib_apply_display_requirements(dc, context); diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c index 20c0290895515..71a401f73a58c 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c @@ -679,8 +679,8 @@ static void destruct(struct dce110_resource_pool *pool) if (pool->base.dmcu != NULL) dce_dmcu_destroy(&pool->base.dmcu); - if (pool->base.display_clock != NULL) - dce_disp_clk_destroy(&pool->base.display_clock); + if (pool->base.dccg != NULL) + dce_dccg_destroy(&pool->base.dccg); if (pool->base.irqs != NULL) { dal_irq_service_destroy(&pool->base.irqs); @@ -1179,11 +1179,11 @@ static bool construct( } } - pool->base.display_clock = dce110_disp_clk_create(ctx, + pool->base.dccg = dce110_dccg_create(ctx, &disp_clk_regs, &disp_clk_shift, &disp_clk_mask); - if (pool->base.display_clock == NULL) { + if (pool->base.dccg == NULL) { dm_error("DC: failed to create display clock!\n"); BREAK_TO_DEBUGGER(); goto res_create_fail; @@ -1213,7 +1213,7 @@ static bool construct( * max_clock_state */ if (dm_pp_get_static_clocks(ctx, &static_clk_info)) - pool->base.display_clock->max_clks_state = + pool->base.dccg->max_clks_state = static_clk_info.max_clocks_state; { diff --git a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c index 00c0a1ef15ebd..ae5b19de559cd 100644 --- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c @@ -668,8 +668,8 @@ static void destruct(struct dce110_resource_pool *pool) if (pool->base.dmcu != NULL) dce_dmcu_destroy(&pool->base.dmcu); - if (pool->base.display_clock != NULL) - dce_disp_clk_destroy(&pool->base.display_clock); + if (pool->base.dccg != NULL) + dce_dccg_destroy(&pool->base.dccg); if (pool->base.irqs != NULL) { dal_irq_service_destroy(&pool->base.irqs); @@ -1124,11 +1124,11 @@ static bool construct( } } - pool->base.display_clock = dce112_disp_clk_create(ctx, + pool->base.dccg = dce112_dccg_create(ctx, &disp_clk_regs, &disp_clk_shift, &disp_clk_mask); - if (pool->base.display_clock == NULL) { + if (pool->base.dccg == NULL) { dm_error("DC: failed to create display clock!\n"); BREAK_TO_DEBUGGER(); goto res_create_fail; @@ -1158,7 +1158,7 @@ static bool construct( * max_clock_state */ if (dm_pp_get_static_clocks(ctx, &static_clk_info)) - pool->base.display_clock->max_clks_state = + pool->base.dccg->max_clks_state = static_clk_info.max_clocks_state; { diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c index 2d58daccc0056..13c388a608c44 100644 --- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c @@ -494,8 +494,8 @@ static void destruct(struct dce110_resource_pool *pool) if (pool->base.dmcu != NULL) dce_dmcu_destroy(&pool->base.dmcu); - if (pool->base.display_clock != NULL) - dce_disp_clk_destroy(&pool->base.display_clock); + if (pool->base.dccg != NULL) + dce_dccg_destroy(&pool->base.dccg); } static void read_dce_straps( @@ -894,11 +894,11 @@ static bool construct( } } - pool->base.display_clock = dce120_disp_clk_create(ctx); - if (pool->base.display_clock == NULL) { + pool->base.dccg = dce120_dccg_create(ctx); + if (pool->base.dccg == NULL) { dm_error("DC: failed to create display clock!\n"); BREAK_TO_DEBUGGER(); - goto disp_clk_create_fail; + goto dccg_create_fail; } pool->base.dmcu = dce_dmcu_create(ctx, @@ -1011,7 +1011,7 @@ static bool construct( irqs_create_fail: controller_create_fail: -disp_clk_create_fail: +dccg_create_fail: clk_src_create_fail: res_create_fail: diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c index 48a0689647225..70700530aec29 100644 --- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c @@ -683,8 +683,8 @@ static void destruct(struct dce110_resource_pool *pool) } } - if (pool->base.display_clock != NULL) - dce_disp_clk_destroy(&pool->base.display_clock); + if (pool->base.dccg != NULL) + dce_dccg_destroy(&pool->base.dccg); if (pool->base.irqs != NULL) { dal_irq_service_destroy(&pool->base.irqs); @@ -822,11 +822,11 @@ static bool dce80_construct( } } - pool->base.display_clock = dce_disp_clk_create(ctx, + pool->base.dccg = dce_dccg_create(ctx, &disp_clk_regs, &disp_clk_shift, &disp_clk_mask); - if (pool->base.display_clock == NULL) { + if (pool->base.dccg == NULL) { dm_error("DC: failed to create display clock!\n"); BREAK_TO_DEBUGGER(); goto res_create_fail; @@ -852,7 +852,7 @@ static bool dce80_construct( goto res_create_fail; } if (dm_pp_get_static_clocks(ctx, &static_clk_info)) - pool->base.display_clock->max_clks_state = + pool->base.dccg->max_clks_state = static_clk_info.max_clocks_state; { @@ -1006,11 +1006,11 @@ static bool dce81_construct( } } - pool->base.display_clock = dce_disp_clk_create(ctx, + pool->base.dccg = dce_dccg_create(ctx, &disp_clk_regs, &disp_clk_shift, &disp_clk_mask); - if (pool->base.display_clock == NULL) { + if (pool->base.dccg == NULL) { dm_error("DC: failed to create display clock!\n"); BREAK_TO_DEBUGGER(); goto res_create_fail; @@ -1037,7 +1037,7 @@ static bool dce81_construct( } if (dm_pp_get_static_clocks(ctx, &static_clk_info)) - pool->base.display_clock->max_clks_state = + pool->base.dccg->max_clks_state = static_clk_info.max_clocks_state; { @@ -1187,11 +1187,11 @@ static bool dce83_construct( } } - pool->base.display_clock = dce_disp_clk_create(ctx, + pool->base.dccg = dce_dccg_create(ctx, &disp_clk_regs, &disp_clk_shift, &disp_clk_mask); - if (pool->base.display_clock == NULL) { + if (pool->base.dccg == NULL) { dm_error("DC: failed to create display clock!\n"); BREAK_TO_DEBUGGER(); goto res_create_fail; @@ -1218,7 +1218,7 @@ static bool dce83_construct( } if (dm_pp_get_static_clocks(ctx, &static_clk_info)) - pool->base.display_clock->max_clks_state = + pool->base.dccg->max_clks_state = static_clk_info.max_clocks_state; { 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 7f1a7ec9ff5f6..f519b98f4b232 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 @@ -2424,8 +2424,8 @@ static void ramp_up_dispclk_with_dpp(struct dc *dc, struct dc_state *context) int dispclk_to_dpp_threshold = determine_dppclk_threshold(dc, context); /* set disp clk to dpp clk threshold */ - dc->res_pool->display_clock->funcs->set_dispclk( - dc->res_pool->display_clock, + dc->res_pool->dccg->funcs->set_dispclk( + dc->res_pool->dccg, dispclk_to_dpp_threshold); /* update request dpp clk division option */ @@ -2443,8 +2443,8 @@ static void ramp_up_dispclk_with_dpp(struct dc *dc, struct dc_state *context) /* If target clk not same as dppclk threshold, set to target clock */ if (dispclk_to_dpp_threshold != context->bw.dcn.calc_clk.dispclk_khz) { - dc->res_pool->display_clock->funcs->set_dispclk( - dc->res_pool->display_clock, + dc->res_pool->dccg->funcs->set_dispclk( + dc->res_pool->dccg, context->bw.dcn.calc_clk.dispclk_khz); } @@ -2473,8 +2473,8 @@ static void dcn10_set_bandwidth( if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) return; - dc->res_pool->display_clock->funcs->update_clocks( - dc->res_pool->display_clock, + dc->res_pool->dccg->funcs->update_clocks( + dc->res_pool->dccg, &context->bw.dcn.calc_clk, decrease_allowed); diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c index 870eb0aabcc9e..8f1ceffa809b7 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c @@ -791,8 +791,8 @@ static void destruct(struct dcn10_resource_pool *pool) if (pool->base.dmcu != NULL) dce_dmcu_destroy(&pool->base.dmcu); - if (pool->base.display_clock != NULL) - dce_disp_clk_destroy(&pool->base.display_clock); + if (pool->base.dccg != NULL) + dce_dccg_destroy(&pool->base.dccg); kfree(pool->base.pp_smu); } @@ -1072,8 +1072,8 @@ static bool construct( } } - pool->base.display_clock = dcn_disp_clk_create(ctx); - if (pool->base.display_clock == NULL) { + pool->base.dccg = dcn_dccg_create(ctx); + if (pool->base.dccg == NULL) { dm_error("DC: failed to create display clock!\n"); BREAK_TO_DEBUGGER(); goto fail; diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h index 4beddca0180c3..44c48f3d0a1de 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h @@ -163,7 +163,7 @@ struct resource_pool { unsigned int audio_count; struct audio_support audio_support; - struct display_clock *display_clock; + struct dccg *dccg; struct irq_service *irqs; struct abm *abm; @@ -282,7 +282,7 @@ struct dc_state { struct dcn_bw_internal_vars dcn_bw_vars; #endif - struct display_clock *dis_clk; + struct dccg *dis_clk; struct kref refcount; }; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/display_clock.h b/drivers/gpu/drm/amd/display/dc/inc/hw/display_clock.h index 8ce106f156476..3c7ccb68ecdb5 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/display_clock.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/display_clock.h @@ -36,7 +36,7 @@ struct state_dependent_clocks { int pixel_clk_khz; }; -struct display_clock { +struct dccg { struct dc_context *ctx; const struct display_clock_funcs *funcs; @@ -46,13 +46,13 @@ struct display_clock { }; struct display_clock_funcs { - void (*update_clocks)(struct display_clock *dccg, + void (*update_clocks)(struct dccg *dccg, struct dc_clocks *new_clocks, bool safe_to_lower); - int (*set_dispclk)(struct display_clock *disp_clk, + int (*set_dispclk)(struct dccg *dccg, int requested_clock_khz); - int (*get_dp_ref_clk_frequency)(struct display_clock *disp_clk); + int (*get_dp_ref_clk_frequency)(struct dccg *dccg); }; #endif /* __DISPLAY_CLOCK_H__ */ -- GitLab From e2e0a1dcd3229eec32ded439f69438a25ec817d6 Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Date: Wed, 23 May 2018 17:52:04 -0400 Subject: [PATCH 0706/1506] drm/amd/display: move clock programming from set_bandwidth to dccg This change moves dcn clock programming(with exception of dispclk) into dccg. This should have no functional effect. Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/display/dc/calcs/dcn_calcs.c | 2 +- .../gpu/drm/amd/display/dc/dce/dce_clocks.c | 57 +++++++++++------ .../amd/display/dc/dcn10/dcn10_hw_sequencer.c | 62 ++++--------------- 3 files changed, 51 insertions(+), 70 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c index 2b70ac67e6c28..9acdd9da740e4 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c @@ -997,7 +997,7 @@ bool dcn_validate_bandwidth( } context->bw.dcn.calc_clk.dppclk_khz = context->bw.dcn.calc_clk.dispclk_khz / v->dispclk_dppclk_ratio; - + context->bw.dcn.calc_clk.phyclk_khz = v->phyclk_per_state[v->voltage_level]; switch (v->voltage_level) { case 0: context->bw.dcn.calc_clk.max_supported_dppclk_khz = diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c index 890a3ec68d49e..93e6063c4b975 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c @@ -523,14 +523,18 @@ static void dce_clock_read_ss_info(struct dce_dccg *clk_dce) } } +static inline bool should_set_clock(bool safe_to_lower, int calc_clk, int cur_clk) +{ + return ((safe_to_lower && calc_clk < cur_clk) || calc_clk > cur_clk); +} + static void dce12_update_clocks(struct dccg *dccg, struct dc_clocks *new_clocks, bool safe_to_lower) { struct dm_pp_clock_for_voltage_req clock_voltage_req = {0}; - if ((new_clocks->dispclk_khz < dccg->clks.dispclk_khz && safe_to_lower) - || new_clocks->dispclk_khz > dccg->clks.dispclk_khz) { + if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, dccg->clks.dispclk_khz)) { clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DISPLAY_CLK; clock_voltage_req.clocks_in_khz = new_clocks->dispclk_khz; dccg->funcs->set_dispclk(dccg, new_clocks->dispclk_khz); @@ -539,8 +543,7 @@ static void dce12_update_clocks(struct dccg *dccg, dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req); } - if ((new_clocks->phyclk_khz < dccg->clks.phyclk_khz && safe_to_lower) - || new_clocks->phyclk_khz > dccg->clks.phyclk_khz) { + if (should_set_clock(safe_to_lower, new_clocks->phyclk_khz, dccg->clks.phyclk_khz)) { clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DISPLAYPHYCLK; clock_voltage_req.clocks_in_khz = new_clocks->phyclk_khz; dccg->clks.phyclk_khz = new_clocks->phyclk_khz; @@ -553,6 +556,11 @@ static void dcn_update_clocks(struct dccg *dccg, struct dc_clocks *new_clocks, bool safe_to_lower) { + struct dc *dc = dccg->ctx->dc; + struct pp_smu_display_requirement_rv *smu_req_cur = + &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}; bool send_request_to_increase = false; bool send_request_to_lower = false; @@ -566,17 +574,14 @@ static void dcn_update_clocks(struct dccg *dccg, #ifdef CONFIG_DRM_AMD_DC_DCN1_0 if (send_request_to_increase ) { - struct dc *core_dc = dccg->ctx->dc; - /*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(core_dc, new_clocks); + clock_voltage_req.clocks_in_khz = dcn_find_dcfclk_suits_all(dc, new_clocks); dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req); } #endif - if ((new_clocks->dispclk_khz < dccg->clks.dispclk_khz && safe_to_lower) - || new_clocks->dispclk_khz > dccg->clks.dispclk_khz) { + if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, dccg->clks.dispclk_khz)) { clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DISPLAY_CLK; clock_voltage_req.clocks_in_khz = new_clocks->dispclk_khz; /* TODO: ramp up - dccg->funcs->set_dispclk(dccg, new_clocks->dispclk_khz);*/ @@ -586,8 +591,7 @@ static void dcn_update_clocks(struct dccg *dccg, send_request_to_lower = true; } - if ((new_clocks->phyclk_khz < dccg->clks.phyclk_khz && safe_to_lower) - || new_clocks->phyclk_khz > dccg->clks.phyclk_khz) { + if (should_set_clock(safe_to_lower, new_clocks->phyclk_khz, dccg->clks.phyclk_khz)) { dccg->clks.phyclk_khz = new_clocks->phyclk_khz; clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DISPLAYPHYCLK; clock_voltage_req.clocks_in_khz = new_clocks->phyclk_khz; @@ -596,36 +600,50 @@ static void dcn_update_clocks(struct dccg *dccg, send_request_to_lower = true; } - if ((new_clocks->fclk_khz < dccg->clks.fclk_khz && safe_to_lower) - || new_clocks->fclk_khz > dccg->clks.fclk_khz) { + if (should_set_clock(safe_to_lower, new_clocks->fclk_khz, dccg->clks.fclk_khz)) { dccg->clks.phyclk_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_khz = new_clocks->fclk_khz; dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req); send_request_to_lower = true; } - if ((new_clocks->dcfclk_khz < dccg->clks.dcfclk_khz && safe_to_lower) - || new_clocks->dcfclk_khz > dccg->clks.dcfclk_khz) { + if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, dccg->clks.dcfclk_khz)) { dccg->clks.phyclk_khz = new_clocks->dcfclk_khz; clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DCFCLK; clock_voltage_req.clocks_in_khz = new_clocks->dcfclk_khz; + smu_req.hard_min_dcefclk_khz = new_clocks->dcfclk_khz; send_request_to_lower = true; } + if (should_set_clock(safe_to_lower, + new_clocks->dcfclk_deep_sleep_khz, dccg->clks.dcfclk_deep_sleep_khz)) { + dccg->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz; + smu_req.min_deep_sleep_dcefclk_mhz = new_clocks->dcfclk_deep_sleep_khz; + } + #ifdef CONFIG_DRM_AMD_DC_DCN1_0 if (!send_request_to_increase && send_request_to_lower ) { - struct dc *core_dc = dccg->ctx->dc; - /*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(core_dc, new_clocks); + clock_voltage_req.clocks_in_khz = dcn_find_dcfclk_suits_all(dc, new_clocks); dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req); } #endif + + if (new_clocks->phyclk_khz) + smu_req.display_count = 1; + else + smu_req.display_count = 0; + + if (pp_smu->set_display_requirement) + pp_smu->set_display_requirement(&pp_smu->pp_smu, &smu_req); + + *smu_req_cur = smu_req; } static void dce_update_clocks(struct dccg *dccg, @@ -642,8 +660,7 @@ static void dce_update_clocks(struct dccg *dccg, dccg->cur_min_clks_state = level_change_req.power_level; } - if ((new_clocks->dispclk_khz < dccg->clks.dispclk_khz && safe_to_lower) - || new_clocks->dispclk_khz > dccg->clks.dispclk_khz) { + if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, dccg->clks.dispclk_khz)) { dccg->funcs->set_dispclk(dccg, new_clocks->dispclk_khz); dccg->clks.dispclk_khz = new_clocks->dispclk_khz; } 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 f519b98f4b232..09c7007868e8d 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 @@ -2153,11 +2153,11 @@ static void dcn10_pplib_apply_display_requirements( { struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg; - pp_display_cfg->min_engine_clock_khz = context->bw.dcn.cur_clk.dcfclk_khz; - pp_display_cfg->min_memory_clock_khz = context->bw.dcn.cur_clk.fclk_khz; - pp_display_cfg->min_engine_clock_deep_sleep_khz = context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz; - pp_display_cfg->min_dcfc_deep_sleep_clock_khz = context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz; - pp_display_cfg->min_dcfclock_khz = context->bw.dcn.cur_clk.dcfclk_khz; + pp_display_cfg->min_engine_clock_khz = dc->res_pool->dccg->clks.dcfclk_khz; + pp_display_cfg->min_memory_clock_khz = dc->res_pool->dccg->clks.fclk_khz; + pp_display_cfg->min_engine_clock_deep_sleep_khz = dc->res_pool->dccg->clks.dcfclk_deep_sleep_khz; + pp_display_cfg->min_dcfc_deep_sleep_clock_khz = dc->res_pool->dccg->clks.dcfclk_deep_sleep_khz; + pp_display_cfg->min_dcfclock_khz = dc->res_pool->dccg->clks.dcfclk_khz; pp_display_cfg->disp_clk_khz = context->bw.dcn.cur_clk.dispclk_khz; dce110_fill_display_configs(context, pp_display_cfg); @@ -2361,11 +2361,6 @@ static void dcn10_apply_ctx_for_surface( */ } -static inline bool should_set_clock(bool decrease_allowed, int calc_clk, int cur_clk) -{ - return ((decrease_allowed && calc_clk < cur_clk) || calc_clk > cur_clk); -} - static int determine_dppclk_threshold(struct dc *dc, struct dc_state *context) { bool request_dpp_div = context->bw.dcn.calc_clk.dispclk_khz > @@ -2456,16 +2451,16 @@ static void ramp_up_dispclk_with_dpp(struct dc *dc, struct dc_state *context) context->bw.dcn.calc_clk.max_supported_dppclk_khz; } +static inline bool should_set_clock(bool safe_to_lower, int calc_clk, int cur_clk) +{ + return ((safe_to_lower && calc_clk < cur_clk) || calc_clk > cur_clk); +} + static void dcn10_set_bandwidth( struct dc *dc, struct dc_state *context, bool decrease_allowed) { - struct pp_smu_display_requirement_rv *smu_req_cur = - &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; - if (dc->debug.sanity_checks) { dcn10_verify_allow_pstate_change_high(dc); } @@ -2473,45 +2468,14 @@ static void dcn10_set_bandwidth( if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) return; + if (context->stream_count == 0) + context->bw.dcn.calc_clk.phyclk_khz = 0; + dc->res_pool->dccg->funcs->update_clocks( dc->res_pool->dccg, &context->bw.dcn.calc_clk, decrease_allowed); - if (should_set_clock( - decrease_allowed, - context->bw.dcn.calc_clk.dcfclk_khz, - dc->current_state->bw.dcn.cur_clk.dcfclk_khz)) { - context->bw.dcn.cur_clk.dcfclk_khz = - context->bw.dcn.calc_clk.dcfclk_khz; - smu_req.hard_min_dcefclk_khz = - context->bw.dcn.calc_clk.dcfclk_khz; - } - - if (should_set_clock( - decrease_allowed, - context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz, - dc->current_state->bw.dcn.cur_clk.dcfclk_deep_sleep_khz)) { - context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz = - context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz; - } - - if (should_set_clock( - decrease_allowed, - context->bw.dcn.calc_clk.fclk_khz, - dc->current_state->bw.dcn.cur_clk.fclk_khz)) { - context->bw.dcn.cur_clk.fclk_khz = - context->bw.dcn.calc_clk.fclk_khz; - smu_req.hard_min_fclk_khz = context->bw.dcn.calc_clk.fclk_khz; - } - - smu_req.display_count = context->stream_count; - - if (pp_smu->set_display_requirement) - pp_smu->set_display_requirement(&pp_smu->pp_smu, &smu_req); - - *smu_req_cur = smu_req; - /* make sure dcf clk is before dpp clk to * make sure we have enough voltage to run dpp clk */ -- GitLab From 734b096096ac860b5a72c52e8a6a8b81fa9e016c Mon Sep 17 00:00:00 2001 From: Mikita Lipski <mikita.lipski@amd.com> Date: Mon, 9 Apr 2018 09:48:15 -0400 Subject: [PATCH 0707/1506] drm/amd/display: Adding dm-pp clocks getting by voltage Function to get clock levels by voltage from PPLib Signed-off-by: Mikita Lipski <mikita.lipski@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../display/amdgpu_dm/amdgpu_dm_services.c | 43 ++++++++++++++++++- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c index e861929dd981f..bc15ee692d377 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c @@ -253,6 +253,34 @@ static void pp_to_dc_clock_levels_with_latency( } } +static void pp_to_dc_clock_levels_with_voltage( + const struct pp_clock_levels_with_voltage *pp_clks, + struct dm_pp_clock_levels_with_voltage *clk_level_info, + enum dm_pp_clock_type dc_clk_type) +{ + uint32_t i; + + if (pp_clks->num_levels > DM_PP_MAX_CLOCK_LEVELS) { + DRM_INFO("DM_PPLIB: Warning: %s clock: number of levels %d exceeds maximum of %d!\n", + DC_DECODE_PP_CLOCK_TYPE(dc_clk_type), + pp_clks->num_levels, + DM_PP_MAX_CLOCK_LEVELS); + + clk_level_info->num_levels = DM_PP_MAX_CLOCK_LEVELS; + } else + clk_level_info->num_levels = pp_clks->num_levels; + + DRM_INFO("DM_PPLIB: values for %s clock\n", + DC_DECODE_PP_CLOCK_TYPE(dc_clk_type)); + + for (i = 0; i < clk_level_info->num_levels; i++) { + DRM_INFO("DM_PPLIB:\t %d\n", pp_clks->data[i].clocks_in_khz); + clk_level_info->data[i].clocks_in_khz = pp_clks->data[i].clocks_in_khz; + clk_level_info->data[i].voltage_in_mv = pp_clks->data[i].voltage_in_mv; + } +} + + bool dm_pp_get_clock_levels_by_type( const struct dc_context *ctx, enum dm_pp_clock_type clk_type, @@ -353,8 +381,19 @@ bool dm_pp_get_clock_levels_by_type_with_voltage( enum dm_pp_clock_type clk_type, struct dm_pp_clock_levels_with_voltage *clk_level_info) { - /* TODO: to be implemented */ - return false; + struct amdgpu_device *adev = ctx->driver_context; + void *pp_handle = adev->powerplay.pp_handle; + struct pp_clock_levels_with_voltage pp_clk_info = {0}; + const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + + if (pp_funcs->get_clock_by_type_with_voltage(pp_handle, + dc_to_pp_clock_type(clk_type), + &pp_clk_info)) + return false; + + pp_to_dc_clock_levels_with_voltage(&pp_clk_info, clk_level_info, clk_type); + + return true; } bool dm_pp_notify_wm_clock_changes( -- GitLab From 28825c841bfd993bbe5c9466533baca8520f08c3 Mon Sep 17 00:00:00 2001 From: Mikita Lipski <mikita.lipski@amd.com> Date: Mon, 9 Apr 2018 13:40:00 -0400 Subject: [PATCH 0708/1506] drm/amd/display: Apply clock for voltage request Translate dm_pp tructure to pp type Call PP lib to apply clock voltage request for display Signed-off-by: Mikita Lipski <mikita.lipski@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../display/amdgpu_dm/amdgpu_dm_services.c | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c index bc15ee692d377..2eef154accf9e 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c @@ -416,8 +416,35 @@ bool dm_pp_apply_clock_for_voltage_request( const struct dc_context *ctx, struct dm_pp_clock_for_voltage_req *clock_for_voltage_req) { - /* TODO: to be implemented */ - return false; + struct amdgpu_device *adev = ctx->driver_context; + struct pp_display_clock_request *pp_clock_request = {0}; + int ret = 0; + switch (clock_for_voltage_req->clk_type) { + case DM_PP_CLOCK_TYPE_DISPLAY_CLK: + pp_clock_request->clock_type = amd_pp_disp_clock; + break; + + case DM_PP_CLOCK_TYPE_DCEFCLK: + pp_clock_request->clock_type = amd_pp_dcef_clock; + break; + + case DM_PP_CLOCK_TYPE_PIXELCLK: + pp_clock_request->clock_type = amd_pp_pixel_clock; + break; + + default: + return false; + } + + pp_clock_request->clock_freq_in_khz = clock_for_voltage_req->clocks_in_khz; + + if (adev->powerplay.pp_funcs->display_clock_voltage_request) + ret = adev->powerplay.pp_funcs->display_clock_voltage_request( + adev->powerplay.pp_handle, + pp_clock_request); + if (ret) + return false; + return true; } bool dm_pp_get_static_clocks( -- GitLab From db4e525304ddf272e45542cbfd820840cf6ac874 Mon Sep 17 00:00:00 2001 From: Mikita Lipski <mikita.lipski@amd.com> Date: Wed, 18 Apr 2018 17:19:23 -0400 Subject: [PATCH 0709/1506] drm/amd/display: Adding Get static clocks for dm_pp interface Adding a call to powerplay to get system clocks and translate to dm structure Signed-off-by: Mikita Lipski <mikita.lipski@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../amd/display/amdgpu_dm/amdgpu_dm_services.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c index 2eef154accf9e..dbd714d0936e9 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c @@ -451,8 +451,22 @@ bool dm_pp_get_static_clocks( const struct dc_context *ctx, struct dm_pp_static_clock_info *static_clk_info) { - /* TODO: to be implemented */ - return false; + struct amdgpu_device *adev = ctx->driver_context; + struct amd_pp_clock_info *pp_clk_info = {0}; + int ret = 0; + + if (adev->powerplay.pp_funcs->get_current_clocks) + ret = adev->powerplay.pp_funcs->get_current_clocks( + adev->powerplay.pp_handle, + pp_clk_info); + if (ret) + return false; + + static_clk_info->max_clocks_state = pp_clk_info->max_clocks_state; + static_clk_info->max_mclk_khz = pp_clk_info->max_memory_clock; + static_clk_info->max_sclk_khz = pp_clk_info->max_engine_clock; + + return true; } void dm_pp_get_funcs_rv( -- GitLab From 30f0ea6d0901c1ff9e7a4d986959e3e4008ee8e1 Mon Sep 17 00:00:00 2001 From: Tony Cheng <tony.cheng@amd.com> Date: Tue, 8 May 2018 12:25:15 -0400 Subject: [PATCH 0710/1506] drm/amd/display: dal 3.1.48 Signed-off-by: Tony Cheng <tony.cheng@amd.com> Reviewed-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 8ba90a75d1284..82e0f55bc3e44 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.1.47" +#define DC_VER "3.1.48" #define MAX_SURFACES 3 #define MAX_STREAMS 6 -- GitLab From 92276a06f9c3d29183c7bdf46a6dbbc9c00f7acf Mon Sep 17 00:00:00 2001 From: Mikita Lipski <mikita.lipski@amd.com> Date: Wed, 11 Apr 2018 14:52:41 -0400 Subject: [PATCH 0711/1506] drm/amd/display: Introduce pp-smu raven functions DM powerplay calls for DCN10 allowing to bypass PPLib and call directly to the SMU functions. Signed-off-by: Mikita Lipski <mikita.lipski@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../display/amdgpu_dm/amdgpu_dm_services.c | 88 ++++++++++++++++++- .../gpu/drm/amd/display/dc/calcs/dcn_calcs.c | 4 +- drivers/gpu/drm/amd/display/dc/dm_pp_smu.h | 6 +- 3 files changed, 92 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c index dbd714d0936e9..e3a9bad4b4045 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c @@ -34,6 +34,11 @@ #include "amdgpu_dm.h" #include "amdgpu_dm_irq.h" #include "amdgpu_pm.h" +#include "dm_pp_smu.h" +#include "../../powerplay/inc/hwmgr.h" +#include "../../powerplay/hwmgr/smu10_hwmgr.h" + + unsigned long long dm_get_elapse_time_in_ns(struct dc_context *ctx, unsigned long long current_time_stamp, @@ -469,9 +474,90 @@ bool dm_pp_get_static_clocks( return true; } +void pp_rv_set_display_requirement(struct pp_smu *pp, + struct pp_smu_display_requirement_rv *req) +{ + struct amdgpu_device *adev = pp->ctx->driver_context; + struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; + int ret = 0; + if (hwmgr->hwmgr_func->set_deep_sleep_dcefclk) + ret = hwmgr->hwmgr_func->set_deep_sleep_dcefclk(hwmgr, req->hard_min_dcefclk_khz/10); + if (hwmgr->hwmgr_func->set_active_display_count) + ret = hwmgr->hwmgr_func->set_active_display_count(hwmgr, req->display_count); + + //store_cc6 is not yet implemented in SMU level +} + +void pp_rv_set_wm_ranges(struct pp_smu *pp, + struct pp_smu_wm_range_sets *ranges) +{ + struct amdgpu_device *adev = pp->ctx->driver_context; + struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; + struct pp_wm_sets_with_clock_ranges_soc15 ranges_soc15 = {0}; + int i = 0; + + if (!hwmgr->hwmgr_func->set_watermarks_for_clocks_ranges || + !pp || !ranges) + return; + + //not entirely sure if thats a correct assignment + ranges_soc15.num_wm_sets_dmif = ranges->num_reader_wm_sets; + ranges_soc15.num_wm_sets_mcif = ranges->num_writer_wm_sets; + + for (i = 0; i < ranges_soc15.num_wm_sets_dmif; i++) { + if (ranges->reader_wm_sets[i].wm_inst > 3) + ranges_soc15.wm_sets_dmif[i].wm_set_id = DC_WM_SET_A; + else + ranges_soc15.wm_sets_dmif[i].wm_set_id = + ranges->reader_wm_sets[i].wm_inst; + ranges_soc15.wm_sets_dmif[i].wm_max_dcefclk_in_khz = + ranges->reader_wm_sets[i].max_drain_clk_khz; + ranges_soc15.wm_sets_dmif[i].wm_min_dcefclk_in_khz = + ranges->reader_wm_sets[i].min_drain_clk_khz; + ranges_soc15.wm_sets_dmif[i].wm_max_memclk_in_khz = + ranges->reader_wm_sets[i].max_fill_clk_khz; + ranges_soc15.wm_sets_dmif[i].wm_min_memclk_in_khz = + ranges->reader_wm_sets[i].min_fill_clk_khz; + } + + for (i = 0; i < ranges_soc15.num_wm_sets_mcif; i++) { + if (ranges->writer_wm_sets[i].wm_inst > 3) + ranges_soc15.wm_sets_dmif[i].wm_set_id = DC_WM_SET_A; + else + ranges_soc15.wm_sets_mcif[i].wm_set_id = + ranges->writer_wm_sets[i].wm_inst; + ranges_soc15.wm_sets_mcif[i].wm_max_socclk_in_khz = + ranges->writer_wm_sets[i].max_fill_clk_khz; + ranges_soc15.wm_sets_mcif[i].wm_min_socclk_in_khz = + ranges->writer_wm_sets[i].min_fill_clk_khz; + ranges_soc15.wm_sets_mcif[i].wm_max_memclk_in_khz = + ranges->writer_wm_sets[i].max_fill_clk_khz; + ranges_soc15.wm_sets_mcif[i].wm_min_memclk_in_khz = + ranges->writer_wm_sets[i].min_fill_clk_khz; + } + + hwmgr->hwmgr_func->set_watermarks_for_clocks_ranges(hwmgr, &ranges_soc15); + +} + +void pp_rv_set_pme_wa_enable(struct pp_smu *pp) +{ + struct amdgpu_device *adev = pp->ctx->driver_context; + struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; + + if (hwmgr->hwmgr_func->smus_notify_pwe) + hwmgr->hwmgr_func->smus_notify_pwe(hwmgr); +} + void dm_pp_get_funcs_rv( struct dc_context *ctx, struct pp_smu_funcs_rv *funcs) -{} +{ + funcs->pp_smu.ctx = ctx; + funcs->set_display_requirement = pp_rv_set_display_requirement; + funcs->set_wm_ranges = pp_rv_set_wm_ranges; + funcs->set_pme_wa_enable = pp_rv_set_pme_wa_enable; +} + /**** end of power component interfaces ****/ diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c index 9acdd9da740e4..9ce329e8f2879 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c @@ -1358,8 +1358,8 @@ void dcn_bw_notify_pplib_of_wm_ranges(struct dc *dc) /* SOCCLK does not affect anytihng but writeback for DCN so for now we dont * care what the value is, hence min to overdrive level */ - ranges.num_reader_wm_sets = WM_COUNT; - ranges.num_writer_wm_sets = WM_COUNT; + ranges.num_reader_wm_sets = WM_SET_COUNT; + ranges.num_writer_wm_sets = WM_SET_COUNT; ranges.reader_wm_sets[0].wm_inst = WM_A; ranges.reader_wm_sets[0].min_drain_clk_khz = min_dcfclk_khz; ranges.reader_wm_sets[0].max_drain_clk_khz = max_dcfclk_khz; diff --git a/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h b/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h index eac4bfe122576..58ed2055ef9f7 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h +++ b/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h @@ -40,7 +40,7 @@ enum wm_set_id { WM_B, WM_C, WM_D, - WM_COUNT, + WM_SET_COUNT, }; struct pp_smu_wm_set_range { @@ -53,10 +53,10 @@ struct pp_smu_wm_set_range { struct pp_smu_wm_range_sets { uint32_t num_reader_wm_sets; - struct pp_smu_wm_set_range reader_wm_sets[WM_COUNT]; + struct pp_smu_wm_set_range reader_wm_sets[WM_SET_COUNT]; uint32_t num_writer_wm_sets; - struct pp_smu_wm_set_range writer_wm_sets[WM_COUNT]; + struct pp_smu_wm_set_range writer_wm_sets[WM_SET_COUNT]; }; struct pp_smu_display_requirement_rv { -- GitLab From 2dfa76d328630de3dd4fc09b296ee9771ba13e39 Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Date: Mon, 28 May 2018 18:09:52 -0400 Subject: [PATCH 0712/1506] drm/amd/display: remove invalid assert when no max_pixel_clk is found Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Reviewed-by: Harry Wentland <Harry.Wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c | 3 --- 1 file changed, 3 deletions(-) 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 34eb7a33851b2..4cdf86690d19d 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 @@ -1779,9 +1779,6 @@ static uint32_t get_max_pixel_clock_for_all_paths( pipe_ctx->stream_res.pix_clk_params.requested_pix_clk; } - if (max_pix_clk == 0) - ASSERT(0); - return max_pix_clk; } -- GitLab From 0d8be24134eddaf5acc937f59d58e62d869f0a6f Mon Sep 17 00:00:00 2001 From: Yongqiang Sun <yongqiang.sun@amd.com> Date: Tue, 29 May 2018 07:18:27 -0700 Subject: [PATCH 0713/1506] drm/amd/display: Use tg count for opp init. In case of tg count not equal to FE pipe count, if use pipe count to iterate the tgs, it will cause BSOD. Signed-off-by: Yongqiang Sun <yongqiang.sun@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 09c7007868e8d..64ca503cab429 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 @@ -1010,7 +1010,7 @@ static void dcn10_init_hw(struct dc *dc) /* Reset all MPCC muxes */ dc->res_pool->mpc->funcs->mpc_init(dc->res_pool->mpc); - for (i = 0; i < dc->res_pool->pipe_count; i++) { + for (i = 0; i < dc->res_pool->timing_generator_count; i++) { struct timing_generator *tg = dc->res_pool->timing_generators[i]; struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; struct hubp *hubp = dc->res_pool->hubps[i]; -- GitLab From 9654a28b3ac075f2454d5867d490b0c2f7cde9fd Mon Sep 17 00:00:00 2001 From: Mikita Lipski <mikita.lipski@amd.com> Date: Tue, 29 May 2018 16:15:12 -0400 Subject: [PATCH 0714/1506] drm/amd/display: Use local structs instead of struct pointers Change struct pointers to creating structs on a stack. Thats fixing a mistake in a previous patch introducing dm_pplib functions Signed-off-by: Mikita Lipski <mikita.lipski@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../display/amdgpu_dm/amdgpu_dm_services.c | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c index e3a9bad4b4045..f5d626e8bf514 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c @@ -422,31 +422,31 @@ bool dm_pp_apply_clock_for_voltage_request( struct dm_pp_clock_for_voltage_req *clock_for_voltage_req) { struct amdgpu_device *adev = ctx->driver_context; - struct pp_display_clock_request *pp_clock_request = {0}; + struct pp_display_clock_request pp_clock_request = {0}; int ret = 0; switch (clock_for_voltage_req->clk_type) { case DM_PP_CLOCK_TYPE_DISPLAY_CLK: - pp_clock_request->clock_type = amd_pp_disp_clock; + pp_clock_request.clock_type = amd_pp_disp_clock; break; case DM_PP_CLOCK_TYPE_DCEFCLK: - pp_clock_request->clock_type = amd_pp_dcef_clock; + pp_clock_request.clock_type = amd_pp_dcef_clock; break; case DM_PP_CLOCK_TYPE_PIXELCLK: - pp_clock_request->clock_type = amd_pp_pixel_clock; + pp_clock_request.clock_type = amd_pp_pixel_clock; break; default: return false; } - pp_clock_request->clock_freq_in_khz = clock_for_voltage_req->clocks_in_khz; + pp_clock_request.clock_freq_in_khz = clock_for_voltage_req->clocks_in_khz; if (adev->powerplay.pp_funcs->display_clock_voltage_request) ret = adev->powerplay.pp_funcs->display_clock_voltage_request( adev->powerplay.pp_handle, - pp_clock_request); + &pp_clock_request); if (ret) return false; return true; @@ -457,19 +457,19 @@ bool dm_pp_get_static_clocks( struct dm_pp_static_clock_info *static_clk_info) { struct amdgpu_device *adev = ctx->driver_context; - struct amd_pp_clock_info *pp_clk_info = {0}; + struct amd_pp_clock_info pp_clk_info = {0}; int ret = 0; if (adev->powerplay.pp_funcs->get_current_clocks) ret = adev->powerplay.pp_funcs->get_current_clocks( adev->powerplay.pp_handle, - pp_clk_info); + &pp_clk_info); if (ret) return false; - static_clk_info->max_clocks_state = pp_clk_info->max_clocks_state; - static_clk_info->max_mclk_khz = pp_clk_info->max_memory_clock; - static_clk_info->max_sclk_khz = pp_clk_info->max_engine_clock; + static_clk_info->max_clocks_state = pp_clk_info.max_clocks_state; + static_clk_info->max_mclk_khz = pp_clk_info.max_memory_clock; + static_clk_info->max_sclk_khz = pp_clk_info.max_engine_clock; return true; } -- GitLab From 25684c59aff5147d48cc7ce04d4d75a15c5a3a71 Mon Sep 17 00:00:00 2001 From: Mikita Lipski <mikita.lipski@amd.com> Date: Tue, 29 May 2018 16:20:37 -0400 Subject: [PATCH 0715/1506] drm/amd/display: Add clock types to applying clk for voltage Add DCF and FCLK clock case statements for changing raven's clocks for voltage request. Also maintain DCEF clock for DCE120 calls. Signed-off-by: Mikita Lipski <mikita.lipski@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c index f5d626e8bf514..0ac428299f5f2 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c @@ -433,10 +433,18 @@ bool dm_pp_apply_clock_for_voltage_request( pp_clock_request.clock_type = amd_pp_dcef_clock; break; + case DM_PP_CLOCK_TYPE_DCFCLK: + pp_clock_request.clock_type = amd_pp_dcf_clock; + break; + case DM_PP_CLOCK_TYPE_PIXELCLK: pp_clock_request.clock_type = amd_pp_pixel_clock; break; + case DM_PP_CLOCK_TYPE_FCLK: + pp_clock_request.clock_type = amd_pp_f_clock; + break; + default: return false; } -- GitLab From d578839ca014e5f4e6d540caadc0b84d50a8977f Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Date: Wed, 23 May 2018 18:02:27 -0400 Subject: [PATCH 0716/1506] drm/amd/display: get rid of cur_clks from dcn_bw_output Cleans up dcn_bw_output to only contain calculated info, actual programmed values will now be stored in respective blocks. Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Reviewed-by: Nikola Cornij <Nikola.Cornij@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/display/dc/calcs/dcn_calcs.c | 28 +++--- .../gpu/drm/amd/display/dc/core/dc_debug.c | 24 +++--- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 2 +- .../gpu/drm/amd/display/dc/dce/dce_clocks.c | 4 +- .../amd/display/dc/dcn10/dcn10_hw_sequencer.c | 85 +++++++++---------- .../gpu/drm/amd/display/dc/inc/core_types.h | 3 +- 6 files changed, 72 insertions(+), 74 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c index 9ce329e8f2879..b8195e5a06767 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c @@ -977,42 +977,42 @@ bool dcn_validate_bandwidth( display_pipe_configuration(v); calc_wm_sets_and_perf_params(context, v); - context->bw.dcn.calc_clk.fclk_khz = (int)(bw_consumed * 1000000 / + context->bw.dcn.clk.fclk_khz = (int)(bw_consumed * 1000000 / (ddr4_dram_factor_single_Channel * v->number_of_channels)); if (bw_consumed == v->fabric_and_dram_bandwidth_vmin0p65) { - context->bw.dcn.calc_clk.fclk_khz = (int)(bw_consumed * 1000000 / 32); + context->bw.dcn.clk.fclk_khz = (int)(bw_consumed * 1000000 / 32); } - context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz = (int)(v->dcf_clk_deep_sleep * 1000); - context->bw.dcn.calc_clk.dcfclk_khz = (int)(v->dcfclk * 1000); + context->bw.dcn.clk.dcfclk_deep_sleep_khz = (int)(v->dcf_clk_deep_sleep * 1000); + context->bw.dcn.clk.dcfclk_khz = (int)(v->dcfclk * 1000); - context->bw.dcn.calc_clk.dispclk_khz = (int)(v->dispclk * 1000); + context->bw.dcn.clk.dispclk_khz = (int)(v->dispclk * 1000); if (dc->debug.max_disp_clk == true) - context->bw.dcn.calc_clk.dispclk_khz = (int)(dc->dcn_soc->max_dispclk_vmax0p9 * 1000); + context->bw.dcn.clk.dispclk_khz = (int)(dc->dcn_soc->max_dispclk_vmax0p9 * 1000); - if (context->bw.dcn.calc_clk.dispclk_khz < + if (context->bw.dcn.clk.dispclk_khz < dc->debug.min_disp_clk_khz) { - context->bw.dcn.calc_clk.dispclk_khz = + context->bw.dcn.clk.dispclk_khz = dc->debug.min_disp_clk_khz; } - context->bw.dcn.calc_clk.dppclk_khz = context->bw.dcn.calc_clk.dispclk_khz / v->dispclk_dppclk_ratio; - context->bw.dcn.calc_clk.phyclk_khz = v->phyclk_per_state[v->voltage_level]; + context->bw.dcn.clk.dppclk_khz = context->bw.dcn.clk.dispclk_khz / v->dispclk_dppclk_ratio; + context->bw.dcn.clk.phyclk_khz = v->phyclk_per_state[v->voltage_level]; switch (v->voltage_level) { case 0: - context->bw.dcn.calc_clk.max_supported_dppclk_khz = + context->bw.dcn.clk.max_supported_dppclk_khz = (int)(dc->dcn_soc->max_dppclk_vmin0p65 * 1000); break; case 1: - context->bw.dcn.calc_clk.max_supported_dppclk_khz = + context->bw.dcn.clk.max_supported_dppclk_khz = (int)(dc->dcn_soc->max_dppclk_vmid0p72 * 1000); break; case 2: - context->bw.dcn.calc_clk.max_supported_dppclk_khz = + context->bw.dcn.clk.max_supported_dppclk_khz = (int)(dc->dcn_soc->max_dppclk_vnom0p8 * 1000); break; default: - context->bw.dcn.calc_clk.max_supported_dppclk_khz = + context->bw.dcn.clk.max_supported_dppclk_khz = (int)(dc->dcn_soc->max_dppclk_vmax0p9 * 1000); break; } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_debug.c b/drivers/gpu/drm/amd/display/dc/core/dc_debug.c index 267c76766deae..e1ebdf7b5eaf3 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_debug.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_debug.c @@ -352,19 +352,19 @@ void context_clock_trace( DC_LOGGER_INIT(dc->ctx->logger); CLOCK_TRACE("Current: dispclk_khz:%d max_dppclk_khz:%d dcfclk_khz:%d\n" "dcfclk_deep_sleep_khz:%d fclk_khz:%d socclk_khz:%d\n", - context->bw.dcn.calc_clk.dispclk_khz, - context->bw.dcn.calc_clk.dppclk_khz, - context->bw.dcn.calc_clk.dcfclk_khz, - context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz, - context->bw.dcn.calc_clk.fclk_khz, - context->bw.dcn.calc_clk.socclk_khz); + context->bw.dcn.clk.dispclk_khz, + context->bw.dcn.clk.dppclk_khz, + context->bw.dcn.clk.dcfclk_khz, + context->bw.dcn.clk.dcfclk_deep_sleep_khz, + context->bw.dcn.clk.fclk_khz, + context->bw.dcn.clk.socclk_khz); CLOCK_TRACE("Calculated: dispclk_khz:%d max_dppclk_khz:%d dcfclk_khz:%d\n" "dcfclk_deep_sleep_khz:%d fclk_khz:%d socclk_khz:%d\n", - context->bw.dcn.calc_clk.dispclk_khz, - context->bw.dcn.calc_clk.dppclk_khz, - context->bw.dcn.calc_clk.dcfclk_khz, - context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz, - context->bw.dcn.calc_clk.fclk_khz, - context->bw.dcn.calc_clk.socclk_khz); + context->bw.dcn.clk.dispclk_khz, + context->bw.dcn.clk.dppclk_khz, + context->bw.dcn.clk.dcfclk_khz, + context->bw.dcn.clk.dcfclk_deep_sleep_khz, + context->bw.dcn.clk.fclk_khz, + context->bw.dcn.clk.socclk_khz); #endif } 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 779d1926a756c..8eb8b87684659 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -1284,7 +1284,7 @@ static enum dc_status enable_link_dp( max_link_rate = LINK_RATE_HIGH3; if (link_settings.link_rate == max_link_rate) { - struct dc_clocks clocks = state->bw.dcn.calc_clk; + struct dc_clocks clocks = state->bw.dcn.clk; /* dce/dcn compat, do not update dispclk */ clocks.dispclk_khz = 0; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c index 93e6063c4b975..6b6570ea998dc 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c @@ -584,8 +584,8 @@ static void dcn_update_clocks(struct dccg *dccg, if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, dccg->clks.dispclk_khz)) { clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DISPLAY_CLK; clock_voltage_req.clocks_in_khz = new_clocks->dispclk_khz; - /* TODO: ramp up - dccg->funcs->set_dispclk(dccg, new_clocks->dispclk_khz);*/ - dccg->clks.dispclk_khz = new_clocks->dispclk_khz; + /* TODO: ramp up - dccg->funcs->set_dispclk(dccg, new_clocks->dispclk_khz); + dccg->clks.dispclk_khz = new_clocks->dispclk_khz;*/ dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req); send_request_to_lower = true; 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 64ca503cab429..6ab00615c4c54 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 @@ -337,13 +337,13 @@ void dcn10_log_hw_state(struct dc *dc) DTN_INFO("\nCALCULATED Clocks: dcfclk_khz:%d dcfclk_deep_sleep_khz:%d dispclk_khz:%d\n" "dppclk_khz:%d max_supported_dppclk_khz:%d fclk_khz:%d socclk_khz:%d\n\n", - dc->current_state->bw.dcn.calc_clk.dcfclk_khz, - dc->current_state->bw.dcn.calc_clk.dcfclk_deep_sleep_khz, - dc->current_state->bw.dcn.calc_clk.dispclk_khz, - dc->current_state->bw.dcn.calc_clk.dppclk_khz, - dc->current_state->bw.dcn.calc_clk.max_supported_dppclk_khz, - dc->current_state->bw.dcn.calc_clk.fclk_khz, - dc->current_state->bw.dcn.calc_clk.socclk_khz); + dc->current_state->bw.dcn.clk.dcfclk_khz, + dc->current_state->bw.dcn.clk.dcfclk_deep_sleep_khz, + dc->current_state->bw.dcn.clk.dispclk_khz, + dc->current_state->bw.dcn.clk.dppclk_khz, + dc->current_state->bw.dcn.clk.max_supported_dppclk_khz, + dc->current_state->bw.dcn.clk.fclk_khz, + dc->current_state->bw.dcn.clk.socclk_khz); log_mpc_crc(dc); @@ -1952,18 +1952,17 @@ static void update_dchubp_dpp( * divided by 2 */ if (plane_state->update_flags.bits.full_update) { - bool should_divided_by_2 = context->bw.dcn.calc_clk.dppclk_khz <= - context->bw.dcn.cur_clk.dispclk_khz / 2; + bool should_divided_by_2 = context->bw.dcn.clk.dppclk_khz <= + dc->res_pool->dccg->clks.dispclk_khz / 2; dpp->funcs->dpp_dppclk_control( dpp, should_divided_by_2, true); - dc->current_state->bw.dcn.cur_clk.dppclk_khz = - should_divided_by_2 ? - context->bw.dcn.cur_clk.dispclk_khz / 2 : - context->bw.dcn.cur_clk.dispclk_khz; + dc->res_pool->dccg->clks.dppclk_khz = should_divided_by_2 ? + dc->res_pool->dccg->clks.dispclk_khz / 2 : + dc->res_pool->dccg->clks.dispclk_khz; } /* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG @@ -2158,7 +2157,7 @@ static void dcn10_pplib_apply_display_requirements( pp_display_cfg->min_engine_clock_deep_sleep_khz = dc->res_pool->dccg->clks.dcfclk_deep_sleep_khz; pp_display_cfg->min_dcfc_deep_sleep_clock_khz = dc->res_pool->dccg->clks.dcfclk_deep_sleep_khz; pp_display_cfg->min_dcfclock_khz = dc->res_pool->dccg->clks.dcfclk_khz; - pp_display_cfg->disp_clk_khz = context->bw.dcn.cur_clk.dispclk_khz; + pp_display_cfg->disp_clk_khz = dc->res_pool->dccg->clks.dispclk_khz; dce110_fill_display_configs(context, pp_display_cfg); if (memcmp(&dc->prev_display_config, pp_display_cfg, sizeof( @@ -2363,29 +2362,29 @@ static void dcn10_apply_ctx_for_surface( static int determine_dppclk_threshold(struct dc *dc, struct dc_state *context) { - bool request_dpp_div = context->bw.dcn.calc_clk.dispclk_khz > - context->bw.dcn.calc_clk.dppclk_khz; - bool dispclk_increase = context->bw.dcn.calc_clk.dispclk_khz > - context->bw.dcn.cur_clk.dispclk_khz; - int disp_clk_threshold = context->bw.dcn.calc_clk.max_supported_dppclk_khz; - bool cur_dpp_div = context->bw.dcn.cur_clk.dispclk_khz > - context->bw.dcn.cur_clk.dppclk_khz; + bool request_dpp_div = context->bw.dcn.clk.dispclk_khz > + context->bw.dcn.clk.dppclk_khz; + bool dispclk_increase = context->bw.dcn.clk.dispclk_khz > + dc->res_pool->dccg->clks.dispclk_khz; + int disp_clk_threshold = context->bw.dcn.clk.max_supported_dppclk_khz; + bool cur_dpp_div = dc->res_pool->dccg->clks.dispclk_khz > + dc->res_pool->dccg->clks.dppclk_khz; /* increase clock, looking for div is 0 for current, request div is 1*/ if (dispclk_increase) { /* already divided by 2, no need to reach target clk with 2 steps*/ if (cur_dpp_div) - return context->bw.dcn.calc_clk.dispclk_khz; + return context->bw.dcn.clk.dispclk_khz; /* request disp clk is lower than maximum supported dpp clk, * no need to reach target clk with two steps. */ - if (context->bw.dcn.calc_clk.dispclk_khz <= disp_clk_threshold) - return context->bw.dcn.calc_clk.dispclk_khz; + if (context->bw.dcn.clk.dispclk_khz <= disp_clk_threshold) + return context->bw.dcn.clk.dispclk_khz; /* target dpp clk not request divided by 2, still within threshold */ if (!request_dpp_div) - return context->bw.dcn.calc_clk.dispclk_khz; + return context->bw.dcn.clk.dispclk_khz; } else { /* decrease clock, looking for current dppclk divided by 2, @@ -2394,17 +2393,17 @@ static int determine_dppclk_threshold(struct dc *dc, struct dc_state *context) /* current dpp clk not divided by 2, no need to ramp*/ if (!cur_dpp_div) - return context->bw.dcn.calc_clk.dispclk_khz; + return context->bw.dcn.clk.dispclk_khz; /* current disp clk is lower than current maximum dpp clk, * no need to ramp */ - if (context->bw.dcn.cur_clk.dispclk_khz <= disp_clk_threshold) - return context->bw.dcn.calc_clk.dispclk_khz; + if (dc->res_pool->dccg->clks.dispclk_khz <= disp_clk_threshold) + return context->bw.dcn.clk.dispclk_khz; /* request dpp clk need to be divided by 2 */ if (request_dpp_div) - return context->bw.dcn.calc_clk.dispclk_khz; + return context->bw.dcn.clk.dispclk_khz; } return disp_clk_threshold; @@ -2413,8 +2412,8 @@ static int determine_dppclk_threshold(struct dc *dc, struct dc_state *context) static void ramp_up_dispclk_with_dpp(struct dc *dc, struct dc_state *context) { int i; - bool request_dpp_div = context->bw.dcn.calc_clk.dispclk_khz > - context->bw.dcn.calc_clk.dppclk_khz; + bool request_dpp_div = context->bw.dcn.clk.dispclk_khz > + context->bw.dcn.clk.dppclk_khz; int dispclk_to_dpp_threshold = determine_dppclk_threshold(dc, context); @@ -2437,18 +2436,18 @@ static void ramp_up_dispclk_with_dpp(struct dc *dc, struct dc_state *context) } /* If target clk not same as dppclk threshold, set to target clock */ - if (dispclk_to_dpp_threshold != context->bw.dcn.calc_clk.dispclk_khz) { + if (dispclk_to_dpp_threshold != context->bw.dcn.clk.dispclk_khz) { dc->res_pool->dccg->funcs->set_dispclk( dc->res_pool->dccg, - context->bw.dcn.calc_clk.dispclk_khz); + context->bw.dcn.clk.dispclk_khz); } - context->bw.dcn.cur_clk.dispclk_khz = - context->bw.dcn.calc_clk.dispclk_khz; - context->bw.dcn.cur_clk.dppclk_khz = - context->bw.dcn.calc_clk.dppclk_khz; - context->bw.dcn.cur_clk.max_supported_dppclk_khz = - context->bw.dcn.calc_clk.max_supported_dppclk_khz; + dc->res_pool->dccg->clks.dispclk_khz = + context->bw.dcn.clk.dispclk_khz; + dc->res_pool->dccg->clks.dppclk_khz = + context->bw.dcn.clk.dppclk_khz; + dc->res_pool->dccg->clks.max_supported_dppclk_khz = + context->bw.dcn.clk.max_supported_dppclk_khz; } static inline bool should_set_clock(bool safe_to_lower, int calc_clk, int cur_clk) @@ -2469,11 +2468,11 @@ static void dcn10_set_bandwidth( return; if (context->stream_count == 0) - context->bw.dcn.calc_clk.phyclk_khz = 0; + context->bw.dcn.clk.phyclk_khz = 0; dc->res_pool->dccg->funcs->update_clocks( dc->res_pool->dccg, - &context->bw.dcn.calc_clk, + &context->bw.dcn.clk, decrease_allowed); /* make sure dcf clk is before dpp clk to @@ -2481,8 +2480,8 @@ static void dcn10_set_bandwidth( */ if (should_set_clock( decrease_allowed, - context->bw.dcn.calc_clk.dispclk_khz, - dc->current_state->bw.dcn.cur_clk.dispclk_khz)) { + context->bw.dcn.clk.dispclk_khz, + dc->res_pool->dccg->clks.dispclk_khz)) { ramp_up_dispclk_with_dpp(dc, context); } diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h index 44c48f3d0a1de..00d728e629fa6 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h @@ -256,8 +256,7 @@ struct dce_bw_output { }; struct dcn_bw_output { - struct dc_clocks cur_clk; - struct dc_clocks calc_clk; + struct dc_clocks clk; struct dcn_watermark_set watermarks; }; -- GitLab From 12c3130dd6f391437a60c765912a30b4cbb77247 Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Date: Wed, 23 May 2018 18:18:50 -0400 Subject: [PATCH 0717/1506] drm/amd/display: move dcn1 dispclk programming to dccg No functional change. Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Reviewed-by: Nikola Cornij <Nikola.Cornij@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/display/dc/dce/dce_clocks.c | 95 ++++++++++++++-- .../gpu/drm/amd/display/dc/dce/dce_clocks.h | 2 +- .../amd/display/dc/dcn10/dcn10_hw_sequencer.c | 106 ------------------ .../drm/amd/display/dc/dcn10/dcn10_resource.c | 2 +- 4 files changed, 90 insertions(+), 115 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c index 6b6570ea998dc..55f533cf55ba6 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c @@ -552,7 +552,85 @@ static void dce12_update_clocks(struct dccg *dccg, } } -static void dcn_update_clocks(struct dccg *dccg, +static int dcn1_determine_dppclk_threshold(struct dccg *dccg, struct dc_clocks *new_clocks) +{ + bool request_dpp_div = new_clocks->dispclk_khz > new_clocks->dppclk_khz; + bool dispclk_increase = new_clocks->dispclk_khz > dccg->clks.dispclk_khz; + int disp_clk_threshold = new_clocks->max_supported_dppclk_khz; + bool cur_dpp_div = dccg->clks.dispclk_khz > dccg->clks.dppclk_khz; + + /* increase clock, looking for div is 0 for current, request div is 1*/ + if (dispclk_increase) { + /* already divided by 2, no need to reach target clk with 2 steps*/ + if (cur_dpp_div) + return new_clocks->dispclk_khz; + + /* request disp clk is lower than maximum supported dpp clk, + * no need to reach target clk with two steps. + */ + if (new_clocks->dispclk_khz <= disp_clk_threshold) + return new_clocks->dispclk_khz; + + /* target dpp clk not request divided by 2, still within threshold */ + if (!request_dpp_div) + return new_clocks->dispclk_khz; + + } else { + /* decrease clock, looking for current dppclk divided by 2, + * request dppclk not divided by 2. + */ + + /* current dpp clk not divided by 2, no need to ramp*/ + if (!cur_dpp_div) + return new_clocks->dispclk_khz; + + /* current disp clk is lower than current maximum dpp clk, + * no need to ramp + */ + if (dccg->clks.dispclk_khz <= disp_clk_threshold) + return new_clocks->dispclk_khz; + + /* request dpp clk need to be divided by 2 */ + if (request_dpp_div) + return new_clocks->dispclk_khz; + } + + return disp_clk_threshold; +} + +static void dcn1_ramp_up_dispclk_with_dpp(struct dccg *dccg, struct dc_clocks *new_clocks) +{ + struct dc *dc = dccg->ctx->dc; + int dispclk_to_dpp_threshold = dcn1_determine_dppclk_threshold(dccg, new_clocks); + bool request_dpp_div = new_clocks->dispclk_khz > new_clocks->dppclk_khz; + int i; + + /* set disp clk to dpp clk threshold */ + dccg->funcs->set_dispclk(dccg, dispclk_to_dpp_threshold); + + /* update request dpp clk division option */ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; + + if (!pipe_ctx->plane_state) + continue; + + pipe_ctx->plane_res.dpp->funcs->dpp_dppclk_control( + pipe_ctx->plane_res.dpp, + request_dpp_div, + true); + } + + /* If target clk not same as dppclk threshold, set to target clock */ + if (dispclk_to_dpp_threshold != new_clocks->dispclk_khz) + dccg->funcs->set_dispclk(dccg, new_clocks->dispclk_khz); + + dccg->clks.dispclk_khz = new_clocks->dispclk_khz; + dccg->clks.dppclk_khz = new_clocks->dppclk_khz; + dccg->clks.max_supported_dppclk_khz = new_clocks->max_supported_dppclk_khz; +} + +static void dcn1_update_clocks(struct dccg *dccg, struct dc_clocks *new_clocks, bool safe_to_lower) { @@ -572,6 +650,9 @@ static void dcn_update_clocks(struct dccg *dccg, send_request_to_increase = true; #ifdef CONFIG_DRM_AMD_DC_DCN1_0 + /* make sure dcf clk is before dpp clk to + * make sure we have enough voltage to run dpp clk + */ if (send_request_to_increase ) { /*use dcfclk to request voltage*/ @@ -584,8 +665,8 @@ static void dcn_update_clocks(struct dccg *dccg, if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, dccg->clks.dispclk_khz)) { clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DISPLAY_CLK; clock_voltage_req.clocks_in_khz = new_clocks->dispclk_khz; - /* TODO: ramp up - dccg->funcs->set_dispclk(dccg, new_clocks->dispclk_khz); - dccg->clks.dispclk_khz = new_clocks->dispclk_khz;*/ + dcn1_ramp_up_dispclk_with_dpp(dccg, new_clocks); + dccg->clks.dispclk_khz = new_clocks->dispclk_khz; dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req); send_request_to_lower = true; @@ -666,10 +747,10 @@ static void dce_update_clocks(struct dccg *dccg, } } -static const struct display_clock_funcs dcn_funcs = { +static const struct display_clock_funcs dcn1_funcs = { .get_dp_ref_clk_frequency = dce_clocks_get_dp_ref_freq_wrkaround, .set_dispclk = dce112_set_clock, - .update_clocks = dcn_update_clocks + .update_clocks = dcn1_update_clocks }; static const struct display_clock_funcs dce120_funcs = { @@ -838,7 +919,7 @@ struct dccg *dce120_dccg_create(struct dc_context *ctx) return &clk_dce->base; } -struct dccg *dcn_dccg_create(struct dc_context *ctx) +struct dccg *dcn1_dccg_create(struct dc_context *ctx) { struct dce_dccg *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL); @@ -851,7 +932,7 @@ struct dccg *dcn_dccg_create(struct dc_context *ctx) dce_dccg_construct( clk_dce, ctx, NULL, NULL, NULL); - clk_dce->base.funcs = &dcn_funcs; + clk_dce->base.funcs = &dcn1_funcs; return &clk_dce->base; } diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h index c695b9c9bcb55..7907c3c4b1c13 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h @@ -128,7 +128,7 @@ struct dccg *dce112_dccg_create( struct dccg *dce120_dccg_create(struct dc_context *ctx); -struct dccg *dcn_dccg_create(struct dc_context *ctx); +struct dccg *dcn1_dccg_create(struct dc_context *ctx); void dce_dccg_destroy(struct dccg **dccg); 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 6ab00615c4c54..60e99477930b1 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 @@ -2360,101 +2360,6 @@ static void dcn10_apply_ctx_for_surface( */ } -static int determine_dppclk_threshold(struct dc *dc, struct dc_state *context) -{ - bool request_dpp_div = context->bw.dcn.clk.dispclk_khz > - context->bw.dcn.clk.dppclk_khz; - bool dispclk_increase = context->bw.dcn.clk.dispclk_khz > - dc->res_pool->dccg->clks.dispclk_khz; - int disp_clk_threshold = context->bw.dcn.clk.max_supported_dppclk_khz; - bool cur_dpp_div = dc->res_pool->dccg->clks.dispclk_khz > - dc->res_pool->dccg->clks.dppclk_khz; - - /* increase clock, looking for div is 0 for current, request div is 1*/ - if (dispclk_increase) { - /* already divided by 2, no need to reach target clk with 2 steps*/ - if (cur_dpp_div) - return context->bw.dcn.clk.dispclk_khz; - - /* request disp clk is lower than maximum supported dpp clk, - * no need to reach target clk with two steps. - */ - if (context->bw.dcn.clk.dispclk_khz <= disp_clk_threshold) - return context->bw.dcn.clk.dispclk_khz; - - /* target dpp clk not request divided by 2, still within threshold */ - if (!request_dpp_div) - return context->bw.dcn.clk.dispclk_khz; - - } else { - /* decrease clock, looking for current dppclk divided by 2, - * request dppclk not divided by 2. - */ - - /* current dpp clk not divided by 2, no need to ramp*/ - if (!cur_dpp_div) - return context->bw.dcn.clk.dispclk_khz; - - /* current disp clk is lower than current maximum dpp clk, - * no need to ramp - */ - if (dc->res_pool->dccg->clks.dispclk_khz <= disp_clk_threshold) - return context->bw.dcn.clk.dispclk_khz; - - /* request dpp clk need to be divided by 2 */ - if (request_dpp_div) - return context->bw.dcn.clk.dispclk_khz; - } - - return disp_clk_threshold; -} - -static void ramp_up_dispclk_with_dpp(struct dc *dc, struct dc_state *context) -{ - int i; - bool request_dpp_div = context->bw.dcn.clk.dispclk_khz > - context->bw.dcn.clk.dppclk_khz; - - int dispclk_to_dpp_threshold = determine_dppclk_threshold(dc, context); - - /* set disp clk to dpp clk threshold */ - dc->res_pool->dccg->funcs->set_dispclk( - dc->res_pool->dccg, - dispclk_to_dpp_threshold); - - /* update request dpp clk division option */ - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; - - if (!pipe_ctx->plane_state) - continue; - - pipe_ctx->plane_res.dpp->funcs->dpp_dppclk_control( - pipe_ctx->plane_res.dpp, - request_dpp_div, - true); - } - - /* If target clk not same as dppclk threshold, set to target clock */ - if (dispclk_to_dpp_threshold != context->bw.dcn.clk.dispclk_khz) { - dc->res_pool->dccg->funcs->set_dispclk( - dc->res_pool->dccg, - context->bw.dcn.clk.dispclk_khz); - } - - dc->res_pool->dccg->clks.dispclk_khz = - context->bw.dcn.clk.dispclk_khz; - dc->res_pool->dccg->clks.dppclk_khz = - context->bw.dcn.clk.dppclk_khz; - dc->res_pool->dccg->clks.max_supported_dppclk_khz = - context->bw.dcn.clk.max_supported_dppclk_khz; -} - -static inline bool should_set_clock(bool safe_to_lower, int calc_clk, int cur_clk) -{ - return ((safe_to_lower && calc_clk < cur_clk) || calc_clk > cur_clk); -} - static void dcn10_set_bandwidth( struct dc *dc, struct dc_state *context, @@ -2475,17 +2380,6 @@ static void dcn10_set_bandwidth( &context->bw.dcn.clk, decrease_allowed); - /* make sure dcf clk is before dpp clk to - * make sure we have enough voltage to run dpp clk - */ - if (should_set_clock( - decrease_allowed, - context->bw.dcn.clk.dispclk_khz, - dc->res_pool->dccg->clks.dispclk_khz)) { - - ramp_up_dispclk_with_dpp(dc, context); - } - dcn10_pplib_apply_display_requirements(dc, context); if (dc->debug.sanity_checks) { diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c index 8f1ceffa809b7..b5a727f7e8800 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c @@ -1072,7 +1072,7 @@ static bool construct( } } - pool->base.dccg = dcn_dccg_create(ctx); + pool->base.dccg = dcn1_dccg_create(ctx); if (pool->base.dccg == NULL) { dm_error("DC: failed to create display clock!\n"); BREAK_TO_DEBUGGER(); -- GitLab From 472800a0a0c84e224a7d4d5a4cfcd8dd6a4dd2b1 Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Date: Thu, 24 May 2018 15:50:18 -0400 Subject: [PATCH 0718/1506] drm/amd/display: clean up dccg divider calc and dcn constructor No functional change. Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/display/dc/dce/dce_clocks.c | 197 ++++++------------ .../gpu/drm/amd/display/dc/dce/dce_clocks.h | 26 --- 2 files changed, 68 insertions(+), 155 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c index 55f533cf55ba6..6e3bfdf8a9e74 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c @@ -101,90 +101,42 @@ static const struct state_dependent_clocks dce120_max_clks_by_state[] = { /*ClocksStatePerformance*/ { .display_clk_khz = 1133000, .pixel_clk_khz = 600000 } }; -/* Starting point for each divider range.*/ -enum dce_divider_range_start { - DIVIDER_RANGE_01_START = 200, /* 2.00*/ - DIVIDER_RANGE_02_START = 1600, /* 16.00*/ - DIVIDER_RANGE_03_START = 3200, /* 32.00*/ - DIVIDER_RANGE_SCALE_FACTOR = 100 /* Results are scaled up by 100.*/ +/* Starting DID for each range */ +enum dentist_base_divider_id { + dentist_base_divider_id_1 = 0x08, + dentist_base_divider_id_2 = 0x40, + dentist_base_divider_id_3 = 0x60, + dentist_max_divider_id = 0x80 }; -/* Ranges for divider identifiers (Divider ID or DID) - mmDENTIST_DISPCLK_CNTL.DENTIST_DISPCLK_WDIVIDER*/ -enum dce_divider_id_register_setting { - DIVIDER_RANGE_01_BASE_DIVIDER_ID = 0X08, - DIVIDER_RANGE_02_BASE_DIVIDER_ID = 0X40, - DIVIDER_RANGE_03_BASE_DIVIDER_ID = 0X60, - DIVIDER_RANGE_MAX_DIVIDER_ID = 0X80 +/* Starting point and step size for each divider range.*/ +enum dentist_divider_range { + dentist_divider_range_1_start = 8, /* 2.00 */ + dentist_divider_range_1_step = 1, /* 0.25 */ + dentist_divider_range_2_start = 64, /* 16.00 */ + dentist_divider_range_2_step = 2, /* 0.50 */ + dentist_divider_range_3_start = 128, /* 32.00 */ + dentist_divider_range_3_step = 4, /* 1.00 */ + dentist_divider_range_scale_factor = 4 }; -/* Step size between each divider within a range. - Incrementing the DENTIST_DISPCLK_WDIVIDER by one - will increment the divider by this much.*/ -enum dce_divider_range_step_size { - DIVIDER_RANGE_01_STEP_SIZE = 25, /* 0.25*/ - DIVIDER_RANGE_02_STEP_SIZE = 50, /* 0.50*/ - DIVIDER_RANGE_03_STEP_SIZE = 100 /* 1.00 */ -}; - -static bool dce_divider_range_construct( - struct dce_divider_range *div_range, - int range_start, - int range_step, - int did_min, - int did_max) -{ - div_range->div_range_start = range_start; - div_range->div_range_step = range_step; - div_range->did_min = did_min; - div_range->did_max = did_max; - - if (div_range->div_range_step == 0) { - div_range->div_range_step = 1; - /*div_range_step cannot be zero*/ - BREAK_TO_DEBUGGER(); - } - /* Calculate this based on the other inputs.*/ - /* See DividerRange.h for explanation of */ - /* the relationship between divider id (DID) and a divider.*/ - /* Number of Divider IDs = (Maximum Divider ID - Minimum Divider ID)*/ - /* Maximum divider identified in this range = - * (Number of Divider IDs)*Step size between dividers - * + The start of this range.*/ - div_range->div_range_end = (did_max - did_min) * range_step - + range_start; - return true; -} - -static int dce_divider_range_calc_divider( - struct dce_divider_range *div_range, - int did) -{ - /* Is this DID within our range?*/ - if ((did < div_range->did_min) || (did >= div_range->did_max)) - return INVALID_DIVIDER; - - return ((did - div_range->did_min) * div_range->div_range_step) - + div_range->div_range_start; - -} - -static int dce_divider_range_get_divider( - struct dce_divider_range *div_range, - int ranges_num, - int did) +static int dentist_get_divider_from_did(int did) { - int div = INVALID_DIVIDER; - int i; - - for (i = 0; i < ranges_num; i++) { - /* Calculate divider with given divider ID*/ - div = dce_divider_range_calc_divider(&div_range[i], did); - /* Found a valid return divider*/ - if (div != INVALID_DIVIDER) - break; + if (did < dentist_base_divider_id_1) + did = dentist_base_divider_id_1; + if (did > dentist_max_divider_id) + did = dentist_max_divider_id; + + if (did < dentist_base_divider_id_2) { + return dentist_divider_range_1_start + dentist_divider_range_1_step + * (did - dentist_base_divider_id_1); + } else if (did < dentist_base_divider_id_3) { + return dentist_divider_range_2_start + dentist_divider_range_2_step + * (did - dentist_base_divider_id_2); + } else { + return dentist_divider_range_3_start + dentist_divider_range_3_step + * (did - dentist_base_divider_id_3); } - return div; } static int dce_clocks_get_dp_ref_freq(struct dccg *clk) @@ -193,7 +145,7 @@ static int dce_clocks_get_dp_ref_freq(struct dccg *clk) int dprefclk_wdivider; int dprefclk_src_sel; int dp_ref_clk_khz = 600000; - int target_div = INVALID_DIVIDER; + int target_div; /* ASSERT DP Reference Clock source is from DFS*/ REG_GET(DPREFCLK_CNTL, DPREFCLK_SRC_SEL, &dprefclk_src_sel); @@ -204,16 +156,11 @@ static int dce_clocks_get_dp_ref_freq(struct dccg *clk) REG_GET(DENTIST_DISPCLK_CNTL, DENTIST_DPREFCLK_WDIVIDER, &dprefclk_wdivider); /* Convert DENTIST_DPREFCLK_WDIVIDERto actual divider*/ - target_div = dce_divider_range_get_divider( - clk_dce->divider_ranges, - DIVIDER_RANGE_MAX, - dprefclk_wdivider); - - if (target_div != INVALID_DIVIDER) { - /* Calculate the current DFS clock, in kHz.*/ - dp_ref_clk_khz = (DIVIDER_RANGE_SCALE_FACTOR - * clk_dce->dentist_vco_freq_khz) / target_div; - } + target_div = dentist_get_divider_from_did(dprefclk_wdivider); + + /* Calculate the current DFS clock, in kHz.*/ + dp_ref_clk_khz = (dentist_divider_range_scale_factor + * clk_dce->dentist_vco_freq_khz) / target_div; /* SW will adjust DP REF Clock average value for all purposes * (DP DTO / DP Audio DTO and DP GTC) @@ -229,17 +176,12 @@ static int dce_clocks_get_dp_ref_freq(struct dccg *clk) */ if (clk_dce->ss_on_dprefclk && clk_dce->dprefclk_ss_divider != 0) { struct fixed31_32 ss_percentage = dc_fixpt_div_int( - dc_fixpt_from_fraction( - clk_dce->dprefclk_ss_percentage, - clk_dce->dprefclk_ss_divider), 200); + dc_fixpt_from_fraction(clk_dce->dprefclk_ss_percentage, + clk_dce->dprefclk_ss_divider), 200); struct fixed31_32 adj_dp_ref_clk_khz; - ss_percentage = dc_fixpt_sub(dc_fixpt_one, - ss_percentage); - adj_dp_ref_clk_khz = - dc_fixpt_mul_int( - ss_percentage, - dp_ref_clk_khz); + ss_percentage = dc_fixpt_sub(dc_fixpt_one, ss_percentage); + adj_dp_ref_clk_khz = dc_fixpt_mul_int(ss_percentage, dp_ref_clk_khz); dp_ref_clk_khz = dc_fixpt_floor(adj_dp_ref_clk_khz); } @@ -257,17 +199,12 @@ static int dce_clocks_get_dp_ref_freq_wrkaround(struct dccg *clk) if (clk_dce->ss_on_dprefclk && clk_dce->dprefclk_ss_divider != 0) { struct fixed31_32 ss_percentage = dc_fixpt_div_int( - dc_fixpt_from_fraction( - clk_dce->dprefclk_ss_percentage, + dc_fixpt_from_fraction(clk_dce->dprefclk_ss_percentage, clk_dce->dprefclk_ss_divider), 200); struct fixed31_32 adj_dp_ref_clk_khz; - ss_percentage = dc_fixpt_sub(dc_fixpt_one, - ss_percentage); - adj_dp_ref_clk_khz = - dc_fixpt_mul_int( - ss_percentage, - dp_ref_clk_khz); + ss_percentage = dc_fixpt_sub(dc_fixpt_one, ss_percentage); + adj_dp_ref_clk_khz = dc_fixpt_mul_int(ss_percentage, dp_ref_clk_khz); dp_ref_clk_khz = dc_fixpt_floor(adj_dp_ref_clk_khz); } @@ -804,25 +741,6 @@ static void dce_dccg_construct( dce_clock_read_integrated_info(clk_dce); dce_clock_read_ss_info(clk_dce); - - dce_divider_range_construct( - &clk_dce->divider_ranges[DIVIDER_RANGE_01], - DIVIDER_RANGE_01_START, - DIVIDER_RANGE_01_STEP_SIZE, - DIVIDER_RANGE_01_BASE_DIVIDER_ID, - DIVIDER_RANGE_02_BASE_DIVIDER_ID); - dce_divider_range_construct( - &clk_dce->divider_ranges[DIVIDER_RANGE_02], - DIVIDER_RANGE_02_START, - DIVIDER_RANGE_02_STEP_SIZE, - DIVIDER_RANGE_02_BASE_DIVIDER_ID, - DIVIDER_RANGE_03_BASE_DIVIDER_ID); - dce_divider_range_construct( - &clk_dce->divider_ranges[DIVIDER_RANGE_03], - DIVIDER_RANGE_03_START, - DIVIDER_RANGE_03_STEP_SIZE, - DIVIDER_RANGE_03_BASE_DIVIDER_ID, - DIVIDER_RANGE_MAX_DIVIDER_ID); } struct dccg *dce_dccg_create( @@ -921,6 +839,9 @@ struct dccg *dce120_dccg_create(struct dc_context *ctx) struct dccg *dcn1_dccg_create(struct dc_context *ctx) { + struct dc_debug *debug = &ctx->dc->debug; + struct dc_bios *bp = ctx->dc_bios; + struct dc_firmware_info fw_info = { { 0 } }; struct dce_dccg *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL); if (clk_dce == NULL) { @@ -928,12 +849,30 @@ struct dccg *dcn1_dccg_create(struct dc_context *ctx) return NULL; } - /* TODO strip out useful stuff out of dce constructor */ - dce_dccg_construct( - clk_dce, ctx, NULL, NULL, NULL); - + clk_dce->base.ctx = ctx; clk_dce->base.funcs = &dcn1_funcs; + clk_dce->dfs_bypass_disp_clk = 0; + + clk_dce->dprefclk_ss_percentage = 0; + clk_dce->dprefclk_ss_divider = 1000; + clk_dce->ss_on_dprefclk = false; + + if (bp->integrated_info) + clk_dce->dentist_vco_freq_khz = bp->integrated_info->dentist_vco_freq; + if (clk_dce->dentist_vco_freq_khz == 0) { + bp->funcs->get_firmware_info(bp, &fw_info); + clk_dce->dentist_vco_freq_khz = fw_info.smu_gpu_pll_output_freq; + if (clk_dce->dentist_vco_freq_khz == 0) + clk_dce->dentist_vco_freq_khz = 3600000; + } + + if (!debug->disable_dfs_bypass && bp->integrated_info) + if (bp->integrated_info->gpu_cap_info & DFS_BYPASS_ENABLE) + clk_dce->dfs_bypass_enabled = true; + + dce_clock_read_ss_info(clk_dce); + return &clk_dce->base; } diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h index 7907c3c4b1c13..04a9e3c04aa77 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h @@ -57,31 +57,6 @@ struct dce_disp_clk_registers { uint32_t DENTIST_DISPCLK_CNTL; }; -/* Array identifiers and count for the divider ranges.*/ -enum dce_divider_range_count { - DIVIDER_RANGE_01 = 0, - DIVIDER_RANGE_02, - DIVIDER_RANGE_03, - DIVIDER_RANGE_MAX /* == 3*/ -}; - -enum dce_divider_error_types { - INVALID_DID = 0, - INVALID_DIVIDER = 1 -}; - -struct dce_divider_range { - int div_range_start; - /* The end of this range of dividers.*/ - int div_range_end; - /* The distance between each divider in this range.*/ - int div_range_step; - /* The divider id for the lowest divider.*/ - int did_min; - /* The divider id for the highest divider.*/ - int did_max; -}; - struct dce_dccg { struct dccg base; const struct dce_disp_clk_registers *regs; @@ -89,7 +64,6 @@ struct dce_dccg { const struct dce_disp_clk_mask *clk_mask; struct state_dependent_clocks max_clks_by_state[DM_PP_CLOCKS_MAX_STATES]; - struct dce_divider_range divider_ranges[DIVIDER_RANGE_MAX]; int dentist_vco_freq_khz; -- GitLab From 3cdecd4513d57993aaddc03ccdf4539add772aa4 Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Date: Thu, 24 May 2018 16:48:38 -0400 Subject: [PATCH 0719/1506] drm/amd/display: rename dce_disp_clk to dccg No functional change. Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Reviewed-by: Nikola Cornij <Nikola.Cornij@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/display/dc/dce/dce_clocks.c | 115 ++++++++---------- .../gpu/drm/amd/display/dc/dce/dce_clocks.h | 41 ++++--- .../gpu/drm/amd/display/dc/dce/dce_hwseq.h | 3 - .../amd/display/dc/dce100/dce100_resource.c | 6 +- .../amd/display/dc/dce110/dce110_resource.c | 6 +- .../amd/display/dc/dce112/dce112_resource.c | 6 +- .../drm/amd/display/dc/dce80/dce80_resource.c | 6 +- 7 files changed, 88 insertions(+), 95 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c index 6e3bfdf8a9e74..242e8ae560256 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c @@ -139,7 +139,34 @@ static int dentist_get_divider_from_did(int did) } } -static int dce_clocks_get_dp_ref_freq(struct dccg *clk) +/* SW will adjust DP REF Clock average value for all purposes + * (DP DTO / DP Audio DTO and DP GTC) + if clock is spread for all cases: + -if SS enabled on DP Ref clock and HW de-spreading enabled with SW + calculations for DS_INCR/DS_MODULO (this is planned to be default case) + -if SS enabled on DP Ref clock and HW de-spreading enabled with HW + calculations (not planned to be used, but average clock should still + be valid) + -if SS enabled on DP Ref clock and HW de-spreading disabled + (should not be case with CIK) then SW should program all rates + generated according to average value (case as with previous ASICs) + */ +static int dccg_adjust_dp_ref_freq_for_ss(struct dce_dccg *clk_dce, int dp_ref_clk_khz) +{ + if (clk_dce->ss_on_dprefclk && clk_dce->dprefclk_ss_divider != 0) { + struct fixed31_32 ss_percentage = dc_fixpt_div_int( + dc_fixpt_from_fraction(clk_dce->dprefclk_ss_percentage, + clk_dce->dprefclk_ss_divider), 200); + struct fixed31_32 adj_dp_ref_clk_khz; + + ss_percentage = dc_fixpt_sub(dc_fixpt_one, ss_percentage); + adj_dp_ref_clk_khz = dc_fixpt_mul_int(ss_percentage, dp_ref_clk_khz); + dp_ref_clk_khz = dc_fixpt_floor(adj_dp_ref_clk_khz); + } + return dp_ref_clk_khz; +} + +static int dce_get_dp_ref_freq_khz(struct dccg *clk) { struct dce_dccg *clk_dce = TO_DCE_CLOCKS(clk); int dprefclk_wdivider; @@ -162,54 +189,16 @@ static int dce_clocks_get_dp_ref_freq(struct dccg *clk) dp_ref_clk_khz = (dentist_divider_range_scale_factor * clk_dce->dentist_vco_freq_khz) / target_div; - /* SW will adjust DP REF Clock average value for all purposes - * (DP DTO / DP Audio DTO and DP GTC) - if clock is spread for all cases: - -if SS enabled on DP Ref clock and HW de-spreading enabled with SW - calculations for DS_INCR/DS_MODULO (this is planned to be default case) - -if SS enabled on DP Ref clock and HW de-spreading enabled with HW - calculations (not planned to be used, but average clock should still - be valid) - -if SS enabled on DP Ref clock and HW de-spreading disabled - (should not be case with CIK) then SW should program all rates - generated according to average value (case as with previous ASICs) - */ - if (clk_dce->ss_on_dprefclk && clk_dce->dprefclk_ss_divider != 0) { - struct fixed31_32 ss_percentage = dc_fixpt_div_int( - dc_fixpt_from_fraction(clk_dce->dprefclk_ss_percentage, - clk_dce->dprefclk_ss_divider), 200); - struct fixed31_32 adj_dp_ref_clk_khz; - - ss_percentage = dc_fixpt_sub(dc_fixpt_one, ss_percentage); - adj_dp_ref_clk_khz = dc_fixpt_mul_int(ss_percentage, dp_ref_clk_khz); - dp_ref_clk_khz = dc_fixpt_floor(adj_dp_ref_clk_khz); - } - - return dp_ref_clk_khz; + return dccg_adjust_dp_ref_freq_for_ss(clk_dce, dp_ref_clk_khz); } -/* TODO: This is DCN DPREFCLK: it could be program by DENTIST by VBIOS - * or CLK0_CLK11 by SMU. For DCE120, it is wlays 600Mhz. Will re-visit - * clock implementation - */ -static int dce_clocks_get_dp_ref_freq_wrkaround(struct dccg *clk) +static int dce12_get_dp_ref_freq_khz(struct dccg *clk) { struct dce_dccg *clk_dce = TO_DCE_CLOCKS(clk); - int dp_ref_clk_khz = 600000; - - if (clk_dce->ss_on_dprefclk && clk_dce->dprefclk_ss_divider != 0) { - struct fixed31_32 ss_percentage = dc_fixpt_div_int( - dc_fixpt_from_fraction(clk_dce->dprefclk_ss_percentage, - clk_dce->dprefclk_ss_divider), 200); - struct fixed31_32 adj_dp_ref_clk_khz; - - ss_percentage = dc_fixpt_sub(dc_fixpt_one, ss_percentage); - adj_dp_ref_clk_khz = dc_fixpt_mul_int(ss_percentage, dp_ref_clk_khz); - dp_ref_clk_khz = dc_fixpt_floor(adj_dp_ref_clk_khz); - } - return dp_ref_clk_khz; + return dccg_adjust_dp_ref_freq_for_ss(clk_dce, 600000); } + static enum dm_pp_clocks_state dce_get_required_clocks_state( struct dccg *clk, struct dc_clocks *req_clocks) @@ -590,8 +579,7 @@ static void dcn1_update_clocks(struct dccg *dccg, /* make sure dcf clk is before dpp clk to * make sure we have enough voltage to run dpp clk */ - if (send_request_to_increase - ) { + 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); @@ -644,8 +632,7 @@ static void dcn1_update_clocks(struct dccg *dccg, } #ifdef CONFIG_DRM_AMD_DC_DCN1_0 - if (!send_request_to_increase && send_request_to_lower - ) { + 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); @@ -685,31 +672,31 @@ static void dce_update_clocks(struct dccg *dccg, } static const struct display_clock_funcs dcn1_funcs = { - .get_dp_ref_clk_frequency = dce_clocks_get_dp_ref_freq_wrkaround, + .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz, .set_dispclk = dce112_set_clock, .update_clocks = dcn1_update_clocks }; static const struct display_clock_funcs dce120_funcs = { - .get_dp_ref_clk_frequency = dce_clocks_get_dp_ref_freq_wrkaround, + .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz, .set_dispclk = dce112_set_clock, .update_clocks = dce12_update_clocks }; static const struct display_clock_funcs dce112_funcs = { - .get_dp_ref_clk_frequency = dce_clocks_get_dp_ref_freq, + .get_dp_ref_clk_frequency = dce_get_dp_ref_freq_khz, .set_dispclk = dce112_set_clock, .update_clocks = dce_update_clocks }; static const struct display_clock_funcs dce110_funcs = { - .get_dp_ref_clk_frequency = dce_clocks_get_dp_ref_freq, + .get_dp_ref_clk_frequency = dce_get_dp_ref_freq_khz, .set_dispclk = dce_psr_set_clock, .update_clocks = dce_update_clocks }; static const struct display_clock_funcs dce_funcs = { - .get_dp_ref_clk_frequency = dce_clocks_get_dp_ref_freq, + .get_dp_ref_clk_frequency = dce_get_dp_ref_freq_khz, .set_dispclk = dce_set_clock, .update_clocks = dce_update_clocks }; @@ -717,9 +704,9 @@ static const struct display_clock_funcs dce_funcs = { static void dce_dccg_construct( struct dce_dccg *clk_dce, struct dc_context *ctx, - const struct dce_disp_clk_registers *regs, - const struct dce_disp_clk_shift *clk_shift, - const struct dce_disp_clk_mask *clk_mask) + const struct dccg_registers *regs, + const struct dccg_shift *clk_shift, + const struct dccg_mask *clk_mask) { struct dccg *base = &clk_dce->base; @@ -745,9 +732,9 @@ static void dce_dccg_construct( struct dccg *dce_dccg_create( struct dc_context *ctx, - const struct dce_disp_clk_registers *regs, - const struct dce_disp_clk_shift *clk_shift, - const struct dce_disp_clk_mask *clk_mask) + const struct dccg_registers *regs, + const struct dccg_shift *clk_shift, + const struct dccg_mask *clk_mask) { struct dce_dccg *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL); @@ -768,9 +755,9 @@ struct dccg *dce_dccg_create( struct dccg *dce110_dccg_create( struct dc_context *ctx, - const struct dce_disp_clk_registers *regs, - const struct dce_disp_clk_shift *clk_shift, - const struct dce_disp_clk_mask *clk_mask) + const struct dccg_registers *regs, + const struct dccg_shift *clk_shift, + const struct dccg_mask *clk_mask) { struct dce_dccg *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL); @@ -793,9 +780,9 @@ struct dccg *dce110_dccg_create( struct dccg *dce112_dccg_create( struct dc_context *ctx, - const struct dce_disp_clk_registers *regs, - const struct dce_disp_clk_shift *clk_shift, - const struct dce_disp_clk_mask *clk_mask) + const struct dccg_registers *regs, + const struct dccg_shift *clk_shift, + const struct dccg_mask *clk_mask) { struct dce_dccg *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL); diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h index 04a9e3c04aa77..be5b68d7c3c04 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h @@ -33,6 +33,9 @@ .DPREFCLK_CNTL = mmDPREFCLK_CNTL, \ .DENTIST_DISPCLK_CNTL = mmDENTIST_DISPCLK_CNTL +#define CLK_COMMON_REG_LIST_DCN_BASE() \ + SR(DENTIST_DISPCLK_CNTL) + #define CLK_SF(reg_name, field_name, post_fix)\ .field_name = reg_name ## __ ## field_name ## post_fix @@ -40,28 +43,34 @@ CLK_SF(DPREFCLK_CNTL, DPREFCLK_SRC_SEL, mask_sh), \ CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DPREFCLK_WDIVIDER, mask_sh) +#define CLK_COMMON_MASK_SH_LIST_DCN_COMMON_BASE(mask_sh) \ + CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DPPCLK_WDIVIDER, mask_sh),\ + CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_WDIVIDER, mask_sh) + #define CLK_REG_FIELD_LIST(type) \ type DPREFCLK_SRC_SEL; \ - type DENTIST_DPREFCLK_WDIVIDER; + type DENTIST_DPREFCLK_WDIVIDER; \ + type DENTIST_DISPCLK_WDIVIDER; \ + type DENTIST_DPPCLK_WDIVIDER; -struct dce_disp_clk_shift { +struct dccg_shift { CLK_REG_FIELD_LIST(uint8_t) }; -struct dce_disp_clk_mask { +struct dccg_mask { CLK_REG_FIELD_LIST(uint32_t) }; -struct dce_disp_clk_registers { +struct dccg_registers { uint32_t DPREFCLK_CNTL; uint32_t DENTIST_DISPCLK_CNTL; }; struct dce_dccg { struct dccg base; - const struct dce_disp_clk_registers *regs; - const struct dce_disp_clk_shift *clk_shift; - const struct dce_disp_clk_mask *clk_mask; + const struct dccg_registers *regs; + const struct dccg_shift *clk_shift; + const struct dccg_mask *clk_mask; struct state_dependent_clocks max_clks_by_state[DM_PP_CLOCKS_MAX_STATES]; @@ -84,21 +93,21 @@ struct dce_dccg { struct dccg *dce_dccg_create( struct dc_context *ctx, - const struct dce_disp_clk_registers *regs, - const struct dce_disp_clk_shift *clk_shift, - const struct dce_disp_clk_mask *clk_mask); + const struct dccg_registers *regs, + const struct dccg_shift *clk_shift, + const struct dccg_mask *clk_mask); struct dccg *dce110_dccg_create( struct dc_context *ctx, - const struct dce_disp_clk_registers *regs, - const struct dce_disp_clk_shift *clk_shift, - const struct dce_disp_clk_mask *clk_mask); + const struct dccg_registers *regs, + const struct dccg_shift *clk_shift, + const struct dccg_mask *clk_mask); struct dccg *dce112_dccg_create( struct dc_context *ctx, - const struct dce_disp_clk_registers *regs, - const struct dce_disp_clk_shift *clk_shift, - const struct dce_disp_clk_mask *clk_mask); + const struct dccg_registers *regs, + const struct dccg_shift *clk_shift, + const struct dccg_mask *clk_mask); struct dccg *dce120_dccg_create(struct dc_context *ctx); diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h index 057b8afd74bcc..0574078926184 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h @@ -249,7 +249,6 @@ struct dce_hwseq_registers { uint32_t DISPCLK_FREQ_CHANGE_CNTL; uint32_t RBBMIF_TIMEOUT_DIS; uint32_t RBBMIF_TIMEOUT_DIS_2; - uint32_t DENTIST_DISPCLK_CNTL; uint32_t DCHUBBUB_CRC_CTRL; uint32_t DPP_TOP0_DPP_CRC_CTRL; uint32_t DPP_TOP0_DPP_CRC_VAL_R_G; @@ -496,8 +495,6 @@ struct dce_hwseq_registers { type DOMAIN7_PGFSM_PWR_STATUS; \ type DCFCLK_GATE_DIS; \ type DCHUBBUB_GLOBAL_TIMER_REFDIV; \ - type DENTIST_DPPCLK_WDIVIDER; \ - type DENTIST_DISPCLK_WDIVIDER; \ type VGA_TEST_ENABLE; \ type VGA_TEST_RENDER_START; \ type D1VGA_MODE_ENABLE; \ diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c index 856d3fe8e6a0f..8ed8eace42be5 100644 --- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c @@ -135,15 +135,15 @@ static const struct dce110_timing_generator_offsets dce100_tg_offsets[] = { .reg_name = mm ## block ## id ## _ ## reg_name -static const struct dce_disp_clk_registers disp_clk_regs = { +static const struct dccg_registers disp_clk_regs = { CLK_COMMON_REG_LIST_DCE_BASE() }; -static const struct dce_disp_clk_shift disp_clk_shift = { +static const struct dccg_shift disp_clk_shift = { CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) }; -static const struct dce_disp_clk_mask disp_clk_mask = { +static const struct dccg_mask disp_clk_mask = { CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) }; diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c index 71a401f73a58c..3edaa006bd576 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c @@ -146,15 +146,15 @@ static const struct dce110_timing_generator_offsets dce110_tg_offsets[] = { #define SRI(reg_name, block, id)\ .reg_name = mm ## block ## id ## _ ## reg_name -static const struct dce_disp_clk_registers disp_clk_regs = { +static const struct dccg_registers disp_clk_regs = { CLK_COMMON_REG_LIST_DCE_BASE() }; -static const struct dce_disp_clk_shift disp_clk_shift = { +static const struct dccg_shift disp_clk_shift = { CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) }; -static const struct dce_disp_clk_mask disp_clk_mask = { +static const struct dccg_mask disp_clk_mask = { CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) }; diff --git a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c index ae5b19de559cd..752910035e813 100644 --- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c @@ -146,15 +146,15 @@ static const struct dce110_timing_generator_offsets dce112_tg_offsets[] = { .reg_name = mm ## block ## id ## _ ## reg_name -static const struct dce_disp_clk_registers disp_clk_regs = { +static const struct dccg_registers disp_clk_regs = { CLK_COMMON_REG_LIST_DCE_BASE() }; -static const struct dce_disp_clk_shift disp_clk_shift = { +static const struct dccg_shift disp_clk_shift = { CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) }; -static const struct dce_disp_clk_mask disp_clk_mask = { +static const struct dccg_mask disp_clk_mask = { CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) }; diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c index 70700530aec29..2ac95ec2bf963 100644 --- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c @@ -153,15 +153,15 @@ static const struct dce110_timing_generator_offsets dce80_tg_offsets[] = { .reg_name = mm ## block ## id ## _ ## reg_name -static const struct dce_disp_clk_registers disp_clk_regs = { +static const struct dccg_registers disp_clk_regs = { CLK_COMMON_REG_LIST_DCE_BASE() }; -static const struct dce_disp_clk_shift disp_clk_shift = { +static const struct dccg_shift disp_clk_shift = { CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) }; -static const struct dce_disp_clk_mask disp_clk_mask = { +static const struct dccg_mask disp_clk_mask = { CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) }; -- GitLab From c910a717dac6540a636a57c1a34261c6d84fc0eb Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Date: Wed, 23 May 2018 18:39:21 -0400 Subject: [PATCH 0720/1506] drm/amd/display: clean up set_bandwidth usage This removes redundant set_bandwidth calls as well as fixes a bug in post_set_address_update where dcn1 would never get to lower clocks. Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Reviewed-by: Nikola Cornij <Nikola.Cornij@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/core/dc.c | 5 ----- .../drm/amd/display/dc/dce110/dce110_hw_sequencer.c | 5 ----- .../gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c | 11 +++-------- 3 files changed, 3 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 53ce7fa864b4f..2a785bbf2b8f1 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -944,12 +944,7 @@ bool dc_post_update_surfaces_to_stream(struct dc *dc) dc->optimized_required = false; - /* 3rd param should be true, temp w/a for RV*/ -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) - dc->hwss.set_bandwidth(dc, context, dc->ctx->dce_version < DCN_VERSION_1_0); -#else dc->hwss.set_bandwidth(dc, context, true); -#endif return true; } 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 4cdf86690d19d..3b983b3f34234 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 @@ -2036,8 +2036,6 @@ enum dc_status dce110_apply_ctx_to_hw( if (dc->fbc_compressor) dc->fbc_compressor->funcs->disable_fbc(dc->fbc_compressor); - dc->hwss.set_bandwidth(dc, context, false); - dce110_setup_audio_dto(dc, context); for (i = 0; i < dc->res_pool->pipe_count; i++) { @@ -2066,9 +2064,6 @@ enum dc_status dce110_apply_ctx_to_hw( return status; } - /* to save power */ - dc->hwss.set_bandwidth(dc, context, true); - dcb->funcs->set_scratch_critical_state(dcb, false); if (dc->fbc_compressor) 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 60e99477930b1..08809b0ff6bfd 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 @@ -2268,8 +2268,7 @@ static void dcn10_apply_ctx_for_surface( hwss1_plane_atomic_disconnect(dc, old_pipe_ctx); removed_pipe[i] = true; - DC_LOG_DC( - "Reset mpcc for pipe %d\n", + DC_LOG_DC("Reset mpcc for pipe %d\n", old_pipe_ctx->pipe_idx); } } @@ -2365,9 +2364,8 @@ static void dcn10_set_bandwidth( struct dc_state *context, bool decrease_allowed) { - if (dc->debug.sanity_checks) { + if (dc->debug.sanity_checks) dcn10_verify_allow_pstate_change_high(dc); - } if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) return; @@ -2382,11 +2380,8 @@ static void dcn10_set_bandwidth( dcn10_pplib_apply_display_requirements(dc, context); - if (dc->debug.sanity_checks) { + if (dc->debug.sanity_checks) dcn10_verify_allow_pstate_change_high(dc); - } - - /* need to fix this function. not doing the right thing here */ } static void set_drr(struct pipe_ctx **pipe_ctx, -- GitLab From aa162e2727254262a79509ec3e99ace33b3232b6 Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Date: Thu, 31 May 2018 13:28:00 -0400 Subject: [PATCH 0721/1506] drm/amd/display: remove unnecessary pplib volage requests that are asserting Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c index 242e8ae560256..df6a37b7b769f 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c @@ -588,21 +588,15 @@ static void dcn1_update_clocks(struct dccg *dccg, #endif if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, dccg->clks.dispclk_khz)) { - clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DISPLAY_CLK; - clock_voltage_req.clocks_in_khz = new_clocks->dispclk_khz; dcn1_ramp_up_dispclk_with_dpp(dccg, new_clocks); dccg->clks.dispclk_khz = new_clocks->dispclk_khz; - dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req); send_request_to_lower = true; } if (should_set_clock(safe_to_lower, new_clocks->phyclk_khz, dccg->clks.phyclk_khz)) { - dccg->clks.phyclk_khz = new_clocks->phyclk_khz; - clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DISPLAYPHYCLK; clock_voltage_req.clocks_in_khz = new_clocks->phyclk_khz; - dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req); send_request_to_lower = true; } @@ -618,8 +612,6 @@ static void dcn1_update_clocks(struct dccg *dccg, if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, dccg->clks.dcfclk_khz)) { dccg->clks.phyclk_khz = new_clocks->dcfclk_khz; - clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DCFCLK; - clock_voltage_req.clocks_in_khz = new_clocks->dcfclk_khz; smu_req.hard_min_dcefclk_khz = new_clocks->dcfclk_khz; send_request_to_lower = true; -- GitLab From 0eebf8ca18b647024fc9a3ccc88c0184d02db534 Mon Sep 17 00:00:00 2001 From: Wesley Chalmers <Wesley.Chalmers@amd.com> Date: Fri, 1 Jun 2018 10:54:53 -0400 Subject: [PATCH 0722/1506] drm/amd/display: Temporarily remove Chroma logs To ensure tests continue to pass Signed-off-by: Wesley Chalmers <Wesley.Chalmers@amd.com> Reviewed-by: Shahin Khayyer <Shahin.Khayyer@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) 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 08809b0ff6bfd..5b40c1c4d9e65 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 @@ -151,23 +151,19 @@ static void dcn10_log_hubp_states(struct dc *dc) DTN_INFO("\n=========RQ========\n"); DTN_INFO("HUBP: drq_exp_m prq_exp_m mrq_exp_m crq_exp_m plane1_ba L:chunk_s min_chu_s meta_ch_s" - " min_m_c_s dpte_gr_s mpte_gr_s swath_hei pte_row_h C:chunk_s min_chu_s meta_ch_s" " min_m_c_s dpte_gr_s mpte_gr_s swath_hei pte_row_h\n"); for (i = 0; i < pool->pipe_count; i++) { struct dcn_hubp_state *s = &(TO_DCN10_HUBP(pool->hubps[i])->state); struct _vcs_dpi_display_rq_regs_st *rq_regs = &s->rq_regs; if (!s->blank_en) - DTN_INFO("[%2d]: %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh\n", + DTN_INFO("[%2d]: %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh\n", pool->hubps[i]->inst, rq_regs->drq_expansion_mode, rq_regs->prq_expansion_mode, rq_regs->mrq_expansion_mode, rq_regs->crq_expansion_mode, rq_regs->plane1_base_address, rq_regs->rq_regs_l.chunk_size, rq_regs->rq_regs_l.min_chunk_size, rq_regs->rq_regs_l.meta_chunk_size, rq_regs->rq_regs_l.min_meta_chunk_size, rq_regs->rq_regs_l.dpte_group_size, rq_regs->rq_regs_l.mpte_group_size, rq_regs->rq_regs_l.swath_height, - rq_regs->rq_regs_l.pte_row_height_linear, rq_regs->rq_regs_c.chunk_size, rq_regs->rq_regs_c.min_chunk_size, - rq_regs->rq_regs_c.meta_chunk_size, rq_regs->rq_regs_c.min_meta_chunk_size, - rq_regs->rq_regs_c.dpte_group_size, rq_regs->rq_regs_c.mpte_group_size, - rq_regs->rq_regs_c.swath_height, rq_regs->rq_regs_c.pte_row_height_linear); + rq_regs->rq_regs_l.pte_row_height_linear); } DTN_INFO("========DLG========\n"); -- GitLab From 7e17cb4ba90cf2ab51e65427092fdc878cc956bc Mon Sep 17 00:00:00 2001 From: Charlene Liu <charlene.liu@amd.com> Date: Wed, 30 May 2018 15:58:08 -0400 Subject: [PATCH 0723/1506] drm/amd/display: Define dp_alt_mode Also cleanup command_table2.c. No need for a lot of forward declarations. Signed-off-by: Charlene Liu <charlene.liu@amd.com> Reviewed-by: Krunoslav Kovac <Krunoslav.Kovac@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../drm/amd/display/dc/bios/command_table2.c | 46 +++++++------------ .../amd/display/dc/dcn10/dcn10_link_encoder.c | 2 + .../drm/amd/display/include/grph_object_id.h | 5 ++ 3 files changed, 24 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c index 752b08a42d3ec..2b5dc499a35ed 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c @@ -59,36 +59,7 @@ bios_cmd_table_para_revision(bp->base.ctx->driver_context, \ GET_INDEX_INTO_MASTER_TABLE(command, fname)) -static void init_dig_encoder_control(struct bios_parser *bp); -static void init_transmitter_control(struct bios_parser *bp); -static void init_set_pixel_clock(struct bios_parser *bp); -static void init_set_crtc_timing(struct bios_parser *bp); - -static void init_select_crtc_source(struct bios_parser *bp); -static void init_enable_crtc(struct bios_parser *bp); - -static void init_external_encoder_control(struct bios_parser *bp); -static void init_enable_disp_power_gating(struct bios_parser *bp); -static void init_set_dce_clock(struct bios_parser *bp); -static void init_get_smu_clock_info(struct bios_parser *bp); - -void dal_firmware_parser_init_cmd_tbl(struct bios_parser *bp) -{ - init_dig_encoder_control(bp); - init_transmitter_control(bp); - init_set_pixel_clock(bp); - - init_set_crtc_timing(bp); - - init_select_crtc_source(bp); - init_enable_crtc(bp); - - init_external_encoder_control(bp); - init_enable_disp_power_gating(bp); - init_set_dce_clock(bp); - init_get_smu_clock_info(bp); -} static uint32_t bios_cmd_table_para_revision(void *dev, uint32_t index) @@ -829,3 +800,20 @@ static unsigned int get_smu_clock_info_v3_1(struct bios_parser *bp, uint8_t id) return 0; } +void dal_firmware_parser_init_cmd_tbl(struct bios_parser *bp) +{ + init_dig_encoder_control(bp); + init_transmitter_control(bp); + init_set_pixel_clock(bp); + + init_set_crtc_timing(bp); + + init_select_crtc_source(bp); + init_enable_crtc(bp); + + init_external_encoder_control(bp); + init_enable_disp_power_gating(bp); + init_set_dce_clock(bp); + init_get_smu_clock_info(bp); + +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c index 21fa40ac0786b..fd9dc70190a88 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c @@ -995,6 +995,8 @@ void dcn10_link_encoder_disable_output( if (!dcn10_is_dig_enabled(enc)) { /* OF_SKIP_POWER_DOWN_INACTIVE_ENCODER */ + /*in DP_Alt_No_Connect case, we turn off the dig already, + after excuation the PHY w/a sequence, not allow touch PHY any more*/ return; } /* Power-down RX and disable GPU PHY should be paired. diff --git a/drivers/gpu/drm/amd/display/include/grph_object_id.h b/drivers/gpu/drm/amd/display/include/grph_object_id.h index c4197432eb7c3..92cc6c112ea69 100644 --- a/drivers/gpu/drm/amd/display/include/grph_object_id.h +++ b/drivers/gpu/drm/amd/display/include/grph_object_id.h @@ -197,6 +197,11 @@ enum transmitter_color_depth { TRANSMITTER_COLOR_DEPTH_48 /* 16 bits */ }; +enum dp_alt_mode { + DP_Alt_mode__Unknown = 0, + DP_Alt_mode__Connect, + DP_Alt_mode__NoConnect, +}; /* ***************************************************************************** * graphics_object_id struct -- GitLab From 89af301e21b53317f1d0c5ed6f8e935f65e877d0 Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Date: Fri, 1 Jun 2018 14:13:40 -0400 Subject: [PATCH 0724/1506] drm/amd/display: fix dccg dcn1 ifdef Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Reviewed-by: Eric Yang <eric.yang2@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c | 10 ++++++---- drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h | 2 ++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c index df6a37b7b769f..e62a21f55064c 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c @@ -478,6 +478,7 @@ static void dce12_update_clocks(struct dccg *dccg, } } +#ifdef CONFIG_DRM_AMD_DC_DCN1_0 static int dcn1_determine_dppclk_threshold(struct dccg *dccg, struct dc_clocks *new_clocks) { bool request_dpp_div = new_clocks->dispclk_khz > new_clocks->dppclk_khz; @@ -575,7 +576,6 @@ static void dcn1_update_clocks(struct dccg *dccg, || new_clocks->dcfclk_khz > dccg->clks.dcfclk_khz) send_request_to_increase = true; -#ifdef CONFIG_DRM_AMD_DC_DCN1_0 /* make sure dcf clk is before dpp clk to * make sure we have enough voltage to run dpp clk */ @@ -585,7 +585,6 @@ static void dcn1_update_clocks(struct dccg *dccg, clock_voltage_req.clocks_in_khz = dcn_find_dcfclk_suits_all(dc, new_clocks); dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req); } -#endif if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, dccg->clks.dispclk_khz)) { dcn1_ramp_up_dispclk_with_dpp(dccg, new_clocks); @@ -623,14 +622,12 @@ static void dcn1_update_clocks(struct dccg *dccg, smu_req.min_deep_sleep_dcefclk_mhz = new_clocks->dcfclk_deep_sleep_khz; } -#ifdef CONFIG_DRM_AMD_DC_DCN1_0 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); dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req); } -#endif if (new_clocks->phyclk_khz) smu_req.display_count = 1; @@ -642,6 +639,7 @@ static void dcn1_update_clocks(struct dccg *dccg, *smu_req_cur = smu_req; } +#endif static void dce_update_clocks(struct dccg *dccg, struct dc_clocks *new_clocks, @@ -663,11 +661,13 @@ static void dce_update_clocks(struct dccg *dccg, } } +#ifdef CONFIG_DRM_AMD_DC_DCN1_0 static const struct display_clock_funcs dcn1_funcs = { .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz, .set_dispclk = dce112_set_clock, .update_clocks = dcn1_update_clocks }; +#endif static const struct display_clock_funcs dce120_funcs = { .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz, @@ -816,6 +816,7 @@ struct dccg *dce120_dccg_create(struct dc_context *ctx) return &clk_dce->base; } +#ifdef CONFIG_DRM_AMD_DC_DCN1_0 struct dccg *dcn1_dccg_create(struct dc_context *ctx) { struct dc_debug *debug = &ctx->dc->debug; @@ -854,6 +855,7 @@ struct dccg *dcn1_dccg_create(struct dc_context *ctx) return &clk_dce->base; } +#endif void dce_dccg_destroy(struct dccg **dccg) { diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h index be5b68d7c3c04..1f1899ef773a1 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h @@ -111,7 +111,9 @@ struct dccg *dce112_dccg_create( struct dccg *dce120_dccg_create(struct dc_context *ctx); +#ifdef CONFIG_DRM_AMD_DC_DCN1_0 struct dccg *dcn1_dccg_create(struct dc_context *ctx); +#endif void dce_dccg_destroy(struct dccg **dccg); -- GitLab From 5b0ec710dadd4569c1ed76dc175b94abb594b977 Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Date: Fri, 1 Jun 2018 15:01:32 -0400 Subject: [PATCH 0725/1506] drm/amd/display: fix pplib voltage request This fixes incorrect clock caching and by extension fixes the clock reporting. Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Reviewed-by: Eric Yang <eric.yang2@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/display/dc/dce/dce_clocks.c | 59 ++++++++++--------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c index e62a21f55064c..0a4ae0f49f99b 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c @@ -570,37 +570,25 @@ static void dcn1_update_clocks(struct dccg *dccg, bool send_request_to_increase = false; bool send_request_to_lower = false; + if (new_clocks->phyclk_khz) + smu_req.display_count = 1; + else + smu_req.display_count = 0; + if (new_clocks->dispclk_khz > dccg->clks.dispclk_khz || new_clocks->phyclk_khz > dccg->clks.phyclk_khz || new_clocks->fclk_khz > dccg->clks.fclk_khz || new_clocks->dcfclk_khz > dccg->clks.dcfclk_khz) send_request_to_increase = true; - /* make sure dcf clk is before dpp clk to - * make sure we have enough voltage to run dpp clk - */ - 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); - dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req); - } - - if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, dccg->clks.dispclk_khz)) { - dcn1_ramp_up_dispclk_with_dpp(dccg, new_clocks); - dccg->clks.dispclk_khz = new_clocks->dispclk_khz; - - send_request_to_lower = true; - } - if (should_set_clock(safe_to_lower, new_clocks->phyclk_khz, dccg->clks.phyclk_khz)) { - clock_voltage_req.clocks_in_khz = new_clocks->phyclk_khz; + dccg->clks.phyclk_khz = new_clocks->phyclk_khz; send_request_to_lower = true; } if (should_set_clock(safe_to_lower, new_clocks->fclk_khz, dccg->clks.fclk_khz)) { - dccg->clks.phyclk_khz = new_clocks->fclk_khz; + dccg->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_khz = new_clocks->fclk_khz; @@ -610,7 +598,7 @@ static void dcn1_update_clocks(struct dccg *dccg, } if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, dccg->clks.dcfclk_khz)) { - dccg->clks.phyclk_khz = new_clocks->dcfclk_khz; + dccg->clks.dcfclk_khz = new_clocks->dcfclk_khz; smu_req.hard_min_dcefclk_khz = new_clocks->dcfclk_khz; send_request_to_lower = true; @@ -620,22 +608,39 @@ static void dcn1_update_clocks(struct dccg *dccg, new_clocks->dcfclk_deep_sleep_khz, dccg->clks.dcfclk_deep_sleep_khz)) { dccg->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz; smu_req.min_deep_sleep_dcefclk_mhz = new_clocks->dcfclk_deep_sleep_khz; + + send_request_to_lower = true; } - if (!send_request_to_increase && send_request_to_lower) { + /* make sure dcf clk is before dpp clk to + * make sure we have enough voltage to run dpp clk + */ + 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); dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req); + if (pp_smu->set_display_requirement) + pp_smu->set_display_requirement(&pp_smu->pp_smu, &smu_req); } - if (new_clocks->phyclk_khz) - smu_req.display_count = 1; - else - smu_req.display_count = 0; + /* dcn1 dppclk is tied to dispclk */ + if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, dccg->clks.dispclk_khz)) { + dcn1_ramp_up_dispclk_with_dpp(dccg, new_clocks); + dccg->clks.dispclk_khz = new_clocks->dispclk_khz; + + send_request_to_lower = true; + } + + 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); + dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req); + if (pp_smu->set_display_requirement) + pp_smu->set_display_requirement(&pp_smu->pp_smu, &smu_req); + } - if (pp_smu->set_display_requirement) - pp_smu->set_display_requirement(&pp_smu->pp_smu, &smu_req); *smu_req_cur = smu_req; } -- GitLab From 5f8d084939d0a94d21c32adf2a4e9249e6ce5654 Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Date: Wed, 30 May 2018 17:12:16 -0400 Subject: [PATCH 0726/1506] drm/amd/display: add CHG_DONE mash/sh defines for dentist Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Reviewed-by: Charlene Liu <Charlene.Liu@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h index 1f1899ef773a1..7ce0a54e548f4 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h @@ -45,13 +45,17 @@ #define CLK_COMMON_MASK_SH_LIST_DCN_COMMON_BASE(mask_sh) \ CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DPPCLK_WDIVIDER, mask_sh),\ - CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_WDIVIDER, mask_sh) + CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_WDIVIDER, mask_sh),\ + CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_CHG_DONE, mask_sh),\ + CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DPPCLK_CHG_DONE, mask_sh) #define CLK_REG_FIELD_LIST(type) \ type DPREFCLK_SRC_SEL; \ type DENTIST_DPREFCLK_WDIVIDER; \ type DENTIST_DISPCLK_WDIVIDER; \ - type DENTIST_DPPCLK_WDIVIDER; + type DENTIST_DPPCLK_WDIVIDER; \ + type DENTIST_DISPCLK_CHG_DONE; \ + type DENTIST_DPPCLK_CHG_DONE; struct dccg_shift { CLK_REG_FIELD_LIST(uint8_t) -- GitLab From 294c7e7347d400b2f2d9f09898e8c462f752f500 Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Date: Wed, 30 May 2018 17:17:27 -0400 Subject: [PATCH 0727/1506] drm/amd/display: change dentist DID enum values to uppercase Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Reviewed-by: Charlene Liu <Charlene.Liu@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/display/dc/dce/dce_clocks.c | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c index 0a4ae0f49f99b..6882dc953a2c2 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c @@ -103,39 +103,39 @@ static const struct state_dependent_clocks dce120_max_clks_by_state[] = { /* Starting DID for each range */ enum dentist_base_divider_id { - dentist_base_divider_id_1 = 0x08, - dentist_base_divider_id_2 = 0x40, - dentist_base_divider_id_3 = 0x60, - dentist_max_divider_id = 0x80 + DENTIST_BASE_DID_1 = 0x08, + DENTIST_BASE_DID_2 = 0x40, + DENTIST_BASE_DID_3 = 0x60, + DENTIST_MAX_DID = 0x80 }; /* Starting point and step size for each divider range.*/ enum dentist_divider_range { - dentist_divider_range_1_start = 8, /* 2.00 */ - dentist_divider_range_1_step = 1, /* 0.25 */ - dentist_divider_range_2_start = 64, /* 16.00 */ - dentist_divider_range_2_step = 2, /* 0.50 */ - dentist_divider_range_3_start = 128, /* 32.00 */ - dentist_divider_range_3_step = 4, /* 1.00 */ - dentist_divider_range_scale_factor = 4 + DENTIST_DIVIDER_RANGE_1_START = 8, /* 2.00 */ + DENTIST_DIVIDER_RANGE_1_STEP = 1, /* 0.25 */ + DENTIST_DIVIDER_RANGE_2_START = 64, /* 16.00 */ + DENTIST_DIVIDER_RANGE_2_STEP = 2, /* 0.50 */ + DENTIST_DIVIDER_RANGE_3_START = 128, /* 32.00 */ + DENTIST_DIVIDER_RANGE_3_STEP = 4, /* 1.00 */ + DENTIST_DIVIDER_RANGE_SCALE_FACTOR = 4 }; static int dentist_get_divider_from_did(int did) { - if (did < dentist_base_divider_id_1) - did = dentist_base_divider_id_1; - if (did > dentist_max_divider_id) - did = dentist_max_divider_id; - - if (did < dentist_base_divider_id_2) { - return dentist_divider_range_1_start + dentist_divider_range_1_step - * (did - dentist_base_divider_id_1); - } else if (did < dentist_base_divider_id_3) { - return dentist_divider_range_2_start + dentist_divider_range_2_step - * (did - dentist_base_divider_id_2); + if (did < DENTIST_BASE_DID_1) + did = DENTIST_BASE_DID_1; + if (did > DENTIST_MAX_DID) + did = DENTIST_MAX_DID; + + if (did < DENTIST_BASE_DID_2) { + return DENTIST_DIVIDER_RANGE_1_START + DENTIST_DIVIDER_RANGE_1_STEP + * (did - DENTIST_BASE_DID_1); + } else if (did < DENTIST_BASE_DID_3) { + return DENTIST_DIVIDER_RANGE_2_START + DENTIST_DIVIDER_RANGE_2_STEP + * (did - DENTIST_BASE_DID_2); } else { - return dentist_divider_range_3_start + dentist_divider_range_3_step - * (did - dentist_base_divider_id_3); + return DENTIST_DIVIDER_RANGE_3_START + DENTIST_DIVIDER_RANGE_3_STEP + * (did - DENTIST_BASE_DID_3); } } @@ -186,7 +186,7 @@ static int dce_get_dp_ref_freq_khz(struct dccg *clk) target_div = dentist_get_divider_from_did(dprefclk_wdivider); /* Calculate the current DFS clock, in kHz.*/ - dp_ref_clk_khz = (dentist_divider_range_scale_factor + dp_ref_clk_khz = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR * clk_dce->dentist_vco_freq_khz) / target_div; return dccg_adjust_dp_ref_freq_for_ss(clk_dce, dp_ref_clk_khz); -- GitLab From d7b539d34acea44ee555a4fe35e77c23b8dc4bc4 Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Date: Thu, 24 May 2018 15:09:40 -0400 Subject: [PATCH 0728/1506] drm/amd/display: add safe_to_lower support to dcn wm programming This will prevent watermarks from lowering when unsafe to do so. Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Reviewed-by: Charlene Liu <Charlene.Liu@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../drm/amd/display/dc/dcn10/dcn10_hubbub.c | 346 +++++++++++------- .../drm/amd/display/dc/dcn10/dcn10_hubbub.h | 4 +- .../amd/display/dc/dcn10/dcn10_hw_sequencer.c | 2 +- 3 files changed, 214 insertions(+), 138 deletions(-) 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 943143efbb823..63b75ac4a1d52 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c @@ -193,7 +193,8 @@ static uint32_t convert_and_clamp( void hubbub1_program_watermarks( struct hubbub *hubbub, struct dcn_watermark_set *watermarks, - unsigned int refclk_mhz) + unsigned int refclk_mhz, + bool safe_to_lower) { uint32_t force_en = hubbub->ctx->dc->debug.disable_stutter ? 1 : 0; /* @@ -207,184 +208,257 @@ void hubbub1_program_watermarks( /* Repeat for water mark set A, B, C and D. */ /* clock state A */ - prog_wm_value = convert_and_clamp(watermarks->a.urgent_ns, - refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, prog_wm_value); - - DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_A calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->a.urgent_ns, prog_wm_value); + if (safe_to_lower || watermarks->a.urgent_ns > hubbub->watermarks.a.urgent_ns) { + hubbub->watermarks.a.urgent_ns = watermarks->a.urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->a.urgent_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, prog_wm_value); - prog_wm_value = convert_and_clamp(watermarks->a.pte_meta_urgent_ns, - refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_A calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->a.pte_meta_urgent_ns, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_A calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->a.urgent_ns, prog_wm_value); + } - if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A)) { - prog_wm_value = convert_and_clamp( - watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, + if (safe_to_lower || watermarks->a.pte_meta_urgent_ns > hubbub->watermarks.a.pte_meta_urgent_ns) { + hubbub->watermarks.a.pte_meta_urgent_ns = watermarks->a.pte_meta_urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->a.pte_meta_urgent_ns, refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_A calculated =%d\n" + REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_A calculated =%d\n" "HW register value = 0x%x\n", - watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + watermarks->a.pte_meta_urgent_ns, prog_wm_value); + } + if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A)) { + if (safe_to_lower || watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns + > hubbub->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns) { + hubbub->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns = + watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_A calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + } + + if (safe_to_lower || watermarks->a.cstate_pstate.cstate_exit_ns + > hubbub->watermarks.a.cstate_pstate.cstate_exit_ns) { + hubbub->watermarks.a.cstate_pstate.cstate_exit_ns = + watermarks->a.cstate_pstate.cstate_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->a.cstate_pstate.cstate_exit_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_A calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->a.cstate_pstate.cstate_exit_ns, prog_wm_value); + } + } + if (safe_to_lower || watermarks->a.cstate_pstate.pstate_change_ns + > hubbub->watermarks.a.cstate_pstate.pstate_change_ns) { + hubbub->watermarks.a.cstate_pstate.pstate_change_ns = + watermarks->a.cstate_pstate.pstate_change_ns; prog_wm_value = convert_and_clamp( - watermarks->a.cstate_pstate.cstate_exit_ns, + watermarks->a.cstate_pstate.pstate_change_ns, refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_A calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->a.cstate_pstate.cstate_exit_ns, prog_wm_value); + REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_A calculated =%d\n" + "HW register value = 0x%x\n\n", + watermarks->a.cstate_pstate.pstate_change_ns, prog_wm_value); } - prog_wm_value = convert_and_clamp( - watermarks->a.cstate_pstate.pstate_change_ns, - refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_A calculated =%d\n" - "HW register value = 0x%x\n\n", - watermarks->a.cstate_pstate.pstate_change_ns, prog_wm_value); - - /* clock state B */ - prog_wm_value = convert_and_clamp( - watermarks->b.urgent_ns, refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_B calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->b.urgent_ns, prog_wm_value); - - - prog_wm_value = convert_and_clamp( - watermarks->b.pte_meta_urgent_ns, - refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_B calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->b.pte_meta_urgent_ns, prog_wm_value); + if (safe_to_lower || watermarks->b.urgent_ns > hubbub->watermarks.b.urgent_ns) { + hubbub->watermarks.b.urgent_ns = watermarks->b.urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->b.urgent_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_B calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->b.urgent_ns, prog_wm_value); + } - if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B)) { - prog_wm_value = convert_and_clamp( - watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, + if (safe_to_lower || watermarks->b.pte_meta_urgent_ns > hubbub->watermarks.b.pte_meta_urgent_ns) { + hubbub->watermarks.b.pte_meta_urgent_ns = watermarks->b.pte_meta_urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->b.pte_meta_urgent_ns, refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("SR_ENTER_WATERMARK_B calculated =%d\n" + REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_B calculated =%d\n" "HW register value = 0x%x\n", - watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + watermarks->b.pte_meta_urgent_ns, prog_wm_value); + } + if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B)) { + if (safe_to_lower || watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns + > hubbub->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns) { + hubbub->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns = + watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_B calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + } + if (safe_to_lower || watermarks->b.cstate_pstate.cstate_exit_ns + > hubbub->watermarks.b.cstate_pstate.cstate_exit_ns) { + hubbub->watermarks.b.cstate_pstate.cstate_exit_ns = + watermarks->b.cstate_pstate.cstate_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->b.cstate_pstate.cstate_exit_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_B calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->b.cstate_pstate.cstate_exit_ns, prog_wm_value); + } + } + + if (safe_to_lower || watermarks->b.cstate_pstate.pstate_change_ns + > hubbub->watermarks.b.cstate_pstate.pstate_change_ns) { + hubbub->watermarks.b.cstate_pstate.pstate_change_ns = + watermarks->b.cstate_pstate.pstate_change_ns; prog_wm_value = convert_and_clamp( - watermarks->b.cstate_pstate.cstate_exit_ns, + watermarks->b.cstate_pstate.pstate_change_ns, refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_B calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->b.cstate_pstate.cstate_exit_ns, prog_wm_value); + REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_B calculated =%d\n" + "HW register value = 0x%x\n\n", + watermarks->b.cstate_pstate.pstate_change_ns, prog_wm_value); } - prog_wm_value = convert_and_clamp( - watermarks->b.cstate_pstate.pstate_change_ns, - refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_B calculated =%d\n\n" - "HW register value = 0x%x\n", - watermarks->b.cstate_pstate.pstate_change_ns, prog_wm_value); - /* clock state C */ - prog_wm_value = convert_and_clamp( - watermarks->c.urgent_ns, refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_C calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->c.urgent_ns, prog_wm_value); - - - prog_wm_value = convert_and_clamp( - watermarks->c.pte_meta_urgent_ns, - refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_C calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->c.pte_meta_urgent_ns, prog_wm_value); + if (safe_to_lower || watermarks->c.urgent_ns > hubbub->watermarks.c.urgent_ns) { + hubbub->watermarks.c.urgent_ns = watermarks->c.urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->c.urgent_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_C calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->c.urgent_ns, prog_wm_value); + } - if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C)) { - prog_wm_value = convert_and_clamp( - watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, + if (safe_to_lower || watermarks->c.pte_meta_urgent_ns > hubbub->watermarks.c.pte_meta_urgent_ns) { + hubbub->watermarks.c.pte_meta_urgent_ns = watermarks->c.pte_meta_urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->c.pte_meta_urgent_ns, refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("SR_ENTER_WATERMARK_C calculated =%d\n" + REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_C calculated =%d\n" "HW register value = 0x%x\n", - watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + watermarks->c.pte_meta_urgent_ns, prog_wm_value); + } + if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C)) { + if (safe_to_lower || watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns + > hubbub->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns) { + hubbub->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns = + watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_C calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + } + if (safe_to_lower || watermarks->c.cstate_pstate.cstate_exit_ns + > hubbub->watermarks.c.cstate_pstate.cstate_exit_ns) { + hubbub->watermarks.c.cstate_pstate.cstate_exit_ns = + watermarks->c.cstate_pstate.cstate_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->c.cstate_pstate.cstate_exit_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_C calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->c.cstate_pstate.cstate_exit_ns, prog_wm_value); + } + } + + if (safe_to_lower || watermarks->c.cstate_pstate.pstate_change_ns + > hubbub->watermarks.c.cstate_pstate.pstate_change_ns) { + hubbub->watermarks.c.cstate_pstate.pstate_change_ns = + watermarks->c.cstate_pstate.pstate_change_ns; prog_wm_value = convert_and_clamp( - watermarks->c.cstate_pstate.cstate_exit_ns, + watermarks->c.cstate_pstate.pstate_change_ns, refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_C calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->c.cstate_pstate.cstate_exit_ns, prog_wm_value); + REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_C calculated =%d\n" + "HW register value = 0x%x\n\n", + watermarks->c.cstate_pstate.pstate_change_ns, prog_wm_value); } - prog_wm_value = convert_and_clamp( - watermarks->c.cstate_pstate.pstate_change_ns, - refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_C calculated =%d\n\n" - "HW register value = 0x%x\n", - watermarks->c.cstate_pstate.pstate_change_ns, prog_wm_value); - /* clock state D */ - prog_wm_value = convert_and_clamp( - watermarks->d.urgent_ns, refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_D calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->d.urgent_ns, prog_wm_value); - - prog_wm_value = convert_and_clamp( - watermarks->d.pte_meta_urgent_ns, - refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_D calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->d.pte_meta_urgent_ns, prog_wm_value); + if (safe_to_lower || watermarks->d.urgent_ns > hubbub->watermarks.d.urgent_ns) { + hubbub->watermarks.d.urgent_ns = watermarks->d.urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->d.urgent_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_D calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->d.urgent_ns, prog_wm_value); + } - if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D)) { - prog_wm_value = convert_and_clamp( - watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, + if (safe_to_lower || watermarks->d.pte_meta_urgent_ns > hubbub->watermarks.d.pte_meta_urgent_ns) { + hubbub->watermarks.d.pte_meta_urgent_ns = watermarks->d.pte_meta_urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->d.pte_meta_urgent_ns, refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("SR_ENTER_WATERMARK_D calculated =%d\n" + REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_D calculated =%d\n" "HW register value = 0x%x\n", - watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + watermarks->d.pte_meta_urgent_ns, prog_wm_value); + } + + if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D)) { + if (safe_to_lower || watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns + > hubbub->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns) { + hubbub->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns = + watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_D calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + } + if (safe_to_lower || watermarks->d.cstate_pstate.cstate_exit_ns + > hubbub->watermarks.d.cstate_pstate.cstate_exit_ns) { + hubbub->watermarks.d.cstate_pstate.cstate_exit_ns = + watermarks->d.cstate_pstate.cstate_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->d.cstate_pstate.cstate_exit_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_D calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->d.cstate_pstate.cstate_exit_ns, prog_wm_value); + } + } + if (safe_to_lower || watermarks->d.cstate_pstate.pstate_change_ns + > hubbub->watermarks.d.cstate_pstate.pstate_change_ns) { + hubbub->watermarks.d.cstate_pstate.pstate_change_ns = + watermarks->d.cstate_pstate.pstate_change_ns; prog_wm_value = convert_and_clamp( - watermarks->d.cstate_pstate.cstate_exit_ns, + watermarks->d.cstate_pstate.pstate_change_ns, refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_D calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->d.cstate_pstate.cstate_exit_ns, prog_wm_value); + REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_D calculated =%d\n" + "HW register value = 0x%x\n\n", + watermarks->d.cstate_pstate.pstate_change_ns, prog_wm_value); } - - prog_wm_value = convert_and_clamp( - watermarks->d.cstate_pstate.pstate_change_ns, - refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_D calculated =%d\n" - "HW register value = 0x%x\n\n", - watermarks->d.cstate_pstate.pstate_change_ns, prog_wm_value); - REG_UPDATE(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL, DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, 1); diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h index 6315a0e6b0d69..0ca39cb71968d 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h @@ -185,6 +185,7 @@ struct hubbub { const struct dcn_hubbub_shift *shifts; const struct dcn_hubbub_mask *masks; unsigned int debug_test_index_pstate; + struct dcn_watermark_set watermarks; }; void hubbub1_update_dchub( @@ -197,7 +198,8 @@ bool hubbub1_verify_allow_pstate_change_high( void hubbub1_program_watermarks( struct hubbub *hubbub, struct dcn_watermark_set *watermarks, - unsigned int refclk_mhz); + unsigned int refclk_mhz, + bool safe_to_lower); void hubbub1_toggle_watermark_change_req( struct hubbub *hubbub); 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 5b40c1c4d9e65..7d9c10b6d99b6 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 @@ -2299,7 +2299,7 @@ static void dcn10_apply_ctx_for_surface( /* watermark is for all pipes */ hubbub1_program_watermarks(dc->res_pool->hubbub, - &context->bw.dcn.watermarks, ref_clk_mhz); + &context->bw.dcn.watermarks, ref_clk_mhz, true); if (dc->debug.sanity_checks) { /* pstate stuck check after watermark update */ -- GitLab From 836758ffe78a7bc45af9484e34cba2b685f2a0b2 Mon Sep 17 00:00:00 2001 From: "Zheng, XueLai(Eric)" <XueLai.Zheng@amd.com> Date: Tue, 8 May 2018 12:25:15 -0400 Subject: [PATCH 0729/1506] drm/amd/display: support ACrYCb2101010 Signed-off-by: XueLai(Eric), Zheng <XueLai.Zheng@amd.com> Reviewed-by: Charlene Liu <Charlene.Liu@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dc_hw_types.h | 1 + drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h index d31023d57b58a..14afbc5c0a621 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h @@ -199,6 +199,7 @@ enum surface_pixel_format { SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb, SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr, SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb, + SURFACE_PIXEL_FORMAT_SUBSAMPLE_END, SURFACE_PIXEL_FORMAT_INVALID /*grow 444 video here if necessary */ 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 c28085be39ff9..93f52c58bc695 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c @@ -166,7 +166,7 @@ void hubp1_program_size_and_rotation( /* Program data and meta surface pitch (calculation from addrlib) * 444 or 420 luma */ - if (format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) { + if (format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN && format < SURFACE_PIXEL_FORMAT_SUBSAMPLE_END) { ASSERT(plane_size->video.chroma_pitch != 0); /* Chroma pitch zero can cause system hang! */ -- GitLab From f3e077d95ca0a016fdf3d6b1e97a9910dfdaff17 Mon Sep 17 00:00:00 2001 From: Wesley Chalmers <Wesley.Chalmers@amd.com> Date: Tue, 29 May 2018 17:45:05 -0400 Subject: [PATCH 0730/1506] drm/amd/display: fix use of uninitialized memory DML does not calculate chroma values for RQ when surface is not YUV, but DC will unconditionally use the uninitialized values for HW programming. This does not cause visual corruption since HW will ignore garbage chroma values when surface is not YUV, but causes presubmission tests to fail golden value comparison. Signed-off-by: Wesley Chalmers <Wesley.Chalmers@amd.com> Signed-off-by: Eryk Brol <eryk.brol@amd.com> Reviewed-by: Wenjing Liu <Wenjing.Liu@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.c b/drivers/gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.c index c2037daa8e666..0efbf411667a5 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.c @@ -239,6 +239,8 @@ void dml1_extract_rq_regs( extract_rq_sizing_regs(mode_lib, &(rq_regs->rq_regs_l), rq_param.sizing.rq_l); if (rq_param.yuv420) extract_rq_sizing_regs(mode_lib, &(rq_regs->rq_regs_c), rq_param.sizing.rq_c); + else + memset(&(rq_regs->rq_regs_c), 0, sizeof(rq_regs->rq_regs_c)); rq_regs->rq_regs_l.swath_height = dml_log2(rq_param.dlg.rq_l.swath_height); rq_regs->rq_regs_c.swath_height = dml_log2(rq_param.dlg.rq_c.swath_height); -- GitLab From 0176e8c4c0f35555f7554ec3097283187b33ccbd Mon Sep 17 00:00:00 2001 From: Tony Cheng <tony.cheng@amd.com> Date: Tue, 8 May 2018 12:25:29 -0400 Subject: [PATCH 0731/1506] drm/amd/display: dal 3.1.49 Signed-off-by: Tony Cheng <tony.cheng@amd.com> Reviewed-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 82e0f55bc3e44..d1ac9676a5396 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.1.48" +#define DC_VER "3.1.49" #define MAX_SURFACES 3 #define MAX_STREAMS 6 -- GitLab From dc38fd9dac3e15538c7c238c4dfb98ceb408fa19 Mon Sep 17 00:00:00 2001 From: David Francis <David.Francis@amd.com> Date: Fri, 1 Jun 2018 09:49:06 -0400 Subject: [PATCH 0732/1506] drm/amd/display: Add front end for dp debugfs files As part of hardware certification, read-write access to the link rate, lane count, voltage swing, pre-emphasis, and PHY test pattern of DP connectors is required. This commit adds debugfs files that will correspond to these values. The file operations are not yet implemented: currently writing or reading them does nothing. Signed-off-by: David Francis <David.Francis@amd.com> Reviewed-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/display/amdgpu_dm/Makefile | 2 +- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 10 ++ .../amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 170 ++++++++++++++++++ .../amd/display/amdgpu_dm/amdgpu_dm_debugfs.h | 34 ++++ 4 files changed, 215 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.h diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile index af16973f2c412..589c60ec59bd2 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile @@ -32,7 +32,7 @@ AMDGPUDM += amdgpu_dm_services.o amdgpu_dm_helpers.o endif ifneq ($(CONFIG_DEBUG_FS),) -AMDGPUDM += amdgpu_dm_crc.o +AMDGPUDM += amdgpu_dm_crc.o amdgpu_dm_debugfs.o endif subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc 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 66bd3cc3e3875..356ac27d01802 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -39,6 +39,9 @@ #include "dm_helpers.h" #include "dm_services_types.h" #include "amdgpu_dm_mst_types.h" +#if defined(CONFIG_DEBUG_FS) +#include "amdgpu_dm_debugfs.h" +#endif #include "ivsrcid/ivsrcid_vislands30.h" @@ -3619,6 +3622,13 @@ static int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm, &aconnector->base, &aencoder->base); drm_connector_register(&aconnector->base); +#if defined(CONFIG_DEBUG_FS) + res = connector_debugfs_init(aconnector); + if (res) { + DRM_ERROR("Failed to create debugfs for connector"); + goto out_free; + } +#endif if (connector_type == DRM_MODE_CONNECTOR_DisplayPort || connector_type == DRM_MODE_CONNECTOR_eDP) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c new file mode 100644 index 0000000000000..cf5ea69e46ad3 --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -0,0 +1,170 @@ +/* + * Copyright 2018 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include <linux/debugfs.h> + +#include "dc.h" +#include "dc_link.h" + +#include "amdgpu.h" +#include "amdgpu_dm.h" +#include "amdgpu_dm_debugfs.h" + +static ssize_t dp_link_rate_debugfs_read(struct file *f, char __user *buf, + size_t size, loff_t *pos) +{ + /* TODO: create method to read link rate */ + return 1; +} + +static ssize_t dp_link_rate_debugfs_write(struct file *f, const char __user *buf, + size_t size, loff_t *pos) +{ + /* TODO: create method to write link rate */ + return 1; +} + +static ssize_t dp_lane_count_debugfs_read(struct file *f, char __user *buf, + size_t size, loff_t *pos) +{ + /* TODO: create method to read lane count */ + return 1; +} + +static ssize_t dp_lane_count_debugfs_write(struct file *f, const char __user *buf, + size_t size, loff_t *pos) +{ + /* TODO: create method to write lane count */ + return 1; +} + +static ssize_t dp_voltage_swing_debugfs_read(struct file *f, char __user *buf, + size_t size, loff_t *pos) +{ + /* TODO: create method to read voltage swing */ + return 1; +} + +static ssize_t dp_voltage_swing_debugfs_write(struct file *f, const char __user *buf, + size_t size, loff_t *pos) +{ + /* TODO: create method to write voltage swing */ + return 1; +} + +static ssize_t dp_pre_emphasis_debugfs_read(struct file *f, char __user *buf, + size_t size, loff_t *pos) +{ + /* TODO: create method to read pre-emphasis */ + return 1; +} + +static ssize_t dp_pre_emphasis_debugfs_write(struct file *f, const char __user *buf, + size_t size, loff_t *pos) +{ + /* TODO: create method to write pre-emphasis */ + return 1; +} + +static ssize_t dp_phy_test_pattern_debugfs_read(struct file *f, char __user *buf, + size_t size, loff_t *pos) +{ + /* TODO: create method to read PHY test pattern */ + return 1; +} + +static ssize_t dp_phy_test_pattern_debugfs_write(struct file *f, const char __user *buf, + size_t size, loff_t *pos) +{ + /* TODO: create method to write PHY test pattern */ + return 1; +} + +static const struct file_operations dp_link_rate_fops = { + .owner = THIS_MODULE, + .read = dp_link_rate_debugfs_read, + .write = dp_link_rate_debugfs_write, + .llseek = default_llseek +}; + +static const struct file_operations dp_lane_count_fops = { + .owner = THIS_MODULE, + .read = dp_lane_count_debugfs_read, + .write = dp_lane_count_debugfs_write, + .llseek = default_llseek +}; + +static const struct file_operations dp_voltage_swing_fops = { + .owner = THIS_MODULE, + .read = dp_voltage_swing_debugfs_read, + .write = dp_voltage_swing_debugfs_write, + .llseek = default_llseek +}; + +static const struct file_operations dp_pre_emphasis_fops = { + .owner = THIS_MODULE, + .read = dp_pre_emphasis_debugfs_read, + .write = dp_pre_emphasis_debugfs_write, + .llseek = default_llseek +}; + +static const struct file_operations dp_phy_test_pattern_fops = { + .owner = THIS_MODULE, + .read = dp_phy_test_pattern_debugfs_read, + .write = dp_phy_test_pattern_debugfs_write, + .llseek = default_llseek +}; + +static const struct { + char *name; + const struct file_operations *fops; +} dp_debugfs_entries[] = { + {"link_rate", &dp_link_rate_fops}, + {"lane_count", &dp_lane_count_fops}, + {"voltage_swing", &dp_voltage_swing_fops}, + {"pre_emphasis", &dp_pre_emphasis_fops}, + {"phy_test_pattern", &dp_phy_test_pattern_fops} +}; + +int connector_debugfs_init(struct amdgpu_dm_connector *connector) +{ + int i; + struct dentry *ent, *dir = connector->base.debugfs_entry; + + if (connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) { + for (i = 0; i < ARRAY_SIZE(dp_debugfs_entries); i++) { + ent = debugfs_create_file(dp_debugfs_entries[i].name, + 0644, + dir, + connector, + dp_debugfs_entries[i].fops); + if (IS_ERR(ent)) + return PTR_ERR(ent); + } + } + + return 0; +} + diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.h new file mode 100644 index 0000000000000..d9ed1b2aa8115 --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.h @@ -0,0 +1,34 @@ +/* + * Copyright 2018 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __AMDGPU_DM_DEBUGFS_H__ +#define __AMDGPU_DM_DEBUGFS_H__ + +#include "amdgpu.h" +#include "amdgpu_dm.h" + +int connector_debugfs_init(struct amdgpu_dm_connector *connector); + +#endif -- GitLab From 9f6e2842d0681a9a6579618a301c8ae06e20a6cd Mon Sep 17 00:00:00 2001 From: Tony Cheng <tony.cheng@amd.com> Date: Tue, 5 Jun 2018 09:13:56 -0400 Subject: [PATCH 0733/1506] drm/amd/display: dal 3.1.50 Signed-off-by: Tony Cheng <tony.cheng@amd.com> Reviewed-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index d1ac9676a5396..cdab7b0453c56 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.1.49" +#define DC_VER "3.1.50" #define MAX_SURFACES 3 #define MAX_STREAMS 6 -- GitLab From b9c1c67aeb8805015f02efb0a6a6ddf68ea8a4b4 Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Date: Tue, 5 Jun 2018 12:54:38 -0400 Subject: [PATCH 0734/1506] drm/amd/display: clean rq/dlg/ttu reg structs before calculations Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c | 4 ++++ drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c | 8 ++++++-- .../gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.c | 2 -- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c index b8195e5a06767..ac4451adeec9f 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c @@ -423,6 +423,10 @@ static void dcn_bw_calc_rq_dlg_ttu( int total_flip_bytes = 0; int i; + memset(dlg_regs, 0, sizeof(*dlg_regs)); + memset(ttu_regs, 0, sizeof(*ttu_regs)); + memset(rq_regs, 0, sizeof(*rq_regs)); + for (i = 0; i < number_of_planes; i++) { total_active_bw += v->read_bandwidth[i]; total_prefetch_bw += v->prefetch_bandwidth[i]; 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 7d9c10b6d99b6..cc12c4757f8b6 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 @@ -151,19 +151,23 @@ static void dcn10_log_hubp_states(struct dc *dc) DTN_INFO("\n=========RQ========\n"); DTN_INFO("HUBP: drq_exp_m prq_exp_m mrq_exp_m crq_exp_m plane1_ba L:chunk_s min_chu_s meta_ch_s" + " min_m_c_s dpte_gr_s mpte_gr_s swath_hei pte_row_h C:chunk_s min_chu_s meta_ch_s" " min_m_c_s dpte_gr_s mpte_gr_s swath_hei pte_row_h\n"); for (i = 0; i < pool->pipe_count; i++) { struct dcn_hubp_state *s = &(TO_DCN10_HUBP(pool->hubps[i])->state); struct _vcs_dpi_display_rq_regs_st *rq_regs = &s->rq_regs; if (!s->blank_en) - DTN_INFO("[%2d]: %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh\n", + DTN_INFO("[%2d]: %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh %8xh\n", pool->hubps[i]->inst, rq_regs->drq_expansion_mode, rq_regs->prq_expansion_mode, rq_regs->mrq_expansion_mode, rq_regs->crq_expansion_mode, rq_regs->plane1_base_address, rq_regs->rq_regs_l.chunk_size, rq_regs->rq_regs_l.min_chunk_size, rq_regs->rq_regs_l.meta_chunk_size, rq_regs->rq_regs_l.min_meta_chunk_size, rq_regs->rq_regs_l.dpte_group_size, rq_regs->rq_regs_l.mpte_group_size, rq_regs->rq_regs_l.swath_height, - rq_regs->rq_regs_l.pte_row_height_linear); + rq_regs->rq_regs_l.pte_row_height_linear, rq_regs->rq_regs_c.chunk_size, rq_regs->rq_regs_c.min_chunk_size, + rq_regs->rq_regs_c.meta_chunk_size, rq_regs->rq_regs_c.min_meta_chunk_size, + rq_regs->rq_regs_c.dpte_group_size, rq_regs->rq_regs_c.mpte_group_size, + rq_regs->rq_regs_c.swath_height, rq_regs->rq_regs_c.pte_row_height_linear); } DTN_INFO("========DLG========\n"); diff --git a/drivers/gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.c b/drivers/gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.c index 0efbf411667a5..c2037daa8e666 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.c @@ -239,8 +239,6 @@ void dml1_extract_rq_regs( extract_rq_sizing_regs(mode_lib, &(rq_regs->rq_regs_l), rq_param.sizing.rq_l); if (rq_param.yuv420) extract_rq_sizing_regs(mode_lib, &(rq_regs->rq_regs_c), rq_param.sizing.rq_c); - else - memset(&(rq_regs->rq_regs_c), 0, sizeof(rq_regs->rq_regs_c)); rq_regs->rq_regs_l.swath_height = dml_log2(rq_param.dlg.rq_l.swath_height); rq_regs->rq_regs_c.swath_height = dml_log2(rq_param.dlg.rq_c.swath_height); -- GitLab From d4fa93e03839c3e4e9d16020f1a3c78ae36c646a Mon Sep 17 00:00:00 2001 From: Tony Cheng <tony.cheng@amd.com> Date: Tue, 5 Jun 2018 09:14:22 -0400 Subject: [PATCH 0735/1506] drm/amd/display: dal 3.1.51 Signed-off-by: Tony Cheng <tony.cheng@amd.com> Reviewed-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index cdab7b0453c56..cbcdbd9b99100 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.1.50" +#define DC_VER "3.1.51" #define MAX_SURFACES 3 #define MAX_STREAMS 6 -- GitLab From 6f66ccf0aa8f6d430d161a1ac2bc43e665d2fc59 Mon Sep 17 00:00:00 2001 From: Roman Li <Roman.Li@amd.com> Date: Tue, 5 Jun 2018 14:24:53 -0400 Subject: [PATCH 0736/1506] drm/amd/display: fix potential infinite loop in fbc path - Fixing integer overflow bug in wait_for_fbc_state_changed() - Correct the max value of retries for the corresponding warning Signed-off-by: Roman Li <Roman.Li@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c index df027013e50c4..1f7f25013217d 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c @@ -143,7 +143,7 @@ static void wait_for_fbc_state_changed( struct dce110_compressor *cp110, bool enabled) { - uint16_t counter = 0; + uint32_t counter = 0; uint32_t addr = mmFBC_STATUS; uint32_t value; @@ -158,7 +158,7 @@ static void wait_for_fbc_state_changed( counter++; } - if (counter == 10) { + if (counter == 1000) { DC_LOG_WARNING("%s: wait counter exceeded, changes to HW not applied", __func__); } else { -- GitLab From 5094ffac6bd265130f735dd500532cef39f0d72f Mon Sep 17 00:00:00 2001 From: Mikita Lipski <mikita.lipski@amd.com> Date: Thu, 31 May 2018 14:49:00 -0400 Subject: [PATCH 0737/1506] drm/amd/display: Enable PPLib calls from DC on linux Set the powerplay debug flag to false for both Windows and Linux to allow the calls to pplib. So we can retrieve the clock values from powerplay instead of using default hardcoded values. Signed-off-by: Mikita Lipski <mikita.lipski@amd.com> Reviewed-by: Charlene Liu <Charlene.Liu@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c index b5a727f7e8800..1761e1a40dad8 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c @@ -437,7 +437,7 @@ static const struct dc_debug debug_defaults_drv = { */ .min_disp_clk_khz = 100000, - .disable_pplib_clock_request = true, + .disable_pplib_clock_request = false, .disable_pplib_wm_range = false, .pplib_wm_report_mode = WM_REPORT_DEFAULT, .pipe_split_policy = MPC_SPLIT_AVOID_MULT_DISP, -- GitLab From 015ec75918698e63f770c9bee0752ce802ed55e2 Mon Sep 17 00:00:00 2001 From: Mikita Lipski <mikita.lipski@amd.com> Date: Thu, 31 May 2018 17:31:14 -0400 Subject: [PATCH 0738/1506] drm/amd/display: Add dmpp clks types for conversion Add more cases for dm_pp clks translator into pp clks so we can pass the right structures to the powerplay. Use clks translator instead of massive switch statement. Signed-off-by: Mikita Lipski <mikita.lipski@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../display/amdgpu_dm/amdgpu_dm_services.c | 41 ++++++++----------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c index 0ac428299f5f2..a87a5946798c4 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c @@ -195,6 +195,21 @@ static enum amd_pp_clock_type dc_to_pp_clock_type( case DM_PP_CLOCK_TYPE_MEMORY_CLK: amd_pp_clk_type = amd_pp_mem_clock; break; + case DM_PP_CLOCK_TYPE_DCEFCLK: + amd_pp_clk_type = amd_pp_dcef_clock; + break; + case DM_PP_CLOCK_TYPE_DCFCLK: + amd_pp_clk_type = amd_pp_dcf_clock; + break; + case DM_PP_CLOCK_TYPE_PIXELCLK: + amd_pp_clk_type = amd_pp_pixel_clock; + break; + case DM_PP_CLOCK_TYPE_FCLK: + amd_pp_clk_type = amd_pp_f_clock; + break; + case DM_PP_CLOCK_TYPE_DISPLAYPHYCLK: + amd_pp_clk_type = amd_pp_dpp_clock; + break; default: DRM_ERROR("DM_PPLIB: invalid clock type: %d!\n", dm_pp_clk_type); @@ -424,32 +439,12 @@ bool dm_pp_apply_clock_for_voltage_request( struct amdgpu_device *adev = ctx->driver_context; struct pp_display_clock_request pp_clock_request = {0}; int ret = 0; - switch (clock_for_voltage_req->clk_type) { - case DM_PP_CLOCK_TYPE_DISPLAY_CLK: - pp_clock_request.clock_type = amd_pp_disp_clock; - break; - - case DM_PP_CLOCK_TYPE_DCEFCLK: - pp_clock_request.clock_type = amd_pp_dcef_clock; - break; - case DM_PP_CLOCK_TYPE_DCFCLK: - pp_clock_request.clock_type = amd_pp_dcf_clock; - break; - - case DM_PP_CLOCK_TYPE_PIXELCLK: - pp_clock_request.clock_type = amd_pp_pixel_clock; - break; - - case DM_PP_CLOCK_TYPE_FCLK: - pp_clock_request.clock_type = amd_pp_f_clock; - break; + pp_clock_request.clock_type = dc_to_pp_clock_type(clock_for_voltage_req->clk_type); + pp_clock_request.clock_freq_in_khz = clock_for_voltage_req->clocks_in_khz; - default: + if (!pp_clock_request.clock_type) return false; - } - - pp_clock_request.clock_freq_in_khz = clock_for_voltage_req->clocks_in_khz; if (adev->powerplay.pp_funcs->display_clock_voltage_request) ret = adev->powerplay.pp_funcs->display_clock_voltage_request( -- GitLab From 724a75524b1c77ea8abb96c21cdba05385b22b39 Mon Sep 17 00:00:00 2001 From: Mikita Lipski <mikita.lipski@amd.com> Date: Thu, 31 May 2018 14:44:18 -0400 Subject: [PATCH 0739/1506] drm/amd/display: Convert 10kHz clks from PPLib into kHz The driver is expecting clock frequency in kHz, while SMU returns the values in 10kHz, which causes the bandwidth validation to fail Signed-off-by: Mikita Lipski <mikita.lipski@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../amd/display/amdgpu_dm/amdgpu_dm_services.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c index a87a5946798c4..a19df20b557b3 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c @@ -267,8 +267,9 @@ static void pp_to_dc_clock_levels_with_latency( DC_DECODE_PP_CLOCK_TYPE(dc_clk_type)); for (i = 0; i < clk_level_info->num_levels; i++) { - DRM_DEBUG("DM_PPLIB:\t %d\n", pp_clks->data[i].clocks_in_khz); - clk_level_info->data[i].clocks_in_khz = pp_clks->data[i].clocks_in_khz; + DRM_DEBUG("DM_PPLIB:\t %d in 10kHz\n", pp_clks->data[i].clocks_in_khz); + /* translate 10kHz to kHz */ + clk_level_info->data[i].clocks_in_khz = pp_clks->data[i].clocks_in_khz * 10; clk_level_info->data[i].latency_in_us = pp_clks->data[i].latency_in_us; } } @@ -294,8 +295,9 @@ static void pp_to_dc_clock_levels_with_voltage( DC_DECODE_PP_CLOCK_TYPE(dc_clk_type)); for (i = 0; i < clk_level_info->num_levels; i++) { - DRM_INFO("DM_PPLIB:\t %d\n", pp_clks->data[i].clocks_in_khz); - clk_level_info->data[i].clocks_in_khz = pp_clks->data[i].clocks_in_khz; + DRM_INFO("DM_PPLIB:\t %d in 10kHz\n", pp_clks->data[i].clocks_in_khz); + /* translate 10kHz to kHz */ + clk_level_info->data[i].clocks_in_khz = pp_clks->data[i].clocks_in_khz * 10; clk_level_info->data[i].voltage_in_mv = pp_clks->data[i].voltage_in_mv; } } @@ -471,8 +473,9 @@ bool dm_pp_get_static_clocks( return false; static_clk_info->max_clocks_state = pp_clk_info.max_clocks_state; - static_clk_info->max_mclk_khz = pp_clk_info.max_memory_clock; - static_clk_info->max_sclk_khz = pp_clk_info.max_engine_clock; + /* translate 10kHz to kHz */ + static_clk_info->max_mclk_khz = pp_clk_info.max_memory_clock * 10; + static_clk_info->max_sclk_khz = pp_clk_info.max_engine_clock * 10; return true; } -- GitLab From 746c58ed225b9439a8272f755a1c60f795de9a3c Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Date: Tue, 5 Jun 2018 07:40:04 -0400 Subject: [PATCH 0740/1506] drm/amd/display: move dml defaults to respective dcn resource files Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../drm/amd/display/dc/dcn10/dcn10_resource.c | 62 ++++++++++++++++++ .../drm/amd/display/dc/dml/display_mode_lib.c | 63 +------------------ 2 files changed, 64 insertions(+), 61 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c index 1761e1a40dad8..2db08b99db561 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c @@ -65,6 +65,68 @@ #include "dce/dce_abm.h" #include "dce/dce_dmcu.h" +const struct _vcs_dpi_ip_params_st dcn1_0_ip = { + .rob_buffer_size_kbytes = 64, + .det_buffer_size_kbytes = 164, + .dpte_buffer_size_in_pte_reqs = 42, + .dpp_output_buffer_pixels = 2560, + .opp_output_buffer_lines = 1, + .pixel_chunk_size_kbytes = 8, + .pte_enable = 1, + .pte_chunk_size_kbytes = 2, + .meta_chunk_size_kbytes = 2, + .writeback_chunk_size_kbytes = 2, + .line_buffer_size_bits = 589824, + .max_line_buffer_lines = 12, + .IsLineBufferBppFixed = 0, + .LineBufferFixedBpp = -1, + .writeback_luma_buffer_size_kbytes = 12, + .writeback_chroma_buffer_size_kbytes = 8, + .max_num_dpp = 4, + .max_num_wb = 2, + .max_dchub_pscl_bw_pix_per_clk = 4, + .max_pscl_lb_bw_pix_per_clk = 2, + .max_lb_vscl_bw_pix_per_clk = 4, + .max_vscl_hscl_bw_pix_per_clk = 4, + .max_hscl_ratio = 4, + .max_vscl_ratio = 4, + .hscl_mults = 4, + .vscl_mults = 4, + .max_hscl_taps = 8, + .max_vscl_taps = 8, + .dispclk_ramp_margin_percent = 1, + .underscan_factor = 1.10, + .min_vblank_lines = 14, + .dppclk_delay_subtotal = 90, + .dispclk_delay_subtotal = 42, + .dcfclk_cstate_latency = 10, + .max_inter_dcn_tile_repeaters = 8, + .can_vstartup_lines_exceed_vsync_plus_back_porch_lines_minus_one = 0, + .bug_forcing_LC_req_same_size_fixed = 0, +}; + +const struct _vcs_dpi_soc_bounding_box_st dcn1_0_soc = { + .sr_exit_time_us = 9.0, + .sr_enter_plus_exit_time_us = 11.0, + .urgent_latency_us = 4.0, + .writeback_latency_us = 12.0, + .ideal_dram_bw_after_urgent_percent = 80.0, + .max_request_size_bytes = 256, + .downspread_percent = 0.5, + .dram_page_open_time_ns = 50.0, + .dram_rw_turnaround_time_ns = 17.5, + .dram_return_buffer_per_channel_bytes = 8192, + .round_trip_ping_latency_dcfclk_cycles = 128, + .urgent_out_of_order_return_per_channel_bytes = 256, + .channel_interleave_bytes = 256, + .num_banks = 8, + .num_chans = 2, + .vmm_page_size_bytes = 4096, + .dram_clock_change_latency_us = 17.0, + .writeback_dram_clock_change_latency_us = 23.0, + .return_bus_width_bytes = 64, +}; + #ifndef mmDP0_DP_DPHY_INTERNAL_CTRL #define mmDP0_DP_DPHY_INTERNAL_CTRL 0x210f #define mmDP0_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c b/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c index fd9d97aab0715..dddeb0d4db8f3 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c @@ -26,67 +26,8 @@ #include "display_mode_lib.h" #include "dc_features.h" -static const struct _vcs_dpi_ip_params_st dcn1_0_ip = { - .rob_buffer_size_kbytes = 64, - .det_buffer_size_kbytes = 164, - .dpte_buffer_size_in_pte_reqs = 42, - .dpp_output_buffer_pixels = 2560, - .opp_output_buffer_lines = 1, - .pixel_chunk_size_kbytes = 8, - .pte_enable = 1, - .pte_chunk_size_kbytes = 2, - .meta_chunk_size_kbytes = 2, - .writeback_chunk_size_kbytes = 2, - .line_buffer_size_bits = 589824, - .max_line_buffer_lines = 12, - .IsLineBufferBppFixed = 0, - .LineBufferFixedBpp = -1, - .writeback_luma_buffer_size_kbytes = 12, - .writeback_chroma_buffer_size_kbytes = 8, - .max_num_dpp = 4, - .max_num_wb = 2, - .max_dchub_pscl_bw_pix_per_clk = 4, - .max_pscl_lb_bw_pix_per_clk = 2, - .max_lb_vscl_bw_pix_per_clk = 4, - .max_vscl_hscl_bw_pix_per_clk = 4, - .max_hscl_ratio = 4, - .max_vscl_ratio = 4, - .hscl_mults = 4, - .vscl_mults = 4, - .max_hscl_taps = 8, - .max_vscl_taps = 8, - .dispclk_ramp_margin_percent = 1, - .underscan_factor = 1.10, - .min_vblank_lines = 14, - .dppclk_delay_subtotal = 90, - .dispclk_delay_subtotal = 42, - .dcfclk_cstate_latency = 10, - .max_inter_dcn_tile_repeaters = 8, - .can_vstartup_lines_exceed_vsync_plus_back_porch_lines_minus_one = 0, - .bug_forcing_LC_req_same_size_fixed = 0, -}; - -static const struct _vcs_dpi_soc_bounding_box_st dcn1_0_soc = { - .sr_exit_time_us = 9.0, - .sr_enter_plus_exit_time_us = 11.0, - .urgent_latency_us = 4.0, - .writeback_latency_us = 12.0, - .ideal_dram_bw_after_urgent_percent = 80.0, - .max_request_size_bytes = 256, - .downspread_percent = 0.5, - .dram_page_open_time_ns = 50.0, - .dram_rw_turnaround_time_ns = 17.5, - .dram_return_buffer_per_channel_bytes = 8192, - .round_trip_ping_latency_dcfclk_cycles = 128, - .urgent_out_of_order_return_per_channel_bytes = 256, - .channel_interleave_bytes = 256, - .num_banks = 8, - .num_chans = 2, - .vmm_page_size_bytes = 4096, - .dram_clock_change_latency_us = 17.0, - .writeback_dram_clock_change_latency_us = 23.0, - .return_bus_width_bytes = 64, -}; +extern const struct _vcs_dpi_ip_params_st dcn1_0_ip; +extern const struct _vcs_dpi_soc_bounding_box_st dcn1_0_soc; static void set_soc_bounding_box(struct _vcs_dpi_soc_bounding_box_st *soc, enum dml_project project) { -- GitLab From f7c1ed341ae0807e55fc583fbd5582ff4ef35a98 Mon Sep 17 00:00:00 2001 From: Mikita Lipski <mikita.lipski@amd.com> Date: Fri, 1 Jun 2018 15:02:55 -0400 Subject: [PATCH 0741/1506] drm/amd/display: Moving powerplay functions to a separate class Moving powerplay functions to a new amdgpu_dm_pp_smu class and cleaning dm_services class from unused headers. Signed-off-by: Mikita Lipski <mikita.lipski@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/display/amdgpu_dm/Makefile | 2 +- .../amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c | 525 ++++++++++++++++++ .../display/amdgpu_dm/amdgpu_dm_services.c | 492 ---------------- 3 files changed, 526 insertions(+), 493 deletions(-) create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile index 589c60ec59bd2..94911871eb9b5 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile @@ -28,7 +28,7 @@ AMDGPUDM = amdgpu_dm.o amdgpu_dm_irq.o amdgpu_dm_mst_types.o amdgpu_dm_color.o ifneq ($(CONFIG_DRM_AMD_DC),) -AMDGPUDM += amdgpu_dm_services.o amdgpu_dm_helpers.o +AMDGPUDM += amdgpu_dm_services.o amdgpu_dm_helpers.o amdgpu_dm_pp_smu.o endif ifneq ($(CONFIG_DEBUG_FS),) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c new file mode 100644 index 0000000000000..ad96e2a2b3cf3 --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c @@ -0,0 +1,525 @@ +/* + * Copyright 2018 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + */ +#include <linux/string.h> +#include <linux/acpi.h> + +#include <drm/drmP.h> +#include <drm/drm_crtc_helper.h> +#include <drm/amdgpu_drm.h> +#include "dm_services.h" +#include "amdgpu.h" +#include "amdgpu_dm.h" +#include "amdgpu_dm_irq.h" +#include "amdgpu_pm.h" +#include "dm_pp_smu.h" +#include "../../powerplay/inc/hwmgr.h" +#include "../../powerplay/hwmgr/smu10_hwmgr.h" + + +bool dm_pp_apply_display_requirements( + const struct dc_context *ctx, + const struct dm_pp_display_configuration *pp_display_cfg) +{ + struct amdgpu_device *adev = ctx->driver_context; + + if (adev->pm.dpm_enabled) { + + memset(&adev->pm.pm_display_cfg, 0, + sizeof(adev->pm.pm_display_cfg)); + + adev->pm.pm_display_cfg.cpu_cc6_disable = + pp_display_cfg->cpu_cc6_disable; + + adev->pm.pm_display_cfg.cpu_pstate_disable = + pp_display_cfg->cpu_pstate_disable; + + adev->pm.pm_display_cfg.cpu_pstate_separation_time = + pp_display_cfg->cpu_pstate_separation_time; + + adev->pm.pm_display_cfg.nb_pstate_switch_disable = + pp_display_cfg->nb_pstate_switch_disable; + + adev->pm.pm_display_cfg.num_display = + pp_display_cfg->display_count; + adev->pm.pm_display_cfg.num_path_including_non_display = + pp_display_cfg->display_count; + + adev->pm.pm_display_cfg.min_core_set_clock = + pp_display_cfg->min_engine_clock_khz/10; + adev->pm.pm_display_cfg.min_core_set_clock_in_sr = + pp_display_cfg->min_engine_clock_deep_sleep_khz/10; + adev->pm.pm_display_cfg.min_mem_set_clock = + pp_display_cfg->min_memory_clock_khz/10; + + adev->pm.pm_display_cfg.multi_monitor_in_sync = + pp_display_cfg->all_displays_in_sync; + adev->pm.pm_display_cfg.min_vblank_time = + pp_display_cfg->avail_mclk_switch_time_us; + + adev->pm.pm_display_cfg.display_clk = + pp_display_cfg->disp_clk_khz/10; + + adev->pm.pm_display_cfg.dce_tolerable_mclk_in_active_latency = + pp_display_cfg->avail_mclk_switch_time_in_disp_active_us; + + adev->pm.pm_display_cfg.crtc_index = pp_display_cfg->crtc_index; + adev->pm.pm_display_cfg.line_time_in_us = + pp_display_cfg->line_time_in_us; + + adev->pm.pm_display_cfg.vrefresh = pp_display_cfg->disp_configs[0].v_refresh; + adev->pm.pm_display_cfg.crossfire_display_index = -1; + adev->pm.pm_display_cfg.min_bus_bandwidth = 0; + + /* TODO: complete implementation of + * pp_display_configuration_change(). + * Follow example of: + * PHM_StoreDALConfigurationData - powerplay\hwmgr\hardwaremanager.c + * PP_IRI_DisplayConfigurationChange - powerplay\eventmgr\iri.c */ + if (adev->powerplay.pp_funcs->display_configuration_change) + adev->powerplay.pp_funcs->display_configuration_change( + adev->powerplay.pp_handle, + &adev->pm.pm_display_cfg); + + /* TODO: replace by a separate call to 'apply display cfg'? */ + amdgpu_pm_compute_clocks(adev); + } + + return true; +} + +static void get_default_clock_levels( + enum dm_pp_clock_type clk_type, + struct dm_pp_clock_levels *clks) +{ + uint32_t disp_clks_in_khz[6] = { + 300000, 400000, 496560, 626090, 685720, 757900 }; + uint32_t sclks_in_khz[6] = { + 300000, 360000, 423530, 514290, 626090, 720000 }; + uint32_t mclks_in_khz[2] = { 333000, 800000 }; + + switch (clk_type) { + case DM_PP_CLOCK_TYPE_DISPLAY_CLK: + clks->num_levels = 6; + memmove(clks->clocks_in_khz, disp_clks_in_khz, + sizeof(disp_clks_in_khz)); + break; + case DM_PP_CLOCK_TYPE_ENGINE_CLK: + clks->num_levels = 6; + memmove(clks->clocks_in_khz, sclks_in_khz, + sizeof(sclks_in_khz)); + break; + case DM_PP_CLOCK_TYPE_MEMORY_CLK: + clks->num_levels = 2; + memmove(clks->clocks_in_khz, mclks_in_khz, + sizeof(mclks_in_khz)); + break; + default: + clks->num_levels = 0; + break; + } +} + +static enum amd_pp_clock_type dc_to_pp_clock_type( + enum dm_pp_clock_type dm_pp_clk_type) +{ + enum amd_pp_clock_type amd_pp_clk_type = 0; + + switch (dm_pp_clk_type) { + case DM_PP_CLOCK_TYPE_DISPLAY_CLK: + amd_pp_clk_type = amd_pp_disp_clock; + break; + case DM_PP_CLOCK_TYPE_ENGINE_CLK: + amd_pp_clk_type = amd_pp_sys_clock; + break; + case DM_PP_CLOCK_TYPE_MEMORY_CLK: + amd_pp_clk_type = amd_pp_mem_clock; + break; + case DM_PP_CLOCK_TYPE_DCEFCLK: + amd_pp_clk_type = amd_pp_dcef_clock; + break; + case DM_PP_CLOCK_TYPE_DCFCLK: + amd_pp_clk_type = amd_pp_dcf_clock; + break; + case DM_PP_CLOCK_TYPE_PIXELCLK: + amd_pp_clk_type = amd_pp_pixel_clock; + break; + case DM_PP_CLOCK_TYPE_FCLK: + amd_pp_clk_type = amd_pp_f_clock; + break; + case DM_PP_CLOCK_TYPE_DISPLAYPHYCLK: + amd_pp_clk_type = amd_pp_dpp_clock; + break; + default: + DRM_ERROR("DM_PPLIB: invalid clock type: %d!\n", + dm_pp_clk_type); + break; + } + + return amd_pp_clk_type; +} + +static void pp_to_dc_clock_levels( + const struct amd_pp_clocks *pp_clks, + struct dm_pp_clock_levels *dc_clks, + enum dm_pp_clock_type dc_clk_type) +{ + uint32_t i; + + if (pp_clks->count > DM_PP_MAX_CLOCK_LEVELS) { + DRM_INFO("DM_PPLIB: Warning: %s clock: number of levels %d exceeds maximum of %d!\n", + DC_DECODE_PP_CLOCK_TYPE(dc_clk_type), + pp_clks->count, + DM_PP_MAX_CLOCK_LEVELS); + + dc_clks->num_levels = DM_PP_MAX_CLOCK_LEVELS; + } else + dc_clks->num_levels = pp_clks->count; + + DRM_INFO("DM_PPLIB: values for %s clock\n", + DC_DECODE_PP_CLOCK_TYPE(dc_clk_type)); + + for (i = 0; i < dc_clks->num_levels; i++) { + DRM_INFO("DM_PPLIB:\t %d\n", pp_clks->clock[i]); + /* translate 10kHz to kHz */ + dc_clks->clocks_in_khz[i] = pp_clks->clock[i] * 10; + } +} + +static void pp_to_dc_clock_levels_with_latency( + const struct pp_clock_levels_with_latency *pp_clks, + struct dm_pp_clock_levels_with_latency *clk_level_info, + enum dm_pp_clock_type dc_clk_type) +{ + uint32_t i; + + if (pp_clks->num_levels > DM_PP_MAX_CLOCK_LEVELS) { + DRM_INFO("DM_PPLIB: Warning: %s clock: number of levels %d exceeds maximum of %d!\n", + DC_DECODE_PP_CLOCK_TYPE(dc_clk_type), + pp_clks->num_levels, + DM_PP_MAX_CLOCK_LEVELS); + + clk_level_info->num_levels = DM_PP_MAX_CLOCK_LEVELS; + } else + clk_level_info->num_levels = pp_clks->num_levels; + + DRM_DEBUG("DM_PPLIB: values for %s clock\n", + DC_DECODE_PP_CLOCK_TYPE(dc_clk_type)); + + for (i = 0; i < clk_level_info->num_levels; i++) { + DRM_DEBUG("DM_PPLIB:\t %d in 10kHz\n", pp_clks->data[i].clocks_in_khz); + /* translate 10kHz to kHz */ + clk_level_info->data[i].clocks_in_khz = pp_clks->data[i].clocks_in_khz * 10; + clk_level_info->data[i].latency_in_us = pp_clks->data[i].latency_in_us; + } +} + +static void pp_to_dc_clock_levels_with_voltage( + const struct pp_clock_levels_with_voltage *pp_clks, + struct dm_pp_clock_levels_with_voltage *clk_level_info, + enum dm_pp_clock_type dc_clk_type) +{ + uint32_t i; + + if (pp_clks->num_levels > DM_PP_MAX_CLOCK_LEVELS) { + DRM_INFO("DM_PPLIB: Warning: %s clock: number of levels %d exceeds maximum of %d!\n", + DC_DECODE_PP_CLOCK_TYPE(dc_clk_type), + pp_clks->num_levels, + DM_PP_MAX_CLOCK_LEVELS); + + clk_level_info->num_levels = DM_PP_MAX_CLOCK_LEVELS; + } else + clk_level_info->num_levels = pp_clks->num_levels; + + DRM_INFO("DM_PPLIB: values for %s clock\n", + DC_DECODE_PP_CLOCK_TYPE(dc_clk_type)); + + for (i = 0; i < clk_level_info->num_levels; i++) { + DRM_INFO("DM_PPLIB:\t %d in 10kHz\n", pp_clks->data[i].clocks_in_khz); + /* translate 10kHz to kHz */ + clk_level_info->data[i].clocks_in_khz = pp_clks->data[i].clocks_in_khz * 10; + clk_level_info->data[i].voltage_in_mv = pp_clks->data[i].voltage_in_mv; + } +} + +bool dm_pp_get_clock_levels_by_type( + const struct dc_context *ctx, + enum dm_pp_clock_type clk_type, + struct dm_pp_clock_levels *dc_clks) +{ + struct amdgpu_device *adev = ctx->driver_context; + void *pp_handle = adev->powerplay.pp_handle; + struct amd_pp_clocks pp_clks = { 0 }; + struct amd_pp_simple_clock_info validation_clks = { 0 }; + uint32_t i; + + if (adev->powerplay.pp_funcs->get_clock_by_type) { + if (adev->powerplay.pp_funcs->get_clock_by_type(pp_handle, + dc_to_pp_clock_type(clk_type), &pp_clks)) { + /* Error in pplib. Provide default values. */ + get_default_clock_levels(clk_type, dc_clks); + return true; + } + } + + pp_to_dc_clock_levels(&pp_clks, dc_clks, clk_type); + + if (adev->powerplay.pp_funcs->get_display_mode_validation_clocks) { + if (adev->powerplay.pp_funcs->get_display_mode_validation_clocks( + pp_handle, &validation_clks)) { + /* Error in pplib. Provide default values. */ + DRM_INFO("DM_PPLIB: Warning: using default validation clocks!\n"); + validation_clks.engine_max_clock = 72000; + validation_clks.memory_max_clock = 80000; + validation_clks.level = 0; + } + } + + DRM_INFO("DM_PPLIB: Validation clocks:\n"); + DRM_INFO("DM_PPLIB: engine_max_clock: %d\n", + validation_clks.engine_max_clock); + DRM_INFO("DM_PPLIB: memory_max_clock: %d\n", + validation_clks.memory_max_clock); + DRM_INFO("DM_PPLIB: level : %d\n", + validation_clks.level); + + /* Translate 10 kHz to kHz. */ + validation_clks.engine_max_clock *= 10; + validation_clks.memory_max_clock *= 10; + + /* Determine the highest non-boosted level from the Validation Clocks */ + if (clk_type == DM_PP_CLOCK_TYPE_ENGINE_CLK) { + for (i = 0; i < dc_clks->num_levels; i++) { + if (dc_clks->clocks_in_khz[i] > validation_clks.engine_max_clock) { + /* This clock is higher the validation clock. + * Than means the previous one is the highest + * non-boosted one. */ + DRM_INFO("DM_PPLIB: reducing engine clock level from %d to %d\n", + dc_clks->num_levels, i); + dc_clks->num_levels = i > 0 ? i : 1; + break; + } + } + } else if (clk_type == DM_PP_CLOCK_TYPE_MEMORY_CLK) { + for (i = 0; i < dc_clks->num_levels; i++) { + if (dc_clks->clocks_in_khz[i] > validation_clks.memory_max_clock) { + DRM_INFO("DM_PPLIB: reducing memory clock level from %d to %d\n", + dc_clks->num_levels, i); + dc_clks->num_levels = i > 0 ? i : 1; + break; + } + } + } + + return true; +} + +bool dm_pp_get_clock_levels_by_type_with_latency( + const struct dc_context *ctx, + enum dm_pp_clock_type clk_type, + struct dm_pp_clock_levels_with_latency *clk_level_info) +{ + struct amdgpu_device *adev = ctx->driver_context; + void *pp_handle = adev->powerplay.pp_handle; + struct pp_clock_levels_with_latency pp_clks = { 0 }; + const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + + if (!pp_funcs || !pp_funcs->get_clock_by_type_with_latency) + return false; + + if (pp_funcs->get_clock_by_type_with_latency(pp_handle, + dc_to_pp_clock_type(clk_type), + &pp_clks)) + return false; + + pp_to_dc_clock_levels_with_latency(&pp_clks, clk_level_info, clk_type); + + return true; +} + +bool dm_pp_get_clock_levels_by_type_with_voltage( + const struct dc_context *ctx, + enum dm_pp_clock_type clk_type, + struct dm_pp_clock_levels_with_voltage *clk_level_info) +{ + struct amdgpu_device *adev = ctx->driver_context; + void *pp_handle = adev->powerplay.pp_handle; + struct pp_clock_levels_with_voltage pp_clk_info = {0}; + const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + + if (pp_funcs->get_clock_by_type_with_voltage(pp_handle, + dc_to_pp_clock_type(clk_type), + &pp_clk_info)) + return false; + + pp_to_dc_clock_levels_with_voltage(&pp_clk_info, clk_level_info, clk_type); + + return true; +} + +bool dm_pp_notify_wm_clock_changes( + const struct dc_context *ctx, + struct dm_pp_wm_sets_with_clock_ranges *wm_with_clock_ranges) +{ + /* TODO: to be implemented */ + return false; +} + +bool dm_pp_apply_power_level_change_request( + const struct dc_context *ctx, + struct dm_pp_power_level_change_request *level_change_req) +{ + /* TODO: to be implemented */ + return false; +} + +bool dm_pp_apply_clock_for_voltage_request( + const struct dc_context *ctx, + struct dm_pp_clock_for_voltage_req *clock_for_voltage_req) +{ + struct amdgpu_device *adev = ctx->driver_context; + struct pp_display_clock_request pp_clock_request = {0}; + int ret = 0; + + pp_clock_request.clock_type = dc_to_pp_clock_type(clock_for_voltage_req->clk_type); + pp_clock_request.clock_freq_in_khz = clock_for_voltage_req->clocks_in_khz; + + if (!pp_clock_request.clock_type) + return false; + + if (adev->powerplay.pp_funcs->display_clock_voltage_request) + ret = adev->powerplay.pp_funcs->display_clock_voltage_request( + adev->powerplay.pp_handle, + &pp_clock_request); + if (ret) + return false; + return true; +} + +bool dm_pp_get_static_clocks( + const struct dc_context *ctx, + struct dm_pp_static_clock_info *static_clk_info) +{ + struct amdgpu_device *adev = ctx->driver_context; + struct amd_pp_clock_info pp_clk_info = {0}; + int ret = 0; + + if (adev->powerplay.pp_funcs->get_current_clocks) + ret = adev->powerplay.pp_funcs->get_current_clocks( + adev->powerplay.pp_handle, + &pp_clk_info); + if (ret) + return false; + + static_clk_info->max_clocks_state = pp_clk_info.max_clocks_state; + /* translate 10kHz to kHz */ + static_clk_info->max_mclk_khz = pp_clk_info.max_memory_clock * 10; + static_clk_info->max_sclk_khz = pp_clk_info.max_engine_clock * 10; + + return true; +} + +void pp_rv_set_display_requirement(struct pp_smu *pp, + struct pp_smu_display_requirement_rv *req) +{ + struct amdgpu_device *adev = pp->ctx->driver_context; + struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; + int ret = 0; + if (hwmgr->hwmgr_func->set_deep_sleep_dcefclk) + ret = hwmgr->hwmgr_func->set_deep_sleep_dcefclk(hwmgr, req->hard_min_dcefclk_khz/10); + if (hwmgr->hwmgr_func->set_active_display_count) + ret = hwmgr->hwmgr_func->set_active_display_count(hwmgr, req->display_count); + + //store_cc6 is not yet implemented in SMU level +} + +void pp_rv_set_wm_ranges(struct pp_smu *pp, + struct pp_smu_wm_range_sets *ranges) +{ + struct amdgpu_device *adev = pp->ctx->driver_context; + struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; + struct pp_wm_sets_with_clock_ranges_soc15 ranges_soc15 = {0}; + int i = 0; + + if (!hwmgr->hwmgr_func->set_watermarks_for_clocks_ranges || + !pp || !ranges) + return; + + //not entirely sure if thats a correct assignment + ranges_soc15.num_wm_sets_dmif = ranges->num_reader_wm_sets; + ranges_soc15.num_wm_sets_mcif = ranges->num_writer_wm_sets; + + for (i = 0; i < ranges_soc15.num_wm_sets_dmif; i++) { + if (ranges->reader_wm_sets[i].wm_inst > 3) + ranges_soc15.wm_sets_dmif[i].wm_set_id = DC_WM_SET_A; + else + ranges_soc15.wm_sets_dmif[i].wm_set_id = + ranges->reader_wm_sets[i].wm_inst; + ranges_soc15.wm_sets_dmif[i].wm_max_dcefclk_in_khz = + ranges->reader_wm_sets[i].max_drain_clk_khz; + ranges_soc15.wm_sets_dmif[i].wm_min_dcefclk_in_khz = + ranges->reader_wm_sets[i].min_drain_clk_khz; + ranges_soc15.wm_sets_dmif[i].wm_max_memclk_in_khz = + ranges->reader_wm_sets[i].max_fill_clk_khz; + ranges_soc15.wm_sets_dmif[i].wm_min_memclk_in_khz = + ranges->reader_wm_sets[i].min_fill_clk_khz; + } + + for (i = 0; i < ranges_soc15.num_wm_sets_mcif; i++) { + if (ranges->writer_wm_sets[i].wm_inst > 3) + ranges_soc15.wm_sets_dmif[i].wm_set_id = DC_WM_SET_A; + else + ranges_soc15.wm_sets_mcif[i].wm_set_id = + ranges->writer_wm_sets[i].wm_inst; + ranges_soc15.wm_sets_mcif[i].wm_max_socclk_in_khz = + ranges->writer_wm_sets[i].max_fill_clk_khz; + ranges_soc15.wm_sets_mcif[i].wm_min_socclk_in_khz = + ranges->writer_wm_sets[i].min_fill_clk_khz; + ranges_soc15.wm_sets_mcif[i].wm_max_memclk_in_khz = + ranges->writer_wm_sets[i].max_fill_clk_khz; + ranges_soc15.wm_sets_mcif[i].wm_min_memclk_in_khz = + ranges->writer_wm_sets[i].min_fill_clk_khz; + } + + hwmgr->hwmgr_func->set_watermarks_for_clocks_ranges(hwmgr, &ranges_soc15); + +} + +void pp_rv_set_pme_wa_enable(struct pp_smu *pp) +{ + struct amdgpu_device *adev = pp->ctx->driver_context; + struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; + + if (hwmgr->hwmgr_func->smus_notify_pwe) + hwmgr->hwmgr_func->smus_notify_pwe(hwmgr); +} + +void dm_pp_get_funcs_rv( + struct dc_context *ctx, + struct pp_smu_funcs_rv *funcs) +{ + funcs->pp_smu.ctx = ctx; + funcs->set_display_requirement = pp_rv_set_display_requirement; + funcs->set_wm_ranges = pp_rv_set_wm_ranges; + funcs->set_pme_wa_enable = pp_rv_set_pme_wa_enable; +} diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c index a19df20b557b3..9f0a217603ad0 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c @@ -34,9 +34,6 @@ #include "amdgpu_dm.h" #include "amdgpu_dm_irq.h" #include "amdgpu_pm.h" -#include "dm_pp_smu.h" -#include "../../powerplay/inc/hwmgr.h" -#include "../../powerplay/hwmgr/smu10_hwmgr.h" @@ -77,493 +74,4 @@ bool dm_read_persistent_data(struct dc_context *ctx, /**** power component interfaces ****/ -bool dm_pp_apply_display_requirements( - const struct dc_context *ctx, - const struct dm_pp_display_configuration *pp_display_cfg) -{ - struct amdgpu_device *adev = ctx->driver_context; - - if (adev->pm.dpm_enabled) { - - memset(&adev->pm.pm_display_cfg, 0, - sizeof(adev->pm.pm_display_cfg)); - - adev->pm.pm_display_cfg.cpu_cc6_disable = - pp_display_cfg->cpu_cc6_disable; - - adev->pm.pm_display_cfg.cpu_pstate_disable = - pp_display_cfg->cpu_pstate_disable; - - adev->pm.pm_display_cfg.cpu_pstate_separation_time = - pp_display_cfg->cpu_pstate_separation_time; - - adev->pm.pm_display_cfg.nb_pstate_switch_disable = - pp_display_cfg->nb_pstate_switch_disable; - - adev->pm.pm_display_cfg.num_display = - pp_display_cfg->display_count; - adev->pm.pm_display_cfg.num_path_including_non_display = - pp_display_cfg->display_count; - - adev->pm.pm_display_cfg.min_core_set_clock = - pp_display_cfg->min_engine_clock_khz/10; - adev->pm.pm_display_cfg.min_core_set_clock_in_sr = - pp_display_cfg->min_engine_clock_deep_sleep_khz/10; - adev->pm.pm_display_cfg.min_mem_set_clock = - pp_display_cfg->min_memory_clock_khz/10; - - adev->pm.pm_display_cfg.multi_monitor_in_sync = - pp_display_cfg->all_displays_in_sync; - adev->pm.pm_display_cfg.min_vblank_time = - pp_display_cfg->avail_mclk_switch_time_us; - - adev->pm.pm_display_cfg.display_clk = - pp_display_cfg->disp_clk_khz/10; - - adev->pm.pm_display_cfg.dce_tolerable_mclk_in_active_latency = - pp_display_cfg->avail_mclk_switch_time_in_disp_active_us; - - adev->pm.pm_display_cfg.crtc_index = pp_display_cfg->crtc_index; - adev->pm.pm_display_cfg.line_time_in_us = - pp_display_cfg->line_time_in_us; - - adev->pm.pm_display_cfg.vrefresh = pp_display_cfg->disp_configs[0].v_refresh; - adev->pm.pm_display_cfg.crossfire_display_index = -1; - adev->pm.pm_display_cfg.min_bus_bandwidth = 0; - - /* TODO: complete implementation of - * pp_display_configuration_change(). - * Follow example of: - * PHM_StoreDALConfigurationData - powerplay\hwmgr\hardwaremanager.c - * PP_IRI_DisplayConfigurationChange - powerplay\eventmgr\iri.c */ - if (adev->powerplay.pp_funcs->display_configuration_change) - adev->powerplay.pp_funcs->display_configuration_change( - adev->powerplay.pp_handle, - &adev->pm.pm_display_cfg); - - /* TODO: replace by a separate call to 'apply display cfg'? */ - amdgpu_pm_compute_clocks(adev); - } - - return true; -} - -static void get_default_clock_levels( - enum dm_pp_clock_type clk_type, - struct dm_pp_clock_levels *clks) -{ - uint32_t disp_clks_in_khz[6] = { - 300000, 400000, 496560, 626090, 685720, 757900 }; - uint32_t sclks_in_khz[6] = { - 300000, 360000, 423530, 514290, 626090, 720000 }; - uint32_t mclks_in_khz[2] = { 333000, 800000 }; - - switch (clk_type) { - case DM_PP_CLOCK_TYPE_DISPLAY_CLK: - clks->num_levels = 6; - memmove(clks->clocks_in_khz, disp_clks_in_khz, - sizeof(disp_clks_in_khz)); - break; - case DM_PP_CLOCK_TYPE_ENGINE_CLK: - clks->num_levels = 6; - memmove(clks->clocks_in_khz, sclks_in_khz, - sizeof(sclks_in_khz)); - break; - case DM_PP_CLOCK_TYPE_MEMORY_CLK: - clks->num_levels = 2; - memmove(clks->clocks_in_khz, mclks_in_khz, - sizeof(mclks_in_khz)); - break; - default: - clks->num_levels = 0; - break; - } -} - -static enum amd_pp_clock_type dc_to_pp_clock_type( - enum dm_pp_clock_type dm_pp_clk_type) -{ - enum amd_pp_clock_type amd_pp_clk_type = 0; - - switch (dm_pp_clk_type) { - case DM_PP_CLOCK_TYPE_DISPLAY_CLK: - amd_pp_clk_type = amd_pp_disp_clock; - break; - case DM_PP_CLOCK_TYPE_ENGINE_CLK: - amd_pp_clk_type = amd_pp_sys_clock; - break; - case DM_PP_CLOCK_TYPE_MEMORY_CLK: - amd_pp_clk_type = amd_pp_mem_clock; - break; - case DM_PP_CLOCK_TYPE_DCEFCLK: - amd_pp_clk_type = amd_pp_dcef_clock; - break; - case DM_PP_CLOCK_TYPE_DCFCLK: - amd_pp_clk_type = amd_pp_dcf_clock; - break; - case DM_PP_CLOCK_TYPE_PIXELCLK: - amd_pp_clk_type = amd_pp_pixel_clock; - break; - case DM_PP_CLOCK_TYPE_FCLK: - amd_pp_clk_type = amd_pp_f_clock; - break; - case DM_PP_CLOCK_TYPE_DISPLAYPHYCLK: - amd_pp_clk_type = amd_pp_dpp_clock; - break; - default: - DRM_ERROR("DM_PPLIB: invalid clock type: %d!\n", - dm_pp_clk_type); - break; - } - - return amd_pp_clk_type; -} - -static void pp_to_dc_clock_levels( - const struct amd_pp_clocks *pp_clks, - struct dm_pp_clock_levels *dc_clks, - enum dm_pp_clock_type dc_clk_type) -{ - uint32_t i; - - if (pp_clks->count > DM_PP_MAX_CLOCK_LEVELS) { - DRM_INFO("DM_PPLIB: Warning: %s clock: number of levels %d exceeds maximum of %d!\n", - DC_DECODE_PP_CLOCK_TYPE(dc_clk_type), - pp_clks->count, - DM_PP_MAX_CLOCK_LEVELS); - - dc_clks->num_levels = DM_PP_MAX_CLOCK_LEVELS; - } else - dc_clks->num_levels = pp_clks->count; - - DRM_INFO("DM_PPLIB: values for %s clock\n", - DC_DECODE_PP_CLOCK_TYPE(dc_clk_type)); - - for (i = 0; i < dc_clks->num_levels; i++) { - DRM_INFO("DM_PPLIB:\t %d\n", pp_clks->clock[i]); - /* translate 10kHz to kHz */ - dc_clks->clocks_in_khz[i] = pp_clks->clock[i] * 10; - } -} - -static void pp_to_dc_clock_levels_with_latency( - const struct pp_clock_levels_with_latency *pp_clks, - struct dm_pp_clock_levels_with_latency *clk_level_info, - enum dm_pp_clock_type dc_clk_type) -{ - uint32_t i; - - if (pp_clks->num_levels > DM_PP_MAX_CLOCK_LEVELS) { - DRM_INFO("DM_PPLIB: Warning: %s clock: number of levels %d exceeds maximum of %d!\n", - DC_DECODE_PP_CLOCK_TYPE(dc_clk_type), - pp_clks->num_levels, - DM_PP_MAX_CLOCK_LEVELS); - - clk_level_info->num_levels = DM_PP_MAX_CLOCK_LEVELS; - } else - clk_level_info->num_levels = pp_clks->num_levels; - - DRM_DEBUG("DM_PPLIB: values for %s clock\n", - DC_DECODE_PP_CLOCK_TYPE(dc_clk_type)); - - for (i = 0; i < clk_level_info->num_levels; i++) { - DRM_DEBUG("DM_PPLIB:\t %d in 10kHz\n", pp_clks->data[i].clocks_in_khz); - /* translate 10kHz to kHz */ - clk_level_info->data[i].clocks_in_khz = pp_clks->data[i].clocks_in_khz * 10; - clk_level_info->data[i].latency_in_us = pp_clks->data[i].latency_in_us; - } -} - -static void pp_to_dc_clock_levels_with_voltage( - const struct pp_clock_levels_with_voltage *pp_clks, - struct dm_pp_clock_levels_with_voltage *clk_level_info, - enum dm_pp_clock_type dc_clk_type) -{ - uint32_t i; - - if (pp_clks->num_levels > DM_PP_MAX_CLOCK_LEVELS) { - DRM_INFO("DM_PPLIB: Warning: %s clock: number of levels %d exceeds maximum of %d!\n", - DC_DECODE_PP_CLOCK_TYPE(dc_clk_type), - pp_clks->num_levels, - DM_PP_MAX_CLOCK_LEVELS); - - clk_level_info->num_levels = DM_PP_MAX_CLOCK_LEVELS; - } else - clk_level_info->num_levels = pp_clks->num_levels; - - DRM_INFO("DM_PPLIB: values for %s clock\n", - DC_DECODE_PP_CLOCK_TYPE(dc_clk_type)); - - for (i = 0; i < clk_level_info->num_levels; i++) { - DRM_INFO("DM_PPLIB:\t %d in 10kHz\n", pp_clks->data[i].clocks_in_khz); - /* translate 10kHz to kHz */ - clk_level_info->data[i].clocks_in_khz = pp_clks->data[i].clocks_in_khz * 10; - clk_level_info->data[i].voltage_in_mv = pp_clks->data[i].voltage_in_mv; - } -} - - -bool dm_pp_get_clock_levels_by_type( - const struct dc_context *ctx, - enum dm_pp_clock_type clk_type, - struct dm_pp_clock_levels *dc_clks) -{ - struct amdgpu_device *adev = ctx->driver_context; - void *pp_handle = adev->powerplay.pp_handle; - struct amd_pp_clocks pp_clks = { 0 }; - struct amd_pp_simple_clock_info validation_clks = { 0 }; - uint32_t i; - - if (adev->powerplay.pp_funcs->get_clock_by_type) { - if (adev->powerplay.pp_funcs->get_clock_by_type(pp_handle, - dc_to_pp_clock_type(clk_type), &pp_clks)) { - /* Error in pplib. Provide default values. */ - get_default_clock_levels(clk_type, dc_clks); - return true; - } - } - - pp_to_dc_clock_levels(&pp_clks, dc_clks, clk_type); - - if (adev->powerplay.pp_funcs->get_display_mode_validation_clocks) { - if (adev->powerplay.pp_funcs->get_display_mode_validation_clocks( - pp_handle, &validation_clks)) { - /* Error in pplib. Provide default values. */ - DRM_INFO("DM_PPLIB: Warning: using default validation clocks!\n"); - validation_clks.engine_max_clock = 72000; - validation_clks.memory_max_clock = 80000; - validation_clks.level = 0; - } - } - - DRM_INFO("DM_PPLIB: Validation clocks:\n"); - DRM_INFO("DM_PPLIB: engine_max_clock: %d\n", - validation_clks.engine_max_clock); - DRM_INFO("DM_PPLIB: memory_max_clock: %d\n", - validation_clks.memory_max_clock); - DRM_INFO("DM_PPLIB: level : %d\n", - validation_clks.level); - - /* Translate 10 kHz to kHz. */ - validation_clks.engine_max_clock *= 10; - validation_clks.memory_max_clock *= 10; - - /* Determine the highest non-boosted level from the Validation Clocks */ - if (clk_type == DM_PP_CLOCK_TYPE_ENGINE_CLK) { - for (i = 0; i < dc_clks->num_levels; i++) { - if (dc_clks->clocks_in_khz[i] > validation_clks.engine_max_clock) { - /* This clock is higher the validation clock. - * Than means the previous one is the highest - * non-boosted one. */ - DRM_INFO("DM_PPLIB: reducing engine clock level from %d to %d\n", - dc_clks->num_levels, i); - dc_clks->num_levels = i > 0 ? i : 1; - break; - } - } - } else if (clk_type == DM_PP_CLOCK_TYPE_MEMORY_CLK) { - for (i = 0; i < dc_clks->num_levels; i++) { - if (dc_clks->clocks_in_khz[i] > validation_clks.memory_max_clock) { - DRM_INFO("DM_PPLIB: reducing memory clock level from %d to %d\n", - dc_clks->num_levels, i); - dc_clks->num_levels = i > 0 ? i : 1; - break; - } - } - } - - return true; -} - -bool dm_pp_get_clock_levels_by_type_with_latency( - const struct dc_context *ctx, - enum dm_pp_clock_type clk_type, - struct dm_pp_clock_levels_with_latency *clk_level_info) -{ - struct amdgpu_device *adev = ctx->driver_context; - void *pp_handle = adev->powerplay.pp_handle; - struct pp_clock_levels_with_latency pp_clks = { 0 }; - const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; - - if (!pp_funcs || !pp_funcs->get_clock_by_type_with_latency) - return false; - - if (pp_funcs->get_clock_by_type_with_latency(pp_handle, - dc_to_pp_clock_type(clk_type), - &pp_clks)) - return false; - - pp_to_dc_clock_levels_with_latency(&pp_clks, clk_level_info, clk_type); - - return true; -} - -bool dm_pp_get_clock_levels_by_type_with_voltage( - const struct dc_context *ctx, - enum dm_pp_clock_type clk_type, - struct dm_pp_clock_levels_with_voltage *clk_level_info) -{ - struct amdgpu_device *adev = ctx->driver_context; - void *pp_handle = adev->powerplay.pp_handle; - struct pp_clock_levels_with_voltage pp_clk_info = {0}; - const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; - - if (pp_funcs->get_clock_by_type_with_voltage(pp_handle, - dc_to_pp_clock_type(clk_type), - &pp_clk_info)) - return false; - - pp_to_dc_clock_levels_with_voltage(&pp_clk_info, clk_level_info, clk_type); - - return true; -} - -bool dm_pp_notify_wm_clock_changes( - const struct dc_context *ctx, - struct dm_pp_wm_sets_with_clock_ranges *wm_with_clock_ranges) -{ - /* TODO: to be implemented */ - return false; -} - -bool dm_pp_apply_power_level_change_request( - const struct dc_context *ctx, - struct dm_pp_power_level_change_request *level_change_req) -{ - /* TODO: to be implemented */ - return false; -} - -bool dm_pp_apply_clock_for_voltage_request( - const struct dc_context *ctx, - struct dm_pp_clock_for_voltage_req *clock_for_voltage_req) -{ - struct amdgpu_device *adev = ctx->driver_context; - struct pp_display_clock_request pp_clock_request = {0}; - int ret = 0; - - pp_clock_request.clock_type = dc_to_pp_clock_type(clock_for_voltage_req->clk_type); - pp_clock_request.clock_freq_in_khz = clock_for_voltage_req->clocks_in_khz; - - if (!pp_clock_request.clock_type) - return false; - - if (adev->powerplay.pp_funcs->display_clock_voltage_request) - ret = adev->powerplay.pp_funcs->display_clock_voltage_request( - adev->powerplay.pp_handle, - &pp_clock_request); - if (ret) - return false; - return true; -} - -bool dm_pp_get_static_clocks( - const struct dc_context *ctx, - struct dm_pp_static_clock_info *static_clk_info) -{ - struct amdgpu_device *adev = ctx->driver_context; - struct amd_pp_clock_info pp_clk_info = {0}; - int ret = 0; - - if (adev->powerplay.pp_funcs->get_current_clocks) - ret = adev->powerplay.pp_funcs->get_current_clocks( - adev->powerplay.pp_handle, - &pp_clk_info); - if (ret) - return false; - - static_clk_info->max_clocks_state = pp_clk_info.max_clocks_state; - /* translate 10kHz to kHz */ - static_clk_info->max_mclk_khz = pp_clk_info.max_memory_clock * 10; - static_clk_info->max_sclk_khz = pp_clk_info.max_engine_clock * 10; - - return true; -} - -void pp_rv_set_display_requirement(struct pp_smu *pp, - struct pp_smu_display_requirement_rv *req) -{ - struct amdgpu_device *adev = pp->ctx->driver_context; - struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; - int ret = 0; - if (hwmgr->hwmgr_func->set_deep_sleep_dcefclk) - ret = hwmgr->hwmgr_func->set_deep_sleep_dcefclk(hwmgr, req->hard_min_dcefclk_khz/10); - if (hwmgr->hwmgr_func->set_active_display_count) - ret = hwmgr->hwmgr_func->set_active_display_count(hwmgr, req->display_count); - - //store_cc6 is not yet implemented in SMU level -} - -void pp_rv_set_wm_ranges(struct pp_smu *pp, - struct pp_smu_wm_range_sets *ranges) -{ - struct amdgpu_device *adev = pp->ctx->driver_context; - struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; - struct pp_wm_sets_with_clock_ranges_soc15 ranges_soc15 = {0}; - int i = 0; - - if (!hwmgr->hwmgr_func->set_watermarks_for_clocks_ranges || - !pp || !ranges) - return; - - //not entirely sure if thats a correct assignment - ranges_soc15.num_wm_sets_dmif = ranges->num_reader_wm_sets; - ranges_soc15.num_wm_sets_mcif = ranges->num_writer_wm_sets; - - for (i = 0; i < ranges_soc15.num_wm_sets_dmif; i++) { - if (ranges->reader_wm_sets[i].wm_inst > 3) - ranges_soc15.wm_sets_dmif[i].wm_set_id = DC_WM_SET_A; - else - ranges_soc15.wm_sets_dmif[i].wm_set_id = - ranges->reader_wm_sets[i].wm_inst; - ranges_soc15.wm_sets_dmif[i].wm_max_dcefclk_in_khz = - ranges->reader_wm_sets[i].max_drain_clk_khz; - ranges_soc15.wm_sets_dmif[i].wm_min_dcefclk_in_khz = - ranges->reader_wm_sets[i].min_drain_clk_khz; - ranges_soc15.wm_sets_dmif[i].wm_max_memclk_in_khz = - ranges->reader_wm_sets[i].max_fill_clk_khz; - ranges_soc15.wm_sets_dmif[i].wm_min_memclk_in_khz = - ranges->reader_wm_sets[i].min_fill_clk_khz; - } - - for (i = 0; i < ranges_soc15.num_wm_sets_mcif; i++) { - if (ranges->writer_wm_sets[i].wm_inst > 3) - ranges_soc15.wm_sets_dmif[i].wm_set_id = DC_WM_SET_A; - else - ranges_soc15.wm_sets_mcif[i].wm_set_id = - ranges->writer_wm_sets[i].wm_inst; - ranges_soc15.wm_sets_mcif[i].wm_max_socclk_in_khz = - ranges->writer_wm_sets[i].max_fill_clk_khz; - ranges_soc15.wm_sets_mcif[i].wm_min_socclk_in_khz = - ranges->writer_wm_sets[i].min_fill_clk_khz; - ranges_soc15.wm_sets_mcif[i].wm_max_memclk_in_khz = - ranges->writer_wm_sets[i].max_fill_clk_khz; - ranges_soc15.wm_sets_mcif[i].wm_min_memclk_in_khz = - ranges->writer_wm_sets[i].min_fill_clk_khz; - } - - hwmgr->hwmgr_func->set_watermarks_for_clocks_ranges(hwmgr, &ranges_soc15); - -} - -void pp_rv_set_pme_wa_enable(struct pp_smu *pp) -{ - struct amdgpu_device *adev = pp->ctx->driver_context; - struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; - - if (hwmgr->hwmgr_func->smus_notify_pwe) - hwmgr->hwmgr_func->smus_notify_pwe(hwmgr); -} - -void dm_pp_get_funcs_rv( - struct dc_context *ctx, - struct pp_smu_funcs_rv *funcs) -{ - funcs->pp_smu.ctx = ctx; - funcs->set_display_requirement = pp_rv_set_display_requirement; - funcs->set_wm_ranges = pp_rv_set_wm_ranges; - funcs->set_pme_wa_enable = pp_rv_set_pme_wa_enable; -} - -/**** end of power component interfaces ****/ -- GitLab From 33a6a7eb8014cb7089570534ef4d502efe4372ed Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Date: Wed, 6 Jun 2018 13:19:39 -0400 Subject: [PATCH 0742/1506] drm/amd/display: fix dcn1 watermark range reporting Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/display/dc/calcs/dcn_calcs.c | 102 ++++-------------- 1 file changed, 18 insertions(+), 84 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c index ac4451adeec9f..8dc0773b285eb 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c @@ -1335,21 +1335,14 @@ void dcn_bw_notify_pplib_of_wm_ranges(struct dc *dc) { struct pp_smu_funcs_rv *pp = dc->res_pool->pp_smu; struct pp_smu_wm_range_sets ranges = {0}; - int max_fclk_khz, nom_fclk_khz, mid_fclk_khz, min_fclk_khz; - int max_dcfclk_khz, min_dcfclk_khz; - int socclk_khz; + int min_fclk_khz, min_dcfclk_khz, socclk_khz; const int overdrive = 5000000; /* 5 GHz to cover Overdrive */ - unsigned factor = (ddr4_dram_factor_single_Channel * dc->dcn_soc->number_of_channels); if (!pp->set_wm_ranges) return; kernel_fpu_begin(); - max_fclk_khz = dc->dcn_soc->fabric_and_dram_bandwidth_vmax0p9 * 1000000 / factor; - nom_fclk_khz = dc->dcn_soc->fabric_and_dram_bandwidth_vnom0p8 * 1000000 / factor; - mid_fclk_khz = dc->dcn_soc->fabric_and_dram_bandwidth_vmid0p72 * 1000000 / factor; min_fclk_khz = dc->dcn_soc->fabric_and_dram_bandwidth_vmin0p65 * 1000000 / 32; - max_dcfclk_khz = dc->dcn_soc->dcfclkv_max0p9 * 1000; min_dcfclk_khz = dc->dcn_soc->dcfclkv_min0p65 * 1000; socclk_khz = dc->dcn_soc->socclk * 1000; kernel_fpu_end(); @@ -1357,7 +1350,7 @@ void dcn_bw_notify_pplib_of_wm_ranges(struct dc *dc) /* Now notify PPLib/SMU about which Watermarks sets they should select * depending on DPM state they are in. And update BW MGR GFX Engine and * Memory clock member variables for Watermarks calculations for each - * Watermark Set + * Watermark Set. Only one watermark set for dcn1 due to hw bug DEGVIDCN10-254. */ /* SOCCLK does not affect anytihng but writeback for DCN so for now we dont * care what the value is, hence min to overdrive level @@ -1366,96 +1359,37 @@ void dcn_bw_notify_pplib_of_wm_ranges(struct dc *dc) ranges.num_writer_wm_sets = WM_SET_COUNT; ranges.reader_wm_sets[0].wm_inst = WM_A; ranges.reader_wm_sets[0].min_drain_clk_khz = min_dcfclk_khz; - ranges.reader_wm_sets[0].max_drain_clk_khz = max_dcfclk_khz; + ranges.reader_wm_sets[0].max_drain_clk_khz = overdrive; ranges.reader_wm_sets[0].min_fill_clk_khz = min_fclk_khz; - ranges.reader_wm_sets[0].max_fill_clk_khz = min_fclk_khz; + ranges.reader_wm_sets[0].max_fill_clk_khz = overdrive; ranges.writer_wm_sets[0].wm_inst = WM_A; ranges.writer_wm_sets[0].min_fill_clk_khz = socclk_khz; ranges.writer_wm_sets[0].max_fill_clk_khz = overdrive; ranges.writer_wm_sets[0].min_drain_clk_khz = min_fclk_khz; - ranges.writer_wm_sets[0].max_drain_clk_khz = min_fclk_khz; - - ranges.reader_wm_sets[1].wm_inst = WM_B; - ranges.reader_wm_sets[1].min_drain_clk_khz = min_fclk_khz; - ranges.reader_wm_sets[1].max_drain_clk_khz = max_dcfclk_khz; - ranges.reader_wm_sets[1].min_fill_clk_khz = mid_fclk_khz; - ranges.reader_wm_sets[1].max_fill_clk_khz = mid_fclk_khz; - ranges.writer_wm_sets[1].wm_inst = WM_B; - ranges.writer_wm_sets[1].min_fill_clk_khz = socclk_khz; - ranges.writer_wm_sets[1].max_fill_clk_khz = overdrive; - ranges.writer_wm_sets[1].min_drain_clk_khz = mid_fclk_khz; - ranges.writer_wm_sets[1].max_drain_clk_khz = mid_fclk_khz; - - - ranges.reader_wm_sets[2].wm_inst = WM_C; - ranges.reader_wm_sets[2].min_drain_clk_khz = min_fclk_khz; - ranges.reader_wm_sets[2].max_drain_clk_khz = max_dcfclk_khz; - ranges.reader_wm_sets[2].min_fill_clk_khz = nom_fclk_khz; - ranges.reader_wm_sets[2].max_fill_clk_khz = nom_fclk_khz; - ranges.writer_wm_sets[2].wm_inst = WM_C; - ranges.writer_wm_sets[2].min_fill_clk_khz = socclk_khz; - ranges.writer_wm_sets[2].max_fill_clk_khz = overdrive; - ranges.writer_wm_sets[2].min_drain_clk_khz = nom_fclk_khz; - ranges.writer_wm_sets[2].max_drain_clk_khz = nom_fclk_khz; - - ranges.reader_wm_sets[3].wm_inst = WM_D; - ranges.reader_wm_sets[3].min_drain_clk_khz = min_fclk_khz; - ranges.reader_wm_sets[3].max_drain_clk_khz = max_dcfclk_khz; - ranges.reader_wm_sets[3].min_fill_clk_khz = max_fclk_khz; - ranges.reader_wm_sets[3].max_fill_clk_khz = max_fclk_khz; - ranges.writer_wm_sets[3].wm_inst = WM_D; - ranges.writer_wm_sets[3].min_fill_clk_khz = socclk_khz; - ranges.writer_wm_sets[3].max_fill_clk_khz = overdrive; - ranges.writer_wm_sets[3].min_drain_clk_khz = max_fclk_khz; - ranges.writer_wm_sets[3].max_drain_clk_khz = max_fclk_khz; + ranges.writer_wm_sets[0].max_drain_clk_khz = overdrive; if (dc->debug.pplib_wm_report_mode == WM_REPORT_OVERRIDE) { ranges.reader_wm_sets[0].wm_inst = WM_A; ranges.reader_wm_sets[0].min_drain_clk_khz = 300000; - ranges.reader_wm_sets[0].max_drain_clk_khz = 654000; + ranges.reader_wm_sets[0].max_drain_clk_khz = 5000000; ranges.reader_wm_sets[0].min_fill_clk_khz = 800000; - ranges.reader_wm_sets[0].max_fill_clk_khz = 800000; + ranges.reader_wm_sets[0].max_fill_clk_khz = 5000000; ranges.writer_wm_sets[0].wm_inst = WM_A; ranges.writer_wm_sets[0].min_fill_clk_khz = 200000; - ranges.writer_wm_sets[0].max_fill_clk_khz = 757000; + ranges.writer_wm_sets[0].max_fill_clk_khz = 5000000; ranges.writer_wm_sets[0].min_drain_clk_khz = 800000; - ranges.writer_wm_sets[0].max_drain_clk_khz = 800000; - - ranges.reader_wm_sets[1].wm_inst = WM_B; - ranges.reader_wm_sets[1].min_drain_clk_khz = 300000; - ranges.reader_wm_sets[1].max_drain_clk_khz = 654000; - ranges.reader_wm_sets[1].min_fill_clk_khz = 933000; - ranges.reader_wm_sets[1].max_fill_clk_khz = 933000; - ranges.writer_wm_sets[1].wm_inst = WM_B; - ranges.writer_wm_sets[1].min_fill_clk_khz = 200000; - ranges.writer_wm_sets[1].max_fill_clk_khz = 757000; - ranges.writer_wm_sets[1].min_drain_clk_khz = 933000; - ranges.writer_wm_sets[1].max_drain_clk_khz = 933000; - - - ranges.reader_wm_sets[2].wm_inst = WM_C; - ranges.reader_wm_sets[2].min_drain_clk_khz = 300000; - ranges.reader_wm_sets[2].max_drain_clk_khz = 654000; - ranges.reader_wm_sets[2].min_fill_clk_khz = 1067000; - ranges.reader_wm_sets[2].max_fill_clk_khz = 1067000; - ranges.writer_wm_sets[2].wm_inst = WM_C; - ranges.writer_wm_sets[2].min_fill_clk_khz = 200000; - ranges.writer_wm_sets[2].max_fill_clk_khz = 757000; - ranges.writer_wm_sets[2].min_drain_clk_khz = 1067000; - ranges.writer_wm_sets[2].max_drain_clk_khz = 1067000; - - ranges.reader_wm_sets[3].wm_inst = WM_D; - ranges.reader_wm_sets[3].min_drain_clk_khz = 300000; - ranges.reader_wm_sets[3].max_drain_clk_khz = 654000; - ranges.reader_wm_sets[3].min_fill_clk_khz = 1200000; - ranges.reader_wm_sets[3].max_fill_clk_khz = 1200000; - ranges.writer_wm_sets[3].wm_inst = WM_D; - ranges.writer_wm_sets[3].min_fill_clk_khz = 200000; - ranges.writer_wm_sets[3].max_fill_clk_khz = 757000; - ranges.writer_wm_sets[3].min_drain_clk_khz = 1200000; - ranges.writer_wm_sets[3].max_drain_clk_khz = 1200000; + ranges.writer_wm_sets[0].max_drain_clk_khz = 5000000; } + ranges.reader_wm_sets[1] = ranges.writer_wm_sets[0]; + ranges.reader_wm_sets[1].wm_inst = WM_B; + + ranges.reader_wm_sets[2] = ranges.writer_wm_sets[0]; + ranges.reader_wm_sets[2].wm_inst = WM_C; + + ranges.reader_wm_sets[3] = ranges.writer_wm_sets[0]; + ranges.reader_wm_sets[3].wm_inst = WM_D; + /* Notify PP Lib/SMU which Watermarks to use for which clock ranges */ pp->set_wm_ranges(&pp->pp_smu, &ranges); } -- GitLab From 69d6bb171fe15f564adfbc485e77dd8c5ca953d5 Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Date: Tue, 5 Jun 2018 07:19:08 -0400 Subject: [PATCH 0743/1506] drm/amd/display: remove dcn1 watermark sets b, c and d Currently dcn1 will not switch between watermark sets so we can save time by not calculating 3 extra sets. Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/display/dc/calcs/dcn_calcs.c | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c index 8dc0773b285eb..12261fbc25e06 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c @@ -505,6 +505,7 @@ static void split_stream_across_pipes( resource_build_scaling_params(secondary_pipe); } +#if 0 static void calc_wm_sets_and_perf_params( struct dc_state *context, struct dcn_bw_internal_vars *v) @@ -586,6 +587,7 @@ static void calc_wm_sets_and_perf_params( if (v->voltage_level >= 3) context->bw.dcn.watermarks.d = context->bw.dcn.watermarks.a; } +#endif static bool dcn_bw_apply_registry_override(struct dc *dc) { @@ -980,7 +982,24 @@ bool dcn_validate_bandwidth( bw_consumed = v->fabric_and_dram_bandwidth; display_pipe_configuration(v); - calc_wm_sets_and_perf_params(context, v); + /*calc_wm_sets_and_perf_params(context, v);*/ + /* Only 1 set is used by dcn since no noticeable + * performance improvement was measured and due to hw bug DEGVIDCN10-254 + */ + dispclkdppclkdcfclk_deep_sleep_prefetch_parameters_watermarks_and_performance_calculation(v); + + context->bw.dcn.watermarks.a.cstate_pstate.cstate_exit_ns = + v->stutter_exit_watermark * 1000; + context->bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns = + v->stutter_enter_plus_exit_watermark * 1000; + context->bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = + v->dram_clock_change_watermark * 1000; + context->bw.dcn.watermarks.a.pte_meta_urgent_ns = v->ptemeta_urgent_watermark * 1000; + context->bw.dcn.watermarks.a.urgent_ns = v->urgent_watermark * 1000; + context->bw.dcn.watermarks.b = context->bw.dcn.watermarks.a; + context->bw.dcn.watermarks.c = context->bw.dcn.watermarks.a; + context->bw.dcn.watermarks.d = context->bw.dcn.watermarks.a; + context->bw.dcn.clk.fclk_khz = (int)(bw_consumed * 1000000 / (ddr4_dram_factor_single_Channel * v->number_of_channels)); if (bw_consumed == v->fabric_and_dram_bandwidth_vmin0p65) { -- GitLab From 7144d3cfff7d8b0d98d9d25ee42c674491e31bc9 Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Date: Tue, 5 Jun 2018 13:14:13 -0400 Subject: [PATCH 0744/1506] drm/amd/display: separate out wm change request dcn workaround Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c | 11 ++++++----- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h | 2 ++ .../gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c | 3 +++ drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c | 1 + drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h | 1 + 5 files changed, 13 insertions(+), 5 deletions(-) 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 63b75ac4a1d52..623db09389b5c 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c @@ -190,6 +190,12 @@ static uint32_t convert_and_clamp( } +void hubbub1_wm_change_req_wa(struct hubbub *hubbub) +{ + REG_UPDATE_SEQ(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL, + DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, 0, 1); +} + void hubbub1_program_watermarks( struct hubbub *hubbub, struct dcn_watermark_set *watermarks, @@ -203,8 +209,6 @@ void hubbub1_program_watermarks( */ uint32_t prog_wm_value; - REG_UPDATE(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL, - DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, 0); /* Repeat for water mark set A, B, C and D. */ /* clock state A */ @@ -459,9 +463,6 @@ void hubbub1_program_watermarks( watermarks->d.cstate_pstate.pstate_change_ns, prog_wm_value); } - REG_UPDATE(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL, - DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, 1); - REG_UPDATE(DCHUBBUB_ARB_SAT_LEVEL, DCHUBBUB_ARB_SAT_LEVEL, 60 * refclk_mhz); REG_UPDATE(DCHUBBUB_ARB_DF_REQ_OUTSTAND, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h index 0ca39cb71968d..d6e596eef4c55 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h @@ -195,6 +195,8 @@ void hubbub1_update_dchub( bool hubbub1_verify_allow_pstate_change_high( struct hubbub *hubbub); +void hubbub1_wm_change_req_wa(struct hubbub *hubbub); + void hubbub1_program_watermarks( struct hubbub *hubbub, struct dcn_watermark_set *watermarks, 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 cc12c4757f8b6..378bb19b98de2 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 @@ -2305,6 +2305,9 @@ static void dcn10_apply_ctx_for_surface( hubbub1_program_watermarks(dc->res_pool->hubbub, &context->bw.dcn.watermarks, ref_clk_mhz, true); + if (dc->hwseq->wa.DEGVIDCN10_254) + hubbub1_wm_change_req_wa(dc->res_pool->hubbub); + if (dc->debug.sanity_checks) { /* pstate stuck check after watermark update */ dcn10_verify_allow_pstate_change_high(dc); diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c index 2db08b99db561..68be66eabc402 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c @@ -743,6 +743,7 @@ static struct dce_hwseq *dcn10_hwseq_create( hws->masks = &hwseq_mask; hws->wa.DEGVIDCN10_253 = true; hws->wa.false_optc_underflow = true; + hws->wa.DEGVIDCN10_254 = true; } return hws; } 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 a71770ed4b9f6..1c94dae6bbde6 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h @@ -44,6 +44,7 @@ struct dce_hwseq_wa { bool blnd_crtc_trigger; bool DEGVIDCN10_253; bool false_optc_underflow; + bool DEGVIDCN10_254; }; struct hwseq_wa_state { -- GitLab From e21db6dbdf4327f620c5a203f7801b59dad9942e Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Date: Thu, 24 May 2018 14:39:01 -0400 Subject: [PATCH 0745/1506] drm/amd/display: move dcn watermark programming to set_bandwidth Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../amd/display/dc/dcn10/dcn10_hw_sequencer.c | 107 +++--------------- .../gpu/drm/amd/display/dc/inc/hw_sequencer.h | 2 +- 2 files changed, 19 insertions(+), 90 deletions(-) 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 378bb19b98de2..21b45e8d49f7d 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 @@ -2219,8 +2219,6 @@ static void dcn10_apply_ctx_for_surface( int i; struct timing_generator *tg; bool removed_pipe[4] = { false }; - unsigned int ref_clk_mhz = dc->res_pool->ref_clock_inKhz/1000; - bool program_water_mark = false; struct pipe_ctx *top_pipe_to_program = find_top_pipe_for_stream(dc, context, stream); DC_LOGGER_INIT(dc->ctx->logger); @@ -2281,107 +2279,38 @@ static void dcn10_apply_ctx_for_surface( if (num_planes == 0) false_optc_underflow_wa(dc, stream, tg); - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *old_pipe_ctx = - &dc->current_state->res_ctx.pipe_ctx[i]; - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - - if (pipe_ctx->stream == stream && - pipe_ctx->plane_state && - pipe_ctx->plane_state->update_flags.bits.full_update) - program_water_mark = true; - + for (i = 0; i < dc->res_pool->pipe_count; i++) if (removed_pipe[i]) - dcn10_disable_plane(dc, old_pipe_ctx); - } - - if (program_water_mark) { - if (dc->debug.sanity_checks) { - /* pstate stuck check after watermark update */ - dcn10_verify_allow_pstate_change_high(dc); - } - - /* watermark is for all pipes */ - hubbub1_program_watermarks(dc->res_pool->hubbub, - &context->bw.dcn.watermarks, ref_clk_mhz, true); - - if (dc->hwseq->wa.DEGVIDCN10_254) - hubbub1_wm_change_req_wa(dc->res_pool->hubbub); + dcn10_disable_plane(dc, &dc->current_state->res_ctx.pipe_ctx[i]); - if (dc->debug.sanity_checks) { - /* pstate stuck check after watermark update */ - dcn10_verify_allow_pstate_change_high(dc); - } - } -/* DC_LOG_BANDWIDTH_CALCS(dc->ctx->logger, - "\n============== Watermark parameters ==============\n" - "a.urgent_ns: %d \n" - "a.cstate_enter_plus_exit: %d \n" - "a.cstate_exit: %d \n" - "a.pstate_change: %d \n" - "a.pte_meta_urgent: %d \n" - "b.urgent_ns: %d \n" - "b.cstate_enter_plus_exit: %d \n" - "b.cstate_exit: %d \n" - "b.pstate_change: %d \n" - "b.pte_meta_urgent: %d \n", - context->bw.dcn.watermarks.a.urgent_ns, - context->bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns, - context->bw.dcn.watermarks.a.cstate_pstate.cstate_exit_ns, - context->bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns, - context->bw.dcn.watermarks.a.pte_meta_urgent_ns, - context->bw.dcn.watermarks.b.urgent_ns, - context->bw.dcn.watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns, - context->bw.dcn.watermarks.b.cstate_pstate.cstate_exit_ns, - context->bw.dcn.watermarks.b.cstate_pstate.pstate_change_ns, - context->bw.dcn.watermarks.b.pte_meta_urgent_ns - ); - DC_LOG_BANDWIDTH_CALCS(dc->ctx->logger, - "\nc.urgent_ns: %d \n" - "c.cstate_enter_plus_exit: %d \n" - "c.cstate_exit: %d \n" - "c.pstate_change: %d \n" - "c.pte_meta_urgent: %d \n" - "d.urgent_ns: %d \n" - "d.cstate_enter_plus_exit: %d \n" - "d.cstate_exit: %d \n" - "d.pstate_change: %d \n" - "d.pte_meta_urgent: %d \n" - "========================================================\n", - context->bw.dcn.watermarks.c.urgent_ns, - context->bw.dcn.watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns, - context->bw.dcn.watermarks.c.cstate_pstate.cstate_exit_ns, - context->bw.dcn.watermarks.c.cstate_pstate.pstate_change_ns, - context->bw.dcn.watermarks.c.pte_meta_urgent_ns, - context->bw.dcn.watermarks.d.urgent_ns, - context->bw.dcn.watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns, - context->bw.dcn.watermarks.d.cstate_pstate.cstate_exit_ns, - context->bw.dcn.watermarks.d.cstate_pstate.pstate_change_ns, - context->bw.dcn.watermarks.d.pte_meta_urgent_ns - ); -*/ + if (dc->hwseq->wa.DEGVIDCN10_254) + hubbub1_wm_change_req_wa(dc->res_pool->hubbub); } static void dcn10_set_bandwidth( struct dc *dc, struct dc_state *context, - bool decrease_allowed) + bool safe_to_lower) { if (dc->debug.sanity_checks) dcn10_verify_allow_pstate_change_high(dc); - if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) - return; + if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { + if (context->stream_count == 0) + context->bw.dcn.clk.phyclk_khz = 0; - if (context->stream_count == 0) - context->bw.dcn.clk.phyclk_khz = 0; + dc->res_pool->dccg->funcs->update_clocks( + dc->res_pool->dccg, + &context->bw.dcn.clk, + safe_to_lower); - dc->res_pool->dccg->funcs->update_clocks( - dc->res_pool->dccg, - &context->bw.dcn.clk, - decrease_allowed); + dcn10_pplib_apply_display_requirements(dc, context); + } - dcn10_pplib_apply_display_requirements(dc, context); + hubbub1_program_watermarks(dc->res_pool->hubbub, + &context->bw.dcn.watermarks, + dc->res_pool->ref_clock_inKhz / 1000, + true); if (dc->debug.sanity_checks) dcn10_verify_allow_pstate_change_high(dc); 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 1c94dae6bbde6..2506601120afa 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h @@ -172,7 +172,7 @@ struct hw_sequencer_funcs { void (*set_bandwidth)( struct dc *dc, struct dc_state *context, - bool decrease_allowed); + bool safe_to_lower); void (*set_drr)(struct pipe_ctx **pipe_ctx, int num_pipes, int vmin, int vmax); -- GitLab From bf28c2e205b1c37e412cb6785a34f10de944bae1 Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Date: Tue, 5 Jun 2018 07:33:10 -0400 Subject: [PATCH 0746/1506] drm/amd/display: remove soc_bounding_box.c Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dml/Makefile | 3 +- .../drm/amd/display/dc/dml/display_mode_lib.h | 1 - .../amd/display/dc/dml/display_mode_structs.h | 3 +- .../drm/amd/display/dc/dml/soc_bounding_box.c | 79 ------------------- .../drm/amd/display/dc/dml/soc_bounding_box.h | 35 -------- 5 files changed, 2 insertions(+), 119 deletions(-) delete mode 100644 drivers/gpu/drm/amd/display/dc/dml/soc_bounding_box.c delete mode 100644 drivers/gpu/drm/amd/display/dc/dml/soc_bounding_box.h diff --git a/drivers/gpu/drm/amd/display/dc/dml/Makefile b/drivers/gpu/drm/amd/display/dc/dml/Makefile index f83a608f93e94..d97ca6528f9d9 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dml/Makefile @@ -36,11 +36,10 @@ CFLAGS_display_mode_lib.o := $(dml_ccflags) CFLAGS_display_pipe_clocks.o := $(dml_ccflags) CFLAGS_dml1_display_rq_dlg_calc.o := $(dml_ccflags) CFLAGS_display_rq_dlg_helpers.o := $(dml_ccflags) -CFLAGS_soc_bounding_box.o := $(dml_ccflags) CFLAGS_dml_common_defs.o := $(dml_ccflags) DML = display_mode_lib.o display_rq_dlg_helpers.o dml1_display_rq_dlg_calc.o \ - soc_bounding_box.o dml_common_defs.o + dml_common_defs.o AMD_DAL_DML = $(addprefix $(AMDDALPATH)/dc/dml/,$(DML)) diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h index 3c2abcb8a1b0c..6352062488898 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h @@ -27,7 +27,6 @@ #include "dml_common_defs.h" -#include "soc_bounding_box.h" #include "dml1_display_rq_dlg_calc.h" enum dml_project { diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h index 7fa0375939aec..6943801c5fd3f 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h @@ -64,10 +64,9 @@ struct _vcs_dpi_voltage_scaling_st { double dscclk_mhz; double dcfclk_mhz; double socclk_mhz; - double dram_speed_mhz; + double dram_speed_mts; double fabricclk_mhz; double dispclk_mhz; - double dram_bw_per_chan_gbps; double phyclk_mhz; double dppclk_mhz; }; diff --git a/drivers/gpu/drm/amd/display/dc/dml/soc_bounding_box.c b/drivers/gpu/drm/amd/display/dc/dml/soc_bounding_box.c deleted file mode 100644 index 324239c779583..0000000000000 --- a/drivers/gpu/drm/amd/display/dc/dml/soc_bounding_box.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2017 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ -#include "soc_bounding_box.h" -#include "display_mode_lib.h" -#include "dc_features.h" - -#include "dml_inline_defs.h" - -/* - * NOTE: - * This file is gcc-parseable HW gospel, coming straight from HW engineers. - * - * It doesn't adhere to Linux kernel style and sometimes will do things in odd - * ways. Unless there is something clearly wrong with it the code should - * remain as-is as it provides us with a guarantee from HW that it is correct. - */ - -void dml_socbb_set_latencies(soc_bounding_box_st *to_box, soc_bounding_box_st *from_box) -{ - to_box->dram_clock_change_latency_us = from_box->dram_clock_change_latency_us; - to_box->sr_exit_time_us = from_box->sr_exit_time_us; - to_box->sr_enter_plus_exit_time_us = from_box->sr_enter_plus_exit_time_us; - to_box->urgent_latency_us = from_box->urgent_latency_us; - to_box->writeback_latency_us = from_box->writeback_latency_us; -} - -voltage_scaling_st dml_socbb_voltage_scaling( - const soc_bounding_box_st *soc, - enum voltage_state voltage) -{ - const voltage_scaling_st *voltage_state; - const voltage_scaling_st * const voltage_end = soc->clock_limits + DC__VOLTAGE_STATES; - - for (voltage_state = soc->clock_limits; - voltage_state < voltage_end && voltage_state->state != voltage; - voltage_state++) { - } - - if (voltage_state < voltage_end) - return *voltage_state; - return soc->clock_limits[DC__VOLTAGE_STATES - 1]; -} - -double dml_socbb_return_bw_mhz(soc_bounding_box_st *box, enum voltage_state voltage) -{ - double return_bw; - - voltage_scaling_st state = dml_socbb_voltage_scaling(box, voltage); - - return_bw = dml_min((double) box->return_bus_width_bytes * state.dcfclk_mhz, - state.dram_bw_per_chan_gbps * 1000.0 * (double) box->num_chans - * box->ideal_dram_bw_after_urgent_percent / 100.0); - - return_bw = dml_min((double) box->return_bus_width_bytes * state.fabricclk_mhz, return_bw); - - return return_bw; -} diff --git a/drivers/gpu/drm/amd/display/dc/dml/soc_bounding_box.h b/drivers/gpu/drm/amd/display/dc/dml/soc_bounding_box.h deleted file mode 100644 index 7a65206a6d21a..0000000000000 --- a/drivers/gpu/drm/amd/display/dc/dml/soc_bounding_box.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2017 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __SOC_BOUNDING_BOX_H__ -#define __SOC_BOUNDING_BOX_H__ - -#include "dml_common_defs.h" - -void dml_socbb_set_latencies(soc_bounding_box_st *to_box, soc_bounding_box_st *from_box); -voltage_scaling_st dml_socbb_voltage_scaling(const soc_bounding_box_st *box, enum voltage_state voltage); -double dml_socbb_return_bw_mhz(soc_bounding_box_st *box, enum voltage_state voltage); - -#endif -- GitLab From b6c3053a8f431a032a1473dc0e0069ca7fd0b0e5 Mon Sep 17 00:00:00 2001 From: Yongqiang Sun <yongqiang.sun@amd.com> Date: Fri, 8 Jun 2018 13:07:53 -0500 Subject: [PATCH 0747/1506] drm/amd/display: Check scaling ration not viewports params. In case of roation, width and height in viewport is difference between viewport and h_active and v_active, while this is not scaling. The right way is check ratios in scaling data, to determine it is a scaling case or not. Signed-off-by: Yongqiang Sun <yongqiang.sun@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c index c69fa4bfab0af..742fd497ed006 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c @@ -145,10 +145,10 @@ static bool dpp_get_optimal_number_of_taps( pixel_width = scl_data->viewport.width; /* Some ASICs does not support FP16 scaling, so we reject modes require this*/ - if (scl_data->viewport.width != scl_data->h_active && - scl_data->viewport.height != scl_data->v_active && + if (scl_data->format == PIXEL_FORMAT_FP16 && dpp->caps->dscl_data_proc_format == DSCL_DATA_PRCESSING_FIXED_FORMAT && - scl_data->format == PIXEL_FORMAT_FP16) + scl_data->ratios.horz.value != dc_fixpt_one.value && + scl_data->ratios.vert.value != dc_fixpt_one.value) return false; if (scl_data->viewport.width > scl_data->h_active && -- GitLab From c1aaea99a43e39c7c8dc6c71b84589c89d5bcbf2 Mon Sep 17 00:00:00 2001 From: Tony Cheng <tony.cheng@amd.com> Date: Tue, 5 Jun 2018 09:14:36 -0400 Subject: [PATCH 0748/1506] drm/amd/display: dal 3.1.52 Signed-off-by: Tony Cheng <tony.cheng@amd.com> Reviewed-by: Harry Wentland <Harry.Wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index cbcdbd9b99100..74e6653b9852e 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.1.51" +#define DC_VER "3.1.52" #define MAX_SURFACES 3 #define MAX_STREAMS 6 -- GitLab From 7f93c1de64693dc18afe55559f14cee6b5403c6c Mon Sep 17 00:00:00 2001 From: Charlene Liu <charlene.liu@amd.com> Date: Sat, 9 Jun 2018 19:33:14 -0400 Subject: [PATCH 0749/1506] drm/amd/display: add valid regoffset and NULL pointer check Signed-off-by: Charlene Liu <charlene.liu@amd.com> Reviewed-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 8 +++--- .../gpu/drm/amd/display/dc/core/dc_link_dp.c | 9 ++++--- .../display/dc/dce110/dce110_hw_sequencer.c | 7 ++--- .../drm/amd/display/dc/dcn10/dcn10_hubbub.c | 5 ++++ .../amd/display/dc/dcn10/dcn10_hw_sequencer.c | 26 ++++++++++++++----- 5 files changed, 38 insertions(+), 17 deletions(-) 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 8eb8b87684659..fa56c0fc02bf5 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -33,6 +33,7 @@ #include "dc_link_dp.h" #include "dc_link_ddc.h" #include "link_hwss.h" +#include "opp.h" #include "link_encoder.h" #include "hw_sequencer.h" @@ -2382,9 +2383,10 @@ void core_link_enable_stream( core_dc->hwss.enable_audio_stream(pipe_ctx); /* turn off otg test pattern if enable */ - pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg, - CONTROLLER_DP_TEST_PATTERN_VIDEOMODE, - COLOR_DEPTH_UNDEFINED); + if (pipe_ctx->stream_res.tg->funcs->set_test_pattern) + pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg, + CONTROLLER_DP_TEST_PATTERN_VIDEOMODE, + COLOR_DEPTH_UNDEFINED); core_dc->hwss.enable_stream(pipe_ctx); 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 509f265663d27..049fc5cce1d26 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 @@ -3,6 +3,7 @@ #include "dc.h" #include "dc_link_dp.h" #include "dm_helpers.h" +#include "opp.h" #include "inc/core_types.h" #include "link_hwss.h" @@ -2511,8 +2512,8 @@ static void set_crtc_test_pattern(struct dc_link *link, pipe_ctx->stream->bit_depth_params = params; pipe_ctx->stream_res.opp->funcs-> opp_program_bit_depth_reduction(pipe_ctx->stream_res.opp, ¶ms); - - pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg, + if (pipe_ctx->stream_res.tg->funcs->set_test_pattern) + pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg, controller_test_pattern, color_depth); } break; @@ -2524,8 +2525,8 @@ static void set_crtc_test_pattern(struct dc_link *link, pipe_ctx->stream->bit_depth_params = params; pipe_ctx->stream_res.opp->funcs-> opp_program_bit_depth_reduction(pipe_ctx->stream_res.opp, ¶ms); - - pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg, + if (pipe_ctx->stream_res.tg->funcs->set_test_pattern) + pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg, CONTROLLER_DP_TEST_PATTERN_VIDEOMODE, color_depth); } 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 3b983b3f34234..9cbd5036db079 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 @@ -1475,7 +1475,7 @@ static void power_down_controllers(struct dc *dc) { int i; - for (i = 0; i < dc->res_pool->pipe_count; i++) { + for (i = 0; i < dc->res_pool->timing_generator_count; i++) { dc->res_pool->timing_generators[i]->funcs->disable_crtc( dc->res_pool->timing_generators[i]); } @@ -1515,12 +1515,13 @@ static void disable_vga_and_power_gate_all_controllers( struct timing_generator *tg; struct dc_context *ctx = dc->ctx; - for (i = 0; i < dc->res_pool->pipe_count; i++) { + for (i = 0; i < dc->res_pool->timing_generator_count; i++) { tg = dc->res_pool->timing_generators[i]; if (tg->funcs->disable_vga) tg->funcs->disable_vga(tg); - + } + for (i = 0; i < dc->res_pool->pipe_count; i++) { /* Enable CLOCK gating for each pipe BEFORE controller * powergating. */ enable_display_pipe_clock_gating(ctx, 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 623db09389b5c..1ea91e153d3a6 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c @@ -483,6 +483,11 @@ void hubbub1_update_dchub( struct hubbub *hubbub, struct dchub_init_data *dh_data) { + if (REG(DCHUBBUB_SDPIF_FB_TOP) == 0) { + ASSERT(false); + /*should not come here*/ + return; + } /* TODO: port code from dal2 */ switch (dh_data->fb_mode) { case FRAME_BUFFER_MODE_ZFB_ONLY: 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 21b45e8d49f7d..3b2cb2d3b8a61 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 @@ -415,6 +415,8 @@ static void dpp_pg_control( if (hws->ctx->dc->debug.disable_dpp_power_gate) return; + if (REG(DOMAIN1_PG_CONFIG) == 0) + return; switch (dpp_inst) { case 0: /* DPP0 */ @@ -465,6 +467,8 @@ static void hubp_pg_control( if (hws->ctx->dc->debug.disable_hubp_power_gate) return; + if (REG(DOMAIN0_PG_CONFIG) == 0) + return; switch (hubp_inst) { case 0: /* DCHUBP0 */ @@ -865,7 +869,8 @@ void hwss1_plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx) return; mpc->funcs->remove_mpcc(mpc, mpc_tree_params, mpcc_to_remove); - opp->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; + if (opp != NULL) + opp->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; dc->optimized_required = true; @@ -1343,10 +1348,11 @@ static void dcn10_enable_per_frame_crtc_position_reset( DC_SYNC_INFO("Setting up\n"); for (i = 0; i < group_size; i++) - 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, - &grouped_pipes[i]->stream->triggered_crtc_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, + &grouped_pipes[i]->stream->triggered_crtc_reset); DC_SYNC_INFO("Waiting for trigger\n"); @@ -2496,8 +2502,14 @@ static void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx) static void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data) { - if (hws->ctx->dc->res_pool->hubbub != NULL) - hubbub1_update_dchub(hws->ctx->dc->res_pool->hubbub, dh_data); + if (hws->ctx->dc->res_pool->hubbub != NULL) { + struct hubp *hubp = hws->ctx->dc->res_pool->hubps[0]; + + if (hubp->funcs->hubp_update_dchub) + hubp->funcs->hubp_update_dchub(hubp, dh_data); + else + hubbub1_update_dchub(hws->ctx->dc->res_pool->hubbub, dh_data); + } } static void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) -- GitLab From 1eeedbcc20d64ff2ef7eb9823f85bbb1c2545064 Mon Sep 17 00:00:00 2001 From: Samson Tam <Samson.Tam@amd.com> Date: Wed, 30 May 2018 15:44:50 -0400 Subject: [PATCH 0750/1506] drm/amd/display: get board layout for edid emulation Signed-off-by: Samson Tam <Samson.Tam@amd.com> Reviewed-by: Aric Cyr <Aric.Cyr@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/display/dc/bios/bios_parser.c | 196 ++++++++++++++++ .../drm/amd/display/dc/bios/bios_parser2.c | 218 +++++++++++++++++- .../gpu/drm/amd/display/dc/dc_bios_types.h | 4 + .../amd/display/include/grph_object_defs.h | 46 ++++ .../drm/amd/display/include/grph_object_id.h | 11 + 5 files changed, 474 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c index c7f0b27e457e4..be8a2494355a4 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c @@ -3762,6 +3762,200 @@ static struct integrated_info *bios_parser_create_integrated_info( return NULL; } +enum bp_result update_slot_layout_info( + struct dc_bios *dcb, + unsigned int i, + struct slot_layout_info *slot_layout_info, + unsigned int record_offset) +{ + unsigned int j; + struct bios_parser *bp; + ATOM_BRACKET_LAYOUT_RECORD *record; + ATOM_COMMON_RECORD_HEADER *record_header; + enum bp_result result = BP_RESULT_NORECORD; + + bp = BP_FROM_DCB(dcb); + record = NULL; + record_header = NULL; + + for (;;) { + + record_header = (ATOM_COMMON_RECORD_HEADER *) + GET_IMAGE(ATOM_COMMON_RECORD_HEADER, record_offset); + if (record_header == NULL) { + result = BP_RESULT_BADBIOSTABLE; + break; + } + + /* the end of the list */ + if (record_header->ucRecordType == 0xff || + record_header->ucRecordSize == 0) { + break; + } + + if (record_header->ucRecordType == + ATOM_BRACKET_LAYOUT_RECORD_TYPE && + sizeof(ATOM_BRACKET_LAYOUT_RECORD) + <= record_header->ucRecordSize) { + record = (ATOM_BRACKET_LAYOUT_RECORD *) + (record_header); + result = BP_RESULT_OK; + break; + } + + record_offset += record_header->ucRecordSize; + } + + /* return if the record not found */ + if (result != BP_RESULT_OK) + return result; + + /* get slot sizes */ + slot_layout_info->length = record->ucLength; + slot_layout_info->width = record->ucWidth; + + /* get info for each connector in the slot */ + slot_layout_info->num_of_connectors = record->ucConnNum; + for (j = 0; j < slot_layout_info->num_of_connectors; ++j) { + slot_layout_info->connectors[j].connector_type = + (enum connector_layout_type) + (record->asConnInfo[j].ucConnectorType); + switch (record->asConnInfo[j].ucConnectorType) { + case CONNECTOR_TYPE_DVI_D: + slot_layout_info->connectors[j].connector_type = + CONNECTOR_LAYOUT_TYPE_DVI_D; + slot_layout_info->connectors[j].length = + CONNECTOR_SIZE_DVI; + break; + + case CONNECTOR_TYPE_HDMI: + slot_layout_info->connectors[j].connector_type = + CONNECTOR_LAYOUT_TYPE_HDMI; + slot_layout_info->connectors[j].length = + CONNECTOR_SIZE_HDMI; + break; + + case CONNECTOR_TYPE_DISPLAY_PORT: + slot_layout_info->connectors[j].connector_type = + CONNECTOR_LAYOUT_TYPE_DP; + slot_layout_info->connectors[j].length = + CONNECTOR_SIZE_DP; + break; + + case CONNECTOR_TYPE_MINI_DISPLAY_PORT: + slot_layout_info->connectors[j].connector_type = + CONNECTOR_LAYOUT_TYPE_MINI_DP; + slot_layout_info->connectors[j].length = + CONNECTOR_SIZE_MINI_DP; + break; + + default: + slot_layout_info->connectors[j].connector_type = + CONNECTOR_LAYOUT_TYPE_UNKNOWN; + slot_layout_info->connectors[j].length = + CONNECTOR_SIZE_UNKNOWN; + } + + slot_layout_info->connectors[j].position = + record->asConnInfo[j].ucPosition; + slot_layout_info->connectors[j].connector_id = + object_id_from_bios_object_id( + record->asConnInfo[j].usConnectorObjectId); + } + return result; +} + + +enum bp_result get_bracket_layout_record( + struct dc_bios *dcb, + unsigned int bracket_layout_id, + struct slot_layout_info *slot_layout_info) +{ + unsigned int i; + unsigned int record_offset; + struct bios_parser *bp; + enum bp_result result; + ATOM_OBJECT *object; + ATOM_OBJECT_TABLE *object_table; + unsigned int genericTableOffset; + + bp = BP_FROM_DCB(dcb); + object = NULL; + if (slot_layout_info == NULL) { + DC_LOG_DETECTION_EDID_PARSER("Invalid slot_layout_info\n"); + return BP_RESULT_BADINPUT; + } + + + genericTableOffset = bp->object_info_tbl_offset + + bp->object_info_tbl.v1_3->usMiscObjectTableOffset; + object_table = (ATOM_OBJECT_TABLE *) + GET_IMAGE(ATOM_OBJECT_TABLE, genericTableOffset); + if (!object_table) + return BP_RESULT_FAILURE; + + result = BP_RESULT_NORECORD; + for (i = 0; i < object_table->ucNumberOfObjects; ++i) { + + if (bracket_layout_id == + object_table->asObjects[i].usObjectID) { + + object = &object_table->asObjects[i]; + record_offset = object->usRecordOffset + + bp->object_info_tbl_offset; + + result = update_slot_layout_info(dcb, i, + slot_layout_info, record_offset); + break; + } + } + return result; +} + +static enum bp_result bios_get_board_layout_info( + struct dc_bios *dcb, + struct board_layout_info *board_layout_info) +{ + unsigned int i; + struct bios_parser *bp; + enum bp_result record_result; + + const unsigned int slot_index_to_vbios_id[MAX_BOARD_SLOTS] = { + GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID1, + GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID2, + 0, 0 + }; + + bp = BP_FROM_DCB(dcb); + if (board_layout_info == NULL) { + DC_LOG_DETECTION_EDID_PARSER("Invalid board_layout_info\n"); + return BP_RESULT_BADINPUT; + } + + board_layout_info->num_of_slots = 0; + + for (i = 0; i < MAX_BOARD_SLOTS; ++i) { + record_result = get_bracket_layout_record(dcb, + slot_index_to_vbios_id[i], + &board_layout_info->slots[i]); + + if (record_result == BP_RESULT_NORECORD && i > 0) + break; /* no more slots present in bios */ + else if (record_result != BP_RESULT_OK) + return record_result; /* fail */ + + ++board_layout_info->num_of_slots; + } + + /* all data is valid */ + board_layout_info->is_number_of_slots_valid = 1; + board_layout_info->is_slots_size_valid = 1; + board_layout_info->is_connector_offsets_valid = 1; + board_layout_info->is_connector_lengths_valid = 1; + + return BP_RESULT_OK; +} + /******************************************************************************/ static const struct dc_vbios_funcs vbios_funcs = { @@ -3836,6 +4030,8 @@ static const struct dc_vbios_funcs vbios_funcs = { .post_init = bios_parser_post_init, /* patch vbios table for mxm module by reading i2c */ .bios_parser_destroy = bios_parser_destroy, + + .get_board_layout_info = bios_get_board_layout_info, }; static bool bios_parser_construct( diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c index b8cef7af3c4af..aeb56e402cccf 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c @@ -43,6 +43,29 @@ #include "bios_parser_interface.h" #include "bios_parser_common.h" + +/* Temporarily add in defines until ObjectID.h patch is updated in a few days */ +#ifndef GENERIC_OBJECT_ID_BRACKET_LAYOUT +#define GENERIC_OBJECT_ID_BRACKET_LAYOUT 0x05 +#endif /* GENERIC_OBJECT_ID_BRACKET_LAYOUT */ + +#ifndef GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID1 +#define GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID1 \ + (GRAPH_OBJECT_TYPE_GENERIC << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + GENERIC_OBJECT_ID_BRACKET_LAYOUT << OBJECT_ID_SHIFT) +#endif /* GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID1 */ + +#ifndef GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID2 +#define GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID2 \ + (GRAPH_OBJECT_TYPE_GENERIC << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + GENERIC_OBJECT_ID_BRACKET_LAYOUT << OBJECT_ID_SHIFT) +#endif /* GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID2 */ + +#define DC_LOGGER \ + bp->base.ctx->logger + #define LAST_RECORD_TYPE 0xff #define SMU9_SYSPLL0_ID 0 @@ -86,7 +109,6 @@ static struct atom_encoder_caps_record *get_encoder_cap_record( #define DATA_TABLES(table) (bp->master_data_tbl->listOfdatatables.table) - static void destruct(struct bios_parser *bp) { kfree(bp->base.bios_local_image); @@ -1854,6 +1876,198 @@ static struct integrated_info *bios_parser_create_integrated_info( return NULL; } +static enum bp_result update_slot_layout_info( + struct dc_bios *dcb, + unsigned int i, + struct slot_layout_info *slot_layout_info) +{ + unsigned int record_offset; + unsigned int j; + struct atom_display_object_path_v2 *object; + struct atom_bracket_layout_record *record; + struct atom_common_record_header *record_header; + enum bp_result result; + struct bios_parser *bp; + struct object_info_table *tbl; + struct display_object_info_table_v1_4 *v1_4; + + record = NULL; + record_header = NULL; + result = BP_RESULT_NORECORD; + + bp = BP_FROM_DCB(dcb); + tbl = &bp->object_info_tbl; + v1_4 = tbl->v1_4; + + object = &v1_4->display_path[i]; + record_offset = (unsigned int) + (object->disp_recordoffset) + + (unsigned int)(bp->object_info_tbl_offset); + + for (;;) { + + record_header = (struct atom_common_record_header *) + GET_IMAGE(struct atom_common_record_header, + record_offset); + if (record_header == NULL) { + result = BP_RESULT_BADBIOSTABLE; + break; + } + + /* the end of the list */ + if (record_header->record_type == 0xff || + record_header->record_size == 0) { + break; + } + + if (record_header->record_type == + ATOM_BRACKET_LAYOUT_RECORD_TYPE && + sizeof(struct atom_bracket_layout_record) + <= record_header->record_size) { + record = (struct atom_bracket_layout_record *) + (record_header); + result = BP_RESULT_OK; + break; + } + + record_offset += record_header->record_size; + } + + /* return if the record not found */ + if (result != BP_RESULT_OK) + return result; + + /* get slot sizes */ + slot_layout_info->length = record->bracketlen; + slot_layout_info->width = record->bracketwidth; + + /* get info for each connector in the slot */ + slot_layout_info->num_of_connectors = record->conn_num; + for (j = 0; j < slot_layout_info->num_of_connectors; ++j) { + slot_layout_info->connectors[j].connector_type = + (enum connector_layout_type) + (record->conn_info[j].connector_type); + switch (record->conn_info[j].connector_type) { + case CONNECTOR_TYPE_DVI_D: + slot_layout_info->connectors[j].connector_type = + CONNECTOR_LAYOUT_TYPE_DVI_D; + slot_layout_info->connectors[j].length = + CONNECTOR_SIZE_DVI; + break; + + case CONNECTOR_TYPE_HDMI: + slot_layout_info->connectors[j].connector_type = + CONNECTOR_LAYOUT_TYPE_HDMI; + slot_layout_info->connectors[j].length = + CONNECTOR_SIZE_HDMI; + break; + + case CONNECTOR_TYPE_DISPLAY_PORT: + slot_layout_info->connectors[j].connector_type = + CONNECTOR_LAYOUT_TYPE_DP; + slot_layout_info->connectors[j].length = + CONNECTOR_SIZE_DP; + break; + + case CONNECTOR_TYPE_MINI_DISPLAY_PORT: + slot_layout_info->connectors[j].connector_type = + CONNECTOR_LAYOUT_TYPE_MINI_DP; + slot_layout_info->connectors[j].length = + CONNECTOR_SIZE_MINI_DP; + break; + + default: + slot_layout_info->connectors[j].connector_type = + CONNECTOR_LAYOUT_TYPE_UNKNOWN; + slot_layout_info->connectors[j].length = + CONNECTOR_SIZE_UNKNOWN; + } + + slot_layout_info->connectors[j].position = + record->conn_info[j].position; + slot_layout_info->connectors[j].connector_id = + object_id_from_bios_object_id( + record->conn_info[j].connectorobjid); + } + return result; +} + + +static enum bp_result get_bracket_layout_record( + struct dc_bios *dcb, + unsigned int bracket_layout_id, + struct slot_layout_info *slot_layout_info) +{ + unsigned int i; + struct bios_parser *bp = BP_FROM_DCB(dcb); + enum bp_result result; + struct object_info_table *tbl; + struct display_object_info_table_v1_4 *v1_4; + + if (slot_layout_info == NULL) { + DC_LOG_DETECTION_EDID_PARSER("Invalid slot_layout_info\n"); + return BP_RESULT_BADINPUT; + } + tbl = &bp->object_info_tbl; + v1_4 = tbl->v1_4; + + result = BP_RESULT_NORECORD; + for (i = 0; i < v1_4->number_of_path; ++i) { + + if (bracket_layout_id == + v1_4->display_path[i].display_objid) { + result = update_slot_layout_info(dcb, i, + slot_layout_info); + break; + } + } + return result; +} + +static enum bp_result bios_get_board_layout_info( + struct dc_bios *dcb, + struct board_layout_info *board_layout_info) +{ + unsigned int i; + struct bios_parser *bp; + enum bp_result record_result; + + const unsigned int slot_index_to_vbios_id[MAX_BOARD_SLOTS] = { + GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID1, + GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID2, + 0, 0 + }; + + bp = BP_FROM_DCB(dcb); + if (board_layout_info == NULL) { + DC_LOG_DETECTION_EDID_PARSER("Invalid board_layout_info\n"); + return BP_RESULT_BADINPUT; + } + + board_layout_info->num_of_slots = 0; + + for (i = 0; i < MAX_BOARD_SLOTS; ++i) { + record_result = get_bracket_layout_record(dcb, + slot_index_to_vbios_id[i], + &board_layout_info->slots[i]); + + if (record_result == BP_RESULT_NORECORD && i > 0) + break; /* no more slots present in bios */ + else if (record_result != BP_RESULT_OK) + return record_result; /* fail */ + + ++board_layout_info->num_of_slots; + } + + /* all data is valid */ + board_layout_info->is_number_of_slots_valid = 1; + board_layout_info->is_slots_size_valid = 1; + board_layout_info->is_connector_offsets_valid = 1; + board_layout_info->is_connector_lengths_valid = 1; + + return BP_RESULT_OK; +} + static const struct dc_vbios_funcs vbios_funcs = { .get_connectors_number = bios_parser_get_connectors_number, @@ -1925,6 +2139,8 @@ static const struct dc_vbios_funcs vbios_funcs = { .bios_parser_destroy = firmware_parser_destroy, .get_smu_clock_info = bios_parser_get_smu_clock_info, + + .get_board_layout_info = bios_get_board_layout_info, }; static bool bios_parser_construct( diff --git a/drivers/gpu/drm/amd/display/dc/dc_bios_types.h b/drivers/gpu/drm/amd/display/dc/dc_bios_types.h index d9b84ec7954c5..90082bab71f07 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_bios_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_bios_types.h @@ -198,6 +198,10 @@ struct dc_vbios_funcs { void (*post_init)(struct dc_bios *bios); void (*bios_parser_destroy)(struct dc_bios **dcb); + + enum bp_result (*get_board_layout_info)( + struct dc_bios *dcb, + struct board_layout_info *board_layout_info); }; struct bios_registers { diff --git a/drivers/gpu/drm/amd/display/include/grph_object_defs.h b/drivers/gpu/drm/amd/display/include/grph_object_defs.h index 2941b882b0b6b..58bb42ed85cab 100644 --- a/drivers/gpu/drm/amd/display/include/grph_object_defs.h +++ b/drivers/gpu/drm/amd/display/include/grph_object_defs.h @@ -37,6 +37,10 @@ * ******************************************************************** */ +#define MAX_CONNECTOR_NUMBER_PER_SLOT (16) +#define MAX_BOARD_SLOTS (4) +#define INVALID_CONNECTOR_INDEX ((unsigned int)(-1)) + /* HPD unit id - HW direct translation */ enum hpd_source_id { HPD_SOURCEID1 = 0, @@ -136,5 +140,47 @@ enum sync_source { SYNC_SOURCE_DUAL_GPU_PIN }; +/* connector sizes in millimeters - from BiosParserTypes.hpp */ +#define CONNECTOR_SIZE_DVI 40 +#define CONNECTOR_SIZE_VGA 32 +#define CONNECTOR_SIZE_HDMI 16 +#define CONNECTOR_SIZE_DP 16 +#define CONNECTOR_SIZE_MINI_DP 9 +#define CONNECTOR_SIZE_UNKNOWN 30 + +enum connector_layout_type { + CONNECTOR_LAYOUT_TYPE_UNKNOWN, + CONNECTOR_LAYOUT_TYPE_DVI_D, + CONNECTOR_LAYOUT_TYPE_DVI_I, + CONNECTOR_LAYOUT_TYPE_VGA, + CONNECTOR_LAYOUT_TYPE_HDMI, + CONNECTOR_LAYOUT_TYPE_DP, + CONNECTOR_LAYOUT_TYPE_MINI_DP, +}; +struct connector_layout_info { + struct graphics_object_id connector_id; + enum connector_layout_type connector_type; + unsigned int length; + unsigned int position; /* offset in mm from right side of the board */ +}; + +/* length and width in mm */ +struct slot_layout_info { + unsigned int length; + unsigned int width; + unsigned int num_of_connectors; + struct connector_layout_info connectors[MAX_CONNECTOR_NUMBER_PER_SLOT]; +}; + +struct board_layout_info { + unsigned int num_of_slots; + /* indicates valid information in bracket layout structure. */ + unsigned int is_number_of_slots_valid : 1; + unsigned int is_slots_size_valid : 1; + unsigned int is_connector_offsets_valid : 1; + unsigned int is_connector_lengths_valid : 1; + + struct slot_layout_info slots[MAX_BOARD_SLOTS]; +}; #endif diff --git a/drivers/gpu/drm/amd/display/include/grph_object_id.h b/drivers/gpu/drm/amd/display/include/grph_object_id.h index 92cc6c112ea69..33b3d755fe655 100644 --- a/drivers/gpu/drm/amd/display/include/grph_object_id.h +++ b/drivers/gpu/drm/amd/display/include/grph_object_id.h @@ -292,4 +292,15 @@ static inline enum engine_id dal_graphics_object_id_get_engine_id( return (enum engine_id) id.id; return ENGINE_ID_UNKNOWN; } + +static inline bool dal_graphics_object_id_equal( + struct graphics_object_id id_1, + struct graphics_object_id id_2) +{ + if ((id_1.id == id_2.id) && (id_1.enum_id == id_2.enum_id) && + (id_1.type == id_2.type)) { + return true; + } + return false; +} #endif -- GitLab From f3efec54ed6ac05ba63be1bd93bd741d41b6eb37 Mon Sep 17 00:00:00 2001 From: Tony Cheng <tony.cheng@amd.com> Date: Fri, 8 Jun 2018 17:36:26 -0400 Subject: [PATCH 0751/1506] drm/amd/display: Allow option to use worst-case watermark use worse case watermark (consider both DCC and VM) to keep golden consistent regardless of DCC Signed-off-by: Tony Cheng <tony.cheng@amd.com> Reviewed-by: Aric Cyr <Aric.Cyr@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/display/dc/calcs/dcn_calcs.c | 23 ++++++++++++++++++- drivers/gpu/drm/amd/display/dc/dc.h | 1 + 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c index 12261fbc25e06..e44b8d3d68910 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c @@ -31,6 +31,8 @@ #include "resource.h" #include "dcn10/dcn10_resource.h" +#include "dcn10/dcn10_hubbub.h" + #include "dcn_calc_math.h" #define DC_LOGGER \ @@ -889,7 +891,26 @@ bool dcn_validate_bandwidth( ASSERT(pipe->plane_res.scl_data.ratios.vert.value != dc_fixpt_one.value || v->scaler_rec_out_width[input_idx] == v->viewport_height[input_idx]); } - v->dcc_enable[input_idx] = pipe->plane_state->dcc.enable ? dcn_bw_yes : dcn_bw_no; + + if (dc->debug.optimized_watermark) { + /* + * this method requires us to always re-calculate watermark when dcc change + * between flip. + */ + v->dcc_enable[input_idx] = pipe->plane_state->dcc.enable ? dcn_bw_yes : dcn_bw_no; + } else { + /* + * allow us to disable dcc on the fly without re-calculating WM + * + * extra overhead for DCC is quite small. for 1080p WM without + * DCC is only 0.417us lower (urgent goes from 6.979us to 6.562us) + */ + unsigned int bpe; + + v->dcc_enable[input_idx] = dc->res_pool->hubbub->funcs->dcc_support_pixel_format( + pipe->plane_state->format, &bpe) ? dcn_bw_yes : dcn_bw_no; + } + v->source_pixel_format[input_idx] = tl_pixel_format_to_bw_defs( pipe->plane_state->format); v->source_surface_mode[input_idx] = tl_sw_mode_to_bw_defs( diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 74e6653b9852e..0cb7e10d2505b 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -233,6 +233,7 @@ struct dc_debug { int urgent_latency_ns; int percent_of_ideal_drambw; int dram_clock_change_latency_ns; + bool optimized_watermark; int always_scale; bool disable_pplib_clock_request; bool disable_clock_gate; -- GitLab From 180fc134d712a93a2bbc3d11ed657b5208e6f90f Mon Sep 17 00:00:00 2001 From: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Date: Tue, 5 Jun 2018 12:43:23 -0400 Subject: [PATCH 0752/1506] drm/scheduler: Rename cleanup functions v2. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Everything in the flush code path (i.e. waiting for SW queue to become empty) names with *_flush() and everything in the release code path names *_fini() This patch also effect the amdgpu and etnaviv drivers which use those functions. v2: Also pplay the change to vd3. Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Suggested-by: Christian König <christian.koenig@amd.com> Acked-by: Lucas Stach <l.stach@pengutronix.de> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c | 8 ++++---- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 4 ++-- drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c | 2 +- drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c | 2 +- drivers/gpu/drm/etnaviv/etnaviv_drv.c | 4 ++-- drivers/gpu/drm/scheduler/gpu_scheduler.c | 18 +++++++++--------- drivers/gpu/drm/v3d/v3d_drv.c | 2 +- include/drm/gpu_scheduler.h | 6 +++--- 11 files changed, 26 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c index 64b3a1ed04dca..c0f06c02f2dea 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c @@ -104,7 +104,7 @@ static int amdgpu_ctx_init(struct amdgpu_device *adev, failed: for (j = 0; j < i; j++) - drm_sched_entity_fini(&adev->rings[j]->sched, + drm_sched_entity_destroy(&adev->rings[j]->sched, &ctx->rings[j].entity); kfree(ctx->fences); ctx->fences = NULL; @@ -178,7 +178,7 @@ static void amdgpu_ctx_do_release(struct kref *ref) if (ctx->adev->rings[i] == &ctx->adev->gfx.kiq.ring) continue; - drm_sched_entity_fini(&ctx->adev->rings[i]->sched, + drm_sched_entity_destroy(&ctx->adev->rings[i]->sched, &ctx->rings[i].entity); } @@ -466,7 +466,7 @@ void amdgpu_ctx_mgr_entity_fini(struct amdgpu_ctx_mgr *mgr) if (ctx->adev->rings[i] == &ctx->adev->gfx.kiq.ring) continue; - max_wait = drm_sched_entity_do_release(&ctx->adev->rings[i]->sched, + max_wait = drm_sched_entity_flush(&ctx->adev->rings[i]->sched, &ctx->rings[i].entity, max_wait); } } @@ -492,7 +492,7 @@ void amdgpu_ctx_mgr_entity_cleanup(struct amdgpu_ctx_mgr *mgr) continue; if (kref_read(&ctx->refcount) == 1) - drm_sched_entity_cleanup(&ctx->adev->rings[i]->sched, + drm_sched_entity_fini(&ctx->adev->rings[i]->sched, &ctx->rings[i].entity); else DRM_ERROR("ctx %p is still alive\n", ctx); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 0c084d3d08652..0246cb87d9e4e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -162,7 +162,7 @@ static int amdgpu_ttm_global_init(struct amdgpu_device *adev) static void amdgpu_ttm_global_fini(struct amdgpu_device *adev) { if (adev->mman.mem_global_referenced) { - drm_sched_entity_fini(adev->mman.entity.sched, + drm_sched_entity_destroy(adev->mman.entity.sched, &adev->mman.entity); mutex_destroy(&adev->mman.gtt_window_lock); drm_global_item_unref(&adev->mman.bo_global_ref.ref); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c index cc15d32304022..0b46ea1c62907 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c @@ -309,7 +309,7 @@ int amdgpu_uvd_sw_fini(struct amdgpu_device *adev) for (j = 0; j < adev->uvd.num_uvd_inst; ++j) { kfree(adev->uvd.inst[j].saved_bo); - drm_sched_entity_fini(&adev->uvd.inst[j].ring.sched, &adev->uvd.inst[j].entity); + drm_sched_entity_destroy(&adev->uvd.inst[j].ring.sched, &adev->uvd.inst[j].entity); amdgpu_bo_free_kernel(&adev->uvd.inst[j].vcpu_bo, &adev->uvd.inst[j].gpu_addr, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c index 23d960ec1cf27..b0dcdfd85f5b8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c @@ -222,7 +222,7 @@ int amdgpu_vce_sw_fini(struct amdgpu_device *adev) if (adev->vce.vcpu_bo == NULL) return 0; - drm_sched_entity_fini(&adev->vce.ring[0].sched, &adev->vce.entity); + drm_sched_entity_destroy(&adev->vce.ring[0].sched, &adev->vce.entity); amdgpu_bo_free_kernel(&adev->vce.vcpu_bo, &adev->vce.gpu_addr, (void **)&adev->vce.cpu_addr); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 590db78b8c725..837066076ccf5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -2643,7 +2643,7 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm, vm->root.base.bo = NULL; error_free_sched_entity: - drm_sched_entity_fini(&ring->sched, &vm->entity); + drm_sched_entity_destroy(&ring->sched, &vm->entity); return r; } @@ -2780,7 +2780,7 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm) spin_unlock_irqrestore(&adev->vm_manager.pasid_lock, flags); } - drm_sched_entity_fini(vm->entity.sched, &vm->entity); + drm_sched_entity_destroy(vm->entity.sched, &vm->entity); if (!RB_EMPTY_ROOT(&vm->va.rb_root)) { dev_err(adev->dev, "still active bo inside vm\n"); diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c index bfddf97dd13e6..1df1c6115341d 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c @@ -470,7 +470,7 @@ static int uvd_v6_0_sw_fini(void *handle) return r; if (uvd_v6_0_enc_support(adev)) { - drm_sched_entity_fini(&adev->uvd.inst->ring_enc[0].sched, &adev->uvd.inst->entity_enc); + drm_sched_entity_destroy(&adev->uvd.inst->ring_enc[0].sched, &adev->uvd.inst->entity_enc); for (i = 0; i < adev->uvd.num_enc_rings; ++i) amdgpu_ring_fini(&adev->uvd.inst->ring_enc[i]); diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c index 57d32f21b3a61..ba244d3b74dbb 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c @@ -491,7 +491,7 @@ static int uvd_v7_0_sw_fini(void *handle) return r; for (j = 0; j < adev->uvd.num_uvd_inst; ++j) { - drm_sched_entity_fini(&adev->uvd.inst[j].ring_enc[0].sched, &adev->uvd.inst[j].entity_enc); + drm_sched_entity_destroy(&adev->uvd.inst[j].ring_enc[0].sched, &adev->uvd.inst[j].entity_enc); for (i = 0; i < adev->uvd.num_enc_rings; ++i) amdgpu_ring_fini(&adev->uvd.inst[j].ring_enc[i]); diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c index e5013a9991477..45bfdf4cc1078 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c @@ -78,8 +78,8 @@ static void etnaviv_postclose(struct drm_device *dev, struct drm_file *file) gpu->lastctx = NULL; mutex_unlock(&gpu->lock); - drm_sched_entity_fini(&gpu->sched, - &ctx->sched_entity[i]); + drm_sched_entity_destroy(&gpu->sched, + &ctx->sched_entity[i]); } } diff --git a/drivers/gpu/drm/scheduler/gpu_scheduler.c b/drivers/gpu/drm/scheduler/gpu_scheduler.c index 6a316701da739..7d2560699b84e 100644 --- a/drivers/gpu/drm/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/scheduler/gpu_scheduler.c @@ -256,7 +256,7 @@ static void drm_sched_entity_kill_jobs_cb(struct dma_fence *f, /** - * drm_sched_entity_do_release - Destroy a context entity + * drm_sched_entity_flush - Flush a context entity * * @sched: scheduler instance * @entity: scheduler entity @@ -267,7 +267,7 @@ static void drm_sched_entity_kill_jobs_cb(struct dma_fence *f, * * Returns the remaining time in jiffies left from the input timeout */ -long drm_sched_entity_do_release(struct drm_gpu_scheduler *sched, +long drm_sched_entity_flush(struct drm_gpu_scheduler *sched, struct drm_sched_entity *entity, long timeout) { long ret = timeout; @@ -294,7 +294,7 @@ long drm_sched_entity_do_release(struct drm_gpu_scheduler *sched, return ret; } -EXPORT_SYMBOL(drm_sched_entity_do_release); +EXPORT_SYMBOL(drm_sched_entity_flush); /** * drm_sched_entity_cleanup - Destroy a context entity @@ -306,7 +306,7 @@ EXPORT_SYMBOL(drm_sched_entity_do_release); * entity and signals all jobs with an error code if the process was killed. * */ -void drm_sched_entity_cleanup(struct drm_gpu_scheduler *sched, +void drm_sched_entity_fini(struct drm_gpu_scheduler *sched, struct drm_sched_entity *entity) { @@ -357,7 +357,7 @@ void drm_sched_entity_cleanup(struct drm_gpu_scheduler *sched, dma_fence_put(entity->last_scheduled); entity->last_scheduled = NULL; } -EXPORT_SYMBOL(drm_sched_entity_cleanup); +EXPORT_SYMBOL(drm_sched_entity_fini); /** * drm_sched_entity_fini - Destroy a context entity @@ -367,13 +367,13 @@ EXPORT_SYMBOL(drm_sched_entity_cleanup); * * Calls drm_sched_entity_do_release() and drm_sched_entity_cleanup() */ -void drm_sched_entity_fini(struct drm_gpu_scheduler *sched, +void drm_sched_entity_destroy(struct drm_gpu_scheduler *sched, struct drm_sched_entity *entity) { - drm_sched_entity_do_release(sched, entity, MAX_WAIT_SCHED_ENTITY_Q_EMPTY); - drm_sched_entity_cleanup(sched, entity); + drm_sched_entity_flush(sched, entity, MAX_WAIT_SCHED_ENTITY_Q_EMPTY); + drm_sched_entity_fini(sched, entity); } -EXPORT_SYMBOL(drm_sched_entity_fini); +EXPORT_SYMBOL(drm_sched_entity_destroy); static void drm_sched_entity_wakeup(struct dma_fence *f, struct dma_fence_cb *cb) { diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c index cdb582043b4fc..567f7d46d912d 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.c +++ b/drivers/gpu/drm/v3d/v3d_drv.c @@ -151,7 +151,7 @@ v3d_postclose(struct drm_device *dev, struct drm_file *file) enum v3d_queue q; for (q = 0; q < V3D_MAX_QUEUES; q++) { - drm_sched_entity_fini(&v3d->queue[q].sched, + drm_sched_entity_destroy(&v3d->queue[q].sched, &v3d_priv->sched_entity[q]); } diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h index 7c2dfd6cc1afb..4214ceb71c054 100644 --- a/include/drm/gpu_scheduler.h +++ b/include/drm/gpu_scheduler.h @@ -284,12 +284,12 @@ int drm_sched_entity_init(struct drm_gpu_scheduler *sched, struct drm_sched_entity *entity, struct drm_sched_rq *rq, atomic_t *guilty); -long drm_sched_entity_do_release(struct drm_gpu_scheduler *sched, +long drm_sched_entity_flush(struct drm_gpu_scheduler *sched, struct drm_sched_entity *entity, long timeout); -void drm_sched_entity_cleanup(struct drm_gpu_scheduler *sched, - struct drm_sched_entity *entity); void drm_sched_entity_fini(struct drm_gpu_scheduler *sched, struct drm_sched_entity *entity); +void drm_sched_entity_destroy(struct drm_gpu_scheduler *sched, + struct drm_sched_entity *entity); void drm_sched_entity_push_job(struct drm_sched_job *sched_job, struct drm_sched_entity *entity); void drm_sched_entity_set_rq(struct drm_sched_entity *entity, -- GitLab From c49d82800bbf04a6d7d6843c6f2c2ea5746eb26e Mon Sep 17 00:00:00 2001 From: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Date: Tue, 5 Jun 2018 12:56:26 -0400 Subject: [PATCH 0753/1506] drm/amdgpu: Rename entity cleanup finctions. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Everything in the flush code path (i.e. waiting for SW queue to become empty) names with *_flush() and everything in the release code path names *_fini() Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Suggested-by: Christian König <christian.koenig@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c | 6 +++--- drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index fb17838114c33..86e4d8bd52a68 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -683,8 +683,8 @@ int amdgpu_ctx_ioctl(struct drm_device *dev, void *data, int amdgpu_ctx_wait_prev_fence(struct amdgpu_ctx *ctx, unsigned ring_id); void amdgpu_ctx_mgr_init(struct amdgpu_ctx_mgr *mgr); -void amdgpu_ctx_mgr_entity_cleanup(struct amdgpu_ctx_mgr *mgr); void amdgpu_ctx_mgr_entity_fini(struct amdgpu_ctx_mgr *mgr); +void amdgpu_ctx_mgr_entity_flush(struct amdgpu_ctx_mgr *mgr); void amdgpu_ctx_mgr_fini(struct amdgpu_ctx_mgr *mgr); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c index c0f06c02f2dea..0120b24fae1b9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c @@ -444,7 +444,7 @@ void amdgpu_ctx_mgr_init(struct amdgpu_ctx_mgr *mgr) idr_init(&mgr->ctx_handles); } -void amdgpu_ctx_mgr_entity_fini(struct amdgpu_ctx_mgr *mgr) +void amdgpu_ctx_mgr_entity_flush(struct amdgpu_ctx_mgr *mgr) { struct amdgpu_ctx *ctx; struct idr *idp; @@ -473,7 +473,7 @@ void amdgpu_ctx_mgr_entity_fini(struct amdgpu_ctx_mgr *mgr) mutex_unlock(&mgr->lock); } -void amdgpu_ctx_mgr_entity_cleanup(struct amdgpu_ctx_mgr *mgr) +void amdgpu_ctx_mgr_entity_fini(struct amdgpu_ctx_mgr *mgr) { struct amdgpu_ctx *ctx; struct idr *idp; @@ -506,7 +506,7 @@ void amdgpu_ctx_mgr_fini(struct amdgpu_ctx_mgr *mgr) struct idr *idp; uint32_t id; - amdgpu_ctx_mgr_entity_cleanup(mgr); + amdgpu_ctx_mgr_entity_fini(mgr); idp = &mgr->ctx_handles; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index a549483032b05..6841497414273 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -860,7 +860,7 @@ static int amdgpu_flush(struct file *f, fl_owner_t id) struct drm_file *file_priv = f->private_data; struct amdgpu_fpriv *fpriv = file_priv->driver_priv; - amdgpu_ctx_mgr_entity_fini(&fpriv->ctx_mgr); + amdgpu_ctx_mgr_entity_flush(&fpriv->ctx_mgr); return 0; } -- GitLab From d6258eaa41fc531277d44fbbee670c866025bfdc Mon Sep 17 00:00:00 2001 From: Stefan Agner <stefan@agner.ch> Date: Sun, 17 Jun 2018 10:53:38 +0200 Subject: [PATCH 0754/1506] drm/amd/display: don't initialize result The wrong enum type is used to initialize the result, leading to a warning when using clang: drivers/gpu/drm/amd/amdgpu/../display/dc/core/dc_link_dp.c:1998:26: warning: implicit conversion from enumeration type 'enum ddc_result' to different enumeration type 'enum dc_status' [-Wenum-conversion] enum dc_status result = DDC_RESULT_UNKNOWN; ~~~~~~ ^~~~~~~~~~~~~~~~~~ 1 warning generated. Initialization of result is unnecessary anyway, just drop the initialization. Signed-off-by: Stefan Agner <stefan@agner.ch> Reviewed-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 049fc5cce1d26..84586b679d73e 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 @@ -2000,7 +2000,7 @@ bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd { union hpd_irq_data hpd_irq_dpcd_data = {{{{0}}}}; union device_service_irq device_service_clear = { { 0 } }; - enum dc_status result = DDC_RESULT_UNKNOWN; + enum dc_status result; bool status = false; /* For use cases related to down stream connection status change, * PSR and device auto test, refer to function handle_sst_hpd_irq -- GitLab From cc450654291bb40c2d67a04d7e2fb42bff7e162a Mon Sep 17 00:00:00 2001 From: Flora Cui <Flora.Cui@amd.com> Date: Wed, 27 Jun 2018 13:53:53 +0800 Subject: [PATCH 0755/1506] drm/amdgpu: remove duplicated codes the fence_context and seqno is init in amdgpu_vm_manager_init() & amdgpu_vmid_mgr_init(). remove the amdgpu_vmid_mgr_init() copy. Signed-off-by: Flora Cui <Flora.Cui@amd.com> Reviewed-by: Junwei Zhang <Jerry.Zhang@amd.com> Reviewed-by: Chunming Zhou <david1.zhou@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c index a1c78f90eadff..3a072a7a39f0f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c @@ -578,11 +578,6 @@ void amdgpu_vmid_mgr_init(struct amdgpu_device *adev) list_add_tail(&id_mgr->ids[j].list, &id_mgr->ids_lru); } } - - adev->vm_manager.fence_context = - dma_fence_context_alloc(AMDGPU_MAX_RINGS); - for (i = 0; i < AMDGPU_MAX_RINGS; ++i) - adev->vm_manager.seqno[i] = 0; } /** -- GitLab From f0626896bb2f09e8ce6438f380ac7f6511b72f84 Mon Sep 17 00:00:00 2001 From: rex zhu <rex.zhu@amd.com> Date: Wed, 27 Jun 2018 17:35:40 +0800 Subject: [PATCH 0756/1506] drm/amd/display: Drop unnecessary header file powerplay implement hwmgr_function table for all supported asics in order to conceal the asic's detail infomation. so no need to include the smu10_hwmgr.h. Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Reviewed-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c index ad96e2a2b3cf3..2acbcc7a94120 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c @@ -34,7 +34,6 @@ #include "amdgpu_pm.h" #include "dm_pp_smu.h" #include "../../powerplay/inc/hwmgr.h" -#include "../../powerplay/hwmgr/smu10_hwmgr.h" bool dm_pp_apply_display_requirements( -- GitLab From 66917e56dcfe8d2ba00f2d86c7dfbf953e0604ae Mon Sep 17 00:00:00 2001 From: rex zhu <rex.zhu@amd.com> Date: Wed, 27 Jun 2018 17:34:37 +0800 Subject: [PATCH 0757/1506] drm/amd/display: Fix dm-pp clks type convert error fix a typo when convert displayphyclk type. Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Reviewed-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c index 2acbcc7a94120..cf92d7a24f338 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c @@ -167,6 +167,9 @@ static enum amd_pp_clock_type dc_to_pp_clock_type( amd_pp_clk_type = amd_pp_f_clock; break; case DM_PP_CLOCK_TYPE_DISPLAYPHYCLK: + amd_pp_clk_type = amd_pp_phy_clock; + break; + case DM_PP_CLOCK_TYPE_DPPCLK: amd_pp_clk_type = amd_pp_dpp_clock; break; default: -- GitLab From a8da8ff3332b1f92588d22a8a643965409d1892d Mon Sep 17 00:00:00 2001 From: Rex Zhu <Rex.Zhu@amd.com> Date: Tue, 5 Jun 2018 10:07:53 +0800 Subject: [PATCH 0758/1506] drm/amdgpu: Rename set_mmhub_powergating_by_smu to powergate_mmhub In order to keep consistent with powergate_uvd/vce. Reviewed-by: Evan Quan <evan.quan@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h | 4 ++-- drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c | 4 ++-- drivers/gpu/drm/amd/include/kgd_pp_interface.h | 2 +- drivers/gpu/drm/amd/powerplay/amd_powerplay.c | 8 ++++---- drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c | 4 ++-- drivers/gpu/drm/amd/powerplay/inc/hwmgr.h | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h index 9acfbee91c40a..c6d6926256875 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h @@ -359,8 +359,8 @@ enum amdgpu_pcie_gen { ((adev)->powerplay.pp_funcs->odn_edit_dpm_table(\ (adev)->powerplay.pp_handle, type, parameter, size)) -#define amdgpu_dpm_set_mmhub_powergating_by_smu(adev) \ - ((adev)->powerplay.pp_funcs->set_mmhub_powergating_by_smu( \ +#define amdgpu_dpm_powergate_mmhub(adev) \ + ((adev)->powerplay.pp_funcs->powergate_mmhub( \ (adev)->powerplay.pp_handle)) struct amdgpu_dpm { diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c index 3d53c4413f138..377f5362a3dfc 100644 --- a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c @@ -471,8 +471,8 @@ void mmhub_v1_0_update_power_gating(struct amdgpu_device *adev, RENG_EXECUTE_ON_REG_UPDATE, 1); WREG32_SOC15(MMHUB, 0, mmPCTL1_RENG_EXECUTE, pctl1_reng_execute); - if (adev->powerplay.pp_funcs->set_mmhub_powergating_by_smu) - amdgpu_dpm_set_mmhub_powergating_by_smu(adev); + if (adev->powerplay.pp_funcs->powergate_mmhub) + amdgpu_dpm_powergate_mmhub(adev); } else { pctl0_reng_execute = REG_SET_FIELD(pctl0_reng_execute, diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h index 06f08f34a110d..0f9886298a84e 100644 --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h @@ -269,7 +269,7 @@ struct amd_pm_funcs { int (*get_power_profile_mode)(void *handle, char *buf); int (*set_power_profile_mode)(void *handle, long *input, uint32_t size); int (*odn_edit_dpm_table)(void *handle, uint32_t type, long *input, uint32_t size); - int (*set_mmhub_powergating_by_smu)(void *handle); + int (*powergate_mmhub)(void *handle); }; #endif diff --git a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c index d567be49c31b8..da98208cd1307 100644 --- a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c +++ b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c @@ -1168,19 +1168,19 @@ static int pp_get_display_mode_validation_clocks(void *handle, return ret; } -static int pp_set_mmhub_powergating_by_smu(void *handle) +static int pp_dpm_powergate_mmhub(void *handle) { struct pp_hwmgr *hwmgr = handle; if (!hwmgr || !hwmgr->pm_en) return -EINVAL; - if (hwmgr->hwmgr_func->set_mmhub_powergating_by_smu == NULL) { + if (hwmgr->hwmgr_func->powergate_mmhub == NULL) { pr_info("%s was not implemented.\n", __func__); return 0; } - return hwmgr->hwmgr_func->set_mmhub_powergating_by_smu(hwmgr); + return hwmgr->hwmgr_func->powergate_mmhub(hwmgr); } static const struct amd_pm_funcs pp_dpm_funcs = { @@ -1227,5 +1227,5 @@ static const struct amd_pm_funcs pp_dpm_funcs = { .set_watermarks_for_clocks_ranges = pp_set_watermarks_for_clocks_ranges, .display_clock_voltage_request = pp_display_clock_voltage_request, .get_display_mode_validation_clocks = pp_get_display_mode_validation_clocks, - .set_mmhub_powergating_by_smu = pp_set_mmhub_powergating_by_smu, + .powergate_mmhub = pp_dpm_powergate_mmhub, }; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c index d4bc83e813896..0f8352cf65673 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c @@ -1126,7 +1126,7 @@ static int smu10_smus_notify_pwe(struct pp_hwmgr *hwmgr) return smum_send_msg_to_smc(hwmgr, PPSMC_MSG_SetRccPfcPmeRestoreRegister); } -static int smu10_set_mmhub_powergating_by_smu(struct pp_hwmgr *hwmgr) +static int smu10_powergate_mmhub(struct pp_hwmgr *hwmgr) { return smum_send_msg_to_smc(hwmgr, PPSMC_MSG_PowerGateMmHub); } @@ -1182,7 +1182,7 @@ static const struct pp_hwmgr_func smu10_hwmgr_funcs = { .asic_setup = smu10_setup_asic_task, .power_state_set = smu10_set_power_state_tasks, .dynamic_state_management_disable = smu10_disable_dpm_tasks, - .set_mmhub_powergating_by_smu = smu10_set_mmhub_powergating_by_smu, + .powergate_mmhub = smu10_powergate_mmhub, .smus_notify_pwe = smu10_smus_notify_pwe, .gfx_off_control = smu10_gfx_off_control, .display_clock_voltage_request = smu10_display_clock_voltage_request, diff --git a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h index 40c98ca5feb74..9b07d6e14ec69 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h @@ -327,7 +327,7 @@ struct pp_hwmgr_func { enum PP_OD_DPM_TABLE_COMMAND type, long *input, uint32_t size); int (*set_power_limit)(struct pp_hwmgr *hwmgr, uint32_t n); - int (*set_mmhub_powergating_by_smu)(struct pp_hwmgr *hwmgr); + int (*powergate_mmhub)(struct pp_hwmgr *hwmgr); int (*smus_notify_pwe)(struct pp_hwmgr *hwmgr); }; -- GitLab From 3eb6e4795de3171d5c59f9368f48bb770087de77 Mon Sep 17 00:00:00 2001 From: Rex Zhu <Rex.Zhu@amd.com> Date: Tue, 5 Jun 2018 11:28:03 +0800 Subject: [PATCH 0759/1506] drm/amd/pp: Rename enable_per_cu_power_gating to powergate_gfx keep consistent with powergate_uvd/vce/mmhub Reviewed-by: Evan Quan <evan.quan@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/powerplay/amd_powerplay.c | 6 +++--- drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.c | 2 +- drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.h | 2 +- drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c | 2 +- drivers/gpu/drm/amd/powerplay/inc/hwmgr.h | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c index da98208cd1307..b69da116b30c7 100644 --- a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c +++ b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c @@ -236,13 +236,13 @@ static int pp_set_powergating_state(void *handle, pr_err("gfx off control failed!\n"); } - if (hwmgr->hwmgr_func->enable_per_cu_power_gating == NULL) { - pr_debug("%s was not implemented.\n", __func__); + if (hwmgr->hwmgr_func->powergate_gfx == NULL) { + pr_info("%s was not implemented.\n", __func__); return 0; } /* Enable/disable GFX per cu powergating through SMU */ - return hwmgr->hwmgr_func->enable_per_cu_power_gating(hwmgr, + return hwmgr->hwmgr_func->powergate_gfx(hwmgr, state == AMD_PG_STATE_GATE); } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.c index 41495621d94a0..683b29a993666 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.c @@ -416,7 +416,7 @@ int smu7_update_clock_gatings(struct pp_hwmgr *hwmgr, * Powerplay will only control the static per CU Power Gating. * Dynamic per CU Power Gating will be done in gfx. */ -int smu7_enable_per_cu_power_gating(struct pp_hwmgr *hwmgr, bool enable) +int smu7_powergate_gfx(struct pp_hwmgr *hwmgr, bool enable) { struct amdgpu_device *adev = hwmgr->adev; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.h b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.h index be7f66d2b234a..fc8f8a6acc722 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.h +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_clockpowergating.h @@ -33,6 +33,6 @@ int smu7_powergate_acp(struct pp_hwmgr *hwmgr, bool bgate); int smu7_disable_clock_power_gating(struct pp_hwmgr *hwmgr); int smu7_update_clock_gatings(struct pp_hwmgr *hwmgr, const uint32_t *msg_id); -int smu7_enable_per_cu_power_gating(struct pp_hwmgr *hwmgr, bool enable); +int smu7_powergate_gfx(struct pp_hwmgr *hwmgr, bool enable); #endif diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c index b89d6fb8559b8..de295b7442b7b 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c @@ -5044,7 +5044,7 @@ static const struct pp_hwmgr_func smu7_hwmgr_funcs = { .get_fan_control_mode = smu7_get_fan_control_mode, .force_clock_level = smu7_force_clock_level, .print_clock_levels = smu7_print_clock_levels, - .enable_per_cu_power_gating = smu7_enable_per_cu_power_gating, + .powergate_gfx = smu7_powergate_gfx, .get_sclk_od = smu7_get_sclk_od, .set_sclk_od = smu7_set_sclk_od, .get_mclk_od = smu7_get_mclk_od, diff --git a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h index 9b07d6e14ec69..95e29a22e4451 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h @@ -302,7 +302,7 @@ struct pp_hwmgr_func { int (*power_off_asic)(struct pp_hwmgr *hwmgr); int (*force_clock_level)(struct pp_hwmgr *hwmgr, enum pp_clock_type type, uint32_t mask); int (*print_clock_levels)(struct pp_hwmgr *hwmgr, enum pp_clock_type type, char *buf); - int (*enable_per_cu_power_gating)(struct pp_hwmgr *hwmgr, bool enable); + int (*powergate_gfx)(struct pp_hwmgr *hwmgr, bool enable); int (*get_sclk_od)(struct pp_hwmgr *hwmgr); int (*set_sclk_od)(struct pp_hwmgr *hwmgr, uint32_t value); int (*get_mclk_od)(struct pp_hwmgr *hwmgr); -- GitLab From b92c628712ed3a1cf5d4a144290e8ffc170bf51e Mon Sep 17 00:00:00 2001 From: Rex Zhu <Rex.Zhu@amd.com> Date: Tue, 5 Jun 2018 13:06:11 +0800 Subject: [PATCH 0760/1506] drm/amd/pp: Unify powergate_uvd/vce/mmhub to set_powergating_by_smu Some HW ip blocks need call SMU to enter/leave power gate state. So export common set_powergating_by_smu interface. 1. keep consistent with set_clockgating_by_smu 2. scales easily to powergate other ip(gfx) if necessary Reviewed-by: Evan Quan <evan.quan@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h | 14 +++------ drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | 8 ++--- drivers/gpu/drm/amd/amdgpu/ci_dpm.c | 15 +++++++++- drivers/gpu/drm/amd/amdgpu/kv_dpm.c | 15 +++++++++- drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c | 4 +-- .../gpu/drm/amd/include/kgd_pp_interface.h | 5 ++-- drivers/gpu/drm/amd/powerplay/amd_powerplay.c | 29 +++++++++++++++++-- 7 files changed, 66 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h index c6d6926256875..ff24e1cc5b65b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h @@ -287,12 +287,6 @@ enum amdgpu_pcie_gen { #define amdgpu_dpm_force_performance_level(adev, l) \ ((adev)->powerplay.pp_funcs->force_performance_level((adev)->powerplay.pp_handle, (l))) -#define amdgpu_dpm_powergate_uvd(adev, g) \ - ((adev)->powerplay.pp_funcs->powergate_uvd((adev)->powerplay.pp_handle, (g))) - -#define amdgpu_dpm_powergate_vce(adev, g) \ - ((adev)->powerplay.pp_funcs->powergate_vce((adev)->powerplay.pp_handle, (g))) - #define amdgpu_dpm_get_current_power_state(adev) \ ((adev)->powerplay.pp_funcs->get_current_power_state((adev)->powerplay.pp_handle)) @@ -347,6 +341,10 @@ enum amdgpu_pcie_gen { ((adev)->powerplay.pp_funcs->set_clockgating_by_smu(\ (adev)->powerplay.pp_handle, msg_id)) +#define amdgpu_dpm_set_powergating_by_smu(adev, block_type, gate) \ + ((adev)->powerplay.pp_funcs->set_powergating_by_smu(\ + (adev)->powerplay.pp_handle, block_type, gate)) + #define amdgpu_dpm_get_power_profile_mode(adev, buf) \ ((adev)->powerplay.pp_funcs->get_power_profile_mode(\ (adev)->powerplay.pp_handle, buf)) @@ -359,10 +357,6 @@ enum amdgpu_pcie_gen { ((adev)->powerplay.pp_funcs->odn_edit_dpm_table(\ (adev)->powerplay.pp_handle, type, parameter, size)) -#define amdgpu_dpm_powergate_mmhub(adev) \ - ((adev)->powerplay.pp_funcs->powergate_mmhub( \ - (adev)->powerplay.pp_handle)) - struct amdgpu_dpm { struct amdgpu_ps *ps; /* number of valid power states */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c index fdb3998219154..a003fd881a89f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c @@ -1729,10 +1729,10 @@ static void amdgpu_dpm_change_power_state_locked(struct amdgpu_device *adev) void amdgpu_dpm_enable_uvd(struct amdgpu_device *adev, bool enable) { - if (adev->powerplay.pp_funcs->powergate_uvd) { + if (adev->powerplay.pp_funcs->set_powergating_by_smu) { /* enable/disable UVD */ mutex_lock(&adev->pm.mutex); - amdgpu_dpm_powergate_uvd(adev, !enable); + amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_UVD, !enable); mutex_unlock(&adev->pm.mutex); } else { if (enable) { @@ -1751,10 +1751,10 @@ void amdgpu_dpm_enable_uvd(struct amdgpu_device *adev, bool enable) void amdgpu_dpm_enable_vce(struct amdgpu_device *adev, bool enable) { - if (adev->powerplay.pp_funcs->powergate_vce) { + if (adev->powerplay.pp_funcs->set_powergating_by_smu) { /* enable/disable VCE */ mutex_lock(&adev->pm.mutex); - amdgpu_dpm_powergate_vce(adev, !enable); + amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_VCE, !enable); mutex_unlock(&adev->pm.mutex); } else { if (enable) { diff --git a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c index c9d45cffca567..7c4ff71e7476e 100644 --- a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c @@ -6767,6 +6767,19 @@ static int ci_dpm_read_sensor(void *handle, int idx, } } +static int ci_set_powergating_by_smu(void *handle, + uint32_t block_type, bool gate) +{ + switch (block_type) { + case AMD_IP_BLOCK_TYPE_UVD: + ci_dpm_powergate_uvd(handle, gate); + break; + default: + break; + } + return 0; +} + static const struct amd_ip_funcs ci_dpm_ip_funcs = { .name = "ci_dpm", .early_init = ci_dpm_early_init, @@ -6804,7 +6817,7 @@ static const struct amd_pm_funcs ci_dpm_funcs = { .debugfs_print_current_performance_level = &ci_dpm_debugfs_print_current_performance_level, .force_performance_level = &ci_dpm_force_performance_level, .vblank_too_short = &ci_dpm_vblank_too_short, - .powergate_uvd = &ci_dpm_powergate_uvd, + .set_powergating_by_smu = &ci_set_powergating_by_smu, .set_fan_control_mode = &ci_dpm_set_fan_control_mode, .get_fan_control_mode = &ci_dpm_get_fan_control_mode, .set_fan_speed_percent = &ci_dpm_set_fan_speed_percent, diff --git a/drivers/gpu/drm/amd/amdgpu/kv_dpm.c b/drivers/gpu/drm/amd/amdgpu/kv_dpm.c index 46de1fd18a7ba..3f57f6463dc88 100644 --- a/drivers/gpu/drm/amd/amdgpu/kv_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/kv_dpm.c @@ -3306,6 +3306,19 @@ static int kv_dpm_read_sensor(void *handle, int idx, } } +static int kv_set_powergating_by_smu(void *handle, + uint32_t block_type, bool gate) +{ + switch (block_type) { + case AMD_IP_BLOCK_TYPE_UVD: + kv_dpm_powergate_uvd(handle, gate); + break; + default: + break; + } + return 0; +} + static const struct amd_ip_funcs kv_dpm_ip_funcs = { .name = "kv_dpm", .early_init = kv_dpm_early_init, @@ -3342,7 +3355,7 @@ static const struct amd_pm_funcs kv_dpm_funcs = { .print_power_state = &kv_dpm_print_power_state, .debugfs_print_current_performance_level = &kv_dpm_debugfs_print_current_performance_level, .force_performance_level = &kv_dpm_force_performance_level, - .powergate_uvd = &kv_dpm_powergate_uvd, + .set_powergating_by_smu = kv_set_powergating_by_smu, .enable_bapm = &kv_dpm_enable_bapm, .get_vce_clock_state = amdgpu_get_vce_clock_state, .check_state_equal = kv_check_state_equal, diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c index 377f5362a3dfc..e70a0d4d6db41 100644 --- a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c @@ -471,8 +471,8 @@ void mmhub_v1_0_update_power_gating(struct amdgpu_device *adev, RENG_EXECUTE_ON_REG_UPDATE, 1); WREG32_SOC15(MMHUB, 0, mmPCTL1_RENG_EXECUTE, pctl1_reng_execute); - if (adev->powerplay.pp_funcs->powergate_mmhub) - amdgpu_dpm_powergate_mmhub(adev); + if (adev->powerplay.pp_funcs->set_powergating_by_smu) + amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_GMC, true); } else { pctl0_reng_execute = REG_SET_FIELD(pctl0_reng_execute, diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h index 0f9886298a84e..4535756428f98 100644 --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h @@ -232,13 +232,13 @@ struct amd_pm_funcs { void (*debugfs_print_current_performance_level)(void *handle, struct seq_file *m); int (*switch_power_profile)(void *handle, enum PP_SMC_POWER_PROFILE type, bool en); /* export to amdgpu */ - void (*powergate_uvd)(void *handle, bool gate); - void (*powergate_vce)(void *handle, bool gate); struct amd_vce_state *(*get_vce_clock_state)(void *handle, u32 idx); int (*dispatch_tasks)(void *handle, enum amd_pp_task task_id, enum amd_pm_state_type *user_state); int (*load_firmware)(void *handle); int (*wait_for_fw_loading_complete)(void *handle); + int (*set_powergating_by_smu)(void *handle, + uint32_t block_type, bool gate); int (*set_clockgating_by_smu)(void *handle, uint32_t msg_id); int (*set_power_limit)(void *handle, uint32_t n); int (*get_power_limit)(void *handle, uint32_t *limit, bool default_limit); @@ -269,7 +269,6 @@ struct amd_pm_funcs { int (*get_power_profile_mode)(void *handle, char *buf); int (*set_power_profile_mode)(void *handle, long *input, uint32_t size); int (*odn_edit_dpm_table)(void *handle, uint32_t type, long *input, uint32_t size); - int (*powergate_mmhub)(void *handle); }; #endif diff --git a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c index b69da116b30c7..f68551ffb1e27 100644 --- a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c +++ b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c @@ -244,6 +244,7 @@ static int pp_set_powergating_state(void *handle, /* Enable/disable GFX per cu powergating through SMU */ return hwmgr->hwmgr_func->powergate_gfx(hwmgr, state == AMD_PG_STATE_GATE); + } static int pp_suspend(void *handle) @@ -1183,14 +1184,36 @@ static int pp_dpm_powergate_mmhub(void *handle) return hwmgr->hwmgr_func->powergate_mmhub(hwmgr); } +static int pp_set_powergating_by_smu(void *handle, + uint32_t block_type, bool gate) +{ + int ret = 0; + + switch (block_type) { + case AMD_IP_BLOCK_TYPE_UVD: + case AMD_IP_BLOCK_TYPE_VCN: + pp_dpm_powergate_uvd(handle, gate); + break; + case AMD_IP_BLOCK_TYPE_VCE: + pp_dpm_powergate_vce(handle, gate); + break; + case AMD_IP_BLOCK_TYPE_GMC: + pp_dpm_powergate_mmhub(handle); + break; + case AMD_IP_BLOCK_TYPE_GFX: + break; + default: + break; + } + return ret; +} + static const struct amd_pm_funcs pp_dpm_funcs = { .load_firmware = pp_dpm_load_fw, .wait_for_fw_loading_complete = pp_dpm_fw_loading_complete, .force_performance_level = pp_dpm_force_performance_level, .get_performance_level = pp_dpm_get_performance_level, .get_current_power_state = pp_dpm_get_current_power_state, - .powergate_vce = pp_dpm_powergate_vce, - .powergate_uvd = pp_dpm_powergate_uvd, .dispatch_tasks = pp_dpm_dispatch_tasks, .set_fan_control_mode = pp_dpm_set_fan_control_mode, .get_fan_control_mode = pp_dpm_get_fan_control_mode, @@ -1210,6 +1233,7 @@ static const struct amd_pm_funcs pp_dpm_funcs = { .get_vce_clock_state = pp_dpm_get_vce_clock_state, .switch_power_profile = pp_dpm_switch_power_profile, .set_clockgating_by_smu = pp_set_clockgating_by_smu, + .set_powergating_by_smu = pp_set_powergating_by_smu, .get_power_profile_mode = pp_get_power_profile_mode, .set_power_profile_mode = pp_set_power_profile_mode, .odn_edit_dpm_table = pp_odn_edit_dpm_table, @@ -1227,5 +1251,4 @@ static const struct amd_pm_funcs pp_dpm_funcs = { .set_watermarks_for_clocks_ranges = pp_set_watermarks_for_clocks_ranges, .display_clock_voltage_request = pp_display_clock_voltage_request, .get_display_mode_validation_clocks = pp_get_display_mode_validation_clocks, - .powergate_mmhub = pp_dpm_powergate_mmhub, }; -- GitLab From 85f80cb3af10f5daf79eee28300c3bbc55a70666 Mon Sep 17 00:00:00 2001 From: Rex Zhu <Rex.Zhu@amd.com> Date: Thu, 14 Jun 2018 13:07:19 +0800 Subject: [PATCH 0761/1506] drm/amd/pp: Add gfx pg support in smu through set_powergating_by_smu gfx ip block can call set_powergating_by_smu to set gfx pg state if necessary. Reviewed-by: Evan Quan <evan.quan@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 10 +++----- drivers/gpu/drm/amd/powerplay/amd_powerplay.c | 25 +++++++++++++------ 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index 4201f3dfaecec..e69fbc944956e 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -5606,14 +5606,12 @@ static int gfx_v8_0_late_init(void *handle) static void gfx_v8_0_enable_gfx_static_mg_power_gating(struct amdgpu_device *adev, bool enable) { - if ((adev->asic_type == CHIP_POLARIS11) || + if (((adev->asic_type == CHIP_POLARIS11) || (adev->asic_type == CHIP_POLARIS12) || - (adev->asic_type == CHIP_VEGAM)) + (adev->asic_type == CHIP_VEGAM)) && + adev->powerplay.pp_funcs->set_powergating_by_smu) /* Send msg to SMU via Powerplay */ - amdgpu_device_ip_set_powergating_state(adev, - AMD_IP_BLOCK_TYPE_SMC, - enable ? - AMD_PG_STATE_GATE : AMD_PG_STATE_UNGATE); + amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_GFX, enable); WREG32_FIELD(RLC_PG_CNTL, STATIC_PER_CU_PG_ENABLE, enable ? 1 : 0); } diff --git a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c index f68551ffb1e27..ef4884b0ddff9 100644 --- a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c +++ b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c @@ -236,14 +236,7 @@ static int pp_set_powergating_state(void *handle, pr_err("gfx off control failed!\n"); } - if (hwmgr->hwmgr_func->powergate_gfx == NULL) { - pr_info("%s was not implemented.\n", __func__); - return 0; - } - - /* Enable/disable GFX per cu powergating through SMU */ - return hwmgr->hwmgr_func->powergate_gfx(hwmgr, - state == AMD_PG_STATE_GATE); + return 0; } @@ -1184,6 +1177,21 @@ static int pp_dpm_powergate_mmhub(void *handle) return hwmgr->hwmgr_func->powergate_mmhub(hwmgr); } +static int pp_dpm_powergate_gfx(void *handle, bool gate) +{ + struct pp_hwmgr *hwmgr = handle; + + if (!hwmgr || !hwmgr->pm_en) + return 0; + + if (hwmgr->hwmgr_func->powergate_gfx == NULL) { + pr_info("%s was not implemented.\n", __func__); + return 0; + } + + return hwmgr->hwmgr_func->powergate_gfx(hwmgr, gate); +} + static int pp_set_powergating_by_smu(void *handle, uint32_t block_type, bool gate) { @@ -1201,6 +1209,7 @@ static int pp_set_powergating_by_smu(void *handle, pp_dpm_powergate_mmhub(handle); break; case AMD_IP_BLOCK_TYPE_GFX: + ret = pp_dpm_powergate_gfx(handle, gate); break; default: break; -- GitLab From a214e1c415e70f5cbc7835180cb9ed5c8e4aa35e Mon Sep 17 00:00:00 2001 From: Rex Zhu <Rex.Zhu@amd.com> Date: Tue, 5 Jun 2018 13:55:04 +0800 Subject: [PATCH 0762/1506] drm/amd/pp: Add powergate_gfx backend function on Raven Raven support gfx off feature instand of gfx powergate, so use smu10_gfx_off_control as the powergate_gfx backend function. Reviewed-by: Evan Quan <evan.quan@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c index 0f8352cf65673..0bbf11d464dda 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c @@ -1186,6 +1186,7 @@ static const struct pp_hwmgr_func smu10_hwmgr_funcs = { .smus_notify_pwe = smu10_smus_notify_pwe, .gfx_off_control = smu10_gfx_off_control, .display_clock_voltage_request = smu10_display_clock_voltage_request, + .powergate_gfx = smu10_gfx_off_control, }; int smu10_init_function_pointers(struct pp_hwmgr *hwmgr) -- GitLab From 9134c6d7f288f902d932e7cf57fab2f49e8ad70b Mon Sep 17 00:00:00 2001 From: Rex Zhu <Rex.Zhu@amd.com> Date: Tue, 5 Jun 2018 11:46:35 +0800 Subject: [PATCH 0763/1506] drm/amdgpu: Add gfx_off support in smu through pp_set_powergating_by_smu we can take gfx off feature as gfx power gate. gfx off feature is also controled by smu. so add gfx_off support in pp_set_powergating_by_smu. Reviewed-by: Evan Quan <evan.quan@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 19 +++++++------------ drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 4 ++++ drivers/gpu/drm/amd/powerplay/amd_powerplay.c | 16 ---------------- 3 files changed, 11 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index d82d0d3142853..c33a41ace0282 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -1730,16 +1730,11 @@ static int amdgpu_device_ip_late_set_cg_state(struct amdgpu_device *adev) } } - if (adev->powerplay.pp_feature & PP_GFXOFF_MASK) { + if (adev->powerplay.pp_feature & PP_GFXOFF_MASK) /* enable gfx powergating */ amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_GFX, AMD_PG_STATE_GATE); - /* enable gfxoff */ - amdgpu_device_ip_set_powergating_state(adev, - AMD_IP_BLOCK_TYPE_SMC, - AMD_PG_STATE_GATE); - } return 0; } @@ -1812,6 +1807,8 @@ static int amdgpu_device_ip_fini(struct amdgpu_device *adev) adev->ip_blocks[i].version->funcs->name, r); return r; } + if (adev->powerplay.pp_funcs->set_powergating_by_smu) + amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_GFX, false); r = adev->ip_blocks[i].version->funcs->hw_fini((void *)adev); /* XXX handle errors */ if (r) { @@ -1921,12 +1918,6 @@ int amdgpu_device_ip_suspend(struct amdgpu_device *adev) if (amdgpu_sriov_vf(adev)) amdgpu_virt_request_full_gpu(adev, false); - /* ungate SMC block powergating */ - if (adev->powerplay.pp_feature & PP_GFXOFF_MASK) - amdgpu_device_ip_set_powergating_state(adev, - AMD_IP_BLOCK_TYPE_SMC, - AMD_PG_STATE_UNGATE); - /* ungate SMC block first */ r = amdgpu_device_ip_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_SMC, AMD_CG_STATE_UNGATE); @@ -1934,6 +1925,10 @@ int amdgpu_device_ip_suspend(struct amdgpu_device *adev) DRM_ERROR("set_clockgating_state(ungate) SMC failed %d\n", r); } + /* call smu to disable gfx off feature first when suspend */ + if (adev->powerplay.pp_funcs->set_powergating_by_smu) + amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_GFX, false); + for (i = adev->num_ip_blocks - 1; i >= 0; i--) { if (!adev->ip_blocks[i].status.valid) continue; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index a69153435ea7e..ac46eabe3bcde 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -3714,6 +3714,10 @@ static int gfx_v9_0_set_powergating_state(void *handle, /* update mgcg state */ gfx_v9_0_update_gfx_mg_power_gating(adev, enable); + + /* set gfx off through smu */ + if (enable && adev->powerplay.pp_funcs->set_powergating_by_smu) + amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_GFX, true); break; default: break; diff --git a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c index ef4884b0ddff9..387a1eb6678dc 100644 --- a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c +++ b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c @@ -221,23 +221,7 @@ static int pp_sw_reset(void *handle) static int pp_set_powergating_state(void *handle, enum amd_powergating_state state) { - struct amdgpu_device *adev = handle; - struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; - int ret; - - if (!hwmgr || !hwmgr->pm_en) - return 0; - - if (hwmgr->hwmgr_func->gfx_off_control) { - /* Enable/disable GFX off through SMU */ - ret = hwmgr->hwmgr_func->gfx_off_control(hwmgr, - state == AMD_PG_STATE_GATE); - if (ret) - pr_err("gfx off control failed!\n"); - } - return 0; - } static int pp_suspend(void *handle) -- GitLab From c9f96fd5063150dce7e71ecc508989f5ff055039 Mon Sep 17 00:00:00 2001 From: Rex Zhu <Rex.Zhu@amd.com> Date: Wed, 13 Jun 2018 19:30:40 +0800 Subject: [PATCH 0764/1506] drm/amdgpu: Split set_pg_state into separate function 1. add amdgpu_device_ip_late_set_pg_state function for set pg state. 2. delete duplicate pg state setting on gfx_v8_0's late_init. Reviewed-by: Evan Quan <evan.quan@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 33 ++++++++++++++++++---- drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 4 --- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index c33a41ace0282..e38564e7c5ecc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -1730,12 +1730,34 @@ static int amdgpu_device_ip_late_set_cg_state(struct amdgpu_device *adev) } } - if (adev->powerplay.pp_feature & PP_GFXOFF_MASK) - /* enable gfx powergating */ - amdgpu_device_ip_set_powergating_state(adev, - AMD_IP_BLOCK_TYPE_GFX, - AMD_PG_STATE_GATE); + return 0; +} + +static int amdgpu_device_ip_late_set_pg_state(struct amdgpu_device *adev) +{ + int i = 0, r; + if (amdgpu_emu_mode == 1) + return 0; + + for (i = 0; i < adev->num_ip_blocks; i++) { + if (!adev->ip_blocks[i].status.valid) + continue; + /* skip CG for VCE/UVD, it's handled specially */ + if (adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_UVD && + adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_VCE && + adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_VCN && + adev->ip_blocks[i].version->funcs->set_powergating_state) { + /* enable powergating to save power */ + r = adev->ip_blocks[i].version->funcs->set_powergating_state((void *)adev, + AMD_PG_STATE_GATE); + if (r) { + DRM_ERROR("set_powergating_state(gate) of IP block <%s> failed %d\n", + adev->ip_blocks[i].version->funcs->name, r); + return r; + } + } + } return 0; } @@ -1898,6 +1920,7 @@ static void amdgpu_device_ip_late_init_func_handler(struct work_struct *work) struct amdgpu_device *adev = container_of(work, struct amdgpu_device, late_init_work.work); amdgpu_device_ip_late_set_cg_state(adev); + amdgpu_device_ip_late_set_pg_state(adev); } /** diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index e69fbc944956e..551f21bad6d38 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -5596,10 +5596,6 @@ static int gfx_v8_0_late_init(void *handle) return r; } - amdgpu_device_ip_set_powergating_state(adev, - AMD_IP_BLOCK_TYPE_GFX, - AMD_PG_STATE_GATE); - return 0; } -- GitLab From 916ac57ffbe952c02fcd883dee28970e39366eca Mon Sep 17 00:00:00 2001 From: Rex Zhu <Rex.Zhu@amd.com> Date: Wed, 6 Jun 2018 13:42:42 +0800 Subject: [PATCH 0765/1506] drm/amdgpu: Move CG/PG setting out of delay worker thread MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Partially revert commit 2dc80b00652f ("drm/amdgpu: optimize amdgpu driver load & resume time")' 1. CG/PG enablement are part of gpu hw ip initialize, we should wait for them complete. otherwise, there are some potential conflicts, for example, Suspend and CG enablement concurrently. 2. better run ib test after hw initialize completely. That is to say, ib test should be after CG/PG enablement. otherwise, the test will not cover the cg/pg/poweroff enable case. Reviewed-by: Evan Quan <evan.quan@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index e38564e7c5ecc..c35db859f050d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -1707,10 +1707,6 @@ static int amdgpu_device_ip_late_set_cg_state(struct amdgpu_device *adev) if (amdgpu_emu_mode == 1) return 0; - r = amdgpu_ib_ring_tests(adev); - if (r) - DRM_ERROR("ib ring test failed (%d).\n", r); - for (i = 0; i < adev->num_ip_blocks; i++) { if (!adev->ip_blocks[i].status.valid) continue; @@ -1791,6 +1787,9 @@ static int amdgpu_device_ip_late_init(struct amdgpu_device *adev) } } + amdgpu_device_ip_late_set_cg_state(adev); + amdgpu_device_ip_late_set_pg_state(adev); + queue_delayed_work(system_wq, &adev->late_init_work, msecs_to_jiffies(AMDGPU_RESUME_MS)); @@ -1919,8 +1918,11 @@ static void amdgpu_device_ip_late_init_func_handler(struct work_struct *work) { struct amdgpu_device *adev = container_of(work, struct amdgpu_device, late_init_work.work); - amdgpu_device_ip_late_set_cg_state(adev); - amdgpu_device_ip_late_set_pg_state(adev); + int r; + + r = amdgpu_ib_ring_tests(adev); + if (r) + DRM_ERROR("ib ring test failed (%d).\n", r); } /** -- GitLab From 22994e16dd025aefd7f97a863f13ae23d8853601 Mon Sep 17 00:00:00 2001 From: rex zhu <rex.zhu@amd.com> Date: Wed, 27 Jun 2018 18:08:43 +0800 Subject: [PATCH 0766/1506] drm/amdgpu: Add stutter mode ctrl in module parameter Enable stutter mode can save power in low DRAM use cases including but not limited to productivity application use, web browsing, and video playback. Currently this feature is disabled by default. Make bit 17 in module parameter amdgpu_pp_feature_mask as stutter mode mask, so user can enable/disable this feature easily. Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Reviewed-by: Huang Rui <ray.huang@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 3 ++- drivers/gpu/drm/amd/include/amd_shared.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 6841497414273..dcdc97d6dc447 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -122,7 +122,8 @@ uint amdgpu_pg_mask = 0xffffffff; uint amdgpu_sdma_phase_quantum = 32; char *amdgpu_disable_cu = NULL; char *amdgpu_virtual_display = NULL; -uint amdgpu_pp_feature_mask = 0xffff3fff; /* gfxoff (bit 15) disabled by default */ +/* OverDrive(bit 14),gfxoff(bit 15),stutter mode(bit 17) disabled by default*/ +uint amdgpu_pp_feature_mask = 0xfffd3fff; int amdgpu_ngg = 0; int amdgpu_prim_buf_per_se = 0; int amdgpu_pos_buf_per_se = 0; diff --git a/drivers/gpu/drm/amd/include/amd_shared.h b/drivers/gpu/drm/amd/include/amd_shared.h index b178176b72ac6..d6f487497397f 100644 --- a/drivers/gpu/drm/amd/include/amd_shared.h +++ b/drivers/gpu/drm/amd/include/amd_shared.h @@ -128,6 +128,7 @@ enum PP_FEATURE_MASK { PP_OVERDRIVE_MASK = 0x4000, PP_GFXOFF_MASK = 0x8000, PP_ACG_MASK = 0x10000, + PP_STUTTER_MODE = 0x20000, }; struct amd_ip_funcs { -- GitLab From e856ec3c292ecd6c15e38f2c6c22b350dc0daa17 Mon Sep 17 00:00:00 2001 From: rex zhu <rex.zhu@amd.com> Date: Wed, 27 Jun 2018 18:19:08 +0800 Subject: [PATCH 0767/1506] drm/amd/display: Ctrl stutter mode through module parameter use ppfeaturemask to enable/disable stutter mode. Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Reviewed-by: Huang Rui <ray.huang@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 356ac27d01802..74683071fa817 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -1535,7 +1535,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) /* * Temporary disable until pplib/smu interaction is implemented */ - dm->dc->debug.disable_stutter = true; + dm->dc->debug.disable_stutter = amdgpu_pp_feature_mask & PP_STUTTER_MODE ? false : true; break; #endif default: -- GitLab From b1c6fddb583f70892f2dd6de8c63af3aa4600a7b Mon Sep 17 00:00:00 2001 From: Rex Zhu <Rex.Zhu@amd.com> Date: Wed, 20 Jun 2018 12:52:43 +0800 Subject: [PATCH 0768/1506] drm/amd/display: Fix a typo in wm_min_memg_clk_in_khz change wm_min_memg_clk_in_khz -> wm_min_mem_clk_in_khz Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c | 8 ++++---- drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c | 8 ++++---- drivers/gpu/drm/amd/display/dc/dm_services_types.h | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c index 752910035e813..9e1afb11e6ad0 100644 --- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c @@ -1000,7 +1000,7 @@ static void bw_calcs_data_update_from_pplib(struct dc *dc) eng_clks.data[0].clocks_in_khz; clk_ranges.wm_clk_ranges[0].wm_max_eng_clk_in_khz = eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz - 1; - clk_ranges.wm_clk_ranges[0].wm_min_memg_clk_in_khz = + clk_ranges.wm_clk_ranges[0].wm_min_mem_clk_in_khz = mem_clks.data[0].clocks_in_khz; clk_ranges.wm_clk_ranges[0].wm_max_mem_clk_in_khz = mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz - 1; @@ -1010,7 +1010,7 @@ static void bw_calcs_data_update_from_pplib(struct dc *dc) eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz; /* 5 GHz instead of data[7].clockInKHz to cover Overdrive */ clk_ranges.wm_clk_ranges[1].wm_max_eng_clk_in_khz = 5000000; - clk_ranges.wm_clk_ranges[1].wm_min_memg_clk_in_khz = + clk_ranges.wm_clk_ranges[1].wm_min_mem_clk_in_khz = mem_clks.data[0].clocks_in_khz; clk_ranges.wm_clk_ranges[1].wm_max_mem_clk_in_khz = mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz - 1; @@ -1020,7 +1020,7 @@ static void bw_calcs_data_update_from_pplib(struct dc *dc) eng_clks.data[0].clocks_in_khz; clk_ranges.wm_clk_ranges[2].wm_max_eng_clk_in_khz = eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz - 1; - clk_ranges.wm_clk_ranges[2].wm_min_memg_clk_in_khz = + clk_ranges.wm_clk_ranges[2].wm_min_mem_clk_in_khz = mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz; /* 5 GHz instead of data[2].clockInKHz to cover Overdrive */ clk_ranges.wm_clk_ranges[2].wm_max_mem_clk_in_khz = 5000000; @@ -1030,7 +1030,7 @@ static void bw_calcs_data_update_from_pplib(struct dc *dc) eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz; /* 5 GHz instead of data[7].clockInKHz to cover Overdrive */ clk_ranges.wm_clk_ranges[3].wm_max_eng_clk_in_khz = 5000000; - clk_ranges.wm_clk_ranges[3].wm_min_memg_clk_in_khz = + clk_ranges.wm_clk_ranges[3].wm_min_mem_clk_in_khz = mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz; /* 5 GHz instead of data[2].clockInKHz to cover Overdrive */ clk_ranges.wm_clk_ranges[3].wm_max_mem_clk_in_khz = 5000000; diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c index 13c388a608c44..8381f27a23612 100644 --- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c @@ -775,7 +775,7 @@ static void bw_calcs_data_update_from_pplib(struct dc *dc) eng_clks.data[0].clocks_in_khz; clk_ranges.wm_clk_ranges[0].wm_max_eng_clk_in_khz = eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz - 1; - clk_ranges.wm_clk_ranges[0].wm_min_memg_clk_in_khz = + clk_ranges.wm_clk_ranges[0].wm_min_mem_clk_in_khz = mem_clks.data[0].clocks_in_khz; clk_ranges.wm_clk_ranges[0].wm_max_mem_clk_in_khz = mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz - 1; @@ -785,7 +785,7 @@ static void bw_calcs_data_update_from_pplib(struct dc *dc) eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz; /* 5 GHz instead of data[7].clockInKHz to cover Overdrive */ clk_ranges.wm_clk_ranges[1].wm_max_eng_clk_in_khz = 5000000; - clk_ranges.wm_clk_ranges[1].wm_min_memg_clk_in_khz = + clk_ranges.wm_clk_ranges[1].wm_min_mem_clk_in_khz = mem_clks.data[0].clocks_in_khz; clk_ranges.wm_clk_ranges[1].wm_max_mem_clk_in_khz = mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz - 1; @@ -795,7 +795,7 @@ static void bw_calcs_data_update_from_pplib(struct dc *dc) eng_clks.data[0].clocks_in_khz; clk_ranges.wm_clk_ranges[2].wm_max_eng_clk_in_khz = eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz - 1; - clk_ranges.wm_clk_ranges[2].wm_min_memg_clk_in_khz = + clk_ranges.wm_clk_ranges[2].wm_min_mem_clk_in_khz = mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz; /* 5 GHz instead of data[2].clockInKHz to cover Overdrive */ clk_ranges.wm_clk_ranges[2].wm_max_mem_clk_in_khz = 5000000; @@ -805,7 +805,7 @@ static void bw_calcs_data_update_from_pplib(struct dc *dc) eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz; /* 5 GHz instead of data[7].clockInKHz to cover Overdrive */ clk_ranges.wm_clk_ranges[3].wm_max_eng_clk_in_khz = 5000000; - clk_ranges.wm_clk_ranges[3].wm_min_memg_clk_in_khz = + clk_ranges.wm_clk_ranges[3].wm_min_mem_clk_in_khz = mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz; /* 5 GHz instead of data[2].clockInKHz to cover Overdrive */ clk_ranges.wm_clk_ranges[3].wm_max_mem_clk_in_khz = 5000000; diff --git a/drivers/gpu/drm/amd/display/dc/dm_services_types.h b/drivers/gpu/drm/amd/display/dc/dm_services_types.h index ab8c77d4e6dfe..2b83f922ac026 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_services_types.h +++ b/drivers/gpu/drm/amd/display/dc/dm_services_types.h @@ -137,7 +137,7 @@ struct dm_pp_clock_range_for_wm_set { enum dm_pp_wm_set_id wm_set_id; uint32_t wm_min_eng_clk_in_khz; uint32_t wm_max_eng_clk_in_khz; - uint32_t wm_min_memg_clk_in_khz; + uint32_t wm_min_mem_clk_in_khz; uint32_t wm_max_mem_clk_in_khz; }; @@ -150,7 +150,7 @@ struct dm_pp_clock_range_for_dmif_wm_set_soc15 { enum dm_pp_wm_set_id wm_set_id; uint32_t wm_min_dcfclk_clk_in_khz; uint32_t wm_max_dcfclk_clk_in_khz; - uint32_t wm_min_memg_clk_in_khz; + uint32_t wm_min_mem_clk_in_khz; uint32_t wm_max_mem_clk_in_khz; }; @@ -158,7 +158,7 @@ struct dm_pp_clock_range_for_mcif_wm_set_soc15 { enum dm_pp_wm_set_id wm_set_id; uint32_t wm_min_socclk_clk_in_khz; uint32_t wm_max_socclk_clk_in_khz; - uint32_t wm_min_memg_clk_in_khz; + uint32_t wm_min_mem_clk_in_khz; uint32_t wm_max_mem_clk_in_khz; }; -- GitLab From acee16f4deab484b9b78876b8b292174e95ccf88 Mon Sep 17 00:00:00 2001 From: Evan Quan <evan.quan@amd.com> Date: Mon, 28 May 2018 08:59:16 +0800 Subject: [PATCH 0769/1506] drm/amd/powerplay: correct vega12 bootup values settings The vbios firmware structure changed between v3_1 and v3_2. So, the code to setup bootup values needs different paths based on header version. Signed-off-by: Evan Quan <evan.quan@amd.com> Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../drm/amd/powerplay/hwmgr/ppatomfwctrl.c | 94 ++++++++++++++++--- .../drm/amd/powerplay/hwmgr/ppatomfwctrl.h | 3 + .../drm/amd/powerplay/hwmgr/vega12_hwmgr.c | 3 + .../drm/amd/powerplay/hwmgr/vega12_hwmgr.h | 3 + 4 files changed, 91 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomfwctrl.c b/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomfwctrl.c index 5325661fedffb..aa2faffef0348 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomfwctrl.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomfwctrl.c @@ -512,14 +512,82 @@ int pp_atomfwctrl_get_clk_information_by_clkid(struct pp_hwmgr *hwmgr, BIOS_CLKI return 0; } +static void pp_atomfwctrl_copy_vbios_bootup_values_3_2(struct pp_hwmgr *hwmgr, + struct pp_atomfwctrl_bios_boot_up_values *boot_values, + struct atom_firmware_info_v3_2 *fw_info) +{ + uint32_t frequency = 0; + + boot_values->ulRevision = fw_info->firmware_revision; + boot_values->ulGfxClk = fw_info->bootup_sclk_in10khz; + boot_values->ulUClk = fw_info->bootup_mclk_in10khz; + boot_values->usVddc = fw_info->bootup_vddc_mv; + boot_values->usVddci = fw_info->bootup_vddci_mv; + boot_values->usMvddc = fw_info->bootup_mvddc_mv; + boot_values->usVddGfx = fw_info->bootup_vddgfx_mv; + boot_values->ucCoolingID = fw_info->coolingsolution_id; + boot_values->ulSocClk = 0; + boot_values->ulDCEFClk = 0; + + if (!pp_atomfwctrl_get_clk_information_by_clkid(hwmgr, SMU11_SYSPLL0_SOCCLK_ID, &frequency)) + boot_values->ulSocClk = frequency; + + if (!pp_atomfwctrl_get_clk_information_by_clkid(hwmgr, SMU11_SYSPLL0_DCEFCLK_ID, &frequency)) + boot_values->ulDCEFClk = frequency; + + if (!pp_atomfwctrl_get_clk_information_by_clkid(hwmgr, SMU11_SYSPLL0_ECLK_ID, &frequency)) + boot_values->ulEClk = frequency; + + if (!pp_atomfwctrl_get_clk_information_by_clkid(hwmgr, SMU11_SYSPLL0_VCLK_ID, &frequency)) + boot_values->ulVClk = frequency; + + if (!pp_atomfwctrl_get_clk_information_by_clkid(hwmgr, SMU11_SYSPLL0_DCLK_ID, &frequency)) + boot_values->ulDClk = frequency; +} + +static void pp_atomfwctrl_copy_vbios_bootup_values_3_1(struct pp_hwmgr *hwmgr, + struct pp_atomfwctrl_bios_boot_up_values *boot_values, + struct atom_firmware_info_v3_1 *fw_info) +{ + uint32_t frequency = 0; + + boot_values->ulRevision = fw_info->firmware_revision; + boot_values->ulGfxClk = fw_info->bootup_sclk_in10khz; + boot_values->ulUClk = fw_info->bootup_mclk_in10khz; + boot_values->usVddc = fw_info->bootup_vddc_mv; + boot_values->usVddci = fw_info->bootup_vddci_mv; + boot_values->usMvddc = fw_info->bootup_mvddc_mv; + boot_values->usVddGfx = fw_info->bootup_vddgfx_mv; + boot_values->ucCoolingID = fw_info->coolingsolution_id; + boot_values->ulSocClk = 0; + boot_values->ulDCEFClk = 0; + + if (!pp_atomfwctrl_get_clk_information_by_clkid(hwmgr, SMU9_SYSPLL0_SOCCLK_ID, &frequency)) + boot_values->ulSocClk = frequency; + + if (!pp_atomfwctrl_get_clk_information_by_clkid(hwmgr, SMU9_SYSPLL0_DCEFCLK_ID, &frequency)) + boot_values->ulDCEFClk = frequency; + + if (!pp_atomfwctrl_get_clk_information_by_clkid(hwmgr, SMU9_SYSPLL0_ECLK_ID, &frequency)) + boot_values->ulEClk = frequency; + + if (!pp_atomfwctrl_get_clk_information_by_clkid(hwmgr, SMU9_SYSPLL0_VCLK_ID, &frequency)) + boot_values->ulVClk = frequency; + + if (!pp_atomfwctrl_get_clk_information_by_clkid(hwmgr, SMU9_SYSPLL0_DCLK_ID, &frequency)) + boot_values->ulDClk = frequency; +} + int pp_atomfwctrl_get_vbios_bootup_values(struct pp_hwmgr *hwmgr, struct pp_atomfwctrl_bios_boot_up_values *boot_values) { - struct atom_firmware_info_v3_1 *info = NULL; + struct atom_firmware_info_v3_2 *fwinfo_3_2; + struct atom_firmware_info_v3_1 *fwinfo_3_1; + struct atom_common_table_header *info = NULL; uint16_t ix; ix = GetIndexIntoMasterDataTable(firmwareinfo); - info = (struct atom_firmware_info_v3_1 *) + info = (struct atom_common_table_header *) smu_atom_get_data_table(hwmgr->adev, ix, NULL, NULL, NULL); @@ -528,16 +596,18 @@ int pp_atomfwctrl_get_vbios_bootup_values(struct pp_hwmgr *hwmgr, return -EINVAL; } - boot_values->ulRevision = info->firmware_revision; - boot_values->ulGfxClk = info->bootup_sclk_in10khz; - boot_values->ulUClk = info->bootup_mclk_in10khz; - boot_values->usVddc = info->bootup_vddc_mv; - boot_values->usVddci = info->bootup_vddci_mv; - boot_values->usMvddc = info->bootup_mvddc_mv; - boot_values->usVddGfx = info->bootup_vddgfx_mv; - boot_values->ucCoolingID = info->coolingsolution_id; - boot_values->ulSocClk = 0; - boot_values->ulDCEFClk = 0; + if ((info->format_revision == 3) && (info->content_revision == 2)) { + fwinfo_3_2 = (struct atom_firmware_info_v3_2 *)info; + pp_atomfwctrl_copy_vbios_bootup_values_3_2(hwmgr, + boot_values, fwinfo_3_2); + } else if ((info->format_revision == 3) && (info->content_revision == 1)) { + fwinfo_3_1 = (struct atom_firmware_info_v3_1 *)info; + pp_atomfwctrl_copy_vbios_bootup_values_3_1(hwmgr, + boot_values, fwinfo_3_1); + } else { + pr_info("Fw info table revision does not match!"); + return -EINVAL; + } return 0; } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomfwctrl.h b/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomfwctrl.h index fe10aa4db5e64..745bd3809549b 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomfwctrl.h +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomfwctrl.h @@ -136,6 +136,9 @@ struct pp_atomfwctrl_bios_boot_up_values { uint32_t ulUClk; uint32_t ulSocClk; uint32_t ulDCEFClk; + uint32_t ulEClk; + uint32_t ulVClk; + uint32_t ulDClk; uint16_t usVddc; uint16_t usVddci; uint16_t usMvddc; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c index 782e2098824df..e81661cc9baee 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c @@ -803,6 +803,9 @@ static int vega12_init_smc_table(struct pp_hwmgr *hwmgr) data->vbios_boot_state.soc_clock = boot_up_values.ulSocClk; data->vbios_boot_state.dcef_clock = boot_up_values.ulDCEFClk; data->vbios_boot_state.uc_cooling_id = boot_up_values.ucCoolingID; + data->vbios_boot_state.eclock = boot_up_values.ulEClk; + data->vbios_boot_state.dclock = boot_up_values.ulDClk; + data->vbios_boot_state.vclock = boot_up_values.ulVClk; smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetMinDeepSleepDcefclk, (uint32_t)(data->vbios_boot_state.dcef_clock / 100)); diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.h b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.h index e81ded1ec1982..49b38df8c7f27 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.h @@ -167,6 +167,9 @@ struct vega12_vbios_boot_state { uint32_t mem_clock; uint32_t soc_clock; uint32_t dcef_clock; + uint32_t eclock; + uint32_t dclock; + uint32_t vclock; }; #define DPMTABLE_OD_UPDATE_SCLK 0x00000001 -- GitLab From 77564c9dff26f2a90d089dfb282906ec7be7c144 Mon Sep 17 00:00:00 2001 From: Evan Quan <evan.quan@amd.com> Date: Mon, 11 Jun 2018 15:20:39 +0800 Subject: [PATCH 0770/1506] drm/amd/powerplay: smc_dpm_info structure change A new member Vr2_I2C_address is added. Signed-off-by: Evan Quan <evan.quan@amd.com> Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/include/atomfirmware.h | 5 ++++- drivers/gpu/drm/amd/powerplay/hwmgr/ppatomfwctrl.c | 2 ++ drivers/gpu/drm/amd/powerplay/hwmgr/ppatomfwctrl.h | 2 ++ drivers/gpu/drm/amd/powerplay/hwmgr/vega12_processpptables.c | 2 ++ drivers/gpu/drm/amd/powerplay/inc/vega12/smu9_driver_if.h | 5 ++++- 5 files changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/include/atomfirmware.h b/drivers/gpu/drm/amd/include/atomfirmware.h index 092d800b703a7..33b4de4ad66eb 100644 --- a/drivers/gpu/drm/amd/include/atomfirmware.h +++ b/drivers/gpu/drm/amd/include/atomfirmware.h @@ -1433,7 +1433,10 @@ struct atom_smc_dpm_info_v4_1 uint8_t acggfxclkspreadpercent; uint16_t acggfxclkspreadfreq; - uint32_t boardreserved[10]; + uint8_t Vr2_I2C_address; + uint8_t padding_vr2[3]; + + uint32_t boardreserved[9]; }; /* diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomfwctrl.c b/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomfwctrl.c index aa2faffef0348..d27c1c9df2868 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomfwctrl.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomfwctrl.c @@ -699,5 +699,7 @@ int pp_atomfwctrl_get_smc_dpm_information(struct pp_hwmgr *hwmgr, param->acggfxclkspreadpercent = info->acggfxclkspreadpercent; param->acggfxclkspreadfreq = info->acggfxclkspreadfreq; + param->Vr2_I2C_address = info->Vr2_I2C_address; + return 0; } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomfwctrl.h b/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomfwctrl.h index 745bd3809549b..22e21668c93a4 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomfwctrl.h +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomfwctrl.h @@ -210,6 +210,8 @@ struct pp_atomfwctrl_smc_dpm_parameters uint8_t acggfxclkspreadenabled; uint8_t acggfxclkspreadpercent; uint16_t acggfxclkspreadfreq; + + uint8_t Vr2_I2C_address; }; int pp_atomfwctrl_get_gpu_pll_dividers_vega10(struct pp_hwmgr *hwmgr, diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_processpptables.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_processpptables.c index 888ddca902d89..29914700ee82f 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_processpptables.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_processpptables.c @@ -230,6 +230,8 @@ static int append_vbios_pptable(struct pp_hwmgr *hwmgr, PPTable_t *ppsmc_pptable ppsmc_pptable->AcgThresholdFreqLow = 0xFFFF; } + ppsmc_pptable->Vr2_I2C_address = smc_dpm_table.Vr2_I2C_address; + return 0; } diff --git a/drivers/gpu/drm/amd/powerplay/inc/vega12/smu9_driver_if.h b/drivers/gpu/drm/amd/powerplay/inc/vega12/smu9_driver_if.h index 2f8a3b983cce0..b08526fd16190 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/vega12/smu9_driver_if.h +++ b/drivers/gpu/drm/amd/powerplay/inc/vega12/smu9_driver_if.h @@ -499,7 +499,10 @@ typedef struct { uint8_t AcgGfxclkSpreadPercent; uint16_t AcgGfxclkSpreadFreq; - uint32_t BoardReserved[10]; + uint8_t Vr2_I2C_address; + uint8_t padding_vr2[3]; + + uint32_t BoardReserved[9]; uint32_t MmHubPadding[7]; -- GitLab From 9bf40d787924f45d6a0fa49d3e69d772c2aa5b19 Mon Sep 17 00:00:00 2001 From: Evan Quan <evan.quan@amd.com> Date: Mon, 11 Jun 2018 17:38:54 +0800 Subject: [PATCH 0771/1506] drm/amd/powerplay: drop the acg fix This workaround is not needed any more. Signed-off-by: Evan Quan <evan.quan@amd.com> Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/powerplay/hwmgr/vega12_processpptables.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_processpptables.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_processpptables.c index 29914700ee82f..f4f366b26fd15 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_processpptables.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_processpptables.c @@ -224,12 +224,6 @@ static int append_vbios_pptable(struct pp_hwmgr *hwmgr, PPTable_t *ppsmc_pptable ppsmc_pptable->AcgGfxclkSpreadPercent = smc_dpm_table.acggfxclkspreadpercent; ppsmc_pptable->AcgGfxclkSpreadFreq = smc_dpm_table.acggfxclkspreadfreq; - /* 0xFFFF will disable the ACG feature */ - if (!(hwmgr->feature_mask & PP_ACG_MASK)) { - ppsmc_pptable->AcgThresholdFreqHigh = 0xFFFF; - ppsmc_pptable->AcgThresholdFreqLow = 0xFFFF; - } - ppsmc_pptable->Vr2_I2C_address = smc_dpm_table.Vr2_I2C_address; return 0; -- GitLab From 3b579c5483286fba6e13bc4b2f1d8a6627410371 Mon Sep 17 00:00:00 2001 From: Evan Quan <evan.quan@amd.com> Date: Mon, 11 Jun 2018 15:25:37 +0800 Subject: [PATCH 0772/1506] drm/amd/powerplay: revise default dpm tables setup Initialize the soft/hard min/max level correctly and handle the dpm disabled situation. Signed-off-by: Evan Quan <evan.quan@amd.com> Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../drm/amd/powerplay/hwmgr/vega12_hwmgr.c | 334 +++++++----------- 1 file changed, 132 insertions(+), 202 deletions(-) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c index e81661cc9baee..bc976e1d22c50 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c @@ -453,37 +453,30 @@ static int vega12_setup_asic_task(struct pp_hwmgr *hwmgr) */ static void vega12_init_dpm_state(struct vega12_dpm_state *dpm_state) { - dpm_state->soft_min_level = 0xff; - dpm_state->soft_max_level = 0xff; - dpm_state->hard_min_level = 0xff; - dpm_state->hard_max_level = 0xff; + dpm_state->soft_min_level = 0x0; + dpm_state->soft_max_level = 0xffff; + dpm_state->hard_min_level = 0x0; + dpm_state->hard_max_level = 0xffff; } -static int vega12_get_number_dpm_level(struct pp_hwmgr *hwmgr, - PPCLK_e clkID, uint32_t *num_dpm_level) +static int vega12_get_number_of_dpm_level(struct pp_hwmgr *hwmgr, + PPCLK_e clk_id, uint32_t *num_of_levels) { - int result; - /* - * SMU expects the Clock ID to be in the top 16 bits. - * Lower 16 bits specify the level however 0xFF is a - * special argument the returns the total number of levels - */ - PP_ASSERT_WITH_CODE(smum_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_GetDpmFreqByIndex, (clkID << 16 | 0xFF)) == 0, - "[GetNumberDpmLevel] Failed to get DPM levels from SMU for CLKID!", - return -EINVAL); - - result = vega12_read_arg_from_smc(hwmgr, num_dpm_level); + int ret = 0; - PP_ASSERT_WITH_CODE(*num_dpm_level < MAX_REGULAR_DPM_NUMBER, - "[GetNumberDPMLevel] Number of DPM levels is greater than limit", - return -EINVAL); + ret = smum_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_GetDpmFreqByIndex, + (clk_id << 16 | 0xFF)); + PP_ASSERT_WITH_CODE(!ret, + "[GetNumOfDpmLevel] failed to get dpm levels!", + return ret); - PP_ASSERT_WITH_CODE(*num_dpm_level != 0, - "[GetNumberDPMLevel] Number of CLK Levels is zero!", - return -EINVAL); + vega12_read_arg_from_smc(hwmgr, num_of_levels); + PP_ASSERT_WITH_CODE(*num_of_levels > 0, + "[GetNumOfDpmLevel] number of clk levels is invalid!", + return -EINVAL); - return result; + return ret; } static int vega12_get_dpm_frequency_by_index(struct pp_hwmgr *hwmgr, @@ -509,6 +502,31 @@ static int vega12_get_dpm_frequency_by_index(struct pp_hwmgr *hwmgr, return result; } +static int vega12_setup_single_dpm_table(struct pp_hwmgr *hwmgr, + struct vega12_single_dpm_table *dpm_table, PPCLK_e clk_id) +{ + int ret = 0; + uint32_t i, num_of_levels, clk; + + ret = vega12_get_number_of_dpm_level(hwmgr, clk_id, &num_of_levels); + PP_ASSERT_WITH_CODE(!ret, + "[SetupSingleDpmTable] failed to get clk levels!", + return ret); + + dpm_table->count = num_of_levels; + + for (i = 0; i < num_of_levels; i++) { + ret = vega12_get_dpm_frequency_by_index(hwmgr, clk_id, i, &clk); + PP_ASSERT_WITH_CODE(!ret, + "[SetupSingleDpmTable] failed to get clk of specific level!", + return ret); + dpm_table->dpm_levels[i].value = clk; + dpm_table->dpm_levels[i].enabled = true; + } + + return ret; +} + /* * This function is to initialize all DPM state tables * for SMU based on the dependency table. @@ -519,224 +537,136 @@ static int vega12_get_dpm_frequency_by_index(struct pp_hwmgr *hwmgr, */ static int vega12_setup_default_dpm_tables(struct pp_hwmgr *hwmgr) { - uint32_t num_levels, i, clock; struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend); - struct vega12_single_dpm_table *dpm_table; + int ret = 0; memset(&data->dpm_table, 0, sizeof(data->dpm_table)); - /* Initialize Sclk DPM and SOC DPM table based on allow Sclk values */ + /* socclk */ dpm_table = &(data->dpm_table.soc_table); - - PP_ASSERT_WITH_CODE(vega12_get_number_dpm_level(hwmgr, PPCLK_SOCCLK, - &num_levels) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for SOCCLK!", - return -EINVAL); - - dpm_table->count = num_levels; - - for (i = 0; i < num_levels; i++) { - PP_ASSERT_WITH_CODE(vega12_get_dpm_frequency_by_index(hwmgr, - PPCLK_SOCCLK, i, &clock) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for SOCCLK!", - return -EINVAL); - - dpm_table->dpm_levels[i].value = clock; - dpm_table->dpm_levels[i].enabled = true; + if (data->smu_features[GNLD_DPM_SOCCLK].enabled) { + ret = vega12_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_SOCCLK); + PP_ASSERT_WITH_CODE(!ret, + "[SetupDefaultDpmTable] failed to get socclk dpm levels!", + return ret); + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = data->vbios_boot_state.soc_clock / 100; } - vega12_init_dpm_state(&(dpm_table->dpm_state)); + /* gfxclk */ dpm_table = &(data->dpm_table.gfx_table); - - PP_ASSERT_WITH_CODE(vega12_get_number_dpm_level(hwmgr, PPCLK_GFXCLK, - &num_levels) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for GFXCLK!", - return -EINVAL); - - dpm_table->count = num_levels; - for (i = 0; i < num_levels; i++) { - PP_ASSERT_WITH_CODE(vega12_get_dpm_frequency_by_index(hwmgr, - PPCLK_GFXCLK, i, &clock) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for GFXCLK!", - return -EINVAL); - - dpm_table->dpm_levels[i].value = clock; - dpm_table->dpm_levels[i].enabled = true; + if (data->smu_features[GNLD_DPM_GFXCLK].enabled) { + ret = vega12_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_GFXCLK); + PP_ASSERT_WITH_CODE(!ret, + "[SetupDefaultDpmTable] failed to get gfxclk dpm levels!", + return ret); + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = data->vbios_boot_state.gfx_clock / 100; } - vega12_init_dpm_state(&(dpm_table->dpm_state)); - /* Initialize Mclk DPM table based on allow Mclk values */ - dpm_table = &(data->dpm_table.mem_table); - PP_ASSERT_WITH_CODE(vega12_get_number_dpm_level(hwmgr, PPCLK_UCLK, - &num_levels) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for UCLK!", - return -EINVAL); - - dpm_table->count = num_levels; - - for (i = 0; i < num_levels; i++) { - PP_ASSERT_WITH_CODE(vega12_get_dpm_frequency_by_index(hwmgr, - PPCLK_UCLK, i, &clock) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for UCLK!", - return -EINVAL); - - dpm_table->dpm_levels[i].value = clock; - dpm_table->dpm_levels[i].enabled = true; + /* memclk */ + dpm_table = &(data->dpm_table.mem_table); + if (data->smu_features[GNLD_DPM_UCLK].enabled) { + ret = vega12_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_UCLK); + PP_ASSERT_WITH_CODE(!ret, + "[SetupDefaultDpmTable] failed to get memclk dpm levels!", + return ret); + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = data->vbios_boot_state.mem_clock / 100; } - vega12_init_dpm_state(&(dpm_table->dpm_state)); + /* eclk */ dpm_table = &(data->dpm_table.eclk_table); - - PP_ASSERT_WITH_CODE(vega12_get_number_dpm_level(hwmgr, PPCLK_ECLK, - &num_levels) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for ECLK!", - return -EINVAL); - - dpm_table->count = num_levels; - - for (i = 0; i < num_levels; i++) { - PP_ASSERT_WITH_CODE(vega12_get_dpm_frequency_by_index(hwmgr, - PPCLK_ECLK, i, &clock) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for ECLK!", - return -EINVAL); - - dpm_table->dpm_levels[i].value = clock; - dpm_table->dpm_levels[i].enabled = true; + if (data->smu_features[GNLD_DPM_VCE].enabled) { + ret = vega12_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_ECLK); + PP_ASSERT_WITH_CODE(!ret, + "[SetupDefaultDpmTable] failed to get eclk dpm levels!", + return ret); + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = data->vbios_boot_state.eclock / 100; } - vega12_init_dpm_state(&(dpm_table->dpm_state)); + /* vclk */ dpm_table = &(data->dpm_table.vclk_table); - - PP_ASSERT_WITH_CODE(vega12_get_number_dpm_level(hwmgr, PPCLK_VCLK, - &num_levels) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for VCLK!", - return -EINVAL); - - dpm_table->count = num_levels; - - for (i = 0; i < num_levels; i++) { - PP_ASSERT_WITH_CODE(vega12_get_dpm_frequency_by_index(hwmgr, - PPCLK_VCLK, i, &clock) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for VCLK!", - return -EINVAL); - - dpm_table->dpm_levels[i].value = clock; - dpm_table->dpm_levels[i].enabled = true; + if (data->smu_features[GNLD_DPM_UVD].enabled) { + ret = vega12_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_VCLK); + PP_ASSERT_WITH_CODE(!ret, + "[SetupDefaultDpmTable] failed to get vclk dpm levels!", + return ret); + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = data->vbios_boot_state.vclock / 100; } - vega12_init_dpm_state(&(dpm_table->dpm_state)); + /* dclk */ dpm_table = &(data->dpm_table.dclk_table); - - PP_ASSERT_WITH_CODE(vega12_get_number_dpm_level(hwmgr, PPCLK_DCLK, - &num_levels) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for DCLK!", - return -EINVAL); - - dpm_table->count = num_levels; - - for (i = 0; i < num_levels; i++) { - PP_ASSERT_WITH_CODE(vega12_get_dpm_frequency_by_index(hwmgr, - PPCLK_DCLK, i, &clock) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for DCLK!", - return -EINVAL); - - dpm_table->dpm_levels[i].value = clock; - dpm_table->dpm_levels[i].enabled = true; + if (data->smu_features[GNLD_DPM_UVD].enabled) { + ret = vega12_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_DCLK); + PP_ASSERT_WITH_CODE(!ret, + "[SetupDefaultDpmTable] failed to get dclk dpm levels!", + return ret); + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = data->vbios_boot_state.dclock / 100; } - vega12_init_dpm_state(&(dpm_table->dpm_state)); - /* Assume there is no headless Vega12 for now */ + /* dcefclk */ dpm_table = &(data->dpm_table.dcef_table); - - PP_ASSERT_WITH_CODE(vega12_get_number_dpm_level(hwmgr, - PPCLK_DCEFCLK, &num_levels) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for DCEFCLK!", - return -EINVAL); - - dpm_table->count = num_levels; - - for (i = 0; i < num_levels; i++) { - PP_ASSERT_WITH_CODE(vega12_get_dpm_frequency_by_index(hwmgr, - PPCLK_DCEFCLK, i, &clock) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for DCEFCLK!", - return -EINVAL); - - dpm_table->dpm_levels[i].value = clock; - dpm_table->dpm_levels[i].enabled = true; + if (data->smu_features[GNLD_DPM_DCEFCLK].enabled) { + ret = vega12_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_DCEFCLK); + PP_ASSERT_WITH_CODE(!ret, + "[SetupDefaultDpmTable] failed to get dcefclk dpm levels!", + return ret); + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = data->vbios_boot_state.dcef_clock / 100; } - vega12_init_dpm_state(&(dpm_table->dpm_state)); + /* pixclk */ dpm_table = &(data->dpm_table.pixel_table); - - PP_ASSERT_WITH_CODE(vega12_get_number_dpm_level(hwmgr, - PPCLK_PIXCLK, &num_levels) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for PIXCLK!", - return -EINVAL); - - dpm_table->count = num_levels; - - for (i = 0; i < num_levels; i++) { - PP_ASSERT_WITH_CODE(vega12_get_dpm_frequency_by_index(hwmgr, - PPCLK_PIXCLK, i, &clock) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for PIXCLK!", - return -EINVAL); - - dpm_table->dpm_levels[i].value = clock; - dpm_table->dpm_levels[i].enabled = true; - } - + if (data->smu_features[GNLD_DPM_DCEFCLK].enabled) { + ret = vega12_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_PIXCLK); + PP_ASSERT_WITH_CODE(!ret, + "[SetupDefaultDpmTable] failed to get pixclk dpm levels!", + return ret); + } else + dpm_table->count = 0; vega12_init_dpm_state(&(dpm_table->dpm_state)); + /* dispclk */ dpm_table = &(data->dpm_table.display_table); - - PP_ASSERT_WITH_CODE(vega12_get_number_dpm_level(hwmgr, - PPCLK_DISPCLK, &num_levels) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for DISPCLK!", - return -EINVAL); - - dpm_table->count = num_levels; - - for (i = 0; i < num_levels; i++) { - PP_ASSERT_WITH_CODE(vega12_get_dpm_frequency_by_index(hwmgr, - PPCLK_DISPCLK, i, &clock) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for DISPCLK!", - return -EINVAL); - - dpm_table->dpm_levels[i].value = clock; - dpm_table->dpm_levels[i].enabled = true; - } - + if (data->smu_features[GNLD_DPM_DCEFCLK].enabled) { + ret = vega12_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_DISPCLK); + PP_ASSERT_WITH_CODE(!ret, + "[SetupDefaultDpmTable] failed to get dispclk dpm levels!", + return ret); + } else + dpm_table->count = 0; vega12_init_dpm_state(&(dpm_table->dpm_state)); + /* phyclk */ dpm_table = &(data->dpm_table.phy_table); - - PP_ASSERT_WITH_CODE(vega12_get_number_dpm_level(hwmgr, - PPCLK_PHYCLK, &num_levels) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for PHYCLK!", - return -EINVAL); - - dpm_table->count = num_levels; - - for (i = 0; i < num_levels; i++) { - PP_ASSERT_WITH_CODE(vega12_get_dpm_frequency_by_index(hwmgr, - PPCLK_PHYCLK, i, &clock) == 0, - "[SetupDefaultDPMTables] Failed to get DPM levels from SMU for PHYCLK!", - return -EINVAL); - - dpm_table->dpm_levels[i].value = clock; - dpm_table->dpm_levels[i].enabled = true; - } - + if (data->smu_features[GNLD_DPM_DCEFCLK].enabled) { + ret = vega12_setup_single_dpm_table(hwmgr, dpm_table, PPCLK_PHYCLK); + PP_ASSERT_WITH_CODE(!ret, + "[SetupDefaultDpmTable] failed to get phyclk dpm levels!", + return ret); + } else + dpm_table->count = 0; vega12_init_dpm_state(&(dpm_table->dpm_state)); /* save a copy of the default DPM table */ -- GitLab From 70fef5741c6b82ad293a225f116006565646fb72 Mon Sep 17 00:00:00 2001 From: Evan Quan <evan.quan@amd.com> Date: Mon, 11 Jun 2018 15:41:44 +0800 Subject: [PATCH 0773/1506] drm/amd/powerplay: retrieve all clock ranges on startup So that we do not need to use PPSMC_MSG_GetMin/MaxDpmFreq to get the clock ranges on runtime. Since that causes some problems. Signed-off-by: Evan Quan <evan.quan@amd.com> Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../drm/amd/powerplay/hwmgr/vega12_hwmgr.c | 69 ++++++++++++++----- .../drm/amd/powerplay/hwmgr/vega12_hwmgr.h | 8 +++ 2 files changed, 61 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c index bc976e1d22c50..d3e898306ced3 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c @@ -856,6 +856,48 @@ static int vega12_power_control_set_level(struct pp_hwmgr *hwmgr) return result; } +static int vega12_get_all_clock_ranges_helper(struct pp_hwmgr *hwmgr, + PPCLK_e clkid, struct vega12_clock_range *clock) +{ + /* AC Max */ + PP_ASSERT_WITH_CODE( + smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_GetMaxDpmFreq, (clkid << 16)) == 0, + "[GetClockRanges] Failed to get max ac clock from SMC!", + return -EINVAL); + vega12_read_arg_from_smc(hwmgr, &(clock->ACMax)); + + /* AC Min */ + PP_ASSERT_WITH_CODE( + smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_GetMinDpmFreq, (clkid << 16)) == 0, + "[GetClockRanges] Failed to get min ac clock from SMC!", + return -EINVAL); + vega12_read_arg_from_smc(hwmgr, &(clock->ACMin)); + + /* DC Max */ + PP_ASSERT_WITH_CODE( + smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_GetDcModeMaxDpmFreq, (clkid << 16)) == 0, + "[GetClockRanges] Failed to get max dc clock from SMC!", + return -EINVAL); + vega12_read_arg_from_smc(hwmgr, &(clock->DCMax)); + + return 0; +} + +static int vega12_get_all_clock_ranges(struct pp_hwmgr *hwmgr) +{ + struct vega12_hwmgr *data = + (struct vega12_hwmgr *)(hwmgr->backend); + uint32_t i; + + for (i = 0; i < PPCLK_COUNT; i++) + PP_ASSERT_WITH_CODE(!vega12_get_all_clock_ranges_helper(hwmgr, + i, &(data->clk_range[i])), + "Failed to get clk range from SMC!", + return -EINVAL); + + return 0; +} + static int vega12_enable_dpm_tasks(struct pp_hwmgr *hwmgr) { int tmp_result, result = 0; @@ -883,6 +925,11 @@ static int vega12_enable_dpm_tasks(struct pp_hwmgr *hwmgr) "Failed to power control set level!", result = tmp_result); + result = vega12_get_all_clock_ranges(hwmgr); + PP_ASSERT_WITH_CODE(!result, + "Failed to get all clock ranges!", + return result); + result = vega12_odn_initialize_default_settings(hwmgr); PP_ASSERT_WITH_CODE(!result, "Failed to power control set level!", @@ -1472,24 +1519,14 @@ static int vega12_get_clock_ranges(struct pp_hwmgr *hwmgr, PPCLK_e clock_select, bool max) { - int result; - *clock = 0; + struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend); - if (max) { - PP_ASSERT_WITH_CODE( - smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_GetMaxDpmFreq, (clock_select << 16)) == 0, - "[GetClockRanges] Failed to get max clock from SMC!", - return -1); - result = vega12_read_arg_from_smc(hwmgr, clock); - } else { - PP_ASSERT_WITH_CODE( - smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_GetMinDpmFreq, (clock_select << 16)) == 0, - "[GetClockRanges] Failed to get min clock from SMC!", - return -1); - result = vega12_read_arg_from_smc(hwmgr, clock); - } + if (max) + *clock = data->clk_range[clock_select].ACMax; + else + *clock = data->clk_range[clock_select].ACMin; - return result; + return 0; } static int vega12_get_sclks(struct pp_hwmgr *hwmgr, diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.h b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.h index 49b38df8c7f27..e18c083086028 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.h @@ -304,6 +304,12 @@ struct vega12_odn_fan_table { bool force_fan_pwm; }; +struct vega12_clock_range { + uint32_t ACMax; + uint32_t ACMin; + uint32_t DCMax; +}; + struct vega12_hwmgr { struct vega12_dpm_table dpm_table; struct vega12_dpm_table golden_dpm_table; @@ -385,6 +391,8 @@ struct vega12_hwmgr { uint32_t smu_version; struct smu_features smu_features[GNLD_FEATURES_MAX]; struct vega12_smc_state_table smc_state_table; + + struct vega12_clock_range clk_range[PPCLK_COUNT]; }; #define VEGA12_DPM2_NEAR_TDP_DEC 10 -- GitLab From 8fd26361701187e6fbb56c7c8bf22b4ab763b082 Mon Sep 17 00:00:00 2001 From: Evan Quan <evan.quan@amd.com> Date: Mon, 11 Jun 2018 16:04:17 +0800 Subject: [PATCH 0774/1506] drm/amd/powerplay: revise clock level setup Make sure the clock level set only on dpm enabled. Also uvd/vce/soc clock also changed correspondingly. Signed-off-by: Evan Quan <evan.quan@amd.com> Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../drm/amd/powerplay/hwmgr/vega12_hwmgr.c | 318 ++++++++++++------ 1 file changed, 211 insertions(+), 107 deletions(-) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c index d3e898306ced3..45c8f2ddaa955 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c @@ -958,76 +958,172 @@ static uint32_t vega12_find_lowest_dpm_level( break; } + if (i >= table->count) { + i = 0; + table->dpm_levels[i].enabled = true; + } + return i; } static uint32_t vega12_find_highest_dpm_level( struct vega12_single_dpm_table *table) { - uint32_t i = 0; + int32_t i = 0; + PP_ASSERT_WITH_CODE(table->count <= MAX_REGULAR_DPM_NUMBER, + "[FindHighestDPMLevel] DPM Table has too many entries!", + return MAX_REGULAR_DPM_NUMBER - 1); - if (table->count <= MAX_REGULAR_DPM_NUMBER) { - for (i = table->count; i > 0; i--) { - if (table->dpm_levels[i - 1].enabled) - return i - 1; - } - } else { - pr_info("DPM Table Has Too Many Entries!"); - return MAX_REGULAR_DPM_NUMBER - 1; + for (i = table->count - 1; i >= 0; i--) { + if (table->dpm_levels[i].enabled) + break; } - return i; + if (i < 0) { + i = 0; + table->dpm_levels[i].enabled = true; + } + + return (uint32_t)i; } static int vega12_upload_dpm_min_level(struct pp_hwmgr *hwmgr) { struct vega12_hwmgr *data = hwmgr->backend; - if (data->smc_state_table.gfx_boot_level != - data->dpm_table.gfx_table.dpm_state.soft_min_level) { - smum_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_SetSoftMinByFreq, - PPCLK_GFXCLK<<16 | data->dpm_table.gfx_table.dpm_levels[data->smc_state_table.gfx_boot_level].value); - data->dpm_table.gfx_table.dpm_state.soft_min_level = - data->smc_state_table.gfx_boot_level; + uint32_t min_freq; + int ret = 0; + + if (data->smu_features[GNLD_DPM_GFXCLK].enabled) { + min_freq = data->dpm_table.gfx_table.dpm_state.soft_min_level; + PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter( + hwmgr, PPSMC_MSG_SetSoftMinByFreq, + (PPCLK_GFXCLK << 16) | (min_freq & 0xffff))), + "Failed to set soft min gfxclk !", + return ret); } - if (data->smc_state_table.mem_boot_level != - data->dpm_table.mem_table.dpm_state.soft_min_level) { - smum_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_SetSoftMinByFreq, - PPCLK_UCLK<<16 | data->dpm_table.mem_table.dpm_levels[data->smc_state_table.mem_boot_level].value); - data->dpm_table.mem_table.dpm_state.soft_min_level = - data->smc_state_table.mem_boot_level; + if (data->smu_features[GNLD_DPM_UCLK].enabled) { + min_freq = data->dpm_table.mem_table.dpm_state.soft_min_level; + PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter( + hwmgr, PPSMC_MSG_SetSoftMinByFreq, + (PPCLK_UCLK << 16) | (min_freq & 0xffff))), + "Failed to set soft min memclk !", + return ret); + + min_freq = data->dpm_table.mem_table.dpm_state.hard_min_level; + PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter( + hwmgr, PPSMC_MSG_SetHardMinByFreq, + (PPCLK_UCLK << 16) | (min_freq & 0xffff))), + "Failed to set hard min memclk !", + return ret); } - return 0; + if (data->smu_features[GNLD_DPM_UVD].enabled) { + min_freq = data->dpm_table.vclk_table.dpm_state.soft_min_level; + + PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter( + hwmgr, PPSMC_MSG_SetSoftMinByFreq, + (PPCLK_VCLK << 16) | (min_freq & 0xffff))), + "Failed to set soft min vclk!", + return ret); + + min_freq = data->dpm_table.dclk_table.dpm_state.soft_min_level; + + PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter( + hwmgr, PPSMC_MSG_SetSoftMinByFreq, + (PPCLK_DCLK << 16) | (min_freq & 0xffff))), + "Failed to set soft min dclk!", + return ret); + } + + if (data->smu_features[GNLD_DPM_VCE].enabled) { + min_freq = data->dpm_table.eclk_table.dpm_state.soft_min_level; + + PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter( + hwmgr, PPSMC_MSG_SetSoftMinByFreq, + (PPCLK_ECLK << 16) | (min_freq & 0xffff))), + "Failed to set soft min eclk!", + return ret); + } + + if (data->smu_features[GNLD_DPM_SOCCLK].enabled) { + min_freq = data->dpm_table.soc_table.dpm_state.soft_min_level; + + PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter( + hwmgr, PPSMC_MSG_SetSoftMinByFreq, + (PPCLK_SOCCLK << 16) | (min_freq & 0xffff))), + "Failed to set soft min socclk!", + return ret); + } + + return ret; } static int vega12_upload_dpm_max_level(struct pp_hwmgr *hwmgr) { struct vega12_hwmgr *data = hwmgr->backend; - if (data->smc_state_table.gfx_max_level != - data->dpm_table.gfx_table.dpm_state.soft_max_level) { - smum_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_SetSoftMaxByFreq, - /* plus the vale by 1 to align the resolution */ - PPCLK_GFXCLK<<16 | (data->dpm_table.gfx_table.dpm_levels[data->smc_state_table.gfx_max_level].value + 1)); - data->dpm_table.gfx_table.dpm_state.soft_max_level = - data->smc_state_table.gfx_max_level; + uint32_t max_freq; + int ret = 0; + + if (data->smu_features[GNLD_DPM_GFXCLK].enabled) { + max_freq = data->dpm_table.gfx_table.dpm_state.soft_max_level; + + PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter( + hwmgr, PPSMC_MSG_SetSoftMaxByFreq, + (PPCLK_GFXCLK << 16) | (max_freq & 0xffff))), + "Failed to set soft max gfxclk!", + return ret); } - if (data->smc_state_table.mem_max_level != - data->dpm_table.mem_table.dpm_state.soft_max_level) { - smum_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_SetSoftMaxByFreq, - /* plus the vale by 1 to align the resolution */ - PPCLK_UCLK<<16 | (data->dpm_table.mem_table.dpm_levels[data->smc_state_table.mem_max_level].value + 1)); - data->dpm_table.mem_table.dpm_state.soft_max_level = - data->smc_state_table.mem_max_level; + if (data->smu_features[GNLD_DPM_UCLK].enabled) { + max_freq = data->dpm_table.mem_table.dpm_state.soft_max_level; + + PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter( + hwmgr, PPSMC_MSG_SetSoftMaxByFreq, + (PPCLK_UCLK << 16) | (max_freq & 0xffff))), + "Failed to set soft max memclk!", + return ret); } - return 0; + if (data->smu_features[GNLD_DPM_UVD].enabled) { + max_freq = data->dpm_table.vclk_table.dpm_state.soft_max_level; + + PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter( + hwmgr, PPSMC_MSG_SetSoftMaxByFreq, + (PPCLK_VCLK << 16) | (max_freq & 0xffff))), + "Failed to set soft max vclk!", + return ret); + + max_freq = data->dpm_table.dclk_table.dpm_state.soft_max_level; + PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter( + hwmgr, PPSMC_MSG_SetSoftMaxByFreq, + (PPCLK_DCLK << 16) | (max_freq & 0xffff))), + "Failed to set soft max dclk!", + return ret); + } + + if (data->smu_features[GNLD_DPM_VCE].enabled) { + max_freq = data->dpm_table.eclk_table.dpm_state.soft_max_level; + + PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter( + hwmgr, PPSMC_MSG_SetSoftMaxByFreq, + (PPCLK_ECLK << 16) | (max_freq & 0xffff))), + "Failed to set soft max eclk!", + return ret); + } + + if (data->smu_features[GNLD_DPM_SOCCLK].enabled) { + max_freq = data->dpm_table.soc_table.dpm_state.soft_max_level; + + PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter( + hwmgr, PPSMC_MSG_SetSoftMaxByFreq, + (PPCLK_SOCCLK << 16) | (max_freq & 0xffff))), + "Failed to set soft max socclk!", + return ret); + } + + return ret; } int vega12_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable) @@ -1330,12 +1426,19 @@ static int vega12_force_dpm_highest(struct pp_hwmgr *hwmgr) struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend); - data->smc_state_table.gfx_boot_level = - data->smc_state_table.gfx_max_level = - vega12_find_highest_dpm_level(&(data->dpm_table.gfx_table)); - data->smc_state_table.mem_boot_level = - data->smc_state_table.mem_max_level = - vega12_find_highest_dpm_level(&(data->dpm_table.mem_table)); + uint32_t soft_level; + + soft_level = vega12_find_highest_dpm_level(&(data->dpm_table.gfx_table)); + + data->dpm_table.gfx_table.dpm_state.soft_min_level = + data->dpm_table.gfx_table.dpm_state.soft_max_level = + data->dpm_table.gfx_table.dpm_levels[soft_level].value; + + soft_level = vega12_find_highest_dpm_level(&(data->dpm_table.mem_table)); + + data->dpm_table.mem_table.dpm_state.soft_min_level = + data->dpm_table.mem_table.dpm_state.soft_max_level = + data->dpm_table.mem_table.dpm_levels[soft_level].value; PP_ASSERT_WITH_CODE(!vega12_upload_dpm_min_level(hwmgr), "Failed to upload boot level to highest!", @@ -1352,13 +1455,19 @@ static int vega12_force_dpm_lowest(struct pp_hwmgr *hwmgr) { struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend); + uint32_t soft_level; + + soft_level = vega12_find_lowest_dpm_level(&(data->dpm_table.gfx_table)); + + data->dpm_table.gfx_table.dpm_state.soft_min_level = + data->dpm_table.gfx_table.dpm_state.soft_max_level = + data->dpm_table.gfx_table.dpm_levels[soft_level].value; - data->smc_state_table.gfx_boot_level = - data->smc_state_table.gfx_max_level = - vega12_find_lowest_dpm_level(&(data->dpm_table.gfx_table)); - data->smc_state_table.mem_boot_level = - data->smc_state_table.mem_max_level = - vega12_find_lowest_dpm_level(&(data->dpm_table.mem_table)); + soft_level = vega12_find_lowest_dpm_level(&(data->dpm_table.mem_table)); + + data->dpm_table.mem_table.dpm_state.soft_min_level = + data->dpm_table.mem_table.dpm_state.soft_max_level = + data->dpm_table.mem_table.dpm_levels[soft_level].value; PP_ASSERT_WITH_CODE(!vega12_upload_dpm_min_level(hwmgr), "Failed to upload boot level to highest!", @@ -1374,17 +1483,6 @@ static int vega12_force_dpm_lowest(struct pp_hwmgr *hwmgr) static int vega12_unforce_dpm_levels(struct pp_hwmgr *hwmgr) { - struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend); - - data->smc_state_table.gfx_boot_level = - vega12_find_lowest_dpm_level(&(data->dpm_table.gfx_table)); - data->smc_state_table.gfx_max_level = - vega12_find_highest_dpm_level(&(data->dpm_table.gfx_table)); - data->smc_state_table.mem_boot_level = - vega12_find_lowest_dpm_level(&(data->dpm_table.mem_table)); - data->smc_state_table.mem_max_level = - vega12_find_highest_dpm_level(&(data->dpm_table.mem_table)); - PP_ASSERT_WITH_CODE(!vega12_upload_dpm_min_level(hwmgr), "Failed to upload DPM Bootup Levels!", return -1); @@ -1392,22 +1490,28 @@ static int vega12_unforce_dpm_levels(struct pp_hwmgr *hwmgr) PP_ASSERT_WITH_CODE(!vega12_upload_dpm_max_level(hwmgr), "Failed to upload DPM Max Levels!", return -1); + return 0; } -#if 0 static int vega12_get_profiling_clk_mask(struct pp_hwmgr *hwmgr, enum amd_dpm_forced_level level, uint32_t *sclk_mask, uint32_t *mclk_mask, uint32_t *soc_mask) { - struct phm_ppt_v2_information *table_info = - (struct phm_ppt_v2_information *)(hwmgr->pptable); + struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend); + struct vega12_single_dpm_table *gfx_dpm_table = &(data->dpm_table.gfx_table); + struct vega12_single_dpm_table *mem_dpm_table = &(data->dpm_table.mem_table); + struct vega12_single_dpm_table *soc_dpm_table = &(data->dpm_table.soc_table); + + *sclk_mask = 0; + *mclk_mask = 0; + *soc_mask = 0; - if (table_info->vdd_dep_on_sclk->count > VEGA12_UMD_PSTATE_GFXCLK_LEVEL && - table_info->vdd_dep_on_socclk->count > VEGA12_UMD_PSTATE_SOCCLK_LEVEL && - table_info->vdd_dep_on_mclk->count > VEGA12_UMD_PSTATE_MCLK_LEVEL) { + if (gfx_dpm_table->count > VEGA12_UMD_PSTATE_GFXCLK_LEVEL && + mem_dpm_table->count > VEGA12_UMD_PSTATE_MCLK_LEVEL && + soc_dpm_table->count > VEGA12_UMD_PSTATE_SOCCLK_LEVEL) { *sclk_mask = VEGA12_UMD_PSTATE_GFXCLK_LEVEL; - *soc_mask = VEGA12_UMD_PSTATE_SOCCLK_LEVEL; *mclk_mask = VEGA12_UMD_PSTATE_MCLK_LEVEL; + *soc_mask = VEGA12_UMD_PSTATE_SOCCLK_LEVEL; } if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) { @@ -1415,13 +1519,13 @@ static int vega12_get_profiling_clk_mask(struct pp_hwmgr *hwmgr, enum amd_dpm_fo } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) { *mclk_mask = 0; } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { - *sclk_mask = table_info->vdd_dep_on_sclk->count - 1; - *soc_mask = table_info->vdd_dep_on_socclk->count - 1; - *mclk_mask = table_info->vdd_dep_on_mclk->count - 1; + *sclk_mask = gfx_dpm_table->count - 1; + *mclk_mask = mem_dpm_table->count - 1; + *soc_mask = soc_dpm_table->count - 1; } + return 0; } -#endif static void vega12_set_fan_control_mode(struct pp_hwmgr *hwmgr, uint32_t mode) { @@ -1445,11 +1549,9 @@ static int vega12_dpm_force_dpm_level(struct pp_hwmgr *hwmgr, enum amd_dpm_forced_level level) { int ret = 0; -#if 0 uint32_t sclk_mask = 0; uint32_t mclk_mask = 0; uint32_t soc_mask = 0; -#endif switch (level) { case AMD_DPM_FORCED_LEVEL_HIGH: @@ -1465,27 +1567,18 @@ static int vega12_dpm_force_dpm_level(struct pp_hwmgr *hwmgr, case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK: case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK: case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK: -#if 0 ret = vega12_get_profiling_clk_mask(hwmgr, level, &sclk_mask, &mclk_mask, &soc_mask); if (ret) return ret; - vega12_force_clock_level(hwmgr, PP_SCLK, 1<<sclk_mask); - vega12_force_clock_level(hwmgr, PP_MCLK, 1<<mclk_mask); -#endif + vega12_force_clock_level(hwmgr, PP_SCLK, 1 << sclk_mask); + vega12_force_clock_level(hwmgr, PP_MCLK, 1 << mclk_mask); break; case AMD_DPM_FORCED_LEVEL_MANUAL: case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT: default: break; } -#if 0 - if (!ret) { - if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK && hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) - vega12_set_fan_control_mode(hwmgr, AMD_FAN_CTRL_NONE); - else if (level != AMD_DPM_FORCED_LEVEL_PROFILE_PEAK && hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) - vega12_set_fan_control_mode(hwmgr, AMD_FAN_CTRL_AUTO); - } -#endif + return ret; } @@ -1745,37 +1838,48 @@ static int vega12_force_clock_level(struct pp_hwmgr *hwmgr, enum pp_clock_type type, uint32_t mask) { struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend); - - if (hwmgr->request_dpm_level & (AMD_DPM_FORCED_LEVEL_AUTO | - AMD_DPM_FORCED_LEVEL_LOW | - AMD_DPM_FORCED_LEVEL_HIGH)) - return -EINVAL; + uint32_t soft_min_level, soft_max_level; + int ret = 0; switch (type) { case PP_SCLK: - data->smc_state_table.gfx_boot_level = mask ? (ffs(mask) - 1) : 0; - data->smc_state_table.gfx_max_level = mask ? (fls(mask) - 1) : 0; + soft_min_level = mask ? (ffs(mask) - 1) : 0; + soft_max_level = mask ? (fls(mask) - 1) : 0; + + data->dpm_table.gfx_table.dpm_state.soft_min_level = + data->dpm_table.gfx_table.dpm_levels[soft_min_level].value; + data->dpm_table.gfx_table.dpm_state.soft_max_level = + data->dpm_table.gfx_table.dpm_levels[soft_max_level].value; - PP_ASSERT_WITH_CODE(!vega12_upload_dpm_min_level(hwmgr), + ret = vega12_upload_dpm_min_level(hwmgr); + PP_ASSERT_WITH_CODE(!ret, "Failed to upload boot level to lowest!", - return -EINVAL); + return ret); - PP_ASSERT_WITH_CODE(!vega12_upload_dpm_max_level(hwmgr), + ret = vega12_upload_dpm_max_level(hwmgr); + PP_ASSERT_WITH_CODE(!ret, "Failed to upload dpm max level to highest!", - return -EINVAL); + return ret); break; case PP_MCLK: - data->smc_state_table.mem_boot_level = mask ? (ffs(mask) - 1) : 0; - data->smc_state_table.mem_max_level = mask ? (fls(mask) - 1) : 0; + soft_min_level = mask ? (ffs(mask) - 1) : 0; + soft_max_level = mask ? (fls(mask) - 1) : 0; + + data->dpm_table.mem_table.dpm_state.soft_min_level = + data->dpm_table.mem_table.dpm_levels[soft_min_level].value; + data->dpm_table.mem_table.dpm_state.soft_max_level = + data->dpm_table.mem_table.dpm_levels[soft_max_level].value; - PP_ASSERT_WITH_CODE(!vega12_upload_dpm_min_level(hwmgr), + ret = vega12_upload_dpm_min_level(hwmgr); + PP_ASSERT_WITH_CODE(!ret, "Failed to upload boot level to lowest!", - return -EINVAL); + return ret); - PP_ASSERT_WITH_CODE(!vega12_upload_dpm_max_level(hwmgr), + ret = vega12_upload_dpm_max_level(hwmgr); + PP_ASSERT_WITH_CODE(!ret, "Failed to upload dpm max level to highest!", - return -EINVAL); + return ret); break; -- GitLab From f74aa69d0aed89b5ea283f4a6f86f0505407021e Mon Sep 17 00:00:00 2001 From: Evan Quan <evan.quan@amd.com> Date: Mon, 11 Jun 2018 16:25:14 +0800 Subject: [PATCH 0775/1506] drm/amd/powerplay: initialize uvd/vce powergate status v4 On UVD/VCE dpm enabled/disabled, the powergate status will be set as false/true. So that we will not try to ungate/gate them( enable/disable their dpm) again. v2: added check for uvd/vce powergate status before gating v3: fix typo in description v4: warning fix (Alex) Signed-off-by: Evan Quan <evan.quan@amd.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../drm/amd/powerplay/hwmgr/vega12_hwmgr.c | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c index 45c8f2ddaa955..8176b231c38b1 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c @@ -777,6 +777,21 @@ static int vega12_set_allowed_featuresmask(struct pp_hwmgr *hwmgr) return 0; } +static void vega12_init_powergate_state(struct pp_hwmgr *hwmgr) +{ + struct vega12_hwmgr *data = + (struct vega12_hwmgr *)(hwmgr->backend); + + data->uvd_power_gated = true; + data->vce_power_gated = true; + + if (data->smu_features[GNLD_DPM_UVD].enabled) + data->uvd_power_gated = false; + + if (data->smu_features[GNLD_DPM_VCE].enabled) + data->vce_power_gated = false; +} + static int vega12_enable_all_smu_features(struct pp_hwmgr *hwmgr) { struct vega12_hwmgr *data = @@ -801,6 +816,8 @@ static int vega12_enable_all_smu_features(struct pp_hwmgr *hwmgr) } } + vega12_init_powergate_state(hwmgr); + return 0; } @@ -1985,6 +2002,9 @@ static void vega12_power_gate_vce(struct pp_hwmgr *hwmgr, bool bgate) { struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend); + if (data->vce_power_gated == bgate) + return; + data->vce_power_gated = bgate; vega12_enable_disable_vce_dpm(hwmgr, !bgate); } @@ -1993,6 +2013,9 @@ static void vega12_power_gate_uvd(struct pp_hwmgr *hwmgr, bool bgate) { struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend); + if (data->uvd_power_gated == bgate) + return; + data->uvd_power_gated = bgate; vega12_enable_disable_uvd_dpm(hwmgr, !bgate); } -- GitLab From ac32b06acee88ab4c9f3336be5aea4a050b0d4e5 Mon Sep 17 00:00:00 2001 From: Evan Quan <evan.quan@amd.com> Date: Wed, 20 Jun 2018 12:24:29 +0800 Subject: [PATCH 0776/1506] drm/amd/powerplay: correct smc display config for multi monitor Need to take into account multi-head with synced displays. Signed-off-by: Evan Quan <evan.quan@amd.com> Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c index 8176b231c38b1..824d9e15d7127 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c @@ -1401,7 +1401,8 @@ static int vega12_notify_smc_display_config_after_ps_adjustment( struct pp_display_clock_request clock_req; uint32_t clk_request; - if (hwmgr->display_config->num_display > 1) + if ((hwmgr->display_config->num_display > 1) && + !hwmgr->display_config->multi_monitor_in_sync) vega12_notify_smc_display_change(hwmgr, false); else vega12_notify_smc_display_change(hwmgr, true); -- GitLab From 30222561808f8fdf6d56c22ccfe3d9140fd0a169 Mon Sep 17 00:00:00 2001 From: Evan Quan <evan.quan@amd.com> Date: Wed, 20 Jun 2018 12:28:10 +0800 Subject: [PATCH 0777/1506] drm/amd/powerplay: drop unnecessary uclk hard min setting We don't need to set uclk hard min here because this will be set with other clocks on power state change. Signed-off-by: Evan Quan <evan.quan@amd.com> Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c index 824d9e15d7127..8222383009da1 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c @@ -1399,7 +1399,6 @@ static int vega12_notify_smc_display_config_after_ps_adjustment( (struct vega12_hwmgr *)(hwmgr->backend); struct PP_Clocks min_clocks = {0}; struct pp_display_clock_request clock_req; - uint32_t clk_request; if ((hwmgr->display_config->num_display > 1) && !hwmgr->display_config->multi_monitor_in_sync) @@ -1427,15 +1426,6 @@ static int vega12_notify_smc_display_config_after_ps_adjustment( } } - if (data->smu_features[GNLD_DPM_UCLK].enabled) { - clk_request = (PPCLK_UCLK << 16) | (min_clocks.memoryClock) / 100; - PP_ASSERT_WITH_CODE( - smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetHardMinByFreq, clk_request) == 0, - "[PhwVega12_NotifySMCDisplayConfigAfterPowerStateAdjustment] Attempt to set UCLK HardMin Failed!", - return -1); - data->dpm_table.mem_table.dpm_state.hard_min_level = min_clocks.memoryClock; - } - return 0; } -- GitLab From a0a59c8fc7af37287228a0c89b0a71a1ffadc29b Mon Sep 17 00:00:00 2001 From: Evan Quan <evan.quan@amd.com> Date: Mon, 11 Jun 2018 16:33:40 +0800 Subject: [PATCH 0778/1506] drm/amd/powerplay: correct vega12 max num of dpm level Use MAX_NUM_CLOCKS instead of VG12_PSUEDO* macros for the max number of dpm levels. Signed-off-by: Evan Quan <evan.quan@amd.com> Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c index 8222383009da1..d1bab9845b086 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c @@ -1642,8 +1642,8 @@ static int vega12_get_sclks(struct pp_hwmgr *hwmgr, return -1; dpm_table = &(data->dpm_table.gfx_table); - ucount = (dpm_table->count > VG12_PSUEDO_NUM_GFXCLK_DPM_LEVELS) ? - VG12_PSUEDO_NUM_GFXCLK_DPM_LEVELS : dpm_table->count; + ucount = (dpm_table->count > MAX_NUM_CLOCKS) ? + MAX_NUM_CLOCKS : dpm_table->count; for (i = 0; i < ucount; i++) { clocks->data[i].clocks_in_khz = @@ -1674,11 +1674,12 @@ static int vega12_get_memclocks(struct pp_hwmgr *hwmgr, return -1; dpm_table = &(data->dpm_table.mem_table); - ucount = (dpm_table->count > VG12_PSUEDO_NUM_UCLK_DPM_LEVELS) ? - VG12_PSUEDO_NUM_UCLK_DPM_LEVELS : dpm_table->count; + ucount = (dpm_table->count > MAX_NUM_CLOCKS) ? + MAX_NUM_CLOCKS : dpm_table->count; for (i = 0; i < ucount; i++) { clocks->data[i].clocks_in_khz = + data->mclk_latency_table.entries[i].frequency = dpm_table->dpm_levels[i].value * 100; clocks->data[i].latency_in_us = @@ -1704,8 +1705,8 @@ static int vega12_get_dcefclocks(struct pp_hwmgr *hwmgr, dpm_table = &(data->dpm_table.dcef_table); - ucount = (dpm_table->count > VG12_PSUEDO_NUM_DCEFCLK_DPM_LEVELS) ? - VG12_PSUEDO_NUM_DCEFCLK_DPM_LEVELS : dpm_table->count; + ucount = (dpm_table->count > MAX_NUM_CLOCKS) ? + MAX_NUM_CLOCKS : dpm_table->count; for (i = 0; i < ucount; i++) { clocks->data[i].clocks_in_khz = @@ -1732,8 +1733,8 @@ static int vega12_get_socclocks(struct pp_hwmgr *hwmgr, dpm_table = &(data->dpm_table.soc_table); - ucount = (dpm_table->count > VG12_PSUEDO_NUM_SOCCLK_DPM_LEVELS) ? - VG12_PSUEDO_NUM_SOCCLK_DPM_LEVELS : dpm_table->count; + ucount = (dpm_table->count > MAX_NUM_CLOCKS) ? + MAX_NUM_CLOCKS : dpm_table->count; for (i = 0; i < ucount; i++) { clocks->data[i].clocks_in_khz = -- GitLab From e17c7f92b2b7c2f14934c305a8d72bbb0bf6f362 Mon Sep 17 00:00:00 2001 From: Evan Quan <evan.quan@amd.com> Date: Mon, 11 Jun 2018 16:40:57 +0800 Subject: [PATCH 0779/1506] drm/amd/powerplay: apply clocks adjust rules on power state change This add the apply_clocks_adjust_rules callback which is used to validate the clock settings on a power state change. Signed-off-by: Evan Quan <evan.quan@amd.com> Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../drm/amd/powerplay/hwmgr/vega12_hwmgr.c | 162 ++++++++++++++++++ .../drm/amd/powerplay/hwmgr/vega12_hwmgr.h | 2 + 2 files changed, 164 insertions(+) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c index d1bab9845b086..d28227efe9063 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c @@ -1950,6 +1950,166 @@ static int vega12_print_clock_levels(struct pp_hwmgr *hwmgr, return size; } +static int vega12_apply_clocks_adjust_rules(struct pp_hwmgr *hwmgr) +{ + struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend); + struct vega12_single_dpm_table *dpm_table; + bool vblank_too_short = false; + bool disable_mclk_switching; + uint32_t i, latency; + + disable_mclk_switching = ((1 < hwmgr->display_config->num_display) && + !hwmgr->display_config->multi_monitor_in_sync) || + vblank_too_short; + latency = hwmgr->display_config->dce_tolerable_mclk_in_active_latency; + + /* gfxclk */ + dpm_table = &(data->dpm_table.gfx_table); + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value; + dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + + if (PP_CAP(PHM_PlatformCaps_UMDPState)) { + if (VEGA12_UMD_PSTATE_GFXCLK_LEVEL < dpm_table->count) { + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA12_UMD_PSTATE_GFXCLK_LEVEL].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA12_UMD_PSTATE_GFXCLK_LEVEL].value; + } + + if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) { + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[0].value; + } + + if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + } + } + + /* memclk */ + dpm_table = &(data->dpm_table.mem_table); + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value; + dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + + if (PP_CAP(PHM_PlatformCaps_UMDPState)) { + if (VEGA12_UMD_PSTATE_MCLK_LEVEL < dpm_table->count) { + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA12_UMD_PSTATE_MCLK_LEVEL].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA12_UMD_PSTATE_MCLK_LEVEL].value; + } + + if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) { + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[0].value; + } + + if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + } + } + + /* honour DAL's UCLK Hardmin */ + if (dpm_table->dpm_state.hard_min_level < (hwmgr->display_config->min_mem_set_clock / 100)) + dpm_table->dpm_state.hard_min_level = hwmgr->display_config->min_mem_set_clock / 100; + + /* Hardmin is dependent on displayconfig */ + if (disable_mclk_switching) { + dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + for (i = 0; i < data->mclk_latency_table.count - 1; i++) { + if (data->mclk_latency_table.entries[i].latency <= latency) { + if (dpm_table->dpm_levels[i].value >= (hwmgr->display_config->min_mem_set_clock / 100)) { + dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[i].value; + break; + } + } + } + } + + if (hwmgr->display_config->nb_pstate_switch_disable) + dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + + /* vclk */ + dpm_table = &(data->dpm_table.vclk_table); + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value; + dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + + if (PP_CAP(PHM_PlatformCaps_UMDPState)) { + if (VEGA12_UMD_PSTATE_UVDCLK_LEVEL < dpm_table->count) { + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA12_UMD_PSTATE_UVDCLK_LEVEL].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA12_UMD_PSTATE_UVDCLK_LEVEL].value; + } + + if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + } + } + + /* dclk */ + dpm_table = &(data->dpm_table.dclk_table); + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value; + dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + + if (PP_CAP(PHM_PlatformCaps_UMDPState)) { + if (VEGA12_UMD_PSTATE_UVDCLK_LEVEL < dpm_table->count) { + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA12_UMD_PSTATE_UVDCLK_LEVEL].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA12_UMD_PSTATE_UVDCLK_LEVEL].value; + } + + if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + } + } + + /* socclk */ + dpm_table = &(data->dpm_table.soc_table); + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value; + dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + + if (PP_CAP(PHM_PlatformCaps_UMDPState)) { + if (VEGA12_UMD_PSTATE_SOCCLK_LEVEL < dpm_table->count) { + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA12_UMD_PSTATE_SOCCLK_LEVEL].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA12_UMD_PSTATE_SOCCLK_LEVEL].value; + } + + if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + } + } + + /* eclk */ + dpm_table = &(data->dpm_table.eclk_table); + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value; + dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + + if (PP_CAP(PHM_PlatformCaps_UMDPState)) { + if (VEGA12_UMD_PSTATE_VCEMCLK_LEVEL < dpm_table->count) { + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA12_UMD_PSTATE_VCEMCLK_LEVEL].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA12_UMD_PSTATE_VCEMCLK_LEVEL].value; + } + + if (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { + dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + } + } + + return 0; +} + static int vega12_display_configuration_changed_task(struct pp_hwmgr *hwmgr) { struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend); @@ -2202,6 +2362,8 @@ static const struct pp_hwmgr_func vega12_hwmgr_funcs = { .display_clock_voltage_request = vega12_display_clock_voltage_request, .force_clock_level = vega12_force_clock_level, .print_clock_levels = vega12_print_clock_levels, + .apply_clocks_adjust_rules = + vega12_apply_clocks_adjust_rules, .display_config_changed = vega12_display_configuration_changed_task, .powergate_uvd = vega12_power_gate_uvd, .powergate_vce = vega12_power_gate_vce, diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.h b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.h index e18c083086028..e17237c90eeaa 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.h @@ -443,6 +443,8 @@ struct vega12_hwmgr { #define VEGA12_UMD_PSTATE_GFXCLK_LEVEL 0x3 #define VEGA12_UMD_PSTATE_SOCCLK_LEVEL 0x3 #define VEGA12_UMD_PSTATE_MCLK_LEVEL 0x2 +#define VEGA12_UMD_PSTATE_UVDCLK_LEVEL 0x3 +#define VEGA12_UMD_PSTATE_VCEMCLK_LEVEL 0x3 int vega12_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable); -- GitLab From 28a7b4f4498546c0d4d41c084abd0496f9922bf3 Mon Sep 17 00:00:00 2001 From: Evan Quan <evan.quan@amd.com> Date: Mon, 11 Jun 2018 17:22:33 +0800 Subject: [PATCH 0780/1506] drm/amd/powerplay: set vega12 pre display configurations Set num_displays to 0 and force uclk high as part of the mode set sequence. Signed-off-by: Evan Quan <evan.quan@amd.com> Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../drm/amd/powerplay/hwmgr/vega12_hwmgr.c | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c index d28227efe9063..e899a0cdbb0db 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c @@ -2110,6 +2110,45 @@ static int vega12_apply_clocks_adjust_rules(struct pp_hwmgr *hwmgr) return 0; } +static int vega12_set_uclk_to_highest_dpm_level(struct pp_hwmgr *hwmgr, + struct vega12_single_dpm_table *dpm_table) +{ + struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend); + int ret = 0; + + if (data->smu_features[GNLD_DPM_UCLK].enabled) { + PP_ASSERT_WITH_CODE(dpm_table->count > 0, + "[SetUclkToHightestDpmLevel] Dpm table has no entry!", + return -EINVAL); + PP_ASSERT_WITH_CODE(dpm_table->count <= NUM_UCLK_DPM_LEVELS, + "[SetUclkToHightestDpmLevel] Dpm table has too many entries!", + return -EINVAL); + + dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value; + PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_SetHardMinByFreq, + (PPCLK_UCLK << 16 ) | dpm_table->dpm_state.hard_min_level)), + "[SetUclkToHightestDpmLevel] Set hard min uclk failed!", + return ret); + } + + return ret; +} + +static int vega12_pre_display_configuration_changed_task(struct pp_hwmgr *hwmgr) +{ + struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend); + int ret = 0; + + smum_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_NumOfDisplays, 0); + + ret = vega12_set_uclk_to_highest_dpm_level(hwmgr, + &data->dpm_table.mem_table); + + return ret; +} + static int vega12_display_configuration_changed_task(struct pp_hwmgr *hwmgr) { struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend); @@ -2364,6 +2403,8 @@ static const struct pp_hwmgr_func vega12_hwmgr_funcs = { .print_clock_levels = vega12_print_clock_levels, .apply_clocks_adjust_rules = vega12_apply_clocks_adjust_rules, + .pre_display_config_changed = + vega12_pre_display_configuration_changed_task, .display_config_changed = vega12_display_configuration_changed_task, .powergate_uvd = vega12_power_gate_uvd, .powergate_vce = vega12_power_gate_vce, -- GitLab From 6ad87101f3a34ea2b955a09dde085e4e9901bab9 Mon Sep 17 00:00:00 2001 From: Evan Quan <evan.quan@amd.com> Date: Mon, 11 Jun 2018 16:46:40 +0800 Subject: [PATCH 0781/1506] drm/amd/powerplay: correct vega12 thermal support as true Thermal support is enabled on vega12. Signed-off-by: Evan Quan <evan.quan@amd.com> Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c index e899a0cdbb0db..6bc5f253ce8d4 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c @@ -81,6 +81,7 @@ static void vega12_set_default_registry_data(struct pp_hwmgr *hwmgr) data->registry_data.disallowed_features = 0x0; data->registry_data.od_state_in_dc_support = 0; + data->registry_data.thermal_support = 1; data->registry_data.skip_baco_hardware = 0; data->registry_data.log_avfs_param = 0; -- GitLab From 0c3d01744511f053c5f67737cb7a6a99c0216a84 Mon Sep 17 00:00:00 2001 From: Evan Quan <evan.quan@amd.com> Date: Mon, 11 Jun 2018 16:48:43 +0800 Subject: [PATCH 0782/1506] drm/amd/powerplay: cosmetic fix Fix coding style and drop unused variable. Signed-off-by: Evan Quan <evan.quan@amd.com> Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c | 10 +++------- .../amd/powerplay/inc/vega12/smu9_driver_if.h | 18 +++++++++--------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c index 6bc5f253ce8d4..a86777954ea76 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c @@ -811,9 +811,6 @@ static int vega12_enable_all_smu_features(struct pp_hwmgr *hwmgr) enabled = (features_enabled & data->smu_features[i].smu_feature_bitmap) ? true : false; data->smu_features[i].enabled = enabled; data->smu_features[i].supported = enabled; - PP_ASSERT( - !data->smu_features[i].allowed || enabled, - "[EnableAllSMUFeatures] Enabled feature is different from allowed, expected disabled!"); } } @@ -1230,8 +1227,8 @@ static int vega12_get_current_gfx_clk_freq(struct pp_hwmgr *hwmgr, uint32_t *gfx *gfx_freq = 0; - PP_ASSERT_WITH_CODE( - smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_GetDpmClockFreq, (PPCLK_GFXCLK << 16)) == 0, + PP_ASSERT_WITH_CODE(smum_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_GetDpmClockFreq, (PPCLK_GFXCLK << 16)) == 0, "[GetCurrentGfxClkFreq] Attempt to get Current GFXCLK Frequency Failed!", return -1); PP_ASSERT_WITH_CODE( @@ -1790,7 +1787,6 @@ static int vega12_set_watermarks_for_clocks_ranges(struct pp_hwmgr *hwmgr, { struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend); Watermarks_t *table = &(data->smc_state_table.water_marks_table); - int result = 0; uint32_t i; if (!data->registry_data.disable_water_mark && @@ -1841,7 +1837,7 @@ static int vega12_set_watermarks_for_clocks_ranges(struct pp_hwmgr *hwmgr, data->water_marks_bitmap &= ~WaterMarksLoaded; } - return result; + return 0; } static int vega12_force_clock_level(struct pp_hwmgr *hwmgr, diff --git a/drivers/gpu/drm/amd/powerplay/inc/vega12/smu9_driver_if.h b/drivers/gpu/drm/amd/powerplay/inc/vega12/smu9_driver_if.h index b08526fd16190..b6ffd08784e7f 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/vega12/smu9_driver_if.h +++ b/drivers/gpu/drm/amd/powerplay/inc/vega12/smu9_driver_if.h @@ -412,10 +412,10 @@ typedef struct { QuadraticInt_t ReservedEquation2; QuadraticInt_t ReservedEquation3; - uint16_t MinVoltageUlvGfx; - uint16_t MinVoltageUlvSoc; + uint16_t MinVoltageUlvGfx; + uint16_t MinVoltageUlvSoc; - uint32_t Reserved[14]; + uint32_t Reserved[14]; @@ -483,9 +483,9 @@ typedef struct { uint8_t padding8_4; - uint8_t PllGfxclkSpreadEnabled; - uint8_t PllGfxclkSpreadPercent; - uint16_t PllGfxclkSpreadFreq; + uint8_t PllGfxclkSpreadEnabled; + uint8_t PllGfxclkSpreadPercent; + uint16_t PllGfxclkSpreadFreq; uint8_t UclkSpreadEnabled; uint8_t UclkSpreadPercent; @@ -495,9 +495,9 @@ typedef struct { uint8_t SocclkSpreadPercent; uint16_t SocclkSpreadFreq; - uint8_t AcgGfxclkSpreadEnabled; - uint8_t AcgGfxclkSpreadPercent; - uint16_t AcgGfxclkSpreadFreq; + uint8_t AcgGfxclkSpreadEnabled; + uint8_t AcgGfxclkSpreadPercent; + uint16_t AcgGfxclkSpreadFreq; uint8_t Vr2_I2C_address; uint8_t padding_vr2[3]; -- GitLab From 102c16a0246d77043e555e1e5b5de316bc068cbc Mon Sep 17 00:00:00 2001 From: Lyude Paul <lyude@redhat.com> Date: Mon, 25 Jun 2018 21:09:04 -0400 Subject: [PATCH 0783/1506] drm/amdgpu: Make struct amdgpu_atif private to amdgpu_acpi.c Currently, there is nothing in amdgpu that actually uses these structs other than amdgpu_acpi.c. Additionally, since we're about to start saving the correct ACPI handle to use for calling ATIF in this struct this saves us from having to handle making sure that the acpi_handle (and by proxy, the type definition for acpi_handle and all of the other acpi headers) doesn't need to be included within the amdgpu_drv struct itself. This follows the example set by amdgpu_atpx_handler.c. Signed-off-by: Lyude Paul <lyude@redhat.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 40 +----------------- drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c | 54 ++++++++++++++++++++++-- 2 files changed, 53 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 86e4d8bd52a68..219fea72beebf 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -190,6 +190,7 @@ struct amdgpu_job; struct amdgpu_irq_src; struct amdgpu_fpriv; struct amdgpu_bo_va_mapping; +struct amdgpu_atif; enum amdgpu_cp_irq { AMDGPU_CP_IRQ_GFX_EOP = 0, @@ -1278,43 +1279,6 @@ struct amdgpu_vram_scratch { /* * ACPI */ -struct amdgpu_atif_notification_cfg { - bool enabled; - int command_code; -}; - -struct amdgpu_atif_notifications { - bool display_switch; - bool expansion_mode_change; - bool thermal_state; - bool forced_power_state; - bool system_power_state; - bool display_conf_change; - bool px_gfx_switch; - bool brightness_change; - bool dgpu_display_event; -}; - -struct amdgpu_atif_functions { - bool system_params; - bool sbios_requests; - bool select_active_disp; - bool lid_state; - bool get_tv_standard; - bool set_tv_standard; - bool get_panel_expansion_mode; - bool set_panel_expansion_mode; - bool temperature_change; - bool graphics_device_types; -}; - -struct amdgpu_atif { - struct amdgpu_atif_notifications notifications; - struct amdgpu_atif_functions functions; - struct amdgpu_atif_notification_cfg notification_cfg; - struct amdgpu_encoder *encoder_for_bl; -}; - struct amdgpu_atcs_functions { bool get_ext_state; bool pcie_perf_req; @@ -1475,7 +1439,7 @@ struct amdgpu_device { #if defined(CONFIG_DEBUG_FS) struct dentry *debugfs_regs[AMDGPU_DEBUGFS_MAX_COMPONENTS]; #endif - struct amdgpu_atif atif; + struct amdgpu_atif *atif; struct amdgpu_atcs atcs; struct mutex srbm_mutex; /* GRBM index mutex. Protects concurrent access to GRBM index */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c index 8fa850a070e0f..22c7e8ec0b9a6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c @@ -34,6 +34,43 @@ #include "amd_acpi.h" #include "atom.h" +struct amdgpu_atif_notification_cfg { + bool enabled; + int command_code; +}; + +struct amdgpu_atif_notifications { + bool display_switch; + bool expansion_mode_change; + bool thermal_state; + bool forced_power_state; + bool system_power_state; + bool display_conf_change; + bool px_gfx_switch; + bool brightness_change; + bool dgpu_display_event; +}; + +struct amdgpu_atif_functions { + bool system_params; + bool sbios_requests; + bool select_active_disp; + bool lid_state; + bool get_tv_standard; + bool set_tv_standard; + bool get_panel_expansion_mode; + bool set_panel_expansion_mode; + bool temperature_change; + bool graphics_device_types; +}; + +struct amdgpu_atif { + struct amdgpu_atif_notifications notifications; + struct amdgpu_atif_functions functions; + struct amdgpu_atif_notification_cfg notification_cfg; + struct amdgpu_encoder *encoder_for_bl; +}; + /* Call the ATIF method */ /** @@ -292,7 +329,7 @@ static int amdgpu_atif_get_sbios_requests(acpi_handle handle, static int amdgpu_atif_handler(struct amdgpu_device *adev, struct acpi_bus_event *event) { - struct amdgpu_atif *atif = &adev->atif; + struct amdgpu_atif *atif = adev->atif; struct atif_sbios_requests req; acpi_handle handle; int count; @@ -303,7 +340,8 @@ static int amdgpu_atif_handler(struct amdgpu_device *adev, if (strcmp(event->device_class, ACPI_VIDEO_CLASS) != 0) return NOTIFY_DONE; - if (!atif->notification_cfg.enabled || + if (!atif || + !atif->notification_cfg.enabled || event->type != atif->notification_cfg.command_code) /* Not our event */ return NOTIFY_DONE; @@ -642,7 +680,7 @@ static int amdgpu_acpi_event(struct notifier_block *nb, int amdgpu_acpi_init(struct amdgpu_device *adev) { acpi_handle handle; - struct amdgpu_atif *atif = &adev->atif; + struct amdgpu_atif *atif; struct amdgpu_atcs *atcs = &adev->atcs; int ret; @@ -659,11 +697,19 @@ int amdgpu_acpi_init(struct amdgpu_device *adev) } /* Call the ATIF method */ + atif = kzalloc(sizeof(*atif), GFP_KERNEL); + if (!atif) { + DRM_WARN("Not enough memory to initialize ATIF\n"); + goto out; + } + ret = amdgpu_atif_verify_interface(handle, atif); if (ret) { DRM_DEBUG_DRIVER("Call to ATIF verify_interface failed: %d\n", ret); + kfree(atif); goto out; } + adev->atif = atif; if (atif->notifications.brightness_change) { struct drm_encoder *tmp; @@ -720,4 +766,6 @@ int amdgpu_acpi_init(struct amdgpu_device *adev) void amdgpu_acpi_fini(struct amdgpu_device *adev) { unregister_acpi_notifier(&adev->acpi_nb); + if (adev->atif) + kfree(adev->atif); } -- GitLab From aa03c075d02f89ae5acae10df1c8a3b095a440e7 Mon Sep 17 00:00:00 2001 From: Lyude Paul <lyude@redhat.com> Date: Mon, 25 Jun 2018 21:09:05 -0400 Subject: [PATCH 0784/1506] drm/amdgpu: s/disp_detetion_ports/disp_detection_ports/ Fix typo. Reviewed-by: Jim Qu <Jim.Qu@amd.com> Signed-off-by: Lyude Paul <lyude@redhat.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c index daa06e7c5bb73..a3896412a019a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c @@ -32,7 +32,7 @@ struct amdgpu_atpx_functions { bool switch_start; bool switch_end; bool disp_connectors_mapping; - bool disp_detetion_ports; + bool disp_detection_ports; }; struct amdgpu_atpx { @@ -156,7 +156,7 @@ static void amdgpu_atpx_parse_functions(struct amdgpu_atpx_functions *f, u32 mas f->switch_start = mask & ATPX_GRAPHICS_DEVICE_SWITCH_START_NOTIFICATION_SUPPORTED; f->switch_end = mask & ATPX_GRAPHICS_DEVICE_SWITCH_END_NOTIFICATION_SUPPORTED; f->disp_connectors_mapping = mask & ATPX_GET_DISPLAY_CONNECTORS_MAPPING_SUPPORTED; - f->disp_detetion_ports = mask & ATPX_GET_DISPLAY_DETECTION_PORTS_SUPPORTED; + f->disp_detection_ports = mask & ATPX_GET_DISPLAY_DETECTION_PORTS_SUPPORTED; } /** -- GitLab From 24aeefcdee255d21cc43bb511d5fdb760062199d Mon Sep 17 00:00:00 2001 From: Lyude Paul <lyude@redhat.com> Date: Mon, 25 Jun 2018 21:09:06 -0400 Subject: [PATCH 0785/1506] drm/amdgpu: Add amdgpu_atpx_get_dhandle() Since it seems that some vendors are storing the ATIF ACPI methods under the same handle that ATPX lives under instead of the device's own handle, we're going to need to be able to retrieve this handle later so we can probe for ATIF there. Signed-off-by: Lyude Paul <lyude@redhat.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 6 ++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 219fea72beebf..8a440b9fa0fdc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1867,6 +1867,12 @@ static inline bool amdgpu_atpx_dgpu_req_power_for_displays(void) { return false; static inline bool amdgpu_has_atpx(void) { return false; } #endif +#if defined(CONFIG_VGA_SWITCHEROO) && defined(CONFIG_ACPI) +void *amdgpu_atpx_get_dhandle(void); +#else +static inline void *amdgpu_atpx_get_dhandle(void) { return NULL; } +#endif + /* * KMS */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c index a3896412a019a..b33f1680c9a32 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c @@ -90,6 +90,12 @@ bool amdgpu_atpx_dgpu_req_power_for_displays(void) { return amdgpu_atpx_priv.atpx.dgpu_req_power_for_displays; } +#if defined(CONFIG_ACPI) +void *amdgpu_atpx_get_dhandle(void) { + return amdgpu_atpx_priv.dhandle; +} +#endif + /** * amdgpu_atpx_call - call an ATPX method * -- GitLab From 280cf1a94b822dfa2b505afcd24979dae643d6bf Mon Sep 17 00:00:00 2001 From: Lyude Paul <lyude@redhat.com> Date: Mon, 25 Jun 2018 21:09:07 -0400 Subject: [PATCH 0786/1506] drm/amdgpu: Dynamically probe for ATIF handle (v2) The other day I was testing one of the HP laptops at my office with an i915/amdgpu hybrid setup and noticed that hotplugging was non-functional on almost all of the display outputs. I eventually discovered that all of the external outputs were connected to the amdgpu device instead of i915, and that the hotplugs weren't being detected so long as the GPU was in runtime suspend. After some talking with folks at AMD, I learned that amdgpu is actually supposed to support hotplug detection in runtime suspend so long as the OEM has implemented it properly in the firmware. On this HP ZBook 15 G4 (the machine in question), amdgpu wasn't managing to find the ATIF handle at all despite the fact that I could see acpi events being sent in response to any hotplugging. After going through dumps of the firmware, I discovered that this machine did in fact support ATIF, but that it's ATIF method lived in an entirely different namespace than this device's handle (the device handle was \_SB_.PCI0.PEG0.PEGP, but ATIF lives in ATPX's handle at \_SB_.PCI0.GFX0). So, fix this by probing ATPX's ACPI parent's namespace if we can't find ATIF elsewhere, along with storing a pointer to the proper handle to use for ATIF and using that instead of the device's handle. This fixes HPD detection while in runtime suspend for this ZBook! v2: Update the comment to reflect how the namespaces are arranged based on the system configuration. (Alex) Signed-off-by: Lyude Paul <lyude@redhat.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c | 79 +++++++++++++++++------- 1 file changed, 58 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c index 22c7e8ec0b9a6..0d8c3fc6eacef 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c @@ -65,6 +65,8 @@ struct amdgpu_atif_functions { }; struct amdgpu_atif { + acpi_handle handle; + struct amdgpu_atif_notifications notifications; struct amdgpu_atif_functions functions; struct amdgpu_atif_notification_cfg notification_cfg; @@ -83,8 +85,9 @@ struct amdgpu_atif { * Executes the requested ATIF function (all asics). * Returns a pointer to the acpi output buffer. */ -static union acpi_object *amdgpu_atif_call(acpi_handle handle, int function, - struct acpi_buffer *params) +static union acpi_object *amdgpu_atif_call(struct amdgpu_atif *atif, + int function, + struct acpi_buffer *params) { acpi_status status; union acpi_object atif_arg_elements[2]; @@ -107,7 +110,8 @@ static union acpi_object *amdgpu_atif_call(acpi_handle handle, int function, atif_arg_elements[1].integer.value = 0; } - status = acpi_evaluate_object(handle, "ATIF", &atif_arg, &buffer); + status = acpi_evaluate_object(atif->handle, NULL, &atif_arg, + &buffer); /* Fail only if calling the method fails and ATIF is supported */ if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { @@ -178,15 +182,14 @@ static void amdgpu_atif_parse_functions(struct amdgpu_atif_functions *f, u32 mas * (all asics). * returns 0 on success, error on failure. */ -static int amdgpu_atif_verify_interface(acpi_handle handle, - struct amdgpu_atif *atif) +static int amdgpu_atif_verify_interface(struct amdgpu_atif *atif) { union acpi_object *info; struct atif_verify_interface output; size_t size; int err = 0; - info = amdgpu_atif_call(handle, ATIF_FUNCTION_VERIFY_INTERFACE, NULL); + info = amdgpu_atif_call(atif, ATIF_FUNCTION_VERIFY_INTERFACE, NULL); if (!info) return -EIO; @@ -213,6 +216,35 @@ static int amdgpu_atif_verify_interface(acpi_handle handle, return err; } +static acpi_handle amdgpu_atif_probe_handle(acpi_handle dhandle) +{ + acpi_handle handle = NULL; + char acpi_method_name[255] = { 0 }; + struct acpi_buffer buffer = { sizeof(acpi_method_name), acpi_method_name }; + acpi_status status; + + /* For PX/HG systems, ATIF and ATPX are in the iGPU's namespace, on dGPU only + * systems, ATIF is in the dGPU's namespace. + */ + status = acpi_get_handle(dhandle, "ATIF", &handle); + if (ACPI_SUCCESS(status)) + goto out; + + if (amdgpu_has_atpx()) { + status = acpi_get_handle(amdgpu_atpx_get_dhandle(), "ATIF", + &handle); + if (ACPI_SUCCESS(status)) + goto out; + } + + DRM_DEBUG_DRIVER("No ATIF handle found\n"); + return NULL; +out: + acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); + DRM_DEBUG_DRIVER("Found ATIF handle %s\n", acpi_method_name); + return handle; +} + /** * amdgpu_atif_get_notification_params - determine notify configuration * @@ -225,15 +257,16 @@ static int amdgpu_atif_verify_interface(acpi_handle handle, * where n is specified in the result if a notifier is used. * Returns 0 on success, error on failure. */ -static int amdgpu_atif_get_notification_params(acpi_handle handle, - struct amdgpu_atif_notification_cfg *n) +static int amdgpu_atif_get_notification_params(struct amdgpu_atif *atif) { union acpi_object *info; + struct amdgpu_atif_notification_cfg *n = &atif->notification_cfg; struct atif_system_params params; size_t size; int err = 0; - info = amdgpu_atif_call(handle, ATIF_FUNCTION_GET_SYSTEM_PARAMETERS, NULL); + info = amdgpu_atif_call(atif, ATIF_FUNCTION_GET_SYSTEM_PARAMETERS, + NULL); if (!info) { err = -EIO; goto out; @@ -287,14 +320,15 @@ static int amdgpu_atif_get_notification_params(acpi_handle handle, * (all asics). * Returns 0 on success, error on failure. */ -static int amdgpu_atif_get_sbios_requests(acpi_handle handle, - struct atif_sbios_requests *req) +static int amdgpu_atif_get_sbios_requests(struct amdgpu_atif *atif, + struct atif_sbios_requests *req) { union acpi_object *info; size_t size; int count = 0; - info = amdgpu_atif_call(handle, ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS, NULL); + info = amdgpu_atif_call(atif, ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS, + NULL); if (!info) return -EIO; @@ -327,11 +361,10 @@ static int amdgpu_atif_get_sbios_requests(acpi_handle handle, * Returns NOTIFY code */ static int amdgpu_atif_handler(struct amdgpu_device *adev, - struct acpi_bus_event *event) + struct acpi_bus_event *event) { struct amdgpu_atif *atif = adev->atif; struct atif_sbios_requests req; - acpi_handle handle; int count; DRM_DEBUG_DRIVER("event, device_class = %s, type = %#x\n", @@ -347,8 +380,7 @@ static int amdgpu_atif_handler(struct amdgpu_device *adev, return NOTIFY_DONE; /* Check pending SBIOS requests */ - handle = ACPI_HANDLE(&adev->pdev->dev); - count = amdgpu_atif_get_sbios_requests(handle, &req); + count = amdgpu_atif_get_sbios_requests(atif, &req); if (count <= 0) return NOTIFY_DONE; @@ -679,7 +711,7 @@ static int amdgpu_acpi_event(struct notifier_block *nb, */ int amdgpu_acpi_init(struct amdgpu_device *adev) { - acpi_handle handle; + acpi_handle handle, atif_handle; struct amdgpu_atif *atif; struct amdgpu_atcs *atcs = &adev->atcs; int ret; @@ -696,14 +728,20 @@ int amdgpu_acpi_init(struct amdgpu_device *adev) DRM_DEBUG_DRIVER("Call to ATCS verify_interface failed: %d\n", ret); } - /* Call the ATIF method */ + /* Probe for ATIF, and initialize it if found */ + atif_handle = amdgpu_atif_probe_handle(handle); + if (!atif_handle) + goto out; + atif = kzalloc(sizeof(*atif), GFP_KERNEL); if (!atif) { DRM_WARN("Not enough memory to initialize ATIF\n"); goto out; } + atif->handle = atif_handle; - ret = amdgpu_atif_verify_interface(handle, atif); + /* Call the ATIF method */ + ret = amdgpu_atif_verify_interface(atif); if (ret) { DRM_DEBUG_DRIVER("Call to ATIF verify_interface failed: %d\n", ret); kfree(atif); @@ -739,8 +777,7 @@ int amdgpu_acpi_init(struct amdgpu_device *adev) } if (atif->functions.system_params) { - ret = amdgpu_atif_get_notification_params(handle, - &atif->notification_cfg); + ret = amdgpu_atif_get_notification_params(atif); if (ret) { DRM_DEBUG_DRIVER("Call to GET_SYSTEM_PARAMS failed: %d\n", ret); -- GitLab From 9735bf1930e658b074d72ea46bb317ad12483692 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= <michel.daenzer@amd.com> Date: Fri, 15 Jun 2018 16:37:03 +0200 Subject: [PATCH 0787/1506] drm/amdgpu: Use gmc_vram_full_visible in vram_mgr_bo_invisible_size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michel Dänzer <michel.daenzer@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c index b6333f92ba456..f7a4bd5885a39 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c @@ -112,7 +112,7 @@ u64 amdgpu_vram_mgr_bo_invisible_size(struct amdgpu_bo *bo) unsigned pages = mem->num_pages; u64 usage = 0; - if (adev->gmc.visible_vram_size == adev->gmc.real_vram_size) + if (amdgpu_gmc_vram_full_visible(&adev->gmc)) return 0; if (mem->start >= adev->gmc.visible_vram_size >> PAGE_SHIFT) -- GitLab From 463d2fe85b0eacb3760febe100994d4eb8fedde9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= <michel.daenzer@amd.com> Date: Fri, 22 Jun 2018 18:54:03 +0200 Subject: [PATCH 0788/1506] drm/amdgpu: Add AMDGPU_GPU_PAGES_IN_CPU_PAGE define MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To hopefully make the code dealing with GPU vs CPU pages a little clearer. Suggested-by: Christian König <christian.koenig@amd.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Michel Dänzer <michel.daenzer@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c | 8 ++++---- drivers/gpu/drm/amd/amdgpu/amdgpu_gart.h | 2 ++ drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 8 ++++---- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c index dd11b7313ca07..36113cb60ca2f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c @@ -234,7 +234,7 @@ int amdgpu_gart_unbind(struct amdgpu_device *adev, uint64_t offset, } t = offset / AMDGPU_GPU_PAGE_SIZE; - p = t / (PAGE_SIZE / AMDGPU_GPU_PAGE_SIZE); + p = t / AMDGPU_GPU_PAGES_IN_CPU_PAGE; for (i = 0; i < pages; i++, p++) { #ifdef CONFIG_DRM_AMDGPU_GART_DEBUGFS adev->gart.pages[p] = NULL; @@ -243,7 +243,7 @@ int amdgpu_gart_unbind(struct amdgpu_device *adev, uint64_t offset, if (!adev->gart.ptr) continue; - for (j = 0; j < (PAGE_SIZE / AMDGPU_GPU_PAGE_SIZE); j++, t++) { + for (j = 0; j < AMDGPU_GPU_PAGES_IN_CPU_PAGE; j++, t++) { amdgpu_gmc_set_pte_pde(adev, adev->gart.ptr, t, page_base, flags); page_base += AMDGPU_GPU_PAGE_SIZE; @@ -282,7 +282,7 @@ int amdgpu_gart_map(struct amdgpu_device *adev, uint64_t offset, for (i = 0; i < pages; i++) { page_base = dma_addr[i]; - for (j = 0; j < (PAGE_SIZE / AMDGPU_GPU_PAGE_SIZE); j++, t++) { + for (j = 0; j < AMDGPU_GPU_PAGES_IN_CPU_PAGE; j++, t++) { amdgpu_gmc_set_pte_pde(adev, dst, t, page_base, flags); page_base += AMDGPU_GPU_PAGE_SIZE; } @@ -319,7 +319,7 @@ int amdgpu_gart_bind(struct amdgpu_device *adev, uint64_t offset, #ifdef CONFIG_DRM_AMDGPU_GART_DEBUGFS t = offset / AMDGPU_GPU_PAGE_SIZE; - p = t / (PAGE_SIZE / AMDGPU_GPU_PAGE_SIZE); + p = t / AMDGPU_GPU_PAGES_IN_CPU_PAGE; for (i = 0; i < pages; i++, p++) adev->gart.pages[p] = pagelist ? pagelist[i] : NULL; #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.h index 456295c002915..9f9e9dc87da11 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.h @@ -37,6 +37,8 @@ struct amdgpu_bo; #define AMDGPU_GPU_PAGE_SHIFT 12 #define AMDGPU_GPU_PAGE_ALIGN(a) (((a) + AMDGPU_GPU_PAGE_MASK) & ~AMDGPU_GPU_PAGE_MASK) +#define AMDGPU_GPU_PAGES_IN_CPU_PAGE (PAGE_SIZE / AMDGPU_GPU_PAGE_SIZE) + struct amdgpu_gart { u64 table_addr; struct amdgpu_bo *robj; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 837066076ccf5..712af5c1a5d69 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -1567,7 +1567,7 @@ static int amdgpu_vm_bo_split_mapping(struct amdgpu_device *adev, if (nodes) { addr = nodes->start << PAGE_SHIFT; max_entries = (nodes->size - pfn) * - (PAGE_SIZE / AMDGPU_GPU_PAGE_SIZE); + AMDGPU_GPU_PAGES_IN_CPU_PAGE; } else { addr = 0; max_entries = S64_MAX; @@ -1578,7 +1578,7 @@ static int amdgpu_vm_bo_split_mapping(struct amdgpu_device *adev, max_entries = min(max_entries, 16ull * 1024ull); for (count = 1; - count < max_entries / (PAGE_SIZE / AMDGPU_GPU_PAGE_SIZE); + count < max_entries / AMDGPU_GPU_PAGES_IN_CPU_PAGE; ++count) { uint64_t idx = pfn + count; @@ -1592,7 +1592,7 @@ static int amdgpu_vm_bo_split_mapping(struct amdgpu_device *adev, dma_addr = pages_addr; } else { addr = pages_addr[pfn]; - max_entries = count * (PAGE_SIZE / AMDGPU_GPU_PAGE_SIZE); + max_entries = count * AMDGPU_GPU_PAGES_IN_CPU_PAGE; } } else if (flags & AMDGPU_PTE_VALID) { @@ -1607,7 +1607,7 @@ static int amdgpu_vm_bo_split_mapping(struct amdgpu_device *adev, if (r) return r; - pfn += (last - start + 1) / (PAGE_SIZE / AMDGPU_GPU_PAGE_SIZE); + pfn += (last - start + 1) / AMDGPU_GPU_PAGES_IN_CPU_PAGE; if (nodes && nodes->size == pfn) { pfn = 0; ++nodes; -- GitLab From 3f37e29626b0b5dbfcdf964ef2858b36a4c2cd67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= <michel.daenzer@amd.com> Date: Fri, 29 Jun 2018 11:27:11 +0200 Subject: [PATCH 0789/1506] drm/amdgpu: Remove amdgpu_gem_map_attach target_dev documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The parameter was removed. Fixes: a19741e5e5a9 "dma_buf: remove device parameter from attach callback v2" Reviewed-by: Junwei Zhang <Jerry.Zhang@amd.com> Signed-off-by: Michel Dänzer <michel.daenzer@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c index b2286bc41aec9..df7226ad64b52 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c @@ -191,7 +191,6 @@ amdgpu_gem_prime_import_sg_table(struct drm_device *dev, /** * amdgpu_gem_map_attach - &dma_buf_ops.attach implementation * @dma_buf: shared DMA buffer - * @target_dev: target device * @attach: DMA-buf attachment * * Makes sure that the shared DMA buffer can be accessed by the target device. -- GitLab From 3413accb3eac9182ee0fc0b350a5f18247d8ac9d Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexander.deucher@amd.com> Date: Thu, 28 Jun 2018 12:38:53 -0500 Subject: [PATCH 0790/1506] drm/amdgpu: fix swapped emit_ib_size in vce3 The phys and vm versions had the values swapped. Reviewed-by: Junwei Zhang <Jerry.Zhang@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/vce_v3_0.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c index 0999c843f623c..a71b97519cc05 100644 --- a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c @@ -900,7 +900,7 @@ static const struct amdgpu_ring_funcs vce_v3_0_ring_phys_funcs = { .emit_frame_size = 4 + /* vce_v3_0_emit_pipeline_sync */ 6, /* amdgpu_vce_ring_emit_fence x1 no user fence */ - .emit_ib_size = 5, /* vce_v3_0_ring_emit_ib */ + .emit_ib_size = 4, /* amdgpu_vce_ring_emit_ib */ .emit_ib = amdgpu_vce_ring_emit_ib, .emit_fence = amdgpu_vce_ring_emit_fence, .test_ring = amdgpu_vce_ring_test_ring, @@ -924,7 +924,7 @@ static const struct amdgpu_ring_funcs vce_v3_0_ring_vm_funcs = { 6 + /* vce_v3_0_emit_vm_flush */ 4 + /* vce_v3_0_emit_pipeline_sync */ 6 + 6, /* amdgpu_vce_ring_emit_fence x2 vm fence */ - .emit_ib_size = 4, /* amdgpu_vce_ring_emit_ib */ + .emit_ib_size = 5, /* vce_v3_0_ring_emit_ib */ .emit_ib = vce_v3_0_ring_emit_ib, .emit_vm_flush = vce_v3_0_emit_vm_flush, .emit_pipeline_sync = vce_v3_0_emit_pipeline_sync, -- GitLab From 70eb46db101b55acdf432187800915f72962a564 Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexander.deucher@amd.com> Date: Thu, 28 Jun 2018 12:44:25 -0500 Subject: [PATCH 0791/1506] drm/amdgpu/pm: fix display count in non-DC path new_active_crtcs is a bitmask, new_active_crtc_count is the actual count. Reviewed-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c index a003fd881a89f..f1404adc3a901 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c @@ -1959,7 +1959,7 @@ void amdgpu_pm_compute_clocks(struct amdgpu_device *adev) if (!amdgpu_device_has_dc_support(adev)) { mutex_lock(&adev->pm.mutex); amdgpu_dpm_get_active_displays(adev); - adev->pm.pm_display_cfg.num_display = adev->pm.dpm.new_active_crtcs; + adev->pm.pm_display_cfg.num_display = adev->pm.dpm.new_active_crtc_count; adev->pm.pm_display_cfg.vrefresh = amdgpu_dpm_get_vrefresh(adev); adev->pm.pm_display_cfg.min_vblank_time = amdgpu_dpm_get_vblank_time(adev); /* we have issues with mclk switching with refresh rates over 120 hz on the non-DC code. */ -- GitLab From c9037d44390cc1ef7ec490c63ec8a4ee92a57925 Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexander.deucher@amd.com> Date: Thu, 28 Jun 2018 12:48:10 -0500 Subject: [PATCH 0792/1506] drm/amdgpu/pp: add missing byte swapping in process_pptables_v1_0.c Values need to be swapped on big endian. Reviewed-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c b/drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c index 35bd9870ab108..4e1fd53938458 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c @@ -183,10 +183,10 @@ static int get_vddc_lookup_table( ATOM_Tonga_Voltage_Lookup_Record, entries, vddc_lookup_pp_tables, i); record->us_calculated = 0; - record->us_vdd = atom_record->usVdd; - record->us_cac_low = atom_record->usCACLow; - record->us_cac_mid = atom_record->usCACMid; - record->us_cac_high = atom_record->usCACHigh; + record->us_vdd = le16_to_cpu(atom_record->usVdd); + record->us_cac_low = le16_to_cpu(atom_record->usCACLow); + record->us_cac_mid = le16_to_cpu(atom_record->usCACMid); + record->us_cac_high = le16_to_cpu(atom_record->usCACHigh); } *lookup_table = table; -- GitLab From 594c34cc6f31807f23aae5c9cec6dea31d782f90 Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexander.deucher@amd.com> Date: Thu, 28 Jun 2018 12:51:06 -0500 Subject: [PATCH 0793/1506] drm/amdgpu/pp: fix endian swapping in atomctrl_get_voltage_range Need to swap before doing arthimetic on the values. Reviewed-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.c b/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.c index 7047e29755c35..01dc46dc9c8a0 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/ppatomctrl.c @@ -1544,14 +1544,14 @@ void atomctrl_get_voltage_range(struct pp_hwmgr *hwmgr, uint32_t *max_vddc, switch (hwmgr->chip_id) { case CHIP_TONGA: case CHIP_FIJI: - *max_vddc = le32_to_cpu(((ATOM_ASIC_PROFILING_INFO_V3_3 *)profile)->ulMaxVddc/4); - *min_vddc = le32_to_cpu(((ATOM_ASIC_PROFILING_INFO_V3_3 *)profile)->ulMinVddc/4); + *max_vddc = le32_to_cpu(((ATOM_ASIC_PROFILING_INFO_V3_3 *)profile)->ulMaxVddc) / 4; + *min_vddc = le32_to_cpu(((ATOM_ASIC_PROFILING_INFO_V3_3 *)profile)->ulMinVddc) / 4; return; case CHIP_POLARIS11: case CHIP_POLARIS10: case CHIP_POLARIS12: - *max_vddc = le32_to_cpu(((ATOM_ASIC_PROFILING_INFO_V3_6 *)profile)->ulMaxVddc/100); - *min_vddc = le32_to_cpu(((ATOM_ASIC_PROFILING_INFO_V3_6 *)profile)->ulMinVddc/100); + *max_vddc = le32_to_cpu(((ATOM_ASIC_PROFILING_INFO_V3_6 *)profile)->ulMaxVddc) / 100; + *min_vddc = le32_to_cpu(((ATOM_ASIC_PROFILING_INFO_V3_6 *)profile)->ulMinVddc) / 100; return; default: break; -- GitLab From 9861023c29dbc069e49dc85fb21f01da9f75ff06 Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexander.deucher@amd.com> Date: Thu, 28 Jun 2018 12:52:43 -0500 Subject: [PATCH 0794/1506] drm/amdgpu/pp: fix copy paste typo in smu7_init_dpm_defaults Should be mclk rather than sclk. Reviewed-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c index de295b7442b7b..e5c27d12aa494 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c @@ -1578,7 +1578,7 @@ static void smu7_init_dpm_defaults(struct pp_hwmgr *hwmgr) data->current_profile_setting.sclk_up_hyst = 0; data->current_profile_setting.sclk_down_hyst = 100; data->current_profile_setting.sclk_activity = SMU7_SCLK_TARGETACTIVITY_DFLT; - data->current_profile_setting.bupdate_sclk = 1; + data->current_profile_setting.bupdate_mclk = 1; data->current_profile_setting.mclk_up_hyst = 0; data->current_profile_setting.mclk_down_hyst = 100; data->current_profile_setting.mclk_activity = SMU7_MCLK_TARGETACTIVITY_DFLT; -- GitLab From ed54d954e5c1d8bad453fb86109075b3577152b7 Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexander.deucher@amd.com> Date: Thu, 28 Jun 2018 13:21:12 -0500 Subject: [PATCH 0795/1506] drm/amdgpu/pp: fix copy paste typo in smu7_get_pp_table_entry_callback_func_v1 Should be using PCIELaneLow for the low clock level. Reviewed-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c index e5c27d12aa494..077b79938528d 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c @@ -3183,7 +3183,7 @@ static int smu7_get_pp_table_entry_callback_func_v1(struct pp_hwmgr *hwmgr, performance_level->pcie_gen = get_pcie_gen_support(data->pcie_gen_cap, state_entry->ucPCIEGenLow); performance_level->pcie_lane = get_pcie_lane_support(data->pcie_lane_cap, - state_entry->ucPCIELaneHigh); + state_entry->ucPCIELaneLow); performance_level = &(smu7_power_state->performance_levels [smu7_power_state->performance_level_count++]); -- GitLab From 1cf0abb6c983d90ec541ebba79934a9c4786df1d Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexander.deucher@amd.com> Date: Mon, 25 Jun 2018 12:24:10 -0500 Subject: [PATCH 0796/1506] drm/amdgpu/sdma: simplify sdma instance setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Set the me instance in early init and use that rather than calculating the instance based on the ring pointer. Reviewed-by: James Zhu <James.Zhu@amd.com> Reviewed-by: Leo Liu <leo.liu@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/cik_sdma.c | 12 ++++++------ drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c | 12 ++++++------ drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c | 14 ++++++-------- drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c | 23 +++++++++++------------ 4 files changed, 29 insertions(+), 32 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c index a7576255cc302..dbd553a8d5842 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c +++ b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c @@ -177,9 +177,8 @@ static uint64_t cik_sdma_ring_get_rptr(struct amdgpu_ring *ring) static uint64_t cik_sdma_ring_get_wptr(struct amdgpu_ring *ring) { struct amdgpu_device *adev = ring->adev; - u32 me = (ring == &adev->sdma.instance[0].ring) ? 0 : 1; - return (RREG32(mmSDMA0_GFX_RB_WPTR + sdma_offsets[me]) & 0x3fffc) >> 2; + return (RREG32(mmSDMA0_GFX_RB_WPTR + sdma_offsets[ring->me]) & 0x3fffc) >> 2; } /** @@ -192,9 +191,8 @@ static uint64_t cik_sdma_ring_get_wptr(struct amdgpu_ring *ring) static void cik_sdma_ring_set_wptr(struct amdgpu_ring *ring) { struct amdgpu_device *adev = ring->adev; - u32 me = (ring == &adev->sdma.instance[0].ring) ? 0 : 1; - WREG32(mmSDMA0_GFX_RB_WPTR + sdma_offsets[me], + WREG32(mmSDMA0_GFX_RB_WPTR + sdma_offsets[ring->me], (lower_32_bits(ring->wptr) << 2) & 0x3fffc); } @@ -248,7 +246,7 @@ static void cik_sdma_ring_emit_hdp_flush(struct amdgpu_ring *ring) SDMA_POLL_REG_MEM_EXTRA_FUNC(3)); /* == */ u32 ref_and_mask; - if (ring == &ring->adev->sdma.instance[0].ring) + if (ring->me == 0) ref_and_mask = GPU_HDP_FLUSH_DONE__SDMA0_MASK; else ref_and_mask = GPU_HDP_FLUSH_DONE__SDMA1_MASK; @@ -1290,8 +1288,10 @@ static void cik_sdma_set_ring_funcs(struct amdgpu_device *adev) { int i; - for (i = 0; i < adev->sdma.num_instances; i++) + for (i = 0; i < adev->sdma.num_instances; i++) { adev->sdma.instance[i].ring.funcs = &cik_sdma_ring_funcs; + adev->sdma.instance[i].ring.me = i; + } } static const struct amdgpu_irq_src_funcs cik_sdma_trap_irq_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c index c7190c39c4f52..cee4fae76d200 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c @@ -202,8 +202,7 @@ static uint64_t sdma_v2_4_ring_get_rptr(struct amdgpu_ring *ring) static uint64_t sdma_v2_4_ring_get_wptr(struct amdgpu_ring *ring) { struct amdgpu_device *adev = ring->adev; - int me = (ring == &ring->adev->sdma.instance[0].ring) ? 0 : 1; - u32 wptr = RREG32(mmSDMA0_GFX_RB_WPTR + sdma_offsets[me]) >> 2; + u32 wptr = RREG32(mmSDMA0_GFX_RB_WPTR + sdma_offsets[ring->me]) >> 2; return wptr; } @@ -218,9 +217,8 @@ static uint64_t sdma_v2_4_ring_get_wptr(struct amdgpu_ring *ring) static void sdma_v2_4_ring_set_wptr(struct amdgpu_ring *ring) { struct amdgpu_device *adev = ring->adev; - int me = (ring == &ring->adev->sdma.instance[0].ring) ? 0 : 1; - WREG32(mmSDMA0_GFX_RB_WPTR + sdma_offsets[me], lower_32_bits(ring->wptr) << 2); + WREG32(mmSDMA0_GFX_RB_WPTR + sdma_offsets[ring->me], lower_32_bits(ring->wptr) << 2); } static void sdma_v2_4_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count) @@ -273,7 +271,7 @@ static void sdma_v2_4_ring_emit_hdp_flush(struct amdgpu_ring *ring) { u32 ref_and_mask = 0; - if (ring == &ring->adev->sdma.instance[0].ring) + if (ring->me == 0) ref_and_mask = REG_SET_FIELD(ref_and_mask, GPU_HDP_FLUSH_DONE, SDMA0, 1); else ref_and_mask = REG_SET_FIELD(ref_and_mask, GPU_HDP_FLUSH_DONE, SDMA1, 1); @@ -1213,8 +1211,10 @@ static void sdma_v2_4_set_ring_funcs(struct amdgpu_device *adev) { int i; - for (i = 0; i < adev->sdma.num_instances; i++) + for (i = 0; i < adev->sdma.num_instances; i++) { adev->sdma.instance[i].ring.funcs = &sdma_v2_4_ring_funcs; + adev->sdma.instance[i].ring.me = i; + } } static const struct amdgpu_irq_src_funcs sdma_v2_4_trap_irq_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c index aa9ab299fd32a..99616dd9594f2 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c @@ -365,9 +365,7 @@ static uint64_t sdma_v3_0_ring_get_wptr(struct amdgpu_ring *ring) /* XXX check if swapping is necessary on BE */ wptr = ring->adev->wb.wb[ring->wptr_offs] >> 2; } else { - int me = (ring == &ring->adev->sdma.instance[0].ring) ? 0 : 1; - - wptr = RREG32(mmSDMA0_GFX_RB_WPTR + sdma_offsets[me]) >> 2; + wptr = RREG32(mmSDMA0_GFX_RB_WPTR + sdma_offsets[ring->me]) >> 2; } return wptr; @@ -394,9 +392,7 @@ static void sdma_v3_0_ring_set_wptr(struct amdgpu_ring *ring) WRITE_ONCE(*wb, (lower_32_bits(ring->wptr) << 2)); } else { - int me = (ring == &ring->adev->sdma.instance[0].ring) ? 0 : 1; - - WREG32(mmSDMA0_GFX_RB_WPTR + sdma_offsets[me], lower_32_bits(ring->wptr) << 2); + WREG32(mmSDMA0_GFX_RB_WPTR + sdma_offsets[ring->me], lower_32_bits(ring->wptr) << 2); } } @@ -450,7 +446,7 @@ static void sdma_v3_0_ring_emit_hdp_flush(struct amdgpu_ring *ring) { u32 ref_and_mask = 0; - if (ring == &ring->adev->sdma.instance[0].ring) + if (ring->me == 0) ref_and_mask = REG_SET_FIELD(ref_and_mask, GPU_HDP_FLUSH_DONE, SDMA0, 1); else ref_and_mask = REG_SET_FIELD(ref_and_mask, GPU_HDP_FLUSH_DONE, SDMA1, 1); @@ -1655,8 +1651,10 @@ static void sdma_v3_0_set_ring_funcs(struct amdgpu_device *adev) { int i; - for (i = 0; i < adev->sdma.num_instances; i++) + for (i = 0; i < adev->sdma.num_instances; i++) { adev->sdma.instance[i].ring.funcs = &sdma_v3_0_ring_funcs; + adev->sdma.instance[i].ring.me = i; + } } static const struct amdgpu_irq_src_funcs sdma_v3_0_trap_irq_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c index ca53b3fba422d..572ca63cf676b 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c @@ -296,13 +296,12 @@ static uint64_t sdma_v4_0_ring_get_wptr(struct amdgpu_ring *ring) DRM_DEBUG("wptr/doorbell before shift == 0x%016llx\n", wptr); } else { u32 lowbit, highbit; - int me = (ring == &adev->sdma.instance[0].ring) ? 0 : 1; - lowbit = RREG32(sdma_v4_0_get_reg_offset(adev, me, mmSDMA0_GFX_RB_WPTR)) >> 2; - highbit = RREG32(sdma_v4_0_get_reg_offset(adev, me, mmSDMA0_GFX_RB_WPTR_HI)) >> 2; + lowbit = RREG32(sdma_v4_0_get_reg_offset(adev, ring->me, mmSDMA0_GFX_RB_WPTR)) >> 2; + highbit = RREG32(sdma_v4_0_get_reg_offset(adev, ring->me, mmSDMA0_GFX_RB_WPTR_HI)) >> 2; DRM_DEBUG("wptr [%i]high== 0x%08x low==0x%08x\n", - me, highbit, lowbit); + ring->me, highbit, lowbit); wptr = highbit; wptr = wptr << 32; wptr |= lowbit; @@ -339,17 +338,15 @@ static void sdma_v4_0_ring_set_wptr(struct amdgpu_ring *ring) ring->doorbell_index, ring->wptr << 2); WDOORBELL64(ring->doorbell_index, ring->wptr << 2); } else { - int me = (ring == &ring->adev->sdma.instance[0].ring) ? 0 : 1; - DRM_DEBUG("Not using doorbell -- " "mmSDMA%i_GFX_RB_WPTR == 0x%08x " "mmSDMA%i_GFX_RB_WPTR_HI == 0x%08x\n", - me, + ring->me, lower_32_bits(ring->wptr << 2), - me, + ring->me, upper_32_bits(ring->wptr << 2)); - WREG32(sdma_v4_0_get_reg_offset(adev, me, mmSDMA0_GFX_RB_WPTR), lower_32_bits(ring->wptr << 2)); - WREG32(sdma_v4_0_get_reg_offset(adev, me, mmSDMA0_GFX_RB_WPTR_HI), upper_32_bits(ring->wptr << 2)); + WREG32(sdma_v4_0_get_reg_offset(adev, ring->me, mmSDMA0_GFX_RB_WPTR), lower_32_bits(ring->wptr << 2)); + WREG32(sdma_v4_0_get_reg_offset(adev, ring->me, mmSDMA0_GFX_RB_WPTR_HI), upper_32_bits(ring->wptr << 2)); } } @@ -430,7 +427,7 @@ static void sdma_v4_0_ring_emit_hdp_flush(struct amdgpu_ring *ring) u32 ref_and_mask = 0; const struct nbio_hdp_flush_reg *nbio_hf_reg = adev->nbio_funcs->hdp_flush_reg; - if (ring == &ring->adev->sdma.instance[0].ring) + if (ring->me == 0) ref_and_mask = nbio_hf_reg->ref_and_mask_sdma0; else ref_and_mask = nbio_hf_reg->ref_and_mask_sdma1; @@ -1651,8 +1648,10 @@ static void sdma_v4_0_set_ring_funcs(struct amdgpu_device *adev) { int i; - for (i = 0; i < adev->sdma.num_instances; i++) + for (i = 0; i < adev->sdma.num_instances; i++) { adev->sdma.instance[i].ring.funcs = &sdma_v4_0_ring_funcs; + adev->sdma.instance[i].ring.me = i; + } } static const struct amdgpu_irq_src_funcs sdma_v4_0_trap_irq_funcs = { -- GitLab From 5d4af988f39052b77f8fdd9ed5cb61ca1645a3a6 Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexander.deucher@amd.com> Date: Mon, 25 Jun 2018 12:41:21 -0500 Subject: [PATCH 0797/1506] drm/amdgpu/vce: simplify vce instance setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Set the me instance in early init and use that rather than calculating the instance based on the ring pointer. Reviewed-by: James Zhu <James.Zhu@amd.com> Reviewed-by: Leo Liu <leo.liu@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/vce_v2_0.c | 10 ++++++---- drivers/gpu/drm/amd/amdgpu/vce_v3_0.c | 20 ++++++++++++-------- drivers/gpu/drm/amd/amdgpu/vce_v4_0.c | 16 +++++++++------- 3 files changed, 27 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c index 47f70827195bf..d48e877b682e8 100644 --- a/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c @@ -56,7 +56,7 @@ static uint64_t vce_v2_0_ring_get_rptr(struct amdgpu_ring *ring) { struct amdgpu_device *adev = ring->adev; - if (ring == &adev->vce.ring[0]) + if (ring->me == 0) return RREG32(mmVCE_RB_RPTR); else return RREG32(mmVCE_RB_RPTR2); @@ -73,7 +73,7 @@ static uint64_t vce_v2_0_ring_get_wptr(struct amdgpu_ring *ring) { struct amdgpu_device *adev = ring->adev; - if (ring == &adev->vce.ring[0]) + if (ring->me == 0) return RREG32(mmVCE_RB_WPTR); else return RREG32(mmVCE_RB_WPTR2); @@ -90,7 +90,7 @@ static void vce_v2_0_ring_set_wptr(struct amdgpu_ring *ring) { struct amdgpu_device *adev = ring->adev; - if (ring == &adev->vce.ring[0]) + if (ring->me == 0) WREG32(mmVCE_RB_WPTR, lower_32_bits(ring->wptr)); else WREG32(mmVCE_RB_WPTR2, lower_32_bits(ring->wptr)); @@ -627,8 +627,10 @@ static void vce_v2_0_set_ring_funcs(struct amdgpu_device *adev) { int i; - for (i = 0; i < adev->vce.num_rings; i++) + for (i = 0; i < adev->vce.num_rings; i++) { adev->vce.ring[i].funcs = &vce_v2_0_ring_funcs; + adev->vce.ring[i].me = i; + } } static const struct amdgpu_irq_src_funcs vce_v2_0_irq_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c index a71b97519cc05..99604d0262ada 100644 --- a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c @@ -86,9 +86,9 @@ static uint64_t vce_v3_0_ring_get_rptr(struct amdgpu_ring *ring) else if (adev->vce.harvest_config == AMDGPU_VCE_HARVEST_VCE0) WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(1)); - if (ring == &adev->vce.ring[0]) + if (ring->me == 0) v = RREG32(mmVCE_RB_RPTR); - else if (ring == &adev->vce.ring[1]) + else if (ring->me == 1) v = RREG32(mmVCE_RB_RPTR2); else v = RREG32(mmVCE_RB_RPTR3); @@ -118,9 +118,9 @@ static uint64_t vce_v3_0_ring_get_wptr(struct amdgpu_ring *ring) else if (adev->vce.harvest_config == AMDGPU_VCE_HARVEST_VCE0) WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(1)); - if (ring == &adev->vce.ring[0]) + if (ring->me == 0) v = RREG32(mmVCE_RB_WPTR); - else if (ring == &adev->vce.ring[1]) + else if (ring->me == 1) v = RREG32(mmVCE_RB_WPTR2); else v = RREG32(mmVCE_RB_WPTR3); @@ -149,9 +149,9 @@ static void vce_v3_0_ring_set_wptr(struct amdgpu_ring *ring) else if (adev->vce.harvest_config == AMDGPU_VCE_HARVEST_VCE0) WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(1)); - if (ring == &adev->vce.ring[0]) + if (ring->me == 0) WREG32(mmVCE_RB_WPTR, lower_32_bits(ring->wptr)); - else if (ring == &adev->vce.ring[1]) + else if (ring->me == 1) WREG32(mmVCE_RB_WPTR2, lower_32_bits(ring->wptr)); else WREG32(mmVCE_RB_WPTR3, lower_32_bits(ring->wptr)); @@ -942,12 +942,16 @@ static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev) int i; if (adev->asic_type >= CHIP_STONEY) { - for (i = 0; i < adev->vce.num_rings; i++) + for (i = 0; i < adev->vce.num_rings; i++) { adev->vce.ring[i].funcs = &vce_v3_0_ring_vm_funcs; + adev->vce.ring[i].me = i; + } DRM_INFO("VCE enabled in VM mode\n"); } else { - for (i = 0; i < adev->vce.num_rings; i++) + for (i = 0; i < adev->vce.num_rings; i++) { adev->vce.ring[i].funcs = &vce_v3_0_ring_phys_funcs; + adev->vce.ring[i].me = i; + } DRM_INFO("VCE enabled in physical mode\n"); } } diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c index 8fd1b742985ac..575bf9709389a 100644 --- a/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c @@ -60,9 +60,9 @@ static uint64_t vce_v4_0_ring_get_rptr(struct amdgpu_ring *ring) { struct amdgpu_device *adev = ring->adev; - if (ring == &adev->vce.ring[0]) + if (ring->me == 0) return RREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_RB_RPTR)); - else if (ring == &adev->vce.ring[1]) + else if (ring->me == 1) return RREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_RB_RPTR2)); else return RREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_RB_RPTR3)); @@ -82,9 +82,9 @@ static uint64_t vce_v4_0_ring_get_wptr(struct amdgpu_ring *ring) if (ring->use_doorbell) return adev->wb.wb[ring->wptr_offs]; - if (ring == &adev->vce.ring[0]) + if (ring->me == 0) return RREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_RB_WPTR)); - else if (ring == &adev->vce.ring[1]) + else if (ring->me == 1) return RREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_RB_WPTR2)); else return RREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_RB_WPTR3)); @@ -108,10 +108,10 @@ static void vce_v4_0_ring_set_wptr(struct amdgpu_ring *ring) return; } - if (ring == &adev->vce.ring[0]) + if (ring->me == 0) WREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_RB_WPTR), lower_32_bits(ring->wptr)); - else if (ring == &adev->vce.ring[1]) + else if (ring->me == 1) WREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_RB_WPTR2), lower_32_bits(ring->wptr)); else @@ -1088,8 +1088,10 @@ static void vce_v4_0_set_ring_funcs(struct amdgpu_device *adev) { int i; - for (i = 0; i < adev->vce.num_rings; i++) + for (i = 0; i < adev->vce.num_rings; i++) { adev->vce.ring[i].funcs = &vce_v4_0_ring_vm_funcs; + adev->vce.ring[i].me = i; + } DRM_INFO("VCE enabled in VM mode\n"); } -- GitLab From c3c18309c8319ab4600830bc010d916cb4e529de Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann <contact@tzimmermann.org> Date: Thu, 28 Jun 2018 16:10:25 +0200 Subject: [PATCH 0798/1506] drm/amd: 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 <contact@tzimmermann.org> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index dcdc97d6dc447..963578c34c472 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -665,7 +665,7 @@ static int amdgpu_pci_probe(struct pci_dev *pdev, err_pci: pci_disable_device(pdev); err_free: - drm_dev_unref(dev); + drm_dev_put(dev); return ret; } @@ -675,7 +675,7 @@ amdgpu_pci_remove(struct pci_dev *pdev) struct drm_device *dev = pci_get_drvdata(pdev); drm_dev_unregister(dev); - drm_dev_unref(dev); + drm_dev_put(dev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); } -- GitLab From 9f87830f61e79d5e2ae2529cd225cb123f7742b2 Mon Sep 17 00:00:00 2001 From: "Dirk Hohndel (VMware)" <dirk@hohndel.org> Date: Mon, 7 May 2018 01:16:20 +0200 Subject: [PATCH 0799/1506] drm/amd: add SPDX identifier and clarify license This is dual licensed under GPL-2.0 or MIT. Acked-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Dirk Hohndel (VMware) <dirk@hohndel.org> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_test.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c index e3878256743a2..57b14dccd8e02 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT /* * Copyright 2009 VMware, Inc. * -- GitLab From da5fd66c0eb79e01501578bfc69352cc5e2e979d Mon Sep 17 00:00:00 2001 From: "Dirk Hohndel (VMware)" <dirk@hohndel.org> Date: Mon, 7 May 2018 01:16:23 +0200 Subject: [PATCH 0800/1506] drm/radeon: add SPDX identifier and clarify license This is dual licensed under GPL-2.0 or MIT. Acked-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Dirk Hohndel (VMware) <dirk@hohndel.org> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/radeon/radeon_test.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/radeon/radeon_test.c b/drivers/gpu/drm/radeon/radeon_test.c index 48f4b273e3161..0c7f228db6e3d 100644 --- a/drivers/gpu/drm/radeon/radeon_test.c +++ b/drivers/gpu/drm/radeon/radeon_test.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT /* * Copyright 2009 VMware, Inc. * -- GitLab From f8ddb39a15100076884a625e97c91f3578c686f5 Mon Sep 17 00:00:00 2001 From: Huang Rui <ray.huang@amd.com> Date: Thu, 28 Jun 2018 14:38:21 +0800 Subject: [PATCH 0801/1506] drm/amdgpu: fix the wrong type of gem object creation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We still use legacy type of gem_object_create, it should update to ttm_bo_type now. Signed-off-by: Huang Rui <ray.huang@amd.com> Reviewed-by: Michel Dänzer <michel.daenzer@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c index bc5fd8ebab5dd..811c62927c382 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c @@ -146,7 +146,7 @@ static int amdgpufb_create_pinned_object(struct amdgpu_fbdev *rfbdev, AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED | AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS | AMDGPU_GEM_CREATE_VRAM_CLEARED, - true, NULL, &gobj); + ttm_bo_type_kernel, NULL, &gobj); if (ret) { pr_err("failed to allocate framebuffer (%d)\n", aligned_size); return -ENOMEM; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index 89743cdc1c2c1..bcbdcf997d207 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -265,7 +265,7 @@ int amdgpu_gem_create_ioctl(struct drm_device *dev, void *data, r = amdgpu_gem_object_create(adev, size, args->in.alignment, (u32)(0xffffffff & args->in.domains), - flags, false, resv, &gobj); + flags, ttm_bo_type_device, resv, &gobj); if (flags & AMDGPU_GEM_CREATE_VM_ALWAYS_VALID) { if (!r) { struct amdgpu_bo *abo = gem_to_amdgpu_bo(gobj); @@ -317,7 +317,7 @@ int amdgpu_gem_userptr_ioctl(struct drm_device *dev, void *data, /* create a gem object to contain this object in */ r = amdgpu_gem_object_create(adev, args->size, 0, AMDGPU_GEM_DOMAIN_CPU, - 0, 0, NULL, &gobj); + 0, ttm_bo_type_device, NULL, &gobj); if (r) return r; @@ -766,7 +766,7 @@ int amdgpu_mode_dumb_create(struct drm_file *file_priv, amdgpu_display_supported_domains(adev)); r = amdgpu_gem_object_create(adev, args->size, 0, domain, AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, - false, NULL, &gobj); + ttm_bo_type_device, NULL, &gobj); if (r) return -ENOMEM; -- GitLab From afb1436c7b44ab928e6369a4d48e3abb8215241e Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexander.deucher@amd.com> Date: Thu, 28 Jun 2018 12:32:27 -0500 Subject: [PATCH 0802/1506] drm/amdgpu: update uvd_v6_0_ring_vm_funcs to use new nop packet Was missed when updating the uvd 6 module. Fixes: 1aac3c9180 (drm/amdgpu: fix insert nop for UVD6 ring) Reviewed-by: Leo Liu <leo.liu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c index 1df1c6115341d..8ee1c2eaaa14e 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c @@ -1569,7 +1569,6 @@ static const struct amdgpu_ring_funcs uvd_v6_0_ring_phys_funcs = { static const struct amdgpu_ring_funcs uvd_v6_0_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_UVD, .align_mask = 0xf, - .nop = PACKET0(mmUVD_NO_OP, 0), .support_64bit_ptrs = false, .get_rptr = uvd_v6_0_ring_get_rptr, .get_wptr = uvd_v6_0_ring_get_wptr, @@ -1587,7 +1586,7 @@ static const struct amdgpu_ring_funcs uvd_v6_0_ring_vm_funcs = { .emit_hdp_flush = uvd_v6_0_ring_emit_hdp_flush, .test_ring = uvd_v6_0_ring_test_ring, .test_ib = amdgpu_uvd_ring_test_ib, - .insert_nop = amdgpu_ring_insert_nop, + .insert_nop = uvd_v6_0_ring_insert_nop, .pad_ib = amdgpu_ring_generic_pad_ib, .begin_use = amdgpu_uvd_ring_begin_use, .end_use = amdgpu_uvd_ring_end_use, -- GitLab From 23ec3d1479fd79658cd52c47618d8ddd2f32550b Mon Sep 17 00:00:00 2001 From: Rex Zhu <Rex.Zhu@amd.com> Date: Mon, 18 Jun 2018 18:15:15 +0800 Subject: [PATCH 0803/1506] drm/amd/pp: Convert clock unit to KHz as defined Convert clock unit 10KHz to KHz as the data sturct defined. e.g. struct pp_clock_with_latency { uint32_t clocks_in_khz; uint32_t latency_in_us; }; Meanwhile revert the same conversion in display side. Acked-by: Alex Deucher <alexander.deucher@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c | 18 ++++------ .../gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c | 4 +-- .../drm/amd/powerplay/hwmgr/vega10_hwmgr.c | 34 +++++++++---------- .../drm/amd/powerplay/hwmgr/vega12_hwmgr.c | 20 +++++------ 4 files changed, 34 insertions(+), 42 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c index cf92d7a24f338..596d49d7f9193 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c @@ -203,8 +203,7 @@ static void pp_to_dc_clock_levels( for (i = 0; i < dc_clks->num_levels; i++) { DRM_INFO("DM_PPLIB:\t %d\n", pp_clks->clock[i]); - /* translate 10kHz to kHz */ - dc_clks->clocks_in_khz[i] = pp_clks->clock[i] * 10; + dc_clks->clocks_in_khz[i] = pp_clks->clock[i]; } } @@ -229,9 +228,8 @@ static void pp_to_dc_clock_levels_with_latency( DC_DECODE_PP_CLOCK_TYPE(dc_clk_type)); for (i = 0; i < clk_level_info->num_levels; i++) { - DRM_DEBUG("DM_PPLIB:\t %d in 10kHz\n", pp_clks->data[i].clocks_in_khz); - /* translate 10kHz to kHz */ - clk_level_info->data[i].clocks_in_khz = pp_clks->data[i].clocks_in_khz * 10; + DRM_DEBUG("DM_PPLIB:\t %d in kHz\n", pp_clks->data[i].clocks_in_khz); + clk_level_info->data[i].clocks_in_khz = pp_clks->data[i].clocks_in_khz; clk_level_info->data[i].latency_in_us = pp_clks->data[i].latency_in_us; } } @@ -257,9 +255,8 @@ static void pp_to_dc_clock_levels_with_voltage( DC_DECODE_PP_CLOCK_TYPE(dc_clk_type)); for (i = 0; i < clk_level_info->num_levels; i++) { - DRM_INFO("DM_PPLIB:\t %d in 10kHz\n", pp_clks->data[i].clocks_in_khz); - /* translate 10kHz to kHz */ - clk_level_info->data[i].clocks_in_khz = pp_clks->data[i].clocks_in_khz * 10; + DRM_INFO("DM_PPLIB:\t %d in kHz\n", pp_clks->data[i].clocks_in_khz); + clk_level_info->data[i].clocks_in_khz = pp_clks->data[i].clocks_in_khz; clk_level_info->data[i].voltage_in_mv = pp_clks->data[i].voltage_in_mv; } } @@ -434,9 +431,8 @@ bool dm_pp_get_static_clocks( return false; static_clk_info->max_clocks_state = pp_clk_info.max_clocks_state; - /* translate 10kHz to kHz */ - static_clk_info->max_mclk_khz = pp_clk_info.max_memory_clock * 10; - static_clk_info->max_sclk_khz = pp_clk_info.max_engine_clock * 10; + static_clk_info->max_mclk_khz = pp_clk_info.max_memory_clock; + static_clk_info->max_sclk_khz = pp_clk_info.max_engine_clock; return true; } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c index 0bbf11d464dda..07cc98c69c7da 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c @@ -993,7 +993,7 @@ static int smu10_get_clock_by_type_with_latency(struct pp_hwmgr *hwmgr, clocks->num_levels = 0; for (i = 0; i < pclk_vol_table->count; i++) { - clocks->data[i].clocks_in_khz = pclk_vol_table->entries[i].clk; + clocks->data[i].clocks_in_khz = pclk_vol_table->entries[i].clk * 10; clocks->data[i].latency_in_us = latency_required ? smu10_get_mem_latency(hwmgr, pclk_vol_table->entries[i].clk) : @@ -1044,7 +1044,7 @@ static int smu10_get_clock_by_type_with_voltage(struct pp_hwmgr *hwmgr, clocks->num_levels = 0; for (i = 0; i < pclk_vol_table->count; i++) { - clocks->data[i].clocks_in_khz = pclk_vol_table->entries[i].clk; + clocks->data[i].clocks_in_khz = pclk_vol_table->entries[i].clk * 10; clocks->data[i].voltage_in_mv = pclk_vol_table->entries[i].vol; clocks->num_levels++; } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c index 3b8d36df52e99..37c2e5c15d621 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c @@ -4064,10 +4064,11 @@ static void vega10_get_sclks(struct pp_hwmgr *hwmgr, table_info->vdd_dep_on_sclk; uint32_t i; + clocks->num_levels = 0; for (i = 0; i < dep_table->count; i++) { if (dep_table->entries[i].clk) { clocks->data[clocks->num_levels].clocks_in_khz = - dep_table->entries[i].clk; + dep_table->entries[i].clk * 10; clocks->num_levels++; } } @@ -4094,26 +4095,23 @@ static void vega10_get_memclocks(struct pp_hwmgr *hwmgr, struct phm_ppt_v1_clock_voltage_dependency_table *dep_table = table_info->vdd_dep_on_mclk; struct vega10_hwmgr *data = hwmgr->backend; + uint32_t j = 0; uint32_t i; - clocks->num_levels = 0; - data->mclk_latency_table.count = 0; - for (i = 0; i < dep_table->count; i++) { if (dep_table->entries[i].clk) { - clocks->data[clocks->num_levels].clocks_in_khz = - data->mclk_latency_table.entries - [data->mclk_latency_table.count].frequency = - dep_table->entries[i].clk; - clocks->data[clocks->num_levels].latency_in_us = - data->mclk_latency_table.entries - [data->mclk_latency_table.count].latency = - vega10_get_mem_latency(hwmgr, - dep_table->entries[i].clk); - clocks->num_levels++; - data->mclk_latency_table.count++; + clocks->data[j].clocks_in_khz = + dep_table->entries[i].clk * 10; + data->mclk_latency_table.entries[j].frequency = + dep_table->entries[i].clk; + clocks->data[j].latency_in_us = + data->mclk_latency_table.entries[j].latency = + vega10_get_mem_latency(hwmgr, + dep_table->entries[i].clk); + j++; } } + clocks->num_levels = data->mclk_latency_table.count = j; } static void vega10_get_dcefclocks(struct pp_hwmgr *hwmgr, @@ -4126,7 +4124,7 @@ static void vega10_get_dcefclocks(struct pp_hwmgr *hwmgr, uint32_t i; for (i = 0; i < dep_table->count; i++) { - clocks->data[i].clocks_in_khz = dep_table->entries[i].clk; + clocks->data[i].clocks_in_khz = dep_table->entries[i].clk * 10; clocks->data[i].latency_in_us = 0; clocks->num_levels++; } @@ -4142,7 +4140,7 @@ static void vega10_get_socclocks(struct pp_hwmgr *hwmgr, uint32_t i; for (i = 0; i < dep_table->count; i++) { - clocks->data[i].clocks_in_khz = dep_table->entries[i].clk; + clocks->data[i].clocks_in_khz = dep_table->entries[i].clk * 10; clocks->data[i].latency_in_us = 0; clocks->num_levels++; } @@ -4202,7 +4200,7 @@ static int vega10_get_clock_by_type_with_voltage(struct pp_hwmgr *hwmgr, } for (i = 0; i < dep_table->count; i++) { - clocks->data[i].clocks_in_khz = dep_table->entries[i].clk; + clocks->data[i].clocks_in_khz = dep_table->entries[i].clk * 10; clocks->data[i].voltage_in_mv = (uint32_t)(table_info->vddc_lookup_table-> entries[dep_table->entries[i].vddInd].us_vdd); clocks->num_levels++; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c index a86777954ea76..4cf257043a2c7 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c @@ -1645,7 +1645,7 @@ static int vega12_get_sclks(struct pp_hwmgr *hwmgr, for (i = 0; i < ucount; i++) { clocks->data[i].clocks_in_khz = - dpm_table->dpm_levels[i].value * 100; + dpm_table->dpm_levels[i].value * 1000; clocks->data[i].latency_in_us = 0; } @@ -1676,10 +1676,8 @@ static int vega12_get_memclocks(struct pp_hwmgr *hwmgr, MAX_NUM_CLOCKS : dpm_table->count; for (i = 0; i < ucount; i++) { - clocks->data[i].clocks_in_khz = - data->mclk_latency_table.entries[i].frequency = - dpm_table->dpm_levels[i].value * 100; - + clocks->data[i].clocks_in_khz = dpm_table->dpm_levels[i].value * 1000; + data->mclk_latency_table.entries[i].frequency = dpm_table->dpm_levels[i].value * 100; clocks->data[i].latency_in_us = data->mclk_latency_table.entries[i].latency = vega12_get_mem_latency(hwmgr, dpm_table->dpm_levels[i].value); @@ -1708,7 +1706,7 @@ static int vega12_get_dcefclocks(struct pp_hwmgr *hwmgr, for (i = 0; i < ucount; i++) { clocks->data[i].clocks_in_khz = - dpm_table->dpm_levels[i].value * 100; + dpm_table->dpm_levels[i].value * 1000; clocks->data[i].latency_in_us = 0; } @@ -1736,7 +1734,7 @@ static int vega12_get_socclocks(struct pp_hwmgr *hwmgr, for (i = 0; i < ucount; i++) { clocks->data[i].clocks_in_khz = - dpm_table->dpm_levels[i].value * 100; + dpm_table->dpm_levels[i].value * 1000; clocks->data[i].latency_in_us = 0; } @@ -1918,8 +1916,8 @@ static int vega12_print_clock_levels(struct pp_hwmgr *hwmgr, return -1); for (i = 0; i < clocks.num_levels; i++) size += sprintf(buf + size, "%d: %uMhz %s\n", - i, clocks.data[i].clocks_in_khz / 100, - (clocks.data[i].clocks_in_khz == now) ? "*" : ""); + i, clocks.data[i].clocks_in_khz / 1000, + (clocks.data[i].clocks_in_khz / 1000 == now) ? "*" : ""); break; case PP_MCLK: @@ -1934,8 +1932,8 @@ static int vega12_print_clock_levels(struct pp_hwmgr *hwmgr, return -1); for (i = 0; i < clocks.num_levels; i++) size += sprintf(buf + size, "%d: %uMhz %s\n", - i, clocks.data[i].clocks_in_khz / 100, - (clocks.data[i].clocks_in_khz == now) ? "*" : ""); + i, clocks.data[i].clocks_in_khz / 1000, + (clocks.data[i].clocks_in_khz / 1000 == now) ? "*" : ""); break; case PP_PCIE: -- GitLab From 6eb9d6030479c5e079a1374941b77ac205b10912 Mon Sep 17 00:00:00 2001 From: Rex Zhu <Rex.Zhu@amd.com> Date: Mon, 18 Jun 2018 18:49:07 +0800 Subject: [PATCH 0804/1506] drm/amd/pp: Memory Latency is always 25us on Vega10 For HBM, 25us latency is enough for memory clock switch. Acked-by: Alex Deucher <alexander.deucher@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../drm/amd/powerplay/hwmgr/vega10_hwmgr.c | 23 ++----------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c index 37c2e5c15d621..7fdd9ede96c79 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c @@ -55,12 +55,6 @@ static const uint32_t channel_number[] = {1, 2, 0, 4, 0, 8, 0, 16, 2}; -#define MEM_FREQ_LOW_LATENCY 25000 -#define MEM_FREQ_HIGH_LATENCY 80000 -#define MEM_LATENCY_HIGH 245 -#define MEM_LATENCY_LOW 35 -#define MEM_LATENCY_ERR 0xFFFF - #define mmDF_CS_AON0_DramBaseAddress0 0x0044 #define mmDF_CS_AON0_DramBaseAddress0_BASE_IDX 0 @@ -4075,18 +4069,6 @@ static void vega10_get_sclks(struct pp_hwmgr *hwmgr, } -static uint32_t vega10_get_mem_latency(struct pp_hwmgr *hwmgr, - uint32_t clock) -{ - if (clock >= MEM_FREQ_LOW_LATENCY && - clock < MEM_FREQ_HIGH_LATENCY) - return MEM_LATENCY_HIGH; - else if (clock >= MEM_FREQ_HIGH_LATENCY) - return MEM_LATENCY_LOW; - else - return MEM_LATENCY_ERR; -} - static void vega10_get_memclocks(struct pp_hwmgr *hwmgr, struct pp_clock_levels_with_latency *clocks) { @@ -4100,14 +4082,13 @@ static void vega10_get_memclocks(struct pp_hwmgr *hwmgr, for (i = 0; i < dep_table->count; i++) { if (dep_table->entries[i].clk) { + clocks->data[j].clocks_in_khz = dep_table->entries[i].clk * 10; data->mclk_latency_table.entries[j].frequency = dep_table->entries[i].clk; clocks->data[j].latency_in_us = - data->mclk_latency_table.entries[j].latency = - vega10_get_mem_latency(hwmgr, - dep_table->entries[i].clk); + data->mclk_latency_table.entries[j].latency = 25; j++; } } -- GitLab From 7d8d968dac88a98bd1d4503a020e8b114672611e Mon Sep 17 00:00:00 2001 From: rex zhu <rex.zhu@amd.com> Date: Thu, 28 Jun 2018 13:55:46 +0800 Subject: [PATCH 0805/1506] drm/amd/pp: Switch the tolerable latency for display Select the lowest MCLK frequency that is within the tolerable latency defined in DISPALY Acked-by: Alex Deucher <alexander.deucher@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c index 7fdd9ede96c79..e5b3abffefb63 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c @@ -3217,7 +3217,7 @@ static int vega10_apply_state_adjust_rules(struct pp_hwmgr *hwmgr, /* Find the lowest MCLK frequency that is within * the tolerable latency defined in DAL */ - latency = 0; + latency = hwmgr->display_config->dce_tolerable_mclk_in_active_latency; for (i = 0; i < data->mclk_latency_table.count; i++) { if ((data->mclk_latency_table.entries[i].latency <= latency) && (data->mclk_latency_table.entries[i].frequency >= -- GitLab From 3180fb676d7fd38a7c1effa2e5d9265779473c23 Mon Sep 17 00:00:00 2001 From: rex zhu <rex.zhu@amd.com> Date: Mon, 2 Jul 2018 14:55:43 +0800 Subject: [PATCH 0806/1506] drm/amd/display: Notify powerplay the min_dcef clock powerplay can notify smu to recalculates the maximum deep-sleep divider display allowed. Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c index 596d49d7f9193..2e801bab5a78d 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c @@ -71,6 +71,11 @@ bool dm_pp_apply_display_requirements( adev->pm.pm_display_cfg.min_mem_set_clock = pp_display_cfg->min_memory_clock_khz/10; + adev->pm.pm_display_cfg.min_dcef_deep_sleep_set_clk = + pp_display_cfg->min_engine_clock_deep_sleep_khz/10; + adev->pm.pm_display_cfg.min_dcef_set_clk = + pp_display_cfg->min_dcfclock_khz/10; + adev->pm.pm_display_cfg.multi_monitor_in_sync = pp_display_cfg->all_displays_in_sync; adev->pm.pm_display_cfg.min_vblank_time = -- GitLab From d4d5eace210d3676202153c19e473aeb51a81909 Mon Sep 17 00:00:00 2001 From: rex zhu <rex.zhu@amd.com> Date: Mon, 2 Jul 2018 16:20:56 +0800 Subject: [PATCH 0807/1506] drm/amd/display: Notify powerplay the display controller id powerplay can recalculate the number of active display Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c index 2e801bab5a78d..81845116cdcc7 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c @@ -41,6 +41,7 @@ bool dm_pp_apply_display_requirements( const struct dm_pp_display_configuration *pp_display_cfg) { struct amdgpu_device *adev = ctx->driver_context; + int i; if (adev->pm.dpm_enabled) { @@ -95,6 +96,12 @@ bool dm_pp_apply_display_requirements( adev->pm.pm_display_cfg.crossfire_display_index = -1; adev->pm.pm_display_cfg.min_bus_bandwidth = 0; + for (i = 0; i < pp_display_cfg->display_count; i++) { + const struct dm_pp_single_disp_config *dc_cfg = + &pp_display_cfg->disp_configs[i]; + adev->pm.pm_display_cfg.displays[i].controller_id = dc_cfg->pipe_idx + 1; + } + /* TODO: complete implementation of * pp_display_configuration_change(). * Follow example of: -- GitLab From 99c5e27d3368eb92476f47530355a6f25bf486e8 Mon Sep 17 00:00:00 2001 From: Rex Zhu <Rex.Zhu@amd.com> Date: Fri, 22 Jun 2018 18:26:52 +0800 Subject: [PATCH 0808/1506] drm/amd/pp: Refine the interface exported to display use void * as function parameter type in order for extension. Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/include/kgd_pp_interface.h | 3 +-- drivers/gpu/drm/amd/powerplay/amd_powerplay.c | 6 +++--- drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c | 4 ++-- drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c | 3 ++- drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c | 3 ++- drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c | 3 ++- drivers/gpu/drm/amd/powerplay/inc/hardwaremanager.h | 2 +- drivers/gpu/drm/amd/powerplay/inc/hwmgr.h | 3 +-- 8 files changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h index 4535756428f98..99ee3edd1609a 100644 --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h @@ -192,7 +192,6 @@ struct amd_pp_simple_clock_info; struct amd_pp_display_configuration; struct amd_pp_clock_info; struct pp_display_clock_request; -struct pp_wm_sets_with_clock_ranges_soc15; struct pp_clock_levels_with_voltage; struct pp_clock_levels_with_latency; struct amd_pp_clocks; @@ -261,7 +260,7 @@ struct amd_pm_funcs { enum amd_pp_clock_type type, struct pp_clock_levels_with_voltage *clocks); int (*set_watermarks_for_clocks_ranges)(void *handle, - struct pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges); + void *clock_ranges); int (*display_clock_voltage_request)(void *handle, struct pp_display_clock_request *clock); int (*get_display_mode_validation_clocks)(void *handle, diff --git a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c index 387a1eb6678dc..b72cc644d4e7c 100644 --- a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c +++ b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c @@ -1096,17 +1096,17 @@ static int pp_get_clock_by_type_with_voltage(void *handle, } static int pp_set_watermarks_for_clocks_ranges(void *handle, - struct pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges) + void *clock_ranges) { struct pp_hwmgr *hwmgr = handle; int ret = 0; - if (!hwmgr || !hwmgr->pm_en ||!wm_with_clock_ranges) + if (!hwmgr || !hwmgr->pm_en || !clock_ranges) return -EINVAL; mutex_lock(&hwmgr->smu_lock); ret = phm_set_watermarks_for_clocks_ranges(hwmgr, - wm_with_clock_ranges); + clock_ranges); mutex_unlock(&hwmgr->smu_lock); return ret; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c index a0bb921fac228..53207e76b0f34 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c @@ -435,7 +435,7 @@ int phm_get_clock_by_type_with_voltage(struct pp_hwmgr *hwmgr, } int phm_set_watermarks_for_clocks_ranges(struct pp_hwmgr *hwmgr, - struct pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges) + void *clock_ranges) { PHM_FUNC_CHECK(hwmgr); @@ -443,7 +443,7 @@ int phm_set_watermarks_for_clocks_ranges(struct pp_hwmgr *hwmgr, return -EINVAL; return hwmgr->hwmgr_func->set_watermarks_for_clocks_ranges(hwmgr, - wm_with_clock_ranges); + clock_ranges); } int phm_display_clock_voltage_request(struct pp_hwmgr *hwmgr, diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c index 07cc98c69c7da..02fc0bc41e0a6 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c @@ -1108,9 +1108,10 @@ static int smu10_read_sensor(struct pp_hwmgr *hwmgr, int idx, } static int smu10_set_watermarks_for_clocks_ranges(struct pp_hwmgr *hwmgr, - struct pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges) + void *clock_ranges) { struct smu10_hwmgr *data = hwmgr->backend; + struct pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges = clock_ranges; Watermarks_t *table = &(data->water_marks_table); int result = 0; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c index e5b3abffefb63..d515eb4fac9fa 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c @@ -4194,9 +4194,10 @@ static int vega10_get_clock_by_type_with_voltage(struct pp_hwmgr *hwmgr, } static int vega10_set_watermarks_for_clocks_ranges(struct pp_hwmgr *hwmgr, - struct pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges) + void *clock_range) { struct vega10_hwmgr *data = hwmgr->backend; + struct pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges = clock_range; Watermarks_t *table = &(data->smc_state_table.water_marks_table); int result = 0; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c index 4cf257043a2c7..448014b173d51 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c @@ -1781,10 +1781,11 @@ static int vega12_get_clock_by_type_with_voltage(struct pp_hwmgr *hwmgr, } static int vega12_set_watermarks_for_clocks_ranges(struct pp_hwmgr *hwmgr, - struct pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges) + void *clock_ranges) { struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend); Watermarks_t *table = &(data->smc_state_table.water_marks_table); + struct pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges = clock_ranges; uint32_t i; if (!data->registry_data.disable_water_mark && diff --git a/drivers/gpu/drm/amd/powerplay/inc/hardwaremanager.h b/drivers/gpu/drm/amd/powerplay/inc/hardwaremanager.h index a202247c98944..429c9c4322daa 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/hardwaremanager.h +++ b/drivers/gpu/drm/amd/powerplay/inc/hardwaremanager.h @@ -455,7 +455,7 @@ extern int phm_get_clock_by_type_with_voltage(struct pp_hwmgr *hwmgr, enum amd_pp_clock_type type, struct pp_clock_levels_with_voltage *clocks); extern int phm_set_watermarks_for_clocks_ranges(struct pp_hwmgr *hwmgr, - struct pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges); + void *clock_ranges); extern int phm_display_clock_voltage_request(struct pp_hwmgr *hwmgr, struct pp_display_clock_request *clock); diff --git a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h index 95e29a22e4451..b3363f26039a7 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h @@ -293,8 +293,7 @@ struct pp_hwmgr_func { int (*get_clock_by_type_with_voltage)(struct pp_hwmgr *hwmgr, enum amd_pp_clock_type type, struct pp_clock_levels_with_voltage *clocks); - int (*set_watermarks_for_clocks_ranges)(struct pp_hwmgr *hwmgr, - struct pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges); + int (*set_watermarks_for_clocks_ranges)(struct pp_hwmgr *hwmgr, void *clock_ranges); int (*display_clock_voltage_request)(struct pp_hwmgr *hwmgr, struct pp_display_clock_request *clock); int (*get_max_high_clocks)(struct pp_hwmgr *hwmgr, struct amd_pp_simple_clock_info *clocks); -- GitLab From 860c15e903327f9af269d2ee7011454624dfcb90 Mon Sep 17 00:00:00 2001 From: Rex Zhu <Rex.Zhu@amd.com> Date: Wed, 20 Jun 2018 13:36:58 +0800 Subject: [PATCH 0809/1506] drm/amd/pp: Remove duplicate code in vega12_hwmgr.c use smu_helper function smu_set_watermarks_for_clocks_ranges in vega12_set_watermarks_for_clocks_ranges. Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../drm/amd/powerplay/hwmgr/vega12_hwmgr.c | 43 +------------------ 1 file changed, 1 insertion(+), 42 deletions(-) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c index 448014b173d51..0a090755545d5 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c @@ -1786,52 +1786,11 @@ static int vega12_set_watermarks_for_clocks_ranges(struct pp_hwmgr *hwmgr, struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend); Watermarks_t *table = &(data->smc_state_table.water_marks_table); struct pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges = clock_ranges; - uint32_t i; if (!data->registry_data.disable_water_mark && data->smu_features[GNLD_DPM_DCEFCLK].supported && data->smu_features[GNLD_DPM_SOCCLK].supported) { - for (i = 0; i < wm_with_clock_ranges->num_wm_sets_dmif; i++) { - table->WatermarkRow[WM_DCEFCLK][i].MinClock = - cpu_to_le16((uint16_t) - (wm_with_clock_ranges->wm_sets_dmif[i].wm_min_dcefclk_in_khz) / - 100); - table->WatermarkRow[WM_DCEFCLK][i].MaxClock = - cpu_to_le16((uint16_t) - (wm_with_clock_ranges->wm_sets_dmif[i].wm_max_dcefclk_in_khz) / - 100); - table->WatermarkRow[WM_DCEFCLK][i].MinUclk = - cpu_to_le16((uint16_t) - (wm_with_clock_ranges->wm_sets_dmif[i].wm_min_memclk_in_khz) / - 100); - table->WatermarkRow[WM_DCEFCLK][i].MaxUclk = - cpu_to_le16((uint16_t) - (wm_with_clock_ranges->wm_sets_dmif[i].wm_max_memclk_in_khz) / - 100); - table->WatermarkRow[WM_DCEFCLK][i].WmSetting = (uint8_t) - wm_with_clock_ranges->wm_sets_dmif[i].wm_set_id; - } - - for (i = 0; i < wm_with_clock_ranges->num_wm_sets_mcif; i++) { - table->WatermarkRow[WM_SOCCLK][i].MinClock = - cpu_to_le16((uint16_t) - (wm_with_clock_ranges->wm_sets_mcif[i].wm_min_socclk_in_khz) / - 100); - table->WatermarkRow[WM_SOCCLK][i].MaxClock = - cpu_to_le16((uint16_t) - (wm_with_clock_ranges->wm_sets_mcif[i].wm_max_socclk_in_khz) / - 100); - table->WatermarkRow[WM_SOCCLK][i].MinUclk = - cpu_to_le16((uint16_t) - (wm_with_clock_ranges->wm_sets_mcif[i].wm_min_memclk_in_khz) / - 100); - table->WatermarkRow[WM_SOCCLK][i].MaxUclk = - cpu_to_le16((uint16_t) - (wm_with_clock_ranges->wm_sets_mcif[i].wm_max_memclk_in_khz) / - 100); - table->WatermarkRow[WM_SOCCLK][i].WmSetting = (uint8_t) - wm_with_clock_ranges->wm_sets_mcif[i].wm_set_id; - } + smu_set_watermarks_for_clocks_ranges(table, wm_with_clock_ranges); data->water_marks_bitmap |= WaterMarksExist; data->water_marks_bitmap &= ~WaterMarksLoaded; } -- GitLab From 9fc15f5fc836712b173f04e143b8d77fdded1a37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolai=20H=C3=A4hnle?= <nicolai.haehnle@amd.com> Date: Fri, 29 Jun 2018 13:23:25 +0200 Subject: [PATCH 0810/1506] drm/amdgpu: fix user fence write race condition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The buffer object backing the user fence is reserved using the non-user fence, i.e., as soon as the non-user fence is signaled, the user fence buffer object can be moved or even destroyed. Therefore, emit the user fence first. Both fences have the same cache invalidation behavior, so this should have no user-visible effect. Signed-off-by: Nicolai Hähnle <nicolai.haehnle@amd.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c index 31f8170313b44..ce7739832d292 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c @@ -231,6 +231,12 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs, if (ib->flags & AMDGPU_IB_FLAG_TC_WB_NOT_INVALIDATE) fence_flags |= AMDGPU_FENCE_FLAG_TC_WB_ONLY; + /* wrap the last IB with fence */ + if (job && job->uf_addr) { + amdgpu_ring_emit_fence(ring, job->uf_addr, job->uf_sequence, + fence_flags | AMDGPU_FENCE_FLAG_64BIT); + } + r = amdgpu_fence_emit(ring, f, fence_flags); if (r) { dev_err(adev->dev, "failed to emit fence (%d)\n", r); @@ -243,12 +249,6 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs, if (ring->funcs->insert_end) ring->funcs->insert_end(ring); - /* wrap the last IB with fence */ - if (job && job->uf_addr) { - amdgpu_ring_emit_fence(ring, job->uf_addr, job->uf_sequence, - fence_flags | AMDGPU_FENCE_FLAG_64BIT); - } - if (patch_offset != ~0 && ring->funcs->patch_cond_exec) amdgpu_ring_patch_cond_exec(ring, patch_offset); -- GitLab From ce206464e3c7a0936468f0190599d2e6070850f4 Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexander.deucher@amd.com> Date: Mon, 2 Jul 2018 14:32:28 -0500 Subject: [PATCH 0811/1506] drm/amdgpu: switch firmware path for CIK parts (v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use separate firmware path for amdgpu to avoid conflicts with radeon on CIK parts. v2: squash in logic simplification (Alex) Reviewed-by: Chunming Zhou <david1.zhou@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c | 8 +-- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 10 ++-- drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c | 10 ++-- drivers/gpu/drm/amd/amdgpu/ci_dpm.c | 10 ++-- drivers/gpu/drm/amd/amdgpu/cik_sdma.c | 24 ++++----- drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c | 72 ++++++++++++------------- drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c | 9 ++-- 7 files changed, 70 insertions(+), 73 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c index e950730f1933b..693ec5ea4950a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c @@ -314,17 +314,17 @@ static int amdgpu_cgs_get_firmware_info(struct cgs_device *cgs_device, (adev->pdev->revision == 0x81) || (adev->pdev->device == 0x665f)) { info->is_kicker = true; - strcpy(fw_name, "radeon/bonaire_k_smc.bin"); + strcpy(fw_name, "amdgpu/bonaire_k_smc.bin"); } else { - strcpy(fw_name, "radeon/bonaire_smc.bin"); + strcpy(fw_name, "amdgpu/bonaire_smc.bin"); } break; case CHIP_HAWAII: if (adev->pdev->revision == 0x80) { info->is_kicker = true; - strcpy(fw_name, "radeon/hawaii_k_smc.bin"); + strcpy(fw_name, "amdgpu/hawaii_k_smc.bin"); } else { - strcpy(fw_name, "radeon/hawaii_smc.bin"); + strcpy(fw_name, "amdgpu/hawaii_smc.bin"); } break; case CHIP_TOPAZ: diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c index 0b46ea1c62907..3e70eb61a9609 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c @@ -53,11 +53,11 @@ /* Firmware Names */ #ifdef CONFIG_DRM_AMDGPU_CIK -#define FIRMWARE_BONAIRE "radeon/bonaire_uvd.bin" -#define FIRMWARE_KABINI "radeon/kabini_uvd.bin" -#define FIRMWARE_KAVERI "radeon/kaveri_uvd.bin" -#define FIRMWARE_HAWAII "radeon/hawaii_uvd.bin" -#define FIRMWARE_MULLINS "radeon/mullins_uvd.bin" +#define FIRMWARE_BONAIRE "amdgpu/bonaire_uvd.bin" +#define FIRMWARE_KABINI "amdgpu/kabini_uvd.bin" +#define FIRMWARE_KAVERI "amdgpu/kaveri_uvd.bin" +#define FIRMWARE_HAWAII "amdgpu/hawaii_uvd.bin" +#define FIRMWARE_MULLINS "amdgpu/mullins_uvd.bin" #endif #define FIRMWARE_TONGA "amdgpu/tonga_uvd.bin" #define FIRMWARE_CARRIZO "amdgpu/carrizo_uvd.bin" diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c index b0dcdfd85f5b8..6ae1ad7e83b3c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c @@ -40,11 +40,11 @@ /* Firmware Names */ #ifdef CONFIG_DRM_AMDGPU_CIK -#define FIRMWARE_BONAIRE "radeon/bonaire_vce.bin" -#define FIRMWARE_KABINI "radeon/kabini_vce.bin" -#define FIRMWARE_KAVERI "radeon/kaveri_vce.bin" -#define FIRMWARE_HAWAII "radeon/hawaii_vce.bin" -#define FIRMWARE_MULLINS "radeon/mullins_vce.bin" +#define FIRMWARE_BONAIRE "amdgpu/bonaire_vce.bin" +#define FIRMWARE_KABINI "amdgpu/kabini_vce.bin" +#define FIRMWARE_KAVERI "amdgpu/kaveri_vce.bin" +#define FIRMWARE_HAWAII "amdgpu/hawaii_vce.bin" +#define FIRMWARE_MULLINS "amdgpu/mullins_vce.bin" #endif #define FIRMWARE_TONGA "amdgpu/tonga_vce.bin" #define FIRMWARE_CARRIZO "amdgpu/carrizo_vce.bin" diff --git a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c index 7c4ff71e7476e..d79ad93b01c32 100644 --- a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c @@ -49,10 +49,10 @@ #include "gmc/gmc_7_1_d.h" #include "gmc/gmc_7_1_sh_mask.h" -MODULE_FIRMWARE("radeon/bonaire_smc.bin"); -MODULE_FIRMWARE("radeon/bonaire_k_smc.bin"); -MODULE_FIRMWARE("radeon/hawaii_smc.bin"); -MODULE_FIRMWARE("radeon/hawaii_k_smc.bin"); +MODULE_FIRMWARE("amdgpu/bonaire_smc.bin"); +MODULE_FIRMWARE("amdgpu/bonaire_k_smc.bin"); +MODULE_FIRMWARE("amdgpu/hawaii_smc.bin"); +MODULE_FIRMWARE("amdgpu/hawaii_k_smc.bin"); #define MC_CG_ARB_FREQ_F0 0x0a #define MC_CG_ARB_FREQ_F1 0x0b @@ -5815,7 +5815,7 @@ static int ci_dpm_init_microcode(struct amdgpu_device *adev) default: BUG(); } - snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_smc.bin", chip_name); err = request_firmware(&adev->pm.fw, fw_name, adev->dev); if (err) goto out; diff --git a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c index dbd553a8d5842..d0fa2aac23888 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c +++ b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c @@ -54,16 +54,16 @@ static void cik_sdma_set_buffer_funcs(struct amdgpu_device *adev); static void cik_sdma_set_vm_pte_funcs(struct amdgpu_device *adev); static int cik_sdma_soft_reset(void *handle); -MODULE_FIRMWARE("radeon/bonaire_sdma.bin"); -MODULE_FIRMWARE("radeon/bonaire_sdma1.bin"); -MODULE_FIRMWARE("radeon/hawaii_sdma.bin"); -MODULE_FIRMWARE("radeon/hawaii_sdma1.bin"); -MODULE_FIRMWARE("radeon/kaveri_sdma.bin"); -MODULE_FIRMWARE("radeon/kaveri_sdma1.bin"); -MODULE_FIRMWARE("radeon/kabini_sdma.bin"); -MODULE_FIRMWARE("radeon/kabini_sdma1.bin"); -MODULE_FIRMWARE("radeon/mullins_sdma.bin"); -MODULE_FIRMWARE("radeon/mullins_sdma1.bin"); +MODULE_FIRMWARE("amdgpu/bonaire_sdma.bin"); +MODULE_FIRMWARE("amdgpu/bonaire_sdma1.bin"); +MODULE_FIRMWARE("amdgpu/hawaii_sdma.bin"); +MODULE_FIRMWARE("amdgpu/hawaii_sdma1.bin"); +MODULE_FIRMWARE("amdgpu/kaveri_sdma.bin"); +MODULE_FIRMWARE("amdgpu/kaveri_sdma1.bin"); +MODULE_FIRMWARE("amdgpu/kabini_sdma.bin"); +MODULE_FIRMWARE("amdgpu/kabini_sdma1.bin"); +MODULE_FIRMWARE("amdgpu/mullins_sdma.bin"); +MODULE_FIRMWARE("amdgpu/mullins_sdma1.bin"); u32 amdgpu_cik_gpu_check_soft_reset(struct amdgpu_device *adev); @@ -132,9 +132,9 @@ static int cik_sdma_init_microcode(struct amdgpu_device *adev) for (i = 0; i < adev->sdma.num_instances; i++) { if (i == 0) - snprintf(fw_name, sizeof(fw_name), "radeon/%s_sdma.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sdma.bin", chip_name); else - snprintf(fw_name, sizeof(fw_name), "radeon/%s_sdma1.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sdma1.bin", chip_name); err = request_firmware(&adev->sdma.instance[i].fw, fw_name, adev->dev); if (err) goto out; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c index 42b6144c1fd59..95452c5a9df6e 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c @@ -57,36 +57,36 @@ static void gfx_v7_0_set_ring_funcs(struct amdgpu_device *adev); static void gfx_v7_0_set_irq_funcs(struct amdgpu_device *adev); static void gfx_v7_0_set_gds_init(struct amdgpu_device *adev); -MODULE_FIRMWARE("radeon/bonaire_pfp.bin"); -MODULE_FIRMWARE("radeon/bonaire_me.bin"); -MODULE_FIRMWARE("radeon/bonaire_ce.bin"); -MODULE_FIRMWARE("radeon/bonaire_rlc.bin"); -MODULE_FIRMWARE("radeon/bonaire_mec.bin"); - -MODULE_FIRMWARE("radeon/hawaii_pfp.bin"); -MODULE_FIRMWARE("radeon/hawaii_me.bin"); -MODULE_FIRMWARE("radeon/hawaii_ce.bin"); -MODULE_FIRMWARE("radeon/hawaii_rlc.bin"); -MODULE_FIRMWARE("radeon/hawaii_mec.bin"); - -MODULE_FIRMWARE("radeon/kaveri_pfp.bin"); -MODULE_FIRMWARE("radeon/kaveri_me.bin"); -MODULE_FIRMWARE("radeon/kaveri_ce.bin"); -MODULE_FIRMWARE("radeon/kaveri_rlc.bin"); -MODULE_FIRMWARE("radeon/kaveri_mec.bin"); -MODULE_FIRMWARE("radeon/kaveri_mec2.bin"); - -MODULE_FIRMWARE("radeon/kabini_pfp.bin"); -MODULE_FIRMWARE("radeon/kabini_me.bin"); -MODULE_FIRMWARE("radeon/kabini_ce.bin"); -MODULE_FIRMWARE("radeon/kabini_rlc.bin"); -MODULE_FIRMWARE("radeon/kabini_mec.bin"); - -MODULE_FIRMWARE("radeon/mullins_pfp.bin"); -MODULE_FIRMWARE("radeon/mullins_me.bin"); -MODULE_FIRMWARE("radeon/mullins_ce.bin"); -MODULE_FIRMWARE("radeon/mullins_rlc.bin"); -MODULE_FIRMWARE("radeon/mullins_mec.bin"); +MODULE_FIRMWARE("amdgpu/bonaire_pfp.bin"); +MODULE_FIRMWARE("amdgpu/bonaire_me.bin"); +MODULE_FIRMWARE("amdgpu/bonaire_ce.bin"); +MODULE_FIRMWARE("amdgpu/bonaire_rlc.bin"); +MODULE_FIRMWARE("amdgpu/bonaire_mec.bin"); + +MODULE_FIRMWARE("amdgpu/hawaii_pfp.bin"); +MODULE_FIRMWARE("amdgpu/hawaii_me.bin"); +MODULE_FIRMWARE("amdgpu/hawaii_ce.bin"); +MODULE_FIRMWARE("amdgpu/hawaii_rlc.bin"); +MODULE_FIRMWARE("amdgpu/hawaii_mec.bin"); + +MODULE_FIRMWARE("amdgpu/kaveri_pfp.bin"); +MODULE_FIRMWARE("amdgpu/kaveri_me.bin"); +MODULE_FIRMWARE("amdgpu/kaveri_ce.bin"); +MODULE_FIRMWARE("amdgpu/kaveri_rlc.bin"); +MODULE_FIRMWARE("amdgpu/kaveri_mec.bin"); +MODULE_FIRMWARE("amdgpu/kaveri_mec2.bin"); + +MODULE_FIRMWARE("amdgpu/kabini_pfp.bin"); +MODULE_FIRMWARE("amdgpu/kabini_me.bin"); +MODULE_FIRMWARE("amdgpu/kabini_ce.bin"); +MODULE_FIRMWARE("amdgpu/kabini_rlc.bin"); +MODULE_FIRMWARE("amdgpu/kabini_mec.bin"); + +MODULE_FIRMWARE("amdgpu/mullins_pfp.bin"); +MODULE_FIRMWARE("amdgpu/mullins_me.bin"); +MODULE_FIRMWARE("amdgpu/mullins_ce.bin"); +MODULE_FIRMWARE("amdgpu/mullins_rlc.bin"); +MODULE_FIRMWARE("amdgpu/mullins_mec.bin"); static const struct amdgpu_gds_reg_offset amdgpu_gds_reg_offset[] = { @@ -925,7 +925,7 @@ static int gfx_v7_0_init_microcode(struct amdgpu_device *adev) default: BUG(); } - snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_pfp.bin", chip_name); err = request_firmware(&adev->gfx.pfp_fw, fw_name, adev->dev); if (err) goto out; @@ -933,7 +933,7 @@ static int gfx_v7_0_init_microcode(struct amdgpu_device *adev) if (err) goto out; - snprintf(fw_name, sizeof(fw_name), "radeon/%s_me.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_me.bin", chip_name); err = request_firmware(&adev->gfx.me_fw, fw_name, adev->dev); if (err) goto out; @@ -941,7 +941,7 @@ static int gfx_v7_0_init_microcode(struct amdgpu_device *adev) if (err) goto out; - snprintf(fw_name, sizeof(fw_name), "radeon/%s_ce.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ce.bin", chip_name); err = request_firmware(&adev->gfx.ce_fw, fw_name, adev->dev); if (err) goto out; @@ -949,7 +949,7 @@ static int gfx_v7_0_init_microcode(struct amdgpu_device *adev) if (err) goto out; - snprintf(fw_name, sizeof(fw_name), "radeon/%s_mec.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec.bin", chip_name); err = request_firmware(&adev->gfx.mec_fw, fw_name, adev->dev); if (err) goto out; @@ -958,7 +958,7 @@ static int gfx_v7_0_init_microcode(struct amdgpu_device *adev) goto out; if (adev->asic_type == CHIP_KAVERI) { - snprintf(fw_name, sizeof(fw_name), "radeon/%s_mec2.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec2.bin", chip_name); err = request_firmware(&adev->gfx.mec2_fw, fw_name, adev->dev); if (err) goto out; @@ -967,7 +967,7 @@ static int gfx_v7_0_init_microcode(struct amdgpu_device *adev) goto out; } - snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_rlc.bin", chip_name); err = request_firmware(&adev->gfx.rlc_fw, fw_name, adev->dev); if (err) goto out; diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c index 7147bfe25a234..78339309a00c6 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c @@ -47,8 +47,8 @@ static void gmc_v7_0_set_gmc_funcs(struct amdgpu_device *adev); static void gmc_v7_0_set_irq_funcs(struct amdgpu_device *adev); static int gmc_v7_0_wait_for_idle(void *handle); -MODULE_FIRMWARE("radeon/bonaire_mc.bin"); -MODULE_FIRMWARE("radeon/hawaii_mc.bin"); +MODULE_FIRMWARE("amdgpu/bonaire_mc.bin"); +MODULE_FIRMWARE("amdgpu/hawaii_mc.bin"); MODULE_FIRMWARE("amdgpu/topaz_mc.bin"); static const u32 golden_settings_iceland_a11[] = @@ -147,10 +147,7 @@ static int gmc_v7_0_init_microcode(struct amdgpu_device *adev) default: BUG(); } - if (adev->asic_type == CHIP_TOPAZ) - snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mc.bin", chip_name); - else - snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mc.bin", chip_name); err = request_firmware(&adev->gmc.fw, fw_name, adev->dev); if (err) -- GitLab From 8eaf2b1faaf4358c6337785f2192055c6ef41e0d Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexander.deucher@amd.com> Date: Mon, 2 Jul 2018 14:35:36 -0500 Subject: [PATCH 0812/1506] drm/amdgpu: switch firmware path for SI parts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use separate firmware path for amdgpu to avoid conflicts with radeon on SI parts. Reviewed-by: Chunming Zhou <david1.zhou@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c | 56 +++++++++++++-------------- drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c | 14 +++---- drivers/gpu/drm/amd/amdgpu/si_dpm.c | 22 +++++------ 3 files changed, 46 insertions(+), 46 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c index cd6bf291a853d..de184a8860573 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c @@ -44,30 +44,30 @@ static void gfx_v6_0_set_ring_funcs(struct amdgpu_device *adev); static void gfx_v6_0_set_irq_funcs(struct amdgpu_device *adev); static void gfx_v6_0_get_cu_info(struct amdgpu_device *adev); -MODULE_FIRMWARE("radeon/tahiti_pfp.bin"); -MODULE_FIRMWARE("radeon/tahiti_me.bin"); -MODULE_FIRMWARE("radeon/tahiti_ce.bin"); -MODULE_FIRMWARE("radeon/tahiti_rlc.bin"); - -MODULE_FIRMWARE("radeon/pitcairn_pfp.bin"); -MODULE_FIRMWARE("radeon/pitcairn_me.bin"); -MODULE_FIRMWARE("radeon/pitcairn_ce.bin"); -MODULE_FIRMWARE("radeon/pitcairn_rlc.bin"); - -MODULE_FIRMWARE("radeon/verde_pfp.bin"); -MODULE_FIRMWARE("radeon/verde_me.bin"); -MODULE_FIRMWARE("radeon/verde_ce.bin"); -MODULE_FIRMWARE("radeon/verde_rlc.bin"); - -MODULE_FIRMWARE("radeon/oland_pfp.bin"); -MODULE_FIRMWARE("radeon/oland_me.bin"); -MODULE_FIRMWARE("radeon/oland_ce.bin"); -MODULE_FIRMWARE("radeon/oland_rlc.bin"); - -MODULE_FIRMWARE("radeon/hainan_pfp.bin"); -MODULE_FIRMWARE("radeon/hainan_me.bin"); -MODULE_FIRMWARE("radeon/hainan_ce.bin"); -MODULE_FIRMWARE("radeon/hainan_rlc.bin"); +MODULE_FIRMWARE("amdgpu/tahiti_pfp.bin"); +MODULE_FIRMWARE("amdgpu/tahiti_me.bin"); +MODULE_FIRMWARE("amdgpu/tahiti_ce.bin"); +MODULE_FIRMWARE("amdgpu/tahiti_rlc.bin"); + +MODULE_FIRMWARE("amdgpu/pitcairn_pfp.bin"); +MODULE_FIRMWARE("amdgpu/pitcairn_me.bin"); +MODULE_FIRMWARE("amdgpu/pitcairn_ce.bin"); +MODULE_FIRMWARE("amdgpu/pitcairn_rlc.bin"); + +MODULE_FIRMWARE("amdgpu/verde_pfp.bin"); +MODULE_FIRMWARE("amdgpu/verde_me.bin"); +MODULE_FIRMWARE("amdgpu/verde_ce.bin"); +MODULE_FIRMWARE("amdgpu/verde_rlc.bin"); + +MODULE_FIRMWARE("amdgpu/oland_pfp.bin"); +MODULE_FIRMWARE("amdgpu/oland_me.bin"); +MODULE_FIRMWARE("amdgpu/oland_ce.bin"); +MODULE_FIRMWARE("amdgpu/oland_rlc.bin"); + +MODULE_FIRMWARE("amdgpu/hainan_pfp.bin"); +MODULE_FIRMWARE("amdgpu/hainan_me.bin"); +MODULE_FIRMWARE("amdgpu/hainan_ce.bin"); +MODULE_FIRMWARE("amdgpu/hainan_rlc.bin"); static u32 gfx_v6_0_get_csb_size(struct amdgpu_device *adev); static void gfx_v6_0_get_csb_buffer(struct amdgpu_device *adev, volatile u32 *buffer); @@ -335,7 +335,7 @@ static int gfx_v6_0_init_microcode(struct amdgpu_device *adev) default: BUG(); } - snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_pfp.bin", chip_name); err = request_firmware(&adev->gfx.pfp_fw, fw_name, adev->dev); if (err) goto out; @@ -346,7 +346,7 @@ static int gfx_v6_0_init_microcode(struct amdgpu_device *adev) adev->gfx.pfp_fw_version = le32_to_cpu(cp_hdr->header.ucode_version); adev->gfx.pfp_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version); - snprintf(fw_name, sizeof(fw_name), "radeon/%s_me.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_me.bin", chip_name); err = request_firmware(&adev->gfx.me_fw, fw_name, adev->dev); if (err) goto out; @@ -357,7 +357,7 @@ static int gfx_v6_0_init_microcode(struct amdgpu_device *adev) adev->gfx.me_fw_version = le32_to_cpu(cp_hdr->header.ucode_version); adev->gfx.me_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version); - snprintf(fw_name, sizeof(fw_name), "radeon/%s_ce.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ce.bin", chip_name); err = request_firmware(&adev->gfx.ce_fw, fw_name, adev->dev); if (err) goto out; @@ -368,7 +368,7 @@ static int gfx_v6_0_init_microcode(struct amdgpu_device *adev) adev->gfx.ce_fw_version = le32_to_cpu(cp_hdr->header.ucode_version); adev->gfx.ce_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version); - snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_rlc.bin", chip_name); err = request_firmware(&adev->gfx.rlc_fw, fw_name, adev->dev); if (err) goto out; diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c index 79f9ac29019bd..75317f283c696 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c @@ -41,11 +41,11 @@ static void gmc_v6_0_set_gmc_funcs(struct amdgpu_device *adev); static void gmc_v6_0_set_irq_funcs(struct amdgpu_device *adev); static int gmc_v6_0_wait_for_idle(void *handle); -MODULE_FIRMWARE("radeon/tahiti_mc.bin"); -MODULE_FIRMWARE("radeon/pitcairn_mc.bin"); -MODULE_FIRMWARE("radeon/verde_mc.bin"); -MODULE_FIRMWARE("radeon/oland_mc.bin"); -MODULE_FIRMWARE("radeon/si58_mc.bin"); +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/si58_mc.bin"); #define MC_SEQ_MISC0__MT__MASK 0xf0000000 #define MC_SEQ_MISC0__MT__GDDR1 0x10000000 @@ -134,9 +134,9 @@ static int gmc_v6_0_init_microcode(struct amdgpu_device *adev) is_58_fw = true; if (is_58_fw) - snprintf(fw_name, sizeof(fw_name), "radeon/si58_mc.bin"); + snprintf(fw_name, sizeof(fw_name), "amdgpu/si58_mc.bin"); else - snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mc.bin", chip_name); err = request_firmware(&adev->gmc.fw, fw_name, adev->dev); if (err) goto out; diff --git a/drivers/gpu/drm/amd/amdgpu/si_dpm.c b/drivers/gpu/drm/amd/amdgpu/si_dpm.c index d51318c695e66..3560b7dc17986 100644 --- a/drivers/gpu/drm/amd/amdgpu/si_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/si_dpm.c @@ -56,16 +56,16 @@ #define BIOS_SCRATCH_4 0x5cd -MODULE_FIRMWARE("radeon/tahiti_smc.bin"); -MODULE_FIRMWARE("radeon/pitcairn_smc.bin"); -MODULE_FIRMWARE("radeon/pitcairn_k_smc.bin"); -MODULE_FIRMWARE("radeon/verde_smc.bin"); -MODULE_FIRMWARE("radeon/verde_k_smc.bin"); -MODULE_FIRMWARE("radeon/oland_smc.bin"); -MODULE_FIRMWARE("radeon/oland_k_smc.bin"); -MODULE_FIRMWARE("radeon/hainan_smc.bin"); -MODULE_FIRMWARE("radeon/hainan_k_smc.bin"); -MODULE_FIRMWARE("radeon/banks_k_2_smc.bin"); +MODULE_FIRMWARE("amdgpu/tahiti_smc.bin"); +MODULE_FIRMWARE("amdgpu/pitcairn_smc.bin"); +MODULE_FIRMWARE("amdgpu/pitcairn_k_smc.bin"); +MODULE_FIRMWARE("amdgpu/verde_smc.bin"); +MODULE_FIRMWARE("amdgpu/verde_k_smc.bin"); +MODULE_FIRMWARE("amdgpu/oland_smc.bin"); +MODULE_FIRMWARE("amdgpu/oland_k_smc.bin"); +MODULE_FIRMWARE("amdgpu/hainan_smc.bin"); +MODULE_FIRMWARE("amdgpu/hainan_k_smc.bin"); +MODULE_FIRMWARE("amdgpu/banks_k_2_smc.bin"); static const struct amd_pm_funcs si_dpm_funcs; @@ -7667,7 +7667,7 @@ static int si_dpm_init_microcode(struct amdgpu_device *adev) default: BUG(); } - snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", chip_name); + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_smc.bin", chip_name); err = request_firmware(&adev->pm.fw, fw_name, adev->dev); if (err) goto out; -- GitLab From 576c7218a1546e0153480b208b125509cec71470 Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexander.deucher@amd.com> Date: Mon, 25 Jun 2018 13:17:41 -0500 Subject: [PATCH 0813/1506] PCI: Export pcie_get_speed_cap and pcie_get_width_cap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So drivers can use them. This can be used to replace duplicate code in the drm subsystem. Acked-by: Christian König <christian.koenig@amd.com> Acked-by: Bjorn Helgaas <bhelgaas@google.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/pci/pci.c | 2 ++ include/linux/pci.h | 3 +++ 2 files changed, 5 insertions(+) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 97acba712e4e7..22adaf35b136b 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -5222,6 +5222,7 @@ enum pci_bus_speed pcie_get_speed_cap(struct pci_dev *dev) return PCI_SPEED_UNKNOWN; } +EXPORT_SYMBOL(pcie_get_speed_cap); /** * pcie_get_width_cap - query for the PCI device's link width capability @@ -5240,6 +5241,7 @@ enum pcie_link_width pcie_get_width_cap(struct pci_dev *dev) return PCIE_LNK_WIDTH_UNKNOWN; } +EXPORT_SYMBOL(pcie_get_width_cap); /** * pcie_bandwidth_capable - calculate a PCI device's link bandwidth capability diff --git a/include/linux/pci.h b/include/linux/pci.h index 340029b2fb382..6e0c0803b2413 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -261,6 +261,9 @@ enum pci_bus_speed { PCI_SPEED_UNKNOWN = 0xff, }; +enum pci_bus_speed pcie_get_speed_cap(struct pci_dev *dev); +enum pcie_link_width pcie_get_width_cap(struct pci_dev *dev); + struct pci_cap_saved_data { u16 cap_nr; bool cap_extended; -- GitLab From 4976f1c8ccff0d682176851692976e3bf03267d6 Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexander.deucher@amd.com> Date: Mon, 25 Jun 2018 13:03:51 -0500 Subject: [PATCH 0814/1506] drm/amdgpu: update amd_pcie.h to include gen4 speeds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Internal header used by the driver to specify pcie gen speeds of the asic and chipset. Acked-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/include/amd_pcie.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/include/amd_pcie.h b/drivers/gpu/drm/amd/include/amd_pcie.h index 5eb895fd98bfb..9cb9ceb4d74dc 100644 --- a/drivers/gpu/drm/amd/include/amd_pcie.h +++ b/drivers/gpu/drm/amd/include/amd_pcie.h @@ -27,6 +27,7 @@ #define CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1 0x00010000 #define CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2 0x00020000 #define CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3 0x00040000 +#define CAIL_PCIE_LINK_SPEED_SUPPORT_GEN4 0x00080000 #define CAIL_PCIE_LINK_SPEED_SUPPORT_MASK 0xFFFF0000 #define CAIL_PCIE_LINK_SPEED_SUPPORT_SHIFT 16 @@ -34,6 +35,7 @@ #define CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN1 0x00000001 #define CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN2 0x00000002 #define CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN3 0x00000004 +#define CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN4 0x00000008 #define CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_MASK 0x0000FFFF #define CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_SHIFT 0 -- GitLab From 5d9a6330403271fbb1244f14380a7cc44662796f Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexander.deucher@amd.com> Date: Mon, 25 Jun 2018 13:07:50 -0500 Subject: [PATCH 0815/1506] drm/amdgpu: use pcie functions for link width and speed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the newly exported pci functions to get the link width and speed rather than using the drm duplicated versions. Also query the GPU link caps directly rather than hardcoding them. Acked-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 83 +++++++++++++++------- drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.c | 7 +- drivers/gpu/drm/amd/amdgpu/ci_dpm.c | 3 +- drivers/gpu/drm/amd/amdgpu/si_dpm.c | 3 +- 4 files changed, 65 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index c35db859f050d..d43abbd2a3cc2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -3311,8 +3311,9 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, */ static void amdgpu_device_get_pcie_info(struct amdgpu_device *adev) { - u32 mask; - int ret; + struct pci_dev *pdev; + enum pci_bus_speed speed_cap; + enum pcie_link_width link_width; if (amdgpu_pcie_gen_cap) adev->pm.pcie_gen_mask = amdgpu_pcie_gen_cap; @@ -3330,27 +3331,61 @@ static void amdgpu_device_get_pcie_info(struct amdgpu_device *adev) } if (adev->pm.pcie_gen_mask == 0) { - ret = drm_pcie_get_speed_cap_mask(adev->ddev, &mask); - if (!ret) { - adev->pm.pcie_gen_mask = (CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN1 | + /* asic caps */ + pdev = adev->pdev; + speed_cap = pcie_get_speed_cap(pdev); + if (speed_cap == PCI_SPEED_UNKNOWN) { + adev->pm.pcie_gen_mask |= (CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN1 | CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN2 | CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN3); - - if (mask & DRM_PCIE_SPEED_25) - adev->pm.pcie_gen_mask |= CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1; - if (mask & DRM_PCIE_SPEED_50) - adev->pm.pcie_gen_mask |= CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2; - if (mask & DRM_PCIE_SPEED_80) - adev->pm.pcie_gen_mask |= CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3; } else { - adev->pm.pcie_gen_mask = AMDGPU_DEFAULT_PCIE_GEN_MASK; + if (speed_cap == PCIE_SPEED_16_0GT) + adev->pm.pcie_gen_mask |= (CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN1 | + CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN2 | + CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN3 | + CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN4); + else if (speed_cap == PCIE_SPEED_8_0GT) + adev->pm.pcie_gen_mask |= (CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN1 | + CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN2 | + CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN3); + else if (speed_cap == PCIE_SPEED_5_0GT) + adev->pm.pcie_gen_mask |= (CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN1 | + CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN2); + else + adev->pm.pcie_gen_mask |= CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN1; + } + /* platform caps */ + pdev = adev->ddev->pdev->bus->self; + speed_cap = pcie_get_speed_cap(pdev); + if (speed_cap == PCI_SPEED_UNKNOWN) { + adev->pm.pcie_gen_mask |= (CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1 | + CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2); + } else { + if (speed_cap == PCIE_SPEED_16_0GT) + adev->pm.pcie_gen_mask |= (CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1 | + CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2 | + CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3 | + CAIL_PCIE_LINK_SPEED_SUPPORT_GEN4); + else if (speed_cap == PCIE_SPEED_8_0GT) + adev->pm.pcie_gen_mask |= (CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1 | + CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2 | + CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3); + else if (speed_cap == PCIE_SPEED_5_0GT) + adev->pm.pcie_gen_mask |= (CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1 | + CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2); + else + adev->pm.pcie_gen_mask |= CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1; + } } if (adev->pm.pcie_mlw_mask == 0) { - ret = drm_pcie_get_max_link_width(adev->ddev, &mask); - if (!ret) { - switch (mask) { - case 32: + pdev = adev->ddev->pdev->bus->self; + link_width = pcie_get_width_cap(pdev); + if (link_width == PCIE_LNK_WIDTH_UNKNOWN) { + adev->pm.pcie_mlw_mask |= AMDGPU_DEFAULT_PCIE_MLW_MASK; + } else { + switch (link_width) { + case PCIE_LNK_X32: adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X32 | CAIL_PCIE_LINK_WIDTH_SUPPORT_X16 | CAIL_PCIE_LINK_WIDTH_SUPPORT_X12 | @@ -3359,7 +3394,7 @@ static void amdgpu_device_get_pcie_info(struct amdgpu_device *adev) CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 | CAIL_PCIE_LINK_WIDTH_SUPPORT_X1); break; - case 16: + case PCIE_LNK_X16: adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X16 | CAIL_PCIE_LINK_WIDTH_SUPPORT_X12 | CAIL_PCIE_LINK_WIDTH_SUPPORT_X8 | @@ -3367,36 +3402,34 @@ static void amdgpu_device_get_pcie_info(struct amdgpu_device *adev) CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 | CAIL_PCIE_LINK_WIDTH_SUPPORT_X1); break; - case 12: + case PCIE_LNK_X12: adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X12 | CAIL_PCIE_LINK_WIDTH_SUPPORT_X8 | CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 | CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 | CAIL_PCIE_LINK_WIDTH_SUPPORT_X1); break; - case 8: + case PCIE_LNK_X8: adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X8 | CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 | CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 | CAIL_PCIE_LINK_WIDTH_SUPPORT_X1); break; - case 4: + case PCIE_LNK_X4: adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 | CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 | CAIL_PCIE_LINK_WIDTH_SUPPORT_X1); break; - case 2: + case PCIE_LNK_X2: adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 | CAIL_PCIE_LINK_WIDTH_SUPPORT_X1); break; - case 1: + case PCIE_LNK_X1: adev->pm.pcie_mlw_mask = CAIL_PCIE_LINK_WIDTH_SUPPORT_X1; break; default: break; } - } else { - adev->pm.pcie_mlw_mask = AMDGPU_DEFAULT_PCIE_MLW_MASK; } } } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.c index 77ad59ade85ca..1c4595562f8fd 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.c @@ -28,6 +28,7 @@ #include "amdgpu_i2c.h" #include "amdgpu_dpm.h" #include "atom.h" +#include "amd_pcie.h" void amdgpu_dpm_print_class_info(u32 class, u32 class2) { @@ -936,9 +937,11 @@ enum amdgpu_pcie_gen amdgpu_get_pcie_gen_support(struct amdgpu_device *adev, case AMDGPU_PCIE_GEN3: return AMDGPU_PCIE_GEN3; default: - if ((sys_mask & DRM_PCIE_SPEED_80) && (default_gen == AMDGPU_PCIE_GEN3)) + if ((sys_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3) && + (default_gen == AMDGPU_PCIE_GEN3)) return AMDGPU_PCIE_GEN3; - else if ((sys_mask & DRM_PCIE_SPEED_50) && (default_gen == AMDGPU_PCIE_GEN2)) + else if ((sys_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2) && + (default_gen == AMDGPU_PCIE_GEN2)) return AMDGPU_PCIE_GEN2; else return AMDGPU_PCIE_GEN1; diff --git a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c index d79ad93b01c32..d2469453dca26 100644 --- a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c @@ -5846,8 +5846,7 @@ static int ci_dpm_init(struct amdgpu_device *adev) adev->pm.dpm.priv = pi; pi->sys_pcie_mask = - (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_MASK) >> - CAIL_PCIE_LINK_SPEED_SUPPORT_SHIFT; + adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_MASK; pi->force_pcie_gen = AMDGPU_PCIE_GEN_INVALID; diff --git a/drivers/gpu/drm/amd/amdgpu/si_dpm.c b/drivers/gpu/drm/amd/amdgpu/si_dpm.c index 3560b7dc17986..db327b4125626 100644 --- a/drivers/gpu/drm/amd/amdgpu/si_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/si_dpm.c @@ -7318,8 +7318,7 @@ static int si_dpm_init(struct amdgpu_device *adev) pi = &eg_pi->rv7xx; si_pi->sys_pcie_mask = - (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_MASK) >> - CAIL_PCIE_LINK_SPEED_SUPPORT_SHIFT; + adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_MASK; si_pi->force_pcie_gen = AMDGPU_PCIE_GEN_INVALID; si_pi->boot_pcie_gen = si_get_current_pcie_speed(adev); -- GitLab From 5f152a572c10cae4b08c2c5f2932a51684f454ba Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexander.deucher@amd.com> Date: Mon, 25 Jun 2018 14:37:45 -0500 Subject: [PATCH 0816/1506] drm/radeon: use pcie functions for link width MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is the last user of drm_pcie_get_speed_cap_mask. Use the pci version so we can drop drm_pcie_get_speed_cap_mask. Acked-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/radeon/ci_dpm.c | 20 +++++++++++++++----- drivers/gpu/drm/radeon/cik.c | 22 ++++++++++++---------- drivers/gpu/drm/radeon/r600_dpm.c | 4 ++-- drivers/gpu/drm/radeon/radeon.h | 4 ++++ drivers/gpu/drm/radeon/si.c | 22 ++++++++++++---------- drivers/gpu/drm/radeon/si_dpm.c | 20 +++++++++++++++----- 6 files changed, 60 insertions(+), 32 deletions(-) diff --git a/drivers/gpu/drm/radeon/ci_dpm.c b/drivers/gpu/drm/radeon/ci_dpm.c index b9302c9182710..d587779a80b4d 100644 --- a/drivers/gpu/drm/radeon/ci_dpm.c +++ b/drivers/gpu/drm/radeon/ci_dpm.c @@ -5676,19 +5676,29 @@ int ci_dpm_init(struct radeon_device *rdev) u16 data_offset, size; u8 frev, crev; struct ci_power_info *pi; + enum pci_bus_speed speed_cap; + struct pci_dev *root = rdev->pdev->bus->self; int ret; - u32 mask; pi = kzalloc(sizeof(struct ci_power_info), GFP_KERNEL); if (pi == NULL) return -ENOMEM; rdev->pm.dpm.priv = pi; - ret = drm_pcie_get_speed_cap_mask(rdev->ddev, &mask); - if (ret) + speed_cap = pcie_get_speed_cap(root); + if (speed_cap == PCI_SPEED_UNKNOWN) { pi->sys_pcie_mask = 0; - else - pi->sys_pcie_mask = mask; + } else { + if (speed_cap == PCIE_SPEED_8_0GT) + pi->sys_pcie_mask = RADEON_PCIE_SPEED_25 | + RADEON_PCIE_SPEED_50 | + RADEON_PCIE_SPEED_80; + else if (speed_cap == PCIE_SPEED_5_0GT) + pi->sys_pcie_mask = RADEON_PCIE_SPEED_25 | + RADEON_PCIE_SPEED_50; + else + pi->sys_pcie_mask = RADEON_PCIE_SPEED_25; + } pi->force_pcie_gen = RADEON_PCIE_GEN_INVALID; pi->pcie_gen_performance.max = RADEON_PCIE_GEN1; diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index 7c73bc7e2f854..ebce4601a3056 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -9499,9 +9499,10 @@ int cik_set_vce_clocks(struct radeon_device *rdev, u32 evclk, u32 ecclk) static void cik_pcie_gen3_enable(struct radeon_device *rdev) { struct pci_dev *root = rdev->pdev->bus->self; + enum pci_bus_speed speed_cap; int bridge_pos, gpu_pos; - u32 speed_cntl, mask, current_data_rate; - int ret, i; + u32 speed_cntl, current_data_rate; + int i; u16 tmp16; if (pci_is_root_bus(rdev->pdev->bus)) @@ -9516,23 +9517,24 @@ static void cik_pcie_gen3_enable(struct radeon_device *rdev) if (!(rdev->flags & RADEON_IS_PCIE)) return; - ret = drm_pcie_get_speed_cap_mask(rdev->ddev, &mask); - if (ret != 0) + speed_cap = pcie_get_speed_cap(root); + if (speed_cap == PCI_SPEED_UNKNOWN) return; - if (!(mask & (DRM_PCIE_SPEED_50 | DRM_PCIE_SPEED_80))) + if ((speed_cap != PCIE_SPEED_8_0GT) && + (speed_cap != PCIE_SPEED_5_0GT)) return; speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); current_data_rate = (speed_cntl & LC_CURRENT_DATA_RATE_MASK) >> LC_CURRENT_DATA_RATE_SHIFT; - if (mask & DRM_PCIE_SPEED_80) { + if (speed_cap == PCIE_SPEED_8_0GT) { if (current_data_rate == 2) { DRM_INFO("PCIE gen 3 link speeds already enabled\n"); return; } DRM_INFO("enabling PCIE gen 3 link speeds, disable with radeon.pcie_gen2=0\n"); - } else if (mask & DRM_PCIE_SPEED_50) { + } else if (speed_cap == PCIE_SPEED_5_0GT) { if (current_data_rate == 1) { DRM_INFO("PCIE gen 2 link speeds already enabled\n"); return; @@ -9548,7 +9550,7 @@ static void cik_pcie_gen3_enable(struct radeon_device *rdev) if (!gpu_pos) return; - if (mask & DRM_PCIE_SPEED_80) { + if (speed_cap == PCIE_SPEED_8_0GT) { /* re-try equalization if gen3 is not already enabled */ if (current_data_rate != 2) { u16 bridge_cfg, gpu_cfg; @@ -9636,9 +9638,9 @@ static void cik_pcie_gen3_enable(struct radeon_device *rdev) pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &tmp16); tmp16 &= ~0xf; - if (mask & DRM_PCIE_SPEED_80) + if (speed_cap == PCIE_SPEED_8_0GT) tmp16 |= 3; /* gen3 */ - else if (mask & DRM_PCIE_SPEED_50) + else if (speed_cap == PCIE_SPEED_5_0GT) tmp16 |= 2; /* gen2 */ else tmp16 |= 1; /* gen1 */ diff --git a/drivers/gpu/drm/radeon/r600_dpm.c b/drivers/gpu/drm/radeon/r600_dpm.c index 73d4c53481168..5e044c98fca2b 100644 --- a/drivers/gpu/drm/radeon/r600_dpm.c +++ b/drivers/gpu/drm/radeon/r600_dpm.c @@ -1327,9 +1327,9 @@ enum radeon_pcie_gen r600_get_pcie_gen_support(struct radeon_device *rdev, case RADEON_PCIE_GEN3: return RADEON_PCIE_GEN3; default: - if ((sys_mask & DRM_PCIE_SPEED_80) && (default_gen == RADEON_PCIE_GEN3)) + if ((sys_mask & RADEON_PCIE_SPEED_80) && (default_gen == RADEON_PCIE_GEN3)) return RADEON_PCIE_GEN3; - else if ((sys_mask & DRM_PCIE_SPEED_50) && (default_gen == RADEON_PCIE_GEN2)) + else if ((sys_mask & RADEON_PCIE_SPEED_50) && (default_gen == RADEON_PCIE_GEN2)) return RADEON_PCIE_GEN2; else return RADEON_PCIE_GEN1; diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 4a2eb409aaccc..1a6f6edb35151 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1653,6 +1653,10 @@ struct radeon_pm { struct radeon_dpm dpm; }; +#define RADEON_PCIE_SPEED_25 1 +#define RADEON_PCIE_SPEED_50 2 +#define RADEON_PCIE_SPEED_80 4 + int radeon_pm_get_type_index(struct radeon_device *rdev, enum radeon_pm_state_type ps_type, int instance); diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 1907c950d76f0..85c604d292358 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -7082,9 +7082,10 @@ int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk) static void si_pcie_gen3_enable(struct radeon_device *rdev) { struct pci_dev *root = rdev->pdev->bus->self; + enum pci_bus_speed speed_cap; int bridge_pos, gpu_pos; - u32 speed_cntl, mask, current_data_rate; - int ret, i; + u32 speed_cntl, current_data_rate; + int i; u16 tmp16; if (pci_is_root_bus(rdev->pdev->bus)) @@ -7099,23 +7100,24 @@ static void si_pcie_gen3_enable(struct radeon_device *rdev) if (!(rdev->flags & RADEON_IS_PCIE)) return; - ret = drm_pcie_get_speed_cap_mask(rdev->ddev, &mask); - if (ret != 0) + speed_cap = pcie_get_speed_cap(root); + if (speed_cap == PCI_SPEED_UNKNOWN) return; - if (!(mask & (DRM_PCIE_SPEED_50 | DRM_PCIE_SPEED_80))) + if ((speed_cap != PCIE_SPEED_8_0GT) && + (speed_cap != PCIE_SPEED_5_0GT)) return; speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); current_data_rate = (speed_cntl & LC_CURRENT_DATA_RATE_MASK) >> LC_CURRENT_DATA_RATE_SHIFT; - if (mask & DRM_PCIE_SPEED_80) { + if (speed_cap == PCIE_SPEED_8_0GT) { if (current_data_rate == 2) { DRM_INFO("PCIE gen 3 link speeds already enabled\n"); return; } DRM_INFO("enabling PCIE gen 3 link speeds, disable with radeon.pcie_gen2=0\n"); - } else if (mask & DRM_PCIE_SPEED_50) { + } else if (speed_cap == PCIE_SPEED_5_0GT) { if (current_data_rate == 1) { DRM_INFO("PCIE gen 2 link speeds already enabled\n"); return; @@ -7131,7 +7133,7 @@ static void si_pcie_gen3_enable(struct radeon_device *rdev) if (!gpu_pos) return; - if (mask & DRM_PCIE_SPEED_80) { + if (speed_cap == PCIE_SPEED_8_0GT) { /* re-try equalization if gen3 is not already enabled */ if (current_data_rate != 2) { u16 bridge_cfg, gpu_cfg; @@ -7219,9 +7221,9 @@ static void si_pcie_gen3_enable(struct radeon_device *rdev) pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &tmp16); tmp16 &= ~0xf; - if (mask & DRM_PCIE_SPEED_80) + if (speed_cap == PCIE_SPEED_8_0GT) tmp16 |= 3; /* gen3 */ - else if (mask & DRM_PCIE_SPEED_50) + else if (speed_cap == PCIE_SPEED_5_0GT) tmp16 |= 2; /* gen2 */ else tmp16 |= 1; /* gen1 */ diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c index fea88078cf8ea..8fb60b3af0158 100644 --- a/drivers/gpu/drm/radeon/si_dpm.c +++ b/drivers/gpu/drm/radeon/si_dpm.c @@ -6899,8 +6899,9 @@ int si_dpm_init(struct radeon_device *rdev) struct ni_power_info *ni_pi; struct si_power_info *si_pi; struct atom_clock_dividers dividers; + enum pci_bus_speed speed_cap; + struct pci_dev *root = rdev->pdev->bus->self; int ret; - u32 mask; si_pi = kzalloc(sizeof(struct si_power_info), GFP_KERNEL); if (si_pi == NULL) @@ -6910,11 +6911,20 @@ int si_dpm_init(struct radeon_device *rdev) eg_pi = &ni_pi->eg; pi = &eg_pi->rv7xx; - ret = drm_pcie_get_speed_cap_mask(rdev->ddev, &mask); - if (ret) + speed_cap = pcie_get_speed_cap(root); + if (speed_cap == PCI_SPEED_UNKNOWN) { si_pi->sys_pcie_mask = 0; - else - si_pi->sys_pcie_mask = mask; + } else { + if (speed_cap == PCIE_SPEED_8_0GT) + si_pi->sys_pcie_mask = RADEON_PCIE_SPEED_25 | + RADEON_PCIE_SPEED_50 | + RADEON_PCIE_SPEED_80; + else if (speed_cap == PCIE_SPEED_5_0GT) + si_pi->sys_pcie_mask = RADEON_PCIE_SPEED_25 | + RADEON_PCIE_SPEED_50; + else + si_pi->sys_pcie_mask = RADEON_PCIE_SPEED_25; + } si_pi->force_pcie_gen = RADEON_PCIE_GEN_INVALID; si_pi->boot_pcie_gen = si_get_current_pcie_speed(rdev); -- GitLab From 289278cb7d32685ee75baf599857d7049c4b8030 Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexander.deucher@amd.com> Date: Mon, 25 Jun 2018 15:14:46 -0500 Subject: [PATCH 0817/1506] drm: drop drm_pcie_get_speed_cap_mask and drm_pcie_get_max_link_width MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These functions duplicated functionality which was ultimately added to the pci core. All users of these functions have been ported to using the newly exposed pci functionality. These functions are no longer used, so drop them. Acked-by: Christian König <christian.koenig@amd.com> Reviewed-by: Dave Airlie <airlied@redhat.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/drm_pci.c | 58 --------------------------------------- include/drm/drm_pci.h | 7 ----- 2 files changed, 65 deletions(-) diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c index 4db9c515b74f7..896e42a34895d 100644 --- a/drivers/gpu/drm/drm_pci.c +++ b/drivers/gpu/drm/drm_pci.c @@ -326,64 +326,6 @@ int drm_legacy_pci_init(struct drm_driver *driver, struct pci_driver *pdriver) } EXPORT_SYMBOL(drm_legacy_pci_init); -int drm_pcie_get_speed_cap_mask(struct drm_device *dev, u32 *mask) -{ - struct pci_dev *root; - u32 lnkcap, lnkcap2; - - *mask = 0; - if (!dev->pdev) - return -EINVAL; - - root = dev->pdev->bus->self; - - /* we've been informed via and serverworks don't make the cut */ - if (root->vendor == PCI_VENDOR_ID_VIA || - root->vendor == PCI_VENDOR_ID_SERVERWORKS) - return -EINVAL; - - pcie_capability_read_dword(root, PCI_EXP_LNKCAP, &lnkcap); - pcie_capability_read_dword(root, PCI_EXP_LNKCAP2, &lnkcap2); - - if (lnkcap2) { /* PCIe r3.0-compliant */ - if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_2_5GB) - *mask |= DRM_PCIE_SPEED_25; - if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_5_0GB) - *mask |= DRM_PCIE_SPEED_50; - if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_8_0GB) - *mask |= DRM_PCIE_SPEED_80; - } else { /* pre-r3.0 */ - if (lnkcap & PCI_EXP_LNKCAP_SLS_2_5GB) - *mask |= DRM_PCIE_SPEED_25; - if (lnkcap & PCI_EXP_LNKCAP_SLS_5_0GB) - *mask |= (DRM_PCIE_SPEED_25 | DRM_PCIE_SPEED_50); - } - - DRM_INFO("probing gen 2 caps for device %x:%x = %x/%x\n", root->vendor, root->device, lnkcap, lnkcap2); - return 0; -} -EXPORT_SYMBOL(drm_pcie_get_speed_cap_mask); - -int drm_pcie_get_max_link_width(struct drm_device *dev, u32 *mlw) -{ - struct pci_dev *root; - u32 lnkcap; - - *mlw = 0; - if (!dev->pdev) - return -EINVAL; - - root = dev->pdev->bus->self; - - pcie_capability_read_dword(root, PCI_EXP_LNKCAP, &lnkcap); - - *mlw = (lnkcap & PCI_EXP_LNKCAP_MLW) >> 4; - - DRM_INFO("probing mlw for device %x:%x = %x\n", root->vendor, root->device, lnkcap); - return 0; -} -EXPORT_SYMBOL(drm_pcie_get_max_link_width); - #else void drm_pci_agp_destroy(struct drm_device *dev) {} diff --git a/include/drm/drm_pci.h b/include/drm/drm_pci.h index 674599025d7d3..8181e9e7cf1dc 100644 --- a/include/drm/drm_pci.h +++ b/include/drm/drm_pci.h @@ -58,11 +58,4 @@ static inline int drm_get_pci_dev(struct pci_dev *pdev, } #endif -#define DRM_PCIE_SPEED_25 1 -#define DRM_PCIE_SPEED_50 2 -#define DRM_PCIE_SPEED_80 4 - -int drm_pcie_get_speed_cap_mask(struct drm_device *dev, u32 *speed_mask); -int drm_pcie_get_max_link_width(struct drm_device *dev, u32 *mlw); - #endif /* _DRM_PCI_H_ */ -- GitLab From ea870e44415a5f5ed09b6e002e38d3e0de7f390e Mon Sep 17 00:00:00 2001 From: Rex Zhu <Rex.Zhu@amd.com> Date: Fri, 22 Jun 2018 14:12:59 +0800 Subject: [PATCH 0818/1506] drm/amd/pp: Export notify_smu_enable_pwe to display Display can notify smu to enable pwe after gpu suspend. It is used in case when display resumes from S3 and wants to start audio driver by enabling pwe Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/include/kgd_pp_interface.h | 7 ++++--- drivers/gpu/drm/amd/powerplay/amd_powerplay.c | 20 +++++++++++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h index 99ee3edd1609a..6a41b81c7325f 100644 --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h @@ -241,6 +241,9 @@ struct amd_pm_funcs { int (*set_clockgating_by_smu)(void *handle, uint32_t msg_id); int (*set_power_limit)(void *handle, uint32_t n); int (*get_power_limit)(void *handle, uint32_t *limit, bool default_limit); + int (*get_power_profile_mode)(void *handle, char *buf); + int (*set_power_profile_mode)(void *handle, long *input, uint32_t size); + int (*odn_edit_dpm_table)(void *handle, uint32_t type, long *input, uint32_t size); /* export to DC */ u32 (*get_sclk)(void *handle, bool low); u32 (*get_mclk)(void *handle, bool low); @@ -265,9 +268,7 @@ struct amd_pm_funcs { struct pp_display_clock_request *clock); int (*get_display_mode_validation_clocks)(void *handle, struct amd_pp_simple_clock_info *clocks); - int (*get_power_profile_mode)(void *handle, char *buf); - int (*set_power_profile_mode)(void *handle, long *input, uint32_t size); - int (*odn_edit_dpm_table)(void *handle, uint32_t type, long *input, uint32_t size); + int (*notify_smu_enable_pwe)(void *handle); }; #endif diff --git a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c index b72cc644d4e7c..145e5c403bea5 100644 --- a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c +++ b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c @@ -1201,6 +1201,25 @@ static int pp_set_powergating_by_smu(void *handle, return ret; } +static int pp_notify_smu_enable_pwe(void *handle) +{ + struct pp_hwmgr *hwmgr = handle; + + if (!hwmgr || !hwmgr->pm_en) + return -EINVAL;; + + if (hwmgr->hwmgr_func->smus_notify_pwe == NULL) { + pr_info("%s was not implemented.\n", __func__); + return -EINVAL;; + } + + mutex_lock(&hwmgr->smu_lock); + hwmgr->hwmgr_func->smus_notify_pwe(hwmgr); + mutex_unlock(&hwmgr->smu_lock); + + return 0; +} + static const struct amd_pm_funcs pp_dpm_funcs = { .load_firmware = pp_dpm_load_fw, .wait_for_fw_loading_complete = pp_dpm_fw_loading_complete, @@ -1244,4 +1263,5 @@ static const struct amd_pm_funcs pp_dpm_funcs = { .set_watermarks_for_clocks_ranges = pp_set_watermarks_for_clocks_ranges, .display_clock_voltage_request = pp_display_clock_voltage_request, .get_display_mode_validation_clocks = pp_get_display_mode_validation_clocks, + .notify_smu_enable_pwe = pp_notify_smu_enable_pwe, }; -- GitLab From b0a634ac68337b263e01d83359a023676e370cce Mon Sep 17 00:00:00 2001 From: Rex Zhu <rex.zhu@amd.com> Date: Tue, 3 Jul 2018 16:31:35 +0800 Subject: [PATCH 0819/1506] drm/amd/display: Refine the implementation of dm_pp_get_funcs_rv powerplay/dpm export all interfaces in struct amd_pm_funcs. so call common exported interfaces instead of powerplay inner interfaces Also not include header file hwmgr.h Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c | 80 +++++++++---------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c index 81845116cdcc7..9c105c07eb25f 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c @@ -33,7 +33,6 @@ #include "amdgpu_dm_irq.h" #include "amdgpu_pm.h" #include "dm_pp_smu.h" -#include "../../powerplay/inc/hwmgr.h" bool dm_pp_apply_display_requirements( @@ -452,76 +451,77 @@ bool dm_pp_get_static_clocks( void pp_rv_set_display_requirement(struct pp_smu *pp, struct pp_smu_display_requirement_rv *req) { - struct amdgpu_device *adev = pp->ctx->driver_context; - struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; - int ret = 0; - if (hwmgr->hwmgr_func->set_deep_sleep_dcefclk) - ret = hwmgr->hwmgr_func->set_deep_sleep_dcefclk(hwmgr, req->hard_min_dcefclk_khz/10); - if (hwmgr->hwmgr_func->set_active_display_count) - ret = hwmgr->hwmgr_func->set_active_display_count(hwmgr, req->display_count); + struct dc_context *ctx = pp->ctx; + struct amdgpu_device *adev = ctx->driver_context; + const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + + if (!pp_funcs || !pp_funcs->display_configuration_changed) + return; - //store_cc6 is not yet implemented in SMU level + amdgpu_dpm_display_configuration_changed(adev); } void pp_rv_set_wm_ranges(struct pp_smu *pp, struct pp_smu_wm_range_sets *ranges) { - struct amdgpu_device *adev = pp->ctx->driver_context; - struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; - struct pp_wm_sets_with_clock_ranges_soc15 ranges_soc15 = {0}; - int i = 0; - - if (!hwmgr->hwmgr_func->set_watermarks_for_clocks_ranges || - !pp || !ranges) - return; + struct dc_context *ctx = pp->ctx; + struct amdgpu_device *adev = ctx->driver_context; + void *pp_handle = adev->powerplay.pp_handle; + const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + struct dm_pp_wm_sets_with_clock_ranges_soc15 wm_with_clock_ranges; + struct dm_pp_clock_range_for_dmif_wm_set_soc15 *wm_dce_clocks = wm_with_clock_ranges.wm_dmif_clocks_ranges; + struct dm_pp_clock_range_for_mcif_wm_set_soc15 *wm_soc_clocks = wm_with_clock_ranges.wm_mcif_clocks_ranges; + int32_t i; - //not entirely sure if thats a correct assignment - ranges_soc15.num_wm_sets_dmif = ranges->num_reader_wm_sets; - ranges_soc15.num_wm_sets_mcif = ranges->num_writer_wm_sets; + wm_with_clock_ranges.num_wm_dmif_sets = ranges->num_reader_wm_sets; + wm_with_clock_ranges.num_wm_mcif_sets = ranges->num_writer_wm_sets; - for (i = 0; i < ranges_soc15.num_wm_sets_dmif; i++) { + for (i = 0; i < wm_with_clock_ranges.num_wm_dmif_sets; i++) { if (ranges->reader_wm_sets[i].wm_inst > 3) - ranges_soc15.wm_sets_dmif[i].wm_set_id = DC_WM_SET_A; + wm_dce_clocks[i].wm_set_id = WM_SET_A; else - ranges_soc15.wm_sets_dmif[i].wm_set_id = + wm_dce_clocks[i].wm_set_id = ranges->reader_wm_sets[i].wm_inst; - ranges_soc15.wm_sets_dmif[i].wm_max_dcefclk_in_khz = + wm_dce_clocks[i].wm_max_dcfclk_clk_in_khz = ranges->reader_wm_sets[i].max_drain_clk_khz; - ranges_soc15.wm_sets_dmif[i].wm_min_dcefclk_in_khz = + wm_dce_clocks[i].wm_min_dcfclk_clk_in_khz = ranges->reader_wm_sets[i].min_drain_clk_khz; - ranges_soc15.wm_sets_dmif[i].wm_max_memclk_in_khz = + wm_dce_clocks[i].wm_max_mem_clk_in_khz = ranges->reader_wm_sets[i].max_fill_clk_khz; - ranges_soc15.wm_sets_dmif[i].wm_min_memclk_in_khz = + wm_dce_clocks[i].wm_min_mem_clk_in_khz = ranges->reader_wm_sets[i].min_fill_clk_khz; } - for (i = 0; i < ranges_soc15.num_wm_sets_mcif; i++) { + for (i = 0; i < wm_with_clock_ranges.num_wm_mcif_sets; i++) { if (ranges->writer_wm_sets[i].wm_inst > 3) - ranges_soc15.wm_sets_dmif[i].wm_set_id = DC_WM_SET_A; + wm_soc_clocks[i].wm_set_id = WM_SET_A; else - ranges_soc15.wm_sets_mcif[i].wm_set_id = + wm_soc_clocks[i].wm_set_id = ranges->writer_wm_sets[i].wm_inst; - ranges_soc15.wm_sets_mcif[i].wm_max_socclk_in_khz = + wm_soc_clocks[i].wm_max_socclk_clk_in_khz = ranges->writer_wm_sets[i].max_fill_clk_khz; - ranges_soc15.wm_sets_mcif[i].wm_min_socclk_in_khz = + wm_soc_clocks[i].wm_min_socclk_clk_in_khz = ranges->writer_wm_sets[i].min_fill_clk_khz; - ranges_soc15.wm_sets_mcif[i].wm_max_memclk_in_khz = + wm_soc_clocks[i].wm_max_mem_clk_in_khz = ranges->writer_wm_sets[i].max_fill_clk_khz; - ranges_soc15.wm_sets_mcif[i].wm_min_memclk_in_khz = + wm_soc_clocks[i].wm_min_mem_clk_in_khz = ranges->writer_wm_sets[i].min_fill_clk_khz; } - hwmgr->hwmgr_func->set_watermarks_for_clocks_ranges(hwmgr, &ranges_soc15); - + pp_funcs->set_watermarks_for_clocks_ranges(pp_handle, &wm_with_clock_ranges); } void pp_rv_set_pme_wa_enable(struct pp_smu *pp) { - struct amdgpu_device *adev = pp->ctx->driver_context; - struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; + struct dc_context *ctx = pp->ctx; + struct amdgpu_device *adev = ctx->driver_context; + void *pp_handle = adev->powerplay.pp_handle; + const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + + if (!pp_funcs || !pp_funcs->notify_smu_enable_pwe) + return; - if (hwmgr->hwmgr_func->smus_notify_pwe) - hwmgr->hwmgr_func->smus_notify_pwe(hwmgr); + pp_funcs->notify_smu_enable_pwe(pp_handle); } void dm_pp_get_funcs_rv( -- GitLab From 70b63170c3effc1d9a66fbfe4a5702c8cbbd31c3 Mon Sep 17 00:00:00 2001 From: Rex Zhu <rex.zhu@amd.com> Date: Tue, 3 Jul 2018 17:17:21 +0800 Subject: [PATCH 0820/1506] drm/amd/display: Fix copy error when set memory clocks Set memory clocks same as soc clocks Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c index 9c105c07eb25f..50e863024f585 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c @@ -503,9 +503,9 @@ void pp_rv_set_wm_ranges(struct pp_smu *pp, wm_soc_clocks[i].wm_min_socclk_clk_in_khz = ranges->writer_wm_sets[i].min_fill_clk_khz; wm_soc_clocks[i].wm_max_mem_clk_in_khz = - ranges->writer_wm_sets[i].max_fill_clk_khz; + ranges->writer_wm_sets[i].max_drain_clk_khz; wm_soc_clocks[i].wm_min_mem_clk_in_khz = - ranges->writer_wm_sets[i].min_fill_clk_khz; + ranges->writer_wm_sets[i].min_drain_clk_khz; } pp_funcs->set_watermarks_for_clocks_ranges(pp_handle, &wm_with_clock_ranges); -- GitLab From 20582319bce482e65ee1f417b9867f028d058c12 Mon Sep 17 00:00:00 2001 From: Rex Zhu <Rex.Zhu@amd.com> Date: Wed, 20 Jun 2018 15:05:04 +0800 Subject: [PATCH 0821/1506] drm/amd/pp: Remove the same struct define in powerplay delete the same struct define in powerplay, share the struct with display. Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/include/dm_pp_interface.h | 37 +--------------- .../gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c | 2 +- .../gpu/drm/amd/powerplay/hwmgr/smu_helper.c | 42 +++++++++---------- .../gpu/drm/amd/powerplay/hwmgr/smu_helper.h | 2 +- .../drm/amd/powerplay/hwmgr/vega10_hwmgr.c | 2 +- .../drm/amd/powerplay/hwmgr/vega12_hwmgr.c | 2 +- 6 files changed, 27 insertions(+), 60 deletions(-) diff --git a/drivers/gpu/drm/amd/include/dm_pp_interface.h b/drivers/gpu/drm/amd/include/dm_pp_interface.h index 7852952d1fdee..1d93a0c574c9e 100644 --- a/drivers/gpu/drm/amd/include/dm_pp_interface.h +++ b/drivers/gpu/drm/amd/include/dm_pp_interface.h @@ -23,6 +23,8 @@ #ifndef _DM_PP_INTERFACE_ #define _DM_PP_INTERFACE_ +#include "dm_services_types.h" + #define PP_MAX_CLOCK_LEVELS 16 enum amd_pp_display_config_type{ @@ -189,39 +191,4 @@ struct pp_display_clock_request { uint32_t clock_freq_in_khz; }; -#define PP_MAX_WM_SETS 4 - -enum pp_wm_set_id { - DC_WM_SET_A = 0, - DC_WM_SET_B, - DC_WM_SET_C, - DC_WM_SET_D, - DC_WM_SET_INVALID = 0xffff, -}; - -struct pp_wm_set_with_dmif_clock_range_soc15 { - enum pp_wm_set_id wm_set_id; - uint32_t wm_min_dcefclk_in_khz; - uint32_t wm_max_dcefclk_in_khz; - uint32_t wm_min_memclk_in_khz; - uint32_t wm_max_memclk_in_khz; -}; - -struct pp_wm_set_with_mcif_clock_range_soc15 { - enum pp_wm_set_id wm_set_id; - uint32_t wm_min_socclk_in_khz; - uint32_t wm_max_socclk_in_khz; - uint32_t wm_min_memclk_in_khz; - uint32_t wm_max_memclk_in_khz; -}; - -struct pp_wm_sets_with_clock_ranges_soc15 { - uint32_t num_wm_sets_dmif; - uint32_t num_wm_sets_mcif; - struct pp_wm_set_with_dmif_clock_range_soc15 - wm_sets_dmif[PP_MAX_WM_SETS]; - struct pp_wm_set_with_mcif_clock_range_soc15 - wm_sets_mcif[PP_MAX_WM_SETS]; -}; - #endif /* _DM_PP_INTERFACE_ */ diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c index 02fc0bc41e0a6..a63e006533243 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c @@ -1111,7 +1111,7 @@ static int smu10_set_watermarks_for_clocks_ranges(struct pp_hwmgr *hwmgr, void *clock_ranges) { struct smu10_hwmgr *data = hwmgr->backend; - struct pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges = clock_ranges; + struct dm_pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges = clock_ranges; Watermarks_t *table = &(data->water_marks_table); int result = 0; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.c index 93a3d022ba47a..3effb5583d1f1 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.c @@ -652,7 +652,7 @@ int smu_get_voltage_dependency_table_ppt_v1( } int smu_set_watermarks_for_clocks_ranges(void *wt_table, - struct pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges) + struct dm_pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges) { uint32_t i; struct watermarks *table = wt_table; @@ -660,49 +660,49 @@ int smu_set_watermarks_for_clocks_ranges(void *wt_table, if (!table || !wm_with_clock_ranges) return -EINVAL; - if (wm_with_clock_ranges->num_wm_sets_dmif > 4 || wm_with_clock_ranges->num_wm_sets_mcif > 4) + if (wm_with_clock_ranges->num_wm_dmif_sets > 4 || wm_with_clock_ranges->num_wm_mcif_sets > 4) return -EINVAL; - for (i = 0; i < wm_with_clock_ranges->num_wm_sets_dmif; i++) { + for (i = 0; i < wm_with_clock_ranges->num_wm_dmif_sets; i++) { table->WatermarkRow[1][i].MinClock = cpu_to_le16((uint16_t) - (wm_with_clock_ranges->wm_sets_dmif[i].wm_min_dcefclk_in_khz) / - 100); + (wm_with_clock_ranges->wm_dmif_clocks_ranges[i].wm_min_dcfclk_clk_in_khz) / + 1000); table->WatermarkRow[1][i].MaxClock = cpu_to_le16((uint16_t) - (wm_with_clock_ranges->wm_sets_dmif[i].wm_max_dcefclk_in_khz) / + (wm_with_clock_ranges->wm_dmif_clocks_ranges[i].wm_max_dcfclk_clk_in_khz) / 100); table->WatermarkRow[1][i].MinUclk = cpu_to_le16((uint16_t) - (wm_with_clock_ranges->wm_sets_dmif[i].wm_min_memclk_in_khz) / - 100); + (wm_with_clock_ranges->wm_dmif_clocks_ranges[i].wm_min_mem_clk_in_khz) / + 1000); table->WatermarkRow[1][i].MaxUclk = cpu_to_le16((uint16_t) - (wm_with_clock_ranges->wm_sets_dmif[i].wm_max_memclk_in_khz) / - 100); + (wm_with_clock_ranges->wm_dmif_clocks_ranges[i].wm_max_mem_clk_in_khz) / + 1000); table->WatermarkRow[1][i].WmSetting = (uint8_t) - wm_with_clock_ranges->wm_sets_dmif[i].wm_set_id; + wm_with_clock_ranges->wm_dmif_clocks_ranges[i].wm_set_id; } - for (i = 0; i < wm_with_clock_ranges->num_wm_sets_mcif; i++) { + for (i = 0; i < wm_with_clock_ranges->num_wm_mcif_sets; i++) { table->WatermarkRow[0][i].MinClock = cpu_to_le16((uint16_t) - (wm_with_clock_ranges->wm_sets_mcif[i].wm_min_socclk_in_khz) / - 100); + (wm_with_clock_ranges->wm_mcif_clocks_ranges[i].wm_min_socclk_clk_in_khz) / + 1000); table->WatermarkRow[0][i].MaxClock = cpu_to_le16((uint16_t) - (wm_with_clock_ranges->wm_sets_mcif[i].wm_max_socclk_in_khz) / - 100); + (wm_with_clock_ranges->wm_mcif_clocks_ranges[i].wm_max_socclk_clk_in_khz) / + 1000); table->WatermarkRow[0][i].MinUclk = cpu_to_le16((uint16_t) - (wm_with_clock_ranges->wm_sets_mcif[i].wm_min_memclk_in_khz) / - 100); + (wm_with_clock_ranges->wm_mcif_clocks_ranges[i].wm_min_mem_clk_in_khz) / + 1000); table->WatermarkRow[0][i].MaxUclk = cpu_to_le16((uint16_t) - (wm_with_clock_ranges->wm_sets_mcif[i].wm_max_memclk_in_khz) / - 100); + (wm_with_clock_ranges->wm_mcif_clocks_ranges[i].wm_max_mem_clk_in_khz) / + 1000); table->WatermarkRow[0][i].WmSetting = (uint8_t) - wm_with_clock_ranges->wm_sets_mcif[i].wm_set_id; + wm_with_clock_ranges->wm_mcif_clocks_ranges[i].wm_set_id; } return 0; } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.h b/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.h index 916cc01e76528..5454289d5226c 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.h +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.h @@ -107,7 +107,7 @@ int smu_get_voltage_dependency_table_ppt_v1( struct phm_ppt_v1_clock_voltage_dependency_table *dep_table); int smu_set_watermarks_for_clocks_ranges(void *wt_table, - struct pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges); + struct dm_pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges); #define PHM_FIELD_SHIFT(reg, field) reg##__##field##__SHIFT #define PHM_FIELD_MASK(reg, field) reg##__##field##_MASK diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c index d515eb4fac9fa..5e771bc119d69 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c @@ -4197,7 +4197,7 @@ static int vega10_set_watermarks_for_clocks_ranges(struct pp_hwmgr *hwmgr, void *clock_range) { struct vega10_hwmgr *data = hwmgr->backend; - struct pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges = clock_range; + struct dm_pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges = clock_range; Watermarks_t *table = &(data->smc_state_table.water_marks_table); int result = 0; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c index 0a090755545d5..57492878874fa 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c @@ -1785,7 +1785,7 @@ static int vega12_set_watermarks_for_clocks_ranges(struct pp_hwmgr *hwmgr, { struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend); Watermarks_t *table = &(data->smc_state_table.water_marks_table); - struct pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges = clock_ranges; + struct dm_pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges = clock_ranges; if (!data->registry_data.disable_water_mark && data->smu_features[GNLD_DPM_DCEFCLK].supported && -- GitLab From 5d908944c5ba4fc8d301e1332635c64c1b77d843 Mon Sep 17 00:00:00 2001 From: Dan Carpenter <dan.carpenter@oracle.com> Date: Wed, 4 Jul 2018 12:46:15 +0300 Subject: [PATCH 0822/1506] drm/amd/display: off by one in find_irq_source_info() The ->info[] array has DAL_IRQ_SOURCES_NUMBER elements so this condition should be >= instead of > or we could read one element beyond the end of the array. Fixes: 4562236b3bc0 ("drm/amd/dc: Add dc display driver (v2)") Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com> Reviewed-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/irq/irq_service.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/irq/irq_service.c b/drivers/gpu/drm/amd/display/dc/irq/irq_service.c index dcdfa0f015517..604bea01fc13e 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/irq_service.c +++ b/drivers/gpu/drm/amd/display/dc/irq/irq_service.c @@ -78,7 +78,7 @@ const struct irq_source_info *find_irq_source_info( struct irq_service *irq_service, enum dc_irq_source source) { - if (source > DAL_IRQ_SOURCES_NUMBER || source < DC_IRQ_SOURCE_INVALID) + if (source >= DAL_IRQ_SOURCES_NUMBER || source < DC_IRQ_SOURCE_INVALID) return NULL; return &irq_service->info[source]; -- GitLab From 25177e7f94a3deeda410edaf9313d0f1a2bb68e0 Mon Sep 17 00:00:00 2001 From: Harry Wentland <harry.wentland@amd.com> Date: Wed, 4 Jul 2018 13:47:07 -0400 Subject: [PATCH 0823/1506] Revert "drm/amd/display: Fix indentation in dcn10 resource constructor" That change was a merge gone bad. This reverts commit cb1d7eacb58f7d1b7d0e57b26dc02d45eada4a3c. Signed-off-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c index 68be66eabc402..771e0cf29bbaa 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c @@ -1068,8 +1068,7 @@ static bool construct( ctx->dc_bios->regs = &bios_regs; - pool->base.res_cap = &res_cap; - + pool->base.res_cap = &res_cap; pool->base.funcs = &dcn10_res_pool_funcs; /* -- GitLab From 4c1ac53eb867670883f1518f620b19c2fed7e516 Mon Sep 17 00:00:00 2001 From: Kees Cook <keescook@chromium.org> Date: Wed, 4 Jul 2018 10:27:30 -0700 Subject: [PATCH 0824/1506] drm/amd/display: Use 2-factor allocator calls As already done treewide, switch from open-coded multiplication to 2-factor allocation helper. Signed-off-by: Kees Cook <keescook@chromium.org> Reviewed-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/modules/color/color_gamma.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c index 98edaefa2b472..ee69c949bfbf2 100644 --- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c +++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c @@ -1723,8 +1723,8 @@ bool mod_color_calculate_curve(enum dc_transfer_func_predefined trans, kvfree(rgb_regamma); } else if (trans == TRANSFER_FUNCTION_HLG || trans == TRANSFER_FUNCTION_HLG12) { - rgb_regamma = kvzalloc(sizeof(*rgb_regamma) * - (MAX_HW_POINTS + _EXTRA_POINTS), + rgb_regamma = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS, + sizeof(*rgb_regamma), GFP_KERNEL); if (!rgb_regamma) goto rgb_regamma_alloc_fail; @@ -1802,8 +1802,8 @@ bool mod_color_calculate_degamma_curve(enum dc_transfer_func_predefined trans, kvfree(rgb_degamma); } else if (trans == TRANSFER_FUNCTION_HLG || trans == TRANSFER_FUNCTION_HLG12) { - rgb_degamma = kvzalloc(sizeof(*rgb_degamma) * - (MAX_HW_POINTS + _EXTRA_POINTS), + rgb_degamma = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS, + sizeof(*rgb_degamma), GFP_KERNEL); if (!rgb_degamma) goto rgb_degamma_alloc_fail; -- GitLab From 6f3472a993e7cb63cde5d818dcabc8e42fc03744 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" <gustavo@embeddedor.com> Date: Wed, 4 Jul 2018 08:22:11 -0500 Subject: [PATCH 0825/1506] drm/amd/display/dc/dce: Fix multiple potential integer overflows Add suffix ULL to constant 5 and cast variables target_pix_clk_khz and feedback_divider to uint64_t in order to avoid multiple potential integer overflows and give the compiler complete information about the proper arithmetic to use. Notice that such constant and variables are used in contexts that expect expressions of type uint64_t (64 bits, unsigned). The current casts to uint64_t effectively apply to each expression as a whole, but they do not prevent them from being evaluated using 32-bit arithmetic instead of 64-bit arithmetic. Also, once the expressions are properly evaluated using 64-bit arithmentic, there is no need for the parentheses that enclose them. Addresses-Coverity-ID: 1460245 ("Unintentional integer overflow") Addresses-Coverity-ID: 1460286 ("Unintentional integer overflow") Addresses-Coverity-ID: 1460401 ("Unintentional integer overflow") Fixes: 4562236b3bc0 ("drm/amd/dc: Add dc display driver (v2)") Signed-off-by: Gustavo A. R. Silva <gustavo@embeddedor.com> Reviewed-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c index 88b09dd758baa..ca137757a69e1 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c @@ -133,7 +133,7 @@ static bool calculate_fb_and_fractional_fb_divider( uint64_t feedback_divider; feedback_divider = - (uint64_t)(target_pix_clk_khz * ref_divider * post_divider); + (uint64_t)target_pix_clk_khz * ref_divider * post_divider; feedback_divider *= 10; /* additional factor, since we divide by 10 afterwards */ feedback_divider *= (uint64_t)(calc_pll_cs->fract_fb_divider_factor); @@ -145,8 +145,8 @@ static bool calculate_fb_and_fractional_fb_divider( * of fractional feedback decimal point and the fractional FB Divider precision * is 2 then the equation becomes (ullfeedbackDivider + 5*100) / (10*100))*/ - feedback_divider += (uint64_t) - (5 * calc_pll_cs->fract_fb_divider_precision_factor); + feedback_divider += 5ULL * + calc_pll_cs->fract_fb_divider_precision_factor; feedback_divider = div_u64(feedback_divider, calc_pll_cs->fract_fb_divider_precision_factor * 10); @@ -203,8 +203,8 @@ static bool calc_fb_divider_checking_tolerance( &fract_feedback_divider); /*Actual calculated value*/ - actual_calc_clk_khz = (uint64_t)(feedback_divider * - calc_pll_cs->fract_fb_divider_factor) + + actual_calc_clk_khz = (uint64_t)feedback_divider * + calc_pll_cs->fract_fb_divider_factor + fract_feedback_divider; actual_calc_clk_khz *= calc_pll_cs->ref_freq_khz; actual_calc_clk_khz = -- GitLab From 87e3f1366eaa82c78b826b38008987406470b03d Mon Sep 17 00:00:00 2001 From: Darren Powell <darren.powell@amd.com> Date: Mon, 25 Jun 2018 19:04:03 -0400 Subject: [PATCH 0826/1506] drm/amd: Remove errors from sphinx documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Eliminating the warnings produced by sphinx when processing the sphinx comments in amdgpu_device.c & amdgpu_mn.c Signed-off-by: Darren Powell <darren.powell@amd.com> Reviewed-by: Michel Dänzer <michel.daenzer@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 20 ++++++++++++-------- drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c | 5 +++-- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index d43abbd2a3cc2..9883fa9bb41be 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -1076,7 +1076,7 @@ static const struct vga_switcheroo_client_ops amdgpu_switcheroo_ops = { /** * amdgpu_device_ip_set_clockgating_state - set the CG state * - * @adev: amdgpu_device pointer + * @dev: amdgpu_device pointer * @block_type: Type of hardware IP (SMU, GFX, UVD, etc.) * @state: clockgating state (gate or ungate) * @@ -1110,7 +1110,7 @@ int amdgpu_device_ip_set_clockgating_state(void *dev, /** * amdgpu_device_ip_set_powergating_state - set the PG state * - * @adev: amdgpu_device pointer + * @dev: amdgpu_device pointer * @block_type: Type of hardware IP (SMU, GFX, UVD, etc.) * @state: powergating state (gate or ungate) * @@ -1221,7 +1221,7 @@ bool amdgpu_device_ip_is_idle(struct amdgpu_device *adev, * amdgpu_device_ip_get_ip_block - get a hw IP pointer * * @adev: amdgpu_device pointer - * @block_type: Type of hardware IP (SMU, GFX, UVD, etc.) + * @type: Type of hardware IP (SMU, GFX, UVD, etc.) * * Returns a pointer to the hardware IP block structure * if it exists for the asic, otherwise NULL. @@ -2229,7 +2229,7 @@ bool amdgpu_device_has_dc_support(struct amdgpu_device *adev) * amdgpu_device_init - initialize the driver * * @adev: amdgpu_device pointer - * @pdev: drm dev pointer + * @ddev: drm dev pointer * @pdev: pci dev pointer * @flags: driver flags * @@ -2602,8 +2602,9 @@ void amdgpu_device_fini(struct amdgpu_device *adev) /** * amdgpu_device_suspend - initiate device suspend * - * @pdev: drm dev pointer - * @state: suspend state + * @dev: drm dev pointer + * @suspend: suspend state + * @fbcon : notify the fbdev of suspend * * Puts the hw in the suspend state (all asics). * Returns 0 for success or an error on failure. @@ -2701,7 +2702,9 @@ int amdgpu_device_suspend(struct drm_device *dev, bool suspend, bool fbcon) /** * amdgpu_device_resume - initiate device resume * - * @pdev: drm dev pointer + * @dev: drm dev pointer + * @resume: resume state + * @fbcon : notify the fbdev of resume * * Bring the hw back to operating state (all asics). * Returns 0 for success or an error on failure. @@ -3164,6 +3167,7 @@ static int amdgpu_device_reset(struct amdgpu_device *adev) * amdgpu_device_reset_sriov - reset ASIC for SR-IOV vf * * @adev: amdgpu device pointer + * @from_hypervisor: request from hypervisor * * do VF FLR and reinitialize Asic * return 0 means successed otherwise failed @@ -3211,7 +3215,7 @@ static int amdgpu_device_reset_sriov(struct amdgpu_device *adev, * * @adev: amdgpu device pointer * @job: which job trigger hang - * @force forces reset regardless of amdgpu_gpu_recovery + * @force: forces reset regardless of amdgpu_gpu_recovery * * Attempt to reset the GPU if it has hung (all asics). * Returns 0 for success or an error on failure. diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c index 72a3e8c688760..a365ea2383d18 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c @@ -58,7 +58,8 @@ * * @adev: amdgpu device pointer * @mm: process address space - * @mn: MMU notifier structur + * @mn: MMU notifier structure + * @type: type of MMU notifier * @work: destruction work item * @node: hash table node to find structure by adev and mn * @lock: rw semaphore protecting the notifier nodes @@ -266,7 +267,7 @@ static void amdgpu_mn_invalidate_range_start_gfx(struct mmu_notifier *mn, * amdgpu_mn_invalidate_range_start_hsa - callback to notify about mm change * * @mn: our notifier - * @mn: the mm this callback is about + * @mm: the mm this callback is about * @start: start of updated range * @end: end of updated range * -- GitLab From fe61a2f1a57fea5d7b3d27d019fa67e1bc5b7079 Mon Sep 17 00:00:00 2001 From: Mikita Lipski <mikita.lipski@amd.com> Date: Wed, 4 Jul 2018 09:27:02 -0400 Subject: [PATCH 0827/1506] drm/amd/display: adding ycbcr420 pixel encoding for hdmi [why] HDMI EDID's VSDB contains spectial timings for specifically YCbCr 4:2:0 colour space. In those cases we need to verify if the mode provided is one of the special ones has to use YCbCr 4:2:0 pixel encoding for display info. [how] Verify if the mode is using specific ycbcr420 colour space with the help of DRM helper function and assign the mode to use ycbcr420 pixel encoding. Signed-off-by: Mikita Lipski <mikita.lipski@amd.com> Tested-by: Mike Lothian <mike@fireburn.co.uk> Reviewed-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) 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 74683071fa817..1386c857546d4 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -2184,6 +2184,7 @@ fill_stream_properties_from_drm_display_mode(struct dc_stream_state *stream, const struct drm_connector *connector) { struct dc_crtc_timing *timing_out = &stream->timing; + const struct drm_display_info *info = &connector->display_info; memset(timing_out, 0, sizeof(struct dc_crtc_timing)); @@ -2192,8 +2193,10 @@ fill_stream_properties_from_drm_display_mode(struct dc_stream_state *stream, timing_out->v_border_top = 0; timing_out->v_border_bottom = 0; /* TODO: un-hardcode */ - - if ((connector->display_info.color_formats & DRM_COLOR_FORMAT_YCRCB444) + if (drm_mode_is_420_only(info, mode_in) + && stream->sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A) + timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420; + else if ((connector->display_info.color_formats & DRM_COLOR_FORMAT_YCRCB444) && stream->sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A) timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR444; else -- GitLab From 400443e894c5a7f63f3ace3664640ec3ea4e1585 Mon Sep 17 00:00:00 2001 From: Mikita Lipski <mikita.lipski@amd.com> Date: Tue, 3 Jul 2018 09:42:51 -0400 Subject: [PATCH 0828/1506] drm/amd/display: add a check for display depth validity [why] HDMI 2.0 fails to validate 4K@60 timing with 10 bpc [how] Adding a helper function that would verify if the display depth assigned would pass a bandwidth validation. Drop the display depth by one level till calculated pixel clk is lower than maximum TMDS clk. Bugzilla: https://bugs.freedesktop.org/106959 Signed-off-by: Mikita Lipski <mikita.lipski@amd.com> Tested-by: Mike Lothian <mike@fireburn.co.uk> Reviewed-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) 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 1386c857546d4..ca017c1dd4dab 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -2176,6 +2176,46 @@ get_output_color_space(const struct dc_crtc_timing *dc_crtc_timing) return color_space; } +static void reduce_mode_colour_depth(struct dc_crtc_timing *timing_out) +{ + if (timing_out->display_color_depth <= COLOR_DEPTH_888) + return; + + timing_out->display_color_depth--; +} + +static void adjust_colour_depth_from_display_info(struct dc_crtc_timing *timing_out, + const struct drm_display_info *info) +{ + int normalized_clk; + if (timing_out->display_color_depth <= COLOR_DEPTH_888) + return; + do { + normalized_clk = timing_out->pix_clk_khz; + /* YCbCr 4:2:0 requires additional adjustment of 1/2 */ + if (timing_out->pixel_encoding == PIXEL_ENCODING_YCBCR420) + normalized_clk /= 2; + /* Adjusting pix clock following on HDMI spec based on colour depth */ + switch (timing_out->display_color_depth) { + case COLOR_DEPTH_101010: + normalized_clk = (normalized_clk * 30) / 24; + break; + case COLOR_DEPTH_121212: + normalized_clk = (normalized_clk * 36) / 24; + break; + case COLOR_DEPTH_161616: + normalized_clk = (normalized_clk * 48) / 24; + break; + default: + return; + } + if (normalized_clk <= info->max_tmds_clock) + return; + reduce_mode_colour_depth(timing_out); + + } while (timing_out->display_color_depth > COLOR_DEPTH_888); + +} /*****************************************************************************/ static void @@ -2232,6 +2272,8 @@ fill_stream_properties_from_drm_display_mode(struct dc_stream_state *stream, stream->out_transfer_func->type = TF_TYPE_PREDEFINED; stream->out_transfer_func->tf = TRANSFER_FUNCTION_SRGB; + if (stream->sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A) + adjust_colour_depth_from_display_info(timing_out, info); } static void fill_audio_info(struct audio_info *audio_info, -- GitLab From 8405cf39e8bd034be29971342fca49b01e772da2 Mon Sep 17 00:00:00 2001 From: Sonny Jiang <sonny.jiang@amd.com> Date: Tue, 26 Jun 2018 15:48:34 -0400 Subject: [PATCH 0829/1506] drm/amdgpu: update documentation for amdgpu_drv.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sonny Jiang <sonny.jiang@amd.com> Acked-by: Junwei Zhang <Jerry.Zhang@amd.com> Acked-by: Christian König <christian.koenig@amd.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- Documentation/gpu/amdgpu.rst | 7 + drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 232 +++++++++++++++++++++++- 2 files changed, 232 insertions(+), 7 deletions(-) diff --git a/Documentation/gpu/amdgpu.rst b/Documentation/gpu/amdgpu.rst index 765c2a32938f3..a740e491dfcc3 100644 --- a/Documentation/gpu/amdgpu.rst +++ b/Documentation/gpu/amdgpu.rst @@ -5,6 +5,13 @@ The drm/amdgpu driver supports all AMD Radeon GPUs based on the Graphics Core Next (GCN) architecture. +Module Parameters +================= + +The amdgpu driver supports the following module parameters: + +.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c + Core Driver Infrastructure ========================== diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 963578c34c472..06aede194bf85 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -1,10 +1,3 @@ -/** - * \file amdgpu_drv.c - * AMD Amdgpu driver - * - * \author Gareth Hughes <gareth@valinux.com> - */ - /* * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All Rights Reserved. @@ -136,102 +129,239 @@ int amdgpu_gpu_recovery = -1; /* auto */ int amdgpu_emu_mode = 0; uint amdgpu_smu_memory_pool_size = 0; +/** + * DOC: vramlimit (int) + * Restrict the total amount of VRAM in MiB for testing. The default is 0 (Use full VRAM). + */ MODULE_PARM_DESC(vramlimit, "Restrict VRAM for testing, in megabytes"); module_param_named(vramlimit, amdgpu_vram_limit, int, 0600); +/** + * DOC: vis_vramlimit (int) + * Restrict the amount of CPU visible VRAM in MiB for testing. The default is 0 (Use full CPU visible VRAM). + */ MODULE_PARM_DESC(vis_vramlimit, "Restrict visible VRAM for testing, in megabytes"); module_param_named(vis_vramlimit, amdgpu_vis_vram_limit, int, 0444); +/** + * DOC: gartsize (uint) + * Restrict the size of GART in Mib (32, 64, etc.) for testing. The default is -1 (The size depends on asic). + */ MODULE_PARM_DESC(gartsize, "Size of GART to setup in megabytes (32, 64, etc., -1=auto)"); module_param_named(gartsize, amdgpu_gart_size, uint, 0600); +/** + * DOC: gttsize (int) + * Restrict the size of GTT domain in MiB for testing. The default is -1 (It's VRAM size if 3GB < VRAM < 3/4 RAM, + * otherwise 3/4 RAM size). + */ MODULE_PARM_DESC(gttsize, "Size of the GTT domain in megabytes (-1 = auto)"); module_param_named(gttsize, amdgpu_gtt_size, int, 0600); +/** + * DOC: moverate (int) + * Set maximum buffer migration rate in MB/s. The default is -1 (8 MB/s). + */ MODULE_PARM_DESC(moverate, "Maximum buffer migration rate in MB/s. (32, 64, etc., -1=auto, 0=1=disabled)"); module_param_named(moverate, amdgpu_moverate, int, 0600); +/** + * DOC: benchmark (int) + * Run benchmarks. The default is 0 (Skip benchmarks). + */ MODULE_PARM_DESC(benchmark, "Run benchmark"); module_param_named(benchmark, amdgpu_benchmarking, int, 0444); +/** + * DOC: test (int) + * Test BO GTT->VRAM and VRAM->GTT GPU copies. The default is 0 (Skip test, only set 1 to run test). + */ MODULE_PARM_DESC(test, "Run tests"); module_param_named(test, amdgpu_testing, int, 0444); +/** + * DOC: audio (int) + * Set HDMI/DPAudio. Only affects non-DC display handling. The default is -1 (Enabled), set 0 to disabled it. + */ MODULE_PARM_DESC(audio, "Audio enable (-1 = auto, 0 = disable, 1 = enable)"); module_param_named(audio, amdgpu_audio, int, 0444); +/** + * DOC: disp_priority (int) + * Set display Priority (1 = normal, 2 = high). Only affects non-DC display handling. The default is 0 (auto). + */ MODULE_PARM_DESC(disp_priority, "Display Priority (0 = auto, 1 = normal, 2 = high)"); module_param_named(disp_priority, amdgpu_disp_priority, int, 0444); +/** + * DOC: hw_i2c (int) + * To enable hw i2c engine. Only affects non-DC display handling. The default is 0 (Disabled). + */ MODULE_PARM_DESC(hw_i2c, "hw i2c engine enable (0 = disable)"); module_param_named(hw_i2c, amdgpu_hw_i2c, int, 0444); +/** + * DOC: pcie_gen2 (int) + * To disable PCIE Gen2/3 mode (0 = disable, 1 = enable). The default is -1 (auto, enabled). + */ MODULE_PARM_DESC(pcie_gen2, "PCIE Gen2 mode (-1 = auto, 0 = disable, 1 = enable)"); module_param_named(pcie_gen2, amdgpu_pcie_gen2, int, 0444); +/** + * DOC: msi (int) + * To disable Message Signaled Interrupts (MSI) functionality (1 = enable, 0 = disable). The default is -1 (auto, enabled). + */ MODULE_PARM_DESC(msi, "MSI support (1 = enable, 0 = disable, -1 = auto)"); module_param_named(msi, amdgpu_msi, int, 0444); +/** + * DOC: lockup_timeout (int) + * Set GPU scheduler timeout value in ms. Value 0 is invalidated, will be adjusted to 10000. + * Negative values mean 'infinite timeout' (MAX_JIFFY_OFFSET). The default is 10000. + */ MODULE_PARM_DESC(lockup_timeout, "GPU lockup timeout in ms > 0 (default 10000)"); module_param_named(lockup_timeout, amdgpu_lockup_timeout, int, 0444); +/** + * DOC: dpm (int) + * Override for dynamic power management setting (1 = enable, 0 = disable). The default is -1 (auto). + */ MODULE_PARM_DESC(dpm, "DPM support (1 = enable, 0 = disable, -1 = auto)"); module_param_named(dpm, amdgpu_dpm, int, 0444); +/** + * DOC: fw_load_type (int) + * Set different firmware loading type for debugging (0 = direct, 1 = SMU, 2 = PSP). The default is -1 (auto). + */ MODULE_PARM_DESC(fw_load_type, "firmware loading type (0 = direct, 1 = SMU, 2 = PSP, -1 = auto)"); module_param_named(fw_load_type, amdgpu_fw_load_type, int, 0444); +/** + * DOC: aspm (int) + * To disable ASPM (1 = enable, 0 = disable). The default is -1 (auto, enabled). + */ MODULE_PARM_DESC(aspm, "ASPM support (1 = enable, 0 = disable, -1 = auto)"); module_param_named(aspm, amdgpu_aspm, int, 0444); +/** + * DOC: runpm (int) + * Override for runtime power management control for dGPUs in PX/HG laptops. The amdgpu driver can dynamically power down + * the dGPU on PX/HG laptops when it is idle. The default is -1 (auto enable). Setting the value to 0 disables this functionality. + */ MODULE_PARM_DESC(runpm, "PX runtime pm (1 = force enable, 0 = disable, -1 = PX only default)"); module_param_named(runpm, amdgpu_runtime_pm, int, 0444); +/** + * DOC: ip_block_mask (uint) + * Override what IP blocks are enabled on the GPU. Each GPU is a collection of IP blocks (gfx, display, video, etc.). + * Use this parameter to disable specific blocks. Note that the IP blocks do not have a fixed index. Some asics may not have + * some IPs or may include multiple instances of an IP so the ordering various from asic to asic. See the driver output in + * the kernel log for the list of IPs on the asic. The default is 0xffffffff (enable all blocks on a device). + */ MODULE_PARM_DESC(ip_block_mask, "IP Block Mask (all blocks enabled (default))"); module_param_named(ip_block_mask, amdgpu_ip_block_mask, uint, 0444); +/** + * DOC: bapm (int) + * Bidirectional Application Power Management (BAPM) used to dynamically share TDP between CPU and GPU. Set value 0 to disable it. + * The default -1 (auto, enabled) + */ MODULE_PARM_DESC(bapm, "BAPM support (1 = enable, 0 = disable, -1 = auto)"); module_param_named(bapm, amdgpu_bapm, int, 0444); +/** + * DOC: deep_color (int) + * Set 1 to enable Deep Color support. Only affects non-DC display handling. The default is 0 (disabled). + */ MODULE_PARM_DESC(deep_color, "Deep Color support (1 = enable, 0 = disable (default))"); module_param_named(deep_color, amdgpu_deep_color, int, 0444); +/** + * DOC: vm_size (int) + * Override the size of the GPU's per client virtual address space in GiB. The default is -1 (automatic for each asic). + */ MODULE_PARM_DESC(vm_size, "VM address space size in gigabytes (default 64GB)"); module_param_named(vm_size, amdgpu_vm_size, int, 0444); +/** + * DOC: vm_fragment_size (int) + * Override VM fragment size in bits (4, 5, etc. 4 = 64K, 9 = 2M). The default is -1 (automatic for each asic). + */ MODULE_PARM_DESC(vm_fragment_size, "VM fragment size in bits (4, 5, etc. 4 = 64K (default), Max 9 = 2M)"); module_param_named(vm_fragment_size, amdgpu_vm_fragment_size, int, 0444); +/** + * DOC: vm_block_size (int) + * Override VM page table size in bits (default depending on vm_size and hw setup). The default is -1 (automatic for each asic). + */ MODULE_PARM_DESC(vm_block_size, "VM page table size in bits (default depending on vm_size)"); module_param_named(vm_block_size, amdgpu_vm_block_size, int, 0444); +/** + * DOC: vm_fault_stop (int) + * Stop on VM fault for debugging (0 = never, 1 = print first, 2 = always). The default is 0 (No stop). + */ MODULE_PARM_DESC(vm_fault_stop, "Stop on VM fault (0 = never (default), 1 = print first, 2 = always)"); module_param_named(vm_fault_stop, amdgpu_vm_fault_stop, int, 0444); +/** + * DOC: vm_debug (int) + * Debug VM handling (0 = disabled, 1 = enabled). The default is 0 (Disabled). + */ MODULE_PARM_DESC(vm_debug, "Debug VM handling (0 = disabled (default), 1 = enabled)"); module_param_named(vm_debug, amdgpu_vm_debug, int, 0644); +/** + * DOC: vm_update_mode (int) + * Override VM update mode. VM updated by using CPU (0 = never, 1 = Graphics only, 2 = Compute only, 3 = Both). The default + * is -1 (Only in large BAR(LB) systems Compute VM tables will be updated by CPU, otherwise 0, never). + */ MODULE_PARM_DESC(vm_update_mode, "VM update using CPU (0 = never (default except for large BAR(LB)), 1 = Graphics only, 2 = Compute only (default for LB), 3 = Both"); module_param_named(vm_update_mode, amdgpu_vm_update_mode, int, 0444); +/** + * DOC: vram_page_split (int) + * Override the number of pages after we split VRAM allocations (default 512, -1 = disable). The default is 512. + */ MODULE_PARM_DESC(vram_page_split, "Number of pages after we split VRAM allocations (default 512, -1 = disable)"); module_param_named(vram_page_split, amdgpu_vram_page_split, int, 0444); +/** + * DOC: exp_hw_support (int) + * Enable experimental hw support (1 = enable). The default is 0 (disabled). + */ MODULE_PARM_DESC(exp_hw_support, "experimental hw support (1 = enable, 0 = disable (default))"); module_param_named(exp_hw_support, amdgpu_exp_hw_support, int, 0444); +/** + * DOC: dc (int) + * Disable/Enable Display Core driver for debugging (1 = enable, 0 = disable). The default is -1 (automatic for each asic). + */ MODULE_PARM_DESC(dc, "Display Core driver (1 = enable, 0 = disable, -1 = auto (default))"); module_param_named(dc, amdgpu_dc, int, 0444); MODULE_PARM_DESC(dc_log, "Display Core Log Level (0 = minimal (default), 1 = chatty"); module_param_named(dc_log, amdgpu_dc_log, int, 0444); +/** + * DOC: sched_jobs (int) + * Override the max number of jobs supported in the sw queue. The default is 32. + */ MODULE_PARM_DESC(sched_jobs, "the max number of jobs supported in the sw queue (default 32)"); module_param_named(sched_jobs, amdgpu_sched_jobs, int, 0444); +/** + * DOC: sched_hw_submission (int) + * Override the max number of HW submissions. The default is 2. + */ MODULE_PARM_DESC(sched_hw_submission, "the max number of HW submissions (default 2)"); module_param_named(sched_hw_submission, amdgpu_sched_hw_submission, int, 0444); +/** + * DOC: ppfeaturemask (uint) + * Override power features enabled. See enum PP_FEATURE_MASK in drivers/gpu/drm/amd/include/amd_shared.h. + * The default is the current set of stable power features. + */ MODULE_PARM_DESC(ppfeaturemask, "all power features enabled (default))"); module_param_named(ppfeaturemask, amdgpu_pp_feature_mask, uint, 0444); @@ -241,58 +371,135 @@ module_param_named(no_evict, amdgpu_no_evict, int, 0444); MODULE_PARM_DESC(direct_gma_size, "Direct GMA size in megabytes (max 96MB)"); module_param_named(direct_gma_size, amdgpu_direct_gma_size, int, 0444); +/** + * DOC: pcie_gen_cap (uint) + * Override PCIE gen speed capabilities. See the CAIL flags in drivers/gpu/drm/amd/include/amd_pcie.h. + * The default is 0 (automatic for each asic). + */ MODULE_PARM_DESC(pcie_gen_cap, "PCIE Gen Caps (0: autodetect (default))"); module_param_named(pcie_gen_cap, amdgpu_pcie_gen_cap, uint, 0444); +/** + * DOC: pcie_lane_cap (uint) + * Override PCIE lanes capabilities. See the CAIL flags in drivers/gpu/drm/amd/include/amd_pcie.h. + * The default is 0 (automatic for each asic). + */ MODULE_PARM_DESC(pcie_lane_cap, "PCIE Lane Caps (0: autodetect (default))"); module_param_named(pcie_lane_cap, amdgpu_pcie_lane_cap, uint, 0444); +/** + * DOC: cg_mask (uint) + * Override Clockgating features enabled on GPU (0 = disable clock gating). See the AMD_CG_SUPPORT flags in + * drivers/gpu/drm/amd/include/amd_shared.h. The default is 0xffffffff (all enabled). + */ MODULE_PARM_DESC(cg_mask, "Clockgating flags mask (0 = disable clock gating)"); module_param_named(cg_mask, amdgpu_cg_mask, uint, 0444); +/** + * DOC: pg_mask (uint) + * Override Powergating features enabled on GPU (0 = disable power gating). See the AMD_PG_SUPPORT flags in + * drivers/gpu/drm/amd/include/amd_shared.h. The default is 0xffffffff (all enabled). + */ MODULE_PARM_DESC(pg_mask, "Powergating flags mask (0 = disable power gating)"); module_param_named(pg_mask, amdgpu_pg_mask, uint, 0444); +/** + * DOC: sdma_phase_quantum (uint) + * Override SDMA context switch phase quantum (x 1K GPU clock cycles, 0 = no change). The default is 32. + */ MODULE_PARM_DESC(sdma_phase_quantum, "SDMA context switch phase quantum (x 1K GPU clock cycles, 0 = no change (default 32))"); module_param_named(sdma_phase_quantum, amdgpu_sdma_phase_quantum, uint, 0444); +/** + * DOC: disable_cu (charp) + * Set to disable CUs (It's set like se.sh.cu,...). The default is NULL. + */ MODULE_PARM_DESC(disable_cu, "Disable CUs (se.sh.cu,...)"); module_param_named(disable_cu, amdgpu_disable_cu, charp, 0444); +/** + * DOC: virtual_display (charp) + * Set to enable virtual display feature. This feature provides a virtual display hardware on headless boards + * or in virtualized environments. It will be set like xxxx:xx:xx.x,x;xxxx:xx:xx.x,x. It's the pci address of + * the device, plus the number of crtcs to expose. E.g., 0000:26:00.0,4 would enable 4 virtual crtcs on the pci + * device at 26:00.0. The default is NULL. + */ MODULE_PARM_DESC(virtual_display, "Enable virtual display feature (the virtual_display will be set like xxxx:xx:xx.x,x;xxxx:xx:xx.x,x)"); module_param_named(virtual_display, amdgpu_virtual_display, charp, 0444); +/** + * DOC: ngg (int) + * Set to enable Next Generation Graphics (1 = enable). The default is 0 (disabled). + */ MODULE_PARM_DESC(ngg, "Next Generation Graphics (1 = enable, 0 = disable(default depending on gfx))"); module_param_named(ngg, amdgpu_ngg, int, 0444); +/** + * DOC: prim_buf_per_se (int) + * Override the size of Primitive Buffer per Shader Engine in Byte. The default is 0 (depending on gfx). + */ MODULE_PARM_DESC(prim_buf_per_se, "the size of Primitive Buffer per Shader Engine (default depending on gfx)"); module_param_named(prim_buf_per_se, amdgpu_prim_buf_per_se, int, 0444); +/** + * DOC: pos_buf_per_se (int) + * Override the size of Position Buffer per Shader Engine in Byte. The default is 0 (depending on gfx). + */ MODULE_PARM_DESC(pos_buf_per_se, "the size of Position Buffer per Shader Engine (default depending on gfx)"); module_param_named(pos_buf_per_se, amdgpu_pos_buf_per_se, int, 0444); +/** + * DOC: cntl_sb_buf_per_se (int) + * Override the size of Control Sideband per Shader Engine in Byte. The default is 0 (depending on gfx). + */ MODULE_PARM_DESC(cntl_sb_buf_per_se, "the size of Control Sideband per Shader Engine (default depending on gfx)"); module_param_named(cntl_sb_buf_per_se, amdgpu_cntl_sb_buf_per_se, int, 0444); +/** + * DOC: param_buf_per_se (int) + * Override the size of Off-Chip Pramater Cache per Shader Engine in Byte. The default is 0 (depending on gfx). + */ MODULE_PARM_DESC(param_buf_per_se, "the size of Off-Chip Pramater Cache per Shader Engine (default depending on gfx)"); module_param_named(param_buf_per_se, amdgpu_param_buf_per_se, int, 0444); +/** + * DOC: job_hang_limit (int) + * Set how much time allow a job hang and not drop it. The default is 0. + */ MODULE_PARM_DESC(job_hang_limit, "how much time allow a job hang and not drop it (default 0)"); module_param_named(job_hang_limit, amdgpu_job_hang_limit, int ,0444); +/** + * DOC: lbpw (int) + * Override Load Balancing Per Watt (LBPW) support (1 = enable, 0 = disable). The default is -1 (auto, enabled). + */ MODULE_PARM_DESC(lbpw, "Load Balancing Per Watt (LBPW) support (1 = enable, 0 = disable, -1 = auto)"); module_param_named(lbpw, amdgpu_lbpw, int, 0444); MODULE_PARM_DESC(compute_multipipe, "Force compute queues to be spread across pipes (1 = enable, 0 = disable, -1 = auto)"); module_param_named(compute_multipipe, amdgpu_compute_multipipe, int, 0444); +/** + * DOC: gpu_recovery (int) + * Set to enable GPU recovery mechanism (1 = enable, 0 = disable). The default is -1 (auto, disabled except SRIOV). + */ MODULE_PARM_DESC(gpu_recovery, "Enable GPU recovery mechanism, (1 = enable, 0 = disable, -1 = auto)"); module_param_named(gpu_recovery, amdgpu_gpu_recovery, int, 0444); +/** + * DOC: emu_mode (int) + * Set value 1 to enable emulation mode. This is only needed when running on an emulator. The default is 0 (disabled). + */ MODULE_PARM_DESC(emu_mode, "Emulation mode, (1 = enable, 0 = disable)"); module_param_named(emu_mode, amdgpu_emu_mode, int, 0444); +/** + * DOC: si_support (int) + * Set SI support driver. This parameter works after set config CONFIG_DRM_AMDGPU_SI. For SI asic, when radeon driver is enabled, + * set value 0 to use radeon driver, while set value 1 to use amdgpu driver. The default is using radeon driver when it available, + * otherwise using amdgpu driver. + */ #ifdef CONFIG_DRM_AMDGPU_SI #if defined(CONFIG_DRM_RADEON) || defined(CONFIG_DRM_RADEON_MODULE) @@ -306,6 +513,12 @@ MODULE_PARM_DESC(si_support, "SI support (1 = enabled (default), 0 = disabled)") module_param_named(si_support, amdgpu_si_support, int, 0444); #endif +/** + * DOC: cik_support (int) + * Set CIK support driver. This parameter works after set config CONFIG_DRM_AMDGPU_CIK. For CIK asic, when radeon driver is enabled, + * set value 0 to use radeon driver, while set value 1 to use amdgpu driver. The default is using radeon driver when it available, + * otherwise using amdgpu driver. + */ #ifdef CONFIG_DRM_AMDGPU_CIK #if defined(CONFIG_DRM_RADEON) || defined(CONFIG_DRM_RADEON_MODULE) @@ -319,6 +532,11 @@ MODULE_PARM_DESC(cik_support, "CIK support (1 = enabled (default), 0 = disabled) module_param_named(cik_support, amdgpu_cik_support, int, 0444); #endif +/** + * DOC: smu_memory_pool_size (uint) + * It is used to reserve gtt for smu debug usage, setting value 0 to disable it. The actual size is value * 256MiB. + * E.g. 0x1 = 256Mbyte, 0x2 = 512Mbyte, 0x4 = 1 Gbyte, 0x8 = 2GByte. The default is 0 (disabled). + */ MODULE_PARM_DESC(smu_memory_pool_size, "reserve gtt for smu debug usage, 0 = disable," "0x1 = 256Mbyte, 0x2 = 512Mbyte, 0x4 = 1 Gbyte, 0x8 = 2GByte"); -- GitLab From 43911fb68b19f7c37ab69eff8e6a3c1370bc0cb5 Mon Sep 17 00:00:00 2001 From: Darren Powell <darren.powell@amd.com> Date: Wed, 27 Jun 2018 17:05:20 -0400 Subject: [PATCH 0830/1506] drm/amd: Add sphinx documentation for amd_ip_funcs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Darren Powell <darren.powell@amd.com> Reviewed-by: Michel Dänzer <michel.daenzer@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/include/amd_shared.h | 45 ++++++++++++++---------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/amd/include/amd_shared.h b/drivers/gpu/drm/amd/include/amd_shared.h index d6f487497397f..265621d8945c3 100644 --- a/drivers/gpu/drm/amd/include/amd_shared.h +++ b/drivers/gpu/drm/amd/include/amd_shared.h @@ -131,45 +131,54 @@ enum PP_FEATURE_MASK { PP_STUTTER_MODE = 0x20000, }; +/** + * struct amd_ip_funcs - general hooks for managing amdgpu IP Blocks + */ struct amd_ip_funcs { - /* Name of IP block */ + /** @name: Name of IP block */ char *name; - /* sets up early driver state (pre sw_init), does not configure hw - Optional */ + /** + * @early_init: + * + * sets up early driver state (pre sw_init), + * does not configure hw - Optional + */ int (*early_init)(void *handle); - /* sets up late driver/hw state (post hw_init) - Optional */ + /** @late_init: sets up late driver/hw state (post hw_init) - Optional */ int (*late_init)(void *handle); - /* sets up driver state, does not configure hw */ + /** @sw_init: sets up driver state, does not configure hw */ int (*sw_init)(void *handle); - /* tears down driver state, does not configure hw */ + /** @sw_fini: tears down driver state, does not configure hw */ int (*sw_fini)(void *handle); - /* sets up the hw state */ + /** @hw_init: sets up the hw state */ int (*hw_init)(void *handle); - /* tears down the hw state */ + /** @hw_fini: tears down the hw state */ int (*hw_fini)(void *handle); + /** @late_fini: final cleanup */ void (*late_fini)(void *handle); - /* handles IP specific hw/sw changes for suspend */ + /** @suspend: handles IP specific hw/sw changes for suspend */ int (*suspend)(void *handle); - /* handles IP specific hw/sw changes for resume */ + /** @resume: handles IP specific hw/sw changes for resume */ int (*resume)(void *handle); - /* returns current IP block idle status */ + /** @is_idle: returns current IP block idle status */ bool (*is_idle)(void *handle); - /* poll for idle */ + /** @wait_for_idle: poll for idle */ int (*wait_for_idle)(void *handle); - /* check soft reset the IP block */ + /** @check_soft_reset: check soft reset the IP block */ bool (*check_soft_reset)(void *handle); - /* pre soft reset the IP block */ + /** @pre_soft_reset: pre soft reset the IP block */ int (*pre_soft_reset)(void *handle); - /* soft reset the IP block */ + /** @soft_reset: soft reset the IP block */ int (*soft_reset)(void *handle); - /* post soft reset the IP block */ + /** @post_soft_reset: post soft reset the IP block */ int (*post_soft_reset)(void *handle); - /* enable/disable cg for the IP block */ + /** @set_clockgating_state: enable/disable cg for the IP block */ int (*set_clockgating_state)(void *handle, enum amd_clockgating_state state); - /* enable/disable pg for the IP block */ + /** @set_powergating_state: enable/disable pg for the IP block */ int (*set_powergating_state)(void *handle, enum amd_powergating_state state); - /* get current clockgating status */ + /** @get_clockgating_state: get current clockgating status */ void (*get_clockgating_state)(void *handle, u32 *flags); }; -- GitLab From c4e4f4545bdc3939ae9fff1da55ed1e28776dafe Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 5 Jul 2018 16:02:14 +0100 Subject: [PATCH 0831/1506] drm/i915/selftests: Fail hangcheck testing if the GPU is wedged If the GPU is irrecoverably wedged on startup, it means that it failed on initialisation and we have already tried to reset it but failed. We can ignore all further testing, as it is already dead. Failing early, prevents us from slowly failing in our endeavours later and timing out. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180705150214.28316-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/selftests/intel_hangcheck.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c index 72547aa24538c..5cb808dc5b500 100644 --- a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c +++ b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c @@ -1243,6 +1243,9 @@ int intel_hangcheck_live_selftests(struct drm_i915_private *i915) if (!intel_has_gpu_reset(i915)) return 0; + if (i915_terminally_wedged(&i915->gpu_error)) + return -EIO; /* we're long past hope of a successful reset */ + intel_runtime_pm_get(i915); saved_hangcheck = fetch_and_zero(&i915_modparams.enable_hangcheck); -- GitLab From ca3589c11815cb1587a908c46e8f04a05a193254 Mon Sep 17 00:00:00 2001 From: Jani Nikula <jani.nikula@intel.com> Date: Thu, 5 Jul 2018 16:25:07 +0300 Subject: [PATCH 0832/1506] drm/i915/dsi: rename the current DSI files based on first platform MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Starting from ICL or gen 11 we have a new DSI block which requires completely different programming from the current implementation. Having them in the same file would be confusing. Rename the current DSI and DSI PLL implementation files as vlv_dsi.c and vlv_dsi_pll.c. No functional changes. v2: use "gen7" prefix. v3: use "vlv" prefix. References: https://patchwork.freedesktop.org/series/44823/ Cc: Madhav Chauhan <madhav.chauhan@intel.com> Cc: Daniel Vetter <daniel@ffwll.ch> Cc: Chris Wilson <chris@chris-wilson.co.uk> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Madhav Chauhan <madhav.chauhan@intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180705132509.12881-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/Makefile | 6 +++--- drivers/gpu/drm/i915/intel_drv.h | 2 +- drivers/gpu/drm/i915/intel_dsi.h | 4 ++-- drivers/gpu/drm/i915/{intel_dsi.c => vlv_dsi.c} | 0 drivers/gpu/drm/i915/{intel_dsi_pll.c => vlv_dsi_pll.c} | 0 5 files changed, 6 insertions(+), 6 deletions(-) rename drivers/gpu/drm/i915/{intel_dsi.c => vlv_dsi.c} (100%) rename drivers/gpu/drm/i915/{intel_dsi_pll.c => vlv_dsi_pll.c} (100%) diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 4c6adae23e18e..e7fedb83aafcd 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -141,9 +141,7 @@ i915-y += dvo_ch7017.o \ intel_dp_link_training.o \ intel_dp_mst.o \ intel_dp.o \ - intel_dsi.o \ intel_dsi_dcs_backlight.o \ - intel_dsi_pll.o \ intel_dsi_vbt.o \ intel_dvo.o \ intel_hdmi.o \ @@ -152,7 +150,9 @@ i915-y += dvo_ch7017.o \ intel_lvds.o \ intel_panel.o \ intel_sdvo.o \ - intel_tv.o + intel_tv.o \ + vlv_dsi.o \ + vlv_dsi_pll.o # Post-mortem debug and GPU hang state capture i915-$(CONFIG_DRM_I915_CAPTURE_ERROR) += i915_gpu_error.o diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index cdfdebc11ef80..88d3581124e87 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1730,7 +1730,7 @@ int intel_dp_aux_init_backlight_funcs(struct intel_connector *intel_connector); /* intel_dp_mst.c */ int intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_id); void intel_dp_mst_encoder_cleanup(struct intel_digital_port *intel_dig_port); -/* intel_dsi.c */ +/* vlv_dsi.c */ void intel_dsi_init(struct drm_i915_private *dev_priv); /* intel_dsi_dcs_backlight.c */ diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h index 7afeb9580f41f..dce9bcc2de533 100644 --- a/drivers/gpu/drm/i915/intel_dsi.h +++ b/drivers/gpu/drm/i915/intel_dsi.h @@ -129,11 +129,11 @@ static inline struct intel_dsi *enc_to_intel_dsi(struct drm_encoder *encoder) return container_of(encoder, struct intel_dsi, base.base); } -/* intel_dsi.c */ +/* vlv_dsi.c */ void wait_for_dsi_fifo_empty(struct intel_dsi *intel_dsi, enum port port); enum mipi_dsi_pixel_format pixel_format_from_register_bits(u32 fmt); -/* intel_dsi_pll.c */ +/* vlv_dsi_pll.c */ bool intel_dsi_pll_is_enabled(struct drm_i915_private *dev_priv); int intel_compute_dsi_pll(struct intel_encoder *encoder, struct intel_crtc_state *config); diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/vlv_dsi.c similarity index 100% rename from drivers/gpu/drm/i915/intel_dsi.c rename to drivers/gpu/drm/i915/vlv_dsi.c diff --git a/drivers/gpu/drm/i915/intel_dsi_pll.c b/drivers/gpu/drm/i915/vlv_dsi_pll.c similarity index 100% rename from drivers/gpu/drm/i915/intel_dsi_pll.c rename to drivers/gpu/drm/i915/vlv_dsi_pll.c -- GitLab From e518634b4366d2fe874d36e6394693b1be0a9f44 Mon Sep 17 00:00:00 2001 From: Jani Nikula <jani.nikula@intel.com> Date: Thu, 5 Jul 2018 16:25:08 +0300 Subject: [PATCH 0833/1506] drm/i915/dsi: use vlv and bxt prefixes for the global DSI functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid confusion with the functions to be added for the new ICL or gen 11 DSI implementation by renaming the current DSI functions. While at it, permutate the words in the function names to make them all start with "vlv_dsi" or "vlv_dsi_pll" etc. Reduce the platform abstractions in the PLL file while at it, moving the checks to vlv_dsi.c instead, where we typically already have the necessary if ladders. Leave the static functions as-is for now; they could be renamed later if needed. No functional changes. v2: use "gen7" prefix. v3: use "vlv" and "bxt" prefixes, reduce the abstractions. References: https://patchwork.freedesktop.org/series/44823/ Cc: Madhav Chauhan <madhav.chauhan@intel.com> Cc: Daniel Vetter <daniel@ffwll.ch> Cc: Chris Wilson <chris@chris-wilson.co.uk> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Madhav Chauhan <madhav.chauhan@intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180705132509.12881-2-jani.nikula@intel.com --- drivers/gpu/drm/i915/intel_display.c | 6 +- drivers/gpu/drm/i915/intel_drv.h | 2 +- drivers/gpu/drm/i915/intel_dsi.h | 30 +++++---- drivers/gpu/drm/i915/intel_dsi_vbt.c | 2 +- drivers/gpu/drm/i915/vlv_dsi.c | 61 ++++++++++------- drivers/gpu/drm/i915/vlv_dsi_pll.c | 98 +++++----------------------- 6 files changed, 80 insertions(+), 119 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 12102224f47ae..d33033abbf185 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9416,7 +9416,7 @@ static bool bxt_get_dsi_transcoder_state(struct intel_crtc *crtc, * registers/MIPI[BXT]. We can break out here early, since we * need the same DSI PLL to be enabled for both DSI ports. */ - if (!intel_dsi_pll_is_enabled(dev_priv)) + if (!bxt_dsi_pll_is_enabled(dev_priv)) break; /* XXX: this works for video mode only */ @@ -14092,7 +14092,7 @@ static void intel_setup_outputs(struct drm_i915_private *dev_priv) intel_ddi_init(dev_priv, PORT_B); intel_ddi_init(dev_priv, PORT_C); - intel_dsi_init(dev_priv); + vlv_dsi_init(dev_priv); } else if (HAS_DDI(dev_priv)) { int found; @@ -14198,7 +14198,7 @@ static void intel_setup_outputs(struct drm_i915_private *dev_priv) intel_hdmi_init(dev_priv, CHV_HDMID, PORT_D); } - intel_dsi_init(dev_priv); + vlv_dsi_init(dev_priv); } else if (!IS_GEN2(dev_priv) && !IS_PINEVIEW(dev_priv)) { bool found = false; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 88d3581124e87..3034477b79ff0 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1731,7 +1731,7 @@ int intel_dp_aux_init_backlight_funcs(struct intel_connector *intel_connector); int intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_id); void intel_dp_mst_encoder_cleanup(struct intel_digital_port *intel_dig_port); /* vlv_dsi.c */ -void intel_dsi_init(struct drm_i915_private *dev_priv); +void vlv_dsi_init(struct drm_i915_private *dev_priv); /* intel_dsi_dcs_backlight.c */ int intel_dsi_dcs_init_backlight_funcs(struct intel_connector *intel_connector); diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h index dce9bcc2de533..ad7c1cb329836 100644 --- a/drivers/gpu/drm/i915/intel_dsi.h +++ b/drivers/gpu/drm/i915/intel_dsi.h @@ -130,20 +130,28 @@ static inline struct intel_dsi *enc_to_intel_dsi(struct drm_encoder *encoder) } /* vlv_dsi.c */ -void wait_for_dsi_fifo_empty(struct intel_dsi *intel_dsi, enum port port); +void vlv_dsi_wait_for_fifo_empty(struct intel_dsi *intel_dsi, enum port port); enum mipi_dsi_pixel_format pixel_format_from_register_bits(u32 fmt); /* vlv_dsi_pll.c */ -bool intel_dsi_pll_is_enabled(struct drm_i915_private *dev_priv); -int intel_compute_dsi_pll(struct intel_encoder *encoder, - struct intel_crtc_state *config); -void intel_enable_dsi_pll(struct intel_encoder *encoder, - const struct intel_crtc_state *config); -void intel_disable_dsi_pll(struct intel_encoder *encoder); -u32 intel_dsi_get_pclk(struct intel_encoder *encoder, int pipe_bpp, - struct intel_crtc_state *config); -void intel_dsi_reset_clocks(struct intel_encoder *encoder, - enum port port); +int vlv_dsi_pll_compute(struct intel_encoder *encoder, + struct intel_crtc_state *config); +void vlv_dsi_pll_enable(struct intel_encoder *encoder, + const struct intel_crtc_state *config); +void vlv_dsi_pll_disable(struct intel_encoder *encoder); +u32 vlv_dsi_get_pclk(struct intel_encoder *encoder, int pipe_bpp, + struct intel_crtc_state *config); +void vlv_dsi_reset_clocks(struct intel_encoder *encoder, enum port port); + +bool bxt_dsi_pll_is_enabled(struct drm_i915_private *dev_priv); +int bxt_dsi_pll_compute(struct intel_encoder *encoder, + struct intel_crtc_state *config); +void bxt_dsi_pll_enable(struct intel_encoder *encoder, + const struct intel_crtc_state *config); +void bxt_dsi_pll_disable(struct intel_encoder *encoder); +u32 bxt_dsi_get_pclk(struct intel_encoder *encoder, int pipe_bpp, + struct intel_crtc_state *config); +void bxt_dsi_reset_clocks(struct intel_encoder *encoder, enum port port); /* intel_dsi_vbt.c */ bool intel_dsi_vbt_init(struct intel_dsi *intel_dsi, u16 panel_id); diff --git a/drivers/gpu/drm/i915/intel_dsi_vbt.c b/drivers/gpu/drm/i915/intel_dsi_vbt.c index 4d6ffa7b3e7b9..ac83d6b89ae0c 100644 --- a/drivers/gpu/drm/i915/intel_dsi_vbt.c +++ b/drivers/gpu/drm/i915/intel_dsi_vbt.c @@ -181,7 +181,7 @@ static const u8 *mipi_exec_send_packet(struct intel_dsi *intel_dsi, break; } - wait_for_dsi_fifo_empty(intel_dsi, port); + vlv_dsi_wait_for_fifo_empty(intel_dsi, port); out: data += len; diff --git a/drivers/gpu/drm/i915/vlv_dsi.c b/drivers/gpu/drm/i915/vlv_dsi.c index 3b7acb5a70b3e..0aa99eeae2715 100644 --- a/drivers/gpu/drm/i915/vlv_dsi.c +++ b/drivers/gpu/drm/i915/vlv_dsi.c @@ -69,7 +69,7 @@ enum mipi_dsi_pixel_format pixel_format_from_register_bits(u32 fmt) } } -void wait_for_dsi_fifo_empty(struct intel_dsi *intel_dsi, enum port port) +void vlv_dsi_wait_for_fifo_empty(struct intel_dsi *intel_dsi, enum port port) { struct drm_encoder *encoder = &intel_dsi->base.base; struct drm_device *dev = encoder->dev; @@ -342,11 +342,15 @@ static bool intel_dsi_compute_config(struct intel_encoder *encoder, pipe_config->cpu_transcoder = TRANSCODER_DSI_C; else pipe_config->cpu_transcoder = TRANSCODER_DSI_A; - } - ret = intel_compute_dsi_pll(encoder, pipe_config); - if (ret) - return false; + ret = bxt_dsi_pll_compute(encoder, pipe_config); + if (ret) + return false; + } else { + ret = vlv_dsi_pll_compute(encoder, pipe_config); + if (ret) + return false; + } pipe_config->clock_set = true; @@ -810,8 +814,13 @@ static void intel_dsi_pre_enable(struct intel_encoder *encoder, * The BIOS may leave the PLL in a wonky state where it doesn't * lock. It needs to be fully powered down to fix it. */ - intel_disable_dsi_pll(encoder); - intel_enable_dsi_pll(encoder, pipe_config); + if (IS_GEN9_LP(dev_priv)) { + bxt_dsi_pll_disable(encoder); + bxt_dsi_pll_enable(encoder, pipe_config); + } else { + vlv_dsi_pll_disable(encoder); + vlv_dsi_pll_enable(encoder, pipe_config); + } if (IS_BROXTON(dev_priv)) { /* Add MIPI IO reset programming for modeset */ @@ -949,7 +958,7 @@ static void intel_dsi_post_disable(struct intel_encoder *encoder, if (is_vid_mode(intel_dsi)) { for_each_dsi_port(port, intel_dsi->ports) - wait_for_dsi_fifo_empty(intel_dsi, port); + vlv_dsi_wait_for_fifo_empty(intel_dsi, port); intel_dsi_port_disable(encoder); usleep_range(2000, 5000); @@ -979,11 +988,13 @@ static void intel_dsi_post_disable(struct intel_encoder *encoder, val & ~MIPIO_RST_CTRL); } - intel_disable_dsi_pll(encoder); - - if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { + if (IS_GEN9_LP(dev_priv)) { + bxt_dsi_pll_disable(encoder); + } else { u32 val; + vlv_dsi_pll_disable(encoder); + val = I915_READ(DSPCLK_GATE_D); val &= ~DPOUNIT_CLOCK_GATE_DISABLE; I915_WRITE(DSPCLK_GATE_D, val); @@ -1024,7 +1035,7 @@ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder, * configuration, otherwise accessing DSI registers will hang the * machine. See BSpec North Display Engine registers/MIPI[BXT]. */ - if (IS_GEN9_LP(dev_priv) && !intel_dsi_pll_is_enabled(dev_priv)) + if (IS_GEN9_LP(dev_priv) && !bxt_dsi_pll_is_enabled(dev_priv)) goto out_put_power; /* XXX: this only works for one DSI output */ @@ -1247,16 +1258,19 @@ static void intel_dsi_get_config(struct intel_encoder *encoder, pipe_config->output_types |= BIT(INTEL_OUTPUT_DSI); - if (IS_GEN9_LP(dev_priv)) + if (IS_GEN9_LP(dev_priv)) { bxt_dsi_get_pipe_config(encoder, pipe_config); + pclk = bxt_dsi_get_pclk(encoder, pipe_config->pipe_bpp, + pipe_config); + } else { + pclk = vlv_dsi_get_pclk(encoder, pipe_config->pipe_bpp, + pipe_config); + } - pclk = intel_dsi_get_pclk(encoder, pipe_config->pipe_bpp, - pipe_config); - if (!pclk) - return; - - pipe_config->base.adjusted_mode.crtc_clock = pclk; - pipe_config->port_clock = pclk; + if (pclk) { + pipe_config->base.adjusted_mode.crtc_clock = pclk; + pipe_config->port_clock = pclk; + } } static enum drm_mode_status @@ -1590,7 +1604,10 @@ static void intel_dsi_unprepare(struct intel_encoder *encoder) /* Panel commands can be sent when clock is in LP11 */ I915_WRITE(MIPI_DEVICE_READY(port), 0x0); - intel_dsi_reset_clocks(encoder, port); + if (IS_GEN9_LP(dev_priv)) + bxt_dsi_reset_clocks(encoder, port); + else + vlv_dsi_reset_clocks(encoder, port); I915_WRITE(MIPI_EOT_DISABLE(port), CLOCKSTOP); val = I915_READ(MIPI_DSI_FUNC_PRG(port)); @@ -1713,7 +1730,7 @@ static void intel_dsi_add_properties(struct intel_connector *connector) } } -void intel_dsi_init(struct drm_i915_private *dev_priv) +void vlv_dsi_init(struct drm_i915_private *dev_priv) { struct drm_device *dev = &dev_priv->drm; struct intel_dsi *intel_dsi; diff --git a/drivers/gpu/drm/i915/vlv_dsi_pll.c b/drivers/gpu/drm/i915/vlv_dsi_pll.c index 2ff2ee7f3b78c..a132a8037ecc6 100644 --- a/drivers/gpu/drm/i915/vlv_dsi_pll.c +++ b/drivers/gpu/drm/i915/vlv_dsi_pll.c @@ -111,8 +111,8 @@ static int dsi_calc_mnp(struct drm_i915_private *dev_priv, * XXX: The muxing and gating is hard coded for now. Need to add support for * sharing PLLs with two DSI outputs. */ -static int vlv_compute_dsi_pll(struct intel_encoder *encoder, - struct intel_crtc_state *config) +int vlv_dsi_pll_compute(struct intel_encoder *encoder, + struct intel_crtc_state *config) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); @@ -142,8 +142,8 @@ static int vlv_compute_dsi_pll(struct intel_encoder *encoder, return 0; } -static void vlv_enable_dsi_pll(struct intel_encoder *encoder, - const struct intel_crtc_state *config) +void vlv_dsi_pll_enable(struct intel_encoder *encoder, + const struct intel_crtc_state *config) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); @@ -175,7 +175,7 @@ static void vlv_enable_dsi_pll(struct intel_encoder *encoder, DRM_DEBUG_KMS("DSI PLL locked\n"); } -static void vlv_disable_dsi_pll(struct intel_encoder *encoder) +void vlv_dsi_pll_disable(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); u32 tmp; @@ -192,7 +192,7 @@ static void vlv_disable_dsi_pll(struct intel_encoder *encoder) mutex_unlock(&dev_priv->sb_lock); } -static bool bxt_dsi_pll_is_enabled(struct drm_i915_private *dev_priv) +bool bxt_dsi_pll_is_enabled(struct drm_i915_private *dev_priv) { bool enabled; u32 val; @@ -229,7 +229,7 @@ static bool bxt_dsi_pll_is_enabled(struct drm_i915_private *dev_priv) return enabled; } -static void bxt_disable_dsi_pll(struct intel_encoder *encoder) +void bxt_dsi_pll_disable(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); u32 val; @@ -261,8 +261,8 @@ static void assert_bpp_mismatch(enum mipi_dsi_pixel_format fmt, int pipe_bpp) bpp, pipe_bpp); } -static u32 vlv_dsi_get_pclk(struct intel_encoder *encoder, int pipe_bpp, - struct intel_crtc_state *config) +u32 vlv_dsi_get_pclk(struct intel_encoder *encoder, int pipe_bpp, + struct intel_crtc_state *config) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); @@ -327,8 +327,8 @@ static u32 vlv_dsi_get_pclk(struct intel_encoder *encoder, int pipe_bpp, return pclk; } -static u32 bxt_dsi_get_pclk(struct intel_encoder *encoder, int pipe_bpp, - struct intel_crtc_state *config) +u32 bxt_dsi_get_pclk(struct intel_encoder *encoder, int pipe_bpp, + struct intel_crtc_state *config) { u32 pclk; u32 dsi_clk; @@ -357,16 +357,7 @@ static u32 bxt_dsi_get_pclk(struct intel_encoder *encoder, int pipe_bpp, return pclk; } -u32 intel_dsi_get_pclk(struct intel_encoder *encoder, int pipe_bpp, - struct intel_crtc_state *config) -{ - if (IS_GEN9_LP(to_i915(encoder->base.dev))) - return bxt_dsi_get_pclk(encoder, pipe_bpp, config); - else - return vlv_dsi_get_pclk(encoder, pipe_bpp, config); -} - -static void vlv_dsi_reset_clocks(struct intel_encoder *encoder, enum port port) +void vlv_dsi_reset_clocks(struct intel_encoder *encoder, enum port port) { u32 temp; struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); @@ -480,8 +471,8 @@ static void bxt_dsi_program_clocks(struct drm_device *dev, enum port port, I915_WRITE(BXT_MIPI_CLOCK_CTL, tmp); } -static int gen9lp_compute_dsi_pll(struct intel_encoder *encoder, - struct intel_crtc_state *config) +int bxt_dsi_pll_compute(struct intel_encoder *encoder, + struct intel_crtc_state *config) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); @@ -528,8 +519,8 @@ static int gen9lp_compute_dsi_pll(struct intel_encoder *encoder, return 0; } -static void gen9lp_enable_dsi_pll(struct intel_encoder *encoder, - const struct intel_crtc_state *config) +void bxt_dsi_pll_enable(struct intel_encoder *encoder, + const struct intel_crtc_state *config) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); @@ -568,52 +559,7 @@ static void gen9lp_enable_dsi_pll(struct intel_encoder *encoder, DRM_DEBUG_KMS("DSI PLL locked\n"); } -bool intel_dsi_pll_is_enabled(struct drm_i915_private *dev_priv) -{ - if (IS_GEN9_LP(dev_priv)) - return bxt_dsi_pll_is_enabled(dev_priv); - - MISSING_CASE(INTEL_DEVID(dev_priv)); - - return false; -} - -int intel_compute_dsi_pll(struct intel_encoder *encoder, - struct intel_crtc_state *config) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - - if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) - return vlv_compute_dsi_pll(encoder, config); - else if (IS_GEN9_LP(dev_priv)) - return gen9lp_compute_dsi_pll(encoder, config); - - return -ENODEV; -} - -void intel_enable_dsi_pll(struct intel_encoder *encoder, - const struct intel_crtc_state *config) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - - if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) - vlv_enable_dsi_pll(encoder, config); - else if (IS_GEN9_LP(dev_priv)) - gen9lp_enable_dsi_pll(encoder, config); -} - -void intel_disable_dsi_pll(struct intel_encoder *encoder) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - - if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) - vlv_disable_dsi_pll(encoder); - else if (IS_GEN9_LP(dev_priv)) - bxt_disable_dsi_pll(encoder); -} - -static void gen9lp_dsi_reset_clocks(struct intel_encoder *encoder, - enum port port) +void bxt_dsi_reset_clocks(struct intel_encoder *encoder, enum port port) { u32 tmp; struct drm_device *dev = encoder->base.dev; @@ -638,13 +584,3 @@ static void gen9lp_dsi_reset_clocks(struct intel_encoder *encoder, } I915_WRITE(MIPI_EOT_DISABLE(port), CLOCKSTOP); } - -void intel_dsi_reset_clocks(struct intel_encoder *encoder, enum port port) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - - if (IS_GEN9_LP(dev_priv)) - gen9lp_dsi_reset_clocks(encoder, port); - else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) - vlv_dsi_reset_clocks(encoder, port); -} -- GitLab From 012bf847d1396e4cf2503e298ca49b3dc4591755 Mon Sep 17 00:00:00 2001 From: Jani Nikula <jani.nikula@intel.com> Date: Thu, 5 Jul 2018 16:25:09 +0300 Subject: [PATCH 0834/1506] drm/i915/dsi: update some of the platform based checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the more customary order of latest platform first, and don't bother with an if in the last branch. Cc: Madhav Chauhan <madhav.chauhan@intel.com> Cc: Daniel Vetter <daniel@ffwll.ch> Cc: Chris Wilson <chris@chris-wilson.co.uk> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Madhav Chauhan <madhav.chauhan@intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180705132509.12881-3-jani.nikula@intel.com --- drivers/gpu/drm/i915/vlv_dsi.c | 56 ++++++++++++++++------------------ 1 file changed, 26 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/i915/vlv_dsi.c b/drivers/gpu/drm/i915/vlv_dsi.c index 0aa99eeae2715..435a2c35ee8c4 100644 --- a/drivers/gpu/drm/i915/vlv_dsi.c +++ b/drivers/gpu/drm/i915/vlv_dsi.c @@ -550,12 +550,12 @@ static void intel_dsi_device_ready(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) - vlv_dsi_device_ready(encoder); - else if (IS_BROXTON(dev_priv)) - bxt_dsi_device_ready(encoder); - else if (IS_GEMINILAKE(dev_priv)) + if (IS_GEMINILAKE(dev_priv)) glk_dsi_device_ready(encoder); + else if (IS_GEN9_LP(dev_priv)) + bxt_dsi_device_ready(encoder); + else + vlv_dsi_device_ready(encoder); } static void glk_dsi_enter_low_power_mode(struct intel_encoder *encoder) @@ -938,11 +938,10 @@ static void intel_dsi_clear_device_ready(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv) || - IS_BROXTON(dev_priv)) - vlv_dsi_clear_device_ready(encoder); - else if (IS_GEMINILAKE(dev_priv)) + if (IS_GEMINILAKE(dev_priv)) glk_dsi_clear_device_ready(encoder); + else + vlv_dsi_clear_device_ready(encoder); } static void intel_dsi_post_disable(struct intel_encoder *encoder, @@ -1599,23 +1598,24 @@ static void intel_dsi_unprepare(struct intel_encoder *encoder) enum port port; u32 val; - if (!IS_GEMINILAKE(dev_priv)) { - for_each_dsi_port(port, intel_dsi->ports) { - /* Panel commands can be sent when clock is in LP11 */ - I915_WRITE(MIPI_DEVICE_READY(port), 0x0); + if (IS_GEMINILAKE(dev_priv)) + return; - if (IS_GEN9_LP(dev_priv)) - bxt_dsi_reset_clocks(encoder, port); - else - vlv_dsi_reset_clocks(encoder, port); - I915_WRITE(MIPI_EOT_DISABLE(port), CLOCKSTOP); + for_each_dsi_port(port, intel_dsi->ports) { + /* Panel commands can be sent when clock is in LP11 */ + I915_WRITE(MIPI_DEVICE_READY(port), 0x0); - val = I915_READ(MIPI_DSI_FUNC_PRG(port)); - val &= ~VID_MODE_FORMAT_MASK; - I915_WRITE(MIPI_DSI_FUNC_PRG(port), val); + if (IS_GEN9_LP(dev_priv)) + bxt_dsi_reset_clocks(encoder, port); + else + vlv_dsi_reset_clocks(encoder, port); + I915_WRITE(MIPI_EOT_DISABLE(port), CLOCKSTOP); - I915_WRITE(MIPI_DEVICE_READY(port), 0x1); - } + val = I915_READ(MIPI_DSI_FUNC_PRG(port)); + val &= ~VID_MODE_FORMAT_MASK; + I915_WRITE(MIPI_DSI_FUNC_PRG(port), val); + + I915_WRITE(MIPI_DEVICE_READY(port), 0x1); } } @@ -1747,14 +1747,10 @@ void vlv_dsi_init(struct drm_i915_private *dev_priv) if (!intel_bios_is_dsi_present(dev_priv, &port)) return; - if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { - dev_priv->mipi_mmio_base = VLV_MIPI_BASE; - } else if (IS_GEN9_LP(dev_priv)) { + if (IS_GEN9_LP(dev_priv)) dev_priv->mipi_mmio_base = BXT_MIPI_BASE; - } else { - DRM_ERROR("Unsupported Mipi device to reg base"); - return; - } + else + dev_priv->mipi_mmio_base = VLV_MIPI_BASE; intel_dsi = kzalloc(sizeof(*intel_dsi), GFP_KERNEL); if (!intel_dsi) -- GitLab From f8878bb2f8675e3c7716906b9b41bddc9b3bc039 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard <benjamin.gaignard@linaro.org> Date: Tue, 5 Jun 2018 15:54:01 +0200 Subject: [PATCH 0835/1506] drm: print plane state normalized zpos value When dumping plane state print normalized zpos value as done for the other plane state fields. Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org> Reviewed-by: Philippe Cornu <philippe.cornu@st.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180605135407.20214-2-benjamin.gaignard@linaro.org --- drivers/gpu/drm/drm_atomic.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index d5cefb1cb2a24..7c55991170cc8 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1111,6 +1111,7 @@ static void drm_atomic_plane_print_state(struct drm_printer *p, drm_printf(p, "\tcrtc-pos=" DRM_RECT_FMT "\n", DRM_RECT_ARG(&dest)); drm_printf(p, "\tsrc-pos=" DRM_RECT_FP_FMT "\n", DRM_RECT_FP_ARG(&src)); drm_printf(p, "\trotation=%x\n", state->rotation); + drm_printf(p, "\tnormalized-zpos=%x\n", state->normalized_zpos); drm_printf(p, "\tcolor-encoding=%s\n", drm_get_color_encoding_name(state->color_encoding)); drm_printf(p, "\tcolor-range=%s\n", -- GitLab From 7868e5079228b4c07cf61b5ad5d35af5c29f7375 Mon Sep 17 00:00:00 2001 From: Yannick Fertre <yannick.fertre@st.com> Date: Fri, 29 Jun 2018 13:22:22 +0200 Subject: [PATCH 0836/1506] drm/stm: ltdc: filter mode pixel clock vs pad constraint Filter the requested mode pixel clock frequency according to the pad maximum supported frequency. Signed-off-by: Yannick Fertre <yannick.fertre@st.com> Reviewed-by: Philippe Cornu <philippe.cornu@st.com> Tested-by: Philippe Cornu <philippe.cornu@st.com> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org> Link: https://patchwork.freedesktop.org/patch/msgid/1530271342-5532-1-git-send-email-yannick.fertre@st.com --- drivers/gpu/drm/stm/ltdc.c | 16 ++++++++++++---- drivers/gpu/drm/stm/ltdc.h | 1 + 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c index d997a6014d6c2..f1f37336a57ad 100644 --- a/drivers/gpu/drm/stm/ltdc.c +++ b/drivers/gpu/drm/stm/ltdc.c @@ -457,6 +457,14 @@ ltdc_crtc_mode_valid(struct drm_crtc *crtc, int target_max = target + CLK_TOLERANCE_HZ; int result; + result = clk_round_rate(ldev->pixel_clk, target); + + DRM_DEBUG_DRIVER("clk rate target %d, available %d\n", target, result); + + /* Filter modes according to the max frequency supported by the pads */ + if (result > ldev->caps.pad_max_freq_hz) + return MODE_CLOCK_HIGH; + /* * Accept all "preferred" modes: * - this is important for panels because panel clock tolerances are @@ -468,10 +476,6 @@ ltdc_crtc_mode_valid(struct drm_crtc *crtc, if (mode->type & DRM_MODE_TYPE_PREFERRED) return MODE_OK; - result = clk_round_rate(ldev->pixel_clk, target); - - DRM_DEBUG_DRIVER("clk rate target %d, available %d\n", target, result); - /* * Filter modes according to the clock value, particularly useful for * hdmi modes that require precise pixel clocks. @@ -991,11 +995,15 @@ static int ltdc_get_caps(struct drm_device *ddev) * does not work on 2nd layer. */ ldev->caps.non_alpha_only_l1 = true; + ldev->caps.pad_max_freq_hz = 90000000; + if (ldev->caps.hw_version == HWVER_10200) + ldev->caps.pad_max_freq_hz = 65000000; break; case HWVER_20101: ldev->caps.reg_ofs = REG_OFS_4; ldev->caps.pix_fmt_hw = ltdc_pix_fmt_a1; ldev->caps.non_alpha_only_l1 = false; + ldev->caps.pad_max_freq_hz = 150000000; break; default: return -ENODEV; diff --git a/drivers/gpu/drm/stm/ltdc.h b/drivers/gpu/drm/stm/ltdc.h index 1e16d6afb0d2f..d5afb89608671 100644 --- a/drivers/gpu/drm/stm/ltdc.h +++ b/drivers/gpu/drm/stm/ltdc.h @@ -18,6 +18,7 @@ struct ltdc_caps { u32 bus_width; /* bus width (32 or 64 bits) */ const u32 *pix_fmt_hw; /* supported pixel formats */ bool non_alpha_only_l1; /* non-native no-alpha formats on layer 1 */ + int pad_max_freq_hz; /* max frequency supported by pad */ }; #define LTDC_MAX_LAYER 4 -- GitLab From 8adbbb2e7871e76d53ea91e6159864ee534fdac8 Mon Sep 17 00:00:00 2001 From: Yannick Fertre <yannick.fertre@st.com> Date: Fri, 29 Jun 2018 13:22:35 +0200 Subject: [PATCH 0837/1506] drm/stm: ltdc: rework reset sequence Reset must be properly assert before deassert. This is important if there is an early boot splash screen before the kernel start up. Signed-off-by: Yannick Fertre <yannick.fertre@st.com> Reviewed-by: Philippe Cornu <philippe.cornu@st.com> Tested-by: Philippe Cornu <philippe.cornu@st.com> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org> Link: https://patchwork.freedesktop.org/patch/msgid/1530271355-5608-1-git-send-email-yannick.fertre@st.com --- drivers/gpu/drm/stm/ltdc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c index f1f37336a57ad..808d9fb627e97 100644 --- a/drivers/gpu/drm/stm/ltdc.c +++ b/drivers/gpu/drm/stm/ltdc.c @@ -1082,8 +1082,11 @@ int ltdc_load(struct drm_device *ddev) } } - if (!IS_ERR(rstc)) + if (!IS_ERR(rstc)) { + reset_control_assert(rstc); + usleep_range(10, 20); reset_control_deassert(rstc); + } /* Disable interrupts */ reg_clear(ldev->regs, LTDC_IER, -- GitLab From fcfe0bdcb1911a4ff6ab6b6264e3323745178025 Mon Sep 17 00:00:00 2001 From: Madhav Chauhan <madhav.chauhan@intel.com> Date: Thu, 5 Jul 2018 19:19:33 +0530 Subject: [PATCH 0838/1506] drm/i915/icl: Program DSI Escape clock Divider Escape Clock is used for LP communication across the DSI Link. To achieve the constant frequency of the escape clock from the variable DPLL frequency output, a variable divider(M) is needed. This patch programs the same. v2: (Jani N) Don't end line with "(". Signed-off-by: Madhav Chauhan <madhav.chauhan@intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: http://patchwork.freedesktop.org/patch/msgid/1530798591-2077-3-git-send-email-madhav.chauhan@intel.com --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/icl_dsi.c | 64 +++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+) create mode 100644 drivers/gpu/drm/i915/icl_dsi.c diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index e7fedb83aafcd..5794f102f9b8f 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -135,6 +135,7 @@ i915-y += dvo_ch7017.o \ dvo_ns2501.o \ dvo_sil164.o \ dvo_tfp410.o \ + icl_dsi.o \ intel_crt.o \ intel_ddi.o \ intel_dp_aux_backlight.o \ diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index dc953ee7e3b3a..a35f4142cced5 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -9552,6 +9552,7 @@ enum skl_power_gate { #define ICL_BYTE_CLK_PER_ESC_CLK_SHIFT 16 #define ICL_ESC_CLK_DIV_MASK 0x1ff #define ICL_ESC_CLK_DIV_SHIFT 0 +#define DSI_MAX_ESC_CLK 20000 /* in KHz */ /* Gen4+ Timestamp and Pipe Frame time stamp registers */ #define GEN4_TIMESTAMP _MMIO(0x2358) diff --git a/drivers/gpu/drm/i915/icl_dsi.c b/drivers/gpu/drm/i915/icl_dsi.c new file mode 100644 index 0000000000000..1eb4ac30e400a --- /dev/null +++ b/drivers/gpu/drm/i915/icl_dsi.c @@ -0,0 +1,64 @@ +/* + * Copyright © 2018 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Madhav Chauhan <madhav.chauhan@intel.com> + * Jani Nikula <jani.nikula@intel.com> + */ + +#include "intel_dsi.h" + +static void gen11_dsi_program_esc_clk_div(struct intel_encoder *encoder) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + enum port port; + u32 bpp = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format); + u32 afe_clk_khz; /* 8X Clock */ + u32 esc_clk_div_m; + + afe_clk_khz = DIV_ROUND_CLOSEST(intel_dsi->pclk * bpp, + intel_dsi->lane_count); + + esc_clk_div_m = DIV_ROUND_UP(afe_clk_khz, DSI_MAX_ESC_CLK); + + for_each_dsi_port(port, intel_dsi->ports) { + I915_WRITE(ICL_DSI_ESC_CLK_DIV(port), + esc_clk_div_m & ICL_ESC_CLK_DIV_MASK); + POSTING_READ(ICL_DSI_ESC_CLK_DIV(port)); + } + + for_each_dsi_port(port, intel_dsi->ports) { + I915_WRITE(ICL_DPHY_ESC_CLK_DIV(port), + esc_clk_div_m & ICL_ESC_CLK_DIV_MASK); + POSTING_READ(ICL_DPHY_ESC_CLK_DIV(port)); + } +} + +static void __attribute__((unused)) +gen11_dsi_pre_enable(struct intel_encoder *encoder, + const struct intel_crtc_state *pipe_config, + const struct drm_connector_state *conn_state) +{ + /* step3: enable DSI PLL */ + gen11_dsi_program_esc_clk_div(encoder); +} -- GitLab From 21652f3b0d48749e3ba0d332d2b39cc18eacb1c0 Mon Sep 17 00:00:00 2001 From: Madhav Chauhan <madhav.chauhan@intel.com> Date: Thu, 5 Jul 2018 19:19:34 +0530 Subject: [PATCH 0839/1506] drm/i915/icl: Define DSI mode ctl register This patch defines DSI IO mode control register and it's bits used while enabling IO power for DSI. Signed-off-by: Madhav Chauhan <madhav.chauhan@intel.com> Reviewed-by: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/1530798591-2077-4-git-send-email-madhav.chauhan@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index a35f4142cced5..eb3b7544a875b 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -9688,6 +9688,14 @@ enum skl_power_gate { #define _BXT_MIPIC_PORT_CTRL 0x6B8C0 #define BXT_MIPI_PORT_CTRL(tc) _MMIO_MIPI(tc, _BXT_MIPIA_PORT_CTRL, _BXT_MIPIC_PORT_CTRL) +/* ICL DSI MODE control */ +#define _ICL_DSI_IO_MODECTL_0 0x6B094 +#define _ICL_DSI_IO_MODECTL_1 0x6B894 +#define ICL_DSI_IO_MODECTL(port) _MMIO_PORT(port, \ + _ICL_DSI_IO_MODECTL_0, \ + _ICL_DSI_IO_MODECTL_1) +#define COMBO_PHY_MODE_DSI (1 << 0) + #define BXT_P_DSI_REGULATOR_CFG _MMIO(0x160020) #define STAP_SELECT (1 << 0) -- GitLab From b1cb21a5f1c668534b25464717c806e141ba500f Mon Sep 17 00:00:00 2001 From: Madhav Chauhan <madhav.chauhan@intel.com> Date: Thu, 5 Jul 2018 19:19:35 +0530 Subject: [PATCH 0840/1506] drm/i915/icl: Enable DSI IO power This patch configures mode of operation for DSI and enable DDI IO power by configuring power well. v2: Use for_each_dsi_port() for power get (Jani N) Signed-off-by: Madhav Chauhan <madhav.chauhan@intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/1530798591-2077-5-git-send-email-madhav.chauhan@intel.com --- drivers/gpu/drm/i915/icl_dsi.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/gpu/drm/i915/icl_dsi.c b/drivers/gpu/drm/i915/icl_dsi.c index 1eb4ac30e400a..774ab262c8f3d 100644 --- a/drivers/gpu/drm/i915/icl_dsi.c +++ b/drivers/gpu/drm/i915/icl_dsi.c @@ -54,11 +54,34 @@ static void gen11_dsi_program_esc_clk_div(struct intel_encoder *encoder) } } +static void gen11_dsi_enable_io_power(struct intel_encoder *encoder) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + enum port port; + u32 tmp; + + for_each_dsi_port(port, intel_dsi->ports) { + tmp = I915_READ(ICL_DSI_IO_MODECTL(port)); + tmp |= COMBO_PHY_MODE_DSI; + I915_WRITE(ICL_DSI_IO_MODECTL(port), tmp); + } + + for_each_dsi_port(port, intel_dsi->ports) { + intel_display_power_get(dev_priv, port == PORT_A ? + POWER_DOMAIN_PORT_DDI_A_IO : + POWER_DOMAIN_PORT_DDI_B_IO); + } +} + static void __attribute__((unused)) gen11_dsi_pre_enable(struct intel_encoder *encoder, const struct intel_crtc_state *pipe_config, const struct drm_connector_state *conn_state) { + /* step2: enable IO power */ + gen11_dsi_enable_io_power(encoder); + /* step3: enable DSI PLL */ gen11_dsi_program_esc_clk_div(encoder); } -- GitLab From 166869b390b6fe763544fe4ae1e01acd28db331a Mon Sep 17 00:00:00 2001 From: Madhav Chauhan <madhav.chauhan@intel.com> Date: Thu, 5 Jul 2018 19:19:36 +0530 Subject: [PATCH 0841/1506] drm/i915/icl: Define PORT_CL_DW_10 register This register used to power down individual lanes for DDI/DSI ports. Bitfields to power up/down various combinations of lanes are also added in this patch. v2: Review comments from Jani N - Use override instead of "override" for bitfields - Define mask for override bitfield - Define PWR_DOWN_LN* macros shifted in place v3: Correct PWR_DOWN_LN_MASK value (Jani N) Signed-off-by: Madhav Chauhan <madhav.chauhan@intel.com> Reviewed-by: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/1530798591-2077-6-git-send-email-madhav.chauhan@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index eb3b7544a875b..3ad5dcb21a7a0 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1720,6 +1720,26 @@ enum i915_power_well_id { #define ICL_PORT_CL_DW5(port) _MMIO_PORT(port, _ICL_PORT_CL_DW5_A, \ _ICL_PORT_CL_DW5_B) +#define _CNL_PORT_CL_DW10_A 0x162028 +#define _ICL_PORT_CL_DW10_B 0x6c028 +#define ICL_PORT_CL_DW10(port) _MMIO_PORT(port, \ + _CNL_PORT_CL_DW10_A, \ + _ICL_PORT_CL_DW10_B) +#define PG_SEQ_DELAY_OVERRIDE_MASK (3 << 25) +#define PG_SEQ_DELAY_OVERRIDE_SHIFT 25 +#define PG_SEQ_DELAY_OVERRIDE_ENABLE (1 << 24) +#define PWR_UP_ALL_LANES (0x0 << 4) +#define PWR_DOWN_LN_3_2_1 (0xe << 4) +#define PWR_DOWN_LN_3_2 (0xc << 4) +#define PWR_DOWN_LN_3 (0x8 << 4) +#define PWR_DOWN_LN_2_1_0 (0x7 << 4) +#define PWR_DOWN_LN_1_0 (0x3 << 4) +#define PWR_DOWN_LN_1 (0x2 << 4) +#define PWR_DOWN_LN_3_1 (0xa << 4) +#define PWR_DOWN_LN_3_1_0 (0xb << 4) +#define PWR_DOWN_LN_MASK (0xf << 4) +#define PWR_DOWN_LN_SHIFT 4 + #define _PORT_CL1CM_DW9_A 0x162024 #define _PORT_CL1CM_DW9_BC 0x6C024 #define IREF0RC_OFFSET_SHIFT 8 -- GitLab From 45f09f7adc8a10138b158c5805a4d3b20aac611a Mon Sep 17 00:00:00 2001 From: Madhav Chauhan <madhav.chauhan@intel.com> Date: Thu, 5 Jul 2018 19:19:37 +0530 Subject: [PATCH 0842/1506] drm/i915/icl: Power down unused DSI lanes To save power, unused lanes should be powered down using the bitfield of PORT_CL_DW10. v2: Review comments from Jani N - Put default label next to case 4 - Include the shifts in the macros Signed-off-by: Madhav Chauhan <madhav.chauhan@intel.com> Reviewed-by: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/1530798591-2077-7-git-send-email-madhav.chauhan@intel.com --- drivers/gpu/drm/i915/icl_dsi.c | 40 ++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/drivers/gpu/drm/i915/icl_dsi.c b/drivers/gpu/drm/i915/icl_dsi.c index 774ab262c8f3d..13830e43a4d12 100644 --- a/drivers/gpu/drm/i915/icl_dsi.c +++ b/drivers/gpu/drm/i915/icl_dsi.c @@ -74,6 +74,43 @@ static void gen11_dsi_enable_io_power(struct intel_encoder *encoder) } } +static void gen11_dsi_power_up_lanes(struct intel_encoder *encoder) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + enum port port; + u32 tmp; + u32 lane_mask; + + switch (intel_dsi->lane_count) { + case 1: + lane_mask = PWR_DOWN_LN_3_1_0; + break; + case 2: + lane_mask = PWR_DOWN_LN_3_1; + break; + case 3: + lane_mask = PWR_DOWN_LN_3; + break; + case 4: + default: + lane_mask = PWR_UP_ALL_LANES; + break; + } + + for_each_dsi_port(port, intel_dsi->ports) { + tmp = I915_READ(ICL_PORT_CL_DW10(port)); + tmp &= ~PWR_DOWN_LN_MASK; + I915_WRITE(ICL_PORT_CL_DW10(port), tmp | lane_mask); + } +} + +static void gen11_dsi_enable_port_and_phy(struct intel_encoder *encoder) +{ + /* step 4a: power up all lanes of the DDI used by DSI */ + gen11_dsi_power_up_lanes(encoder); +} + static void __attribute__((unused)) gen11_dsi_pre_enable(struct intel_encoder *encoder, const struct intel_crtc_state *pipe_config, @@ -84,4 +121,7 @@ gen11_dsi_pre_enable(struct intel_encoder *encoder, /* step3: enable DSI PLL */ gen11_dsi_program_esc_clk_div(encoder); + + /* step4: enable DSI port and DPHY */ + gen11_dsi_enable_port_and_phy(encoder); } -- GitLab From d61d1b3bbba1054a7a326c18a3c66f822f9fa338 Mon Sep 17 00:00:00 2001 From: Madhav Chauhan <madhav.chauhan@intel.com> Date: Thu, 5 Jul 2018 19:19:38 +0530 Subject: [PATCH 0843/1506] drm/i915/icl: Define AUX lane registers for Port A/B This patch defines AUX lane registers for PORT_PCS_DW1, PORT_TX_DW2, PORT_TX_DW4, PORT_TX_DW5 used during dsi enabling. v2: Review comments from Jani N: - Define _ICL_PORT_PCS_DW1_AUX_A for consistency - Three spaces for bitfield definition. Signed-off-by: Madhav Chauhan <madhav.chauhan@intel.com> Reviewed-by: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/1530798591-2077-8-git-send-email-madhav.chauhan@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 3ad5dcb21a7a0..0424e45f88dbc 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1796,16 +1796,22 @@ enum i915_power_well_id { _CNL_PORT_PCS_DW1_LN0_D, \ _CNL_PORT_PCS_DW1_LN0_AE, \ _CNL_PORT_PCS_DW1_LN0_F)) + #define _ICL_PORT_PCS_DW1_GRP_A 0x162604 #define _ICL_PORT_PCS_DW1_GRP_B 0x6C604 #define _ICL_PORT_PCS_DW1_LN0_A 0x162804 #define _ICL_PORT_PCS_DW1_LN0_B 0x6C804 +#define _ICL_PORT_PCS_DW1_AUX_A 0x162304 +#define _ICL_PORT_PCS_DW1_AUX_B 0x6c304 #define ICL_PORT_PCS_DW1_GRP(port) _MMIO_PORT(port,\ _ICL_PORT_PCS_DW1_GRP_A, \ _ICL_PORT_PCS_DW1_GRP_B) #define ICL_PORT_PCS_DW1_LN0(port) _MMIO_PORT(port, \ _ICL_PORT_PCS_DW1_LN0_A, \ _ICL_PORT_PCS_DW1_LN0_B) +#define ICL_PORT_PCS_DW1_AUX(port) _MMIO_PORT(port, \ + _ICL_PORT_PCS_DW1_AUX_A, \ + _ICL_PORT_PCS_DW1_AUX_B) #define COMMON_KEEPER_EN (1 << 26) /* CNL Port TX registers */ @@ -1842,16 +1848,23 @@ enum i915_power_well_id { #define _ICL_PORT_TX_DW2_GRP_B 0x6C688 #define _ICL_PORT_TX_DW2_LN0_A 0x162888 #define _ICL_PORT_TX_DW2_LN0_B 0x6C888 +#define _ICL_PORT_TX_DW2_AUX_A 0x162388 +#define _ICL_PORT_TX_DW2_AUX_B 0x6c388 #define ICL_PORT_TX_DW2_GRP(port) _MMIO_PORT(port, \ _ICL_PORT_TX_DW2_GRP_A, \ _ICL_PORT_TX_DW2_GRP_B) #define ICL_PORT_TX_DW2_LN0(port) _MMIO_PORT(port, \ _ICL_PORT_TX_DW2_LN0_A, \ _ICL_PORT_TX_DW2_LN0_B) +#define ICL_PORT_TX_DW2_AUX(port) _MMIO_PORT(port, \ + _ICL_PORT_TX_DW2_AUX_A, \ + _ICL_PORT_TX_DW2_AUX_B) #define SWING_SEL_UPPER(x) (((x) >> 3) << 15) #define SWING_SEL_UPPER_MASK (1 << 15) #define SWING_SEL_LOWER(x) (((x) & 0x7) << 11) #define SWING_SEL_LOWER_MASK (0x7 << 11) +#define FRC_LATENCY_OPTIM_MASK (0x7 << 8) +#define FRC_LATENCY_OPTIM_VAL(x) ((x) << 8) #define RCOMP_SCALAR(x) ((x) << 0) #define RCOMP_SCALAR_MASK (0xFF << 0) @@ -1867,6 +1880,8 @@ enum i915_power_well_id { #define _ICL_PORT_TX_DW4_LN0_A 0x162890 #define _ICL_PORT_TX_DW4_LN1_A 0x162990 #define _ICL_PORT_TX_DW4_LN0_B 0x6C890 +#define _ICL_PORT_TX_DW4_AUX_A 0x162390 +#define _ICL_PORT_TX_DW4_AUX_B 0x6c390 #define ICL_PORT_TX_DW4_GRP(port) _MMIO_PORT(port, \ _ICL_PORT_TX_DW4_GRP_A, \ _ICL_PORT_TX_DW4_GRP_B) @@ -1875,6 +1890,9 @@ enum i915_power_well_id { _ICL_PORT_TX_DW4_LN0_B) + \ ((ln) * (_ICL_PORT_TX_DW4_LN1_A - \ _ICL_PORT_TX_DW4_LN0_A))) +#define ICL_PORT_TX_DW4_AUX(port) _MMIO_PORT(port, \ + _ICL_PORT_TX_DW4_AUX_A, \ + _ICL_PORT_TX_DW4_AUX_B) #define LOADGEN_SELECT (1 << 31) #define POST_CURSOR_1(x) ((x) << 12) #define POST_CURSOR_1_MASK (0x3F << 12) @@ -1889,12 +1907,17 @@ enum i915_power_well_id { #define _ICL_PORT_TX_DW5_GRP_B 0x6C694 #define _ICL_PORT_TX_DW5_LN0_A 0x162894 #define _ICL_PORT_TX_DW5_LN0_B 0x6C894 +#define _ICL_PORT_TX_DW5_AUX_A 0x162394 +#define _ICL_PORT_TX_DW5_AUX_B 0x6c394 #define ICL_PORT_TX_DW5_GRP(port) _MMIO_PORT(port, \ _ICL_PORT_TX_DW5_GRP_A, \ _ICL_PORT_TX_DW5_GRP_B) #define ICL_PORT_TX_DW5_LN0(port) _MMIO_PORT(port, \ _ICL_PORT_TX_DW5_LN0_A, \ _ICL_PORT_TX_DW5_LN0_B) +#define ICL_PORT_TX_DW5_AUX(port) _MMIO_PORT(port, \ + _ICL_PORT_TX_DW5_AUX_A, \ + _ICL_PORT_TX_DW5_AUX_B) #define TX_TRAINING_EN (1 << 31) #define TAP2_DISABLE (1 << 30) #define TAP3_DISABLE (1 << 29) -- GitLab From 1eca65d922d7543b60610624afd345b4f3d71ae2 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 6 Jul 2018 07:53:06 +0100 Subject: [PATCH 0844/1506] drm/i915: Squelch very verbose error logging Having found the error causing the IGT test to fail, downgrade the verbose logging so that we stop flooding the syslogs as we deliberately provoke it many thousands of time during selftests. References: 10195b1e4411 ("drm/i915: Show vma allocator stack when in doubt") Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Matthew Auld <matthew.auld@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180706065332.15214-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/Kconfig.debug | 12 ++++++++++++ drivers/gpu/drm/i915/i915_vma.c | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/Kconfig.debug b/drivers/gpu/drm/i915/Kconfig.debug index 80efee1ff7f38..96b577f627529 100644 --- a/drivers/gpu/drm/i915/Kconfig.debug +++ b/drivers/gpu/drm/i915/Kconfig.debug @@ -51,6 +51,18 @@ config DRM_I915_DEBUG_GEM If in doubt, say "N". +config DRM_I915_ERRLOG_GEM + bool "Insert extra logging (very verbose) for common GEM errors" + default n + depends on DRM_I915_DEBUG_GEM + help + Enable additional logging that may help track down the cause of + principally userspace errors. + + Recommended for driver developers only. + + If in doubt, say "N". + config DRM_I915_TRACE_GEM bool "Insert extra ftrace output from the GEM internals" depends on DRM_I915_DEBUG_GEM diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c index de2b6d65e865e..518de47111ff2 100644 --- a/drivers/gpu/drm/i915/i915_vma.c +++ b/drivers/gpu/drm/i915/i915_vma.c @@ -30,7 +30,7 @@ #include <drm/drm_gem.h> -#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM) && IS_ENABLED(CONFIG_DRM_DEBUG_MM) +#if IS_ENABLED(CONFIG_DRM_I915_ERRLOG_GEM) && IS_ENABLED(CONFIG_DRM_DEBUG_MM) #include <linux/stackdepot.h> -- GitLab From e5d2435bfaeee3f4045e03441d3902c63254b618 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 6 Jul 2018 07:53:07 +0100 Subject: [PATCH 0845/1506] drm/i915/selftests: Destroy partial tiling vma after use As we keep VMA around until the object is destroyed, when testing partial tiling we instantiate many, many VMA (as the object is huge allowing for many different partial regions). We test elsewhere our handling of populating large objects with a full set of VMA and checking we can retrieve them afterwards, but in this test we incur the cost of flushing all VMA after every GTT write, dramatically slowing down the test. References: https://bugs.freedesktop.org/show_bug.cgi?id=107130 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Matthew Auld <matthew.auld@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180706065332.15214-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/selftests/i915_gem_object.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_object.c b/drivers/gpu/drm/i915/selftests/i915_gem_object.c index 8851532689680..232e5ccf1852f 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_object.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_object.c @@ -288,6 +288,8 @@ static int check_partial_mapping(struct drm_i915_gem_object *obj, kunmap(p); if (err) return err; + + i915_vma_destroy(vma); } return 0; -- GitLab From b5f6e53d4cd58043e2c4e1b60fd446924cf56cbe Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 6 Jul 2018 07:53:08 +0100 Subject: [PATCH 0846/1506] drm/i915/selftests: Skip using the GPU if wedged If the GPU is irrecoverably broken, we can not use it to dirty memory and check for cache coherency with the CPU. All we can do is simply skip over the GPU subtests and focus on the CPU domains (WC, WB) cache management. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=107127 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Matthew Auld <matthew.auld@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180706065332.15214-3-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/selftests/i915_gem_coherency.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c b/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c index a4900091ae3dc..cb9eef1635e10 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c @@ -239,8 +239,16 @@ static bool always_valid(struct drm_i915_private *i915) return true; } +static bool needs_fence_registers(struct drm_i915_private *i915) +{ + return !i915_terminally_wedged(&i915->gpu_error); +} + static bool needs_mi_store_dword(struct drm_i915_private *i915) { + if (i915_terminally_wedged(&i915->gpu_error)) + return false; + return intel_engine_can_store_dword(i915->engine[RCS]); } @@ -251,7 +259,7 @@ static const struct igt_coherency_mode { bool (*valid)(struct drm_i915_private *i915); } igt_coherency_mode[] = { { "cpu", cpu_set, cpu_get, always_valid }, - { "gtt", gtt_set, gtt_get, always_valid }, + { "gtt", gtt_set, gtt_get, needs_fence_registers }, { "wc", wc_set, wc_get, always_valid }, { "gpu", gpu_set, NULL, needs_mi_store_dword }, { }, -- GitLab From e16f4c36cb9bf61fcd70a2ea978cee2a23ebf71d Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 6 Jul 2018 07:53:09 +0100 Subject: [PATCH 0847/1506] drm/i915/selftests: Skip making an object busy if the GPU is wedged If the GPU is wedged, we cannot make the object busy as trying to submit a request will generate -EIO. Skip to the end of the test. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Matthew Auld <matthew.auld@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180706065332.15214-4-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/selftests/i915_gem_object.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_object.c b/drivers/gpu/drm/i915/selftests/i915_gem_object.c index 232e5ccf1852f..6fe71865b7109 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_object.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_object.c @@ -553,6 +553,9 @@ static int igt_mmap_offset_exhaustion(void *arg) /* Now fill with busy dead objects that we expect to reap */ for (loop = 0; loop < 3; loop++) { + if (i915_terminally_wedged(&i915->gpu_error)) + break; + obj = i915_gem_object_create_internal(i915, PAGE_SIZE); if (IS_ERR(obj)) { err = PTR_ERR(obj); -- GitLab From a9450e15ad9e921fd2d76b038a8b252b1afc7bb6 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 6 Jul 2018 07:53:10 +0100 Subject: [PATCH 0848/1506] drm/i915/selftests: Skip all request selftests when wedged If the GPU is irrecoverably wedge, we cannot submit any request and so all of the request selftests will expectedly fail. Skip over them. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Matthew Auld <matthew.auld@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180706065332.15214-5-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/selftests/i915_request.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/selftests/i915_request.c b/drivers/gpu/drm/i915/selftests/i915_request.c index e44aa3335d9ed..cc27edc40356c 100644 --- a/drivers/gpu/drm/i915/selftests/i915_request.c +++ b/drivers/gpu/drm/i915/selftests/i915_request.c @@ -859,5 +859,9 @@ int i915_request_live_selftests(struct drm_i915_private *i915) SUBTEST(live_sequential_engines), SUBTEST(live_empty_request), }; + + if (i915_terminally_wedged(&i915->gpu_error)) + return 0; + return i915_subtests(tests, i915); } -- GitLab From 47e61a79806d5d222261250dc573a68c53e99c22 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 6 Jul 2018 07:53:11 +0100 Subject: [PATCH 0849/1506] drm/i915/selftests: Skip workaround tests when wedged If the GPU is irrecoverably wedged, we cannot submit any request and therefore cannot query the register state of the context (which is done using the GPU command stream). So skip over the test as it expectedly fails. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Matthew Auld <matthew.auld@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180706065332.15214-6-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/selftests/intel_workarounds.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/selftests/intel_workarounds.c b/drivers/gpu/drm/i915/selftests/intel_workarounds.c index e1ea2d2bedd2f..3d86b90ab7221 100644 --- a/drivers/gpu/drm/i915/selftests/intel_workarounds.c +++ b/drivers/gpu/drm/i915/selftests/intel_workarounds.c @@ -283,6 +283,9 @@ int intel_workarounds_live_selftests(struct drm_i915_private *i915) }; int err; + if (i915_terminally_wedged(&i915->gpu_error)) + return 0; + mutex_lock(&i915->drm.struct_mutex); err = i915_subtests(tests, i915); mutex_unlock(&i915->drm.struct_mutex); -- GitLab From 7783decff5be6811a1a31df91b47fd2541b993d0 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 6 Jul 2018 07:53:12 +0100 Subject: [PATCH 0850/1506] drm/i915/selftests: Skip live eviction tests when wedged If the GPU is irrecoverably wedged, we cannot submit any requests and so cannot make the GTT busy in order to test evicting active objects. As this expectedly fails, skip over the test. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Matthew Auld <matthew.auld@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180706065332.15214-7-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/selftests/i915_gem_evict.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_evict.c b/drivers/gpu/drm/i915/selftests/i915_gem_evict.c index 8059268800fa5..128ad1cf0647a 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_evict.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_evict.c @@ -500,5 +500,8 @@ int i915_gem_evict_live_selftests(struct drm_i915_private *i915) SUBTEST(igt_evict_contexts), }; + if (i915_terminally_wedged(&i915->gpu_error)) + return 0; + return i915_subtests(tests, i915); } -- GitLab From 921d07d73ebf6d87064883d69fedd3d7e9e99538 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 6 Jul 2018 07:53:13 +0100 Subject: [PATCH 0851/1506] drm/i915/selftests: Skip huge pages live tests if wedged We test the GPU handling of huge pages by submitting requests that write into a huge page, but if the GPU is irrecoverably wedged we cannot submit any requests. As the test expectedly fails, skip over it. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Matthew Auld <matthew.auld@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180706065332.15214-8-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/selftests/huge_pages.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/selftests/huge_pages.c b/drivers/gpu/drm/i915/selftests/huge_pages.c index 39699939587da..1193dd36913a6 100644 --- a/drivers/gpu/drm/i915/selftests/huge_pages.c +++ b/drivers/gpu/drm/i915/selftests/huge_pages.c @@ -1748,6 +1748,9 @@ int i915_gem_huge_page_live_selftests(struct drm_i915_private *dev_priv) return 0; } + if (i915_terminally_wedged(&dev_priv->gpu_error)) + return 0; + file = mock_file(dev_priv); if (IS_ERR(file)) return PTR_ERR(file); -- GitLab From 31c9bd78018cc36e62525fe3edc0009c1da6347f Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 6 Jul 2018 07:53:14 +0100 Subject: [PATCH 0852/1506] drm/i915/selftests: Skip over live context testing when wedged If the GPU is terminally wedged we cannot submit any requests into a context, completely unfulfilling our purpose of doing so. As this expectedly fails, skip over the test. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Matthew Auld <matthew.auld@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180706065332.15214-9-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/selftests/i915_gem_context.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_context.c b/drivers/gpu/drm/i915/selftests/i915_gem_context.c index cc848ceeb3c31..0b36265a0f96d 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_context.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_context.c @@ -599,6 +599,9 @@ int i915_gem_context_live_selftests(struct drm_i915_private *dev_priv) bool fake_alias = false; int err; + if (i915_terminally_wedged(&dev_priv->gpu_error)) + return 0; + /* Install a fake aliasing gtt for exercise */ if (USES_PPGTT(dev_priv) && !dev_priv->mm.aliasing_ppgtt) { mutex_lock(&dev_priv->drm.struct_mutex); -- GitLab From 6cc42152b02b3f73969934b63332d47e2dac55e4 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Date: Thu, 28 Jun 2018 09:23:02 +0200 Subject: [PATCH 0853/1506] drm/i915: Remove support for legacy debugfs crc interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This interface is deprecated, and has been replaced by the upstream drm crc interface. Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Cc: Tomi Sarvela <tomi.p.sarvela@intel.com> Cc: Petri Latvala <petri.latvala@intel.com> Cc: Jani Nikula <jani.nikula@intel.com> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Acked-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Acked-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180628072303.14175-1-maarten.lankhorst@linux.intel.com --- drivers/gpu/drm/i915/i915_debugfs.c | 7 +- drivers/gpu/drm/i915/i915_drv.h | 11 +- drivers/gpu/drm/i915/i915_irq.c | 79 ++--- drivers/gpu/drm/i915/intel_drv.h | 2 - drivers/gpu/drm/i915/intel_pipe_crc.c | 445 -------------------------- 5 files changed, 24 insertions(+), 520 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index f6142d78ede4c..544e5e7f011fb 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -4818,7 +4818,6 @@ static const struct i915_debugfs_files { #endif {"i915_fifo_underrun_reset", &i915_fifo_underrun_reset_ops}, {"i915_next_seqno", &i915_next_seqno_fops}, - {"i915_display_crc_ctl", &i915_display_crc_ctl_fops}, {"i915_pri_wm_latency", &i915_pri_wm_latency_fops}, {"i915_spr_wm_latency", &i915_spr_wm_latency_fops}, {"i915_cur_wm_latency", &i915_cur_wm_latency_fops}, @@ -4838,7 +4837,7 @@ int i915_debugfs_register(struct drm_i915_private *dev_priv) { struct drm_minor *minor = dev_priv->drm.primary; struct dentry *ent; - int ret, i; + int i; ent = debugfs_create_file("i915_forcewake_user", S_IRUSR, minor->debugfs_root, to_i915(minor->dev), @@ -4846,10 +4845,6 @@ int i915_debugfs_register(struct drm_i915_private *dev_priv) if (!ent) return -ENOMEM; - ret = intel_pipe_crc_create(minor); - if (ret) - return ret; - for (i = 0; i < ARRAY_SIZE(i915_debugfs_files); i++) { ent = debugfs_create_file(i915_debugfs_files[i].name, S_IRUGO | S_IWUSR, diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e236016eef7bb..8a2196e4262bc 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1271,20 +1271,11 @@ enum intel_pipe_crc_source { INTEL_PIPE_CRC_SOURCE_MAX, }; -struct intel_pipe_crc_entry { - uint32_t frame; - uint32_t crc[5]; -}; - #define INTEL_PIPE_CRC_ENTRIES_NR 128 struct intel_pipe_crc { spinlock_t lock; - bool opened; /* exclusive access to the result file */ - struct intel_pipe_crc_entry *entries; - enum intel_pipe_crc_source source; - int head, tail; - wait_queue_head_t wq; int skipped; + enum intel_pipe_crc_source source; }; struct i915_frontbuffer_tracking { diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 2fcc00b069154..495b9d27990e7 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1751,69 +1751,34 @@ static void display_pipe_crc_irq_handler(struct drm_i915_private *dev_priv, uint32_t crc4) { struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe]; - struct intel_pipe_crc_entry *entry; struct intel_crtc *crtc = intel_get_crtc_for_pipe(dev_priv, pipe); - struct drm_driver *driver = dev_priv->drm.driver; uint32_t crcs[5]; - int head, tail; spin_lock(&pipe_crc->lock); - if (pipe_crc->source && !crtc->base.crc.opened) { - if (!pipe_crc->entries) { - spin_unlock(&pipe_crc->lock); - DRM_DEBUG_KMS("spurious interrupt\n"); - return; - } - - head = pipe_crc->head; - tail = pipe_crc->tail; - - if (CIRC_SPACE(head, tail, INTEL_PIPE_CRC_ENTRIES_NR) < 1) { - spin_unlock(&pipe_crc->lock); - DRM_ERROR("CRC buffer overflowing\n"); - return; - } - - entry = &pipe_crc->entries[head]; - - entry->frame = driver->get_vblank_counter(&dev_priv->drm, pipe); - entry->crc[0] = crc0; - entry->crc[1] = crc1; - entry->crc[2] = crc2; - entry->crc[3] = crc3; - entry->crc[4] = crc4; - - head = (head + 1) & (INTEL_PIPE_CRC_ENTRIES_NR - 1); - pipe_crc->head = head; - - spin_unlock(&pipe_crc->lock); - - wake_up_interruptible(&pipe_crc->wq); - } else { - /* - * For some not yet identified reason, the first CRC is - * bonkers. So let's just wait for the next vblank and read - * out the buggy result. - * - * On GEN8+ sometimes the second CRC is bonkers as well, so - * don't trust that one either. - */ - if (pipe_crc->skipped <= 0 || - (INTEL_GEN(dev_priv) >= 8 && pipe_crc->skipped == 1)) { - pipe_crc->skipped++; - spin_unlock(&pipe_crc->lock); - return; - } + /* + * For some not yet identified reason, the first CRC is + * bonkers. So let's just wait for the next vblank and read + * out the buggy result. + * + * On GEN8+ sometimes the second CRC is bonkers as well, so + * don't trust that one either. + */ + if (pipe_crc->skipped <= 0 || + (INTEL_GEN(dev_priv) >= 8 && pipe_crc->skipped == 1)) { + pipe_crc->skipped++; spin_unlock(&pipe_crc->lock); - crcs[0] = crc0; - crcs[1] = crc1; - crcs[2] = crc2; - crcs[3] = crc3; - crcs[4] = crc4; - drm_crtc_add_crc_entry(&crtc->base, true, - drm_crtc_accurate_vblank_count(&crtc->base), - crcs); + return; } + spin_unlock(&pipe_crc->lock); + + crcs[0] = crc0; + crcs[1] = crc1; + crcs[2] = crc2; + crcs[3] = crc3; + crcs[4] = crc4; + drm_crtc_add_crc_entry(&crtc->base, true, + drm_crtc_accurate_vblank_count(&crtc->base), + crcs); } #else static inline void diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 3034477b79ff0..e283e9e901c2d 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -2153,7 +2153,6 @@ void lspcon_resume(struct intel_lspcon *lspcon); void lspcon_wait_pcon_mode(struct intel_lspcon *lspcon); /* intel_pipe_crc.c */ -int intel_pipe_crc_create(struct drm_minor *minor); #ifdef CONFIG_DEBUG_FS int intel_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name, size_t *values_cnt); @@ -2169,5 +2168,4 @@ static inline void intel_crtc_enable_pipe_crc(struct intel_crtc *crtc) { } #endif -extern const struct file_operations i915_display_crc_ctl_fops; #endif /* __INTEL_DRV_H__ */ diff --git a/drivers/gpu/drm/i915/intel_pipe_crc.c b/drivers/gpu/drm/i915/intel_pipe_crc.c index 39a4e4edda070..849e1b69ba739 100644 --- a/drivers/gpu/drm/i915/intel_pipe_crc.c +++ b/drivers/gpu/drm/i915/intel_pipe_crc.c @@ -30,160 +30,6 @@ #include <linux/debugfs.h> #include "intel_drv.h" -struct pipe_crc_info { - const char *name; - struct drm_i915_private *dev_priv; - enum pipe pipe; -}; - -static int i915_pipe_crc_open(struct inode *inode, struct file *filep) -{ - struct pipe_crc_info *info = inode->i_private; - struct drm_i915_private *dev_priv = info->dev_priv; - struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[info->pipe]; - - if (info->pipe >= INTEL_INFO(dev_priv)->num_pipes) - return -ENODEV; - - spin_lock_irq(&pipe_crc->lock); - - if (pipe_crc->opened) { - spin_unlock_irq(&pipe_crc->lock); - return -EBUSY; /* already open */ - } - - pipe_crc->opened = true; - filep->private_data = inode->i_private; - - spin_unlock_irq(&pipe_crc->lock); - - return 0; -} - -static int i915_pipe_crc_release(struct inode *inode, struct file *filep) -{ - struct pipe_crc_info *info = inode->i_private; - struct drm_i915_private *dev_priv = info->dev_priv; - struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[info->pipe]; - - spin_lock_irq(&pipe_crc->lock); - pipe_crc->opened = false; - spin_unlock_irq(&pipe_crc->lock); - - return 0; -} - -/* (6 fields, 8 chars each, space separated (5) + '\n') */ -#define PIPE_CRC_LINE_LEN (6 * 8 + 5 + 1) -/* account for \'0' */ -#define PIPE_CRC_BUFFER_LEN (PIPE_CRC_LINE_LEN + 1) - -static int pipe_crc_data_count(struct intel_pipe_crc *pipe_crc) -{ - lockdep_assert_held(&pipe_crc->lock); - return CIRC_CNT(pipe_crc->head, pipe_crc->tail, - INTEL_PIPE_CRC_ENTRIES_NR); -} - -static ssize_t -i915_pipe_crc_read(struct file *filep, char __user *user_buf, size_t count, - loff_t *pos) -{ - struct pipe_crc_info *info = filep->private_data; - struct drm_i915_private *dev_priv = info->dev_priv; - struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[info->pipe]; - char buf[PIPE_CRC_BUFFER_LEN]; - int n_entries; - ssize_t bytes_read; - - /* - * Don't allow user space to provide buffers not big enough to hold - * a line of data. - */ - if (count < PIPE_CRC_LINE_LEN) - return -EINVAL; - - if (pipe_crc->source == INTEL_PIPE_CRC_SOURCE_NONE) - return 0; - - /* nothing to read */ - spin_lock_irq(&pipe_crc->lock); - while (pipe_crc_data_count(pipe_crc) == 0) { - int ret; - - if (filep->f_flags & O_NONBLOCK) { - spin_unlock_irq(&pipe_crc->lock); - return -EAGAIN; - } - - ret = wait_event_interruptible_lock_irq(pipe_crc->wq, - pipe_crc_data_count(pipe_crc), pipe_crc->lock); - if (ret) { - spin_unlock_irq(&pipe_crc->lock); - return ret; - } - } - - /* We now have one or more entries to read */ - n_entries = count / PIPE_CRC_LINE_LEN; - - bytes_read = 0; - while (n_entries > 0) { - struct intel_pipe_crc_entry *entry = - &pipe_crc->entries[pipe_crc->tail]; - - if (CIRC_CNT(pipe_crc->head, pipe_crc->tail, - INTEL_PIPE_CRC_ENTRIES_NR) < 1) - break; - - BUILD_BUG_ON_NOT_POWER_OF_2(INTEL_PIPE_CRC_ENTRIES_NR); - pipe_crc->tail = (pipe_crc->tail + 1) & - (INTEL_PIPE_CRC_ENTRIES_NR - 1); - - bytes_read += snprintf(buf, PIPE_CRC_BUFFER_LEN, - "%8u %8x %8x %8x %8x %8x\n", - entry->frame, entry->crc[0], - entry->crc[1], entry->crc[2], - entry->crc[3], entry->crc[4]); - - spin_unlock_irq(&pipe_crc->lock); - - if (copy_to_user(user_buf, buf, PIPE_CRC_LINE_LEN)) - return -EFAULT; - - user_buf += PIPE_CRC_LINE_LEN; - n_entries--; - - spin_lock_irq(&pipe_crc->lock); - } - - spin_unlock_irq(&pipe_crc->lock); - - return bytes_read; -} - -static const struct file_operations i915_pipe_crc_fops = { - .owner = THIS_MODULE, - .open = i915_pipe_crc_open, - .read = i915_pipe_crc_read, - .release = i915_pipe_crc_release, -}; - -static struct pipe_crc_info i915_pipe_crc_data[I915_MAX_PIPES] = { - { - .name = "i915_pipe_A_crc", - .pipe = PIPE_A, - }, - { - .name = "i915_pipe_B_crc", - .pipe = PIPE_B, - }, - { - .name = "i915_pipe_C_crc", - .pipe = PIPE_C, - }, -}; - static const char * const pipe_crc_sources[] = { "none", "plane1", @@ -197,29 +43,6 @@ static const char * const pipe_crc_sources[] = { "auto", }; -static const char *pipe_crc_source_name(enum intel_pipe_crc_source source) -{ - BUILD_BUG_ON(ARRAY_SIZE(pipe_crc_sources) != INTEL_PIPE_CRC_SOURCE_MAX); - return pipe_crc_sources[source]; -} - -static int display_crc_ctl_show(struct seq_file *m, void *data) -{ - struct drm_i915_private *dev_priv = m->private; - enum pipe pipe; - - for_each_pipe(dev_priv, pipe) - seq_printf(m, "%c %s\n", pipe_name(pipe), - pipe_crc_source_name(dev_priv->pipe_crc[pipe].source)); - - return 0; -} - -static int display_crc_ctl_open(struct inode *inode, struct file *file) -{ - return single_open(file, display_crc_ctl_show, inode->i_private); -} - static int i8xx_pipe_crc_ctl_reg(enum intel_pipe_crc_source *source, uint32_t *val) { @@ -616,177 +439,6 @@ static int get_new_crc_ctl_reg(struct drm_i915_private *dev_priv, return ivb_pipe_crc_ctl_reg(dev_priv, pipe, source, val, set_wa); } -static int pipe_crc_set_source(struct drm_i915_private *dev_priv, - enum pipe pipe, - enum intel_pipe_crc_source source) -{ - struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe]; - enum intel_display_power_domain power_domain; - u32 val = 0; /* shut up gcc */ - int ret; - - if (pipe_crc->source == source) - return 0; - - /* forbid changing the source without going back to 'none' */ - if (pipe_crc->source && source) - return -EINVAL; - - power_domain = POWER_DOMAIN_PIPE(pipe); - if (!intel_display_power_get_if_enabled(dev_priv, power_domain)) { - DRM_DEBUG_KMS("Trying to capture CRC while pipe is off\n"); - return -EIO; - } - - ret = get_new_crc_ctl_reg(dev_priv, pipe, &source, &val, true); - if (ret != 0) - goto out; - - /* none -> real source transition */ - if (source) { - struct intel_pipe_crc_entry *entries; - - DRM_DEBUG_DRIVER("collecting CRCs for pipe %c, %s\n", - pipe_name(pipe), pipe_crc_source_name(source)); - - entries = kcalloc(INTEL_PIPE_CRC_ENTRIES_NR, - sizeof(pipe_crc->entries[0]), - GFP_KERNEL); - if (!entries) { - ret = -ENOMEM; - goto out; - } - - spin_lock_irq(&pipe_crc->lock); - kfree(pipe_crc->entries); - pipe_crc->entries = entries; - pipe_crc->head = 0; - pipe_crc->tail = 0; - spin_unlock_irq(&pipe_crc->lock); - } - - pipe_crc->source = source; - - I915_WRITE(PIPE_CRC_CTL(pipe), val); - POSTING_READ(PIPE_CRC_CTL(pipe)); - - /* real source -> none transition */ - if (!source) { - struct intel_pipe_crc_entry *entries; - struct intel_crtc *crtc = intel_get_crtc_for_pipe(dev_priv, - pipe); - - DRM_DEBUG_DRIVER("stopping CRCs for pipe %c\n", - pipe_name(pipe)); - - drm_modeset_lock(&crtc->base.mutex, NULL); - if (crtc->base.state->active) - intel_wait_for_vblank(dev_priv, pipe); - drm_modeset_unlock(&crtc->base.mutex); - - spin_lock_irq(&pipe_crc->lock); - entries = pipe_crc->entries; - pipe_crc->entries = NULL; - pipe_crc->head = 0; - pipe_crc->tail = 0; - spin_unlock_irq(&pipe_crc->lock); - - kfree(entries); - - if (IS_G4X(dev_priv)) - g4x_undo_pipe_scramble_reset(dev_priv, pipe); - else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) - vlv_undo_pipe_scramble_reset(dev_priv, pipe); - else if ((IS_HASWELL(dev_priv) || - IS_BROADWELL(dev_priv)) && pipe == PIPE_A) - hsw_pipe_A_crc_wa(dev_priv, false); - } - - ret = 0; - -out: - intel_display_power_put(dev_priv, power_domain); - - return ret; -} - -/* - * Parse pipe CRC command strings: - * command: wsp* object wsp+ name wsp+ source wsp* - * object: 'pipe' - * name: (A | B | C) - * source: (none | plane1 | plane2 | pf) - * wsp: (#0x20 | #0x9 | #0xA)+ - * - * eg.: - * "pipe A plane1" -> Start CRC computations on plane1 of pipe A - * "pipe A none" -> Stop CRC - */ -static int display_crc_ctl_tokenize(char *buf, char *words[], int max_words) -{ - int n_words = 0; - - while (*buf) { - char *end; - - /* skip leading white space */ - buf = skip_spaces(buf); - if (!*buf) - break; /* end of buffer */ - - /* find end of word */ - for (end = buf; *end && !isspace(*end); end++) - ; - - if (n_words == max_words) { - DRM_DEBUG_DRIVER("too many words, allowed <= %d\n", - max_words); - return -EINVAL; /* ran out of words[] before bytes */ - } - - if (*end) - *end++ = '\0'; - words[n_words++] = buf; - buf = end; - } - - return n_words; -} - -enum intel_pipe_crc_object { - PIPE_CRC_OBJECT_PIPE, -}; - -static const char * const pipe_crc_objects[] = { - "pipe", -}; - -static int -display_crc_ctl_parse_object(const char *buf, enum intel_pipe_crc_object *o) -{ - int i; - - i = match_string(pipe_crc_objects, ARRAY_SIZE(pipe_crc_objects), buf); - if (i < 0) - return i; - - *o = i; - return 0; -} - -static int display_crc_ctl_parse_pipe(struct drm_i915_private *dev_priv, - const char *buf, enum pipe *pipe) -{ - const char name = buf[0]; - - if (name < 'A' || name >= pipe_name(INTEL_INFO(dev_priv)->num_pipes)) - return -EINVAL; - - *pipe = name - 'A'; - - return 0; -} - static int display_crc_ctl_parse_source(const char *buf, enum intel_pipe_crc_source *s) { @@ -805,81 +457,6 @@ display_crc_ctl_parse_source(const char *buf, enum intel_pipe_crc_source *s) return 0; } -static int display_crc_ctl_parse(struct drm_i915_private *dev_priv, - char *buf, size_t len) -{ -#define N_WORDS 3 - int n_words; - char *words[N_WORDS]; - enum pipe pipe; - enum intel_pipe_crc_object object; - enum intel_pipe_crc_source source; - - n_words = display_crc_ctl_tokenize(buf, words, N_WORDS); - if (n_words != N_WORDS) { - DRM_DEBUG_DRIVER("tokenize failed, a command is %d words\n", - N_WORDS); - return -EINVAL; - } - - if (display_crc_ctl_parse_object(words[0], &object) < 0) { - DRM_DEBUG_DRIVER("unknown object %s\n", words[0]); - return -EINVAL; - } - - if (display_crc_ctl_parse_pipe(dev_priv, words[1], &pipe) < 0) { - DRM_DEBUG_DRIVER("unknown pipe %s\n", words[1]); - return -EINVAL; - } - - if (display_crc_ctl_parse_source(words[2], &source) < 0) { - DRM_DEBUG_DRIVER("unknown source %s\n", words[2]); - return -EINVAL; - } - - return pipe_crc_set_source(dev_priv, pipe, source); -} - -static ssize_t display_crc_ctl_write(struct file *file, const char __user *ubuf, - size_t len, loff_t *offp) -{ - struct seq_file *m = file->private_data; - struct drm_i915_private *dev_priv = m->private; - char *tmpbuf; - int ret; - - if (len == 0) - return 0; - - if (len > PAGE_SIZE - 1) { - DRM_DEBUG_DRIVER("expected <%lu bytes into pipe crc control\n", - PAGE_SIZE); - return -E2BIG; - } - - tmpbuf = memdup_user_nul(ubuf, len); - if (IS_ERR(tmpbuf)) - return PTR_ERR(tmpbuf); - - ret = display_crc_ctl_parse(dev_priv, tmpbuf, len); - - kfree(tmpbuf); - if (ret < 0) - return ret; - - *offp += len; - return len; -} - -const struct file_operations i915_display_crc_ctl_fops = { - .owner = THIS_MODULE, - .open = display_crc_ctl_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .write = display_crc_ctl_write -}; - void intel_display_crc_init(struct drm_i915_private *dev_priv) { enum pipe pipe; @@ -887,30 +464,8 @@ void intel_display_crc_init(struct drm_i915_private *dev_priv) for_each_pipe(dev_priv, pipe) { struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe]; - pipe_crc->opened = false; spin_lock_init(&pipe_crc->lock); - init_waitqueue_head(&pipe_crc->wq); - } -} - -int intel_pipe_crc_create(struct drm_minor *minor) -{ - struct drm_i915_private *dev_priv = to_i915(minor->dev); - struct dentry *ent; - int i; - - for (i = 0; i < ARRAY_SIZE(i915_pipe_crc_data); i++) { - struct pipe_crc_info *info = &i915_pipe_crc_data[i]; - - info->dev_priv = dev_priv; - ent = debugfs_create_file(info->name, S_IRUGO, - minor->debugfs_root, info, - &i915_pipe_crc_fops); - if (!ent) - return -ENOMEM; } - - return 0; } int intel_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name, -- GitLab From b79ebe74e1c4219e91940b637d40939b0c80c0f2 Mon Sep 17 00:00:00 2001 From: Imre Deak <imre.deak@intel.com> Date: Thu, 5 Jul 2018 15:26:54 +0300 Subject: [PATCH 0854/1506] drm/i915/ddi: Simplify get_encoder_power_domains() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can simplify the encoder's get_power_domains() hook by calling it only if the encoder is active. That way the hook can return its power domains unconditionally without checking the active state by calling encoder::get_hw_state(). This get_hw_state() query is in fact redundant since it's already done by intel_modeset_readout_hw_state() setting the encoder's crtc or leaving it NULL accordingly. Let's use this fact to decide if the encoder is active. While at it clarify the comment in intel_ddi_get_power_domains() about primary vs. fake MST encoders and make sure we never do an incorrect encoder->dig_port cast for fake MST encoders. Suggested-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Imre Deak <imre.deak@intel.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180705122654.17072-1-imre.deak@intel.com --- drivers/gpu/drm/i915/intel_ddi.c | 19 +++++++------------ drivers/gpu/drm/i915/intel_display.c | 11 +++++------ 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index c74b01a52082b..32838ed89ee7a 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -2006,24 +2006,19 @@ intel_ddi_main_link_aux_domain(struct intel_dp *intel_dp) static u64 intel_ddi_get_power_domains(struct intel_encoder *encoder, struct intel_crtc_state *crtc_state) { - struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base); - enum pipe pipe; + struct intel_digital_port *dig_port; u64 domains; - if (!intel_ddi_get_hw_state(encoder, &pipe)) - return 0; - - domains = BIT_ULL(dig_port->ddi_io_power_domain); - if (!crtc_state) - return domains; - /* * TODO: Add support for MST encoders. Atm, the following should never - * happen since this function will be called only for the primary - * encoder which doesn't have its own pipe/crtc_state. + * happen since fake-MST encoders don't set their get_power_domains() + * hook. */ if (WARN_ON(intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST))) - return domains; + return 0; + + dig_port = enc_to_dig_port(&encoder->base); + domains = BIT_ULL(dig_port->ddi_io_power_domain); /* AUX power is only needed for (e)DP mode, not for HDMI. */ if (intel_crtc_has_dp_encoder(crtc_state)) { diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d33033abbf185..19f756d571aea 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -15664,14 +15664,13 @@ get_encoder_power_domains(struct drm_i915_private *dev_priv) continue; /* - * For MST and inactive encoders we don't have a crtc state. - * FIXME: no need to call get_power_domains in such cases, it - * will always return 0. + * MST-primary and inactive encoders don't have a crtc state + * and neither of these require any power domain references. */ - crtc_state = encoder->base.crtc ? - to_intel_crtc_state(encoder->base.crtc->state) : - NULL; + if (!encoder->base.crtc) + continue; + crtc_state = to_intel_crtc_state(encoder->base.crtc->state); get_domains = encoder->get_power_domains(encoder, crtc_state); for_each_power_domain(domain, get_domains) intel_display_power_get(dev_priv, domain); -- GitLab From a012024571d98e2e4bf29a9168fb7ddc44b7ab86 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Date: Wed, 18 Apr 2018 14:51:21 +0200 Subject: [PATCH 0855/1506] drm/crc: Only report a single overflow when a CRC fd is opened MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reduces the amount of spam when you debug a CRC reading program. Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> [mlankhorst: Change bool overflow to was_overflow (Ville)] Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180418125121.72081-1-maarten.lankhorst@linux.intel.com --- drivers/gpu/drm/drm_debugfs_crc.c | 9 ++++++++- include/drm/drm_debugfs_crc.h | 3 ++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_debugfs_crc.c b/drivers/gpu/drm/drm_debugfs_crc.c index 9f8312137cade..99961192bf034 100644 --- a/drivers/gpu/drm/drm_debugfs_crc.c +++ b/drivers/gpu/drm/drm_debugfs_crc.c @@ -139,6 +139,7 @@ static int crtc_crc_data_count(struct drm_crtc_crc *crc) static void crtc_crc_cleanup(struct drm_crtc_crc *crc) { kfree(crc->entries); + crc->overflow = false; crc->entries = NULL; crc->head = 0; crc->tail = 0; @@ -391,8 +392,14 @@ int drm_crtc_add_crc_entry(struct drm_crtc *crtc, bool has_frame, tail = crc->tail; if (CIRC_SPACE(head, tail, DRM_CRC_ENTRIES_NR) < 1) { + bool was_overflow = crc->overflow; + + crc->overflow = true; spin_unlock(&crc->lock); - DRM_ERROR("Overflow of CRC buffer, userspace reads too slow.\n"); + + if (!was_overflow) + DRM_ERROR("Overflow of CRC buffer, userspace reads too slow.\n"); + return -ENOBUFS; } diff --git a/include/drm/drm_debugfs_crc.h b/include/drm/drm_debugfs_crc.h index 7d63b1d4adb97..b225eeb30d05f 100644 --- a/include/drm/drm_debugfs_crc.h +++ b/include/drm/drm_debugfs_crc.h @@ -43,6 +43,7 @@ struct drm_crtc_crc_entry { * @lock: protects the fields in this struct * @source: name of the currently configured source of CRCs * @opened: whether userspace has opened the data file for reading + * @overflow: whether an overflow occured. * @entries: array of entries, with size of %DRM_CRC_ENTRIES_NR * @head: head of circular queue * @tail: tail of circular queue @@ -52,7 +53,7 @@ struct drm_crtc_crc_entry { struct drm_crtc_crc { spinlock_t lock; const char *source; - bool opened; + bool opened, overflow; struct drm_crtc_crc_entry *entries; int head, tail; size_t values_cnt; -- GitLab From 481827b441674b7f1d030c223decdb56266ff398 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 6 Jul 2018 11:14:41 +0100 Subject: [PATCH 0856/1506] drm/i915: Record logical context support in driver caps Avoid looking at the magical engines[RCS] to decide if the HW and driver supports logical contexts, and instead record that knowledge during initialisation. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Matthew Auld <matthew.auld@intel.com> Reviewed-by: Matthew Auld <matthew.auld@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180706101442.21279-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_gem_context.c | 6 +++--- drivers/gpu/drm/i915/intel_device_info.c | 2 ++ drivers/gpu/drm/i915/intel_device_info.h | 1 + drivers/gpu/drm/i915/intel_engine_cs.c | 2 ++ 5 files changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 8a2196e4262bc..c1c637e47bf5d 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2306,6 +2306,7 @@ intel_info(const struct drm_i915_private *dev_priv) } #define INTEL_INFO(dev_priv) intel_info((dev_priv)) +#define DRIVER_CAPS(dev_priv) (&(dev_priv)->caps) #define INTEL_GEN(dev_priv) ((dev_priv)->info.gen) #define INTEL_DEVID(dev_priv) ((dev_priv)->info.device_id) diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 985ef70d9416d..b10770cfccd24 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -512,8 +512,8 @@ int i915_gem_contexts_init(struct drm_i915_private *dev_priv) } DRM_DEBUG_DRIVER("%s context support initialized\n", - dev_priv->engine[RCS]->context_size ? "logical" : - "fake"); + DRIVER_CAPS(dev_priv)->has_logical_contexts ? + "logical" : "fake"); return 0; } @@ -720,7 +720,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data, struct i915_gem_context *ctx; int ret; - if (!dev_priv->engine[RCS]->context_size) + if (!DRIVER_CAPS(dev_priv)->has_logical_contexts) return -ENODEV; if (args->pad != 0) diff --git a/drivers/gpu/drm/i915/intel_device_info.c b/drivers/gpu/drm/i915/intel_device_info.c index 0fd13df424cf1..0ef0c6448d53a 100644 --- a/drivers/gpu/drm/i915/intel_device_info.c +++ b/drivers/gpu/drm/i915/intel_device_info.c @@ -858,6 +858,8 @@ void intel_device_info_runtime_init(struct intel_device_info *info) void intel_driver_caps_print(const struct intel_driver_caps *caps, struct drm_printer *p) { + drm_printf(p, "Has logical contexts? %s\n", + yesno(caps->has_logical_contexts)); drm_printf(p, "scheduler: %x\n", caps->scheduler); } diff --git a/drivers/gpu/drm/i915/intel_device_info.h b/drivers/gpu/drm/i915/intel_device_info.h index 933e31669557e..633f9fbf72eab 100644 --- a/drivers/gpu/drm/i915/intel_device_info.h +++ b/drivers/gpu/drm/i915/intel_device_info.h @@ -186,6 +186,7 @@ struct intel_device_info { struct intel_driver_caps { unsigned int scheduler; + bool has_logical_contexts:1; }; static inline unsigned int sseu_subslice_total(const struct sseu_dev_info *sseu) diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index 478c928912c4c..e2f562853aeec 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -302,6 +302,8 @@ intel_engine_setup(struct drm_i915_private *dev_priv, engine->class); if (WARN_ON(engine->context_size > BIT(20))) engine->context_size = 0; + if (engine->context_size) + DRIVER_CAPS(dev_priv)->has_logical_contexts = true; /* Nothing to do here, execute in order of dependencies */ engine->schedule = NULL; -- GitLab From 0fdbe58c4a0f8c2fa67e38a740ce6ff3cffa8c86 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 6 Jul 2018 11:19:23 +0100 Subject: [PATCH 0857/1506] drm/i915/selftests: Skip live context execution test without logical contexts If the HW (or driver) doesn't support logical contexts, don't pretend we gain anything from trying to execute GPU commands with them. At best it reports -ENODEV, which is an unhelpful failure that we should just skip. v2: Be more specific and check the driver/engine caps for logical (HW) context support. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Matthew Auld <matthew.auld@intel.com> Reviewed-by: Matthew Auld <matthew.auld@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180706101923.28548-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/selftests/i915_gem_context.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_context.c b/drivers/gpu/drm/i915/selftests/i915_gem_context.c index 0b36265a0f96d..0d8e719802fa2 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_context.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_context.c @@ -336,11 +336,15 @@ static int igt_ctx_exec(void *arg) bool first_shared_gtt = true; int err = -ENODEV; - /* Create a few different contexts (with different mm) and write + /* + * Create a few different contexts (with different mm) and write * through each ctx/mm using the GPU making sure those writes end * up in the expected pages of our obj. */ + if (!DRIVER_CAPS(i915)->has_logical_contexts) + return 0; + file = mock_file(i915); if (IS_ERR(file)) return PTR_ERR(file); @@ -367,6 +371,9 @@ static int igt_ctx_exec(void *arg) } for_each_engine(engine, i915, id) { + if (!engine->context_size) + continue; /* No logical context support in HW */ + if (!intel_engine_can_store_dword(engine)) continue; -- GitLab From 03bbc508a312d9f4833f1cb0f7b2da7517787b61 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 6 Jul 2018 12:45:10 +0100 Subject: [PATCH 0858/1506] drm/i915/selftests: Skip live_execlists if the GPU is terminally wedged If the GPU is irrecoverably wedged, we can not execute any requests making testing execlists (request execution) pointless. Skip! Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Matthew Auld <matthew.auld@intel.com> Reviewed-by: Matthew Auld <matthew.auld@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180706114510.18467-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/selftests/intel_lrc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/selftests/intel_lrc.c b/drivers/gpu/drm/i915/selftests/intel_lrc.c index ea27c7cfbf968..730a02d390586 100644 --- a/drivers/gpu/drm/i915/selftests/intel_lrc.c +++ b/drivers/gpu/drm/i915/selftests/intel_lrc.c @@ -455,5 +455,8 @@ int intel_execlists_live_selftests(struct drm_i915_private *i915) if (!HAS_EXECLISTS(i915)) return 0; + if (i915_terminally_wedged(&i915->gpu_error)) + return 0; + return i915_subtests(tests, i915); } -- GitLab From add00e6d896fab882e6115ed4908b2456f1b3a85 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 6 Jul 2018 12:54:02 +0100 Subject: [PATCH 0859/1506] drm/i915: Flush the WCB following a WC write If we have just completed a WC write, we must ensure that the WCB (Write Combining Buffer) is flushed out to main memory before we can expect to see the results. This is especially important when mixing WC with GTT as the physical paths are different and cachelines are not naturally flushed. Testcase: igt/drv_selftests/live_coherency #gdg Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Matthew Auld <matthew.auld@intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180706115402.18547-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 0c0a1a959d0bd..be63e8bbb6d21 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -837,6 +837,10 @@ flush_write_domain(struct drm_i915_gem_object *obj, unsigned int flush_domains) } break; + case I915_GEM_DOMAIN_WC: + wmb(); + break; + case I915_GEM_DOMAIN_CPU: i915_gem_clflush_object(obj, I915_CLFLUSH_SYNC); break; -- GitLab From 58174eac1593f104c03a15330e0fea1b1ec01434 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 6 Jul 2018 13:26:10 +0100 Subject: [PATCH 0860/1506] drm/i915/gtt: Suppress warnings for dma_map_page As we propagate back the error to the caller for them to handle, we do not need the lowest level spitting out a redundant warning upon an allocation failure inside dma_map_page(). Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Matthew Auld <matthew.auld@intel.com> Reviewed-by: Matthew Auld <matthew.auld@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180706122611.4142-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_gtt.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index a9330de886f8c..92a06042e0bf7 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -561,8 +561,10 @@ static int __setup_page_dma(struct i915_address_space *vm, if (unlikely(!p->page)) return -ENOMEM; - p->daddr = dma_map_page(vm->dma, p->page, 0, PAGE_SIZE, - PCI_DMA_BIDIRECTIONAL); + p->daddr = dma_map_page_attrs(vm->dma, + p->page, 0, PAGE_SIZE, + PCI_DMA_BIDIRECTIONAL, + DMA_ATTR_NO_WARN); if (unlikely(dma_mapping_error(vm->dma, p->daddr))) { vm_free_page(vm, p->page); return -ENOMEM; @@ -643,8 +645,10 @@ setup_scratch_page(struct i915_address_space *vm, gfp_t gfp) if (unlikely(!page)) goto skip; - addr = dma_map_page(vm->dma, page, 0, size, - PCI_DMA_BIDIRECTIONAL); + addr = dma_map_page_attrs(vm->dma, + page, 0, size, + PCI_DMA_BIDIRECTIONAL, + DMA_ATTR_NO_WARN); if (unlikely(dma_mapping_error(vm->dma, addr))) goto free_page; -- GitLab From 66daec6b21840ea09af4c41f706867df7d81c820 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 6 Jul 2018 13:26:11 +0100 Subject: [PATCH 0861/1506] drm/i915/gtt: Control cache domain of dma_map_page() directly We already maually control the CPU cache for our page table directories, so we can tell the dma mapper to skip doing it as well. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Matthew Auld <matthew.auld@intel.com> Reviewed-by: Matthew Auld <matthew.auld@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180706122611.4142-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_gtt.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 92a06042e0bf7..e2793231ef49a 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -564,6 +564,7 @@ static int __setup_page_dma(struct i915_address_space *vm, p->daddr = dma_map_page_attrs(vm->dma, p->page, 0, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL, + DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_NO_WARN); if (unlikely(dma_mapping_error(vm->dma, p->daddr))) { vm_free_page(vm, p->page); @@ -648,6 +649,7 @@ setup_scratch_page(struct i915_address_space *vm, gfp_t gfp) addr = dma_map_page_attrs(vm->dma, page, 0, size, PCI_DMA_BIDIRECTIONAL, + DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_NO_WARN); if (unlikely(dma_mapping_error(vm->dma, addr))) goto free_page; -- GitLab From 207b700050b8d323d0c23b457c200b22c7ed3737 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 6 Jul 2018 13:53:38 +0100 Subject: [PATCH 0862/1506] drm/i915/selftests: Limit live_gtt allocation test to fit within RAM Limit the GTT size we try and allocate to ensure that it fits within RAM and does not trigger the oomkiller indiscriminately. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Matthew Auld <matthew.auld@intel.com> Reviewed-by: Matthew Auld <matthew.auld@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180706125338.24432-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/selftests/i915_gem_gtt.c | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c index e108fe4e0fd94..600a3bcbd3d6e 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c @@ -148,7 +148,7 @@ static int igt_ppgtt_alloc(void *arg) { struct drm_i915_private *dev_priv = arg; struct i915_hw_ppgtt *ppgtt; - u64 size, last; + u64 size, last, limit; int err = 0; /* Allocate a ppggt and try to fill the entire range */ @@ -163,10 +163,18 @@ static int igt_ppgtt_alloc(void *arg) if (!ppgtt->vm.allocate_va_range) goto err_ppgtt_cleanup; + /* + * While we only allocate the page tables here and so we could + * address a much larger GTT than we could actually fit into + * RAM, a practical limit is the amount of physical pages in the system. + * This should ensure that we do not run into the oomkiller during + * the test and take down the machine wilfully. + */ + limit = totalram_pages << PAGE_SHIFT; + limit = min(ppgtt->vm.total, limit); + /* Check we can allocate the entire range */ - for (size = 4096; - size <= ppgtt->vm.total; - size <<= 2) { + for (size = 4096; size <= limit; size <<= 2) { err = ppgtt->vm.allocate_va_range(&ppgtt->vm, 0, size); if (err) { if (err == -ENOMEM) { @@ -183,9 +191,7 @@ static int igt_ppgtt_alloc(void *arg) } /* Check we can incrementally allocate the entire range */ - for (last = 0, size = 4096; - size <= ppgtt->vm.total; - last = size, size <<= 2) { + for (last = 0, size = 4096; size <= limit; last = size, size <<= 2) { err = ppgtt->vm.allocate_va_range(&ppgtt->vm, last, size - last); if (err) { -- GitLab From 5b544337109081ac4de23e7ded1c31f7457e5f5e Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 6 Jul 2018 15:23:22 +0100 Subject: [PATCH 0863/1506] drm/i915/selftests: Replace magic 1<<22 with MI_USE_GGTT/MI_MEM_VIRTUAL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the magic bit with the proper symbolic name for instructing MI_STORE_DWORD_IMM to use a virtual address (on gen3) or the global GTT address (still virtual!) on gen4+. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20180706142323.25699-1-chris@chris-wilson.co.uk Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> --- drivers/gpu/drm/i915/selftests/huge_pages.c | 4 ++-- drivers/gpu/drm/i915/selftests/i915_gem_coherency.c | 4 ++-- drivers/gpu/drm/i915/selftests/i915_gem_context.c | 4 ++-- drivers/gpu/drm/i915/selftests/intel_hangcheck.c | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/selftests/huge_pages.c b/drivers/gpu/drm/i915/selftests/huge_pages.c index 1193dd36913a6..ab662dabcff7a 100644 --- a/drivers/gpu/drm/i915/selftests/huge_pages.c +++ b/drivers/gpu/drm/i915/selftests/huge_pages.c @@ -919,12 +919,12 @@ gpu_write_dw(struct i915_vma *vma, u64 offset, u32 val) *cmd++ = val; } else if (gen >= 4) { *cmd++ = MI_STORE_DWORD_IMM_GEN4 | - (gen < 6 ? 1 << 22 : 0); + (gen < 6 ? MI_USE_GGTT : 0); *cmd++ = 0; *cmd++ = offset; *cmd++ = val; } else { - *cmd++ = MI_STORE_DWORD_IMM | 1 << 22; + *cmd++ = MI_STORE_DWORD_IMM | MI_MEM_VIRTUAL; *cmd++ = offset; *cmd++ = val; } diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c b/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c index cb9eef1635e10..294c58aba2c15 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c @@ -210,12 +210,12 @@ static int gpu_set(struct drm_i915_gem_object *obj, *cs++ = upper_32_bits(i915_ggtt_offset(vma) + offset); *cs++ = v; } else if (INTEL_GEN(i915) >= 4) { - *cs++ = MI_STORE_DWORD_IMM_GEN4 | 1 << 22; + *cs++ = MI_STORE_DWORD_IMM_GEN4 | MI_USE_GGTT; *cs++ = 0; *cs++ = i915_ggtt_offset(vma) + offset; *cs++ = v; } else { - *cs++ = MI_STORE_DWORD_IMM | 1 << 22; + *cs++ = MI_STORE_DWORD_IMM | MI_MEM_VIRTUAL; *cs++ = i915_ggtt_offset(vma) + offset; *cs++ = v; *cs++ = MI_NOOP; diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_context.c b/drivers/gpu/drm/i915/selftests/i915_gem_context.c index 0d8e719802fa2..65100d3e31cff 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_context.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_context.c @@ -63,12 +63,12 @@ gpu_fill_dw(struct i915_vma *vma, u64 offset, unsigned long count, u32 value) *cmd++ = value; } else if (gen >= 4) { *cmd++ = MI_STORE_DWORD_IMM_GEN4 | - (gen < 6 ? 1 << 22 : 0); + (gen < 6 ? MI_USE_GGTT : 0); *cmd++ = 0; *cmd++ = offset; *cmd++ = value; } else { - *cmd++ = MI_STORE_DWORD_IMM | 1 << 22; + *cmd++ = MI_STORE_DWORD_IMM | MI_MEM_VIRTUAL; *cmd++ = offset; *cmd++ = value; } diff --git a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c index 5cb808dc5b500..0fc6da81f86e2 100644 --- a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c +++ b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c @@ -171,7 +171,7 @@ static int emit_recurse_batch(struct hang *h, *batch++ = MI_BATCH_BUFFER_START | 1 << 8; *batch++ = lower_32_bits(vma->node.start); } else if (INTEL_GEN(i915) >= 4) { - *batch++ = MI_STORE_DWORD_IMM_GEN4 | 1 << 22; + *batch++ = MI_STORE_DWORD_IMM_GEN4 | MI_USE_GGTT; *batch++ = 0; *batch++ = lower_32_bits(hws_address(hws, rq)); *batch++ = rq->fence.seqno; -- GitLab From 8fdbfd8686329e286465bcef11a7ef20be84d6b6 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 6 Jul 2018 15:23:23 +0100 Subject: [PATCH 0864/1506] drm/i915/selftests: Fixup missing MI_MEM_VIRTUAL for live_hangcheck MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We always want to use a virtual address (i.e. use the GTT) for MI_STORE_DWORD_IMM, but forgot the ever so important flag in live_hangcheck for gen3. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180706142323.25699-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/selftests/intel_hangcheck.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c index 0fc6da81f86e2..c838f7d08cb97 100644 --- a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c +++ b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c @@ -184,7 +184,7 @@ static int emit_recurse_batch(struct hang *h, *batch++ = MI_BATCH_BUFFER_START | 2 << 6; *batch++ = lower_32_bits(vma->node.start); } else { - *batch++ = MI_STORE_DWORD_IMM; + *batch++ = MI_STORE_DWORD_IMM | MI_MEM_VIRTUAL; *batch++ = lower_32_bits(hws_address(hws, rq)); *batch++ = rq->fence.seqno; *batch++ = MI_ARB_CHECK; -- GitLab From da99fe5f858525b0eac5a5296bba5d6bedb81abd Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 6 Jul 2018 11:39:42 +0100 Subject: [PATCH 0865/1506] drm/i915: Refactor export_fence() after i915_vma_move_to_active() Currently all callers are responsible for adding the vma to the active timeline and then exporting its fence. Combine the two operations into i915_vma_move_to_active() to move all the extra handling from the callers to the single site. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180706103947.15919-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 47 +++++++++---------- drivers/gpu/drm/i915/selftests/huge_pages.c | 4 -- .../drm/i915/selftests/i915_gem_coherency.c | 4 -- .../gpu/drm/i915/selftests/i915_gem_context.c | 4 -- .../gpu/drm/i915/selftests/i915_gem_object.c | 4 -- .../drm/i915/selftests/intel_workarounds.c | 3 -- 6 files changed, 21 insertions(+), 45 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index c2dd9b4cdacea..91f20445147f1 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1166,15 +1166,9 @@ static int __reloc_gpu_alloc(struct i915_execbuffer *eb, GEM_BUG_ON(!reservation_object_test_signaled_rcu(batch->resv, true)); i915_vma_move_to_active(batch, rq, 0); - reservation_object_lock(batch->resv, NULL); - reservation_object_add_excl_fence(batch->resv, &rq->fence); - reservation_object_unlock(batch->resv); i915_vma_unpin(batch); i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE); - reservation_object_lock(vma->resv, NULL); - reservation_object_add_excl_fence(vma->resv, &rq->fence); - reservation_object_unlock(vma->resv); rq->batch = batch; @@ -1771,25 +1765,6 @@ static int eb_relocate(struct i915_execbuffer *eb) return eb_relocate_slow(eb); } -static void eb_export_fence(struct i915_vma *vma, - struct i915_request *rq, - unsigned int flags) -{ - struct reservation_object *resv = vma->resv; - - /* - * Ignore errors from failing to allocate the new fence, we can't - * handle an error right now. Worst case should be missed - * synchronisation leading to rendering corruption. - */ - reservation_object_lock(resv, NULL); - if (flags & EXEC_OBJECT_WRITE) - reservation_object_add_excl_fence(resv, &rq->fence); - else if (reservation_object_reserve_shared(resv) == 0) - reservation_object_add_shared_fence(resv, &rq->fence); - reservation_object_unlock(resv); -} - static int eb_move_to_gpu(struct i915_execbuffer *eb) { const unsigned int count = eb->buffer_count; @@ -1844,7 +1819,6 @@ static int eb_move_to_gpu(struct i915_execbuffer *eb) struct i915_vma *vma = eb->vma[i]; i915_vma_move_to_active(vma, eb->request, flags); - eb_export_fence(vma, eb->request, flags); __eb_unreserve_vma(vma, flags); vma->exec_flags = NULL; @@ -1884,6 +1858,25 @@ static bool i915_gem_check_execbuffer(struct drm_i915_gem_execbuffer2 *exec) return true; } +static void export_fence(struct i915_vma *vma, + struct i915_request *rq, + unsigned int flags) +{ + struct reservation_object *resv = vma->resv; + + /* + * Ignore errors from failing to allocate the new fence, we can't + * handle an error right now. Worst case should be missed + * synchronisation leading to rendering corruption. + */ + reservation_object_lock(resv, NULL); + if (flags & EXEC_OBJECT_WRITE) + reservation_object_add_excl_fence(resv, &rq->fence); + else if (reservation_object_reserve_shared(resv) == 0) + reservation_object_add_shared_fence(resv, &rq->fence); + reservation_object_unlock(resv); +} + void i915_vma_move_to_active(struct i915_vma *vma, struct i915_request *rq, unsigned int flags) @@ -1921,6 +1914,8 @@ void i915_vma_move_to_active(struct i915_vma *vma, if (flags & EXEC_OBJECT_NEEDS_FENCE) i915_gem_active_set(&vma->last_fence, rq); + + export_fence(vma, rq, flags); } static int i915_reset_gen7_sol_offsets(struct i915_request *rq) diff --git a/drivers/gpu/drm/i915/selftests/huge_pages.c b/drivers/gpu/drm/i915/selftests/huge_pages.c index ab662dabcff7a..84bed69f30cc2 100644 --- a/drivers/gpu/drm/i915/selftests/huge_pages.c +++ b/drivers/gpu/drm/i915/selftests/huge_pages.c @@ -998,10 +998,6 @@ static int gpu_write(struct i915_vma *vma, i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE); - reservation_object_lock(vma->resv, NULL); - reservation_object_add_excl_fence(vma->resv, &rq->fence); - reservation_object_unlock(vma->resv); - err_request: i915_request_add(rq); diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c b/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c index 294c58aba2c15..97a16311f0831 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c @@ -225,10 +225,6 @@ static int gpu_set(struct drm_i915_gem_object *obj, i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE); i915_vma_unpin(vma); - reservation_object_lock(obj->resv, NULL); - reservation_object_add_excl_fence(obj->resv, &rq->fence); - reservation_object_unlock(obj->resv); - i915_request_add(rq); return 0; diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_context.c b/drivers/gpu/drm/i915/selftests/i915_gem_context.c index 65100d3e31cff..c642ab97698ee 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_context.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_context.c @@ -178,10 +178,6 @@ static int gpu_fill(struct drm_i915_gem_object *obj, i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE); i915_vma_unpin(vma); - reservation_object_lock(obj->resv, NULL); - reservation_object_add_excl_fence(obj->resv, &rq->fence); - reservation_object_unlock(obj->resv); - i915_request_add(rq); return 0; diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_object.c b/drivers/gpu/drm/i915/selftests/i915_gem_object.c index 6fe71865b7109..b2ccbc5e2bbed 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_object.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_object.c @@ -466,10 +466,6 @@ static int make_obj_busy(struct drm_i915_gem_object *obj) i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE); - reservation_object_lock(vma->resv, NULL); - reservation_object_add_excl_fence(vma->resv, &rq->fence); - reservation_object_unlock(vma->resv); - i915_request_add(rq); i915_gem_object_set_active_reference(obj); diff --git a/drivers/gpu/drm/i915/selftests/intel_workarounds.c b/drivers/gpu/drm/i915/selftests/intel_workarounds.c index 3d86b90ab7221..4a9dc01a364a8 100644 --- a/drivers/gpu/drm/i915/selftests/intel_workarounds.c +++ b/drivers/gpu/drm/i915/selftests/intel_workarounds.c @@ -68,9 +68,6 @@ read_nonprivs(struct i915_gem_context *ctx, struct intel_engine_cs *engine) intel_ring_advance(rq, cs); i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE); - reservation_object_lock(vma->resv, NULL); - reservation_object_add_excl_fence(vma->resv, &rq->fence); - reservation_object_unlock(vma->resv); i915_gem_object_get(result); i915_gem_object_set_active_reference(result); -- GitLab From 6dd7526f6f6c73961eecec8a4b9b717d414010f8 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 6 Jul 2018 11:39:43 +0100 Subject: [PATCH 0866/1506] drm/i915: Export i915_request_skip() In the next patch, we will want to start skipping requests on failing to complete their payloads. So export the utility function current used to make requests inoperable following a failed gpu reset. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180706103947.15919-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 25 +++---------------------- drivers/gpu/drm/i915/i915_request.c | 21 +++++++++++++++++++++ drivers/gpu/drm/i915/i915_request.h | 2 ++ 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index be63e8bbb6d21..2e05cf1140832 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3085,25 +3085,6 @@ int i915_gem_reset_prepare(struct drm_i915_private *dev_priv) return err; } -static void skip_request(struct i915_request *request) -{ - void *vaddr = request->ring->vaddr; - u32 head; - - /* As this request likely depends on state from the lost - * context, clear out all the user operations leaving the - * breadcrumb at the end (so we get the fence notifications). - */ - head = request->head; - if (request->postfix < head) { - memset(vaddr + head, 0, request->ring->size - head); - head = 0; - } - memset(vaddr + head, 0, request->postfix - head); - - dma_fence_set_error(&request->fence, -EIO); -} - static void engine_skip_context(struct i915_request *request) { struct intel_engine_cs *engine = request->engine; @@ -3118,10 +3099,10 @@ static void engine_skip_context(struct i915_request *request) list_for_each_entry_continue(request, &engine->timeline.requests, link) if (request->gem_context == hung_ctx) - skip_request(request); + i915_request_skip(request, -EIO); list_for_each_entry(request, &timeline->requests, link) - skip_request(request); + i915_request_skip(request, -EIO); spin_unlock(&timeline->lock); spin_unlock_irqrestore(&engine->timeline.lock, flags); @@ -3164,7 +3145,7 @@ i915_gem_reset_request(struct intel_engine_cs *engine, if (stalled) { i915_gem_context_mark_guilty(request->gem_context); - skip_request(request); + i915_request_skip(request, -EIO); /* If this context is now banned, skip all pending requests. */ if (i915_gem_context_is_banned(request->gem_context)) diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index a2f7e9358450f..7ae08b68121e8 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -1013,6 +1013,27 @@ i915_request_await_object(struct i915_request *to, return ret; } +void i915_request_skip(struct i915_request *rq, int error) +{ + void *vaddr = rq->ring->vaddr; + u32 head; + + GEM_BUG_ON(!IS_ERR_VALUE((long)error)); + dma_fence_set_error(&rq->fence, error); + + /* + * As this request likely depends on state from the lost + * context, clear out all the user operations leaving the + * breadcrumb at the end (so we get the fence notifications). + */ + head = rq->infix; + if (rq->postfix < head) { + memset(vaddr + head, 0, rq->ring->size - head); + head = 0; + } + memset(vaddr + head, 0, rq->postfix - head); +} + /* * NB: This function is not allowed to fail. Doing so would mean the the * request is not being tracked for completion but the work itself is diff --git a/drivers/gpu/drm/i915/i915_request.h b/drivers/gpu/drm/i915/i915_request.h index 7ee220ded9c9a..a355a081485f5 100644 --- a/drivers/gpu/drm/i915/i915_request.h +++ b/drivers/gpu/drm/i915/i915_request.h @@ -258,6 +258,8 @@ void i915_request_add(struct i915_request *rq); void __i915_request_submit(struct i915_request *request); void i915_request_submit(struct i915_request *request); +void i915_request_skip(struct i915_request *request, int error); + void __i915_request_unsubmit(struct i915_request *request); void i915_request_unsubmit(struct i915_request *request); -- GitLab From a523697857cdfb6a548f6caf38f42f4fe0f7d757 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 6 Jul 2018 11:39:44 +0100 Subject: [PATCH 0867/1506] drm/i915: Start returning an error from i915_vma_move_to_active() Handling such a late error in request construction is tricky, but to accommodate future patches which may allocate here, we potentially could err. To handle the error after already adjusting global state to track the new request, we must finish and submit the request. But we don't want to use the request as not everything is being tracked by it, so we opt to cancel the commands inside the request. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180706103947.15919-3-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/gvt/scheduler.c | 6 ++++- drivers/gpu/drm/i915/i915_drv.h | 6 ++--- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 25 +++++++++++++------ drivers/gpu/drm/i915/i915_gem_render_state.c | 2 +- drivers/gpu/drm/i915/selftests/huge_pages.c | 9 +++++-- .../drm/i915/selftests/i915_gem_coherency.c | 4 +-- .../gpu/drm/i915/selftests/i915_gem_context.c | 12 +++++++-- .../gpu/drm/i915/selftests/i915_gem_object.c | 7 +++--- drivers/gpu/drm/i915/selftests/i915_request.c | 8 ++++-- .../gpu/drm/i915/selftests/intel_hangcheck.c | 11 ++++++-- drivers/gpu/drm/i915/selftests/intel_lrc.c | 11 ++++++-- .../drm/i915/selftests/intel_workarounds.c | 6 +++-- 12 files changed, 78 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/scheduler.c b/drivers/gpu/drm/i915/gvt/scheduler.c index 928818f218f7f..b0e566956b8d5 100644 --- a/drivers/gpu/drm/i915/gvt/scheduler.c +++ b/drivers/gpu/drm/i915/gvt/scheduler.c @@ -476,7 +476,11 @@ static int prepare_shadow_batch_buffer(struct intel_vgpu_workload *workload) i915_gem_obj_finish_shmem_access(bb->obj); bb->accessing = false; - i915_vma_move_to_active(bb->vma, workload->req, 0); + ret = i915_vma_move_to_active(bb->vma, + workload->req, + 0); + if (ret) + goto err; } } return 0; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c1c637e47bf5d..07846e63671d0 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3090,9 +3090,9 @@ i915_gem_obj_finish_shmem_access(struct drm_i915_gem_object *obj) } int __must_check i915_mutex_lock_interruptible(struct drm_device *dev); -void i915_vma_move_to_active(struct i915_vma *vma, - struct i915_request *rq, - unsigned int flags); +int __must_check i915_vma_move_to_active(struct i915_vma *vma, + struct i915_request *rq, + unsigned int flags); int i915_gem_dumb_create(struct drm_file *file_priv, struct drm_device *dev, struct drm_mode_create_dumb *args); diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 91f20445147f1..97136e4ce91db 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1165,12 +1165,16 @@ static int __reloc_gpu_alloc(struct i915_execbuffer *eb, goto err_request; GEM_BUG_ON(!reservation_object_test_signaled_rcu(batch->resv, true)); - i915_vma_move_to_active(batch, rq, 0); - i915_vma_unpin(batch); + err = i915_vma_move_to_active(batch, rq, 0); + if (err) + goto skip_request; - i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE); + err = i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE); + if (err) + goto skip_request; rq->batch = batch; + i915_vma_unpin(batch); cache->rq = rq; cache->rq_cmd = cmd; @@ -1179,6 +1183,8 @@ static int __reloc_gpu_alloc(struct i915_execbuffer *eb, /* Return with batch mapping (cmd) still pinned */ return 0; +skip_request: + i915_request_skip(rq, err); err_request: i915_request_add(rq); err_unpin: @@ -1818,7 +1824,11 @@ static int eb_move_to_gpu(struct i915_execbuffer *eb) unsigned int flags = eb->flags[i]; struct i915_vma *vma = eb->vma[i]; - i915_vma_move_to_active(vma, eb->request, flags); + err = i915_vma_move_to_active(vma, eb->request, flags); + if (unlikely(err)) { + i915_request_skip(eb->request, err); + return err; + } __eb_unreserve_vma(vma, flags); vma->exec_flags = NULL; @@ -1877,9 +1887,9 @@ static void export_fence(struct i915_vma *vma, reservation_object_unlock(resv); } -void i915_vma_move_to_active(struct i915_vma *vma, - struct i915_request *rq, - unsigned int flags) +int i915_vma_move_to_active(struct i915_vma *vma, + struct i915_request *rq, + unsigned int flags) { struct drm_i915_gem_object *obj = vma->obj; const unsigned int idx = rq->engine->id; @@ -1916,6 +1926,7 @@ void i915_vma_move_to_active(struct i915_vma *vma, i915_gem_active_set(&vma->last_fence, rq); export_fence(vma, rq, flags); + return 0; } static int i915_reset_gen7_sol_offsets(struct i915_request *rq) diff --git a/drivers/gpu/drm/i915/i915_gem_render_state.c b/drivers/gpu/drm/i915/i915_gem_render_state.c index 3210cedfa46c3..90baf9086d0a4 100644 --- a/drivers/gpu/drm/i915/i915_gem_render_state.c +++ b/drivers/gpu/drm/i915/i915_gem_render_state.c @@ -222,7 +222,7 @@ int i915_gem_render_state_emit(struct i915_request *rq) goto err_unpin; } - i915_vma_move_to_active(so.vma, rq, 0); + err = i915_vma_move_to_active(so.vma, rq, 0); err_unpin: i915_vma_unpin(so.vma); err_vma: diff --git a/drivers/gpu/drm/i915/selftests/huge_pages.c b/drivers/gpu/drm/i915/selftests/huge_pages.c index 84bed69f30cc2..d9f439f6219f6 100644 --- a/drivers/gpu/drm/i915/selftests/huge_pages.c +++ b/drivers/gpu/drm/i915/selftests/huge_pages.c @@ -985,7 +985,10 @@ static int gpu_write(struct i915_vma *vma, goto err_request; } - i915_vma_move_to_active(batch, rq, 0); + err = i915_vma_move_to_active(batch, rq, 0); + if (err) + goto err_request; + i915_gem_object_set_active_reference(batch->obj); i915_vma_unpin(batch); i915_vma_close(batch); @@ -996,7 +999,9 @@ static int gpu_write(struct i915_vma *vma, if (err) goto err_request; - i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE); + err = i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE); + if (err) + i915_request_skip(rq, err); err_request: i915_request_add(rq); diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c b/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c index 97a16311f0831..1de7c1402fd5a 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c @@ -222,12 +222,12 @@ static int gpu_set(struct drm_i915_gem_object *obj, } intel_ring_advance(rq, cs); - i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE); + err = i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE); i915_vma_unpin(vma); i915_request_add(rq); - return 0; + return err; } static bool always_valid(struct drm_i915_private *i915) diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_context.c b/drivers/gpu/drm/i915/selftests/i915_gem_context.c index c642ab97698ee..5fbe15f4effdb 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_context.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_context.c @@ -170,18 +170,26 @@ static int gpu_fill(struct drm_i915_gem_object *obj, if (err) goto err_request; - i915_vma_move_to_active(batch, rq, 0); + err = i915_vma_move_to_active(batch, rq, 0); + if (err) + goto skip_request; + + err = i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE); + if (err) + goto skip_request; + i915_gem_object_set_active_reference(batch->obj); i915_vma_unpin(batch); i915_vma_close(batch); - i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE); i915_vma_unpin(vma); i915_request_add(rq); return 0; +skip_request: + i915_request_skip(rq, err); err_request: i915_request_add(rq); err_batch: diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_object.c b/drivers/gpu/drm/i915/selftests/i915_gem_object.c index b2ccbc5e2bbed..25c2b2d433bdb 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_object.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_object.c @@ -464,13 +464,14 @@ static int make_obj_busy(struct drm_i915_gem_object *obj) return PTR_ERR(rq); } - i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE); + err = i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE); i915_request_add(rq); - i915_gem_object_set_active_reference(obj); + __i915_gem_object_release_unless_active(obj); i915_vma_unpin(vma); - return 0; + + return err; } static bool assert_mmap_offset(struct drm_i915_private *i915, diff --git a/drivers/gpu/drm/i915/selftests/i915_request.c b/drivers/gpu/drm/i915/selftests/i915_request.c index cc27edc40356c..43995fc3534d7 100644 --- a/drivers/gpu/drm/i915/selftests/i915_request.c +++ b/drivers/gpu/drm/i915/selftests/i915_request.c @@ -675,7 +675,9 @@ static int live_all_engines(void *arg) i915_gem_object_set_active_reference(batch->obj); } - i915_vma_move_to_active(batch, request[id], 0); + err = i915_vma_move_to_active(batch, request[id], 0); + GEM_BUG_ON(err); + i915_request_get(request[id]); i915_request_add(request[id]); } @@ -785,7 +787,9 @@ static int live_sequential_engines(void *arg) GEM_BUG_ON(err); request[id]->batch = batch; - i915_vma_move_to_active(batch, request[id], 0); + err = i915_vma_move_to_active(batch, request[id], 0); + GEM_BUG_ON(err); + i915_gem_object_set_active_reference(batch->obj); i915_vma_get(batch); diff --git a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c index c838f7d08cb97..73462a65a3303 100644 --- a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c +++ b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c @@ -130,13 +130,19 @@ static int emit_recurse_batch(struct hang *h, if (err) goto unpin_vma; - i915_vma_move_to_active(vma, rq, 0); + err = i915_vma_move_to_active(vma, rq, 0); + if (err) + goto unpin_hws; + if (!i915_gem_object_has_active_reference(vma->obj)) { i915_gem_object_get(vma->obj); i915_gem_object_set_active_reference(vma->obj); } - i915_vma_move_to_active(hws, rq, 0); + err = i915_vma_move_to_active(hws, rq, 0); + if (err) + goto unpin_hws; + if (!i915_gem_object_has_active_reference(hws->obj)) { i915_gem_object_get(hws->obj); i915_gem_object_set_active_reference(hws->obj); @@ -205,6 +211,7 @@ static int emit_recurse_batch(struct hang *h, err = rq->engine->emit_bb_start(rq, vma->node.start, PAGE_SIZE, flags); +unpin_hws: i915_vma_unpin(hws); unpin_vma: i915_vma_unpin(vma); diff --git a/drivers/gpu/drm/i915/selftests/intel_lrc.c b/drivers/gpu/drm/i915/selftests/intel_lrc.c index 730a02d390586..636cb68191e3b 100644 --- a/drivers/gpu/drm/i915/selftests/intel_lrc.c +++ b/drivers/gpu/drm/i915/selftests/intel_lrc.c @@ -104,13 +104,19 @@ static int emit_recurse_batch(struct spinner *spin, if (err) goto unpin_vma; - i915_vma_move_to_active(vma, rq, 0); + err = i915_vma_move_to_active(vma, rq, 0); + if (err) + goto unpin_hws; + if (!i915_gem_object_has_active_reference(vma->obj)) { i915_gem_object_get(vma->obj); i915_gem_object_set_active_reference(vma->obj); } - i915_vma_move_to_active(hws, rq, 0); + err = i915_vma_move_to_active(hws, rq, 0); + if (err) + goto unpin_hws; + if (!i915_gem_object_has_active_reference(hws->obj)) { i915_gem_object_get(hws->obj); i915_gem_object_set_active_reference(hws->obj); @@ -134,6 +140,7 @@ static int emit_recurse_batch(struct spinner *spin, err = rq->engine->emit_bb_start(rq, vma->node.start, PAGE_SIZE, 0); +unpin_hws: i915_vma_unpin(hws); unpin_vma: i915_vma_unpin(vma); diff --git a/drivers/gpu/drm/i915/selftests/intel_workarounds.c b/drivers/gpu/drm/i915/selftests/intel_workarounds.c index 4a9dc01a364a8..fafdec3fe83eb 100644 --- a/drivers/gpu/drm/i915/selftests/intel_workarounds.c +++ b/drivers/gpu/drm/i915/selftests/intel_workarounds.c @@ -49,6 +49,10 @@ read_nonprivs(struct i915_gem_context *ctx, struct intel_engine_cs *engine) goto err_pin; } + err = i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE); + if (err) + goto err_req; + srm = MI_STORE_REGISTER_MEM | MI_SRM_LRM_GLOBAL_GTT; if (INTEL_GEN(ctx->i915) >= 8) srm++; @@ -67,8 +71,6 @@ read_nonprivs(struct i915_gem_context *ctx, struct intel_engine_cs *engine) } intel_ring_advance(rq, cs); - i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE); - i915_gem_object_get(result); i915_gem_object_set_active_reference(result); -- GitLab From e6bb1d7f1adfcd24ac7d82ab157a8b8809a0d2c8 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 6 Jul 2018 11:39:45 +0100 Subject: [PATCH 0868/1506] drm/i915: Move i915_vma_move_to_active() to i915_vma.c i915_vma_move_to_active() has grown beyond its execbuf origins, and should take its rightful place in i915_vma.c as a method for i915_vma! Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180706103947.15919-4-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_drv.h | 3 -- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 61 ---------------------- drivers/gpu/drm/i915/i915_vma.c | 61 ++++++++++++++++++++++ drivers/gpu/drm/i915/i915_vma.h | 4 ++ 4 files changed, 65 insertions(+), 64 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 07846e63671d0..c790081777083 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3090,9 +3090,6 @@ i915_gem_obj_finish_shmem_access(struct drm_i915_gem_object *obj) } int __must_check i915_mutex_lock_interruptible(struct drm_device *dev); -int __must_check i915_vma_move_to_active(struct i915_vma *vma, - struct i915_request *rq, - unsigned int flags); int i915_gem_dumb_create(struct drm_file *file_priv, struct drm_device *dev, struct drm_mode_create_dumb *args); diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 97136e4ce91db..3f0c612d42e78 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1868,67 +1868,6 @@ static bool i915_gem_check_execbuffer(struct drm_i915_gem_execbuffer2 *exec) return true; } -static void export_fence(struct i915_vma *vma, - struct i915_request *rq, - unsigned int flags) -{ - struct reservation_object *resv = vma->resv; - - /* - * Ignore errors from failing to allocate the new fence, we can't - * handle an error right now. Worst case should be missed - * synchronisation leading to rendering corruption. - */ - reservation_object_lock(resv, NULL); - if (flags & EXEC_OBJECT_WRITE) - reservation_object_add_excl_fence(resv, &rq->fence); - else if (reservation_object_reserve_shared(resv) == 0) - reservation_object_add_shared_fence(resv, &rq->fence); - reservation_object_unlock(resv); -} - -int i915_vma_move_to_active(struct i915_vma *vma, - struct i915_request *rq, - unsigned int flags) -{ - struct drm_i915_gem_object *obj = vma->obj; - const unsigned int idx = rq->engine->id; - - lockdep_assert_held(&rq->i915->drm.struct_mutex); - GEM_BUG_ON(!drm_mm_node_allocated(&vma->node)); - - /* - * Add a reference if we're newly entering the active list. - * The order in which we add operations to the retirement queue is - * vital here: mark_active adds to the start of the callback list, - * such that subsequent callbacks are called first. Therefore we - * add the active reference first and queue for it to be dropped - * *last*. - */ - if (!i915_vma_is_active(vma)) - obj->active_count++; - i915_vma_set_active(vma, idx); - i915_gem_active_set(&vma->last_read[idx], rq); - list_move_tail(&vma->vm_link, &vma->vm->active_list); - - obj->write_domain = 0; - if (flags & EXEC_OBJECT_WRITE) { - obj->write_domain = I915_GEM_DOMAIN_RENDER; - - if (intel_fb_obj_invalidate(obj, ORIGIN_CS)) - i915_gem_active_set(&obj->frontbuffer_write, rq); - - obj->read_domains = 0; - } - obj->read_domains |= I915_GEM_GPU_DOMAINS; - - if (flags & EXEC_OBJECT_NEEDS_FENCE) - i915_gem_active_set(&vma->last_fence, rq); - - export_fence(vma, rq, flags); - return 0; -} - static int i915_reset_gen7_sol_offsets(struct i915_request *rq) { u32 *cs; diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c index 518de47111ff2..6f3a0f2296c22 100644 --- a/drivers/gpu/drm/i915/i915_vma.c +++ b/drivers/gpu/drm/i915/i915_vma.c @@ -859,6 +859,67 @@ void i915_vma_revoke_mmap(struct i915_vma *vma) list_del(&vma->obj->userfault_link); } +static void export_fence(struct i915_vma *vma, + struct i915_request *rq, + unsigned int flags) +{ + struct reservation_object *resv = vma->resv; + + /* + * Ignore errors from failing to allocate the new fence, we can't + * handle an error right now. Worst case should be missed + * synchronisation leading to rendering corruption. + */ + reservation_object_lock(resv, NULL); + if (flags & EXEC_OBJECT_WRITE) + reservation_object_add_excl_fence(resv, &rq->fence); + else if (reservation_object_reserve_shared(resv) == 0) + reservation_object_add_shared_fence(resv, &rq->fence); + reservation_object_unlock(resv); +} + +int i915_vma_move_to_active(struct i915_vma *vma, + struct i915_request *rq, + unsigned int flags) +{ + struct drm_i915_gem_object *obj = vma->obj; + const unsigned int idx = rq->engine->id; + + lockdep_assert_held(&rq->i915->drm.struct_mutex); + GEM_BUG_ON(!drm_mm_node_allocated(&vma->node)); + + /* + * Add a reference if we're newly entering the active list. + * The order in which we add operations to the retirement queue is + * vital here: mark_active adds to the start of the callback list, + * such that subsequent callbacks are called first. Therefore we + * add the active reference first and queue for it to be dropped + * *last*. + */ + if (!i915_vma_is_active(vma)) + obj->active_count++; + i915_vma_set_active(vma, idx); + i915_gem_active_set(&vma->last_read[idx], rq); + list_move_tail(&vma->vm_link, &vma->vm->active_list); + + obj->write_domain = 0; + if (flags & EXEC_OBJECT_WRITE) { + obj->write_domain = I915_GEM_DOMAIN_RENDER; + + if (intel_fb_obj_invalidate(obj, ORIGIN_CS)) + i915_gem_active_set(&obj->frontbuffer_write, rq); + + obj->read_domains = 0; + } + obj->read_domains |= I915_GEM_GPU_DOMAINS; + + if (flags & EXEC_OBJECT_NEEDS_FENCE) + i915_gem_active_set(&vma->last_fence, rq); + + export_fence(vma, rq, flags); + return 0; +} + int i915_vma_unbind(struct i915_vma *vma) { unsigned long active; diff --git a/drivers/gpu/drm/i915/i915_vma.h b/drivers/gpu/drm/i915/i915_vma.h index 66a228931517f..a218b689e418a 100644 --- a/drivers/gpu/drm/i915/i915_vma.h +++ b/drivers/gpu/drm/i915/i915_vma.h @@ -215,6 +215,10 @@ static inline bool i915_vma_has_active_engine(const struct i915_vma *vma, return vma->active & BIT(engine); } +int __must_check i915_vma_move_to_active(struct i915_vma *vma, + struct i915_request *rq, + unsigned int flags); + static inline u32 i915_ggtt_offset(const struct i915_vma *vma) { GEM_BUG_ON(!i915_vma_is_ggtt(vma)); -- GitLab From 5c3f8c221c77ccdce3c2a8b96d196e5f4e2dac0c Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 6 Jul 2018 11:39:46 +0100 Subject: [PATCH 0869/1506] drm/i915: Track vma activity per fence.context, not per engine In the next patch, we will want to be able to use more flexible request timelines that can hop between engines. From the vma pov, we can then not rely on the binding of this request to an engine and so can not ensure that different requests are ordered through a per-engine timeline, and so we must track activity of all timelines. (We track activity on the vma itself to prevent unbinding from HW before the HW has finished accessing it.) v2: Switch to a rbtree for 32b safety (since using u64 as a radixtree index is fraught with aliasing of unsigned longs). v3: s/lookup_active/active_instance/ because we can never agree on names Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180706103947.15919-5-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_gtt.c | 5 +- drivers/gpu/drm/i915/i915_gpu_error.c | 14 +--- drivers/gpu/drm/i915/i915_gpu_error.h | 2 +- drivers/gpu/drm/i915/i915_request.h | 1 + drivers/gpu/drm/i915/i915_vma.c | 112 +++++++++++++++++++------- drivers/gpu/drm/i915/i915_vma.h | 46 +++-------- 6 files changed, 100 insertions(+), 80 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index e2793231ef49a..4db31aaaa9d39 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -2074,7 +2074,6 @@ static struct i915_vma *pd_vma_create(struct gen6_hw_ppgtt *ppgtt, int size) struct drm_i915_private *i915 = ppgtt->base.vm.i915; struct i915_ggtt *ggtt = &i915->ggtt; struct i915_vma *vma; - int i; GEM_BUG_ON(!IS_ALIGNED(size, I915_GTT_PAGE_SIZE)); GEM_BUG_ON(size > ggtt->vm.total); @@ -2083,14 +2082,14 @@ static struct i915_vma *pd_vma_create(struct gen6_hw_ppgtt *ppgtt, int size) if (!vma) return ERR_PTR(-ENOMEM); - for (i = 0; i < ARRAY_SIZE(vma->last_read); i++) - init_request_active(&vma->last_read[i], NULL); init_request_active(&vma->last_fence, NULL); vma->vm = &ggtt->vm; vma->ops = &pd_vma_ops; vma->private = ppgtt; + vma->active = RB_ROOT; + vma->size = size; vma->fence_size = size; vma->flags = I915_VMA_GGTT; diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index df524c9cad408..8c81cf3aa182e 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -335,21 +335,16 @@ static void print_error_buffers(struct drm_i915_error_state_buf *m, struct drm_i915_error_buffer *err, int count) { - int i; - err_printf(m, "%s [%d]:\n", name, count); while (count--) { - err_printf(m, " %08x_%08x %8u %02x %02x [ ", + err_printf(m, " %08x_%08x %8u %02x %02x %02x", upper_32_bits(err->gtt_offset), lower_32_bits(err->gtt_offset), err->size, err->read_domains, - err->write_domain); - for (i = 0; i < I915_NUM_ENGINES; i++) - err_printf(m, "%02x ", err->rseqno[i]); - - err_printf(m, "] %02x", err->wseqno); + err->write_domain, + err->wseqno); err_puts(m, tiling_flag(err->tiling)); err_puts(m, dirty_flag(err->dirty)); err_puts(m, purgeable_flag(err->purgeable)); @@ -1021,13 +1016,10 @@ static void capture_bo(struct drm_i915_error_buffer *err, struct i915_vma *vma) { struct drm_i915_gem_object *obj = vma->obj; - int i; err->size = obj->base.size; err->name = obj->base.name; - for (i = 0; i < I915_NUM_ENGINES; i++) - err->rseqno[i] = __active_get_seqno(&vma->last_read[i]); err->wseqno = __active_get_seqno(&obj->frontbuffer_write); err->engine = __active_get_engine_id(&obj->frontbuffer_write); diff --git a/drivers/gpu/drm/i915/i915_gpu_error.h b/drivers/gpu/drm/i915/i915_gpu_error.h index 58910f1dc67c2..f893a4e8b7831 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.h +++ b/drivers/gpu/drm/i915/i915_gpu_error.h @@ -177,7 +177,7 @@ struct i915_gpu_state { struct drm_i915_error_buffer { u32 size; u32 name; - u32 rseqno[I915_NUM_ENGINES], wseqno; + u32 wseqno; u64 gtt_offset; u32 read_domains; u32 write_domain; diff --git a/drivers/gpu/drm/i915/i915_request.h b/drivers/gpu/drm/i915/i915_request.h index a355a081485f5..e1c9365dfefb1 100644 --- a/drivers/gpu/drm/i915/i915_request.h +++ b/drivers/gpu/drm/i915/i915_request.h @@ -380,6 +380,7 @@ static inline void init_request_active(struct i915_gem_active *active, i915_gem_retire_fn retire) { + RCU_INIT_POINTER(active->request, NULL); INIT_LIST_HEAD(&active->link); active->retire = retire ?: i915_gem_retire_noop; } diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c index 6f3a0f2296c22..b4cc98330225e 100644 --- a/drivers/gpu/drm/i915/i915_vma.c +++ b/drivers/gpu/drm/i915/i915_vma.c @@ -63,18 +63,20 @@ static void vma_print_allocator(struct i915_vma *vma, const char *reason) #endif +struct i915_vma_active { + struct i915_gem_active base; + struct i915_vma *vma; + struct rb_node node; + u64 timeline; +}; + static void -i915_vma_retire(struct i915_gem_active *active, struct i915_request *rq) +__i915_vma_retire(struct i915_vma *vma, struct i915_request *rq) { - const unsigned int idx = rq->engine->id; - struct i915_vma *vma = - container_of(active, struct i915_vma, last_read[idx]); struct drm_i915_gem_object *obj = vma->obj; - GEM_BUG_ON(!i915_vma_has_active_engine(vma, idx)); - - i915_vma_clear_active(vma, idx); - if (i915_vma_is_active(vma)) + GEM_BUG_ON(!i915_vma_is_active(vma)); + if (--vma->active_count) return; GEM_BUG_ON(!drm_mm_node_allocated(&vma->node)); @@ -108,6 +110,15 @@ i915_vma_retire(struct i915_gem_active *active, struct i915_request *rq) } } +static void +i915_vma_retire(struct i915_gem_active *base, struct i915_request *rq) +{ + struct i915_vma_active *active = + container_of(base, typeof(*active), base); + + __i915_vma_retire(active->vma, rq); +} + static struct i915_vma * vma_create(struct drm_i915_gem_object *obj, struct i915_address_space *vm, @@ -115,7 +126,6 @@ vma_create(struct drm_i915_gem_object *obj, { struct i915_vma *vma; struct rb_node *rb, **p; - int i; /* The aliasing_ppgtt should never be used directly! */ GEM_BUG_ON(vm == &vm->i915->mm.aliasing_ppgtt->vm); @@ -124,8 +134,8 @@ vma_create(struct drm_i915_gem_object *obj, if (vma == NULL) return ERR_PTR(-ENOMEM); - for (i = 0; i < ARRAY_SIZE(vma->last_read); i++) - init_request_active(&vma->last_read[i], i915_vma_retire); + vma->active = RB_ROOT; + init_request_active(&vma->last_fence, NULL); vma->vm = vm; vma->ops = &vm->vma_ops; @@ -778,13 +788,11 @@ void i915_vma_reopen(struct i915_vma *vma) static void __i915_vma_destroy(struct i915_vma *vma) { struct drm_i915_private *i915 = vma->vm->i915; - int i; + struct i915_vma_active *iter, *n; GEM_BUG_ON(vma->node.allocated); GEM_BUG_ON(vma->fence); - for (i = 0; i < ARRAY_SIZE(vma->last_read); i++) - GEM_BUG_ON(i915_gem_active_isset(&vma->last_read[i])); GEM_BUG_ON(i915_gem_active_isset(&vma->last_fence)); list_del(&vma->obj_link); @@ -795,6 +803,11 @@ static void __i915_vma_destroy(struct i915_vma *vma) if (!i915_vma_is_ggtt(vma)) i915_ppgtt_put(i915_vm_to_ppgtt(vma->vm)); + rbtree_postorder_for_each_entry_safe(iter, n, &vma->active, node) { + GEM_BUG_ON(i915_gem_active_isset(&iter->base)); + kfree(iter); + } + kmem_cache_free(i915->vmas, vma); } @@ -878,16 +891,54 @@ static void export_fence(struct i915_vma *vma, reservation_object_unlock(resv); } +static struct i915_gem_active *active_instance(struct i915_vma *vma, u64 idx) +{ + struct i915_vma_active *active; + struct rb_node **p, *parent; + + parent = NULL; + p = &vma->active.rb_node; + while (*p) { + parent = *p; + + active = rb_entry(parent, struct i915_vma_active, node); + if (active->timeline == idx) + return &active->base; + + if (active->timeline < idx) + p = &parent->rb_right; + else + p = &parent->rb_left; + } + + active = kmalloc(sizeof(*active), GFP_KERNEL); + if (unlikely(!active)) + return ERR_PTR(-ENOMEM); + + init_request_active(&active->base, i915_vma_retire); + active->vma = vma; + active->timeline = idx; + + rb_link_node(&active->node, parent, p); + rb_insert_color(&active->node, &vma->active); + + return &active->base; +} + int i915_vma_move_to_active(struct i915_vma *vma, struct i915_request *rq, unsigned int flags) { struct drm_i915_gem_object *obj = vma->obj; - const unsigned int idx = rq->engine->id; + struct i915_gem_active *active; lockdep_assert_held(&rq->i915->drm.struct_mutex); GEM_BUG_ON(!drm_mm_node_allocated(&vma->node)); + active = active_instance(vma, rq->fence.context); + if (IS_ERR(active)) + return PTR_ERR(active); + /* * Add a reference if we're newly entering the active list. * The order in which we add operations to the retirement queue is @@ -896,11 +947,13 @@ int i915_vma_move_to_active(struct i915_vma *vma, * add the active reference first and queue for it to be dropped * *last*. */ - if (!i915_vma_is_active(vma)) + if (!i915_gem_active_isset(active) && !vma->active_count++) { + list_move_tail(&vma->vm_link, &vma->vm->active_list); obj->active_count++; - i915_vma_set_active(vma, idx); - i915_gem_active_set(&vma->last_read[idx], rq); - list_move_tail(&vma->vm_link, &vma->vm->active_list); + } + i915_gem_active_set(active, rq); + GEM_BUG_ON(!i915_vma_is_active(vma)); + GEM_BUG_ON(!obj->active_count); obj->write_domain = 0; if (flags & EXEC_OBJECT_WRITE) { @@ -922,7 +975,6 @@ int i915_vma_move_to_active(struct i915_vma *vma, int i915_vma_unbind(struct i915_vma *vma) { - unsigned long active; int ret; lockdep_assert_held(&vma->vm->i915->drm.struct_mutex); @@ -932,9 +984,8 @@ int i915_vma_unbind(struct i915_vma *vma) * have side-effects such as unpinning or even unbinding this vma. */ might_sleep(); - active = i915_vma_get_active(vma); - if (active) { - int idx; + if (i915_vma_is_active(vma)) { + struct i915_vma_active *active, *n; /* * When a closed VMA is retired, it is unbound - eek. @@ -951,18 +1002,17 @@ int i915_vma_unbind(struct i915_vma *vma) */ __i915_vma_pin(vma); - for_each_active(active, idx) { - ret = i915_gem_active_retire(&vma->last_read[idx], + rbtree_postorder_for_each_entry_safe(active, n, + &vma->active, node) { + ret = i915_gem_active_retire(&active->base, &vma->vm->i915->drm.struct_mutex); if (ret) - break; - } - - if (!ret) { - ret = i915_gem_active_retire(&vma->last_fence, - &vma->vm->i915->drm.struct_mutex); + goto unpin; } + ret = i915_gem_active_retire(&vma->last_fence, + &vma->vm->i915->drm.struct_mutex); +unpin: __i915_vma_unpin(vma); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/i915_vma.h b/drivers/gpu/drm/i915/i915_vma.h index a218b689e418a..c297b0a0dc47e 100644 --- a/drivers/gpu/drm/i915/i915_vma.h +++ b/drivers/gpu/drm/i915/i915_vma.h @@ -26,6 +26,7 @@ #define __I915_VMA_H__ #include <linux/io-mapping.h> +#include <linux/rbtree.h> #include <drm/drm_mm.h> @@ -94,8 +95,8 @@ struct i915_vma { #define I915_VMA_USERFAULT BIT(I915_VMA_USERFAULT_BIT) #define I915_VMA_GGTT_WRITE BIT(12) - unsigned int active; - struct i915_gem_active last_read[I915_NUM_ENGINES]; + unsigned int active_count; + struct rb_root active; struct i915_gem_active last_fence; /** @@ -138,6 +139,15 @@ i915_vma_instance(struct drm_i915_gem_object *obj, void i915_vma_unpin_and_release(struct i915_vma **p_vma); +static inline bool i915_vma_is_active(struct i915_vma *vma) +{ + return vma->active_count; +} + +int __must_check i915_vma_move_to_active(struct i915_vma *vma, + struct i915_request *rq, + unsigned int flags); + static inline bool i915_vma_is_ggtt(const struct i915_vma *vma) { return vma->flags & I915_VMA_GGTT; @@ -187,38 +197,6 @@ static inline bool i915_vma_has_userfault(const struct i915_vma *vma) return test_bit(I915_VMA_USERFAULT_BIT, &vma->flags); } -static inline unsigned int i915_vma_get_active(const struct i915_vma *vma) -{ - return vma->active; -} - -static inline bool i915_vma_is_active(const struct i915_vma *vma) -{ - return i915_vma_get_active(vma); -} - -static inline void i915_vma_set_active(struct i915_vma *vma, - unsigned int engine) -{ - vma->active |= BIT(engine); -} - -static inline void i915_vma_clear_active(struct i915_vma *vma, - unsigned int engine) -{ - vma->active &= ~BIT(engine); -} - -static inline bool i915_vma_has_active_engine(const struct i915_vma *vma, - unsigned int engine) -{ - return vma->active & BIT(engine); -} - -int __must_check i915_vma_move_to_active(struct i915_vma *vma, - struct i915_request *rq, - unsigned int flags); - static inline u32 i915_ggtt_offset(const struct i915_vma *vma) { GEM_BUG_ON(!i915_vma_is_ggtt(vma)); -- GitLab From 8b293eb53a7d7605f762351918083a4e402dc784 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 6 Jul 2018 13:31:57 +0100 Subject: [PATCH 0870/1506] drm/i915: Track the last-active inside the i915_vma Using a VMA on more than one timeline concurrently is the exception rather than the rule (using it concurrently on multiple engines). As we expect to only use one active tracker, store the most recently used tracker inside the i915_vma itself and only fallback to the rbtree if we need a second or more concurrent active trackers. v2: Comments on how we overwrite any existing last_active cache. v3: __list_del_entry() before list_replace_init() is confusing and, much more important, entirely redundant. v4: Note that both last_active and the rbtree may be simultaneously tracking this timeline, albeit with different requests, and so the vma may be retired twice for the same timeline. v5: No, that list_del is required! Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180706123157.9645-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_vma.c | 58 +++++++++++++++++++++++++++++++-- drivers/gpu/drm/i915/i915_vma.h | 1 + 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c index b4cc98330225e..ed4e0fb558f7c 100644 --- a/drivers/gpu/drm/i915/i915_vma.c +++ b/drivers/gpu/drm/i915/i915_vma.c @@ -119,6 +119,12 @@ i915_vma_retire(struct i915_gem_active *base, struct i915_request *rq) __i915_vma_retire(active->vma, rq); } +static void +i915_vma_last_retire(struct i915_gem_active *base, struct i915_request *rq) +{ + __i915_vma_retire(container_of(base, struct i915_vma, last_active), rq); +} + static struct i915_vma * vma_create(struct drm_i915_gem_object *obj, struct i915_address_space *vm, @@ -136,6 +142,7 @@ vma_create(struct drm_i915_gem_object *obj, vma->active = RB_ROOT; + init_request_active(&vma->last_active, i915_vma_last_retire); init_request_active(&vma->last_fence, NULL); vma->vm = vm; vma->ops = &vm->vma_ops; @@ -895,6 +902,29 @@ static struct i915_gem_active *active_instance(struct i915_vma *vma, u64 idx) { struct i915_vma_active *active; struct rb_node **p, *parent; + struct i915_request *old; + + /* + * We track the most recently used timeline to skip a rbtree search + * for the common case, under typical loads we never need the rbtree + * at all. We can reuse the last_active slot if it is empty, that is + * after the previous activity has been retired, or if the active + * matches the current timeline. + * + * Note that we allow the timeline to be active simultaneously in + * the rbtree and the last_active cache. We do this to avoid having + * to search and replace the rbtree element for a new timeline, with + * the cost being that we must be aware that the vma may be retired + * twice for the same timeline (as the older rbtree element will be + * retired before the new request added to last_active). + */ + old = i915_gem_active_raw(&vma->last_active, + &vma->vm->i915->drm.struct_mutex); + if (!old || old->fence.context == idx) + goto out; + + /* Move the currently active fence into the rbtree */ + idx = old->fence.context; parent = NULL; p = &vma->active.rb_node; @@ -903,7 +933,7 @@ static struct i915_gem_active *active_instance(struct i915_vma *vma, u64 idx) active = rb_entry(parent, struct i915_vma_active, node); if (active->timeline == idx) - return &active->base; + goto replace; if (active->timeline < idx) p = &parent->rb_right; @@ -922,7 +952,26 @@ static struct i915_gem_active *active_instance(struct i915_vma *vma, u64 idx) rb_link_node(&active->node, parent, p); rb_insert_color(&active->node, &vma->active); - return &active->base; +replace: + /* + * Overwrite the previous active slot in the rbtree with last_active, + * leaving last_active zeroed. If the previous slot is still active, + * we must be careful as we now only expect to receive one retire + * callback not two, and so much undo the active counting for the + * overwritten slot. + */ + if (i915_gem_active_isset(&active->base)) { + /* Retire ourselves from the old rq->active_list */ + __list_del_entry(&active->base.link); + vma->active_count--; + GEM_BUG_ON(!vma->active_count); + } + GEM_BUG_ON(list_empty(&vma->last_active.link)); + list_replace_init(&vma->last_active.link, &active->base.link); + active->base.request = fetch_and_zero(&vma->last_active.request); + +out: + return &vma->last_active; } int i915_vma_move_to_active(struct i915_vma *vma, @@ -1002,6 +1051,11 @@ int i915_vma_unbind(struct i915_vma *vma) */ __i915_vma_pin(vma); + ret = i915_gem_active_retire(&vma->last_active, + &vma->vm->i915->drm.struct_mutex); + if (ret) + goto unpin; + rbtree_postorder_for_each_entry_safe(active, n, &vma->active, node) { ret = i915_gem_active_retire(&active->base, diff --git a/drivers/gpu/drm/i915/i915_vma.h b/drivers/gpu/drm/i915/i915_vma.h index c297b0a0dc47e..f06d663771070 100644 --- a/drivers/gpu/drm/i915/i915_vma.h +++ b/drivers/gpu/drm/i915/i915_vma.h @@ -97,6 +97,7 @@ struct i915_vma { unsigned int active_count; struct rb_root active; + struct i915_gem_active last_active; struct i915_gem_active last_fence; /** -- GitLab From 3b4c2511c004521efa89875512b5039a04d5e2e0 Mon Sep 17 00:00:00 2001 From: Neha Bhende <bhenden@vmware.com> Date: Mon, 18 Jun 2018 16:44:48 -0700 Subject: [PATCH 0871/1506] drm/vmwgfx: Add CAP2 support in vmwgfx The device exposes a new capability register. Add support for it. Signed-off-by: Neha Bhende <bhenden@vmware.com> Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 17 +++++++++++++++++ drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 1 + drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c | 3 +++ include/uapi/drm/vmwgfx_drm.h | 1 + 4 files changed, 22 insertions(+) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 1128420de2c0b..f2fad88e4c541 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -258,6 +258,15 @@ MODULE_PARM_DESC(assume_16bpp, "Assume 16-bpp when filtering modes"); module_param_named(assume_16bpp, vmw_assume_16bpp, int, 0600); +static void vmw_print_capabilities2(uint32_t capabilities2) +{ + DRM_INFO("Capabilities2:\n"); + if (capabilities2 & SVGA_CAP2_GROW_OTABLE) + DRM_INFO(" Grow oTable.\n"); + if (capabilities2 & SVGA_CAP2_INTRA_SURFACE_COPY) + DRM_INFO(" IntraSurface copy.\n"); +} + static void vmw_print_capabilities(uint32_t capabilities) { DRM_INFO("Capabilities:\n"); @@ -684,6 +693,12 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) } dev_priv->capabilities = vmw_read(dev_priv, SVGA_REG_CAPABILITIES); + + if (dev_priv->capabilities & SVGA_CAP_CAP2_REGISTER) { + dev_priv->capabilities2 = vmw_read(dev_priv, SVGA_REG_CAP2); + } + + ret = vmw_dma_select_mode(dev_priv); if (unlikely(ret != 0)) { DRM_INFO("Restricting capabilities due to IOMMU setup.\n"); @@ -752,6 +767,8 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) } vmw_print_capabilities(dev_priv->capabilities); + if (dev_priv->capabilities & SVGA_CAP_CAP2_REGISTER) + vmw_print_capabilities2(dev_priv->capabilities2); ret = vmw_dma_masks(dev_priv); if (unlikely(ret != 0)) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index a3a0826958a14..920365c0e9abc 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -386,6 +386,7 @@ struct vmw_private { uint32_t initial_height; u32 *mmio_virt; uint32_t capabilities; + uint32_t capabilities2; uint32_t max_gmr_ids; uint32_t max_gmr_pages; uint32_t max_mob_pages; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c index 6872c7ee8a080..ac6da0da28246 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c @@ -56,6 +56,9 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data, case DRM_VMW_PARAM_HW_CAPS: param->value = dev_priv->capabilities; break; + case DRM_VMW_PARAM_HW_CAPS2: + param->value = dev_priv->capabilities2; + break; case DRM_VMW_PARAM_FIFO_CAPS: param->value = dev_priv->fifo.capabilities; break; diff --git a/include/uapi/drm/vmwgfx_drm.h b/include/uapi/drm/vmwgfx_drm.h index 57115a5fe61a7..84e81b38ca187 100644 --- a/include/uapi/drm/vmwgfx_drm.h +++ b/include/uapi/drm/vmwgfx_drm.h @@ -95,6 +95,7 @@ extern "C" { #define DRM_VMW_PARAM_MAX_MOB_SIZE 10 #define DRM_VMW_PARAM_SCREEN_TARGET 11 #define DRM_VMW_PARAM_DX 12 +#define DRM_VMW_PARAM_HW_CAPS2 13 /** * enum drm_vmw_handle_type - handle type for ref ioctls -- GitLab From 0d81d346a6281c59595a34a035c470e54f403cab Mon Sep 17 00:00:00 2001 From: Neha Bhende <bhenden@vmware.com> Date: Mon, 18 Jun 2018 17:14:56 -0700 Subject: [PATCH 0872/1506] drm/vmwgfx: Add support for SVGA3dCmdIntraSurfaceCopy command A new command to support Intra-Surface-Copy. Signed-off-by: Neha Bhende <bhenden@vmware.com> Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 28 +++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 2d6efc36288f8..8b8386cb98930 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -3116,6 +3116,32 @@ static int vmw_cmd_dx_transfer_from_buffer(struct vmw_private *dev_priv, &cmd->body.destSid, NULL); } +/** + * vmw_cmd_intra_surface_copy - + * Validate an SVGA_3D_CMD_INTRA_SURFACE_COPY command + * + * @dev_priv: Pointer to a device private struct. + * @sw_context: The software context being used for this batch. + * @header: Pointer to the command header in the command stream. + */ +static int vmw_cmd_intra_surface_copy(struct vmw_private *dev_priv, + struct vmw_sw_context *sw_context, + SVGA3dCmdHeader *header) +{ + struct { + SVGA3dCmdHeader header; + SVGA3dCmdIntraSurfaceCopy body; + } *cmd = container_of(header, typeof(*cmd), header); + + if (!(dev_priv->capabilities2 & SVGA_CAP2_INTRA_SURFACE_COPY)) + return -EINVAL; + + return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, + user_surface_converter, + &cmd->body.surface.sid, NULL); +} + + static int vmw_cmd_check_not_3d(struct vmw_private *dev_priv, struct vmw_sw_context *sw_context, void *buf, uint32_t *size) @@ -3471,6 +3497,8 @@ static const struct vmw_cmd_entry vmw_cmd_entries[SVGA_3D_CMD_MAX] = { VMW_CMD_DEF(SVGA_3D_CMD_DX_TRANSFER_FROM_BUFFER, &vmw_cmd_dx_transfer_from_buffer, true, false, true), + VMW_CMD_DEF(SVGA_3D_CMD_INTRA_SURFACE_COPY, &vmw_cmd_intra_surface_copy, + true, false, true), }; bool vmw_cmd_describe(const void *buf, u32 *size, char const **cmd) -- GitLab From 30aeee6728abf29b29d625061782519a15be88db Mon Sep 17 00:00:00 2001 From: Deepak Rawat <drawat@vmware.com> Date: Wed, 20 Jun 2018 13:52:32 -0700 Subject: [PATCH 0873/1506] drm/vmwgfx: Add SM4_1 flag A boolean flag in device private structure to specify if the device support SM4_1. Signed-off-by: Deepak Rawat <drawat@vmware.com> Reviewed-by: Sinclair Yeh <syeh@vmware.com> Reviewed-by: Brian Paul <brianp@vmware.com> Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 18 ++++++++++++++++-- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 1 + 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index f2fad88e4c541..6cf81e19182f6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -916,9 +916,23 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) if (ret) goto out_no_fifo; + if (dev_priv->has_dx) { + /* + * SVGA_CAP2_DX2 (DefineGBSurface_v3) is needed for SM4_1 + * support + */ + if ((dev_priv->capabilities2 & SVGA_CAP2_DX2) != 0) { + vmw_write(dev_priv, SVGA_REG_DEV_CAP, + SVGA3D_DEVCAP_SM41); + dev_priv->has_sm4_1 = vmw_read(dev_priv, + SVGA_REG_DEV_CAP); + } + } + DRM_INFO("DX: %s\n", dev_priv->has_dx ? "yes." : "no."); - DRM_INFO("Atomic: %s\n", - (dev->driver->driver_features & DRIVER_ATOMIC) ? "yes" : "no"); + DRM_INFO("Atomic: %s\n", (dev->driver->driver_features & DRIVER_ATOMIC) + ? "yes." : "no."); + DRM_INFO("SM4_1: %s\n", dev_priv->has_sm4_1 ? "yes." : "no."); snprintf(host_log, sizeof(host_log), "vmwgfx: %s-%s", VMWGFX_REPO, VMWGFX_GIT_VERSION); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 920365c0e9abc..7bb08bac728e3 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -398,6 +398,7 @@ struct vmw_private { spinlock_t cap_lock; bool has_dx; bool assume_16bpp; + bool has_sm4_1; /* * VGA registers. -- GitLab From cdff8e73006c05ee342dd588b5ba90b5def56184 Mon Sep 17 00:00:00 2001 From: Deepak Rawat <drawat@vmware.com> Date: Wed, 20 Jun 2018 14:20:23 -0700 Subject: [PATCH 0874/1506] drm/vmwgfx: Add support for SVGA3dCmdDefineGBSurface_v3 SVGA device added new command SVGA3dCmdDefineGBSurface_v3 which allows 64-bit SVGA3dSurfaceAllFlags. This commit adds support for SVGA3dCmdDefineGBSurface_v3 command in vmwgfx. Signed-off-by: Deepak Rawat <drawat@vmware.com> Reviewed-by: Sinclair Yeh <syeh@vmware.com> Reviewed-by: Brian Paul <brianp@vmware.com> Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com> Reviewed-by: Charmaine Lee <charmainel@vmware.com> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 2 ++ drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 3 +++ drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 32 +++++++++++++++++++++++-- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 7bb08bac728e3..06cce72b7b9e4 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -180,6 +180,8 @@ struct vmw_surface { SVGA3dTextureFilter autogen_filter; uint32_t multisample_count; struct list_head view_list; + SVGA3dMSPattern multisample_pattern; + SVGA3dMSQualityLevel quality_level; }; struct vmw_marker_queue { diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index 15f2cb2a151b0..6630abf3a95c3 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -1157,6 +1157,9 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane, content_srf.flags = 0; content_srf.mip_levels[0] = 1; content_srf.multisample_count = 0; + content_srf.multisample_pattern = + SVGA3D_MS_PATTERN_NONE; + content_srf.quality_level = SVGA3D_MS_QUALITY_NONE; } else { content_srf = *new_vfbs->surface; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c index e90f8d39de535..2abf9a895605c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c @@ -785,6 +785,8 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, srf->base_size = *srf->sizes; srf->autogen_filter = SVGA3D_TEX_FILTER_NONE; srf->multisample_count = 0; + srf->multisample_pattern = SVGA3D_MS_PATTERN_NONE; + srf->quality_level = SVGA3D_MS_QUALITY_NONE; cur_bo_offset = 0; cur_offset = srf->offsets; @@ -1031,6 +1033,10 @@ static int vmw_gb_surface_create(struct vmw_resource *res) SVGA3dCmdHeader header; SVGA3dCmdDefineGBSurface_v2 body; } *cmd2; + struct { + SVGA3dCmdHeader header; + SVGA3dCmdDefineGBSurface_v3 body; + } *cmd3; if (likely(res->id != -1)) return 0; @@ -1047,7 +1053,11 @@ static int vmw_gb_surface_create(struct vmw_resource *res) goto out_no_fifo; } - if (srf->array_size > 0) { + if (dev_priv->has_sm4_1 && srf->array_size > 0) { + cmd_id = SVGA_3D_CMD_DEFINE_GB_SURFACE_V3; + cmd_len = sizeof(cmd3->body); + submit_len = sizeof(*cmd3); + } else if (srf->array_size > 0) { /* has_dx checked on creation time. */ cmd_id = SVGA_3D_CMD_DEFINE_GB_SURFACE_V2; cmd_len = sizeof(cmd2->body); @@ -1060,6 +1070,7 @@ static int vmw_gb_surface_create(struct vmw_resource *res) cmd = vmw_fifo_reserve(dev_priv, submit_len); cmd2 = (typeof(cmd2))cmd; + cmd3 = (typeof(cmd3))cmd; if (unlikely(!cmd)) { DRM_ERROR("Failed reserving FIFO space for surface " "creation.\n"); @@ -1067,7 +1078,22 @@ static int vmw_gb_surface_create(struct vmw_resource *res) goto out_no_fifo; } - if (srf->array_size > 0) { + if (dev_priv->has_sm4_1 && srf->array_size > 0) { + cmd3->header.id = cmd_id; + cmd3->header.size = cmd_len; + cmd3->body.sid = srf->res.id; + cmd3->body.surfaceFlags = (SVGA3dSurfaceAllFlags)srf->flags; + cmd3->body.format = srf->format; + cmd3->body.numMipLevels = srf->mip_levels[0]; + cmd3->body.multisampleCount = srf->multisample_count; + cmd3->body.multisamplePattern = srf->multisample_pattern; + cmd3->body.qualityLevel = srf->quality_level; + cmd3->body.autogenFilter = srf->autogen_filter; + cmd3->body.size.width = srf->base_size.width; + cmd3->body.size.height = srf->base_size.height; + cmd3->body.size.depth = srf->base_size.depth; + cmd3->body.arraySize = srf->array_size; + } else if (srf->array_size > 0) { cmd2->header.id = cmd_id; cmd2->header.size = cmd_len; cmd2->body.sid = srf->res.id; @@ -1561,6 +1587,8 @@ int vmw_surface_gb_priv_define(struct drm_device *dev, srf->autogen_filter = SVGA3D_TEX_FILTER_NONE; srf->array_size = array_size; srf->multisample_count = multisample_count; + srf->multisample_pattern = SVGA3D_MS_PATTERN_NONE; + srf->quality_level = SVGA3D_MS_QUALITY_NONE; if (array_size) num_layers = array_size; -- GitLab From 397a11175f830e1ceb82b608a1c7adbacfbe39b0 Mon Sep 17 00:00:00 2001 From: Deepak Rawat <drawat@vmware.com> Date: Wed, 20 Jun 2018 14:25:07 -0700 Subject: [PATCH 0875/1506] drm/vmwgfx: Support for SVGA3dSurfaceAllFlags in vmwgfx Since svga device introduced new 64bit SVGA3dSurfaceAllFlags, vmwgfx now stores the surface flags internally as SVGA3dSurfaceAllFlags. For legacy surface define commands, only lower 32-bit is used. Signed-off-by: Deepak Rawat <drawat@vmware.com> Reviewed-by: Sinclair Yeh <syeh@vmware.com> Reviewed-by: Brian Paul <brianp@vmware.com> Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 4 ++-- drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 21 ++++++++++++++------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 06cce72b7b9e4..7e5c930830362 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -166,7 +166,7 @@ struct vmw_surface_offset; struct vmw_surface { struct vmw_resource res; - uint32_t flags; + SVGA3dSurfaceAllFlags flags; uint32_t format; uint32_t mip_levels[DRM_VMW_MAX_SURFACE_FACES]; struct drm_vmw_size base_size; @@ -1080,7 +1080,7 @@ extern int vmw_surface_validate(struct vmw_private *dev_priv, struct vmw_surface *srf); int vmw_surface_gb_priv_define(struct drm_device *dev, uint32_t user_accounting_size, - uint32_t svga3d_flags, + SVGA3dSurfaceAllFlags svga3d_flags, SVGA3dSurfaceFormat format, bool for_scanout, uint32_t num_mip_levels, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c index 2abf9a895605c..a5f93f62c7fac 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c @@ -224,7 +224,12 @@ static void vmw_surface_define_encode(const struct vmw_surface *srf, cmd->header.id = SVGA_3D_CMD_SURFACE_DEFINE; cmd->header.size = cmd_len; cmd->body.sid = srf->res.id; - cmd->body.surfaceFlags = srf->flags; + /* + * Downcast of surfaceFlags, was upcasted when received from user-space, + * since driver internally stores as 64 bit. + * For legacy surface define only 32 bit flag is supported. + */ + cmd->body.surfaceFlags = (SVGA3dSurface1Flags)srf->flags; cmd->body.format = srf->format; for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i) cmd->body.face[i].numMipLevels = srf->mip_levels[i]; @@ -760,7 +765,8 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, srf = &user_srf->srf; res = &srf->res; - srf->flags = req->flags; + /* Driver internally stores as 64-bit flags */ + srf->flags = (SVGA3dSurfaceAllFlags)req->flags; srf->format = req->format; srf->scanout = req->scanout; @@ -992,7 +998,8 @@ int vmw_surface_reference_ioctl(struct drm_device *dev, void *data, user_srf = container_of(base, struct vmw_user_surface, prime.base); srf = &user_srf->srf; - rep->flags = srf->flags; + /* Downcast of flags when sending back to user space */ + rep->flags = (uint32_t)srf->flags; rep->format = srf->format; memcpy(rep->mip_levels, srf->mip_levels, sizeof(srf->mip_levels)); user_sizes = (struct drm_vmw_size __user *)(unsigned long) @@ -1082,7 +1089,7 @@ static int vmw_gb_surface_create(struct vmw_resource *res) cmd3->header.id = cmd_id; cmd3->header.size = cmd_len; cmd3->body.sid = srf->res.id; - cmd3->body.surfaceFlags = (SVGA3dSurfaceAllFlags)srf->flags; + cmd3->body.surfaceFlags = srf->flags; cmd3->body.format = srf->format; cmd3->body.numMipLevels = srf->mip_levels[0]; cmd3->body.multisampleCount = srf->multisample_count; @@ -1320,7 +1327,7 @@ int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data, /* Define a surface based on the parameters. */ ret = vmw_surface_gb_priv_define(dev, size, - req->svga3d_flags, + (SVGA3dSurfaceAllFlags)req->svga3d_flags, req->format, req->drm_surface_flags & drm_vmw_surface_flag_scanout, req->mip_levels, @@ -1451,7 +1458,7 @@ int vmw_gb_surface_reference_ioctl(struct drm_device *dev, void *data, goto out_bad_resource; } - rep->creq.svga3d_flags = srf->flags; + rep->creq.svga3d_flags = (uint32_t)srf->flags; rep->creq.format = srf->format; rep->creq.mip_levels = srf->mip_levels[0]; rep->creq.drm_surface_flags = 0; @@ -1495,7 +1502,7 @@ int vmw_gb_surface_reference_ioctl(struct drm_device *dev, void *data, */ int vmw_surface_gb_priv_define(struct drm_device *dev, uint32_t user_accounting_size, - uint32_t svga3d_flags, + SVGA3dSurfaceAllFlags svga3d_flags, SVGA3dSurfaceFormat format, bool for_scanout, uint32_t num_mip_levels, -- GitLab From 14b1c33e84295693c3b1a1d7c6ac82b3f384cd17 Mon Sep 17 00:00:00 2001 From: Deepak Rawat <drawat@vmware.com> Date: Wed, 20 Jun 2018 14:48:35 -0700 Subject: [PATCH 0876/1506] drm/vmwgfx: Add new ioctl for GB surface create and reference New ioctls DRM_VMW_GB_SURFACE_CREATE_EXT and DRM_VMW_GB_SURFACE_REF_EXT are added which support 64-bit wide svga device surface flags, quality level and multisample pattern. Signed-off-by: Deepak Rawat <drawat@vmware.com> Reviewed-by: Sinclair Yeh <syeh@vmware.com> Reviewed-by: Brian Paul <brianp@vmware.com> Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com> Reviewed-by: Charmaine Lee <charmainel@vmware.com> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 12 + drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 8 + drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 20 +- drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 2 + drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 468 +++++++++++++++--------- include/uapi/drm/vmwgfx_drm.h | 102 ++++++ 6 files changed, 437 insertions(+), 175 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 6cf81e19182f6..59229111f303d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -137,6 +137,12 @@ #define DRM_IOCTL_VMW_CREATE_EXTENDED_CONTEXT \ DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_CREATE_EXTENDED_CONTEXT, \ struct drm_vmw_context_arg) +#define DRM_IOCTL_VMW_GB_SURFACE_CREATE_EXT \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_GB_SURFACE_CREATE_EXT, \ + union drm_vmw_gb_surface_create_ext_arg) +#define DRM_IOCTL_VMW_GB_SURFACE_REF_EXT \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_GB_SURFACE_REF_EXT, \ + union drm_vmw_gb_surface_reference_ext_arg) /** * The core DRM version of this macro doesn't account for @@ -224,6 +230,12 @@ static const struct drm_ioctl_desc vmw_ioctls[] = { VMW_IOCTL_DEF(VMW_CREATE_EXTENDED_CONTEXT, vmw_extended_context_define_ioctl, DRM_AUTH | DRM_RENDER_ALLOW), + VMW_IOCTL_DEF(VMW_GB_SURFACE_CREATE_EXT, + vmw_gb_surface_define_ext_ioctl, + DRM_AUTH | DRM_RENDER_ALLOW), + VMW_IOCTL_DEF(VMW_GB_SURFACE_REF_EXT, + vmw_gb_surface_reference_ext_ioctl, + DRM_AUTH | DRM_RENDER_ALLOW), }; static const struct pci_device_id vmw_pci_id_list[] = { diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 7e5c930830362..59af147147973 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -1087,7 +1087,15 @@ int vmw_surface_gb_priv_define(struct drm_device *dev, uint32_t multisample_count, uint32_t array_size, struct drm_vmw_size size, + SVGA3dMSPattern multisample_pattern, + SVGA3dMSQualityLevel quality_level, struct vmw_surface **srf_out); +extern int vmw_gb_surface_define_ext_ioctl(struct drm_device *dev, + void *data, + struct drm_file *file_priv); +extern int vmw_gb_surface_reference_ext_ioctl(struct drm_device *dev, + void *data, + struct drm_file *file_priv); /* * Shader management - vmwgfx_shader.c diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 0fb363458ab57..3201b0a51d10a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -1238,15 +1238,17 @@ static int vmw_create_bo_proxy(struct drm_device *dev, content_base_size.depth = 1; ret = vmw_surface_gb_priv_define(dev, - 0, /* kernel visible only */ - 0, /* flags */ - format, - true, /* can be a scanout buffer */ - 1, /* num of mip levels */ - 0, - 0, - content_base_size, - srf_out); + 0, /* kernel visible only */ + 0, /* flags */ + format, + true, /* can be a scanout buffer */ + 1, /* num of mip levels */ + 0, + 0, + content_base_size, + SVGA3D_MS_PATTERN_NONE, + SVGA3D_MS_QUALITY_NONE, + srf_out); if (ret) { DRM_ERROR("Failed to allocate proxy content buffer\n"); return ret; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index 6630abf3a95c3..f9872c9e60c4e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -1188,6 +1188,8 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane, content_srf.multisample_count, 0, display_base_size, + content_srf.multisample_pattern, + content_srf.quality_level, &vps->surf); if (ret != 0) { DRM_ERROR("Couldn't allocate STDU surface.\n"); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c index a5f93f62c7fac..1d4c010a0e48c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c @@ -33,6 +33,10 @@ #include "vmwgfx_binding.h" #include "device_include/svga3d_surfacedefs.h" +#define SVGA3D_FLAGS_64(upper32, lower32) (((uint64_t)upper32 << 32) | lower32) +#define SVGA3D_FLAGS_UPPER_32(svga3d_flags) (svga3d_flags >> 32) +#define SVGA3D_FLAGS_LOWER_32(svga3d_flags) \ + (svga3d_flags & ((uint64_t)U32_MAX)) /** * struct vmw_user_surface - User-space visible surface resource @@ -81,7 +85,16 @@ static int vmw_gb_surface_unbind(struct vmw_resource *res, bool readback, struct ttm_validate_buffer *val_buf); static int vmw_gb_surface_destroy(struct vmw_resource *res); - +static int +vmw_gb_surface_define_internal(struct drm_device *dev, + struct drm_vmw_gb_surface_create_ext_req *req, + struct drm_vmw_gb_surface_create_rep *rep, + struct drm_file *file_priv); +static int +vmw_gb_surface_reference_internal(struct drm_device *dev, + struct drm_vmw_surface_arg *req, + struct drm_vmw_gb_surface_ref_ext_rep *rep, + struct drm_file *file_priv); static const struct vmw_user_resource_conv user_surface_conv = { .object_type = VMW_RES_SURFACE, @@ -1289,193 +1302,55 @@ static int vmw_gb_surface_destroy(struct vmw_resource *res) /** * vmw_gb_surface_define_ioctl - Ioctl function implementing - * the user surface define functionality. + * the user surface define functionality. * - * @dev: Pointer to a struct drm_device. - * @data: Pointer to data copied from / to user-space. - * @file_priv: Pointer to a drm file private structure. + * @dev: Pointer to a struct drm_device. + * @data: Pointer to data copied from / to user-space. + * @file_priv: Pointer to a drm file private structure. */ int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct vmw_private *dev_priv = vmw_priv(dev); - struct vmw_user_surface *user_srf; - struct vmw_surface *srf; - struct vmw_resource *res; - struct vmw_resource *tmp; union drm_vmw_gb_surface_create_arg *arg = (union drm_vmw_gb_surface_create_arg *)data; - struct drm_vmw_gb_surface_create_req *req = &arg->req; struct drm_vmw_gb_surface_create_rep *rep = &arg->rep; - struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; - int ret; - uint32_t size; - uint32_t backup_handle = 0; - - if (req->multisample_count != 0) - return -EINVAL; - - if (req->mip_levels > DRM_VMW_MAX_MIP_LEVELS) - return -EINVAL; - - if (unlikely(vmw_user_surface_size == 0)) - vmw_user_surface_size = ttm_round_pot(sizeof(*user_srf)) + - 128; - - size = vmw_user_surface_size + 128; - - /* Define a surface based on the parameters. */ - ret = vmw_surface_gb_priv_define(dev, - size, - (SVGA3dSurfaceAllFlags)req->svga3d_flags, - req->format, - req->drm_surface_flags & drm_vmw_surface_flag_scanout, - req->mip_levels, - req->multisample_count, - req->array_size, - req->base_size, - &srf); - if (unlikely(ret != 0)) - return ret; - - user_srf = container_of(srf, struct vmw_user_surface, srf); - if (drm_is_primary_client(file_priv)) - user_srf->master = drm_master_get(file_priv->master); - - ret = ttm_read_lock(&dev_priv->reservation_sem, true); - if (unlikely(ret != 0)) - return ret; - - res = &user_srf->srf.res; - - - if (req->buffer_handle != SVGA3D_INVALID_ID) { - ret = vmw_user_bo_lookup(tfile, req->buffer_handle, - &res->backup, - &user_srf->backup_base); - if (ret == 0) { - if (res->backup->base.num_pages * PAGE_SIZE < - res->backup_size) { - DRM_ERROR("Surface backup buffer is too small.\n"); - vmw_bo_unreference(&res->backup); - ret = -EINVAL; - goto out_unlock; - } else { - backup_handle = req->buffer_handle; - } - } - } else if (req->drm_surface_flags & drm_vmw_surface_flag_create_buffer) - ret = vmw_user_bo_alloc(dev_priv, tfile, - res->backup_size, - req->drm_surface_flags & - drm_vmw_surface_flag_shareable, - &backup_handle, - &res->backup, - &user_srf->backup_base); - - if (unlikely(ret != 0)) { - vmw_resource_unreference(&res); - goto out_unlock; - } - - tmp = vmw_resource_reference(res); - ret = ttm_prime_object_init(tfile, res->backup_size, &user_srf->prime, - req->drm_surface_flags & - drm_vmw_surface_flag_shareable, - VMW_RES_SURFACE, - &vmw_user_surface_base_release, NULL); - - if (unlikely(ret != 0)) { - vmw_resource_unreference(&tmp); - vmw_resource_unreference(&res); - goto out_unlock; - } - - rep->handle = user_srf->prime.base.hash.key; - rep->backup_size = res->backup_size; - if (res->backup) { - rep->buffer_map_handle = - drm_vma_node_offset_addr(&res->backup->base.vma_node); - rep->buffer_size = res->backup->base.num_pages * PAGE_SIZE; - rep->buffer_handle = backup_handle; - } else { - rep->buffer_map_handle = 0; - rep->buffer_size = 0; - rep->buffer_handle = SVGA3D_INVALID_ID; - } + struct drm_vmw_gb_surface_create_ext_req req_ext; - vmw_resource_unreference(&res); + req_ext.base = arg->req; + req_ext.version = drm_vmw_gb_surface_v1; + req_ext.svga3d_flags_upper_32_bits = 0; + req_ext.multisample_pattern = SVGA3D_MS_PATTERN_NONE; + req_ext.quality_level = SVGA3D_MS_QUALITY_NONE; + req_ext.must_be_zero = 0; -out_unlock: - ttm_read_unlock(&dev_priv->reservation_sem); - return ret; + return vmw_gb_surface_define_internal(dev, &req_ext, rep, file_priv); } /** * vmw_gb_surface_reference_ioctl - Ioctl function implementing - * the user surface reference functionality. + * the user surface reference functionality. * - * @dev: Pointer to a struct drm_device. - * @data: Pointer to data copied from / to user-space. - * @file_priv: Pointer to a drm file private structure. + * @dev: Pointer to a struct drm_device. + * @data: Pointer to data copied from / to user-space. + * @file_priv: Pointer to a drm file private structure. */ int vmw_gb_surface_reference_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct vmw_private *dev_priv = vmw_priv(dev); union drm_vmw_gb_surface_reference_arg *arg = (union drm_vmw_gb_surface_reference_arg *)data; struct drm_vmw_surface_arg *req = &arg->req; struct drm_vmw_gb_surface_ref_rep *rep = &arg->rep; - struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; - struct vmw_surface *srf; - struct vmw_user_surface *user_srf; - struct ttm_base_object *base; - uint32_t backup_handle; - int ret = -EINVAL; + struct drm_vmw_gb_surface_ref_ext_rep rep_ext; + int ret; + + ret = vmw_gb_surface_reference_internal(dev, req, &rep_ext, file_priv); - ret = vmw_surface_handle_reference(dev_priv, file_priv, req->sid, - req->handle_type, &base); if (unlikely(ret != 0)) return ret; - user_srf = container_of(base, struct vmw_user_surface, prime.base); - srf = &user_srf->srf; - if (!srf->res.backup) { - DRM_ERROR("Shared GB surface is missing a backup buffer.\n"); - goto out_bad_resource; - } - - mutex_lock(&dev_priv->cmdbuf_mutex); /* Protect res->backup */ - ret = vmw_user_bo_reference(tfile, srf->res.backup, &backup_handle); - mutex_unlock(&dev_priv->cmdbuf_mutex); - - if (unlikely(ret != 0)) { - DRM_ERROR("Could not add a reference to a GB surface " - "backup buffer.\n"); - (void) ttm_ref_object_base_unref(tfile, base->hash.key, - TTM_REF_USAGE); - goto out_bad_resource; - } - - rep->creq.svga3d_flags = (uint32_t)srf->flags; - rep->creq.format = srf->format; - rep->creq.mip_levels = srf->mip_levels[0]; - rep->creq.drm_surface_flags = 0; - rep->creq.multisample_count = srf->multisample_count; - rep->creq.autogen_filter = srf->autogen_filter; - rep->creq.array_size = srf->array_size; - rep->creq.buffer_handle = backup_handle; - rep->creq.base_size = srf->base_size; - rep->crep.handle = user_srf->prime.base.hash.key; - rep->crep.backup_size = srf->res.backup_size; - rep->crep.buffer_handle = backup_handle; - rep->crep.buffer_map_handle = - drm_vma_node_offset_addr(&srf->res.backup->base.vma_node); - rep->crep.buffer_size = srf->res.backup->base.num_pages * PAGE_SIZE; - -out_bad_resource: - ttm_base_object_unref(&base); + rep->creq = rep_ext.creq.base; + rep->crep = rep_ext.crep; return ret; } @@ -1493,6 +1368,8 @@ int vmw_gb_surface_reference_ioctl(struct drm_device *dev, void *data, * @multisample_count: * @array_size: Surface array size. * @size: width, heigh, depth of the surface requested + * @multisample_pattern: Multisampling pattern when msaa is supported + * @quality_level: Precision settings * @user_srf_out: allocated user_srf. Set to NULL on failure. * * GB surfaces allocated by this function will not have a user mode handle, and @@ -1509,6 +1386,8 @@ int vmw_surface_gb_priv_define(struct drm_device *dev, uint32_t multisample_count, uint32_t array_size, struct drm_vmw_size size, + SVGA3dMSPattern multisample_pattern, + SVGA3dMSQualityLevel quality_level, struct vmw_surface **srf_out) { struct vmw_private *dev_priv = vmw_priv(dev); @@ -1519,7 +1398,7 @@ int vmw_surface_gb_priv_define(struct drm_device *dev, }; struct vmw_surface *srf; int ret; - u32 num_layers; + u32 num_layers = 1; *srf_out = NULL; @@ -1594,15 +1473,13 @@ int vmw_surface_gb_priv_define(struct drm_device *dev, srf->autogen_filter = SVGA3D_TEX_FILTER_NONE; srf->array_size = array_size; srf->multisample_count = multisample_count; - srf->multisample_pattern = SVGA3D_MS_PATTERN_NONE; - srf->quality_level = SVGA3D_MS_QUALITY_NONE; + srf->multisample_pattern = multisample_pattern; + srf->quality_level = quality_level; if (array_size) num_layers = array_size; else if (svga3d_flags & SVGA3D_SURFACE_CUBEMAP) num_layers = SVGA3D_MAX_SURFACE_FACES; - else - num_layers = 1; srf->res.backup_size = svga3dsurface_get_serialized_size(srf->format, @@ -1633,3 +1510,262 @@ int vmw_surface_gb_priv_define(struct drm_device *dev, ttm_read_unlock(&dev_priv->reservation_sem); return ret; } + +/** + * vmw_gb_surface_define_ext_ioctl - Ioctl function implementing + * the user surface define functionality. + * + * @dev: Pointer to a struct drm_device. + * @data: Pointer to data copied from / to user-space. + * @file_priv: Pointer to a drm file private structure. + */ +int vmw_gb_surface_define_ext_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + union drm_vmw_gb_surface_create_ext_arg *arg = + (union drm_vmw_gb_surface_create_ext_arg *)data; + struct drm_vmw_gb_surface_create_ext_req *req = &arg->req; + struct drm_vmw_gb_surface_create_rep *rep = &arg->rep; + + return vmw_gb_surface_define_internal(dev, req, rep, file_priv); +} + +/** + * vmw_gb_surface_reference_ext_ioctl - Ioctl function implementing + * the user surface reference functionality. + * + * @dev: Pointer to a struct drm_device. + * @data: Pointer to data copied from / to user-space. + * @file_priv: Pointer to a drm file private structure. + */ +int vmw_gb_surface_reference_ext_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + union drm_vmw_gb_surface_reference_ext_arg *arg = + (union drm_vmw_gb_surface_reference_ext_arg *)data; + struct drm_vmw_surface_arg *req = &arg->req; + struct drm_vmw_gb_surface_ref_ext_rep *rep = &arg->rep; + + return vmw_gb_surface_reference_internal(dev, req, rep, file_priv); +} + +/** + * vmw_gb_surface_define_internal - Ioctl function implementing + * the user surface define functionality. + * + * @dev: Pointer to a struct drm_device. + * @req: Request argument from user-space. + * @rep: Response argument to user-space. + * @file_priv: Pointer to a drm file private structure. + */ +static int +vmw_gb_surface_define_internal(struct drm_device *dev, + struct drm_vmw_gb_surface_create_ext_req *req, + struct drm_vmw_gb_surface_create_rep *rep, + struct drm_file *file_priv) +{ + struct vmw_private *dev_priv = vmw_priv(dev); + struct vmw_user_surface *user_srf; + struct vmw_surface *srf; + struct vmw_resource *res; + struct vmw_resource *tmp; + struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; + int ret; + uint32_t size; + uint32_t backup_handle = 0; + SVGA3dSurfaceAllFlags svga3d_flags_64 = + SVGA3D_FLAGS_64(req->svga3d_flags_upper_32_bits, + req->base.svga3d_flags); + + if (!dev_priv->has_sm4_1) { + /* + * If SM4_1 is not support then cannot send 64-bit flag to + * device. + */ + if (req->svga3d_flags_upper_32_bits != 0) + return -EINVAL; + + if (req->base.multisample_count != 0) + return -EINVAL; + + if (req->multisample_pattern != SVGA3D_MS_PATTERN_NONE) + return -EINVAL; + + if (req->quality_level != SVGA3D_MS_QUALITY_NONE) + return -EINVAL; + } + + if (req->base.mip_levels > DRM_VMW_MAX_MIP_LEVELS) + return -EINVAL; + + if (unlikely(vmw_user_surface_size == 0)) + vmw_user_surface_size = ttm_round_pot(sizeof(*user_srf)) + + 128; + + size = vmw_user_surface_size + 128; + + /* Define a surface based on the parameters. */ + ret = vmw_surface_gb_priv_define(dev, + size, + svga3d_flags_64, + req->base.format, + req->base.drm_surface_flags & + drm_vmw_surface_flag_scanout, + req->base.mip_levels, + req->base.multisample_count, + req->base.array_size, + req->base.base_size, + req->multisample_pattern, + req->quality_level, + &srf); + if (unlikely(ret != 0)) + return ret; + + user_srf = container_of(srf, struct vmw_user_surface, srf); + if (drm_is_primary_client(file_priv)) + user_srf->master = drm_master_get(file_priv->master); + + ret = ttm_read_lock(&dev_priv->reservation_sem, true); + if (unlikely(ret != 0)) + return ret; + + res = &user_srf->srf.res; + + if (req->base.buffer_handle != SVGA3D_INVALID_ID) { + ret = vmw_user_bo_lookup(tfile, req->base.buffer_handle, + &res->backup, + &user_srf->backup_base); + if (ret == 0) { + if (res->backup->base.num_pages * PAGE_SIZE < + res->backup_size) { + DRM_ERROR("Surface backup buffer too small.\n"); + vmw_bo_unreference(&res->backup); + ret = -EINVAL; + goto out_unlock; + } else { + backup_handle = req->base.buffer_handle; + } + } + } else if (req->base.drm_surface_flags & + drm_vmw_surface_flag_create_buffer) + ret = vmw_user_bo_alloc(dev_priv, tfile, + res->backup_size, + req->base.drm_surface_flags & + drm_vmw_surface_flag_shareable, + &backup_handle, + &res->backup, + &user_srf->backup_base); + + if (unlikely(ret != 0)) { + vmw_resource_unreference(&res); + goto out_unlock; + } + + tmp = vmw_resource_reference(res); + ret = ttm_prime_object_init(tfile, res->backup_size, &user_srf->prime, + req->base.drm_surface_flags & + drm_vmw_surface_flag_shareable, + VMW_RES_SURFACE, + &vmw_user_surface_base_release, NULL); + + if (unlikely(ret != 0)) { + vmw_resource_unreference(&tmp); + vmw_resource_unreference(&res); + goto out_unlock; + } + + rep->handle = user_srf->prime.base.hash.key; + rep->backup_size = res->backup_size; + if (res->backup) { + rep->buffer_map_handle = + drm_vma_node_offset_addr(&res->backup->base.vma_node); + rep->buffer_size = res->backup->base.num_pages * PAGE_SIZE; + rep->buffer_handle = backup_handle; + } else { + rep->buffer_map_handle = 0; + rep->buffer_size = 0; + rep->buffer_handle = SVGA3D_INVALID_ID; + } + + vmw_resource_unreference(&res); + +out_unlock: + ttm_read_unlock(&dev_priv->reservation_sem); + return ret; +} + +/** + * vmw_gb_surface_reference_internal - Ioctl function implementing + * the user surface reference functionality. + * + * @dev: Pointer to a struct drm_device. + * @req: Pointer to user-space request surface arg. + * @rep: Pointer to response to user-space. + * @file_priv: Pointer to a drm file private structure. + */ +static int +vmw_gb_surface_reference_internal(struct drm_device *dev, + struct drm_vmw_surface_arg *req, + struct drm_vmw_gb_surface_ref_ext_rep *rep, + struct drm_file *file_priv) +{ + struct vmw_private *dev_priv = vmw_priv(dev); + struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; + struct vmw_surface *srf; + struct vmw_user_surface *user_srf; + struct ttm_base_object *base; + uint32_t backup_handle; + int ret = -EINVAL; + + ret = vmw_surface_handle_reference(dev_priv, file_priv, req->sid, + req->handle_type, &base); + if (unlikely(ret != 0)) + return ret; + + user_srf = container_of(base, struct vmw_user_surface, prime.base); + srf = &user_srf->srf; + if (!srf->res.backup) { + DRM_ERROR("Shared GB surface is missing a backup buffer.\n"); + goto out_bad_resource; + } + + mutex_lock(&dev_priv->cmdbuf_mutex); /* Protect res->backup */ + ret = vmw_user_bo_reference(tfile, srf->res.backup, &backup_handle); + mutex_unlock(&dev_priv->cmdbuf_mutex); + + if (unlikely(ret != 0)) { + DRM_ERROR("Could not add a reference to a GB surface " + "backup buffer.\n"); + (void) ttm_ref_object_base_unref(tfile, base->hash.key, + TTM_REF_USAGE); + goto out_bad_resource; + } + + rep->creq.base.svga3d_flags = SVGA3D_FLAGS_LOWER_32(srf->flags); + rep->creq.base.format = srf->format; + rep->creq.base.mip_levels = srf->mip_levels[0]; + rep->creq.base.drm_surface_flags = 0; + rep->creq.base.multisample_count = srf->multisample_count; + rep->creq.base.autogen_filter = srf->autogen_filter; + rep->creq.base.array_size = srf->array_size; + rep->creq.base.buffer_handle = backup_handle; + rep->creq.base.base_size = srf->base_size; + rep->crep.handle = user_srf->prime.base.hash.key; + rep->crep.backup_size = srf->res.backup_size; + rep->crep.buffer_handle = backup_handle; + rep->crep.buffer_map_handle = + drm_vma_node_offset_addr(&srf->res.backup->base.vma_node); + rep->crep.buffer_size = srf->res.backup->base.num_pages * PAGE_SIZE; + + rep->creq.version = drm_vmw_gb_surface_v1; + rep->creq.svga3d_flags_upper_32_bits = + SVGA3D_FLAGS_UPPER_32(srf->flags); + rep->creq.multisample_pattern = srf->multisample_pattern; + rep->creq.quality_level = srf->quality_level; + rep->creq.must_be_zero = 0; + +out_bad_resource: + ttm_base_object_unref(&base); + + return ret; +} diff --git a/include/uapi/drm/vmwgfx_drm.h b/include/uapi/drm/vmwgfx_drm.h index 84e81b38ca187..68ff37d4c0350 100644 --- a/include/uapi/drm/vmwgfx_drm.h +++ b/include/uapi/drm/vmwgfx_drm.h @@ -69,6 +69,8 @@ extern "C" { #define DRM_VMW_GB_SURFACE_REF 24 #define DRM_VMW_SYNCCPU 25 #define DRM_VMW_CREATE_EXTENDED_CONTEXT 26 +#define DRM_VMW_GB_SURFACE_CREATE_EXT 27 +#define DRM_VMW_GB_SURFACE_REF_EXT 28 /*************************************************************************/ /** @@ -1105,6 +1107,106 @@ struct drm_vmw_handle_close_arg { }; #define drm_vmw_unref_dmabuf_arg drm_vmw_handle_close_arg +/*************************************************************************/ +/** + * DRM_VMW_GB_SURFACE_CREATE_EXT - Create a host guest-backed surface. + * + * Allocates a surface handle and queues a create surface command + * for the host on the first use of the surface. The surface ID can + * be used as the surface ID in commands referencing the surface. + * + * This new command extends DRM_VMW_GB_SURFACE_CREATE by adding version + * parameter and 64 bit svga flag. + */ + +/** + * enum drm_vmw_surface_version + * + * @drm_vmw_surface_gb_v1: Corresponds to current gb surface format with + * svga3d surface flags split into 2, upper half and lower half. + */ +enum drm_vmw_surface_version { + drm_vmw_gb_surface_v1 +}; + +/** + * struct drm_vmw_gb_surface_create_ext_req + * + * @base: Surface create parameters. + * @version: Version of surface create ioctl. + * @svga3d_flags_upper_32_bits: Upper 32 bits of svga3d flags. + * @multisample_pattern: Multisampling pattern when msaa is supported. + * @quality_level: Precision settings for each sample. + * @must_be_zero: Reserved for future usage. + * + * Input argument to the DRM_VMW_GB_SURFACE_CREATE_EXT Ioctl. + * Part of output argument for the DRM_VMW_GB_SURFACE_REF_EXT Ioctl. + */ +struct drm_vmw_gb_surface_create_ext_req { + struct drm_vmw_gb_surface_create_req base; + enum drm_vmw_surface_version version; + uint32_t svga3d_flags_upper_32_bits; + SVGA3dMSPattern multisample_pattern; + SVGA3dMSQualityLevel quality_level; + uint64_t must_be_zero; +}; + +/** + * union drm_vmw_gb_surface_create_ext_arg + * + * @req: Input argument as described above. + * @rep: Output argument as described above. + * + * Argument to the DRM_VMW_GB_SURFACE_CREATE_EXT ioctl. + */ +union drm_vmw_gb_surface_create_ext_arg { + struct drm_vmw_gb_surface_create_rep rep; + struct drm_vmw_gb_surface_create_ext_req req; +}; + +/*************************************************************************/ +/** + * DRM_VMW_GB_SURFACE_REF_EXT - Reference a host surface. + * + * Puts a reference on a host surface with a given handle, as previously + * returned by the DRM_VMW_GB_SURFACE_CREATE_EXT ioctl. + * A reference will make sure the surface isn't destroyed while we hold + * it and will allow the calling client to use the surface handle in + * the command stream. + * + * On successful return, the Ioctl returns the surface information given + * to and returned from the DRM_VMW_GB_SURFACE_CREATE_EXT ioctl. + */ + +/** + * struct drm_vmw_gb_surface_ref_ext_rep + * + * @creq: The data used as input when the surface was created, as described + * above at "struct drm_vmw_gb_surface_create_ext_req" + * @crep: Additional data output when the surface was created, as described + * above at "struct drm_vmw_gb_surface_create_rep" + * + * Output Argument to the DRM_VMW_GB_SURFACE_REF_EXT ioctl. + */ +struct drm_vmw_gb_surface_ref_ext_rep { + struct drm_vmw_gb_surface_create_ext_req creq; + struct drm_vmw_gb_surface_create_rep crep; +}; + +/** + * union drm_vmw_gb_surface_reference_ext_arg + * + * @req: Input data as described above at "struct drm_vmw_surface_arg" + * @rep: Output data as described above at + * "struct drm_vmw_gb_surface_ref_ext_rep" + * + * Argument to the DRM_VMW_GB_SURFACE_REF Ioctl. + */ +union drm_vmw_gb_surface_reference_ext_arg { + struct drm_vmw_gb_surface_ref_ext_rep rep; + struct drm_vmw_surface_arg req; +}; + #if defined(__cplusplus) } #endif -- GitLab From f9261b30d92f3835891648041ce8699b1fb9a694 Mon Sep 17 00:00:00 2001 From: Deepak Rawat <drawat@vmware.com> Date: Wed, 20 Jun 2018 15:24:05 -0700 Subject: [PATCH 0877/1506] drm/vmwgfx: Add support for multisampling Support for SVGA3D_SURFACE_MULTISAMPLE and surface mob size according to sample count. Signed-off-by: Deepak Rawat <drawat@vmware.com> Reviewed-by: Sinclair Yeh <syeh@vmware.com> Reviewed-by: Brian Paul <brianp@vmware.com> Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com> Reviewed-by: Charmaine Lee <charmainel@vmware.com> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> --- .../device_include/svga3d_surfacedefs.h | 20 +++++++++++++++++++ drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 17 ++++++++++++---- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/device_include/svga3d_surfacedefs.h b/drivers/gpu/drm/vmwgfx/device_include/svga3d_surfacedefs.h index 6422e3899cdf0..809a4ec68e89b 100644 --- a/drivers/gpu/drm/vmwgfx/device_include/svga3d_surfacedefs.h +++ b/drivers/gpu/drm/vmwgfx/device_include/svga3d_surfacedefs.h @@ -1235,6 +1235,26 @@ svga3dsurface_get_serialized_size(SVGA3dSurfaceFormat format, return total_size * num_layers; } +/** + * svga3dsurface_get_serialized_size_extended - Returns the number of bytes + * required for a surface with given parameters. Support for sample count. + */ +static inline u32 +svga3dsurface_get_serialized_size_extended(SVGA3dSurfaceFormat format, + surf_size_struct base_level_size, + u32 num_mip_levels, + u32 num_layers, + u32 num_samples) +{ + uint64_t total_size = + svga3dsurface_get_serialized_size(format, + base_level_size, + num_mip_levels, + num_layers); + total_size *= max_t(u32, 1, num_samples); + + return min_t(uint64_t, total_size, (uint64_t)U32_MAX); +} /** * svga3dsurface_get_pixel_offset - Compute the offset (in bytes) to a pixel diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 59af147147973..a67b54e4fd50a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -83,7 +83,7 @@ struct vmw_fpriv { struct drm_master *locked_master; struct ttm_object_file *tfile; - bool gb_aware; + bool gb_aware; /* user-space is guest-backed aware */ }; struct vmw_buffer_object { diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c index 1d4c010a0e48c..7636bf2db17e9 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c @@ -1399,6 +1399,7 @@ int vmw_surface_gb_priv_define(struct drm_device *dev, struct vmw_surface *srf; int ret; u32 num_layers = 1; + u32 sample_count = 1; *srf_out = NULL; @@ -1481,11 +1482,15 @@ int vmw_surface_gb_priv_define(struct drm_device *dev, else if (svga3d_flags & SVGA3D_SURFACE_CUBEMAP) num_layers = SVGA3D_MAX_SURFACE_FACES; + if (srf->flags & SVGA3D_SURFACE_MULTISAMPLE) + sample_count = srf->multisample_count; + srf->res.backup_size = - svga3dsurface_get_serialized_size(srf->format, - srf->base_size, - srf->mip_levels[0], - num_layers); + svga3dsurface_get_serialized_size_extended(srf->format, + srf->base_size, + srf->mip_levels[0], + num_layers, + sample_count); if (srf->flags & SVGA3D_SURFACE_BIND_STREAM_OUTPUT) srf->res.backup_size += sizeof(SVGA3dDXSOState); @@ -1595,6 +1600,10 @@ vmw_gb_surface_define_internal(struct drm_device *dev, return -EINVAL; } + if ((svga3d_flags_64 & SVGA3D_SURFACE_MULTISAMPLE) && + req->base.multisample_count == 0) + return -EINVAL; + if (req->base.mip_levels > DRM_VMW_MAX_MIP_LEVELS) return -EINVAL; -- GitLab From 9b07b287aa3ef49695bfad59c1870cd942f579a8 Mon Sep 17 00:00:00 2001 From: Deepak Rawat <drawat@vmware.com> Date: Wed, 20 Jun 2018 15:09:43 -0700 Subject: [PATCH 0878/1506] drm/vmwgfx: Expose SM4_1 param to user space A new param DRM_VMW_PARAM_SM4_1, is added for user space to determine availability of SM4.1. Minor version bump for SM4.1. Signed-off-by: Deepak Rawat <drawat@vmware.com> Reviewed-by: Sinclair Yeh <syeh@vmware.com> Reviewed-by: Brian Paul <brianp@vmware.com> Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 6 +++--- drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c | 3 +++ include/uapi/drm/vmwgfx_drm.h | 4 ++++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index a67b54e4fd50a..f1b803d34c593 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -43,10 +43,10 @@ #include <linux/sync_file.h> #define VMWGFX_DRIVER_NAME "vmwgfx" -#define VMWGFX_DRIVER_DATE "20180322" +#define VMWGFX_DRIVER_DATE "20180704" #define VMWGFX_DRIVER_MAJOR 2 -#define VMWGFX_DRIVER_MINOR 14 -#define VMWGFX_DRIVER_PATCHLEVEL 1 +#define VMWGFX_DRIVER_MINOR 15 +#define VMWGFX_DRIVER_PATCHLEVEL 0 #define VMWGFX_FILE_PAGE_OFFSET 0x00100000 #define VMWGFX_FIFO_STATIC_SIZE (1024*1024) #define VMWGFX_MAX_RELOCATIONS 2048 diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c index ac6da0da28246..e825192ca30ec 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c @@ -116,6 +116,9 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data, case DRM_VMW_PARAM_DX: param->value = dev_priv->has_dx; break; + case DRM_VMW_PARAM_SM4_1: + param->value = dev_priv->has_sm4_1; + break; default: return -EINVAL; } diff --git a/include/uapi/drm/vmwgfx_drm.h b/include/uapi/drm/vmwgfx_drm.h index 68ff37d4c0350..399f58317cff3 100644 --- a/include/uapi/drm/vmwgfx_drm.h +++ b/include/uapi/drm/vmwgfx_drm.h @@ -82,6 +82,9 @@ extern "C" { * * DRM_VMW_PARAM_OVERLAY_IOCTL: * Does the driver support the overlay ioctl. + * + * DRM_VMW_PARAM_SM4_1 + * SM4_1 support is enabled. */ #define DRM_VMW_PARAM_NUM_STREAMS 0 @@ -98,6 +101,7 @@ extern "C" { #define DRM_VMW_PARAM_SCREEN_TARGET 11 #define DRM_VMW_PARAM_DX 12 #define DRM_VMW_PARAM_HW_CAPS2 13 +#define DRM_VMW_PARAM_SM4_1 14 /** * enum drm_vmw_handle_type - handle type for ref ioctls -- GitLab From 3a32497f0dbe170794e1506deb41dc44c4fea8d9 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 6 Jul 2018 18:49:26 +0100 Subject: [PATCH 0879/1506] drm/i915/selftests: Provide full mb() around clflush clflush is an unserialised instruction and the IA manual strongly advises you to serialise it with a mb. To be cautious, apply one before and one after, so that it is serialised with both writes and reads without worrying too much about the required direction. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180706174926.4712-1-chris@chris-wilson.co.uk --- .../drm/i915/selftests/i915_gem_coherency.c | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c b/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c index 1de7c1402fd5a..3a095c37c1203 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c @@ -42,11 +42,21 @@ static int cpu_set(struct drm_i915_gem_object *obj, page = i915_gem_object_get_page(obj, offset >> PAGE_SHIFT); map = kmap_atomic(page); - if (needs_clflush & CLFLUSH_BEFORE) + + if (needs_clflush & CLFLUSH_BEFORE) { + mb(); clflush(map+offset_in_page(offset) / sizeof(*map)); + mb(); + } + map[offset_in_page(offset) / sizeof(*map)] = v; - if (needs_clflush & CLFLUSH_AFTER) + + if (needs_clflush & CLFLUSH_AFTER) { + mb(); clflush(map+offset_in_page(offset) / sizeof(*map)); + mb(); + } + kunmap_atomic(map); i915_gem_obj_finish_shmem_access(obj); @@ -68,8 +78,13 @@ static int cpu_get(struct drm_i915_gem_object *obj, page = i915_gem_object_get_page(obj, offset >> PAGE_SHIFT); map = kmap_atomic(page); - if (needs_clflush & CLFLUSH_BEFORE) + + if (needs_clflush & CLFLUSH_BEFORE) { + mb(); clflush(map+offset_in_page(offset) / sizeof(*map)); + mb(); + } + *v = map[offset_in_page(offset) / sizeof(*map)]; kunmap_atomic(map); -- GitLab From 07e070e1e3b24e4b66a3b5e55e6486d7fe9769dd Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 6 Jul 2018 21:59:47 +0100 Subject: [PATCH 0880/1506] drm/i915/selftests: Avoid warning if runtime pm is disabled Inside the mock GEM device, we try to grab the runtime pm for the fake device to prevent it from ever suspending. However, if CONFIG_PM is not set, trying to obtain the wakref returns an error which we WARN about. Suppress the expected warning. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180706205947.11209-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/selftests/mock_gem_device.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/selftests/mock_gem_device.c b/drivers/gpu/drm/i915/selftests/mock_gem_device.c index c97075c5ccafa..43ed8b28aeaa0 100644 --- a/drivers/gpu/drm/i915/selftests/mock_gem_device.c +++ b/drivers/gpu/drm/i915/selftests/mock_gem_device.c @@ -157,7 +157,8 @@ struct drm_i915_private *mock_gem_device(void) dev_pm_domain_set(&pdev->dev, &pm_domain); pm_runtime_enable(&pdev->dev); pm_runtime_dont_use_autosuspend(&pdev->dev); - WARN_ON(pm_runtime_get_sync(&pdev->dev)); + if (pm_runtime_enabled(&pdev->dev)) + WARN_ON(pm_runtime_get_sync(&pdev->dev)); i915 = (struct drm_i915_private *)(pdev + 1); pci_set_drvdata(pdev, i915); -- GitLab From 73915b2b1f2581cbce5a511550c2cac2e2b42595 Mon Sep 17 00:00:00 2001 From: Boris Brezillon <boris.brezillon@bootlin.com> Date: Tue, 3 Jul 2018 19:40:46 +0200 Subject: [PATCH 0881/1506] drm/writeback: Fix the "overview" section of the doc Fix the bullet list declaration in the overview section. Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com> Reported-by: Daniel Vetter <daniel.vetter@ffwll.ch> Fixes: 935774cd71fe ("drm: Add writeback connector type") Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180703174046.22396-1-boris.brezillon@bootlin.com --- drivers/gpu/drm/drm_writeback.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_writeback.c b/drivers/gpu/drm/drm_writeback.c index 827395071f0b5..69e7a63cfcc31 100644 --- a/drivers/gpu/drm/drm_writeback.c +++ b/drivers/gpu/drm/drm_writeback.c @@ -22,10 +22,13 @@ * Writeback connectors are used to expose hardware which can write the output * from a CRTC to a memory buffer. They are used and act similarly to other * types of connectors, with some important differences: - * - Writeback connectors don't provide a way to output visually to the user. - * - Writeback connectors should always report as "disconnected" (so that - * clients which don't understand them will ignore them). - * - Writeback connectors don't have EDID. + * + * * Writeback connectors don't provide a way to output visually to the user. + * + * * Writeback connectors should always report as "disconnected" (so that + * clients which don't understand them will ignore them). + * + * * Writeback connectors don't have EDID. * * A framebuffer may only be attached to a writeback connector when the * connector is attached to a CRTC. The WRITEBACK_FB_ID property which sets the -- GitLab From b82c1f8f78b4d273d1bcefe3e805eff61e879a68 Mon Sep 17 00:00:00 2001 From: Boris Brezillon <boris.brezillon@bootlin.com> Date: Tue, 3 Jul 2018 09:50:15 +0200 Subject: [PATCH 0882/1506] drm/atomic: Avoid connector to writeback_connector casts Use container_of() instead of type casting so that it keeps working even if base is moved inside the drm_writeback_connector struct. Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com> Reviewed-by: Liviu Dudau <liviu.dudau@arm.com> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180703075022.15138-2-boris.brezillon@bootlin.com --- drivers/gpu/drm/drm_atomic.c | 4 +++- include/drm/drm_writeback.h | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index e6062c779aaf8..3eb061e11e2ef 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -2428,6 +2428,7 @@ static int prepare_signaling(struct drm_device *dev, } for_each_new_connector_in_state(state, conn, conn_state, i) { + struct drm_writeback_connector *wb_conn; struct drm_writeback_job *job; struct drm_out_fence_state *f; struct dma_fence *fence; @@ -2451,7 +2452,8 @@ static int prepare_signaling(struct drm_device *dev, f[*num_fences].out_fence_ptr = fence_ptr; *fence_state = f; - fence = drm_writeback_get_out_fence((struct drm_writeback_connector *)conn); + wb_conn = drm_connector_to_writeback(conn); + fence = drm_writeback_get_out_fence(wb_conn); if (!fence) return -ENOMEM; diff --git a/include/drm/drm_writeback.h b/include/drm/drm_writeback.h index a10fe556dfd45..23df9d4630032 100644 --- a/include/drm/drm_writeback.h +++ b/include/drm/drm_writeback.h @@ -110,6 +110,12 @@ struct drm_writeback_job { struct dma_fence *out_fence; }; +static inline struct drm_writeback_connector * +drm_connector_to_writeback(struct drm_connector *connector) +{ + return container_of(connector, struct drm_writeback_connector, base); +} + int drm_writeback_connector_init(struct drm_device *dev, struct drm_writeback_connector *wb_connector, const struct drm_connector_funcs *con_funcs, -- GitLab From 425132fdb169c2a2772190ff56e0e8eea37ff716 Mon Sep 17 00:00:00 2001 From: Boris Brezillon <boris.brezillon@bootlin.com> Date: Tue, 3 Jul 2018 09:50:16 +0200 Subject: [PATCH 0883/1506] drm/connector: Pass a drm_connector_state to ->atomic_commit() Other atomic hooks are passed state objects, let's change this one to be consistent. Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com> Acked-by: Liviu Dudau <liviu.dudau@arm.com> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180703075022.15138-3-boris.brezillon@bootlin.com --- drivers/gpu/drm/drm_atomic_helper.c | 2 +- include/drm/drm_modeset_helper_vtables.h | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 7787e0e6bbc6b..47e84aa7b6e24 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1187,7 +1187,7 @@ static void drm_atomic_helper_commit_writebacks(struct drm_device *dev, if (new_conn_state->writeback_job && new_conn_state->writeback_job->fb) { WARN_ON(connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK); - funcs->atomic_commit(connector, new_conn_state->writeback_job); + funcs->atomic_commit(connector, new_conn_state); } } } diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h index 3b289773297c2..fb841f44949cf 100644 --- a/include/drm/drm_modeset_helper_vtables.h +++ b/include/drm/drm_modeset_helper_vtables.h @@ -980,11 +980,13 @@ struct drm_connector_helper_funcs { * * This hook is to be used by drivers implementing writeback connectors * that need a point when to commit the writeback job to the hardware. + * The writeback_job to commit is available in + * &drm_connector_state.writeback_job. * * This callback is used by the atomic modeset helpers. */ void (*atomic_commit)(struct drm_connector *connector, - struct drm_writeback_job *writeback_job); + struct drm_connector_state *state); }; /** -- GitLab From 814bde99ee809c172a409829889d1bafc3e4bcf7 Mon Sep 17 00:00:00 2001 From: Boris Brezillon <boris.brezillon@bootlin.com> Date: Tue, 3 Jul 2018 09:50:17 +0200 Subject: [PATCH 0884/1506] drm/connector: Make ->atomic_commit() optional Not all writeback connector implementations might want to commit things from the connector driver. Some, like the malidp driver, commit things from their main commit_tail() function, and would rather not have to implement a dummy hook for drm_connector_helper_funcs.atomic_commit(). Make this function optional and reflect this fact in the doc. Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com> Acked-by: Liviu Dudau <liviu.dudau@arm.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180703075022.15138-4-boris.brezillon@bootlin.com --- drivers/gpu/drm/drm_atomic_helper.c | 2 ++ include/drm/drm_modeset_helper_vtables.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 47e84aa7b6e24..bab8051690bbf 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1184,6 +1184,8 @@ static void drm_atomic_helper_commit_writebacks(struct drm_device *dev, const struct drm_connector_helper_funcs *funcs; funcs = connector->helper_private; + if (!funcs->atomic_commit) + continue; if (new_conn_state->writeback_job && new_conn_state->writeback_job->fb) { WARN_ON(connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK); diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h index fb841f44949cf..d0eb76c4b309a 100644 --- a/include/drm/drm_modeset_helper_vtables.h +++ b/include/drm/drm_modeset_helper_vtables.h @@ -983,6 +983,8 @@ struct drm_connector_helper_funcs { * The writeback_job to commit is available in * &drm_connector_state.writeback_job. * + * This hook is optional. + * * This callback is used by the atomic modeset helpers. */ void (*atomic_commit)(struct drm_connector *connector, -- GitLab From 184d3cf4f73896267340cf06acfa751fad4f8dd2 Mon Sep 17 00:00:00 2001 From: Boris Brezillon <boris.brezillon@bootlin.com> Date: Tue, 3 Jul 2018 09:50:18 +0200 Subject: [PATCH 0885/1506] drm/vc4: Use wait_for_flip_done() instead of wait_for_vblanks() drm_atomic_helper_wait_for_vblanks() assumes the CRTC will continuously generate VBLANK events and the vblank counter will keep increasing. While this work for a regular pipeline, it doesn't when you have the CRTC is feeding the transposer block, because this block works in oneshot mode, and, by the time we reach drm_atomic_helper_wait_for_vblanks() the only VBLANK event might have already been sent and the VBLANK counter will stay unchanged, thus triggering a timeout. Luckily, we can replace the drm_atomic_helper_wait_for_vblanks() call by drm_atomic_helper_wait_for_flip_done() because the only thing we want to check when calling drm_atomic_helper_wait_for_vblanks() from vc4_atomic_complete_commit() is that new FBs are in use and the old ones can be safely released. Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com> Reviewed-by: Liviu Dudau <liviu.dudau@arm.com> Reviewed-by: Eric Anholt <eric@anholt.net> Link: https://patchwork.freedesktop.org/patch/msgid/20180703075022.15138-5-boris.brezillon@bootlin.com --- drivers/gpu/drm/vc4/vc4_kms.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c index 8a411e5f87768..91239b0a4fa0e 100644 --- a/drivers/gpu/drm/vc4/vc4_kms.c +++ b/drivers/gpu/drm/vc4/vc4_kms.c @@ -153,18 +153,9 @@ vc4_atomic_complete_commit(struct drm_atomic_state *state) drm_atomic_helper_commit_modeset_enables(dev, state); - /* Make sure that drm_atomic_helper_wait_for_vblanks() - * actually waits for vblank. If we're doing a full atomic - * modeset (as opposed to a vc4_update_plane() short circuit), - * then we need to wait for scanout to be done with our - * display lists before we free it and potentially reallocate - * and overwrite the dlist memory with a new modeset. - */ - state->legacy_cursor_update = false; - drm_atomic_helper_commit_hw_done(state); - drm_atomic_helper_wait_for_vblanks(dev, state); + drm_atomic_helper_wait_for_flip_done(dev, state); drm_atomic_helper_cleanup_planes(dev, state); -- GitLab From b25c60af7a8773694a505cdb0d2e67807243217d Mon Sep 17 00:00:00 2001 From: Boris Brezillon <boris.brezillon@bootlin.com> Date: Tue, 3 Jul 2018 09:50:19 +0200 Subject: [PATCH 0886/1506] drm/crtc: Add a generic infrastructure to fake VBLANK events In some cases CRTCs are active but are not able to generating events, at least not at every frame at it's expected to. This is typically the case when the CRTC is feeding a writeback connector that has no job queued. In this situation the CRTC is usually stopped until a new job is queued, and this can lead to timeouts when part of the pipeline is updated but no new jobs are queued to the active writeback connector. In order to solve that, we add a ->no_vblank flag to drm_crtc_state and ask the CRTC drivers to set it to true when they know they're not able to generate VBLANK events. The core drm_atomic_helper_fake_vblank() helper can then be used to fake VBLANKs at commit time. Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com> Reviewed-by: Liviu Dudau <liviu.dudau@arm.com> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180703075022.15138-6-boris.brezillon@bootlin.com --- drivers/gpu/drm/drm_atomic_helper.c | 39 +++++++++++++++++++++++++++++ include/drm/drm_atomic_helper.h | 1 + include/drm/drm_crtc.h | 23 +++++++++++++++++ 3 files changed, 63 insertions(+) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index bab8051690bbf..c31f670b12834 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -2053,6 +2053,45 @@ void drm_atomic_helper_wait_for_dependencies(struct drm_atomic_state *old_state) } EXPORT_SYMBOL(drm_atomic_helper_wait_for_dependencies); +/** + * drm_atomic_helper_fake_vblank - fake VBLANK events if needed + * @old_state: atomic state object with old state structures + * + * This function walks all CRTCs and fake VBLANK events on those with + * &drm_crtc_state.no_vblank set to true and &drm_crtc_state.event != NULL. + * The primary use of this function is writeback connectors working in oneshot + * mode and faking VBLANK events. In this case they only fake the VBLANK event + * when a job is queued, and any change to the pipeline that does not touch the + * connector is leading to timeouts when calling + * drm_atomic_helper_wait_for_vblanks() or + * drm_atomic_helper_wait_for_flip_done(). + * + * This is part of the atomic helper support for nonblocking commits, see + * drm_atomic_helper_setup_commit() for an overview. + */ +void drm_atomic_helper_fake_vblank(struct drm_atomic_state *old_state) +{ + struct drm_crtc_state *new_crtc_state; + struct drm_crtc *crtc; + int i; + + for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i) { + unsigned long flags; + + if (!new_crtc_state->no_vblank) + continue; + + spin_lock_irqsave(&old_state->dev->event_lock, flags); + if (new_crtc_state->event) { + drm_crtc_send_vblank_event(crtc, + new_crtc_state->event); + new_crtc_state->event = NULL; + } + spin_unlock_irqrestore(&old_state->dev->event_lock, flags); + } +} +EXPORT_SYMBOL(drm_atomic_helper_fake_vblank); + /** * drm_atomic_helper_commit_hw_done - setup possible nonblocking commit * @old_state: atomic state object with old state structures diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index 26aaba58d6ceb..99e2a5297c697 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -100,6 +100,7 @@ int __must_check drm_atomic_helper_swap_state(struct drm_atomic_state *state, int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, bool nonblock); void drm_atomic_helper_wait_for_dependencies(struct drm_atomic_state *state); +void drm_atomic_helper_fake_vblank(struct drm_atomic_state *state); void drm_atomic_helper_commit_hw_done(struct drm_atomic_state *state); void drm_atomic_helper_commit_cleanup_done(struct drm_atomic_state *state); diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 23eddbccab10f..17f4f93340b84 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -119,6 +119,29 @@ struct drm_crtc_state { bool zpos_changed : 1; bool color_mgmt_changed : 1; + /** + * @no_vblank: + * + * Reflects the ability of a CRTC to send VBLANK events. This state + * usually depends on the pipeline configuration, and the main usuage + * is CRTCs feeding a writeback connector operating in oneshot mode. + * In this case the VBLANK event is only generated when a job is queued + * to the writeback connector, and we want the core to fake VBLANK + * events when this part of the pipeline hasn't changed but others had + * or when the CRTC and connectors are being disabled. + * + * __drm_atomic_helper_crtc_duplicate_state() will not reset the value + * from the current state, the CRTC driver is then responsible for + * updating this field when needed. + * + * Note that the combination of &drm_crtc_state.event == NULL and + * &drm_crtc_state.no_blank == true is valid and usually used when the + * writeback connector attached to the CRTC has a new job queued. In + * this case the driver will send the VBLANK event on its own when the + * writeback job is complete. + */ + bool no_vblank : 1; + /* attached planes bitmask: * WARNING: transitional helpers do not maintain plane_mask so * drivers not converted over to atomic helpers should not rely -- GitLab From 6fb42b6682f0d3c6ca9dc0e338c294fb92448e1d Mon Sep 17 00:00:00 2001 From: Boris Brezillon <boris.brezillon@bootlin.com> Date: Tue, 3 Jul 2018 09:50:20 +0200 Subject: [PATCH 0887/1506] drm/atomic: Call fake_vblank() from the generic commit_tail() helpers Now that we have a way to fake VBLANK events when requested by the CRTC hook it up to the generic commit_tail() helpers. Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com> Reviewed-by: Liviu Dudau <liviu.dudau@arm.com> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180703075022.15138-7-boris.brezillon@bootlin.com --- drivers/gpu/drm/drm_atomic_helper.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index c31f670b12834..91fda6b8926e7 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1450,6 +1450,8 @@ void drm_atomic_helper_commit_tail(struct drm_atomic_state *old_state) drm_atomic_helper_commit_modeset_enables(dev, old_state); + drm_atomic_helper_fake_vblank(old_state); + drm_atomic_helper_commit_hw_done(old_state); drm_atomic_helper_wait_for_vblanks(dev, old_state); @@ -1479,6 +1481,8 @@ void drm_atomic_helper_commit_tail_rpm(struct drm_atomic_state *old_state) drm_atomic_helper_commit_planes(dev, old_state, DRM_PLANE_COMMIT_ACTIVE_ONLY); + drm_atomic_helper_fake_vblank(old_state); + drm_atomic_helper_commit_hw_done(old_state); drm_atomic_helper_wait_for_vblanks(dev, old_state); -- GitLab From 1ebe99a75eeda1067c39c1c039ca9bb7e3c9c342 Mon Sep 17 00:00:00 2001 From: Boris Brezillon <boris.brezillon@bootlin.com> Date: Tue, 3 Jul 2018 09:50:21 +0200 Subject: [PATCH 0888/1506] drm/vc4: Call drm_atomic_helper_fake_vblank() in the commit path Mimic what is done in drm_atomic_commit_tail() and call drm_atomic_helper_fake_vblank() so that VBLANK events are faked when the drm_crtc_state.no_vblank is true. Will be needed when we'll add support for the transposer block. Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com> Reviewed-by: Eric Anholt <eric@anholt.net> Link: https://patchwork.freedesktop.org/patch/msgid/20180703075022.15138-8-boris.brezillon@bootlin.com --- drivers/gpu/drm/vc4/vc4_kms.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c index 91239b0a4fa0e..ca5aa7fba7694 100644 --- a/drivers/gpu/drm/vc4/vc4_kms.c +++ b/drivers/gpu/drm/vc4/vc4_kms.c @@ -153,6 +153,8 @@ vc4_atomic_complete_commit(struct drm_atomic_state *state) drm_atomic_helper_commit_modeset_enables(dev, state); + drm_atomic_helper_fake_vblank(state); + drm_atomic_helper_commit_hw_done(state); drm_atomic_helper_wait_for_flip_done(dev, state); -- GitLab From 008095e065a85a13ffb41b9c98149456267c30b8 Mon Sep 17 00:00:00 2001 From: Boris Brezillon <boris.brezillon@free-electrons.com> Date: Tue, 3 Jul 2018 09:50:22 +0200 Subject: [PATCH 0889/1506] drm/vc4: Add support for the transposer block The transposer block is providing support for mem-to-mem composition, which is exposed as a drm_writeback connector in DRM. Add a driver to support this feature. Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com> Reviewed-by: Eric Anholt <eric@anholt.net> Link: https://patchwork.freedesktop.org/patch/msgid/20180703075022.15138-9-boris.brezillon@bootlin.com --- .../bindings/display/brcm,bcm-vc4.txt | 6 + drivers/gpu/drm/vc4/Makefile | 1 + drivers/gpu/drm/vc4/vc4_crtc.c | 138 ++++- drivers/gpu/drm/vc4/vc4_debugfs.c | 1 + drivers/gpu/drm/vc4/vc4_drv.c | 1 + drivers/gpu/drm/vc4/vc4_drv.h | 7 + drivers/gpu/drm/vc4/vc4_txp.c | 477 ++++++++++++++++++ 7 files changed, 607 insertions(+), 24 deletions(-) create mode 100644 drivers/gpu/drm/vc4/vc4_txp.c diff --git a/Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt b/Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt index 284e2b14cfbe0..26649b4c4dd8d 100644 --- a/Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt +++ b/Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt @@ -74,6 +74,12 @@ Required properties for DSI: The 3 clocks output from the DSI analog PHY: dsi[01]_byte, dsi[01]_ddr2, and dsi[01]_ddr +Required properties for the TXP (writeback) block: +- compatible: Should be "brcm,bcm2835-txp" +- reg: Physical base address and length of the TXP block's registers +- interrupts: The interrupt number + See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt + [1] Documentation/devicetree/bindings/media/video-interfaces.txt Example: diff --git a/drivers/gpu/drm/vc4/Makefile b/drivers/gpu/drm/vc4/Makefile index 4a3a868235f84..b303703bc7f37 100644 --- a/drivers/gpu/drm/vc4/Makefile +++ b/drivers/gpu/drm/vc4/Makefile @@ -19,6 +19,7 @@ vc4-y := \ vc4_plane.o \ vc4_render_cl.o \ vc4_trace_points.o \ + vc4_txp.o \ vc4_v3d.o \ vc4_validate.o \ vc4_validate_shaders.o diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index d222358fa8a70..0e6a121858d13 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -46,6 +46,8 @@ struct vc4_crtc_state { struct drm_crtc_state base; /* Dlist area for this CRTC configuration. */ struct drm_mm_node mm; + bool feed_txp; + bool txp_armed; }; static inline struct vc4_crtc_state * @@ -324,10 +326,8 @@ static struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc) return NULL; } -static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc) +static void vc4_crtc_config_pv(struct drm_crtc *crtc) { - struct drm_device *dev = crtc->dev; - struct vc4_dev *vc4 = to_vc4_dev(dev); struct drm_encoder *encoder = vc4_get_crtc_encoder(crtc); struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder); struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); @@ -338,12 +338,6 @@ static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc) bool is_dsi = (vc4_encoder->type == VC4_ENCODER_TYPE_DSI0 || vc4_encoder->type == VC4_ENCODER_TYPE_DSI1); u32 format = is_dsi ? PV_CONTROL_FORMAT_DSIV_24 : PV_CONTROL_FORMAT_24; - bool debug_dump_regs = false; - - if (debug_dump_regs) { - DRM_INFO("CRTC %d regs before:\n", drm_crtc_index(crtc)); - vc4_crtc_dump_regs(vc4_crtc); - } /* Reset the PV fifo. */ CRTC_WRITE(PV_CONTROL, 0); @@ -419,6 +413,49 @@ static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc) PV_CONTROL_CLK_SELECT) | PV_CONTROL_FIFO_CLR | PV_CONTROL_EN); +} + +static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); + struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state); + struct drm_display_mode *mode = &crtc->state->adjusted_mode; + bool interlace = mode->flags & DRM_MODE_FLAG_INTERLACE; + bool debug_dump_regs = false; + + if (debug_dump_regs) { + DRM_INFO("CRTC %d regs before:\n", drm_crtc_index(crtc)); + vc4_crtc_dump_regs(vc4_crtc); + } + + if (vc4_crtc->channel == 2) { + u32 dispctrl; + u32 dsp3_mux; + + /* + * SCALER_DISPCTRL_DSP3 = X, where X < 2 means 'connect DSP3 to + * FIFO X'. + * SCALER_DISPCTRL_DSP3 = 3 means 'disable DSP 3'. + * + * DSP3 is connected to FIFO2 unless the transposer is + * enabled. In this case, FIFO 2 is directly accessed by the + * TXP IP, and we need to disable the FIFO2 -> pixelvalve1 + * route. + */ + if (vc4_state->feed_txp) + dsp3_mux = VC4_SET_FIELD(3, SCALER_DISPCTRL_DSP3_MUX); + else + dsp3_mux = VC4_SET_FIELD(2, SCALER_DISPCTRL_DSP3_MUX); + + dispctrl = HVS_READ(SCALER_DISPCTRL) & + ~SCALER_DISPCTRL_DSP3_MUX_MASK; + HVS_WRITE(SCALER_DISPCTRL, dispctrl | dsp3_mux); + } + + if (!vc4_state->feed_txp) + vc4_crtc_config_pv(crtc); HVS_WRITE(SCALER_DISPBKGNDX(vc4_crtc->channel), SCALER_DISPBKGND_AUTOHS | @@ -499,6 +536,13 @@ static void vc4_crtc_atomic_disable(struct drm_crtc *crtc, } } +void vc4_crtc_txp_armed(struct drm_crtc_state *state) +{ + struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state); + + vc4_state->txp_armed = true; +} + static void vc4_crtc_update_dlist(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -514,8 +558,11 @@ static void vc4_crtc_update_dlist(struct drm_crtc *crtc) WARN_ON(drm_crtc_vblank_get(crtc) != 0); spin_lock_irqsave(&dev->event_lock, flags); - vc4_crtc->event = crtc->state->event; - crtc->state->event = NULL; + + if (!vc4_state->feed_txp || vc4_state->txp_armed) { + vc4_crtc->event = crtc->state->event; + crtc->state->event = NULL; + } HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel), vc4_state->mm.start); @@ -533,8 +580,8 @@ static void vc4_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_device *dev = crtc->dev; struct vc4_dev *vc4 = to_vc4_dev(dev); struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); - struct drm_crtc_state *state = crtc->state; - struct drm_display_mode *mode = &state->adjusted_mode; + struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state); + struct drm_display_mode *mode = &crtc->state->adjusted_mode; require_hvs_enabled(dev); @@ -546,15 +593,21 @@ static void vc4_crtc_atomic_enable(struct drm_crtc *crtc, /* Turn on the scaler, which will wait for vstart to start * compositing. + * When feeding the transposer, we should operate in oneshot + * mode. */ HVS_WRITE(SCALER_DISPCTRLX(vc4_crtc->channel), VC4_SET_FIELD(mode->hdisplay, SCALER_DISPCTRLX_WIDTH) | VC4_SET_FIELD(mode->vdisplay, SCALER_DISPCTRLX_HEIGHT) | - SCALER_DISPCTRLX_ENABLE); + SCALER_DISPCTRLX_ENABLE | + (vc4_state->feed_txp ? SCALER_DISPCTRLX_ONESHOT : 0)); - /* Turn on the pixel valve, which will emit the vstart signal. */ - CRTC_WRITE(PV_V_CONTROL, - CRTC_READ(PV_V_CONTROL) | PV_VCONTROL_VIDEN); + /* When feeding the transposer block the pixelvalve is unneeded and + * should not be enabled. + */ + if (!vc4_state->feed_txp) + CRTC_WRITE(PV_V_CONTROL, + CRTC_READ(PV_V_CONTROL) | PV_VCONTROL_VIDEN); } static enum drm_mode_status vc4_crtc_mode_valid(struct drm_crtc *crtc, @@ -579,8 +632,10 @@ static int vc4_crtc_atomic_check(struct drm_crtc *crtc, struct drm_plane *plane; unsigned long flags; const struct drm_plane_state *plane_state; + struct drm_connector *conn; + struct drm_connector_state *conn_state; u32 dlist_count = 0; - int ret; + int ret, i; /* The pixelvalve can only feed one encoder (and encoders are * 1:1 with connectors.) @@ -600,6 +655,24 @@ static int vc4_crtc_atomic_check(struct drm_crtc *crtc, if (ret) return ret; + for_each_new_connector_in_state(state->state, conn, conn_state, i) { + if (conn_state->crtc != crtc) + continue; + + /* The writeback connector is implemented using the transposer + * block which is directly taking its data from the HVS FIFO. + */ + if (conn->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) { + state->no_vblank = true; + vc4_state->feed_txp = true; + } else { + state->no_vblank = false; + vc4_state->feed_txp = false; + } + + break; + } + return 0; } @@ -713,7 +786,8 @@ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc) spin_lock_irqsave(&dev->event_lock, flags); if (vc4_crtc->event && - (vc4_state->mm.start == HVS_READ(SCALER_DISPLACTX(chan)))) { + (vc4_state->mm.start == HVS_READ(SCALER_DISPLACTX(chan)) || + vc4_state->feed_txp)) { drm_crtc_send_vblank_event(crtc, vc4_crtc->event); vc4_crtc->event = NULL; drm_crtc_vblank_put(crtc); @@ -721,6 +795,13 @@ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc) spin_unlock_irqrestore(&dev->event_lock, flags); } +void vc4_crtc_handle_vblank(struct vc4_crtc *crtc) +{ + crtc->t_vblank = ktime_get(); + drm_crtc_handle_vblank(&crtc->base); + vc4_crtc_handle_page_flip(crtc); +} + static irqreturn_t vc4_crtc_irq_handler(int irq, void *data) { struct vc4_crtc *vc4_crtc = data; @@ -728,10 +809,8 @@ static irqreturn_t vc4_crtc_irq_handler(int irq, void *data) irqreturn_t ret = IRQ_NONE; if (stat & PV_INT_VFP_START) { - vc4_crtc->t_vblank = ktime_get(); CRTC_WRITE(PV_INTSTAT, PV_INT_VFP_START); - drm_crtc_handle_vblank(&vc4_crtc->base); - vc4_crtc_handle_page_flip(vc4_crtc); + vc4_crtc_handle_vblank(vc4_crtc); ret = IRQ_HANDLED; } @@ -884,12 +963,15 @@ static int vc4_page_flip(struct drm_crtc *crtc, static struct drm_crtc_state *vc4_crtc_duplicate_state(struct drm_crtc *crtc) { - struct vc4_crtc_state *vc4_state; + struct vc4_crtc_state *vc4_state, *old_vc4_state; vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL); if (!vc4_state) return NULL; + old_vc4_state = to_vc4_crtc_state(crtc->state); + vc4_state->feed_txp = old_vc4_state->feed_txp; + __drm_atomic_helper_crtc_duplicate_state(crtc, &vc4_state->base); return &vc4_state->base; } @@ -987,9 +1069,17 @@ static void vc4_set_crtc_possible_masks(struct drm_device *drm, struct drm_encoder *encoder; drm_for_each_encoder(encoder, drm) { - struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder); + struct vc4_encoder *vc4_encoder; int i; + /* HVS FIFO2 can feed the TXP IP. */ + if (crtc_data->hvs_channel == 2 && + encoder->encoder_type == DRM_MODE_ENCODER_VIRTUAL) { + encoder->possible_crtcs |= drm_crtc_mask(crtc); + continue; + } + + vc4_encoder = to_vc4_encoder(encoder); for (i = 0; i < ARRAY_SIZE(crtc_data->encoder_types); i++) { if (vc4_encoder->type == encoder_types[i]) { vc4_encoder->clock_select = i; diff --git a/drivers/gpu/drm/vc4/vc4_debugfs.c b/drivers/gpu/drm/vc4/vc4_debugfs.c index 5db06bdb5f27b..7a0003de71ab0 100644 --- a/drivers/gpu/drm/vc4/vc4_debugfs.c +++ b/drivers/gpu/drm/vc4/vc4_debugfs.c @@ -21,6 +21,7 @@ static const struct drm_info_list vc4_debugfs_list[] = { {"dsi1_regs", vc4_dsi_debugfs_regs, 0, (void *)(uintptr_t)1}, {"hdmi_regs", vc4_hdmi_debugfs_regs, 0}, {"vec_regs", vc4_vec_debugfs_regs, 0}, + {"txp_regs", vc4_txp_debugfs_regs, 0}, {"hvs_regs", vc4_hvs_debugfs_regs, 0}, {"crtc0_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)0}, {"crtc1_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)1}, diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c index 466d0a27b4151..e42fd5ec41cc9 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.c +++ b/drivers/gpu/drm/vc4/vc4_drv.c @@ -344,6 +344,7 @@ static struct platform_driver *const component_drivers[] = { &vc4_vec_driver, &vc4_dpi_driver, &vc4_dsi_driver, + &vc4_txp_driver, &vc4_hvs_driver, &vc4_crtc_driver, &vc4_v3d_driver, diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index eace76c621a18..bd6ef1f318220 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -73,6 +73,7 @@ struct vc4_dev { struct vc4_dpi *dpi; struct vc4_dsi *dsi1; struct vc4_vec *vec; + struct vc4_txp *txp; struct vc4_hang_state *hang_state; @@ -698,6 +699,8 @@ bool vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id, bool in_vblank_irq, int *vpos, int *hpos, ktime_t *stime, ktime_t *etime, const struct drm_display_mode *mode); +void vc4_crtc_handle_vblank(struct vc4_crtc *crtc); +void vc4_crtc_txp_armed(struct drm_crtc_state *state); /* vc4_debugfs.c */ int vc4_debugfs_init(struct drm_minor *minor); @@ -745,6 +748,10 @@ int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused); extern struct platform_driver vc4_vec_driver; int vc4_vec_debugfs_regs(struct seq_file *m, void *unused); +/* vc4_txp.c */ +extern struct platform_driver vc4_txp_driver; +int vc4_txp_debugfs_regs(struct seq_file *m, void *unused); + /* vc4_irq.c */ irqreturn_t vc4_irq(int irq, void *arg); void vc4_irq_preinstall(struct drm_device *dev); diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c new file mode 100644 index 0000000000000..6e23c50168f9a --- /dev/null +++ b/drivers/gpu/drm/vc4/vc4_txp.c @@ -0,0 +1,477 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright © 2018 Broadcom + * + * Authors: + * Eric Anholt <eric@anholt.net> + * Boris Brezillon <boris.brezillon@bootlin.com> + */ + +#include <drm/drm_atomic_helper.h> +#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_edid.h> +#include <drm/drm_panel.h> +#include <drm/drm_writeback.h> +#include <linux/clk.h> +#include <linux/component.h> +#include <linux/of_graph.h> +#include <linux/of_platform.h> +#include <linux/pm_runtime.h> + +#include "vc4_drv.h" +#include "vc4_regs.h" + +/* Base address of the output. Raster formats must be 4-byte aligned, + * T and LT must be 16-byte aligned or maybe utile-aligned (docs are + * inconsistent, but probably utile). + */ +#define TXP_DST_PTR 0x00 + +/* Pitch in bytes for raster images, 16-byte aligned. For tiled, it's + * the width in tiles. + */ +#define TXP_DST_PITCH 0x04 +/* For T-tiled imgaes, DST_PITCH should be the number of tiles wide, + * shifted up. + */ +# define TXP_T_TILE_WIDTH_SHIFT 7 +/* For LT-tiled images, DST_PITCH should be the number of utiles wide, + * shifted up. + */ +# define TXP_LT_TILE_WIDTH_SHIFT 4 + +/* Pre-rotation width/height of the image. Must match HVS config. + * + * If TFORMAT and 32-bit, limit is 1920 for 32-bit and 3840 to 16-bit + * and width/height must be tile or utile-aligned as appropriate. If + * transposing (rotating), width is limited to 1920. + * + * Height is limited to various numbers between 4088 and 4095. I'd + * just use 4088 to be safe. + */ +#define TXP_DIM 0x08 +# define TXP_HEIGHT_SHIFT 16 +# define TXP_HEIGHT_MASK GENMASK(31, 16) +# define TXP_WIDTH_SHIFT 0 +# define TXP_WIDTH_MASK GENMASK(15, 0) + +#define TXP_DST_CTRL 0x0c +/* These bits are set to 0x54 */ +#define TXP_PILOT_SHIFT 24 +#define TXP_PILOT_MASK GENMASK(31, 24) +/* Bits 22-23 are set to 0x01 */ +#define TXP_VERSION_SHIFT 22 +#define TXP_VERSION_MASK GENMASK(23, 22) + +/* Powers down the internal memory. */ +# define TXP_POWERDOWN BIT(21) + +/* Enables storing the alpha component in 8888/4444, instead of + * filling with ~ALPHA_INVERT. + */ +# define TXP_ALPHA_ENABLE BIT(20) + +/* 4 bits, each enables stores for a channel in each set of 4 bytes. + * Set to 0xf for normal operation. + */ +# define TXP_BYTE_ENABLE_SHIFT 16 +# define TXP_BYTE_ENABLE_MASK GENMASK(19, 16) + +/* Debug: Generate VSTART again at EOF. */ +# define TXP_VSTART_AT_EOF BIT(15) + +/* Debug: Terminate the current frame immediately. Stops AXI + * writes. + */ +# define TXP_ABORT BIT(14) + +# define TXP_DITHER BIT(13) + +/* Inverts alpha if TXP_ALPHA_ENABLE, chooses fill value for + * !TXP_ALPHA_ENABLE. + */ +# define TXP_ALPHA_INVERT BIT(12) + +/* Note: I've listed the channels here in high bit (in byte 3/2/1) to + * low bit (in byte 0) order. + */ +# define TXP_FORMAT_SHIFT 8 +# define TXP_FORMAT_MASK GENMASK(11, 8) +# define TXP_FORMAT_ABGR4444 0 +# define TXP_FORMAT_ARGB4444 1 +# define TXP_FORMAT_BGRA4444 2 +# define TXP_FORMAT_RGBA4444 3 +# define TXP_FORMAT_BGR565 6 +# define TXP_FORMAT_RGB565 7 +/* 888s are non-rotated, raster-only */ +# define TXP_FORMAT_BGR888 8 +# define TXP_FORMAT_RGB888 9 +# define TXP_FORMAT_ABGR8888 12 +# define TXP_FORMAT_ARGB8888 13 +# define TXP_FORMAT_BGRA8888 14 +# define TXP_FORMAT_RGBA8888 15 + +/* If TFORMAT is set, generates LT instead of T format. */ +# define TXP_LINEAR_UTILE BIT(7) + +/* Rotate output by 90 degrees. */ +# define TXP_TRANSPOSE BIT(6) + +/* Generate a tiled format for V3D. */ +# define TXP_TFORMAT BIT(5) + +/* Generates some undefined test mode output. */ +# define TXP_TEST_MODE BIT(4) + +/* Request odd field from HVS. */ +# define TXP_FIELD BIT(3) + +/* Raise interrupt when idle. */ +# define TXP_EI BIT(2) + +/* Set when generating a frame, clears when idle. */ +# define TXP_BUSY BIT(1) + +/* Starts a frame. Self-clearing. */ +# define TXP_GO BIT(0) + +/* Number of lines received and committed to memory. */ +#define TXP_PROGRESS 0x10 + +#define TXP_READ(offset) readl(txp->regs + (offset)) +#define TXP_WRITE(offset, val) writel(val, txp->regs + (offset)) + +struct vc4_txp { + struct platform_device *pdev; + + struct drm_writeback_connector connector; + + void __iomem *regs; +}; + +static inline struct vc4_txp *encoder_to_vc4_txp(struct drm_encoder *encoder) +{ + return container_of(encoder, struct vc4_txp, connector.encoder); +} + +static inline struct vc4_txp *connector_to_vc4_txp(struct drm_connector *conn) +{ + return container_of(conn, struct vc4_txp, connector.base); +} + +#define TXP_REG(reg) { reg, #reg } +static const struct { + u32 reg; + const char *name; +} txp_regs[] = { + TXP_REG(TXP_DST_PTR), + TXP_REG(TXP_DST_PITCH), + TXP_REG(TXP_DIM), + TXP_REG(TXP_DST_CTRL), + TXP_REG(TXP_PROGRESS), +}; + +#ifdef CONFIG_DEBUG_FS +int vc4_txp_debugfs_regs(struct seq_file *m, void *unused) +{ + struct drm_info_node *node = (struct drm_info_node *)m->private; + struct drm_device *dev = node->minor->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct vc4_txp *txp = vc4->txp; + int i; + + if (!txp) + return 0; + + for (i = 0; i < ARRAY_SIZE(txp_regs); i++) { + seq_printf(m, "%s (0x%04x): 0x%08x\n", + txp_regs[i].name, txp_regs[i].reg, + TXP_READ(txp_regs[i].reg)); + } + + return 0; +} +#endif + +static int vc4_txp_connector_get_modes(struct drm_connector *connector) +{ + struct drm_device *dev = connector->dev; + + return drm_add_modes_noedid(connector, dev->mode_config.max_width, + dev->mode_config.max_height); +} + +static enum drm_mode_status +vc4_txp_connector_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + struct drm_device *dev = connector->dev; + struct drm_mode_config *mode_config = &dev->mode_config; + int w = mode->hdisplay, h = mode->vdisplay; + + if (w < mode_config->min_width || w > mode_config->max_width) + return MODE_BAD_HVALUE; + + if (h < mode_config->min_height || h > mode_config->max_height) + return MODE_BAD_VVALUE; + + return MODE_OK; +} + +static const u32 drm_fmts[] = { + DRM_FORMAT_RGB888, + DRM_FORMAT_BGR888, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_RGBX8888, + DRM_FORMAT_BGRX8888, + DRM_FORMAT_RGBA8888, + DRM_FORMAT_BGRA8888, +}; + +static const u32 txp_fmts[] = { + TXP_FORMAT_RGB888, + TXP_FORMAT_BGR888, + TXP_FORMAT_ARGB8888, + TXP_FORMAT_ABGR8888, + TXP_FORMAT_ARGB8888, + TXP_FORMAT_ABGR8888, + TXP_FORMAT_RGBA8888, + TXP_FORMAT_BGRA8888, + TXP_FORMAT_RGBA8888, + TXP_FORMAT_BGRA8888, +}; + +static int vc4_txp_connector_atomic_check(struct drm_connector *conn, + struct drm_connector_state *conn_state) +{ + struct drm_crtc_state *crtc_state; + struct drm_gem_cma_object *gem; + struct drm_framebuffer *fb; + int i; + + if (!conn_state->writeback_job || !conn_state->writeback_job->fb) + return 0; + + crtc_state = drm_atomic_get_new_crtc_state(conn_state->state, + conn_state->crtc); + + fb = conn_state->writeback_job->fb; + if (fb->width != crtc_state->mode.hdisplay || + fb->height != crtc_state->mode.vdisplay) { + DRM_DEBUG_KMS("Invalid framebuffer size %ux%u\n", + fb->width, fb->height); + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(drm_fmts); i++) { + if (fb->format->format == drm_fmts[i]) + break; + } + + if (i == ARRAY_SIZE(drm_fmts)) + return -EINVAL; + + gem = drm_fb_cma_get_gem_obj(fb, 0); + + /* Pitch must be aligned on 16 bytes. */ + if (fb->pitches[0] & GENMASK(3, 0)) + return -EINVAL; + + vc4_crtc_txp_armed(crtc_state); + + return 0; +} + +static void vc4_txp_connector_atomic_commit(struct drm_connector *conn, + struct drm_connector_state *conn_state) +{ + struct vc4_txp *txp = connector_to_vc4_txp(conn); + struct drm_gem_cma_object *gem; + struct drm_display_mode *mode; + struct drm_framebuffer *fb; + u32 ctrl; + int i; + + if (WARN_ON(!conn_state->writeback_job || + !conn_state->writeback_job->fb)) + return; + + mode = &conn_state->crtc->state->adjusted_mode; + fb = conn_state->writeback_job->fb; + + for (i = 0; i < ARRAY_SIZE(drm_fmts); i++) { + if (fb->format->format == drm_fmts[i]) + break; + } + + if (WARN_ON(i == ARRAY_SIZE(drm_fmts))) + return; + + ctrl = TXP_GO | TXP_VSTART_AT_EOF | TXP_EI | + VC4_SET_FIELD(0xf, TXP_BYTE_ENABLE) | + VC4_SET_FIELD(txp_fmts[i], TXP_FORMAT); + + if (fb->format->has_alpha) + ctrl |= TXP_ALPHA_ENABLE; + + gem = drm_fb_cma_get_gem_obj(fb, 0); + TXP_WRITE(TXP_DST_PTR, gem->paddr + fb->offsets[0]); + TXP_WRITE(TXP_DST_PITCH, fb->pitches[0]); + TXP_WRITE(TXP_DIM, + VC4_SET_FIELD(mode->hdisplay, TXP_WIDTH) | + VC4_SET_FIELD(mode->vdisplay, TXP_HEIGHT)); + + TXP_WRITE(TXP_DST_CTRL, ctrl); + + drm_writeback_queue_job(&txp->connector, conn_state->writeback_job); +} + +static const struct drm_connector_helper_funcs vc4_txp_connector_helper_funcs = { + .get_modes = vc4_txp_connector_get_modes, + .mode_valid = vc4_txp_connector_mode_valid, + .atomic_check = vc4_txp_connector_atomic_check, + .atomic_commit = vc4_txp_connector_atomic_commit, +}; + +static enum drm_connector_status +vc4_txp_connector_detect(struct drm_connector *connector, bool force) +{ + return connector_status_connected; +} + +static void vc4_txp_connector_destroy(struct drm_connector *connector) +{ + drm_connector_unregister(connector); + drm_connector_cleanup(connector); +} + +static const struct drm_connector_funcs vc4_txp_connector_funcs = { + .detect = vc4_txp_connector_detect, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = vc4_txp_connector_destroy, + .reset = drm_atomic_helper_connector_reset, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +}; + +static void vc4_txp_encoder_disable(struct drm_encoder *encoder) +{ + struct vc4_txp *txp = encoder_to_vc4_txp(encoder); + + if (TXP_READ(TXP_DST_CTRL) & TXP_BUSY) { + unsigned long timeout = jiffies + msecs_to_jiffies(1000); + + TXP_WRITE(TXP_DST_CTRL, TXP_ABORT); + + while (TXP_READ(TXP_DST_CTRL) & TXP_BUSY && + time_before(jiffies, timeout)) + ; + + WARN_ON(TXP_READ(TXP_DST_CTRL) & TXP_BUSY); + } + + TXP_WRITE(TXP_DST_CTRL, TXP_POWERDOWN); +} + +static const struct drm_encoder_helper_funcs vc4_txp_encoder_helper_funcs = { + .disable = vc4_txp_encoder_disable, +}; + +static irqreturn_t vc4_txp_interrupt(int irq, void *data) +{ + struct vc4_txp *txp = data; + + TXP_WRITE(TXP_DST_CTRL, TXP_READ(TXP_DST_CTRL) & ~TXP_EI); + vc4_crtc_handle_vblank(to_vc4_crtc(txp->connector.base.state->crtc)); + drm_writeback_signal_completion(&txp->connector, 0); + + return IRQ_HANDLED; +} + +static int vc4_txp_bind(struct device *dev, struct device *master, void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + struct drm_device *drm = dev_get_drvdata(master); + struct vc4_dev *vc4 = to_vc4_dev(drm); + struct vc4_txp *txp; + int ret, irq; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + txp = devm_kzalloc(dev, sizeof(*txp), GFP_KERNEL); + if (!txp) + return -ENOMEM; + + txp->pdev = pdev; + + txp->regs = vc4_ioremap_regs(pdev, 0); + if (IS_ERR(txp->regs)) + return PTR_ERR(txp->regs); + + drm_connector_helper_add(&txp->connector.base, + &vc4_txp_connector_helper_funcs); + ret = drm_writeback_connector_init(drm, &txp->connector, + &vc4_txp_connector_funcs, + &vc4_txp_encoder_helper_funcs, + drm_fmts, ARRAY_SIZE(drm_fmts)); + if (ret) + return ret; + + ret = devm_request_irq(dev, irq, vc4_txp_interrupt, 0, + dev_name(dev), txp); + if (ret) + return ret; + + dev_set_drvdata(dev, txp); + vc4->txp = txp; + + return 0; +} + +static void vc4_txp_unbind(struct device *dev, struct device *master, + void *data) +{ + struct drm_device *drm = dev_get_drvdata(master); + struct vc4_dev *vc4 = to_vc4_dev(drm); + struct vc4_txp *txp = dev_get_drvdata(dev); + + vc4_txp_connector_destroy(&txp->connector.base); + + vc4->txp = NULL; +} + +static const struct component_ops vc4_txp_ops = { + .bind = vc4_txp_bind, + .unbind = vc4_txp_unbind, +}; + +static int vc4_txp_probe(struct platform_device *pdev) +{ + return component_add(&pdev->dev, &vc4_txp_ops); +} + +static int vc4_txp_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &vc4_txp_ops); + return 0; +} + +static const struct of_device_id vc4_txp_dt_match[] = { + { .compatible = "brcm,bcm2835-txp" }, + { /* sentinel */ }, +}; + +struct platform_driver vc4_txp_driver = { + .probe = vc4_txp_probe, + .remove = vc4_txp_remove, + .driver = { + .name = "vc4_txp", + .of_match_table = vc4_txp_dt_match, + }, +}; -- GitLab From 890fd185d53037d05d10a0825950c4b038e39d4a Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 6 Jul 2018 22:07:10 +0100 Subject: [PATCH 0890/1506] drm/i915: Replace nested subclassing with explicit subclasses In the next patch, we will want a third distinct class of timeline that may overlap with the current pair of client and engine timeline classes. Rather than use the ad hoc markup of SINGLE_DEPTH_NESTING, initialise the different timeline classes with an explicit subclass. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180706210710.16251-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 2 +- drivers/gpu/drm/i915/i915_request.c | 2 +- drivers/gpu/drm/i915/i915_timeline.h | 2 ++ drivers/gpu/drm/i915/intel_engine_cs.c | 1 + drivers/gpu/drm/i915/selftests/mock_engine.c | 2 ++ 5 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 2e05cf1140832..1a9dab302433e 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3095,7 +3095,7 @@ static void engine_skip_context(struct i915_request *request) GEM_BUG_ON(timeline == &engine->timeline); spin_lock_irqsave(&engine->timeline.lock, flags); - spin_lock_nested(&timeline->lock, SINGLE_DEPTH_NESTING); + spin_lock(&timeline->lock); list_for_each_entry_continue(request, &engine->timeline.requests, link) if (request->gem_context == hung_ctx) diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index 7ae08b68121e8..3248369dbcfb2 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -503,7 +503,7 @@ static void move_to_timeline(struct i915_request *request, GEM_BUG_ON(request->timeline == &request->engine->timeline); lockdep_assert_held(&request->engine->timeline.lock); - spin_lock_nested(&request->timeline->lock, SINGLE_DEPTH_NESTING); + spin_lock(&request->timeline->lock); list_move_tail(&request->link, &timeline->requests); spin_unlock(&request->timeline->lock); } diff --git a/drivers/gpu/drm/i915/i915_timeline.h b/drivers/gpu/drm/i915/i915_timeline.h index dc2a4632faa7d..a2c2c3ab5fb0c 100644 --- a/drivers/gpu/drm/i915/i915_timeline.h +++ b/drivers/gpu/drm/i915/i915_timeline.h @@ -37,6 +37,8 @@ struct i915_timeline { u32 seqno; spinlock_t lock; +#define TIMELINE_CLIENT 0 /* default subclass */ +#define TIMELINE_ENGINE 1 /** * List of breadcrumbs associated with GPU requests currently diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index e2f562853aeec..0ac497275a513 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -483,6 +483,7 @@ static void intel_engine_init_execlist(struct intel_engine_cs *engine) void intel_engine_setup_common(struct intel_engine_cs *engine) { i915_timeline_init(engine->i915, &engine->timeline, engine->name); + lockdep_set_subclass(&engine->timeline.lock, TIMELINE_ENGINE); intel_engine_init_execlist(engine); intel_engine_init_hangcheck(engine); diff --git a/drivers/gpu/drm/i915/selftests/mock_engine.c b/drivers/gpu/drm/i915/selftests/mock_engine.c index c2a0451336cf5..22a73da45ad58 100644 --- a/drivers/gpu/drm/i915/selftests/mock_engine.c +++ b/drivers/gpu/drm/i915/selftests/mock_engine.c @@ -200,6 +200,8 @@ struct intel_engine_cs *mock_engine(struct drm_i915_private *i915, engine->base.submit_request = mock_submit_request; i915_timeline_init(i915, &engine->base.timeline, engine->base.name); + lockdep_set_subclass(&engine->base.timeline.lock, TIMELINE_ENGINE); + intel_engine_init_breadcrumbs(&engine->base); engine->base.breadcrumbs.mock = true; /* prevent touching HW for irqs */ -- GitLab From b294657d1bab3371bf02c31a243232bfa9f4629f Mon Sep 17 00:00:00 2001 From: Changbin Du <changbin.du@intel.com> Date: Tue, 15 May 2018 10:35:33 +0800 Subject: [PATCH 0891/1506] drm/i915/gvt: Add new 64K entry type Add a new entry type GTT_TYPE_PPGTT_PTE_64K_ENTRY. 64K entry is very different from 2M/1G entry. 64K entry is controlled by IPS bit in upper PDE. To leverage the current logic, I take IPS bit as 'PSE' for PTE level. Which means, 64K entries can also processed by get_pse_type(). v2: Make it bisectable. Signed-off-by: Changbin Du <changbin.du@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> --- drivers/gpu/drm/i915/gvt/gtt.c | 26 ++++++++++++++++++++++---- drivers/gpu/drm/i915/gvt/gtt.h | 1 + 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/gtt.c b/drivers/gpu/drm/i915/gvt/gtt.c index 6a8a9868bcfb9..03f2a5b26546c 100644 --- a/drivers/gpu/drm/i915/gvt/gtt.c +++ b/drivers/gpu/drm/i915/gvt/gtt.c @@ -216,16 +216,22 @@ static struct gtt_type_table_entry gtt_type_table[] = { GTT_TYPE_PPGTT_PDE_PT, GTT_TYPE_PPGTT_PTE_PT, GTT_TYPE_PPGTT_PTE_2M_ENTRY), + /* We take IPS bit as 'PSE' for PTE level. */ GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_PTE_PT, GTT_TYPE_PPGTT_PTE_4K_ENTRY, GTT_TYPE_PPGTT_PTE_PT, GTT_TYPE_INVALID, - GTT_TYPE_INVALID), + GTT_TYPE_PPGTT_PTE_64K_ENTRY), GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_PTE_4K_ENTRY, GTT_TYPE_PPGTT_PTE_4K_ENTRY, GTT_TYPE_PPGTT_PTE_PT, GTT_TYPE_INVALID, - GTT_TYPE_INVALID), + GTT_TYPE_PPGTT_PTE_64K_ENTRY), + GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_PTE_64K_ENTRY, + GTT_TYPE_PPGTT_PTE_4K_ENTRY, + GTT_TYPE_PPGTT_PTE_PT, + GTT_TYPE_INVALID, + GTT_TYPE_PPGTT_PTE_64K_ENTRY), GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_PTE_2M_ENTRY, GTT_TYPE_PPGTT_PDE_ENTRY, GTT_TYPE_PPGTT_PDE_PT, @@ -339,6 +345,7 @@ static inline int gtt_set_entry64(void *pt, #define ADDR_1G_MASK GENMASK_ULL(GTT_HAW - 1, 30) #define ADDR_2M_MASK GENMASK_ULL(GTT_HAW - 1, 21) +#define ADDR_64K_MASK GENMASK_ULL(GTT_HAW - 1, 16) #define ADDR_4K_MASK GENMASK_ULL(GTT_HAW - 1, 12) static unsigned long gen8_gtt_get_pfn(struct intel_gvt_gtt_entry *e) @@ -349,6 +356,8 @@ static unsigned long gen8_gtt_get_pfn(struct intel_gvt_gtt_entry *e) pfn = (e->val64 & ADDR_1G_MASK) >> PAGE_SHIFT; else if (e->type == GTT_TYPE_PPGTT_PTE_2M_ENTRY) pfn = (e->val64 & ADDR_2M_MASK) >> PAGE_SHIFT; + else if (e->type == GTT_TYPE_PPGTT_PTE_64K_ENTRY) + pfn = (e->val64 & ADDR_64K_MASK) >> PAGE_SHIFT; else pfn = (e->val64 & ADDR_4K_MASK) >> PAGE_SHIFT; return pfn; @@ -362,6 +371,9 @@ static void gen8_gtt_set_pfn(struct intel_gvt_gtt_entry *e, unsigned long pfn) } else if (e->type == GTT_TYPE_PPGTT_PTE_2M_ENTRY) { e->val64 &= ~ADDR_2M_MASK; pfn &= (ADDR_2M_MASK >> PAGE_SHIFT); + } else if (e->type == GTT_TYPE_PPGTT_PTE_64K_ENTRY) { + e->val64 &= ~ADDR_64K_MASK; + pfn &= (ADDR_64K_MASK >> PAGE_SHIFT); } else { e->val64 &= ~ADDR_4K_MASK; pfn &= (ADDR_4K_MASK >> PAGE_SHIFT); @@ -380,6 +392,10 @@ static bool gen8_gtt_test_pse(struct intel_gvt_gtt_entry *e) if (!(e->val64 & _PAGE_PSE)) return false; + /* We don't support 64K entry yet, will remove this later. */ + if (get_pse_type(e->type) == GTT_TYPE_PPGTT_PTE_64K_ENTRY) + return false; + e->type = get_pse_type(e->type); return true; } @@ -871,9 +887,10 @@ static int ppgtt_invalidate_spt(struct intel_vgpu_ppgtt_spt *spt) gvt_vdbg_mm("invalidate 4K entry\n"); ppgtt_invalidate_pte(spt, &e); break; + case GTT_TYPE_PPGTT_PTE_64K_ENTRY: case GTT_TYPE_PPGTT_PTE_2M_ENTRY: case GTT_TYPE_PPGTT_PTE_1G_ENTRY: - WARN(1, "GVT doesn't support 2M/1GB page\n"); + WARN(1, "GVT doesn't support 64K/2M/1GB page\n"); continue; case GTT_TYPE_PPGTT_PML4_ENTRY: case GTT_TYPE_PPGTT_PDP_ENTRY: @@ -970,9 +987,10 @@ static int ppgtt_populate_shadow_entry(struct intel_vgpu *vgpu, case GTT_TYPE_PPGTT_PTE_4K_ENTRY: gvt_vdbg_mm("shadow 4K gtt entry\n"); break; + case GTT_TYPE_PPGTT_PTE_64K_ENTRY: case GTT_TYPE_PPGTT_PTE_2M_ENTRY: case GTT_TYPE_PPGTT_PTE_1G_ENTRY: - gvt_vgpu_err("GVT doesn't support 2M/1GB entry\n"); + gvt_vgpu_err("GVT doesn't support 64K/2M/1GB entry\n"); return -EINVAL; default: GEM_BUG_ON(1); diff --git a/drivers/gpu/drm/i915/gvt/gtt.h b/drivers/gpu/drm/i915/gvt/gtt.h index 3792f2b7f4ff0..60630816df5c5 100644 --- a/drivers/gpu/drm/i915/gvt/gtt.h +++ b/drivers/gpu/drm/i915/gvt/gtt.h @@ -95,6 +95,7 @@ typedef enum { GTT_TYPE_GGTT_PTE, GTT_TYPE_PPGTT_PTE_4K_ENTRY, + GTT_TYPE_PPGTT_PTE_64K_ENTRY, GTT_TYPE_PPGTT_PTE_2M_ENTRY, GTT_TYPE_PPGTT_PTE_1G_ENTRY, -- GitLab From 6fd7937832698e73a5719ff488c2fc5e22c9c0ba Mon Sep 17 00:00:00 2001 From: Changbin Du <changbin.du@intel.com> Date: Tue, 15 May 2018 10:35:34 +0800 Subject: [PATCH 0892/1506] drm/i915/gvt: Add PTE IPS bit operations Add three IPS operation functions to test/set/clear IPS in PDE. Signed-off-by: Changbin Du <changbin.du@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> --- drivers/gpu/drm/i915/gvt/gtt.c | 18 ++++++++++++++++++ drivers/gpu/drm/i915/gvt/gtt.h | 2 ++ 2 files changed, 20 insertions(+) diff --git a/drivers/gpu/drm/i915/gvt/gtt.c b/drivers/gpu/drm/i915/gvt/gtt.c index 03f2a5b26546c..3e67339145309 100644 --- a/drivers/gpu/drm/i915/gvt/gtt.c +++ b/drivers/gpu/drm/i915/gvt/gtt.c @@ -400,6 +400,22 @@ static bool gen8_gtt_test_pse(struct intel_gvt_gtt_entry *e) return true; } +static bool gen8_gtt_test_ips(struct intel_gvt_gtt_entry *e) +{ + if (GEM_WARN_ON(e->type != GTT_TYPE_PPGTT_PDE_ENTRY)) + return false; + + return !!(e->val64 & GEN8_PDE_IPS_64K); +} + +static void gen8_gtt_clear_ips(struct intel_gvt_gtt_entry *e) +{ + if (GEM_WARN_ON(e->type != GTT_TYPE_PPGTT_PDE_ENTRY)) + return; + + e->val64 &= ~GEN8_PDE_IPS_64K; +} + static bool gen8_gtt_test_present(struct intel_gvt_gtt_entry *e) { /* @@ -456,6 +472,8 @@ static struct intel_gvt_gtt_pte_ops gen8_gtt_pte_ops = { .set_present = gtt_entry_set_present, .test_present = gen8_gtt_test_present, .test_pse = gen8_gtt_test_pse, + .clear_ips = gen8_gtt_clear_ips, + .test_ips = gen8_gtt_test_ips, .get_pfn = gen8_gtt_get_pfn, .set_pfn = gen8_gtt_set_pfn, }; diff --git a/drivers/gpu/drm/i915/gvt/gtt.h b/drivers/gpu/drm/i915/gvt/gtt.h index 60630816df5c5..9257b7467b14f 100644 --- a/drivers/gpu/drm/i915/gvt/gtt.h +++ b/drivers/gpu/drm/i915/gvt/gtt.h @@ -63,6 +63,8 @@ struct intel_gvt_gtt_pte_ops { void (*clear_present)(struct intel_gvt_gtt_entry *e); void (*set_present)(struct intel_gvt_gtt_entry *e); bool (*test_pse)(struct intel_gvt_gtt_entry *e); + bool (*test_ips)(struct intel_gvt_gtt_entry *e); + void (*clear_ips)(struct intel_gvt_gtt_entry *e); void (*set_pfn)(struct intel_gvt_gtt_entry *e, unsigned long pfn); unsigned long (*get_pfn)(struct intel_gvt_gtt_entry *e); }; -- GitLab From 52ca14e6844a04e174b5cd3d7dbf63a23271775c Mon Sep 17 00:00:00 2001 From: Changbin Du <changbin.du@intel.com> Date: Tue, 15 May 2018 10:35:35 +0800 Subject: [PATCH 0893/1506] drm/i915/gvt: Handle MMIO GEN8_GAMW_ECO_DEV_RW_IA for 64K GTT The register RENDER_HWS_PGA_GEN7 is renamed to GEN8_GAMW_ECO_DEV_RW_IA from GEN8 which can control IPS enabling. v3: MMIO control for IPS is not removed from gen9 but gen10 (Matthew Auld) v2: IPS of all engines must be enabled together for gen9. Signed-off-by: Changbin Du <changbin.du@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> --- drivers/gpu/drm/i915/gvt/handlers.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c index 0bc0c5418adb8..17f56fc20613f 100644 --- a/drivers/gpu/drm/i915/gvt/handlers.c +++ b/drivers/gpu/drm/i915/gvt/handlers.c @@ -210,6 +210,31 @@ static int sanitize_fence_mmio_access(struct intel_vgpu *vgpu, return 0; } +static int gamw_echo_dev_rw_ia_write(struct intel_vgpu *vgpu, + unsigned int offset, void *p_data, unsigned int bytes) +{ + u32 ips = (*(u32 *)p_data) & GAMW_ECO_ENABLE_64K_IPS_FIELD; + + if (INTEL_GEN(vgpu->gvt->dev_priv) <= 10) { + if (ips == GAMW_ECO_ENABLE_64K_IPS_FIELD) + gvt_dbg_core("vgpu%d: ips enabled\n", vgpu->id); + else if (!ips) + gvt_dbg_core("vgpu%d: ips disabled\n", vgpu->id); + else { + /* All engines must be enabled together for vGPU, + * since we don't know which engine the ppgtt will + * bind to when shadowing. + */ + gvt_vgpu_err("Unsupported IPS setting %x, cannot enable 64K gtt.\n", + ips); + return -EINVAL; + } + } + + write_vreg(vgpu, offset, p_data, bytes); + return 0; +} + static int fence_mmio_read(struct intel_vgpu *vgpu, unsigned int off, void *p_data, unsigned int bytes) { @@ -1769,7 +1794,9 @@ static int init_generic_mmio_info(struct intel_gvt *gvt) MMIO_RING_DFH(RING_HWSTAM, D_ALL, F_CMD_ACCESS, NULL, NULL); - MMIO_GM_RDR(RENDER_HWS_PGA_GEN7, D_ALL, NULL, NULL); + MMIO_DH(GEN8_GAMW_ECO_DEV_RW_IA, D_BDW_PLUS, NULL, + gamw_echo_dev_rw_ia_write); + MMIO_GM_RDR(BSD_HWS_PGA_GEN7, D_ALL, NULL, NULL); MMIO_GM_RDR(BLT_HWS_PGA_GEN7, D_ALL, NULL, NULL); MMIO_GM_RDR(VEBOX_HWS_PGA_GEN7, D_ALL, NULL, NULL); -- GitLab From 40b271767dcf9748327619ed550be810cc2e10ae Mon Sep 17 00:00:00 2001 From: Changbin Du <changbin.du@intel.com> Date: Tue, 15 May 2018 10:35:36 +0800 Subject: [PATCH 0894/1506] drm/i915/gvt: Detect 64K gtt entry by IPS bit of PDE This change help us detect the real entry type per PSE and IPS setting. For 64K entry, we also need to check reg GEN8_GAMW_ECO_DEV_RW_IA. v2: Extend IPS mmio control to Gen10. (Matthew Auld) Signed-off-by: Changbin Du <changbin.du@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> --- drivers/gpu/drm/i915/gvt/gtt.c | 70 ++++++++++++++++++++++++---------- drivers/gpu/drm/i915/gvt/gtt.h | 2 + 2 files changed, 51 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/gtt.c b/drivers/gpu/drm/i915/gvt/gtt.c index 3e67339145309..3dae75b5b5748 100644 --- a/drivers/gpu/drm/i915/gvt/gtt.c +++ b/drivers/gpu/drm/i915/gvt/gtt.c @@ -384,20 +384,7 @@ static void gen8_gtt_set_pfn(struct intel_gvt_gtt_entry *e, unsigned long pfn) static bool gen8_gtt_test_pse(struct intel_gvt_gtt_entry *e) { - /* Entry doesn't have PSE bit. */ - if (get_pse_type(e->type) == GTT_TYPE_INVALID) - return false; - - e->type = get_entry_type(e->type); - if (!(e->val64 & _PAGE_PSE)) - return false; - - /* We don't support 64K entry yet, will remove this later. */ - if (get_pse_type(e->type) == GTT_TYPE_PPGTT_PTE_64K_ENTRY) - return false; - - e->type = get_pse_type(e->type); - return true; + return !!(e->val64 & _PAGE_PSE); } static bool gen8_gtt_test_ips(struct intel_gvt_gtt_entry *e) @@ -487,6 +474,27 @@ static struct intel_gvt_gtt_gma_ops gen8_gtt_gma_ops = { .gma_to_pml4_index = gen8_gma_to_pml4_index, }; +/* Update entry type per pse and ips bit. */ +static void update_entry_type_for_real(struct intel_gvt_gtt_pte_ops *pte_ops, + struct intel_gvt_gtt_entry *entry, bool ips) +{ + switch (entry->type) { + case GTT_TYPE_PPGTT_PDE_ENTRY: + case GTT_TYPE_PPGTT_PDP_ENTRY: + if (pte_ops->test_pse(entry)) + entry->type = get_pse_type(entry->type); + break; + case GTT_TYPE_PPGTT_PTE_4K_ENTRY: + if (ips) + entry->type = get_pse_type(entry->type); + break; + default: + GEM_BUG_ON(!gtt_type_is_entry(entry->type)); + } + + GEM_BUG_ON(entry->type == GTT_TYPE_INVALID); +} + /* * MM helpers. */ @@ -502,8 +510,7 @@ static void _ppgtt_get_root_entry(struct intel_vgpu_mm *mm, pte_ops->get_entry(guest ? mm->ppgtt_mm.guest_pdps : mm->ppgtt_mm.shadow_pdps, entry, index, false, 0, mm->vgpu); - - pte_ops->test_pse(entry); + update_entry_type_for_real(pte_ops, entry, false); } static inline void ppgtt_get_guest_root_entry(struct intel_vgpu_mm *mm, @@ -608,7 +615,8 @@ static inline int ppgtt_spt_get_entry( if (ret) return ret; - ops->test_pse(e); + update_entry_type_for_real(ops, e, guest ? + spt->guest_page.pde_ips : false); gvt_vdbg_mm("read ppgtt entry, spt type %d, entry type %d, index %lu, value %llx\n", type, e->type, index, e->val64); @@ -752,7 +760,8 @@ static inline struct intel_vgpu_ppgtt_spt *intel_vgpu_find_spt_by_mfn( static int reclaim_one_ppgtt_mm(struct intel_gvt *gvt); static struct intel_vgpu_ppgtt_spt *ppgtt_alloc_spt( - struct intel_vgpu *vgpu, int type, unsigned long gfn) + struct intel_vgpu *vgpu, int type, unsigned long gfn, + bool guest_pde_ips) { struct device *kdev = &vgpu->gvt->dev_priv->drm.pdev->dev; struct intel_vgpu_ppgtt_spt *spt = NULL; @@ -792,6 +801,7 @@ static struct intel_vgpu_ppgtt_spt *ppgtt_alloc_spt( */ spt->guest_page.type = type; spt->guest_page.gfn = gfn; + spt->guest_page.pde_ips = guest_pde_ips; ret = intel_vgpu_register_page_track(vgpu, spt->guest_page.gfn, ppgtt_write_protection_handler, spt); @@ -934,6 +944,22 @@ static int ppgtt_invalidate_spt(struct intel_vgpu_ppgtt_spt *spt) return ret; } +static bool vgpu_ips_enabled(struct intel_vgpu *vgpu) +{ + struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv; + + if (INTEL_GEN(dev_priv) == 9 || INTEL_GEN(dev_priv) == 10) { + u32 ips = vgpu_vreg_t(vgpu, GEN8_GAMW_ECO_DEV_RW_IA) & + GAMW_ECO_ENABLE_64K_IPS_FIELD; + + return ips == GAMW_ECO_ENABLE_64K_IPS_FIELD; + } else if (INTEL_GEN(dev_priv) >= 11) { + /* 64K paging only controlled by IPS bit in PTE now. */ + return true; + } else + return false; +} + static int ppgtt_populate_spt(struct intel_vgpu_ppgtt_spt *spt); static struct intel_vgpu_ppgtt_spt *ppgtt_populate_spt_by_guest_entry( @@ -941,6 +967,7 @@ static struct intel_vgpu_ppgtt_spt *ppgtt_populate_spt_by_guest_entry( { struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops; struct intel_vgpu_ppgtt_spt *spt = NULL; + bool ips = false; int ret; GEM_BUG_ON(!gtt_type_is_pt(get_next_pt_type(we->type))); @@ -951,7 +978,10 @@ static struct intel_vgpu_ppgtt_spt *ppgtt_populate_spt_by_guest_entry( else { int type = get_next_pt_type(we->type); - spt = ppgtt_alloc_spt(vgpu, type, ops->get_pfn(we)); + if (we->type == GTT_TYPE_PPGTT_PDE_ENTRY) + ips = vgpu_ips_enabled(vgpu) && ops->test_ips(we); + + spt = ppgtt_alloc_spt(vgpu, type, ops->get_pfn(we), ips); if (IS_ERR(spt)) { ret = PTR_ERR(spt); goto fail; @@ -1427,8 +1457,6 @@ static int ppgtt_handle_guest_write_page_table_bytes( ppgtt_get_guest_entry(spt, &we, index); - ops->test_pse(&we); - if (bytes == info->gtt_entry_size) { ret = ppgtt_handle_guest_write_page_table(spt, &we, index); if (ret) diff --git a/drivers/gpu/drm/i915/gvt/gtt.h b/drivers/gpu/drm/i915/gvt/gtt.h index 9257b7467b14f..c11284bb291b8 100644 --- a/drivers/gpu/drm/i915/gvt/gtt.h +++ b/drivers/gpu/drm/i915/gvt/gtt.h @@ -223,6 +223,7 @@ struct intel_vgpu_ppgtt_spt { struct { intel_gvt_gtt_type_t type; + bool pde_ips; /* for 64KB PTEs */ void *vaddr; struct page *page; unsigned long mfn; @@ -230,6 +231,7 @@ struct intel_vgpu_ppgtt_spt { struct { intel_gvt_gtt_type_t type; + bool pde_ips; /* for 64KB PTEs */ unsigned long gfn; unsigned long write_cnt; struct intel_vgpu_oos_page *oos_page; -- GitLab From 716348485695de1a91b2f8b398f9c08687f794af Mon Sep 17 00:00:00 2001 From: Changbin Du <changbin.du@intel.com> Date: Tue, 15 May 2018 10:35:37 +0800 Subject: [PATCH 0895/1506] drm/i915/gvt: Add software PTE flag to mark special 64K splited entry This add a software PTE flag on the Ignored bit of PTE. It will be used to identify splited 64K shadow entries. v2: fix mask definition. Signed-off-by: Changbin Du <changbin.du@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> --- drivers/gpu/drm/i915/gvt/gtt.c | 21 +++++++++++++++++++++ drivers/gpu/drm/i915/gvt/gtt.h | 3 +++ 2 files changed, 24 insertions(+) diff --git a/drivers/gpu/drm/i915/gvt/gtt.c b/drivers/gpu/drm/i915/gvt/gtt.c index 3dae75b5b5748..34c401fb37d1c 100644 --- a/drivers/gpu/drm/i915/gvt/gtt.c +++ b/drivers/gpu/drm/i915/gvt/gtt.c @@ -348,6 +348,9 @@ static inline int gtt_set_entry64(void *pt, #define ADDR_64K_MASK GENMASK_ULL(GTT_HAW - 1, 16) #define ADDR_4K_MASK GENMASK_ULL(GTT_HAW - 1, 12) +#define GTT_SPTE_FLAG_MASK GENMASK_ULL(62, 52) +#define GTT_SPTE_FLAG_64K_SPLITED BIT(52) /* splited 64K gtt entry */ + static unsigned long gen8_gtt_get_pfn(struct intel_gvt_gtt_entry *e) { unsigned long pfn; @@ -427,6 +430,21 @@ static void gtt_entry_set_present(struct intel_gvt_gtt_entry *e) e->val64 |= _PAGE_PRESENT; } +static bool gen8_gtt_test_64k_splited(struct intel_gvt_gtt_entry *e) +{ + return !!(e->val64 & GTT_SPTE_FLAG_64K_SPLITED); +} + +static void gen8_gtt_set_64k_splited(struct intel_gvt_gtt_entry *e) +{ + e->val64 |= GTT_SPTE_FLAG_64K_SPLITED; +} + +static void gen8_gtt_clear_64k_splited(struct intel_gvt_gtt_entry *e) +{ + e->val64 &= ~GTT_SPTE_FLAG_64K_SPLITED; +} + /* * Per-platform GMA routines. */ @@ -461,6 +479,9 @@ static struct intel_gvt_gtt_pte_ops gen8_gtt_pte_ops = { .test_pse = gen8_gtt_test_pse, .clear_ips = gen8_gtt_clear_ips, .test_ips = gen8_gtt_test_ips, + .clear_64k_splited = gen8_gtt_clear_64k_splited, + .set_64k_splited = gen8_gtt_set_64k_splited, + .test_64k_splited = gen8_gtt_test_64k_splited, .get_pfn = gen8_gtt_get_pfn, .set_pfn = gen8_gtt_set_pfn, }; diff --git a/drivers/gpu/drm/i915/gvt/gtt.h b/drivers/gpu/drm/i915/gvt/gtt.h index c11284bb291b8..162ef19f4117d 100644 --- a/drivers/gpu/drm/i915/gvt/gtt.h +++ b/drivers/gpu/drm/i915/gvt/gtt.h @@ -65,6 +65,9 @@ struct intel_gvt_gtt_pte_ops { bool (*test_pse)(struct intel_gvt_gtt_entry *e); bool (*test_ips)(struct intel_gvt_gtt_entry *e); void (*clear_ips)(struct intel_gvt_gtt_entry *e); + bool (*test_64k_splited)(struct intel_gvt_gtt_entry *e); + void (*clear_64k_splited)(struct intel_gvt_gtt_entry *e); + void (*set_64k_splited)(struct intel_gvt_gtt_entry *e); void (*set_pfn)(struct intel_gvt_gtt_entry *e, unsigned long pfn); unsigned long (*get_pfn)(struct intel_gvt_gtt_entry *e); }; -- GitLab From c3e697635fcc9173e1d7116d9ebfd2fd0887177d Mon Sep 17 00:00:00 2001 From: Changbin Du <changbin.du@intel.com> Date: Tue, 15 May 2018 10:35:38 +0800 Subject: [PATCH 0896/1506] drm/i915/gvt: Add GTT clear_pse operation Add clear_pse operation in case we need to split huge gtt into small pages. v2: correct description. Signed-off-by: Changbin Du <changbin.du@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> --- drivers/gpu/drm/i915/gvt/gtt.c | 19 +++++++++++++++++++ drivers/gpu/drm/i915/gvt/gtt.h | 1 + 2 files changed, 20 insertions(+) diff --git a/drivers/gpu/drm/i915/gvt/gtt.c b/drivers/gpu/drm/i915/gvt/gtt.c index 34c401fb37d1c..d34dc9ab66e10 100644 --- a/drivers/gpu/drm/i915/gvt/gtt.c +++ b/drivers/gpu/drm/i915/gvt/gtt.c @@ -390,6 +390,24 @@ static bool gen8_gtt_test_pse(struct intel_gvt_gtt_entry *e) return !!(e->val64 & _PAGE_PSE); } +static void gen8_gtt_clear_pse(struct intel_gvt_gtt_entry *e) +{ + if (gen8_gtt_test_pse(e)) { + switch (e->type) { + case GTT_TYPE_PPGTT_PTE_2M_ENTRY: + e->val64 &= ~_PAGE_PSE; + e->type = GTT_TYPE_PPGTT_PDE_ENTRY; + break; + case GTT_TYPE_PPGTT_PTE_1G_ENTRY: + e->type = GTT_TYPE_PPGTT_PDP_ENTRY; + e->val64 &= ~_PAGE_PSE; + break; + default: + WARN_ON(1); + } + } +} + static bool gen8_gtt_test_ips(struct intel_gvt_gtt_entry *e) { if (GEM_WARN_ON(e->type != GTT_TYPE_PPGTT_PDE_ENTRY)) @@ -477,6 +495,7 @@ static struct intel_gvt_gtt_pte_ops gen8_gtt_pte_ops = { .set_present = gtt_entry_set_present, .test_present = gen8_gtt_test_present, .test_pse = gen8_gtt_test_pse, + .clear_pse = gen8_gtt_clear_pse, .clear_ips = gen8_gtt_clear_ips, .test_ips = gen8_gtt_test_ips, .clear_64k_splited = gen8_gtt_clear_64k_splited, diff --git a/drivers/gpu/drm/i915/gvt/gtt.h b/drivers/gpu/drm/i915/gvt/gtt.h index 162ef19f4117d..b7bf68cc84180 100644 --- a/drivers/gpu/drm/i915/gvt/gtt.h +++ b/drivers/gpu/drm/i915/gvt/gtt.h @@ -63,6 +63,7 @@ struct intel_gvt_gtt_pte_ops { void (*clear_present)(struct intel_gvt_gtt_entry *e); void (*set_present)(struct intel_gvt_gtt_entry *e); bool (*test_pse)(struct intel_gvt_gtt_entry *e); + void (*clear_pse)(struct intel_gvt_gtt_entry *e); bool (*test_ips)(struct intel_gvt_gtt_entry *e); void (*clear_ips)(struct intel_gvt_gtt_entry *e); bool (*test_64k_splited)(struct intel_gvt_gtt_entry *e); -- GitLab From 155521c93e468211673206e1871b53d26a44a82d Mon Sep 17 00:00:00 2001 From: Changbin Du <changbin.du@intel.com> Date: Tue, 15 May 2018 10:35:39 +0800 Subject: [PATCH 0897/1506] drm/i915/gvt: Split ppgtt_alloc_spt into two parts We need a interface to allocate a pure shadow page which doesn't have a guest page associated with. Such shadow page is used to shadow 2M huge gtt entry. Signed-off-by: Changbin Du <changbin.du@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> --- drivers/gpu/drm/i915/gvt/gtt.c | 62 ++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/gtt.c b/drivers/gpu/drm/i915/gvt/gtt.c index d34dc9ab66e10..15f6908fc648f 100644 --- a/drivers/gpu/drm/i915/gvt/gtt.c +++ b/drivers/gpu/drm/i915/gvt/gtt.c @@ -735,10 +735,12 @@ static void ppgtt_free_spt(struct intel_vgpu_ppgtt_spt *spt) radix_tree_delete(&spt->vgpu->gtt.spt_tree, spt->shadow_page.mfn); - if (spt->guest_page.oos_page) - detach_oos_page(spt->vgpu, spt->guest_page.oos_page); + if (spt->guest_page.gfn) { + if (spt->guest_page.oos_page) + detach_oos_page(spt->vgpu, spt->guest_page.oos_page); - intel_vgpu_unregister_page_track(spt->vgpu, spt->guest_page.gfn); + intel_vgpu_unregister_page_track(spt->vgpu, spt->guest_page.gfn); + } list_del_init(&spt->post_shadow_list); free_spt(spt); @@ -799,9 +801,9 @@ static inline struct intel_vgpu_ppgtt_spt *intel_vgpu_find_spt_by_mfn( static int reclaim_one_ppgtt_mm(struct intel_gvt *gvt); +/* Allocate shadow page table without guest page. */ static struct intel_vgpu_ppgtt_spt *ppgtt_alloc_spt( - struct intel_vgpu *vgpu, int type, unsigned long gfn, - bool guest_pde_ips) + struct intel_vgpu *vgpu, intel_gvt_gtt_type_t type) { struct device *kdev = &vgpu->gvt->dev_priv->drm.pdev->dev; struct intel_vgpu_ppgtt_spt *spt = NULL; @@ -836,27 +838,12 @@ static struct intel_vgpu_ppgtt_spt *ppgtt_alloc_spt( spt->shadow_page.vaddr = page_address(spt->shadow_page.page); spt->shadow_page.mfn = daddr >> I915_GTT_PAGE_SHIFT; - /* - * Init guest_page. - */ - spt->guest_page.type = type; - spt->guest_page.gfn = gfn; - spt->guest_page.pde_ips = guest_pde_ips; - - ret = intel_vgpu_register_page_track(vgpu, spt->guest_page.gfn, - ppgtt_write_protection_handler, spt); - if (ret) - goto err_unmap_dma; - ret = radix_tree_insert(&vgpu->gtt.spt_tree, spt->shadow_page.mfn, spt); if (ret) - goto err_unreg_page_track; + goto err_unmap_dma; - trace_spt_alloc(vgpu->id, spt, type, spt->shadow_page.mfn, gfn); return spt; -err_unreg_page_track: - intel_vgpu_unregister_page_track(vgpu, spt->guest_page.gfn); err_unmap_dma: dma_unmap_page(kdev, daddr, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); err_free_spt: @@ -864,6 +851,37 @@ static struct intel_vgpu_ppgtt_spt *ppgtt_alloc_spt( return ERR_PTR(ret); } +/* Allocate shadow page table associated with specific gfn. */ +static struct intel_vgpu_ppgtt_spt *ppgtt_alloc_spt_gfn( + struct intel_vgpu *vgpu, intel_gvt_gtt_type_t type, + unsigned long gfn, bool guest_pde_ips) +{ + struct intel_vgpu_ppgtt_spt *spt; + int ret; + + spt = ppgtt_alloc_spt(vgpu, type); + if (IS_ERR(spt)) + return spt; + + /* + * Init guest_page. + */ + ret = intel_vgpu_register_page_track(vgpu, gfn, + ppgtt_write_protection_handler, spt); + if (ret) { + ppgtt_free_spt(spt); + return ERR_PTR(ret); + } + + spt->guest_page.type = type; + spt->guest_page.gfn = gfn; + spt->guest_page.pde_ips = guest_pde_ips; + + trace_spt_alloc(vgpu->id, spt, type, spt->shadow_page.mfn, gfn); + + return spt; +} + #define pt_entry_size_shift(spt) \ ((spt)->vgpu->gvt->device_info.gtt_entry_size_shift) @@ -1021,7 +1039,7 @@ static struct intel_vgpu_ppgtt_spt *ppgtt_populate_spt_by_guest_entry( if (we->type == GTT_TYPE_PPGTT_PDE_ENTRY) ips = vgpu_ips_enabled(vgpu) && ops->test_ips(we); - spt = ppgtt_alloc_spt(vgpu, type, ops->get_pfn(we), ips); + spt = ppgtt_alloc_spt_gfn(vgpu, type, ops->get_pfn(we), ips); if (IS_ERR(spt)) { ret = PTR_ERR(spt); goto fail; -- GitLab From 4c9414d7b152bf344521bf786b5748e833270776 Mon Sep 17 00:00:00 2001 From: Changbin Du <changbin.du@intel.com> Date: Tue, 15 May 2018 10:35:40 +0800 Subject: [PATCH 0898/1506] drm/i915/gvt: Make PTE iterator 64K entry aware 64K PTE is special, only PTE#0, PTE#16, PTE#32, ... PTE#496 are used in the page table. Signed-off-by: Changbin Du <changbin.du@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> --- drivers/gpu/drm/i915/gvt/gtt.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/gtt.c b/drivers/gpu/drm/i915/gvt/gtt.c index 15f6908fc648f..7fc277cceb23f 100644 --- a/drivers/gpu/drm/i915/gvt/gtt.c +++ b/drivers/gpu/drm/i915/gvt/gtt.c @@ -351,6 +351,8 @@ static inline int gtt_set_entry64(void *pt, #define GTT_SPTE_FLAG_MASK GENMASK_ULL(62, 52) #define GTT_SPTE_FLAG_64K_SPLITED BIT(52) /* splited 64K gtt entry */ +#define GTT_64K_PTE_STRIDE 16 + static unsigned long gen8_gtt_get_pfn(struct intel_gvt_gtt_entry *e) { unsigned long pfn; @@ -889,12 +891,14 @@ static struct intel_vgpu_ppgtt_spt *ppgtt_alloc_spt_gfn( (I915_GTT_PAGE_SIZE >> pt_entry_size_shift(spt)) #define for_each_present_guest_entry(spt, e, i) \ - for (i = 0; i < pt_entries(spt); i++) \ + for (i = 0; i < pt_entries(spt); \ + i += spt->guest_page.pde_ips ? GTT_64K_PTE_STRIDE : 1) \ if (!ppgtt_get_guest_entry(spt, e, i) && \ spt->vgpu->gvt->gtt.pte_ops->test_present(e)) #define for_each_present_shadow_entry(spt, e, i) \ - for (i = 0; i < pt_entries(spt); i++) \ + for (i = 0; i < pt_entries(spt); \ + i += spt->shadow_page.pde_ips ? GTT_64K_PTE_STRIDE : 1) \ if (!ppgtt_get_shadow_entry(spt, e, i) && \ spt->vgpu->gvt->gtt.pte_ops->test_present(e)) -- GitLab From eb3a353014d2c2402e572ab7bef86bf5e328160f Mon Sep 17 00:00:00 2001 From: Changbin Du <changbin.du@intel.com> Date: Tue, 15 May 2018 10:35:41 +0800 Subject: [PATCH 0899/1506] drm/i915/gvt: Add 64K huge gtt support Finally, this add the first huge gtt support for GVTg - 64K pages. Since 64K page and 4K page cannot be mixed on the same page table, so we always split a 64K entry into small 4K page. And when unshadow guest 64K entry, we need ensure all the shadowed entries in shadow page table also get cleared. For page table which has 64K gtt entry, only PTE#0, PTE#16, PTE#32, ... PTE#496 are used. Unused PTEs update should be ignored. Signed-off-by: Changbin Du <changbin.du@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> --- drivers/gpu/drm/i915/gvt/gtt.c | 86 +++++++++++++++++++++++++++++++--- 1 file changed, 80 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/gtt.c b/drivers/gpu/drm/i915/gvt/gtt.c index 7fc277cceb23f..54c221dedfe8c 100644 --- a/drivers/gpu/drm/i915/gvt/gtt.c +++ b/drivers/gpu/drm/i915/gvt/gtt.c @@ -978,9 +978,12 @@ static int ppgtt_invalidate_spt(struct intel_vgpu_ppgtt_spt *spt) ppgtt_invalidate_pte(spt, &e); break; case GTT_TYPE_PPGTT_PTE_64K_ENTRY: + /* We don't setup 64K shadow entry so far. */ + WARN(1, "suspicious 64K gtt entry\n"); + continue; case GTT_TYPE_PPGTT_PTE_2M_ENTRY: case GTT_TYPE_PPGTT_PTE_1G_ENTRY: - WARN(1, "GVT doesn't support 64K/2M/1GB page\n"); + WARN(1, "GVT doesn't support 2M/1GB page\n"); continue; case GTT_TYPE_PPGTT_PML4_ENTRY: case GTT_TYPE_PPGTT_PDP_ENTRY: @@ -1075,9 +1078,44 @@ static inline void ppgtt_generate_shadow_entry(struct intel_gvt_gtt_entry *se, se->type = ge->type; se->val64 = ge->val64; + /* Because we always split 64KB pages, so clear IPS in shadow PDE. */ + if (se->type == GTT_TYPE_PPGTT_PDE_ENTRY) + ops->clear_ips(se); + ops->set_pfn(se, s->shadow_page.mfn); } +static int split_64KB_gtt_entry(struct intel_vgpu *vgpu, + struct intel_vgpu_ppgtt_spt *spt, unsigned long index, + struct intel_gvt_gtt_entry *se) +{ + struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops; + struct intel_gvt_gtt_entry entry = *se; + unsigned long start_gfn; + dma_addr_t dma_addr; + int i, ret; + + gvt_vdbg_mm("Split 64K gtt entry, index %lu\n", index); + + GEM_BUG_ON(index % GTT_64K_PTE_STRIDE); + + start_gfn = ops->get_pfn(se); + + entry.type = GTT_TYPE_PPGTT_PTE_4K_ENTRY; + ops->set_64k_splited(&entry); + + for (i = 0; i < GTT_64K_PTE_STRIDE; i++) { + ret = intel_gvt_hypervisor_dma_map_guest_page(vgpu, + start_gfn + i, &dma_addr); + if (ret) + return ret; + + ops->set_pfn(&entry, dma_addr >> PAGE_SHIFT); + ppgtt_set_shadow_entry(spt, &entry, index + i); + } + return 0; +} + static int ppgtt_populate_shadow_entry(struct intel_vgpu *vgpu, struct intel_vgpu_ppgtt_spt *spt, unsigned long index, struct intel_gvt_gtt_entry *ge) @@ -1098,9 +1136,16 @@ static int ppgtt_populate_shadow_entry(struct intel_vgpu *vgpu, gvt_vdbg_mm("shadow 4K gtt entry\n"); break; case GTT_TYPE_PPGTT_PTE_64K_ENTRY: + gvt_vdbg_mm("shadow 64K gtt entry\n"); + /* + * The layout of 64K page is special, the page size is + * controlled by uper PDE. To be simple, we always split + * 64K page to smaller 4K pages in shadow PT. + */ + return split_64KB_gtt_entry(vgpu, spt, index, &se); case GTT_TYPE_PPGTT_PTE_2M_ENTRY: case GTT_TYPE_PPGTT_PTE_1G_ENTRY: - gvt_vgpu_err("GVT doesn't support 64K/2M/1GB entry\n"); + gvt_vgpu_err("GVT doesn't support 2M/1GB entry\n"); return -EINVAL; default: GEM_BUG_ON(1); @@ -1190,8 +1235,12 @@ static int ppgtt_handle_guest_entry_removal(struct intel_vgpu_ppgtt_spt *spt, ret = ppgtt_invalidate_spt(s); if (ret) goto fail; - } else + } else { + /* We don't setup 64K shadow entry so far. */ + WARN(se->type == GTT_TYPE_PPGTT_PTE_64K_ENTRY, + "suspicious 64K entry\n"); ppgtt_invalidate_pte(spt, se); + } return 0; fail: @@ -1414,7 +1463,7 @@ static int ppgtt_handle_guest_write_page_table( struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops; struct intel_gvt_gtt_entry old_se; int new_present; - int ret; + int i, ret; new_present = ops->test_present(we); @@ -1436,8 +1485,21 @@ static int ppgtt_handle_guest_write_page_table( goto fail; if (!new_present) { - ops->set_pfn(&old_se, vgpu->gtt.scratch_pt[type].page_mfn); - ppgtt_set_shadow_entry(spt, &old_se, index); + /* For 64KB splited entries, we need clear them all. */ + if (ops->test_64k_splited(&old_se) && + !(index % GTT_64K_PTE_STRIDE)) { + gvt_vdbg_mm("remove splited 64K shadow entries\n"); + for (i = 0; i < GTT_64K_PTE_STRIDE; i++) { + ops->clear_64k_splited(&old_se); + ops->set_pfn(&old_se, + vgpu->gtt.scratch_pt[type].page_mfn); + ppgtt_set_shadow_entry(spt, &old_se, index + i); + } + } else { + ops->set_pfn(&old_se, + vgpu->gtt.scratch_pt[type].page_mfn); + ppgtt_set_shadow_entry(spt, &old_se, index); + } } return 0; @@ -1519,6 +1581,18 @@ static int ppgtt_handle_guest_write_page_table_bytes( ppgtt_get_guest_entry(spt, &we, index); + /* + * For page table which has 64K gtt entry, only PTE#0, PTE#16, + * PTE#32, ... PTE#496 are used. Unused PTEs update should be + * ignored. + */ + if (we.type == GTT_TYPE_PPGTT_PTE_64K_ENTRY && + (index % GTT_64K_PTE_STRIDE)) { + gvt_vdbg_mm("Ignore write to unused PTE entry, index %lu\n", + index); + return 0; + } + if (bytes == info->gtt_entry_size) { ret = ppgtt_handle_guest_write_page_table(spt, &we, index); if (ret) -- GitLab From 79e542f5af79918e5e766c441561fb9bff8af3aa Mon Sep 17 00:00:00 2001 From: Changbin Du <changbin.du@intel.com> Date: Tue, 15 May 2018 10:35:42 +0800 Subject: [PATCH 0900/1506] drm/i915/kvmgt: Support setting dma map for huge pages To support huge gtt, we need to support huge pages in kvmgt first. This patch adds a 'size' param to the intel_gvt_mpt::dma_map_guest_page API and implements it in kvmgt. v2: rebase. Signed-off-by: Changbin Du <changbin.du@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> --- drivers/gpu/drm/i915/gvt/gtt.c | 6 +- drivers/gpu/drm/i915/gvt/hypercall.h | 2 +- drivers/gpu/drm/i915/gvt/kvmgt.c | 126 ++++++++++++++++++++------- drivers/gpu/drm/i915/gvt/mpt.h | 7 +- 4 files changed, 102 insertions(+), 39 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/gtt.c b/drivers/gpu/drm/i915/gvt/gtt.c index 54c221dedfe8c..e26c01da2bd69 100644 --- a/drivers/gpu/drm/i915/gvt/gtt.c +++ b/drivers/gpu/drm/i915/gvt/gtt.c @@ -1106,7 +1106,7 @@ static int split_64KB_gtt_entry(struct intel_vgpu *vgpu, for (i = 0; i < GTT_64K_PTE_STRIDE; i++) { ret = intel_gvt_hypervisor_dma_map_guest_page(vgpu, - start_gfn + i, &dma_addr); + start_gfn + i, PAGE_SIZE, &dma_addr); if (ret) return ret; @@ -1152,7 +1152,7 @@ static int ppgtt_populate_shadow_entry(struct intel_vgpu *vgpu, }; /* direct shadow */ - ret = intel_gvt_hypervisor_dma_map_guest_page(vgpu, gfn, &dma_addr); + ret = intel_gvt_hypervisor_dma_map_guest_page(vgpu, gfn, PAGE_SIZE, &dma_addr); if (ret) return -ENXIO; @@ -2080,7 +2080,7 @@ static int emulate_ggtt_mmio_write(struct intel_vgpu *vgpu, unsigned int off, } ret = intel_gvt_hypervisor_dma_map_guest_page(vgpu, gfn, - &dma_addr); + PAGE_SIZE, &dma_addr); if (ret) { gvt_vgpu_err("fail to populate guest ggtt entry\n"); /* guest driver may read/write the entry when partial diff --git a/drivers/gpu/drm/i915/gvt/hypercall.h b/drivers/gpu/drm/i915/gvt/hypercall.h index f6dd9f7178883..5af11cf1b4823 100644 --- a/drivers/gpu/drm/i915/gvt/hypercall.h +++ b/drivers/gpu/drm/i915/gvt/hypercall.h @@ -53,7 +53,7 @@ struct intel_gvt_mpt { unsigned long (*gfn_to_mfn)(unsigned long handle, unsigned long gfn); int (*dma_map_guest_page)(unsigned long handle, unsigned long gfn, - dma_addr_t *dma_addr); + unsigned long size, dma_addr_t *dma_addr); void (*dma_unmap_guest_page)(unsigned long handle, dma_addr_t dma_addr); int (*map_gfn_to_mfn)(unsigned long handle, unsigned long gfn, diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c index 1466d8769ec9f..685cb3de6daba 100644 --- a/drivers/gpu/drm/i915/gvt/kvmgt.c +++ b/drivers/gpu/drm/i915/gvt/kvmgt.c @@ -94,6 +94,7 @@ struct gvt_dma { struct rb_node dma_addr_node; gfn_t gfn; dma_addr_t dma_addr; + unsigned long size; struct kref ref; }; @@ -106,45 +107,103 @@ static int kvmgt_guest_init(struct mdev_device *mdev); static void intel_vgpu_release_work(struct work_struct *work); static bool kvmgt_guest_exit(struct kvmgt_guest_info *info); +static void gvt_unpin_guest_page(struct intel_vgpu *vgpu, unsigned long gfn, + unsigned long size) +{ + int total_pages; + int npage; + int ret; + + total_pages = roundup(size, PAGE_SIZE) / PAGE_SIZE; + + for (npage = 0; npage < total_pages; npage++) { + unsigned long cur_gfn = gfn + npage; + + ret = vfio_unpin_pages(mdev_dev(vgpu->vdev.mdev), &cur_gfn, 1); + WARN_ON(ret != 1); + } +} + +/* Pin a normal or compound guest page for dma. */ +static int gvt_pin_guest_page(struct intel_vgpu *vgpu, unsigned long gfn, + unsigned long size, struct page **page) +{ + unsigned long base_pfn = 0; + int total_pages; + int npage; + int ret; + + total_pages = roundup(size, PAGE_SIZE) / PAGE_SIZE; + /* + * We pin the pages one-by-one to avoid allocating a big arrary + * on stack to hold pfns. + */ + for (npage = 0; npage < total_pages; npage++) { + unsigned long cur_gfn = gfn + npage; + unsigned long pfn; + + ret = vfio_pin_pages(mdev_dev(vgpu->vdev.mdev), &cur_gfn, 1, + IOMMU_READ | IOMMU_WRITE, &pfn); + if (ret != 1) { + gvt_vgpu_err("vfio_pin_pages failed for gfn 0x%lx, ret %d\n", + cur_gfn, ret); + goto err; + } + + if (!pfn_valid(pfn)) { + gvt_vgpu_err("pfn 0x%lx is not mem backed\n", pfn); + npage++; + ret = -EFAULT; + goto err; + } + + if (npage == 0) + base_pfn = pfn; + else if (base_pfn + npage != pfn) { + gvt_vgpu_err("The pages are not continuous\n"); + ret = -EINVAL; + npage++; + goto err; + } + } + + *page = pfn_to_page(base_pfn); + return 0; +err: + gvt_unpin_guest_page(vgpu, gfn, npage * PAGE_SIZE); + return ret; +} + static int gvt_dma_map_page(struct intel_vgpu *vgpu, unsigned long gfn, - dma_addr_t *dma_addr) + dma_addr_t *dma_addr, unsigned long size) { struct device *dev = &vgpu->gvt->dev_priv->drm.pdev->dev; - struct page *page; - unsigned long pfn; + struct page *page = NULL; int ret; - /* Pin the page first. */ - ret = vfio_pin_pages(mdev_dev(vgpu->vdev.mdev), &gfn, 1, - IOMMU_READ | IOMMU_WRITE, &pfn); - if (ret != 1) { - gvt_vgpu_err("vfio_pin_pages failed for gfn 0x%lx: %d\n", - gfn, ret); - return -EINVAL; - } + ret = gvt_pin_guest_page(vgpu, gfn, size, &page); + if (ret) + return ret; /* Setup DMA mapping. */ - page = pfn_to_page(pfn); - *dma_addr = dma_map_page(dev, page, 0, PAGE_SIZE, - PCI_DMA_BIDIRECTIONAL); - if (dma_mapping_error(dev, *dma_addr)) { - gvt_vgpu_err("DMA mapping failed for gfn 0x%lx\n", gfn); - vfio_unpin_pages(mdev_dev(vgpu->vdev.mdev), &gfn, 1); - return -ENOMEM; + *dma_addr = dma_map_page(dev, page, 0, size, PCI_DMA_BIDIRECTIONAL); + ret = dma_mapping_error(dev, *dma_addr); + if (ret) { + gvt_vgpu_err("DMA mapping failed for pfn 0x%lx, ret %d\n", + page_to_pfn(page), ret); + gvt_unpin_guest_page(vgpu, gfn, size); } - return 0; + return ret; } static void gvt_dma_unmap_page(struct intel_vgpu *vgpu, unsigned long gfn, - dma_addr_t dma_addr) + dma_addr_t dma_addr, unsigned long size) { struct device *dev = &vgpu->gvt->dev_priv->drm.pdev->dev; - int ret; - dma_unmap_page(dev, dma_addr, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); - ret = vfio_unpin_pages(mdev_dev(vgpu->vdev.mdev), &gfn, 1); - WARN_ON(ret != 1); + dma_unmap_page(dev, dma_addr, size, PCI_DMA_BIDIRECTIONAL); + gvt_unpin_guest_page(vgpu, gfn, size); } static struct gvt_dma *__gvt_cache_find_dma_addr(struct intel_vgpu *vgpu, @@ -185,7 +244,7 @@ static struct gvt_dma *__gvt_cache_find_gfn(struct intel_vgpu *vgpu, gfn_t gfn) } static int __gvt_cache_add(struct intel_vgpu *vgpu, gfn_t gfn, - dma_addr_t dma_addr) + dma_addr_t dma_addr, unsigned long size) { struct gvt_dma *new, *itr; struct rb_node **link, *parent = NULL; @@ -197,6 +256,7 @@ static int __gvt_cache_add(struct intel_vgpu *vgpu, gfn_t gfn, new->vgpu = vgpu; new->gfn = gfn; new->dma_addr = dma_addr; + new->size = size; kref_init(&new->ref); /* gfn_cache maps gfn to struct gvt_dma. */ @@ -254,7 +314,7 @@ static void gvt_cache_destroy(struct intel_vgpu *vgpu) break; } dma = rb_entry(node, struct gvt_dma, gfn_node); - gvt_dma_unmap_page(vgpu, dma->gfn, dma->dma_addr); + gvt_dma_unmap_page(vgpu, dma->gfn, dma->dma_addr, dma->size); __gvt_cache_remove_entry(vgpu, dma); mutex_unlock(&vgpu->vdev.cache_lock); } @@ -509,7 +569,8 @@ static int intel_vgpu_iommu_notifier(struct notifier_block *nb, if (!entry) continue; - gvt_dma_unmap_page(vgpu, entry->gfn, entry->dma_addr); + gvt_dma_unmap_page(vgpu, entry->gfn, entry->dma_addr, + entry->size); __gvt_cache_remove_entry(vgpu, entry); } mutex_unlock(&vgpu->vdev.cache_lock); @@ -1616,7 +1677,7 @@ static unsigned long kvmgt_gfn_to_pfn(unsigned long handle, unsigned long gfn) } int kvmgt_dma_map_guest_page(unsigned long handle, unsigned long gfn, - dma_addr_t *dma_addr) + unsigned long size, dma_addr_t *dma_addr) { struct kvmgt_guest_info *info; struct intel_vgpu *vgpu; @@ -1633,11 +1694,11 @@ int kvmgt_dma_map_guest_page(unsigned long handle, unsigned long gfn, entry = __gvt_cache_find_gfn(info->vgpu, gfn); if (!entry) { - ret = gvt_dma_map_page(vgpu, gfn, dma_addr); + ret = gvt_dma_map_page(vgpu, gfn, dma_addr, size); if (ret) goto err_unlock; - ret = __gvt_cache_add(info->vgpu, gfn, *dma_addr); + ret = __gvt_cache_add(info->vgpu, gfn, *dma_addr, size); if (ret) goto err_unmap; } else { @@ -1649,7 +1710,7 @@ int kvmgt_dma_map_guest_page(unsigned long handle, unsigned long gfn, return 0; err_unmap: - gvt_dma_unmap_page(vgpu, gfn, *dma_addr); + gvt_dma_unmap_page(vgpu, gfn, *dma_addr, size); err_unlock: mutex_unlock(&info->vgpu->vdev.cache_lock); return ret; @@ -1659,7 +1720,8 @@ static void __gvt_dma_release(struct kref *ref) { struct gvt_dma *entry = container_of(ref, typeof(*entry), ref); - gvt_dma_unmap_page(entry->vgpu, entry->gfn, entry->dma_addr); + gvt_dma_unmap_page(entry->vgpu, entry->gfn, entry->dma_addr, + entry->size); __gvt_cache_remove_entry(entry->vgpu, entry); } diff --git a/drivers/gpu/drm/i915/gvt/mpt.h b/drivers/gpu/drm/i915/gvt/mpt.h index 32ffcd566cddf..67f19992b226f 100644 --- a/drivers/gpu/drm/i915/gvt/mpt.h +++ b/drivers/gpu/drm/i915/gvt/mpt.h @@ -230,17 +230,18 @@ static inline unsigned long intel_gvt_hypervisor_gfn_to_mfn( /** * intel_gvt_hypervisor_dma_map_guest_page - setup dma map for guest page * @vgpu: a vGPU - * @gpfn: guest pfn + * @gfn: guest pfn + * @size: page size * @dma_addr: retrieve allocated dma addr * * Returns: * 0 on success, negative error code if failed. */ static inline int intel_gvt_hypervisor_dma_map_guest_page( - struct intel_vgpu *vgpu, unsigned long gfn, + struct intel_vgpu *vgpu, unsigned long gfn, unsigned long size, dma_addr_t *dma_addr) { - return intel_gvt_host.mpt->dma_map_guest_page(vgpu->handle, gfn, + return intel_gvt_host.mpt->dma_map_guest_page(vgpu->handle, gfn, size, dma_addr); } -- GitLab From b901b252b6cf5cecc612059ccf05d974a9085c58 Mon Sep 17 00:00:00 2001 From: Changbin Du <changbin.du@intel.com> Date: Tue, 15 May 2018 10:35:43 +0800 Subject: [PATCH 0901/1506] drm/i915/gvt: Add 2M huge gtt support This add 2M huge gtt support for GVTg. Unlike 64K gtt entry, we can shadow 2M guest entry with real huge gtt. But before that, we have to check memory physical continuous, alignment and if it is supported on the host. We can get all supported page sizes from intel_device_info.page_sizes. Finally we must split the 2M page into smaller pages if we cannot satisfy guest Huge Page. Signed-off-by: Changbin Du <changbin.du@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> --- drivers/gpu/drm/i915/gvt/gtt.c | 100 +++++++++++++++++++++++++++++++-- 1 file changed, 95 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/gtt.c b/drivers/gpu/drm/i915/gvt/gtt.c index e26c01da2bd69..5a66d0f3365cd 100644 --- a/drivers/gpu/drm/i915/gvt/gtt.c +++ b/drivers/gpu/drm/i915/gvt/gtt.c @@ -902,6 +902,11 @@ static struct intel_vgpu_ppgtt_spt *ppgtt_alloc_spt_gfn( if (!ppgtt_get_shadow_entry(spt, e, i) && \ spt->vgpu->gvt->gtt.pte_ops->test_present(e)) +#define for_each_shadow_entry(spt, e, i) \ + for (i = 0; i < pt_entries(spt); \ + i += (spt->shadow_page.pde_ips ? GTT_64K_PTE_STRIDE : 1)) \ + if (!ppgtt_get_shadow_entry(spt, e, i)) + static void ppgtt_get_spt(struct intel_vgpu_ppgtt_spt *spt) { int v = atomic_read(&spt->refcount); @@ -949,7 +954,8 @@ static inline void ppgtt_invalidate_pte(struct intel_vgpu_ppgtt_spt *spt, pfn = ops->get_pfn(entry); type = spt->shadow_page.type; - if (pfn == vgpu->gtt.scratch_pt[type].page_mfn) + /* Uninitialized spte or unshadowed spte. */ + if (!pfn || pfn == vgpu->gtt.scratch_pt[type].page_mfn) return; intel_gvt_hypervisor_dma_unmap_guest_page(vgpu, pfn << PAGE_SHIFT); @@ -982,8 +988,10 @@ static int ppgtt_invalidate_spt(struct intel_vgpu_ppgtt_spt *spt) WARN(1, "suspicious 64K gtt entry\n"); continue; case GTT_TYPE_PPGTT_PTE_2M_ENTRY: + gvt_vdbg_mm("invalidate 2M entry\n"); + continue; case GTT_TYPE_PPGTT_PTE_1G_ENTRY: - WARN(1, "GVT doesn't support 2M/1GB page\n"); + WARN(1, "GVT doesn't support 1GB page\n"); continue; case GTT_TYPE_PPGTT_PML4_ENTRY: case GTT_TYPE_PPGTT_PDP_ENTRY: @@ -1085,6 +1093,73 @@ static inline void ppgtt_generate_shadow_entry(struct intel_gvt_gtt_entry *se, ops->set_pfn(se, s->shadow_page.mfn); } +/** + * Return 1 if 2MB huge gtt shadowing is possilbe, 0 if miscondition, + * negtive if found err. + */ +static int is_2MB_gtt_possible(struct intel_vgpu *vgpu, + struct intel_gvt_gtt_entry *entry) +{ + struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops; + unsigned long pfn; + + if (!HAS_PAGE_SIZES(vgpu->gvt->dev_priv, I915_GTT_PAGE_SIZE_2M)) + return 0; + + pfn = intel_gvt_hypervisor_gfn_to_mfn(vgpu, ops->get_pfn(entry)); + if (pfn == INTEL_GVT_INVALID_ADDR) + return -EINVAL; + + return PageTransHuge(pfn_to_page(pfn)); +} + +static int split_2MB_gtt_entry(struct intel_vgpu *vgpu, + struct intel_vgpu_ppgtt_spt *spt, unsigned long index, + struct intel_gvt_gtt_entry *se) +{ + struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops; + struct intel_vgpu_ppgtt_spt *sub_spt; + struct intel_gvt_gtt_entry sub_se; + unsigned long start_gfn; + dma_addr_t dma_addr; + unsigned long sub_index; + int ret; + + gvt_dbg_mm("Split 2M gtt entry, index %lu\n", index); + + start_gfn = ops->get_pfn(se); + + sub_spt = ppgtt_alloc_spt(vgpu, GTT_TYPE_PPGTT_PTE_PT); + if (IS_ERR(sub_spt)) + return PTR_ERR(sub_spt); + + for_each_shadow_entry(sub_spt, &sub_se, sub_index) { + ret = intel_gvt_hypervisor_dma_map_guest_page(vgpu, + start_gfn + sub_index, PAGE_SIZE, &dma_addr); + if (ret) { + ppgtt_invalidate_spt(spt); + return ret; + } + sub_se.val64 = se->val64; + + /* Copy the PAT field from PDE. */ + sub_se.val64 &= ~_PAGE_PAT; + sub_se.val64 |= (se->val64 & _PAGE_PAT_LARGE) >> 5; + + ops->set_pfn(&sub_se, dma_addr >> PAGE_SHIFT); + ppgtt_set_shadow_entry(sub_spt, &sub_se, sub_index); + } + + /* Clear dirty field. */ + se->val64 &= ~_PAGE_DIRTY; + + ops->clear_pse(se); + ops->clear_ips(se); + ops->set_pfn(se, sub_spt->shadow_page.mfn); + ppgtt_set_shadow_entry(spt, se, index); + return 0; +} + static int split_64KB_gtt_entry(struct intel_vgpu *vgpu, struct intel_vgpu_ppgtt_spt *spt, unsigned long index, struct intel_gvt_gtt_entry *se) @@ -1122,7 +1197,7 @@ static int ppgtt_populate_shadow_entry(struct intel_vgpu *vgpu, { struct intel_gvt_gtt_pte_ops *pte_ops = vgpu->gvt->gtt.pte_ops; struct intel_gvt_gtt_entry se = *ge; - unsigned long gfn; + unsigned long gfn, page_size = PAGE_SIZE; dma_addr_t dma_addr; int ret; @@ -1144,15 +1219,24 @@ static int ppgtt_populate_shadow_entry(struct intel_vgpu *vgpu, */ return split_64KB_gtt_entry(vgpu, spt, index, &se); case GTT_TYPE_PPGTT_PTE_2M_ENTRY: + gvt_vdbg_mm("shadow 2M gtt entry\n"); + ret = is_2MB_gtt_possible(vgpu, ge); + if (ret == 0) + return split_2MB_gtt_entry(vgpu, spt, index, &se); + else if (ret < 0) + return ret; + page_size = I915_GTT_PAGE_SIZE_2M; + break; case GTT_TYPE_PPGTT_PTE_1G_ENTRY: - gvt_vgpu_err("GVT doesn't support 2M/1GB entry\n"); + gvt_vgpu_err("GVT doesn't support 1GB entry\n"); return -EINVAL; default: GEM_BUG_ON(1); }; /* direct shadow */ - ret = intel_gvt_hypervisor_dma_map_guest_page(vgpu, gfn, PAGE_SIZE, &dma_addr); + ret = intel_gvt_hypervisor_dma_map_guest_page(vgpu, gfn, page_size, + &dma_addr); if (ret) return -ENXIO; @@ -1495,6 +1579,12 @@ static int ppgtt_handle_guest_write_page_table( vgpu->gtt.scratch_pt[type].page_mfn); ppgtt_set_shadow_entry(spt, &old_se, index + i); } + } else if (old_se.type == GTT_TYPE_PPGTT_PTE_2M_ENTRY || + old_se.type == GTT_TYPE_PPGTT_PTE_1G_ENTRY) { + ops->clear_pse(&old_se); + ops->set_pfn(&old_se, + vgpu->gtt.scratch_pt[type].page_mfn); + ppgtt_set_shadow_entry(spt, &old_se, index); } else { ops->set_pfn(&old_se, vgpu->gtt.scratch_pt[type].page_mfn); -- GitLab From 54c81653bd67ce2a11fa08295d9148385ea29603 Mon Sep 17 00:00:00 2001 From: Changbin Du <changbin.du@intel.com> Date: Tue, 15 May 2018 10:35:44 +0800 Subject: [PATCH 0902/1506] drm/i915/gvt: Handle special sequence on PDE IPS bit If the guest update the 64K gtt entry before changing IPS bit of PDE, we need to re-shadow the whole page table. Because we have ignored all updates to unused entries. Signed-off-by: Changbin Du <changbin.du@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> --- drivers/gpu/drm/i915/gvt/gtt.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/gtt.c b/drivers/gpu/drm/i915/gvt/gtt.c index 5a66d0f3365cd..b40c6154e5716 100644 --- a/drivers/gpu/drm/i915/gvt/gtt.c +++ b/drivers/gpu/drm/i915/gvt/gtt.c @@ -1045,14 +1045,24 @@ static struct intel_vgpu_ppgtt_spt *ppgtt_populate_spt_by_guest_entry( GEM_BUG_ON(!gtt_type_is_pt(get_next_pt_type(we->type))); + if (we->type == GTT_TYPE_PPGTT_PDE_ENTRY) + ips = vgpu_ips_enabled(vgpu) && ops->test_ips(we); + spt = intel_vgpu_find_spt_by_gfn(vgpu, ops->get_pfn(we)); - if (spt) + if (spt) { ppgtt_get_spt(spt); - else { - int type = get_next_pt_type(we->type); - if (we->type == GTT_TYPE_PPGTT_PDE_ENTRY) - ips = vgpu_ips_enabled(vgpu) && ops->test_ips(we); + if (ips != spt->guest_page.pde_ips) { + spt->guest_page.pde_ips = ips; + + gvt_dbg_mm("reshadow PDE since ips changed\n"); + clear_page(spt->shadow_page.vaddr); + ret = ppgtt_populate_spt(spt); + if (ret) + goto fail; + } + } else { + int type = get_next_pt_type(we->type); spt = ppgtt_alloc_spt_gfn(vgpu, type, ops->get_pfn(we), ips); if (IS_ERR(spt)) { -- GitLab From 80e76ea631de6e14c2c436b278ee0c6871227606 Mon Sep 17 00:00:00 2001 From: Changbin Du <changbin.du@intel.com> Date: Tue, 15 May 2018 10:35:45 +0800 Subject: [PATCH 0903/1506] drm/i915/gvt: Fix error handling in ppgtt_populate_spt_by_guest_entry Don't forget to free allocated spt if shadowing failed. Signed-off-by: Changbin Du <changbin.du@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> --- drivers/gpu/drm/i915/gvt/gtt.c | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/gtt.c b/drivers/gpu/drm/i915/gvt/gtt.c index b40c6154e5716..156ceeeb74463 100644 --- a/drivers/gpu/drm/i915/gvt/gtt.c +++ b/drivers/gpu/drm/i915/gvt/gtt.c @@ -907,15 +907,22 @@ static struct intel_vgpu_ppgtt_spt *ppgtt_alloc_spt_gfn( i += (spt->shadow_page.pde_ips ? GTT_64K_PTE_STRIDE : 1)) \ if (!ppgtt_get_shadow_entry(spt, e, i)) -static void ppgtt_get_spt(struct intel_vgpu_ppgtt_spt *spt) +static inline void ppgtt_get_spt(struct intel_vgpu_ppgtt_spt *spt) { int v = atomic_read(&spt->refcount); trace_spt_refcount(spt->vgpu->id, "inc", spt, v, (v + 1)); - atomic_inc(&spt->refcount); } +static inline int ppgtt_put_spt(struct intel_vgpu_ppgtt_spt *spt) +{ + int v = atomic_read(&spt->refcount); + + trace_spt_refcount(spt->vgpu->id, "dec", spt, v, (v - 1)); + return atomic_dec_return(&spt->refcount); +} + static int ppgtt_invalidate_spt(struct intel_vgpu_ppgtt_spt *spt); static int ppgtt_invalidate_spt_by_shadow_entry(struct intel_vgpu *vgpu, @@ -967,14 +974,11 @@ static int ppgtt_invalidate_spt(struct intel_vgpu_ppgtt_spt *spt) struct intel_gvt_gtt_entry e; unsigned long index; int ret; - int v = atomic_read(&spt->refcount); trace_spt_change(spt->vgpu->id, "die", spt, spt->guest_page.gfn, spt->shadow_page.type); - trace_spt_refcount(spt->vgpu->id, "dec", spt, v, (v - 1)); - - if (atomic_dec_return(&spt->refcount) > 0) + if (ppgtt_put_spt(spt) > 0) return 0; for_each_present_shadow_entry(spt, &e, index) { @@ -1058,8 +1062,10 @@ static struct intel_vgpu_ppgtt_spt *ppgtt_populate_spt_by_guest_entry( gvt_dbg_mm("reshadow PDE since ips changed\n"); clear_page(spt->shadow_page.vaddr); ret = ppgtt_populate_spt(spt); - if (ret) - goto fail; + if (ret) { + ppgtt_put_spt(spt); + goto err; + } } } else { int type = get_next_pt_type(we->type); @@ -1067,22 +1073,25 @@ static struct intel_vgpu_ppgtt_spt *ppgtt_populate_spt_by_guest_entry( spt = ppgtt_alloc_spt_gfn(vgpu, type, ops->get_pfn(we), ips); if (IS_ERR(spt)) { ret = PTR_ERR(spt); - goto fail; + goto err; } ret = intel_vgpu_enable_page_track(vgpu, spt->guest_page.gfn); if (ret) - goto fail; + goto err_free_spt; ret = ppgtt_populate_spt(spt); if (ret) - goto fail; + goto err_free_spt; trace_spt_change(vgpu->id, "new", spt, spt->guest_page.gfn, spt->shadow_page.type); } return spt; -fail: + +err_free_spt: + ppgtt_free_spt(spt); +err: gvt_vgpu_err("fail: shadow page %p guest entry 0x%llx type %d\n", spt, we->val64, we->type); return ERR_PTR(ret); -- GitLab From aa36ed6d9536ad694995340264b69d57b01da7d3 Mon Sep 17 00:00:00 2001 From: Changbin Du <changbin.du@intel.com> Date: Tue, 15 May 2018 10:35:46 +0800 Subject: [PATCH 0904/1506] drm/i915: Enable platform support for vGPU huge gtt pages Now GVTg supports shadowing both 2M/64K huge gtt pages. So let's turn on the cap info bit VGT_CAPS_HUGE_GTT. v2: Split changes in i915 side into a separated patch. Signed-off-by: Changbin Du <changbin.du@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> --- drivers/gpu/drm/i915/gvt/vgpu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/gvt/vgpu.c b/drivers/gpu/drm/i915/gvt/vgpu.c index 889d10f8ee96c..aa063b275e81d 100644 --- a/drivers/gpu/drm/i915/gvt/vgpu.c +++ b/drivers/gpu/drm/i915/gvt/vgpu.c @@ -46,6 +46,7 @@ void populate_pvinfo_page(struct intel_vgpu *vgpu) vgpu_vreg_t(vgpu, vgtif_reg(vgt_caps)) = VGT_CAPS_FULL_48BIT_PPGTT; vgpu_vreg_t(vgpu, vgtif_reg(vgt_caps)) |= VGT_CAPS_HWSP_EMULATION; + vgpu_vreg_t(vgpu, vgtif_reg(vgt_caps)) |= VGT_CAPS_HUGE_GTT; vgpu_vreg_t(vgpu, vgtif_reg(avail_rs.mappable_gmadr.base)) = vgpu_aperture_gmadr_base(vgpu); -- GitLab From 93d68b258e7d6b2b4b0716c6f33a38d5b6a536ff Mon Sep 17 00:00:00 2001 From: Colin Xu <colin.xu@intel.com> Date: Mon, 9 Jul 2018 09:28:18 +0800 Subject: [PATCH 0905/1506] drm/i915/gvt: Handle EDP_PSR_IMR and EDP_PSR_IIR for BXT. BXT supports EDP. However since GVT-g only simulate DP monitor to guest and handles EDP_PSR_IMR and EDP_PSR_IIR as default MMIO r/w. If guest r/w these IMR/IIR, GVT-g won't simulate the real HW behavior and below warning is printed: -------- Interrupt register 0x64838 is not zero: 0xffffffff WARNING: CPU: 1 PID: 1 at drivers/gpu/drm/i915/i915_irq.c:161 gen3_assert_iir_is_zero+0x34/0xa0 Call Trace: gen8_de_irq_postinstall+0xad/0x330 gen8_irq_postinstall+0x23/0x80 drm_irq_install+0xb5/0x130 i915_driver_load+0xafd/0xf70 -------- Since GVT-g won't simulate EDP to guest, always set EDP_PSR_IMR and EDP_PSR_IIR IMR/IIR to 0. Signed-off-by: Colin Xu <colin.xu@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> --- drivers/gpu/drm/i915/gvt/handlers.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c index 17f56fc20613f..e2e252c67de82 100644 --- a/drivers/gpu/drm/i915/gvt/handlers.c +++ b/drivers/gpu/drm/i915/gvt/handlers.c @@ -1584,6 +1584,13 @@ static int bxt_gt_disp_pwron_write(struct intel_vgpu *vgpu, return 0; } +static int bxt_edp_psr_imr_iir_write(struct intel_vgpu *vgpu, + unsigned int offset, void *p_data, unsigned int bytes) +{ + vgpu_vreg(vgpu, offset) = 0; + return 0; +} + static int mmio_read_from_hw(struct intel_vgpu *vgpu, unsigned int offset, void *p_data, unsigned int bytes) { @@ -3182,6 +3189,9 @@ static int init_bxt_mmio_info(struct intel_gvt *gvt) MMIO_D(HSW_TVIDEO_DIP_GCP(TRANSCODER_B), D_BXT); MMIO_D(HSW_TVIDEO_DIP_GCP(TRANSCODER_C), D_BXT); + MMIO_DH(EDP_PSR_IMR, D_BXT, NULL, bxt_edp_psr_imr_iir_write); + MMIO_DH(EDP_PSR_IIR, D_BXT, NULL, bxt_edp_psr_imr_iir_write); + MMIO_D(RC6_CTX_BASE, D_BXT); MMIO_D(GEN8_PUSHBUS_CONTROL, D_BXT); -- GitLab From e147913247e3a7ea98e72e8537336bcea06c2405 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Sat, 7 Jul 2018 11:04:05 +0100 Subject: [PATCH 0906/1506] drm/i915/selftests: Magic numbers for old Y-tiling i915g has a slightly different tiling layout, and so requires a different reference swizzle pattern. Testcase: igt/drv_selftests/live_objects #gdg Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Acked-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180707100405.817-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/selftests/i915_gem_object.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_object.c b/drivers/gpu/drm/i915/selftests/i915_gem_object.c index 25c2b2d433bdb..f4a5099c75b5f 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_object.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_object.c @@ -169,9 +169,16 @@ static u64 tiled_offset(const struct tile *tile, u64 v) v += y * tile->width; v += div64_u64_rem(x, tile->width, &x) << tile->size; v += x; - } else { + } else if (tile->width == 128) { const unsigned int ytile_span = 16; - const unsigned int ytile_height = 32 * ytile_span; + const unsigned int ytile_height = 512; + + v += y * ytile_span; + v += div64_u64_rem(x, ytile_span, &x) * ytile_height; + v += x; + } else { + const unsigned int ytile_span = 32; + const unsigned int ytile_height = 256; v += y * ytile_span; v += div64_u64_rem(x, ytile_span, &x) * ytile_height; -- GitLab From ec625fb932bb057e2d3c2ed28eee56a827385ab8 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Mon, 9 Jul 2018 13:20:42 +0100 Subject: [PATCH 0907/1506] drm/i915: Provide a timeout to i915_gem_wait_for_idle() Usually we have no idea about the upper bound we need to wait to catch up with userspace when idling the device, but in a few situations we know the system was idle beforehand and can provide a short timeout in order to very quickly catch a failure, long before hangcheck kicks in. In the following patches, we will use the timeout to curtain two overly long waits, where we know we can expect the GPU to complete within a reasonable time or declare it broken. In particular, with a broken GPU we expect it to fail during the initial GPU setup where do a couple of context switches to record the defaults. This is a task that takes a few milliseconds even on the slowest of devices, but we may have to wait 60s for hangcheck to give in and declare the machine inoperable. In this a case where any gpu hang is unacceptable, both from a timeliness and practical standpoint. The other improvement is that in selftests, we do not need to arm an independent timer to inject a wedge, as we can just limit the timeout on the wait directly. v2: Include the timeout parameter in the trace. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180709122044.7028-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_debugfs.c | 6 ++- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_gem.c | 48 +++++++++++-------- drivers/gpu/drm/i915/i915_gem_evict.c | 3 +- drivers/gpu/drm/i915/i915_gem_gtt.c | 2 +- drivers/gpu/drm/i915/i915_gem_shrinker.c | 11 +++-- drivers/gpu/drm/i915/i915_perf.c | 4 +- drivers/gpu/drm/i915/i915_request.c | 6 ++- .../gpu/drm/i915/selftests/i915_gem_context.c | 4 +- drivers/gpu/drm/i915/selftests/i915_request.c | 4 +- .../gpu/drm/i915/selftests/igt_flush_test.c | 2 +- 11 files changed, 59 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 544e5e7f011fb..099f97ef23039 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -4105,7 +4105,8 @@ fault_irq_set(struct drm_i915_private *i915, err = i915_gem_wait_for_idle(i915, I915_WAIT_LOCKED | - I915_WAIT_INTERRUPTIBLE); + I915_WAIT_INTERRUPTIBLE, + MAX_SCHEDULE_TIMEOUT); if (err) goto err_unlock; @@ -4210,7 +4211,8 @@ i915_drop_caches_set(void *data, u64 val) if (val & DROP_ACTIVE) ret = i915_gem_wait_for_idle(dev_priv, I915_WAIT_INTERRUPTIBLE | - I915_WAIT_LOCKED); + I915_WAIT_LOCKED, + MAX_SCHEDULE_TIMEOUT); if (val & DROP_RETIRE) i915_retire_requests(dev_priv); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c790081777083..fcb8f49a9b8a7 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3157,7 +3157,7 @@ void i915_gem_init_swizzling(struct drm_i915_private *dev_priv); void i915_gem_fini(struct drm_i915_private *dev_priv); void i915_gem_cleanup_engines(struct drm_i915_private *dev_priv); int i915_gem_wait_for_idle(struct drm_i915_private *dev_priv, - unsigned int flags); + unsigned int flags, long timeout); int __must_check i915_gem_suspend(struct drm_i915_private *dev_priv); void i915_gem_suspend_late(struct drm_i915_private *dev_priv); void i915_gem_resume(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 1a9dab302433e..91d705a67d389 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2267,7 +2267,9 @@ static int i915_gem_object_create_mmap_offset(struct drm_i915_gem_object *obj) /* Attempt to reap some mmap space from dead objects */ do { - err = i915_gem_wait_for_idle(dev_priv, I915_WAIT_INTERRUPTIBLE); + err = i915_gem_wait_for_idle(dev_priv, + I915_WAIT_INTERRUPTIBLE, + MAX_SCHEDULE_TIMEOUT); if (err) break; @@ -3742,14 +3744,14 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file) return ret; } -static int wait_for_timeline(struct i915_timeline *tl, unsigned int flags) +static long wait_for_timeline(struct i915_timeline *tl, + unsigned int flags, long timeout) { struct i915_request *rq; - long ret; rq = i915_gem_active_get_unlocked(&tl->last_request); if (!rq) - return 0; + return timeout; /* * "Race-to-idle". @@ -3763,10 +3765,10 @@ static int wait_for_timeline(struct i915_timeline *tl, unsigned int flags) if (flags & I915_WAIT_FOR_IDLE_BOOST) gen6_rps_boost(rq, NULL); - ret = i915_request_wait(rq, flags, MAX_SCHEDULE_TIMEOUT); + timeout = i915_request_wait(rq, flags, timeout); i915_request_put(rq); - return ret < 0 ? ret : 0; + return timeout; } static int wait_for_engines(struct drm_i915_private *i915) @@ -3782,10 +3784,12 @@ static int wait_for_engines(struct drm_i915_private *i915) return 0; } -int i915_gem_wait_for_idle(struct drm_i915_private *i915, unsigned int flags) +int i915_gem_wait_for_idle(struct drm_i915_private *i915, + unsigned int flags, long timeout) { - GEM_TRACE("flags=%x (%s)\n", - flags, flags & I915_WAIT_LOCKED ? "locked" : "unlocked"); + GEM_TRACE("flags=%x (%s), timeout=%ld%s\n", + flags, flags & I915_WAIT_LOCKED ? "locked" : "unlocked", + timeout, timeout == MAX_SCHEDULE_TIMEOUT ? " (forever)" : ""); /* If the device is asleep, we have no requests outstanding */ if (!READ_ONCE(i915->gt.awake)) @@ -3798,9 +3802,9 @@ int i915_gem_wait_for_idle(struct drm_i915_private *i915, unsigned int flags) lockdep_assert_held(&i915->drm.struct_mutex); list_for_each_entry(tl, &i915->gt.timelines, link) { - err = wait_for_timeline(tl, flags); - if (err) - return err; + timeout = wait_for_timeline(tl, flags, timeout); + if (timeout < 0) + return timeout; } err = wait_for_engines(i915); @@ -3812,12 +3816,13 @@ int i915_gem_wait_for_idle(struct drm_i915_private *i915, unsigned int flags) } else { struct intel_engine_cs *engine; enum intel_engine_id id; - int err; for_each_engine(engine, i915, id) { - err = wait_for_timeline(&engine->timeline, flags); - if (err) - return err; + struct i915_timeline *tl = &engine->timeline; + + timeout = wait_for_timeline(tl, flags, timeout); + if (timeout < 0) + return timeout; } } @@ -5052,7 +5057,8 @@ int i915_gem_suspend(struct drm_i915_private *dev_priv) ret = i915_gem_wait_for_idle(dev_priv, I915_WAIT_INTERRUPTIBLE | I915_WAIT_LOCKED | - I915_WAIT_FOR_IDLE_BOOST); + I915_WAIT_FOR_IDLE_BOOST, + MAX_SCHEDULE_TIMEOUT); if (ret && ret != -EIO) goto err_unlock; @@ -5356,7 +5362,9 @@ static int __intel_engines_record_defaults(struct drm_i915_private *i915) if (err) goto err_active; - err = i915_gem_wait_for_idle(i915, I915_WAIT_LOCKED); + err = i915_gem_wait_for_idle(i915, + I915_WAIT_LOCKED, + MAX_SCHEDULE_TIMEOUT); if (err) goto err_active; @@ -5421,7 +5429,9 @@ static int __intel_engines_record_defaults(struct drm_i915_private *i915) if (WARN_ON(i915_gem_switch_to_kernel_context(i915))) goto out_ctx; - if (WARN_ON(i915_gem_wait_for_idle(i915, I915_WAIT_LOCKED))) + if (WARN_ON(i915_gem_wait_for_idle(i915, + I915_WAIT_LOCKED, + MAX_SCHEDULE_TIMEOUT))) goto out_ctx; i915_gem_contexts_lost(i915); diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c index 54814a196ee4d..02b83a5ed96c9 100644 --- a/drivers/gpu/drm/i915/i915_gem_evict.c +++ b/drivers/gpu/drm/i915/i915_gem_evict.c @@ -69,7 +69,8 @@ static int ggtt_flush(struct drm_i915_private *i915) err = i915_gem_wait_for_idle(i915, I915_WAIT_INTERRUPTIBLE | - I915_WAIT_LOCKED); + I915_WAIT_LOCKED, + MAX_SCHEDULE_TIMEOUT); if (err) return err; diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 4db31aaaa9d39..210baf3c8d112 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -2793,7 +2793,7 @@ void i915_gem_gtt_finish_pages(struct drm_i915_gem_object *obj, struct i915_ggtt *ggtt = &dev_priv->ggtt; if (unlikely(ggtt->do_idle_maps)) { - if (i915_gem_wait_for_idle(dev_priv, 0)) { + if (i915_gem_wait_for_idle(dev_priv, 0, MAX_SCHEDULE_TIMEOUT)) { DRM_ERROR("Failed to wait for idle; VT'd may hang.\n"); /* Wait a bit, in hopes it avoids the hang */ udelay(10); diff --git a/drivers/gpu/drm/i915/i915_gem_shrinker.c b/drivers/gpu/drm/i915/i915_gem_shrinker.c index 55e84e71f526d..c61f5b80fee3a 100644 --- a/drivers/gpu/drm/i915/i915_gem_shrinker.c +++ b/drivers/gpu/drm/i915/i915_gem_shrinker.c @@ -172,7 +172,9 @@ i915_gem_shrink(struct drm_i915_private *i915, * we will free as much as we can and hope to get a second chance. */ if (flags & I915_SHRINK_ACTIVE) - i915_gem_wait_for_idle(i915, I915_WAIT_LOCKED); + i915_gem_wait_for_idle(i915, + I915_WAIT_LOCKED, + MAX_SCHEDULE_TIMEOUT); trace_i915_gem_shrink(i915, target, flags); i915_retire_requests(i915); @@ -392,7 +394,8 @@ shrinker_lock_uninterruptible(struct drm_i915_private *i915, bool *unlock, unsigned long timeout = jiffies + msecs_to_jiffies_timeout(timeout_ms); do { - if (i915_gem_wait_for_idle(i915, 0) == 0 && + if (i915_gem_wait_for_idle(i915, + 0, MAX_SCHEDULE_TIMEOUT) == 0 && shrinker_lock(i915, unlock)) break; @@ -466,7 +469,9 @@ i915_gem_shrinker_vmap(struct notifier_block *nb, unsigned long event, void *ptr return NOTIFY_DONE; /* Force everything onto the inactive lists */ - ret = i915_gem_wait_for_idle(i915, I915_WAIT_LOCKED); + ret = i915_gem_wait_for_idle(i915, + I915_WAIT_LOCKED, + MAX_SCHEDULE_TIMEOUT); if (ret) goto out; diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index 447407fee3b89..6bf10952c7240 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -1836,7 +1836,9 @@ static int gen8_configure_all_contexts(struct drm_i915_private *dev_priv, * So far the best way to work around this issue seems to be draining * the GPU from any submitted work. */ - ret = i915_gem_wait_for_idle(dev_priv, wait_flags); + ret = i915_gem_wait_for_idle(dev_priv, + wait_flags, + MAX_SCHEDULE_TIMEOUT); if (ret) goto out; diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index 3248369dbcfb2..5c2c93cbab12f 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -206,7 +206,8 @@ static int reset_all_global_seqno(struct drm_i915_private *i915, u32 seqno) /* Carefully retire all requests without writing to the rings */ ret = i915_gem_wait_for_idle(i915, I915_WAIT_INTERRUPTIBLE | - I915_WAIT_LOCKED); + I915_WAIT_LOCKED, + MAX_SCHEDULE_TIMEOUT); if (ret) return ret; @@ -735,7 +736,8 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx) /* Ratelimit ourselves to prevent oom from malicious clients */ ret = i915_gem_wait_for_idle(i915, I915_WAIT_LOCKED | - I915_WAIT_INTERRUPTIBLE); + I915_WAIT_INTERRUPTIBLE, + MAX_SCHEDULE_TIMEOUT); if (ret) goto err_unreserve; diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_context.c b/drivers/gpu/drm/i915/selftests/i915_gem_context.c index 5fbe15f4effdb..ab25902420333 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_context.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_context.c @@ -478,7 +478,9 @@ static int __igt_switch_to_kernel_context(struct drm_i915_private *i915, } } - err = i915_gem_wait_for_idle(i915, I915_WAIT_LOCKED); + err = i915_gem_wait_for_idle(i915, + I915_WAIT_LOCKED, + MAX_SCHEDULE_TIMEOUT); if (err) return err; diff --git a/drivers/gpu/drm/i915/selftests/i915_request.c b/drivers/gpu/drm/i915/selftests/i915_request.c index 43995fc3534d7..c4aac6141e04d 100644 --- a/drivers/gpu/drm/i915/selftests/i915_request.c +++ b/drivers/gpu/drm/i915/selftests/i915_request.c @@ -286,7 +286,9 @@ static int begin_live_test(struct live_test *t, t->func = func; t->name = name; - err = i915_gem_wait_for_idle(i915, I915_WAIT_LOCKED); + err = i915_gem_wait_for_idle(i915, + I915_WAIT_LOCKED, + MAX_SCHEDULE_TIMEOUT); if (err) { pr_err("%s(%s): failed to idle before, with err=%d!", func, name, err); diff --git a/drivers/gpu/drm/i915/selftests/igt_flush_test.c b/drivers/gpu/drm/i915/selftests/igt_flush_test.c index 0d06f559243f9..09ab037ce8038 100644 --- a/drivers/gpu/drm/i915/selftests/igt_flush_test.c +++ b/drivers/gpu/drm/i915/selftests/igt_flush_test.c @@ -64,7 +64,7 @@ int igt_flush_test(struct drm_i915_private *i915, unsigned int flags) } wedge_on_timeout(&w, i915, HZ) - i915_gem_wait_for_idle(i915, flags); + i915_gem_wait_for_idle(i915, flags, MAX_SCHEDULE_TIMEOUT); return i915_terminally_wedged(&i915->gpu_error) ? -EIO : 0; } -- GitLab From 2621cefaa42b3a7455d30e78831c6b55290d40c8 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Mon, 9 Jul 2018 13:20:43 +0100 Subject: [PATCH 0908/1506] drm/i915: Provide a timeout to i915_gem_wait_for_idle() on setup With a broken GPU we expect it to fail during the initial GPU setup where do a couple of context switches to record the defaults. This is a task that takes a few milliseconds even on the slowest of devices, but we may have to wait 60s for hangcheck to give in and declare the machine inoperable. In this a case where any gpu hang is unacceptable, both from a timeliness and practical standpoint. We can therefore set a timeout on our wait-for-idle that is shorter than the hangcheck (which may be up to 60s for a declaring a wedged driver) and so detect the broken GPU much more quickly during driver load (and so prevent stalling userspace for ages). Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180709122044.7028-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 91d705a67d389..b35cbfd16c9c4 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5362,11 +5362,11 @@ static int __intel_engines_record_defaults(struct drm_i915_private *i915) if (err) goto err_active; - err = i915_gem_wait_for_idle(i915, - I915_WAIT_LOCKED, - MAX_SCHEDULE_TIMEOUT); - if (err) + if (i915_gem_wait_for_idle(i915, I915_WAIT_LOCKED, HZ / 5)) { + i915_gem_set_wedged(i915); + err = -EIO; /* Caller will declare us wedged */ goto err_active; + } assert_kernel_context_is_current(i915); -- GitLab From d9a13ce3fa5f396f100ab3f58e5ca127c77a74bb Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Mon, 9 Jul 2018 13:20:44 +0100 Subject: [PATCH 0909/1506] drm/i915/selftests: Replace wait-on-timeout with explicit timeout In igt_flush_test() we install a background timer in order to ensure that the wait completes within a certain time. We can now tell the wait that it has to complete within a timeout, and so no longer need the background timer. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180709122044.7028-3-chris@chris-wilson.co.uk --- .../gpu/drm/i915/selftests/igt_flush_test.c | 55 +++---------------- 1 file changed, 9 insertions(+), 46 deletions(-) diff --git a/drivers/gpu/drm/i915/selftests/igt_flush_test.c b/drivers/gpu/drm/i915/selftests/igt_flush_test.c index 09ab037ce8038..af66e3d4e23a4 100644 --- a/drivers/gpu/drm/i915/selftests/igt_flush_test.c +++ b/drivers/gpu/drm/i915/selftests/igt_flush_test.c @@ -9,52 +9,8 @@ #include "../i915_selftest.h" #include "igt_flush_test.h" -struct wedge_me { - struct delayed_work work; - struct drm_i915_private *i915; - const void *symbol; -}; - -static void wedge_me(struct work_struct *work) -{ - struct wedge_me *w = container_of(work, typeof(*w), work.work); - - pr_err("%pS timed out, cancelling all further testing.\n", w->symbol); - - GEM_TRACE("%pS timed out.\n", w->symbol); - GEM_TRACE_DUMP(); - - i915_gem_set_wedged(w->i915); -} - -static void __init_wedge(struct wedge_me *w, - struct drm_i915_private *i915, - long timeout, - const void *symbol) -{ - w->i915 = i915; - w->symbol = symbol; - - INIT_DELAYED_WORK_ONSTACK(&w->work, wedge_me); - schedule_delayed_work(&w->work, timeout); -} - -static void __fini_wedge(struct wedge_me *w) -{ - cancel_delayed_work_sync(&w->work); - destroy_delayed_work_on_stack(&w->work); - w->i915 = NULL; -} - -#define wedge_on_timeout(W, DEV, TIMEOUT) \ - for (__init_wedge((W), (DEV), (TIMEOUT), __builtin_return_address(0)); \ - (W)->i915; \ - __fini_wedge((W))) - int igt_flush_test(struct drm_i915_private *i915, unsigned int flags) { - struct wedge_me w; - cond_resched(); if (flags & I915_WAIT_LOCKED && @@ -63,8 +19,15 @@ int igt_flush_test(struct drm_i915_private *i915, unsigned int flags) i915_gem_set_wedged(i915); } - wedge_on_timeout(&w, i915, HZ) - i915_gem_wait_for_idle(i915, flags, MAX_SCHEDULE_TIMEOUT); + if (i915_gem_wait_for_idle(i915, flags, HZ / 5) == -ETIME) { + pr_err("%pS timed out, cancelling all further testing.\n", + __builtin_return_address(0)); + + GEM_TRACE("%pS timed out.\n", __builtin_return_address(0)); + GEM_TRACE_DUMP(); + + i915_gem_set_wedged(i915); + } return i915_terminally_wedged(&i915->gpu_error) ? -EIO : 0; } -- GitLab From 932cac10c8fb07e72a1eba28e71b92f7f2cd756e Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Mon, 9 Jul 2018 14:01:58 +0100 Subject: [PATCH 0910/1506] drm/i915/selftests: Prevent background reaping of active objects igt_mmap_offset_exhaustion() wants to test what happens when the mmap space is filled with zombie objects, objects discarded by userspace but still active on the GPU. As they are only protected by the active reference, we have to be certain that active reference is kept while we peek into our dangling pointer. That active reference should not be freed until we retire, but we do that retirement from a background thread. This leaves us with a subtle timing problem, exacerbated and highlighted by KASAN: <3>[ 132.380399] BUG: KASAN: use-after-free in drm_gem_create_mmap_offset+0x8c/0xd0 <3>[ 132.380430] Read of size 8 at addr ffff8801e13245f8 by task drv_selftest/5822 <4>[ 132.380470] CPU: 0 PID: 5822 Comm: drv_selftest Tainted: G U 4.18.0-rc3-g7ae7763aa2be-kasan_48+ #1 <4>[ 132.380473] Hardware name: Dell Inc. XPS 8300 /0Y2MRG, BIOS A06 10/17/2011 <4>[ 132.380475] Call Trace: <4>[ 132.380481] dump_stack+0x7c/0xbb <4>[ 132.380487] print_address_description+0x65/0x270 <4>[ 132.380493] kasan_report+0x25b/0x380 <4>[ 132.380497] ? drm_gem_create_mmap_offset+0x8c/0xd0 <4>[ 132.380503] drm_gem_create_mmap_offset+0x8c/0xd0 <4>[ 132.380584] i915_gem_object_create_mmap_offset+0x6d/0x100 [i915] <4>[ 132.380650] igt_mmap_offset_exhaustion+0x462/0x940 [i915] <4>[ 132.380714] ? i915_gem_close_object+0x740/0x740 [i915] <4>[ 132.380784] ? igt_gem_huge+0x269/0x3d0 [i915] <4>[ 132.380865] __i915_subtests+0x5a/0x160 [i915] <4>[ 132.380936] __run_selftests+0x1a2/0x2f0 [i915] <4>[ 132.381008] i915_live_selftests+0x4e/0x80 [i915] <4>[ 132.381071] i915_pci_probe+0xd8/0x1b0 [i915] <4>[ 132.381077] pci_device_probe+0x1c5/0x3a0 <4>[ 132.381087] driver_probe_device+0x6b6/0xcb0 <4>[ 132.381094] __driver_attach+0x22d/0x2c0 <4>[ 132.381100] ? driver_probe_device+0xcb0/0xcb0 <4>[ 132.381103] bus_for_each_dev+0x113/0x1a0 <4>[ 132.381108] ? check_flags.part.24+0x450/0x450 <4>[ 132.381112] ? subsys_dev_iter_exit+0x10/0x10 <4>[ 132.381123] bus_add_driver+0x38b/0x6e0 <4>[ 132.381131] driver_register+0x189/0x400 <4>[ 132.381136] ? 0xffffffffc12d8000 <4>[ 132.381140] do_one_initcall+0xa0/0x4c0 <4>[ 132.381145] ? initcall_blacklisted+0x180/0x180 <4>[ 132.381152] ? do_init_module+0x4a/0x54c <4>[ 132.381156] ? rcu_lockdep_current_cpu_online+0xdc/0x130 <4>[ 132.381161] ? kasan_unpoison_shadow+0x30/0x40 <4>[ 132.381169] do_init_module+0x1b5/0x54c <4>[ 132.381177] load_module+0x619e/0x9b70 <4>[ 132.381202] ? module_frob_arch_sections+0x20/0x20 <4>[ 132.381211] ? vfs_read+0x257/0x2f0 <4>[ 132.381214] ? vfs_read+0x257/0x2f0 <4>[ 132.381221] ? kernel_read+0x8b/0x130 <4>[ 132.381231] ? copy_strings_kernel+0x120/0x120 <4>[ 132.381244] ? __se_sys_finit_module+0x17c/0x1a0 <4>[ 132.381248] __se_sys_finit_module+0x17c/0x1a0 <4>[ 132.381252] ? __ia32_sys_init_module+0xa0/0xa0 <4>[ 132.381261] ? __se_sys_newstat+0x77/0xd0 <4>[ 132.381265] ? cp_new_stat+0x590/0x590 <4>[ 132.381269] ? kmem_cache_free+0x2f0/0x340 <4>[ 132.381285] do_syscall_64+0x97/0x400 <4>[ 132.381292] entry_SYSCALL_64_after_hwframe+0x49/0xbe <4>[ 132.381295] RIP: 0033:0x7eff4af46839 <4>[ 132.381297] Code: 00 f3 c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 1f f6 2c 00 f7 d8 64 89 01 48 <4>[ 132.381426] RSP: 002b:00007ffcd84f4cf8 EFLAGS: 00000246 ORIG_RAX: 0000000000000139 <4>[ 132.381432] RAX: ffffffffffffffda RBX: 000055dfdeb429a0 RCX: 00007eff4af46839 <4>[ 132.381435] RDX: 0000000000000000 RSI: 000055dfdeb43670 RDI: 0000000000000004 <4>[ 132.381437] RBP: 000055dfdeb43670 R08: 0000000000000004 R09: 0000000000000000 <4>[ 132.381440] R10: 00007ffcd84f4e60 R11: 0000000000000246 R12: 0000000000000000 <4>[ 132.381442] R13: 000055dfdeb3bec0 R14: 0000000000000000 R15: 000000000000003b <3>[ 132.381466] Allocated by task 5822: <4>[ 132.381485] kmem_cache_alloc+0xdf/0x2e0 <4>[ 132.381546] i915_gem_object_create_internal+0x24/0x1e0 [i915] <4>[ 132.381609] igt_mmap_offset_exhaustion+0x257/0x940 [i915] <4>[ 132.381677] __i915_subtests+0x5a/0x160 [i915] <4>[ 132.381742] __run_selftests+0x1a2/0x2f0 [i915] <4>[ 132.381806] i915_live_selftests+0x4e/0x80 [i915] <4>[ 132.381865] i915_pci_probe+0xd8/0x1b0 [i915] <4>[ 132.381868] pci_device_probe+0x1c5/0x3a0 <4>[ 132.381871] driver_probe_device+0x6b6/0xcb0 <4>[ 132.381874] __driver_attach+0x22d/0x2c0 <4>[ 132.381877] bus_for_each_dev+0x113/0x1a0 <4>[ 132.381880] bus_add_driver+0x38b/0x6e0 <4>[ 132.381884] driver_register+0x189/0x400 <4>[ 132.381886] do_one_initcall+0xa0/0x4c0 <4>[ 132.381889] do_init_module+0x1b5/0x54c <4>[ 132.381892] load_module+0x619e/0x9b70 <4>[ 132.381895] __se_sys_finit_module+0x17c/0x1a0 <4>[ 132.381898] do_syscall_64+0x97/0x400 <4>[ 132.381901] entry_SYSCALL_64_after_hwframe+0x49/0xbe <3>[ 132.381914] Freed by task 150: <4>[ 132.381931] kmem_cache_free+0xb7/0x340 <4>[ 132.381995] __i915_gem_free_objects+0x875/0xf50 [i915] <4>[ 132.382054] __i915_gem_free_work+0x69/0xb0 [i915] <4>[ 132.382058] process_one_work+0x78b/0x1740 <4>[ 132.382061] worker_thread+0x82/0xb80 <4>[ 132.382064] kthread+0x30c/0x3d0 <4>[ 132.382067] ret_from_fork+0x3a/0x50 <3>[ 132.382081] The buggy address belongs to the object at ffff8801e1324500 which belongs to the cache drm_i915_gem_object of size 1168 <3>[ 132.382133] The buggy address is located 248 bytes inside of 1168-byte region [ffff8801e1324500, ffff8801e1324990) <3>[ 132.382179] The buggy address belongs to the page: <0>[ 132.382202] page:ffffea000784c800 count:1 mapcount:0 mapping:ffff8801dedf6500 index:0xffff8801e1323ec0 compound_mapcount: 0 <0>[ 132.382251] flags: 0x8000000000008100(slab|head) <1>[ 132.382274] raw: 8000000000008100 ffff8801d6317440 ffff8801d6317440 ffff8801dedf6500 <1>[ 132.382307] raw: ffff8801e1323ec0 0000000000140013 00000001ffffffff 0000000000000000 <1>[ 132.382339] page dumped because: kasan: bad access detected <3>[ 132.382373] Memory state around the buggy address: <3>[ 132.382395] ffff8801e1324480: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc <3>[ 132.382426] ffff8801e1324500: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb <3>[ 132.382457] >ffff8801e1324580: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb <3>[ 132.382488] ^ <3>[ 132.382517] ffff8801e1324600: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb <3>[ 132.382548] ffff8801e1324680: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb This patch tricks the system into running without the background retire thread, until after we finish the test. The only reaping should then be performed by the mmap offset routine to reclaim the space as required. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180709130208.11730-1-chris@chris-wilson.co.uk --- .../gpu/drm/i915/selftests/i915_gem_object.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_object.c b/drivers/gpu/drm/i915/selftests/i915_gem_object.c index f4a5099c75b5f..d77acf4cc4397 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_object.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_object.c @@ -507,6 +507,15 @@ static int igt_mmap_offset_exhaustion(void *arg) u64 hole_start, hole_end; int loop, err; + /* Disable background reaper */ + mutex_lock(&i915->drm.struct_mutex); + if (!i915->gt.active_requests++) + i915_gem_unpark(i915); + mutex_unlock(&i915->drm.struct_mutex); + cancel_delayed_work_sync(&i915->gt.retire_work); + cancel_delayed_work_sync(&i915->gt.idle_work); + GEM_BUG_ON(!i915->gt.awake); + /* Trim the device mmap space to only a page */ memset(&resv, 0, sizeof(resv)); drm_mm_for_each_hole(hole, mm, hole_start, hole_end) { @@ -515,7 +524,7 @@ static int igt_mmap_offset_exhaustion(void *arg) err = drm_mm_reserve_node(mm, &resv); if (err) { pr_err("Failed to trim VMA manager, err=%d\n", err); - return err; + goto out_park; } break; } @@ -576,6 +585,7 @@ static int igt_mmap_offset_exhaustion(void *arg) goto err_obj; } + /* NB we rely on the _active_ reference to access obj now */ GEM_BUG_ON(!i915_gem_object_is_active(obj)); err = i915_gem_object_create_mmap_offset(obj); if (err) { @@ -587,6 +597,13 @@ static int igt_mmap_offset_exhaustion(void *arg) out: drm_mm_remove_node(&resv); +out_park: + mutex_lock(&i915->drm.struct_mutex); + if (--i915->gt.active_requests) + queue_delayed_work(i915->wq, &i915->gt.retire_work, 0); + else + queue_delayed_work(i915->wq, &i915->gt.idle_work, 0); + mutex_unlock(&i915->drm.struct_mutex); return err; err_obj: i915_gem_object_put(obj); -- GitLab From 5ba57babcb40227ceb70d9bc71afa57e004f8417 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann <arnd@arndb.de> Date: Mon, 9 Jul 2018 17:48:18 +0200 Subject: [PATCH 0911/1506] drm: vkms: select DRM_KMS_HELPER Without this, we get link errors during randconfig build: drivers/gpu/drm/vkms/vkms_drv.o:(.rodata+0xa0): undefined reference to `drm_atomic_helper_check' drivers/gpu/drm/vkms/vkms_drv.o:(.rodata+0xa8): undefined reference to `drm_atomic_helper_commit' drivers/gpu/drm/vkms/vkms_plane.o:(.rodata+0x0): undefined reference to `drm_atomic_helper_update_plane' drivers/gpu/drm/vkms/vkms_plane.o:(.rodata+0x8): undefined reference to `drm_atomic_helper_disable_plane' drivers/gpu/drm/vkms/vkms_plane.o:(.rodata+0x18): undefined reference to `drm_atomic_helper_plane_reset' drivers/gpu/drm/vkms/vkms_plane.o:(.rodata+0x28): undefined reference to `drm_atomic_helper_plane_duplicate_state' drivers/gpu/drm/vkms/vkms_plane.o:(.rodata+0x30): undefined reference to `drm_atomic_helper_plane_destroy_state' drivers/gpu/drm/vkms/vkms_output.o:(.rodata+0x1c0): undefined reference to `drm_helper_probe_single_connector_modes' drivers/gpu/drm/vkms/vkms_crtc.o:(.rodata+0x40): undefined reference to `drm_atomic_helper_crtc_reset' drivers/gpu/drm/vkms/vkms_crtc.o:(.rodata+0x70): undefined reference to `drm_atomic_helper_set_config' drivers/gpu/drm/vkms/vkms_crtc.o:(.rodata+0x78): undefined reference to `drm_atomic_helper_page_flip' drivers/gpu/drm/vkms/vkms_crtc.o:(.rodata+0x90): undefined reference to `drm_atomic_helper_crtc_duplicate_state' drivers/gpu/drm/vkms/vkms_crtc.o:(.rodata+0x98): undefined reference to `drm_atomic_helper_crtc_destroy_state' Fixes: 854502fa0a38 ("drm/vkms: Add basic CRTC initialization") Fixes: 1c7c5fd916a0 ("drm/vkms: Introduce basic VKMS driver") Signed-off-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180709154901.1989316-1-arnd@arndb.de --- drivers/gpu/drm/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 10f9f01123ead..a8054dde49b50 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -216,6 +216,7 @@ config DRM_VGEM config DRM_VKMS tristate "Virtual KMS (EXPERIMENTAL)" depends on DRM + select DRM_KMS_HELPER default n help Virtual Kernel Mode-Setting (VKMS) is used for testing or for -- GitLab From 82edc7e8b8c06151bdc653935bc13b83e2f0fcfa Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi <rodrigo.vivi@intel.com> Date: Mon, 9 Jul 2018 15:39:27 -0700 Subject: [PATCH 0912/1506] drm/i915: Update DRIVER_DATE to 20180709 Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com> --- drivers/gpu/drm/i915/i915_drv.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index fcb8f49a9b8a7..a90a37ce2ef9c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -86,8 +86,8 @@ #define DRIVER_NAME "i915" #define DRIVER_DESC "Intel Graphics" -#define DRIVER_DATE "20180620" -#define DRIVER_TIMESTAMP 1529529048 +#define DRIVER_DATE "20180709" +#define DRIVER_TIMESTAMP 1531175967 /* Use I915_STATE_WARN(x) and I915_STATE_WARN_ON() (rather than WARN() and * WARN_ON()) for hw state sanity checks to check for unexpected conditions -- GitLab From 279ce5d117078ee8ea40c40199399889981fd808 Mon Sep 17 00:00:00 2001 From: Hang Yuan <hang.yuan@linux.intel.com> Date: Mon, 9 Jul 2018 18:24:10 +0800 Subject: [PATCH 0913/1506] drm/i915/gvt: declare gvt as i915's soft dependency This helps initramfs builder and other tools to know the full dependencies of i915 and have gvt module loaded with i915. v2: add condition and change to pre-dependency (Chris) v3: move declaration to gvt.c. (Chris) v4: remove xengt (Zhenyu) Signed-off-by: Hang Yuan <hang.yuan@linux.intel.com> Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> --- drivers/gpu/drm/i915/gvt/gvt.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/gvt/gvt.c b/drivers/gpu/drm/i915/gvt/gvt.c index 4e65266e7b95b..712f9d14e7200 100644 --- a/drivers/gpu/drm/i915/gvt/gvt.c +++ b/drivers/gpu/drm/i915/gvt/gvt.c @@ -468,3 +468,7 @@ int intel_gvt_init_device(struct drm_i915_private *dev_priv) kfree(gvt); return ret; } + +#if IS_ENABLED(CONFIG_DRM_I915_GVT_KVMGT) +MODULE_SOFTDEP("pre: kvmgt"); +#endif -- GitLab From 8cff1f4a3ca58ab426f224b4bd6af61c1a9976ab Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Mon, 9 Jul 2018 14:48:58 +0100 Subject: [PATCH 0914/1506] drm/i915: Remove function details from device error messages Error messages are intended to be addressed to the user; be clear, succinct, instructive and unambiguous. Adding the function name to that message does not add any information the user requires and in the process makes the message less clear. E.g. [ 245.539711] i915 0000:00:02.0: [drm:i915_gem_init [i915]] Failed to initialize GPU, declaring it wedged! becomes [ 245.539711] i915 0000:00:02.0: Failed to initialize GPU, declaring it wedged! Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Acked-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180709134858.12446-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_drv.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 2959c88a37a59..c2b9a4a0ee493 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -104,8 +104,13 @@ __i915_printk(struct drm_i915_private *dev_priv, const char *level, vaf.fmt = fmt; vaf.va = &args; - dev_printk(level, kdev, "[" DRM_NAME ":%ps] %pV", - __builtin_return_address(0), &vaf); + if (is_error) + dev_printk(level, kdev, "%pV", &vaf); + else + dev_printk(level, kdev, "[" DRM_NAME ":%ps] %pV", + __builtin_return_address(0), &vaf); + + va_end(args); if (is_error && !shown_bug_once) { /* @@ -117,8 +122,6 @@ __i915_printk(struct drm_i915_private *dev_priv, const char *level, dev_notice(kdev, "%s", FDO_BUG_MSG); shown_bug_once = true; } - - va_end(args); } /* Map PCH device id to PCH type, or PCH_NONE if unknown. */ -- GitLab From ebfa7944d6d951c77dca6911a252917f6cecaab3 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Tue, 10 Jul 2018 09:04:24 +0100 Subject: [PATCH 0915/1506] drm/i915/selftests: Constrain mock_gtt tests to fit within RAM Be pessimistic and presume that we actually allocate every page we exercise via the mock_gtt (e.g. for gvt). In which case we have to keep our working set under the available physical memory to prevent oom. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Matthew Auld <matthew.auld@intel.com> Reviewed-by: Matthew Auld <matthew.auld@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180710080424.7821-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/selftests/i915_gem_gtt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c index 600a3bcbd3d6e..8e2e269db97e8 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c @@ -1244,6 +1244,7 @@ static int exercise_mock(struct drm_i915_private *i915, u64 hole_start, u64 hole_end, unsigned long end_time)) { + const u64 limit = totalram_pages << PAGE_SHIFT; struct i915_gem_context *ctx; struct i915_hw_ppgtt *ppgtt; IGT_TIMEOUT(end_time); @@ -1256,7 +1257,7 @@ static int exercise_mock(struct drm_i915_private *i915, ppgtt = ctx->ppgtt; GEM_BUG_ON(!ppgtt); - err = func(i915, &ppgtt->vm, 0, ppgtt->vm.total, end_time); + err = func(i915, &ppgtt->vm, 0, min(ppgtt->vm.total, limit), end_time); mock_context_close(ctx); return err; -- GitLab From cecb368d2fe40e7f6a8166fef35abc69852f7501 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Mon, 9 Jul 2018 20:49:15 +0100 Subject: [PATCH 0916/1506] drm/i915/selftests: Filter out both physical address swizzles In our swizzling selftests, we cannot predict the physical address of the target page (at least not simply!) and so skip bit17 swizzles. However, there are two bit17 swizzle modes and we only skipped one, with the second being observed on the lab gdg causing the test to fail, as soon as we hit a page with bit17 set in its address. Testcase: igt/drv_selftest/live_objects #gdg Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Matthew Auld <matthew.auld@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180709194915.5789-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/selftests/i915_gem_object.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_object.c b/drivers/gpu/drm/i915/selftests/i915_gem_object.c index d77acf4cc4397..c69cbd5aed527 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_object.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_object.c @@ -375,7 +375,8 @@ static int igt_partial_tiling(void *arg) } GEM_BUG_ON(tile.swizzle == I915_BIT_6_SWIZZLE_UNKNOWN); - if (tile.swizzle == I915_BIT_6_SWIZZLE_9_10_17) + if (tile.swizzle == I915_BIT_6_SWIZZLE_9_17 || + tile.swizzle == I915_BIT_6_SWIZZLE_9_10_17) continue; if (INTEL_GEN(i915) <= 2) { -- GitLab From b7bb6138c2d5fc0a79a465478c7bbf74902289f7 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Mon, 9 Jul 2018 14:01:59 +0100 Subject: [PATCH 0917/1506] drm/i915: Only reset hangcheck at the start of an activity cycle Across a reset, the seqno (and thus hangcheck) should restart and the hangcheck naturally progress, for when it does not, we want to declare an emergency. Currently, we only detect if reset and reinit fails, but we do not detect if the call to reinit succeeds but the HW is fried - as we are resetting hangcheck on initialisation the engine. Remove that and rely on the natural progress to reset the hangcheck timer. References: e21b141376f9 ("drm/i915: Mark the hangcheck as idle when unparking the engines") References: 1fd00c0faeec ("drm/i915: Declare the driver wedged if hangcheck makes no progress") Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180709130208.11730-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_lrc.c | 1 - drivers/gpu/drm/i915/intel_ringbuffer.c | 2 -- 2 files changed, 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 6ab6ddb103d12..d937a21da2d80 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1853,7 +1853,6 @@ static int gen8_init_common_ring(struct intel_engine_cs *engine) return ret; intel_engine_reset_breadcrumbs(engine); - intel_engine_init_hangcheck(engine); if (GEM_SHOW_DEBUG() && unexpected_starting_state(engine)) { struct drm_printer p = drm_debug_printer(__func__); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index d248742b14739..fab83e3c15029 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -524,8 +524,6 @@ static int init_ring_common(struct intel_engine_cs *engine) goto out; } - intel_engine_init_hangcheck(engine); - if (INTEL_GEN(dev_priv) > 2) I915_WRITE_MODE(engine, _MASKED_BIT_DISABLE(STOP_RING)); -- GitLab From bf06112f869dd6a6c85a8d9fbbe879fb363011d6 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Mon, 9 Jul 2018 14:02:04 +0100 Subject: [PATCH 0918/1506] drm/i915: Tidy i915_gem_suspend() In the next patch, we will make a fairly minor change to flush outstanding resets before suspend. In order to keep churn to a minimum in that functional patch, we fix up the comments and coding style now. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180709130208.11730-7-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 50 +++++++++++++++++---------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index b35cbfd16c9c4..25728c9d27277 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5029,32 +5029,32 @@ void i915_gem_sanitize(struct drm_i915_private *i915) mutex_unlock(&i915->drm.struct_mutex); } -int i915_gem_suspend(struct drm_i915_private *dev_priv) +int i915_gem_suspend(struct drm_i915_private *i915) { - struct drm_device *dev = &dev_priv->drm; int ret; GEM_TRACE("\n"); - intel_runtime_pm_get(dev_priv); - intel_suspend_gt_powersave(dev_priv); + intel_runtime_pm_get(i915); + intel_suspend_gt_powersave(i915); - mutex_lock(&dev->struct_mutex); + mutex_lock(&i915->drm.struct_mutex); - /* We have to flush all the executing contexts to main memory so + /* + * We have to flush all the executing contexts to main memory so * that they can saved in the hibernation image. To ensure the last * context image is coherent, we have to switch away from it. That - * leaves the dev_priv->kernel_context still active when + * leaves the i915->kernel_context still active when * we actually suspend, and its image in memory may not match the GPU * state. Fortunately, the kernel_context is disposable and we do * not rely on its state. */ - if (!i915_terminally_wedged(&dev_priv->gpu_error)) { - ret = i915_gem_switch_to_kernel_context(dev_priv); + if (!i915_terminally_wedged(&i915->gpu_error)) { + ret = i915_gem_switch_to_kernel_context(i915); if (ret) goto err_unlock; - ret = i915_gem_wait_for_idle(dev_priv, + ret = i915_gem_wait_for_idle(i915, I915_WAIT_INTERRUPTIBLE | I915_WAIT_LOCKED | I915_WAIT_FOR_IDLE_BOOST, @@ -5062,33 +5062,35 @@ int i915_gem_suspend(struct drm_i915_private *dev_priv) if (ret && ret != -EIO) goto err_unlock; - assert_kernel_context_is_current(dev_priv); + assert_kernel_context_is_current(i915); } - mutex_unlock(&dev->struct_mutex); + mutex_unlock(&i915->drm.struct_mutex); - intel_uc_suspend(dev_priv); + intel_uc_suspend(i915); - cancel_delayed_work_sync(&dev_priv->gpu_error.hangcheck_work); - cancel_delayed_work_sync(&dev_priv->gt.retire_work); + cancel_delayed_work_sync(&i915->gpu_error.hangcheck_work); + cancel_delayed_work_sync(&i915->gt.retire_work); - /* As the idle_work is rearming if it detects a race, play safe and + /* + * As the idle_work is rearming if it detects a race, play safe and * repeat the flush until it is definitely idle. */ - drain_delayed_work(&dev_priv->gt.idle_work); + drain_delayed_work(&i915->gt.idle_work); - /* Assert that we sucessfully flushed all the work and + /* + * Assert that we successfully flushed all the work and * reset the GPU back to its idle, low power state. */ - WARN_ON(dev_priv->gt.awake); - if (WARN_ON(!intel_engines_are_idle(dev_priv))) - i915_gem_set_wedged(dev_priv); /* no hope, discard everything */ + WARN_ON(i915->gt.awake); + if (WARN_ON(!intel_engines_are_idle(i915))) + i915_gem_set_wedged(i915); /* no hope, discard everything */ - intel_runtime_pm_put(dev_priv); + intel_runtime_pm_put(i915); return 0; err_unlock: - mutex_unlock(&dev->struct_mutex); - intel_runtime_pm_put(dev_priv); + mutex_unlock(&i915->drm.struct_mutex); + intel_runtime_pm_put(i915); return ret; } -- GitLab From c76f0f7cb546b661b5e0ac769850a5c854927f65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org> Date: Tue, 3 Jul 2018 18:03:47 +0200 Subject: [PATCH 0919/1506] drm: Begin an API for in-kernel clients MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This the beginning of an API for in-kernel clients. First out is a way to get a framebuffer backed by a dumb buffer. Only GEM drivers are supported. The original idea of using an exported dma-buf was dropped because it also creates an anonomous file descriptor which doesn't work when the buffer is created from a kernel thread. The easy way out is to use drm_driver.gem_prime_vmap to get the virtual address, which requires a GEM object. This excludes the vmwgfx driver which is the only non-GEM driver apart from the legacy ones. A solution for vmwgfx will have to be worked out later if it wants to support the client API which it probably will when we have a bootsplash client. Suggested-by: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Noralf Trønnes <noralf@tronnes.org> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180703160354.59955-2-noralf@tronnes.org --- Documentation/gpu/drm-client.rst | 12 + Documentation/gpu/index.rst | 1 + drivers/gpu/drm/Makefile | 2 +- drivers/gpu/drm/drm_client.c | 387 +++++++++++++++++++++++++++++ drivers/gpu/drm/drm_drv.c | 8 + drivers/gpu/drm/drm_file.c | 3 + drivers/gpu/drm/drm_probe_helper.c | 3 + include/drm/drm_client.h | 136 ++++++++++ include/drm/drm_device.h | 21 ++ 9 files changed, 572 insertions(+), 1 deletion(-) create mode 100644 Documentation/gpu/drm-client.rst create mode 100644 drivers/gpu/drm/drm_client.c create mode 100644 include/drm/drm_client.h diff --git a/Documentation/gpu/drm-client.rst b/Documentation/gpu/drm-client.rst new file mode 100644 index 0000000000000..7e672063e7eb6 --- /dev/null +++ b/Documentation/gpu/drm-client.rst @@ -0,0 +1,12 @@ +================= +Kernel clients +================= + +.. kernel-doc:: drivers/gpu/drm/drm_client.c + :doc: overview + +.. kernel-doc:: include/drm/drm_client.h + :internal: + +.. kernel-doc:: drivers/gpu/drm/drm_client.c + :export: diff --git a/Documentation/gpu/index.rst b/Documentation/gpu/index.rst index 00288f34c5a63..1fcf8e851e154 100644 --- a/Documentation/gpu/index.rst +++ b/Documentation/gpu/index.rst @@ -10,6 +10,7 @@ Linux GPU Driver Developer's Guide drm-kms drm-kms-helpers drm-uapi + drm-client drivers vga-switcheroo vgaarbiter diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 6ae535ca09141..0e0a3ef1abadc 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -18,7 +18,7 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \ drm_encoder.o drm_mode_object.o drm_property.o \ drm_plane.o drm_color_mgmt.o drm_print.o \ drm_dumb_buffers.o drm_mode_config.o drm_vblank.o \ - drm_syncobj.o drm_lease.o drm_writeback.o + drm_syncobj.o drm_lease.o drm_writeback.o drm_client.o drm-$(CONFIG_DRM_LIB_RANDOM) += lib/drm_random.o drm-$(CONFIG_DRM_VM) += drm_vm.o diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c new file mode 100644 index 0000000000000..743495f7f833b --- /dev/null +++ b/drivers/gpu/drm/drm_client.c @@ -0,0 +1,387 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2018 Noralf Trønnes + */ + +#include <linux/list.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/seq_file.h> +#include <linux/slab.h> + +#include <drm/drm_client.h> +#include <drm/drm_debugfs.h> +#include <drm/drm_device.h> +#include <drm/drm_drv.h> +#include <drm/drm_file.h> +#include <drm/drm_fourcc.h> +#include <drm/drm_gem.h> +#include <drm/drm_mode.h> +#include <drm/drm_print.h> +#include <drm/drmP.h> + +#include "drm_crtc_internal.h" +#include "drm_internal.h" + +/** + * DOC: overview + * + * This library provides support for clients running in the kernel like fbdev and bootsplash. + * Currently it's only partially implemented, just enough to support fbdev. + * + * GEM drivers which provide a GEM based dumb buffer with a virtual address are supported. + */ + +static int drm_client_open(struct drm_client_dev *client) +{ + struct drm_device *dev = client->dev; + struct drm_file *file; + + file = drm_file_alloc(dev->primary); + if (IS_ERR(file)) + return PTR_ERR(file); + + mutex_lock(&dev->filelist_mutex); + list_add(&file->lhead, &dev->filelist_internal); + mutex_unlock(&dev->filelist_mutex); + + client->file = file; + + return 0; +} + +static void drm_client_close(struct drm_client_dev *client) +{ + struct drm_device *dev = client->dev; + + mutex_lock(&dev->filelist_mutex); + list_del(&client->file->lhead); + mutex_unlock(&dev->filelist_mutex); + + drm_file_free(client->file); +} +EXPORT_SYMBOL(drm_client_close); + +/** + * drm_client_new - Create a DRM client + * @dev: DRM device + * @client: DRM client + * @name: Client name + * @funcs: DRM client functions (optional) + * + * The caller needs to hold a reference on @dev before calling this function. + * The client is freed when the &drm_device is unregistered. See drm_client_release(). + * + * Returns: + * Zero on success or negative error code on failure. + */ +int drm_client_new(struct drm_device *dev, struct drm_client_dev *client, + const char *name, const struct drm_client_funcs *funcs) +{ + bool registered; + int ret; + + if (!drm_core_check_feature(dev, DRIVER_MODESET) || + !dev->driver->dumb_create || !dev->driver->gem_prime_vmap) + return -ENOTSUPP; + + if (funcs && !try_module_get(funcs->owner)) + return -ENODEV; + + client->dev = dev; + client->name = name; + client->funcs = funcs; + + ret = drm_client_open(client); + if (ret) + goto err_put_module; + + mutex_lock(&dev->clientlist_mutex); + registered = dev->registered; + if (registered) + list_add(&client->list, &dev->clientlist); + mutex_unlock(&dev->clientlist_mutex); + if (!registered) { + ret = -ENODEV; + goto err_close; + } + + drm_dev_get(dev); + + return 0; + +err_close: + drm_client_close(client); +err_put_module: + if (funcs) + module_put(funcs->owner); + + return ret; +} +EXPORT_SYMBOL(drm_client_new); + +/** + * drm_client_release - Release DRM client resources + * @client: DRM client + * + * Releases resources by closing the &drm_file that was opened by drm_client_new(). + * It is called automatically if the &drm_client_funcs.unregister callback is _not_ set. + * + * This function should only be called from the unregister callback. An exception + * is fbdev which cannot free the buffer if userspace has open file descriptors. + * + * Note: + * Clients cannot initiate a release by themselves. This is done to keep the code simple. + * The driver has to be unloaded before the client can be unloaded. + */ +void drm_client_release(struct drm_client_dev *client) +{ + struct drm_device *dev = client->dev; + + DRM_DEV_DEBUG_KMS(dev->dev, "%s\n", client->name); + + drm_client_close(client); + drm_dev_put(dev); + if (client->funcs) + module_put(client->funcs->owner); +} +EXPORT_SYMBOL(drm_client_release); + +void drm_client_dev_unregister(struct drm_device *dev) +{ + struct drm_client_dev *client, *tmp; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return; + + mutex_lock(&dev->clientlist_mutex); + list_for_each_entry_safe(client, tmp, &dev->clientlist, list) { + list_del(&client->list); + if (client->funcs && client->funcs->unregister) { + client->funcs->unregister(client); + } else { + drm_client_release(client); + kfree(client); + } + } + mutex_unlock(&dev->clientlist_mutex); +} + +/** + * drm_client_dev_hotplug - Send hotplug event to clients + * @dev: DRM device + * + * This function calls the &drm_client_funcs.hotplug callback on the attached clients. + * + * drm_kms_helper_hotplug_event() calls this function, so drivers that use it + * don't need to call this function themselves. + */ +void drm_client_dev_hotplug(struct drm_device *dev) +{ + struct drm_client_dev *client; + int ret; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return; + + mutex_lock(&dev->clientlist_mutex); + list_for_each_entry(client, &dev->clientlist, list) { + if (!client->funcs || !client->funcs->hotplug) + continue; + + ret = client->funcs->hotplug(client); + DRM_DEV_DEBUG_KMS(dev->dev, "%s: ret=%d\n", client->name, ret); + } + mutex_unlock(&dev->clientlist_mutex); +} +EXPORT_SYMBOL(drm_client_dev_hotplug); + +void drm_client_dev_restore(struct drm_device *dev) +{ + struct drm_client_dev *client; + int ret; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return; + + mutex_lock(&dev->clientlist_mutex); + list_for_each_entry(client, &dev->clientlist, list) { + if (!client->funcs || !client->funcs->restore) + continue; + + ret = client->funcs->restore(client); + DRM_DEV_DEBUG_KMS(dev->dev, "%s: ret=%d\n", client->name, ret); + if (!ret) /* The first one to return zero gets the privilege to restore */ + break; + } + mutex_unlock(&dev->clientlist_mutex); +} + +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); + + if (buffer->gem) + drm_gem_object_put_unlocked(buffer->gem); + + drm_mode_destroy_dumb(dev, buffer->handle, buffer->client->file); + kfree(buffer); +} + +static struct drm_client_buffer * +drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format) +{ + struct drm_mode_create_dumb dumb_args = { }; + struct drm_device *dev = client->dev; + struct drm_client_buffer *buffer; + struct drm_gem_object *obj; + void *vaddr; + int ret; + + buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); + if (!buffer) + return ERR_PTR(-ENOMEM); + + buffer->client = client; + + dumb_args.width = width; + dumb_args.height = height; + dumb_args.bpp = drm_format_plane_cpp(format, 0) * 8; + ret = drm_mode_create_dumb(dev, &dumb_args, client->file); + if (ret) + goto err_free; + + buffer->handle = dumb_args.handle; + buffer->pitch = dumb_args.pitch; + + obj = drm_gem_object_lookup(client->file, dumb_args.handle); + if (!obj) { + ret = -ENOENT; + goto err_delete; + } + + buffer->gem = obj; + + /* + * FIXME: The dependency on GEM here isn't required, we could + * convert the driver handle to a dma-buf instead and use the + * backend-agnostic dma-buf vmap support instead. This would + * require that the handle2fd prime ioctl is reworked to pull the + * 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; + goto err_delete; + } + + buffer->vaddr = vaddr; + + return buffer; + +err_delete: + drm_client_buffer_delete(buffer); +err_free: + kfree(buffer); + + return ERR_PTR(ret); +} + +static void drm_client_buffer_rmfb(struct drm_client_buffer *buffer) +{ + int ret; + + if (!buffer->fb) + return; + + ret = drm_mode_rmfb(buffer->client->dev, buffer->fb->base.id, buffer->client->file); + if (ret) + DRM_DEV_ERROR(buffer->client->dev->dev, + "Error removing FB:%u (%d)\n", buffer->fb->base.id, ret); + + buffer->fb = NULL; +} + +static int drm_client_buffer_addfb(struct drm_client_buffer *buffer, + u32 width, u32 height, u32 format) +{ + struct drm_client_dev *client = buffer->client; + struct drm_mode_fb_cmd fb_req = { }; + const struct drm_format_info *info; + int ret; + + info = drm_format_info(format); + fb_req.bpp = info->cpp[0] * 8; + fb_req.depth = info->depth; + fb_req.width = width; + fb_req.height = height; + fb_req.handle = buffer->handle; + fb_req.pitch = buffer->pitch; + + ret = drm_mode_addfb(client->dev, &fb_req, client->file); + if (ret) + return ret; + + buffer->fb = drm_framebuffer_lookup(client->dev, buffer->client->file, fb_req.fb_id); + if (WARN_ON(!buffer->fb)) + return -ENOENT; + + /* drop the reference we picked up in framebuffer lookup */ + drm_framebuffer_put(buffer->fb); + + strscpy(buffer->fb->comm, client->name, TASK_COMM_LEN); + + return 0; +} + +/** + * drm_client_framebuffer_create - Create a client framebuffer + * @client: DRM client + * @width: Framebuffer width + * @height: Framebuffer height + * @format: Buffer format + * + * This function creates a &drm_client_buffer which consists of a + * &drm_framebuffer backed by a dumb buffer. + * Call drm_client_framebuffer_delete() to free the buffer. + * + * Returns: + * Pointer to a client buffer or an error pointer on failure. + */ +struct drm_client_buffer * +drm_client_framebuffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format) +{ + struct drm_client_buffer *buffer; + int ret; + + buffer = drm_client_buffer_create(client, width, height, format); + if (IS_ERR(buffer)) + return buffer; + + ret = drm_client_buffer_addfb(buffer, width, height, format); + if (ret) { + drm_client_buffer_delete(buffer); + return ERR_PTR(ret); + } + + return buffer; +} +EXPORT_SYMBOL(drm_client_framebuffer_create); + +/** + * drm_client_framebuffer_delete - Delete a client framebuffer + * @buffer: DRM client buffer (can be NULL) + */ +void drm_client_framebuffer_delete(struct drm_client_buffer *buffer) +{ + if (!buffer) + return; + + drm_client_buffer_rmfb(buffer); + drm_client_buffer_delete(buffer); +} +EXPORT_SYMBOL(drm_client_framebuffer_delete); diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 7af748ed1c58d..6eb935bb2f92f 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -34,6 +34,7 @@ #include <linux/slab.h> #include <linux/srcu.h> +#include <drm/drm_client.h> #include <drm/drm_drv.h> #include <drm/drmP.h> @@ -505,6 +506,8 @@ int drm_dev_init(struct drm_device *dev, dev->driver = driver; INIT_LIST_HEAD(&dev->filelist); + INIT_LIST_HEAD(&dev->filelist_internal); + INIT_LIST_HEAD(&dev->clientlist); INIT_LIST_HEAD(&dev->ctxlist); INIT_LIST_HEAD(&dev->vmalist); INIT_LIST_HEAD(&dev->maplist); @@ -514,6 +517,7 @@ int drm_dev_init(struct drm_device *dev, spin_lock_init(&dev->event_lock); mutex_init(&dev->struct_mutex); mutex_init(&dev->filelist_mutex); + mutex_init(&dev->clientlist_mutex); mutex_init(&dev->ctxlist_mutex); mutex_init(&dev->master_mutex); @@ -569,6 +573,7 @@ int drm_dev_init(struct drm_device *dev, err_free: mutex_destroy(&dev->master_mutex); mutex_destroy(&dev->ctxlist_mutex); + mutex_destroy(&dev->clientlist_mutex); mutex_destroy(&dev->filelist_mutex); mutex_destroy(&dev->struct_mutex); return ret; @@ -603,6 +608,7 @@ void drm_dev_fini(struct drm_device *dev) mutex_destroy(&dev->master_mutex); mutex_destroy(&dev->ctxlist_mutex); + mutex_destroy(&dev->clientlist_mutex); mutex_destroy(&dev->filelist_mutex); mutex_destroy(&dev->struct_mutex); kfree(dev->unique); @@ -858,6 +864,8 @@ void drm_dev_unregister(struct drm_device *dev) dev->registered = false; + drm_client_dev_unregister(dev); + if (drm_core_check_feature(dev, DRIVER_MODESET)) drm_modeset_unregister_all(dev); diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c index 66bb403dc8abb..ffa8dc35515ff 100644 --- a/drivers/gpu/drm/drm_file.c +++ b/drivers/gpu/drm/drm_file.c @@ -35,6 +35,7 @@ #include <linux/slab.h> #include <linux/module.h> +#include <drm/drm_client.h> #include <drm/drm_file.h> #include <drm/drmP.h> @@ -444,6 +445,8 @@ void drm_lastclose(struct drm_device * dev) if (drm_core_check_feature(dev, DRIVER_LEGACY)) drm_legacy_dev_reinit(dev); + + drm_client_dev_restore(dev); } /** diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 1a901fe9e23e7..34fe2704a31c0 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -33,6 +33,7 @@ #include <linux/moduleparam.h> #include <drm/drmP.h> +#include <drm/drm_client.h> #include <drm/drm_crtc.h> #include <drm/drm_fourcc.h> #include <drm/drm_crtc_helper.h> @@ -559,6 +560,8 @@ void drm_kms_helper_hotplug_event(struct drm_device *dev) drm_sysfs_hotplug_event(dev); if (dev->mode_config.funcs->output_poll_changed) dev->mode_config.funcs->output_poll_changed(dev); + + drm_client_dev_hotplug(dev); } EXPORT_SYMBOL(drm_kms_helper_hotplug_event); diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h new file mode 100644 index 0000000000000..671052d80e38b --- /dev/null +++ b/include/drm/drm_client.h @@ -0,0 +1,136 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _DRM_CLIENT_H_ +#define _DRM_CLIENT_H_ + +#include <linux/types.h> + +struct drm_client_dev; +struct drm_device; +struct drm_file; +struct drm_framebuffer; +struct drm_gem_object; +struct module; + +/** + * struct drm_client_funcs - DRM client callbacks + */ +struct drm_client_funcs { + /** + * @owner: The module owner + */ + struct module *owner; + + /** + * @unregister: + * + * Called when &drm_device is unregistered. The client should respond by + * releasing it's resources using drm_client_release(). + * + * This callback is optional. + */ + void (*unregister)(struct drm_client_dev *client); + + /** + * @restore: + * + * Called on drm_lastclose(). The first client instance in the list that + * returns zero gets the privilege to restore and no more clients are + * called. This callback is not called after @unregister has been called. + * + * This callback is optional. + */ + int (*restore)(struct drm_client_dev *client); + + /** + * @hotplug: + * + * Called on drm_kms_helper_hotplug_event(). + * This callback is not called after @unregister has been called. + * + * This callback is optional. + */ + int (*hotplug)(struct drm_client_dev *client); +}; + +/** + * struct drm_client_dev - DRM client instance + */ +struct drm_client_dev { + /** + * @dev: DRM device + */ + struct drm_device *dev; + + /** + * @name: Name of the client. + */ + const char *name; + + /** + * @list: + * + * List of all clients of a DRM device, linked into + * &drm_device.clientlist. Protected by &drm_device.clientlist_mutex. + */ + struct list_head list; + + /** + * @funcs: DRM client functions (optional) + */ + const struct drm_client_funcs *funcs; + + /** + * @file: DRM file + */ + struct drm_file *file; +}; + +int drm_client_new(struct drm_device *dev, struct drm_client_dev *client, + const char *name, const struct drm_client_funcs *funcs); +void drm_client_release(struct drm_client_dev *client); + +void drm_client_dev_unregister(struct drm_device *dev); +void drm_client_dev_hotplug(struct drm_device *dev); +void drm_client_dev_restore(struct drm_device *dev); + +/** + * struct drm_client_buffer - DRM client buffer + */ +struct drm_client_buffer { + /** + * @client: DRM client + */ + struct drm_client_dev *client; + + /** + * @handle: Buffer handle + */ + u32 handle; + + /** + * @pitch: Buffer pitch + */ + u32 pitch; + + /** + * @gem: GEM object backing this buffer + */ + struct drm_gem_object *gem; + + /** + * @vaddr: Virtual address for the buffer + */ + void *vaddr; + + /** + * @fb: DRM framebuffer + */ + struct drm_framebuffer *fb; +}; + +struct drm_client_buffer * +drm_client_framebuffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format); +void drm_client_framebuffer_delete(struct drm_client_buffer *buffer); + +#endif diff --git a/include/drm/drm_device.h b/include/drm/drm_device.h index 858ba19a3e293..f9c6e0e3aec7d 100644 --- a/include/drm/drm_device.h +++ b/include/drm/drm_device.h @@ -74,6 +74,27 @@ struct drm_device { struct mutex filelist_mutex; struct list_head filelist; + /** + * @filelist_internal: + * + * List of open DRM files for in-kernel clients. Protected by @filelist_mutex. + */ + struct list_head filelist_internal; + + /** + * @clientlist_mutex: + * + * Protects @clientlist access. + */ + struct mutex clientlist_mutex; + + /** + * @clientlist: + * + * List of in-kernel clients. Protected by @clientlist_mutex. + */ + struct list_head clientlist; + /** \name Memory management */ /*@{ */ struct list_head maplist; /**< Linked list of regions */ -- GitLab From d536540f304ce0ee35db9f67f7d880bc09f3743f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org> Date: Tue, 3 Jul 2018 18:03:48 +0200 Subject: [PATCH 0920/1506] drm/fb-helper: Add generic fbdev emulation .fb_probe function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is the first step in getting generic fbdev emulation. A drm_fb_helper_funcs.fb_probe function is added which uses the DRM client API to get a framebuffer backed by a dumb buffer. Signed-off-by: Noralf Trønnes <noralf@tronnes.org> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180703160354.59955-3-noralf@tronnes.org --- drivers/gpu/drm/drm_fb_helper.c | 199 +++++++++++++++++++++++++++++++- include/drm/drm_fb_helper.h | 31 +++++ 2 files changed, 229 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index d697c1c4a0678..7e29d5340a170 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -30,6 +30,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/console.h> +#include <linux/dma-buf.h> #include <linux/kernel.h> #include <linux/sysrq.h> #include <linux/slab.h> @@ -738,6 +739,24 @@ static void drm_fb_helper_resume_worker(struct work_struct *work) console_unlock(); } +static void drm_fb_helper_dirty_blit_real(struct drm_fb_helper *fb_helper, + struct drm_clip_rect *clip) +{ + struct drm_framebuffer *fb = fb_helper->fb; + unsigned int cpp = drm_format_plane_cpp(fb->format->format, 0); + size_t offset = clip->y1 * fb->pitches[0] + clip->x1 * cpp; + void *src = fb_helper->fbdev->screen_buffer + offset; + void *dst = fb_helper->buffer->vaddr + offset; + size_t len = (clip->x2 - clip->x1) * cpp; + unsigned int y; + + for (y = clip->y1; y < clip->y2; y++) { + memcpy(dst, src, len); + src += fb->pitches[0]; + dst += fb->pitches[0]; + } +} + static void drm_fb_helper_dirty_work(struct work_struct *work) { struct drm_fb_helper *helper = container_of(work, struct drm_fb_helper, @@ -753,8 +772,12 @@ static void drm_fb_helper_dirty_work(struct work_struct *work) spin_unlock_irqrestore(&helper->dirty_lock, flags); /* call dirty callback only when it has been really touched */ - if (clip_copy.x1 < clip_copy.x2 && clip_copy.y1 < clip_copy.y2) + if (clip_copy.x1 < clip_copy.x2 && clip_copy.y1 < clip_copy.y2) { + /* Generic fbdev uses a shadow buffer */ + if (helper->buffer) + drm_fb_helper_dirty_blit_real(helper, &clip_copy); helper->fb->funcs->dirty(helper->fb, NULL, 0, 0, &clip_copy, 1); + } } /** @@ -2921,6 +2944,180 @@ void drm_fb_helper_output_poll_changed(struct drm_device *dev) } EXPORT_SYMBOL(drm_fb_helper_output_poll_changed); +/* @user: 1=userspace, 0=fbcon */ +static int drm_fbdev_fb_open(struct fb_info *info, int user) +{ + struct drm_fb_helper *fb_helper = info->par; + + if (!try_module_get(fb_helper->dev->driver->fops->owner)) + return -ENODEV; + + return 0; +} + +static int drm_fbdev_fb_release(struct fb_info *info, int user) +{ + struct drm_fb_helper *fb_helper = info->par; + + module_put(fb_helper->dev->driver->fops->owner); + + return 0; +} + +/* + * fb_ops.fb_destroy is called by the last put_fb_info() call at the end of + * unregister_framebuffer() or fb_release(). + */ +static void drm_fbdev_fb_destroy(struct fb_info *info) +{ + struct drm_fb_helper *fb_helper = info->par; + struct fb_info *fbi = fb_helper->fbdev; + struct fb_ops *fbops = NULL; + void *shadow = NULL; + + if (fbi->fbdefio) { + fb_deferred_io_cleanup(fbi); + shadow = fbi->screen_buffer; + fbops = fbi->fbops; + } + + drm_fb_helper_fini(fb_helper); + + if (shadow) { + vfree(shadow); + kfree(fbops); + } + + drm_client_framebuffer_delete(fb_helper->buffer); + /* + * FIXME: + * Remove conditional when all CMA drivers have been moved over to using + * drm_fbdev_generic_setup(). + */ + if (fb_helper->client.funcs) { + drm_client_release(&fb_helper->client); + kfree(fb_helper); + } +} + +static int drm_fbdev_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) +{ + struct drm_fb_helper *fb_helper = info->par; + + if (fb_helper->dev->driver->gem_prime_mmap) + return fb_helper->dev->driver->gem_prime_mmap(fb_helper->buffer->gem, vma); + else + return -ENODEV; +} + +static struct fb_ops drm_fbdev_fb_ops = { + .owner = THIS_MODULE, + DRM_FB_HELPER_DEFAULT_OPS, + .fb_open = drm_fbdev_fb_open, + .fb_release = drm_fbdev_fb_release, + .fb_destroy = drm_fbdev_fb_destroy, + .fb_mmap = drm_fbdev_fb_mmap, + .fb_read = drm_fb_helper_sys_read, + .fb_write = drm_fb_helper_sys_write, + .fb_fillrect = drm_fb_helper_sys_fillrect, + .fb_copyarea = drm_fb_helper_sys_copyarea, + .fb_imageblit = drm_fb_helper_sys_imageblit, +}; + +static struct fb_deferred_io drm_fbdev_defio = { + .delay = HZ / 20, + .deferred_io = drm_fb_helper_deferred_io, +}; + +/** + * drm_fb_helper_generic_probe - Generic fbdev emulation probe helper + * @fb_helper: fbdev helper structure + * @sizes: describes fbdev size and scanout surface size + * + * This function uses the client API to crate a framebuffer backed by a dumb buffer. + * + * The _sys_ versions are used for &fb_ops.fb_read, fb_write, fb_fillrect, + * fb_copyarea, fb_imageblit. + * + * Returns: + * Zero on success or negative error code on failure. + */ +int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper, + struct drm_fb_helper_surface_size *sizes) +{ + struct drm_client_dev *client = &fb_helper->client; + struct drm_client_buffer *buffer; + struct drm_framebuffer *fb; + struct fb_info *fbi; + u32 format; + int ret; + + DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d)\n", + sizes->surface_width, sizes->surface_height, + sizes->surface_bpp); + + format = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth); + buffer = drm_client_framebuffer_create(client, sizes->surface_width, + sizes->surface_height, format); + if (IS_ERR(buffer)) + return PTR_ERR(buffer); + + fb_helper->buffer = buffer; + fb_helper->fb = buffer->fb; + fb = buffer->fb; + + fbi = drm_fb_helper_alloc_fbi(fb_helper); + if (IS_ERR(fbi)) { + ret = PTR_ERR(fbi); + goto err_free_buffer; + } + + fbi->par = fb_helper; + fbi->fbops = &drm_fbdev_fb_ops; + fbi->screen_size = fb->height * fb->pitches[0]; + fbi->fix.smem_len = fbi->screen_size; + fbi->screen_buffer = buffer->vaddr; + strcpy(fbi->fix.id, "DRM emulated"); + + drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->format->depth); + drm_fb_helper_fill_var(fbi, fb_helper, sizes->fb_width, sizes->fb_height); + + if (fb->funcs->dirty) { + struct fb_ops *fbops; + void *shadow; + + /* + * fb_deferred_io_cleanup() clears &fbops->fb_mmap so a per + * instance version is necessary. + */ + fbops = kzalloc(sizeof(*fbops), GFP_KERNEL); + shadow = vzalloc(fbi->screen_size); + if (!fbops || !shadow) { + kfree(fbops); + vfree(shadow); + ret = -ENOMEM; + goto err_fb_info_destroy; + } + + *fbops = *fbi->fbops; + fbi->fbops = fbops; + fbi->screen_buffer = shadow; + fbi->fbdefio = &drm_fbdev_defio; + + fb_deferred_io_init(fbi); + } + + return 0; + +err_fb_info_destroy: + drm_fb_helper_fini(fb_helper); +err_free_buffer: + drm_client_framebuffer_delete(buffer); + + return ret; +} +EXPORT_SYMBOL(drm_fb_helper_generic_probe); + /* The Kconfig DRM_KMS_HELPER selects FRAMEBUFFER_CONSOLE (if !EXPERT) * but the module doesn't depend on any fb console symbols. At least * attempt to load fbcon to avoid leaving the system without a usable console. diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index b069433e7fc12..c134bbcfd2e96 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -32,6 +32,7 @@ struct drm_fb_helper; +#include <drm/drm_client.h> #include <drm/drm_crtc.h> #include <drm/drm_device.h> #include <linux/kgdb.h> @@ -154,6 +155,20 @@ struct drm_fb_helper_connector { * operations. */ struct drm_fb_helper { + /** + * @client: + * + * DRM client used by the generic fbdev emulation. + */ + struct drm_client_dev client; + + /** + * @buffer: + * + * Framebuffer used by the generic fbdev emulation. + */ + struct drm_client_buffer *buffer; + struct drm_framebuffer *fb; struct drm_device *dev; int crtc_count; @@ -234,6 +249,12 @@ struct drm_fb_helper { int preferred_bpp; }; +static inline struct drm_fb_helper * +drm_fb_helper_from_client(struct drm_client_dev *client) +{ + return container_of(client, struct drm_fb_helper, client); +} + /** * define DRM_FB_HELPER_DEFAULT_OPS - helper define for drm drivers * @@ -330,6 +351,9 @@ void drm_fb_helper_fbdev_teardown(struct drm_device *dev); void drm_fb_helper_lastclose(struct drm_device *dev); void drm_fb_helper_output_poll_changed(struct drm_device *dev); + +int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper, + struct drm_fb_helper_surface_size *sizes); #else static inline void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper, @@ -564,6 +588,13 @@ static inline void drm_fb_helper_output_poll_changed(struct drm_device *dev) { } +static inline int +drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper, + struct drm_fb_helper_surface_size *sizes) +{ + return 0; +} + #endif static inline int -- GitLab From 244007ecb6bb94fa4e9b9a969fa86f2ad86ec543 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org> Date: Tue, 3 Jul 2018 18:03:49 +0200 Subject: [PATCH 0921/1506] drm/pl111: Set .gem_prime_vmap and .gem_prime_mmap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These are needed for pl111 to use the generic fbdev emulation. Cc: Eric Anholt <eric@anholt.net> Signed-off-by: Noralf Trønnes <noralf@tronnes.org> Reviewed-by: Eric Anholt <eric@anholt.net> Link: https://patchwork.freedesktop.org/patch/msgid/20180703160354.59955-4-noralf@tronnes.org --- drivers/gpu/drm/pl111/pl111_drv.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/pl111/pl111_drv.c b/drivers/gpu/drm/pl111/pl111_drv.c index 054b93689d944..17a38e85ba7dd 100644 --- a/drivers/gpu/drm/pl111/pl111_drv.c +++ b/drivers/gpu/drm/pl111/pl111_drv.c @@ -250,6 +250,8 @@ static struct drm_driver pl111_drm_driver = { .gem_prime_import_sg_table = pl111_gem_import_sg_table, .gem_prime_export = drm_gem_prime_export, .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, + .gem_prime_mmap = drm_gem_cma_prime_mmap, + .gem_prime_vmap = drm_gem_cma_prime_vmap, #if defined(CONFIG_DEBUG_FS) .debugfs_init = pl111_debugfs_init, -- GitLab From 894a677f4b3e6d2ab8d01bb46c1fbd5f92e4591b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org> Date: Tue, 3 Jul 2018 18:03:50 +0200 Subject: [PATCH 0922/1506] drm/cma-helper: Use the generic fbdev emulation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This switches the CMA helper drivers that use its fbdev emulation over to the generic fbdev emulation. It's the first phase of using generic fbdev. A later phase will use DRM client callbacks for the lastclose/hotplug/remove callbacks. There are currently 2 fbdev init/fini functions: - drm_fb_cma_fbdev_init/drm_fb_cma_fbdev_fini - drm_fbdev_cma_init/drm_fbdev_cma_fini This is because the work on generic fbdev came up during a fbdev refactoring and thus wasn't completed. No point in completing that refactoring when drivers will soon move to drm_fb_helper_generic_probe(). tinydrm uses drm_fb_cma_fbdev_init_with_funcs(). Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Noralf Trønnes <noralf@tronnes.org> Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180703160354.59955-5-noralf@tronnes.org --- drivers/gpu/drm/drm_fb_cma_helper.c | 338 +++------------------------- include/drm/drm_fb_cma_helper.h | 3 - 2 files changed, 31 insertions(+), 310 deletions(-) diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c index 186d00adfb5f8..718c7f961d8ad 100644 --- a/drivers/gpu/drm/drm_fb_cma_helper.c +++ b/drivers/gpu/drm/drm_fb_cma_helper.c @@ -18,6 +18,7 @@ */ #include <drm/drmP.h> +#include <drm/drm_client.h> #include <drm/drm_fb_helper.h> #include <drm/drm_framebuffer.h> #include <drm/drm_gem_cma_helper.h> @@ -26,11 +27,8 @@ #include <drm/drm_print.h> #include <linux/module.h> -#define DEFAULT_FBDEFIO_DELAY_MS 50 - struct drm_fbdev_cma { struct drm_fb_helper fb_helper; - const struct drm_framebuffer_funcs *fb_funcs; }; /** @@ -44,36 +42,6 @@ struct drm_fbdev_cma { * * An fbdev framebuffer backed by cma is also available by calling * drm_fb_cma_fbdev_init(). drm_fb_cma_fbdev_fini() tears it down. - * If the &drm_framebuffer_funcs.dirty callback is set, fb_deferred_io will be - * set up automatically. &drm_framebuffer_funcs.dirty is called by - * drm_fb_helper_deferred_io() in process context (&struct delayed_work). - * - * Example fbdev deferred io code:: - * - * static int driver_fb_dirty(struct drm_framebuffer *fb, - * struct drm_file *file_priv, - * unsigned flags, unsigned color, - * struct drm_clip_rect *clips, - * unsigned num_clips) - * { - * struct drm_gem_cma_object *cma = drm_fb_cma_get_gem_obj(fb, 0); - * ... push changes ... - * return 0; - * } - * - * static struct drm_framebuffer_funcs driver_fb_funcs = { - * .destroy = drm_gem_fb_destroy, - * .create_handle = drm_gem_fb_create_handle, - * .dirty = driver_fb_dirty, - * }; - * - * Initialize:: - * - * fbdev = drm_fb_cma_fbdev_init_with_funcs(dev, 16, - * dev->mode_config.num_crtc, - * dev->mode_config.num_connector, - * &driver_fb_funcs); - * */ static inline struct drm_fbdev_cma *to_fbdev_cma(struct drm_fb_helper *helper) @@ -131,153 +99,6 @@ dma_addr_t drm_fb_cma_get_gem_addr(struct drm_framebuffer *fb, } EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_addr); -static int drm_fb_cma_mmap(struct fb_info *info, struct vm_area_struct *vma) -{ - return dma_mmap_writecombine(info->device, vma, info->screen_base, - info->fix.smem_start, info->fix.smem_len); -} - -static struct fb_ops drm_fbdev_cma_ops = { - .owner = THIS_MODULE, - DRM_FB_HELPER_DEFAULT_OPS, - .fb_fillrect = drm_fb_helper_sys_fillrect, - .fb_copyarea = drm_fb_helper_sys_copyarea, - .fb_imageblit = drm_fb_helper_sys_imageblit, - .fb_mmap = drm_fb_cma_mmap, -}; - -static int drm_fbdev_cma_deferred_io_mmap(struct fb_info *info, - struct vm_area_struct *vma) -{ - fb_deferred_io_mmap(info, vma); - vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); - - return 0; -} - -static int drm_fbdev_cma_defio_init(struct fb_info *fbi, - struct drm_gem_cma_object *cma_obj) -{ - struct fb_deferred_io *fbdefio; - struct fb_ops *fbops; - - /* - * Per device structures are needed because: - * fbops: fb_deferred_io_cleanup() clears fbops.fb_mmap - * fbdefio: individual delays - */ - fbdefio = kzalloc(sizeof(*fbdefio), GFP_KERNEL); - fbops = kzalloc(sizeof(*fbops), GFP_KERNEL); - if (!fbdefio || !fbops) { - kfree(fbdefio); - kfree(fbops); - return -ENOMEM; - } - - /* can't be offset from vaddr since dirty() uses cma_obj */ - fbi->screen_buffer = cma_obj->vaddr; - /* fb_deferred_io_fault() needs a physical address */ - fbi->fix.smem_start = page_to_phys(virt_to_page(fbi->screen_buffer)); - - *fbops = *fbi->fbops; - fbi->fbops = fbops; - - fbdefio->delay = msecs_to_jiffies(DEFAULT_FBDEFIO_DELAY_MS); - fbdefio->deferred_io = drm_fb_helper_deferred_io; - fbi->fbdefio = fbdefio; - fb_deferred_io_init(fbi); - fbi->fbops->fb_mmap = drm_fbdev_cma_deferred_io_mmap; - - return 0; -} - -static void drm_fbdev_cma_defio_fini(struct fb_info *fbi) -{ - if (!fbi->fbdefio) - return; - - fb_deferred_io_cleanup(fbi); - kfree(fbi->fbdefio); - kfree(fbi->fbops); -} - -static int -drm_fbdev_cma_create(struct drm_fb_helper *helper, - struct drm_fb_helper_surface_size *sizes) -{ - struct drm_fbdev_cma *fbdev_cma = to_fbdev_cma(helper); - struct drm_device *dev = helper->dev; - struct drm_gem_cma_object *obj; - struct drm_framebuffer *fb; - unsigned int bytes_per_pixel; - unsigned long offset; - struct fb_info *fbi; - size_t size; - int ret; - - DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d)\n", - sizes->surface_width, sizes->surface_height, - sizes->surface_bpp); - - bytes_per_pixel = DIV_ROUND_UP(sizes->surface_bpp, 8); - size = sizes->surface_width * sizes->surface_height * bytes_per_pixel; - obj = drm_gem_cma_create(dev, size); - if (IS_ERR(obj)) - return -ENOMEM; - - fbi = drm_fb_helper_alloc_fbi(helper); - if (IS_ERR(fbi)) { - ret = PTR_ERR(fbi); - goto err_gem_free_object; - } - - fb = drm_gem_fbdev_fb_create(dev, sizes, 0, &obj->base, - fbdev_cma->fb_funcs); - if (IS_ERR(fb)) { - dev_err(dev->dev, "Failed to allocate DRM framebuffer.\n"); - ret = PTR_ERR(fb); - goto err_fb_info_destroy; - } - - helper->fb = fb; - - fbi->par = helper; - fbi->flags = FBINFO_FLAG_DEFAULT; - fbi->fbops = &drm_fbdev_cma_ops; - - drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->format->depth); - drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height); - - offset = fbi->var.xoffset * bytes_per_pixel; - offset += fbi->var.yoffset * fb->pitches[0]; - - dev->mode_config.fb_base = (resource_size_t)obj->paddr; - fbi->screen_base = obj->vaddr + offset; - fbi->fix.smem_start = (unsigned long)(obj->paddr + offset); - fbi->screen_size = size; - fbi->fix.smem_len = size; - - if (fb->funcs->dirty) { - ret = drm_fbdev_cma_defio_init(fbi, obj); - if (ret) - goto err_cma_destroy; - } - - return 0; - -err_cma_destroy: - drm_framebuffer_remove(fb); -err_fb_info_destroy: - drm_fb_helper_fini(helper); -err_gem_free_object: - drm_gem_object_put_unlocked(&obj->base); - return ret; -} - -static const struct drm_fb_helper_funcs drm_fb_cma_helper_funcs = { - .fb_probe = drm_fbdev_cma_create, -}; - /** * drm_fb_cma_fbdev_init_with_funcs() - Allocate and initialize fbdev emulation * @dev: DRM device @@ -295,53 +116,7 @@ int drm_fb_cma_fbdev_init_with_funcs(struct drm_device *dev, unsigned int preferred_bpp, unsigned int max_conn_count, const struct drm_framebuffer_funcs *funcs) { - struct drm_fbdev_cma *fbdev_cma; - struct drm_fb_helper *fb_helper; - int ret; - - if (!preferred_bpp) - preferred_bpp = dev->mode_config.preferred_depth; - if (!preferred_bpp) - preferred_bpp = 32; - - if (!max_conn_count) - max_conn_count = dev->mode_config.num_connector; - - fbdev_cma = kzalloc(sizeof(*fbdev_cma), GFP_KERNEL); - if (!fbdev_cma) - return -ENOMEM; - - fbdev_cma->fb_funcs = funcs; - fb_helper = &fbdev_cma->fb_helper; - - drm_fb_helper_prepare(dev, fb_helper, &drm_fb_cma_helper_funcs); - - ret = drm_fb_helper_init(dev, fb_helper, max_conn_count); - if (ret < 0) { - DRM_DEV_ERROR(dev->dev, "Failed to initialize fbdev helper.\n"); - goto err_free; - } - - ret = drm_fb_helper_single_add_all_connectors(fb_helper); - if (ret < 0) { - DRM_DEV_ERROR(dev->dev, "Failed to add connectors.\n"); - goto err_drm_fb_helper_fini; - } - - ret = drm_fb_helper_initial_config(fb_helper, preferred_bpp); - if (ret < 0) { - DRM_DEV_ERROR(dev->dev, "Failed to set fbdev configuration.\n"); - goto err_drm_fb_helper_fini; - } - - return 0; - -err_drm_fb_helper_fini: - drm_fb_helper_fini(fb_helper); -err_free: - kfree(fbdev_cma); - - return ret; + return drm_fb_cma_fbdev_init(dev, preferred_bpp, max_conn_count); } EXPORT_SYMBOL_GPL(drm_fb_cma_fbdev_init_with_funcs); @@ -359,8 +134,14 @@ EXPORT_SYMBOL_GPL(drm_fb_cma_fbdev_init_with_funcs); int drm_fb_cma_fbdev_init(struct drm_device *dev, unsigned int preferred_bpp, unsigned int max_conn_count) { - return drm_fb_cma_fbdev_init_with_funcs(dev, preferred_bpp, - max_conn_count, NULL); + struct drm_fbdev_cma *fbdev_cma; + + /* dev->fb_helper will indirectly point to fbdev_cma after this call */ + fbdev_cma = drm_fbdev_cma_init(dev, preferred_bpp, max_conn_count); + if (IS_ERR(fbdev_cma)) + return PTR_ERR(fbdev_cma); + + return 0; } EXPORT_SYMBOL_GPL(drm_fb_cma_fbdev_init); @@ -370,104 +151,54 @@ EXPORT_SYMBOL_GPL(drm_fb_cma_fbdev_init); */ void drm_fb_cma_fbdev_fini(struct drm_device *dev) { - struct drm_fb_helper *fb_helper = dev->fb_helper; - - if (!fb_helper) - return; - - /* Unregister if it hasn't been done already */ - if (fb_helper->fbdev && fb_helper->fbdev->dev) - drm_fb_helper_unregister_fbi(fb_helper); - - if (fb_helper->fbdev) - drm_fbdev_cma_defio_fini(fb_helper->fbdev); - - if (fb_helper->fb) - drm_framebuffer_remove(fb_helper->fb); - - drm_fb_helper_fini(fb_helper); - kfree(to_fbdev_cma(fb_helper)); + if (dev->fb_helper) + drm_fbdev_cma_fini(to_fbdev_cma(dev->fb_helper)); } EXPORT_SYMBOL_GPL(drm_fb_cma_fbdev_fini); +static const struct drm_fb_helper_funcs drm_fb_cma_helper_funcs = { + .fb_probe = drm_fb_helper_generic_probe, +}; + /** - * drm_fbdev_cma_init_with_funcs() - Allocate and initializes a drm_fbdev_cma struct + * drm_fbdev_cma_init() - Allocate and initializes a drm_fbdev_cma struct * @dev: DRM device * @preferred_bpp: Preferred bits per pixel for the device * @max_conn_count: Maximum number of connectors - * @funcs: fb helper functions, in particular a custom dirty() callback * * Returns a newly allocated drm_fbdev_cma struct or a ERR_PTR. */ -struct drm_fbdev_cma *drm_fbdev_cma_init_with_funcs(struct drm_device *dev, - unsigned int preferred_bpp, unsigned int max_conn_count, - const struct drm_framebuffer_funcs *funcs) +struct drm_fbdev_cma *drm_fbdev_cma_init(struct drm_device *dev, + unsigned int preferred_bpp, unsigned int max_conn_count) { struct drm_fbdev_cma *fbdev_cma; - struct drm_fb_helper *helper; + struct drm_fb_helper *fb_helper; int ret; fbdev_cma = kzalloc(sizeof(*fbdev_cma), GFP_KERNEL); - if (!fbdev_cma) { - dev_err(dev->dev, "Failed to allocate drm fbdev.\n"); + if (!fbdev_cma) return ERR_PTR(-ENOMEM); - } - fbdev_cma->fb_funcs = funcs; - - helper = &fbdev_cma->fb_helper; - drm_fb_helper_prepare(dev, helper, &drm_fb_cma_helper_funcs); + fb_helper = &fbdev_cma->fb_helper; - ret = drm_fb_helper_init(dev, helper, max_conn_count); - if (ret < 0) { - dev_err(dev->dev, "Failed to initialize drm fb helper.\n"); + ret = drm_client_new(dev, &fb_helper->client, "fbdev", NULL); + if (ret) goto err_free; - } - - ret = drm_fb_helper_single_add_all_connectors(helper); - if (ret < 0) { - dev_err(dev->dev, "Failed to add connectors.\n"); - goto err_drm_fb_helper_fini; - } - - ret = drm_fb_helper_initial_config(helper, preferred_bpp); - if (ret < 0) { - dev_err(dev->dev, "Failed to set initial hw configuration.\n"); - goto err_drm_fb_helper_fini; - } + ret = drm_fb_helper_fbdev_setup(dev, fb_helper, &drm_fb_cma_helper_funcs, + preferred_bpp, max_conn_count); + if (ret) + goto err_client_put; return fbdev_cma; -err_drm_fb_helper_fini: - drm_fb_helper_fini(helper); +err_client_put: + drm_client_release(&fb_helper->client); err_free: kfree(fbdev_cma); return ERR_PTR(ret); } -EXPORT_SYMBOL_GPL(drm_fbdev_cma_init_with_funcs); - -static const struct drm_framebuffer_funcs drm_fb_cma_funcs = { - .destroy = drm_gem_fb_destroy, - .create_handle = drm_gem_fb_create_handle, -}; - -/** - * drm_fbdev_cma_init() - Allocate and initializes a drm_fbdev_cma struct - * @dev: DRM device - * @preferred_bpp: Preferred bits per pixel for the device - * @max_conn_count: Maximum number of connectors - * - * Returns a newly allocated drm_fbdev_cma struct or a ERR_PTR. - */ -struct drm_fbdev_cma *drm_fbdev_cma_init(struct drm_device *dev, - unsigned int preferred_bpp, unsigned int max_conn_count) -{ - return drm_fbdev_cma_init_with_funcs(dev, preferred_bpp, - max_conn_count, - &drm_fb_cma_funcs); -} EXPORT_SYMBOL_GPL(drm_fbdev_cma_init); /** @@ -477,14 +208,7 @@ EXPORT_SYMBOL_GPL(drm_fbdev_cma_init); void drm_fbdev_cma_fini(struct drm_fbdev_cma *fbdev_cma) { drm_fb_helper_unregister_fbi(&fbdev_cma->fb_helper); - if (fbdev_cma->fb_helper.fbdev) - drm_fbdev_cma_defio_fini(fbdev_cma->fb_helper.fbdev); - - if (fbdev_cma->fb_helper.fb) - drm_framebuffer_remove(fbdev_cma->fb_helper.fb); - - drm_fb_helper_fini(&fbdev_cma->fb_helper); - kfree(fbdev_cma); + /* All resources have now been freed by drm_fbdev_fb_destroy() */ } EXPORT_SYMBOL_GPL(drm_fbdev_cma_fini); diff --git a/include/drm/drm_fb_cma_helper.h b/include/drm/drm_fb_cma_helper.h index d532f88a8d557..a0546c3451f95 100644 --- a/include/drm/drm_fb_cma_helper.h +++ b/include/drm/drm_fb_cma_helper.h @@ -23,9 +23,6 @@ int drm_fb_cma_fbdev_init(struct drm_device *dev, unsigned int preferred_bpp, unsigned int max_conn_count); void drm_fb_cma_fbdev_fini(struct drm_device *dev); -struct drm_fbdev_cma *drm_fbdev_cma_init_with_funcs(struct drm_device *dev, - unsigned int preferred_bpp, unsigned int max_conn_count, - const struct drm_framebuffer_funcs *funcs); struct drm_fbdev_cma *drm_fbdev_cma_init(struct drm_device *dev, unsigned int preferred_bpp, unsigned int max_conn_count); void drm_fbdev_cma_fini(struct drm_fbdev_cma *fbdev_cma); -- GitLab From e896c132eb2cb4975d99477ea7e95aedb6dffa95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org> Date: Tue, 3 Jul 2018 18:03:51 +0200 Subject: [PATCH 0923/1506] drm/debugfs: Add internal client debugfs file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Print the names of the internal clients currently attached. Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Noralf Trønnes <noralf@tronnes.org> Link: https://patchwork.freedesktop.org/patch/msgid/20180703160354.59955-6-noralf@tronnes.org --- drivers/gpu/drm/drm_client.c | 28 ++++++++++++++++++++++++++++ drivers/gpu/drm/drm_debugfs.c | 7 +++++++ include/drm/drm_client.h | 3 +++ 3 files changed, 38 insertions(+) diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c index 743495f7f833b..4039a4d103a83 100644 --- a/drivers/gpu/drm/drm_client.c +++ b/drivers/gpu/drm/drm_client.c @@ -385,3 +385,31 @@ void drm_client_framebuffer_delete(struct drm_client_buffer *buffer) drm_client_buffer_delete(buffer); } EXPORT_SYMBOL(drm_client_framebuffer_delete); + +#ifdef CONFIG_DEBUG_FS +static int drm_client_debugfs_internal_clients(struct seq_file *m, void *data) +{ + struct drm_info_node *node = m->private; + struct drm_device *dev = node->minor->dev; + struct drm_printer p = drm_seq_file_printer(m); + struct drm_client_dev *client; + + mutex_lock(&dev->clientlist_mutex); + list_for_each_entry(client, &dev->clientlist, list) + drm_printf(&p, "%s\n", client->name); + mutex_unlock(&dev->clientlist_mutex); + + return 0; +} + +static const struct drm_info_list drm_client_debugfs_list[] = { + { "internal_clients", drm_client_debugfs_internal_clients, 0 }, +}; + +int drm_client_debugfs_init(struct drm_minor *minor) +{ + return drm_debugfs_create_files(drm_client_debugfs_list, + ARRAY_SIZE(drm_client_debugfs_list), + minor->debugfs_root, minor); +} +#endif diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index b2482818fee8c..50a20bfc07ead 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c @@ -28,6 +28,7 @@ #include <linux/slab.h> #include <linux/export.h> +#include <drm/drm_client.h> #include <drm/drm_debugfs.h> #include <drm/drm_edid.h> #include <drm/drm_atomic.h> @@ -164,6 +165,12 @@ int drm_debugfs_init(struct drm_minor *minor, int minor_id, DRM_ERROR("Failed to create framebuffer debugfs file\n"); return ret; } + + ret = drm_client_debugfs_init(minor); + if (ret) { + DRM_ERROR("Failed to create client debugfs file\n"); + return ret; + } } if (dev->driver->debugfs_init) { diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h index 671052d80e38b..989f8e52864da 100644 --- a/include/drm/drm_client.h +++ b/include/drm/drm_client.h @@ -10,6 +10,7 @@ struct drm_device; struct drm_file; struct drm_framebuffer; struct drm_gem_object; +struct drm_minor; struct module; /** @@ -133,4 +134,6 @@ struct drm_client_buffer * drm_client_framebuffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format); void drm_client_framebuffer_delete(struct drm_client_buffer *buffer); +int drm_client_debugfs_init(struct drm_minor *minor); + #endif -- GitLab From 9060d7f49376159dcc500a97cb247ca8e4b98f48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org> Date: Tue, 3 Jul 2018 18:03:52 +0200 Subject: [PATCH 0924/1506] drm/fb-helper: Finish the generic fbdev emulation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds a drm_fbdev_generic_setup() function that sets up generic fbdev emulation with client callbacks for restore, hotplug and unregister. Signed-off-by: Noralf Trønnes <noralf@tronnes.org> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180703160354.59955-7-noralf@tronnes.org --- drivers/gpu/drm/drm_fb_helper.c | 117 ++++++++++++++++++++++++++++++++ include/drm/drm_fb_helper.h | 7 ++ 2 files changed, 124 insertions(+) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 7e29d5340a170..4b0dd20bccb8f 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -67,6 +67,9 @@ static DEFINE_MUTEX(kernel_fb_helper_lock); * helper functions used by many drivers to implement the kernel mode setting * interfaces. * + * Drivers that support a dumb buffer with a virtual address and mmap support, + * should try out the generic fbdev emulation using drm_fbdev_generic_setup(). + * * Setup fbdev emulation by calling drm_fb_helper_fbdev_setup() and tear it * down by calling drm_fb_helper_fbdev_teardown(). * @@ -3118,6 +3121,120 @@ int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper, } EXPORT_SYMBOL(drm_fb_helper_generic_probe); +static const struct drm_fb_helper_funcs drm_fb_helper_generic_funcs = { + .fb_probe = drm_fb_helper_generic_probe, +}; + +static void drm_fbdev_client_unregister(struct drm_client_dev *client) +{ + struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client); + + if (fb_helper->fbdev) { + drm_fb_helper_unregister_fbi(fb_helper); + /* drm_fbdev_fb_destroy() takes care of cleanup */ + return; + } + + /* Did drm_fb_helper_fbdev_setup() run? */ + if (fb_helper->dev) + drm_fb_helper_fini(fb_helper); + + drm_client_release(client); + kfree(fb_helper); +} + +static int drm_fbdev_client_restore(struct drm_client_dev *client) +{ + struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client); + + drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper); + + return 0; +} + +static int drm_fbdev_client_hotplug(struct drm_client_dev *client) +{ + struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client); + struct drm_device *dev = client->dev; + int ret; + + /* If drm_fb_helper_fbdev_setup() failed, we only try once */ + if (!fb_helper->dev && fb_helper->funcs) + return 0; + + if (dev->fb_helper) + return drm_fb_helper_hotplug_event(dev->fb_helper); + + if (!dev->mode_config.num_connector) + return 0; + + ret = drm_fb_helper_fbdev_setup(dev, fb_helper, &drm_fb_helper_generic_funcs, + fb_helper->preferred_bpp, 0); + if (ret) { + fb_helper->dev = NULL; + fb_helper->fbdev = NULL; + return ret; + } + + return 0; +} + +static const struct drm_client_funcs drm_fbdev_client_funcs = { + .owner = THIS_MODULE, + .unregister = drm_fbdev_client_unregister, + .restore = drm_fbdev_client_restore, + .hotplug = drm_fbdev_client_hotplug, +}; + +/** + * drm_fb_helper_generic_fbdev_setup() - Setup generic fbdev emulation + * @dev: DRM device + * @preferred_bpp: Preferred bits per pixel for the device. + * @dev->mode_config.preferred_depth is used if this is zero. + * + * This function sets up generic fbdev emulation for drivers that supports + * dumb buffers with a virtual address and that can be mmap'ed. + * + * Restore, hotplug events and teardown are all taken care of. Drivers that do + * suspend/resume need to call drm_fb_helper_set_suspend_unlocked() themselves. + * Simple drivers might use drm_mode_config_helper_suspend(). + * + * Drivers that set the dirty callback on their framebuffer will get a shadow + * fbdev buffer that is blitted onto the real buffer. This is done in order to + * make deferred I/O work with all kinds of buffers. + * + * This function is safe to call even when there are no connectors present. + * Setup will be retried on the next hotplug event. + * + * Returns: + * Zero on success or negative error code on failure. + */ +int drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp) +{ + struct drm_fb_helper *fb_helper; + int ret; + + if (!drm_fbdev_emulation) + return 0; + + fb_helper = kzalloc(sizeof(*fb_helper), GFP_KERNEL); + if (!fb_helper) + return -ENOMEM; + + ret = drm_client_new(dev, &fb_helper->client, "fbdev", &drm_fbdev_client_funcs); + if (ret) { + kfree(fb_helper); + return ret; + } + + fb_helper->preferred_bpp = preferred_bpp; + + drm_fbdev_client_hotplug(&fb_helper->client); + + return 0; +} +EXPORT_SYMBOL(drm_fbdev_generic_setup); + /* The Kconfig DRM_KMS_HELPER selects FRAMEBUFFER_CONSOLE (if !EXPERT) * but the module doesn't depend on any fb console symbols. At least * attempt to load fbcon to avoid leaving the system without a usable console. diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index c134bbcfd2e96..5db08c8f1d258 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -354,6 +354,7 @@ void drm_fb_helper_output_poll_changed(struct drm_device *dev); int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper, struct drm_fb_helper_surface_size *sizes); +int drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp); #else static inline void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper, @@ -595,6 +596,12 @@ drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper, return 0; } +static inline int +drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp) +{ + return 0; +} + #endif static inline int -- GitLab From dff1c7032ffea20cca2ad3973ed4c69c8182683d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org> Date: Tue, 3 Jul 2018 18:03:53 +0200 Subject: [PATCH 0925/1506] drm/tinydrm: Use drm_fbdev_generic_setup() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make full use of the generic fbdev client. Cc: David Lechner <david@lechnology.com> Signed-off-by: Noralf Trønnes <noralf@tronnes.org> Reviewed-by: David Lechner <david@lechnology.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180703160354.59955-8-noralf@tronnes.org --- drivers/gpu/drm/tinydrm/core/tinydrm-core.c | 3 +-- drivers/gpu/drm/tinydrm/ili9225.c | 1 - drivers/gpu/drm/tinydrm/ili9341.c | 1 - drivers/gpu/drm/tinydrm/mi0283qt.c | 1 - drivers/gpu/drm/tinydrm/st7586.c | 1 - drivers/gpu/drm/tinydrm/st7735r.c | 1 - 6 files changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/gpu/drm/tinydrm/core/tinydrm-core.c b/drivers/gpu/drm/tinydrm/core/tinydrm-core.c index 24a33bf862fa1..19c7f70adfa5b 100644 --- a/drivers/gpu/drm/tinydrm/core/tinydrm-core.c +++ b/drivers/gpu/drm/tinydrm/core/tinydrm-core.c @@ -204,7 +204,7 @@ static int tinydrm_register(struct tinydrm_device *tdev) if (ret) return ret; - ret = drm_fb_cma_fbdev_init_with_funcs(drm, 0, 0, tdev->fb_funcs); + ret = drm_fbdev_generic_setup(drm, 0); if (ret) DRM_ERROR("Failed to initialize fbdev: %d\n", ret); @@ -214,7 +214,6 @@ static int tinydrm_register(struct tinydrm_device *tdev) static void tinydrm_unregister(struct tinydrm_device *tdev) { drm_atomic_helper_shutdown(tdev->drm); - drm_fb_cma_fbdev_fini(tdev->drm); drm_dev_unregister(tdev->drm); } diff --git a/drivers/gpu/drm/tinydrm/ili9225.c b/drivers/gpu/drm/tinydrm/ili9225.c index 841c69aba0590..455fefe012f59 100644 --- a/drivers/gpu/drm/tinydrm/ili9225.c +++ b/drivers/gpu/drm/tinydrm/ili9225.c @@ -368,7 +368,6 @@ static struct drm_driver ili9225_driver = { DRIVER_ATOMIC, .fops = &ili9225_fops, TINYDRM_GEM_DRIVER_OPS, - .lastclose = drm_fb_helper_lastclose, .name = "ili9225", .desc = "Ilitek ILI9225", .date = "20171106", diff --git a/drivers/gpu/drm/tinydrm/ili9341.c b/drivers/gpu/drm/tinydrm/ili9341.c index 8864dcde6edca..6701037749a74 100644 --- a/drivers/gpu/drm/tinydrm/ili9341.c +++ b/drivers/gpu/drm/tinydrm/ili9341.c @@ -145,7 +145,6 @@ static struct drm_driver ili9341_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_ATOMIC, .fops = &ili9341_fops, TINYDRM_GEM_DRIVER_OPS, - .lastclose = drm_fb_helper_lastclose, .debugfs_init = mipi_dbi_debugfs_init, .name = "ili9341", .desc = "Ilitek ILI9341", diff --git a/drivers/gpu/drm/tinydrm/mi0283qt.c b/drivers/gpu/drm/tinydrm/mi0283qt.c index 015d03f2acba8..d7bb4c5e6657a 100644 --- a/drivers/gpu/drm/tinydrm/mi0283qt.c +++ b/drivers/gpu/drm/tinydrm/mi0283qt.c @@ -154,7 +154,6 @@ static struct drm_driver mi0283qt_driver = { DRIVER_ATOMIC, .fops = &mi0283qt_fops, TINYDRM_GEM_DRIVER_OPS, - .lastclose = drm_fb_helper_lastclose, .debugfs_init = mipi_dbi_debugfs_init, .name = "mi0283qt", .desc = "Multi-Inno MI0283QT", diff --git a/drivers/gpu/drm/tinydrm/st7586.c b/drivers/gpu/drm/tinydrm/st7586.c index 5c29e3803ecba..2fcbc3067d71b 100644 --- a/drivers/gpu/drm/tinydrm/st7586.c +++ b/drivers/gpu/drm/tinydrm/st7586.c @@ -304,7 +304,6 @@ static struct drm_driver st7586_driver = { DRIVER_ATOMIC, .fops = &st7586_fops, TINYDRM_GEM_DRIVER_OPS, - .lastclose = drm_fb_helper_lastclose, .debugfs_init = mipi_dbi_debugfs_init, .name = "st7586", .desc = "Sitronix ST7586", diff --git a/drivers/gpu/drm/tinydrm/st7735r.c b/drivers/gpu/drm/tinydrm/st7735r.c index 6c7b15c9da4fc..3081bc57c1166 100644 --- a/drivers/gpu/drm/tinydrm/st7735r.c +++ b/drivers/gpu/drm/tinydrm/st7735r.c @@ -120,7 +120,6 @@ static struct drm_driver st7735r_driver = { DRIVER_ATOMIC, .fops = &st7735r_fops, TINYDRM_GEM_DRIVER_OPS, - .lastclose = drm_fb_helper_lastclose, .debugfs_init = mipi_dbi_debugfs_init, .name = "st7735r", .desc = "Sitronix ST7735R", -- GitLab From 85b5bafb86e64f5d0ef143ab1a8363f5511eaabb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org> Date: Tue, 3 Jul 2018 18:03:54 +0200 Subject: [PATCH 0926/1506] drm/cma-helper: Remove drm_fb_cma_fbdev_init_with_funcs() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove drm_fb_cma_fbdev_init_with_funcs(), its only user tinydrm has moved to drm_fbdev_generic_setup(). Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Noralf Trønnes <noralf@tronnes.org> Reviewed-by: David Lechner <david@lechnology.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180703160354.59955-9-noralf@tronnes.org --- drivers/gpu/drm/drm_fb_cma_helper.c | 21 --------------------- include/drm/drm_fb_cma_helper.h | 3 --- 2 files changed, 24 deletions(-) diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c index 718c7f961d8ad..9da36a6271d3a 100644 --- a/drivers/gpu/drm/drm_fb_cma_helper.c +++ b/drivers/gpu/drm/drm_fb_cma_helper.c @@ -99,27 +99,6 @@ dma_addr_t drm_fb_cma_get_gem_addr(struct drm_framebuffer *fb, } EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_addr); -/** - * drm_fb_cma_fbdev_init_with_funcs() - Allocate and initialize fbdev emulation - * @dev: DRM device - * @preferred_bpp: Preferred bits per pixel for the device. - * @dev->mode_config.preferred_depth is used if this is zero. - * @max_conn_count: Maximum number of connectors. - * @dev->mode_config.num_connector is used if this is zero. - * @funcs: Framebuffer functions, in particular a custom dirty() callback. - * Can be NULL. - * - * Returns: - * Zero on success or negative error code on failure. - */ -int drm_fb_cma_fbdev_init_with_funcs(struct drm_device *dev, - unsigned int preferred_bpp, unsigned int max_conn_count, - const struct drm_framebuffer_funcs *funcs) -{ - return drm_fb_cma_fbdev_init(dev, preferred_bpp, max_conn_count); -} -EXPORT_SYMBOL_GPL(drm_fb_cma_fbdev_init_with_funcs); - /** * drm_fb_cma_fbdev_init() - Allocate and initialize fbdev emulation * @dev: DRM device diff --git a/include/drm/drm_fb_cma_helper.h b/include/drm/drm_fb_cma_helper.h index a0546c3451f95..96e26e3b9a0cd 100644 --- a/include/drm/drm_fb_cma_helper.h +++ b/include/drm/drm_fb_cma_helper.h @@ -16,9 +16,6 @@ struct drm_mode_fb_cmd2; struct drm_plane; struct drm_plane_state; -int drm_fb_cma_fbdev_init_with_funcs(struct drm_device *dev, - unsigned int preferred_bpp, unsigned int max_conn_count, - const struct drm_framebuffer_funcs *funcs); int drm_fb_cma_fbdev_init(struct drm_device *dev, unsigned int preferred_bpp, unsigned int max_conn_count); void drm_fb_cma_fbdev_fini(struct drm_device *dev); -- GitLab From 8bcf9f7034d81979837e97a6509b0b2a96f8f4c8 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Tue, 10 Jul 2018 10:44:20 +0100 Subject: [PATCH 0927/1506] drm/i915: Flush the residual parking on emergency shutdown On unwinding following a critical failure inside GEM init, we also need to be sure to flush the workers before unloading the module. Testcase: igt/drv_module_reload/basic-reload-inject Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Matthew Auld <matthew.auld@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180710094421.16223-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 2 ++ drivers/gpu/drm/i915/intel_display.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 25728c9d27277..07a92ca61dbfc 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5550,6 +5550,8 @@ int i915_gem_init(struct drm_i915_private *dev_priv) WARN_ON(i915_gem_suspend(dev_priv)); i915_gem_suspend_late(dev_priv); + i915_gem_drain_workqueue(dev_priv); + mutex_lock(&dev_priv->drm.struct_mutex); intel_uc_fini_hw(dev_priv); err_uc_init: diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 19f756d571aea..694975afe394a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -15847,6 +15847,8 @@ void intel_modeset_cleanup(struct drm_device *dev) { struct drm_i915_private *dev_priv = to_i915(dev); + flush_workqueue(dev_priv->modeset_wq); + flush_work(&dev_priv->atomic_helper.free_work); WARN_ON(!llist_empty(&dev_priv->atomic_helper.free_list)); -- GitLab From 73bad7ca87b65a91f61cf34b92a1febd689c01c1 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Tue, 10 Jul 2018 10:44:21 +0100 Subject: [PATCH 0928/1506] drm/i915: Cleanup modesetting on load-error path After handling a critical failure initialising GEM we need to unwind the modesetting setup. Testcase: igt/drv_module_reload/basic-reload-inject Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20180710094421.16223-2-chris@chris-wilson.co.uk Reviewed-by: Matthew Auld <matthew.auld@intel.com> --- drivers/gpu/drm/i915/i915_drv.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index c2b9a4a0ee493..f26cc721ee0fe 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -682,7 +682,7 @@ static int i915_load_modeset_init(struct drm_device *dev) ret = i915_gem_init(dev_priv); if (ret) - goto cleanup_irq; + goto cleanup_modeset; intel_setup_overlay(dev_priv); @@ -702,6 +702,8 @@ static int i915_load_modeset_init(struct drm_device *dev) if (i915_gem_suspend(dev_priv)) DRM_ERROR("failed to idle hardware; continuing to unload!\n"); i915_gem_fini(dev_priv); +cleanup_modeset: + intel_modeset_cleanup(dev); cleanup_irq: drm_irq_uninstall(dev); intel_teardown_gmbus(dev_priv); -- GitLab From 7ab87ede5078af1daccf26951096e16ac16e19cb Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Tue, 10 Jul 2018 15:38:21 +0100 Subject: [PATCH 0929/1506] drm/i915: Unwind HW init after GVT setup failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Following intel_gvt_init() failure, we missed unwinding our setup leaving pointers dangling past the module unload. For our example, the pm_qos: [ 441.057615] top: 000000006b3baf1c, n: 0000000054d8ef33, p: 0000000097cdf1a2 prev: 0000000054d8ef33, n: 0000000097cdf1a2, p: 000000006b3baf1c next: 0000000097cdf1a2, n: 000000006de8fc8b, p: 0000000081087253 [ 441.057627] WARNING: CPU: 4 PID: 9277 at lib/plist.c:42 plist_check_prev_next+0x2d/0x40 [ 441.057628] Modules linked in: i915(+) vgem snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_codec_generic x86_pkg_temp_thermal intel_powerclamp coretemp crct10dif_pclmul crc32_pclmul ghash_clmulni_intel snd_hda_codec snd_hwdep snd_hda_core e1000e snd_pcm mei_me mei prime_numbers [last unloaded: i915] [ 441.057652] CPU: 4 PID: 9277 Comm: drv_selftest Tainted: G U 4.18.0-rc4-CI-CI_DRM_4464+ #1 [ 441.057653] Hardware name: System manufacturer System Product Name/Z170 PRO GAMING, BIOS 3402 04/26/2017 [ 441.057656] RIP: 0010:plist_check_prev_next+0x2d/0x40 [ 441.057657] Code: 08 48 39 f0 74 2b 49 89 f0 48 8b 4f 08 50 ff 32 52 48 89 fe 41 ff 70 08 48 8b 17 48 c7 c7 d8 ae 14 82 4d 8b 08 e8 63 0e 76 ff <0f> 0b 48 83 c4 20 c3 48 39 10 75 d0 f3 c3 0f 1f 44 00 00 41 54 55 [ 441.057717] RSP: 0018:ffffc900003a3a68 EFLAGS: 00010082 [ 441.057720] RAX: 0000000000000000 RBX: ffff8802193978c0 RCX: 0000000000000002 [ 441.057721] RDX: 0000000080000002 RSI: ffffffff820c65a4 RDI: 00000000ffffffff [ 441.057722] RBP: ffff8802193978c0 R08: 0000000000000000 R09: 0000000000000001 [ 441.057724] R10: ffffc900003a3a70 R11: 0000000000000000 R12: ffffffff82243de0 [ 441.057725] R13: ffffffff82243de0 R14: ffff88021a6c78c0 R15: 0000000077359400 [ 441.057726] FS: 00007fc23a4a9980(0000) GS:ffff880236d00000(0000) knlGS:0000000000000000 [ 441.057728] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 441.057729] CR2: 0000563e4503d038 CR3: 0000000138f86005 CR4: 00000000003606e0 [ 441.057730] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 441.057731] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 441.057732] Call Trace: [ 441.057736] plist_check_list+0x2e/0x40 [ 441.057738] plist_add+0x23/0x130 [ 441.057743] pm_qos_update_target+0x1bd/0x2f0 [ 441.057771] i915_driver_load+0xec4/0x1060 [i915] [ 441.057775] ? trace_hardirqs_on_caller+0xe0/0x1b0 [ 441.057800] i915_pci_probe+0x29/0x90 [i915] [ 441.057804] pci_device_probe+0xa1/0x130 [ 441.057807] driver_probe_device+0x306/0x480 [ 441.057810] __driver_attach+0xdb/0x100 [ 441.057812] ? driver_probe_device+0x480/0x480 [ 441.057813] ? driver_probe_device+0x480/0x480 [ 441.057816] bus_for_each_dev+0x74/0xc0 [ 441.057819] bus_add_driver+0x15f/0x250 [ 441.057821] ? 0xffffffffa0696000 [ 441.057823] driver_register+0x56/0xe0 [ 441.057825] ? 0xffffffffa0696000 [ 441.057827] do_one_initcall+0x58/0x370 [ 441.057830] ? do_init_module+0x1d/0x1ea [ 441.057832] ? rcu_read_lock_sched_held+0x6f/0x80 [ 441.057834] ? kmem_cache_alloc_trace+0x282/0x2e0 [ 441.057838] do_init_module+0x56/0x1ea [ 441.057841] load_module+0x2435/0x2b20 [ 441.057852] ? __se_sys_finit_module+0xd3/0xf0 [ 441.057854] __se_sys_finit_module+0xd3/0xf0 [ 441.057861] do_syscall_64+0x55/0x190 [ 441.057863] entry_SYSCALL_64_after_hwframe+0x49/0xbe [ 441.057865] RIP: 0033:0x7fc239d75839 [ 441.057866] Code: 00 f3 c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 1f f6 2c 00 f7 d8 64 89 01 48 [ 441.057927] RSP: 002b:00007fffb7825d38 EFLAGS: 00000246 ORIG_RAX: 0000000000000139 [ 441.057930] RAX: ffffffffffffffda RBX: 0000563e45035dd0 RCX: 00007fc239d75839 [ 441.057931] RDX: 0000000000000000 RSI: 0000563e4502f8a0 RDI: 0000000000000004 [ 441.057932] RBP: 0000563e4502f8a0 R08: 0000000000000004 R09: 0000000000000000 [ 441.057933] R10: 00007fffb7825ea0 R11: 0000000000000246 R12: 0000000000000000 [ 441.057934] R13: 0000563e4502f690 R14: 0000000000000000 R15: 000000000000003f [ 441.057940] irq event stamp: 231338 [ 441.057943] hardirqs last enabled at (231337): [<ffffffff8193e3fc>] _raw_spin_unlock_irqrestore+0x4c/0x60 [ 441.057944] hardirqs last disabled at (231338): [<ffffffff8193e26d>] _raw_spin_lock_irqsave+0xd/0x50 [ 441.057947] softirqs last enabled at (231024): [<ffffffff81c0034f>] __do_softirq+0x34f/0x505 [ 441.057949] softirqs last disabled at (231005): [<ffffffff8108c7b9>] irq_exit+0xa9/0xc0 [ 441.057951] WARNING: CPU: 4 PID: 9277 at lib/plist.c:42 plist_check_prev_next+0x2d/0x40 v2: Add a load failure point to intel_gvt_init() so that we always exercise this path in future. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=107129 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Matthew Auld <matthew.auld@intel.com> Cc: MichaÅ‚ Winiarski <michal.winiarski@intel.com> Reviewed-by: MichaÅ‚ Winiarski <michal.winiarski@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180710143821.1889-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_drv.c | 10 +++++++--- drivers/gpu/drm/i915/intel_gvt.c | 3 +++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index f26cc721ee0fe..f059aa332323e 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1154,8 +1154,6 @@ static int i915_driver_init_hw(struct drm_i915_private *dev_priv) intel_uncore_sanitize(dev_priv); - intel_opregion_setup(dev_priv); - i915_gem_load_init_fences(dev_priv); /* On the 945G/GM, the chipset reports the MSI capability on the @@ -1184,10 +1182,16 @@ static int i915_driver_init_hw(struct drm_i915_private *dev_priv) ret = intel_gvt_init(dev_priv); if (ret) - goto err_ggtt; + goto err_msi; + + intel_opregion_setup(dev_priv); return 0; +err_msi: + if (pdev->msi_enabled) + pci_disable_msi(pdev); + pm_qos_remove_request(&dev_priv->pm_qos); err_ggtt: i915_ggtt_cleanup_hw(dev_priv); err_perf: diff --git a/drivers/gpu/drm/i915/intel_gvt.c b/drivers/gpu/drm/i915/intel_gvt.c index a6291f60545bf..c22b3e18a0f5f 100644 --- a/drivers/gpu/drm/i915/intel_gvt.c +++ b/drivers/gpu/drm/i915/intel_gvt.c @@ -92,6 +92,9 @@ int intel_gvt_init(struct drm_i915_private *dev_priv) { int ret; + if (i915_inject_load_failure()) + return -ENODEV; + if (!i915_modparams.enable_gvt) { DRM_DEBUG_DRIVER("GVT-g is disabled by kernel params\n"); return 0; -- GitLab From 23167fa9a519c5408c4aa7fd1dc85b7c48b37864 Mon Sep 17 00:00:00 2001 From: Jagan Teki <jagan@amarulasolutions.com> Date: Thu, 7 Jun 2018 19:16:48 +0530 Subject: [PATCH 0930/1506] drm/panel: simple: Add support for Rocktech RK070ER9427 LCD panel This adds support for the Rocktech Display Ltd. RK070ER9427 800(RGB)x480 TFT LCD panel, which can be supported by the simple panel driver. Signed-off-by: Jagan Teki <jagan@amarulasolutions.com> Reviewed-by: Rob Herring <robh@kernel.org> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180607134648.2902-1-jagan@amarulasolutions.com --- .../display/panel/rocktech,rk070er9427.txt | 25 ++++++++++++++ drivers/gpu/drm/panel/panel-simple.c | 33 +++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/panel/rocktech,rk070er9427.txt diff --git a/Documentation/devicetree/bindings/display/panel/rocktech,rk070er9427.txt b/Documentation/devicetree/bindings/display/panel/rocktech,rk070er9427.txt new file mode 100644 index 0000000000000..eb1fb9f8d1f46 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/rocktech,rk070er9427.txt @@ -0,0 +1,25 @@ +Rocktech Display Ltd. RK070ER9427 800(RGB)x480 TFT LCD panel + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. + +Required properties: +- compatible: should be "rocktech,rk070er9427" + +Optional properties: +- backlight: phandle of the backlight device attached to the panel + +Optional nodes: +- Video port for LCD panel input. + +Example: + panel { + compatible = "rocktech,rk070er9427"; + backlight = <&backlight_lcd>; + + port { + lcd_panel_in: endpoint { + remote-endpoint = <&lcd_display_out>; + }; + }; + }; diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index ac6aaa174c0b8..884fd534c8b39 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -1747,6 +1747,36 @@ static const struct panel_desc qd43003c0_40 = { .bus_format = MEDIA_BUS_FMT_RGB888_1X24, }; +static const struct display_timing rocktech_rk070er9427_timing = { + .pixelclock = { 26400000, 33300000, 46800000 }, + .hactive = { 800, 800, 800 }, + .hfront_porch = { 16, 210, 354 }, + .hback_porch = { 46, 46, 46 }, + .hsync_len = { 1, 1, 1 }, + .vactive = { 480, 480, 480 }, + .vfront_porch = { 7, 22, 147 }, + .vback_porch = { 23, 23, 23 }, + .vsync_len = { 1, 1, 1 }, + .flags = DISPLAY_FLAGS_DE_HIGH, +}; + +static const struct panel_desc rocktech_rk070er9427 = { + .timings = &rocktech_rk070er9427_timing, + .num_timings = 1, + .bpc = 6, + .size = { + .width = 154, + .height = 86, + }, + .delay = { + .prepare = 41, + .enable = 50, + .unprepare = 41, + .disable = 50, + }, + .bus_format = MEDIA_BUS_FMT_RGB666_1X18, +}; + static const struct drm_display_mode samsung_lsn122dl01_c01_mode = { .clock = 271560, .hdisplay = 2560, @@ -2283,6 +2313,9 @@ static const struct of_device_id platform_of_match[] = { }, { .compatible = "qiaodian,qd43003c0-40", .data = &qd43003c0_40, + }, { + .compatible = "rocktech,rk070er9427", + .data = &rocktech_rk070er9427, }, { .compatible = "samsung,lsn122dl01-c01", .data = &samsung_lsn122dl01_c01, -- GitLab From 2230ca12cca14c5f42e38f11d94d2f3c1f868453 Mon Sep 17 00:00:00 2001 From: Jan Tuerk <jan.tuerk@emtrion.com> Date: Tue, 19 Jun 2018 11:55:43 +0200 Subject: [PATCH 0931/1506] dt-bindings: display: Document the EDT et* displays in one file. Document the Emerging Display Technology Corp. (EDT) using the simple-panel binding in one single file. Reviewed-by: Rob Herring <robh@kernel.org> Signed-off-by: Jan Tuerk <jan.tuerk@emtrion.com> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180619095546.24445-1-jan.tuerk@emtrion.com --- .../bindings/display/panel/edt,et-series.txt | 39 +++++++++++++++++++ .../display/panel/edt,et057090dhu.txt | 7 ---- .../display/panel/edt,et070080dh6.txt | 10 ----- .../display/panel/edt,etm0700g0dh6.txt | 10 ----- 4 files changed, 39 insertions(+), 27 deletions(-) create mode 100644 Documentation/devicetree/bindings/display/panel/edt,et-series.txt delete mode 100644 Documentation/devicetree/bindings/display/panel/edt,et057090dhu.txt delete mode 100644 Documentation/devicetree/bindings/display/panel/edt,et070080dh6.txt delete mode 100644 Documentation/devicetree/bindings/display/panel/edt,etm0700g0dh6.txt diff --git a/Documentation/devicetree/bindings/display/panel/edt,et-series.txt b/Documentation/devicetree/bindings/display/panel/edt,et-series.txt new file mode 100644 index 0000000000000..f56b99ebd9be1 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/edt,et-series.txt @@ -0,0 +1,39 @@ +Emerging Display Technology Corp. Displays +========================================== + + +Display bindings for EDT Display Technology Corp. Displays which are +compatible with the simple-panel binding, which is specified in +simple-panel.txt + + +5,7" WVGA TFT Panels +-------------------- + ++-----------------+---------------------+-------------------------------------+ +| Identifier | compatbile | description | ++=================+=====================+=====================================+ +| ET057090DHU | edt,et057090dhu | 5.7" VGA TFT LCD panel | ++-----------------+---------------------+-------------------------------------+ + + +7,0" WVGA TFT Panels +-------------------- + ++-----------------+---------------------+-------------------------------------+ +| Identifier | compatbile | description | ++=================+=====================+=====================================+ +| ETM0700G0DH6 | edt,etm070080dh6 | WVGA TFT Display with capacitive | +| | | Touchscreen | ++-----------------+---------------------+-------------------------------------+ +| ETM0700G0BDH6 | edt,etm070080bdh6 | Same as ETM0700G0DH6 but with | +| | | inverted pixel clock. | ++-----------------+---------------------+-------------------------------------+ +| ETM0700G0EDH6 | edt,etm070080edh6 | Same display as the ETM0700G0BDH6, | +| | | but with changed Hardware for the | +| | | backlight and the touch interface | ++-----------------+---------------------+-------------------------------------+ +| ET070080DH6 | edt,etm070080dh6 | Same timings as the ETM0700G0DH6, | +| | | but with resistive touch. | ++-----------------+---------------------+-------------------------------------+ + diff --git a/Documentation/devicetree/bindings/display/panel/edt,et057090dhu.txt b/Documentation/devicetree/bindings/display/panel/edt,et057090dhu.txt deleted file mode 100644 index 4903d7b1d947f..0000000000000 --- a/Documentation/devicetree/bindings/display/panel/edt,et057090dhu.txt +++ /dev/null @@ -1,7 +0,0 @@ -Emerging Display Technology Corp. 5.7" VGA TFT LCD panel - -Required properties: -- compatible: should be "edt,et057090dhu" - -This binding is compatible with the simple-panel binding, which is specified -in simple-panel.txt in this directory. diff --git a/Documentation/devicetree/bindings/display/panel/edt,et070080dh6.txt b/Documentation/devicetree/bindings/display/panel/edt,et070080dh6.txt deleted file mode 100644 index 20cb38e836e4c..0000000000000 --- a/Documentation/devicetree/bindings/display/panel/edt,et070080dh6.txt +++ /dev/null @@ -1,10 +0,0 @@ -Emerging Display Technology Corp. ET070080DH6 7.0" WVGA TFT LCD panel - -Required properties: -- compatible: should be "edt,et070080dh6" - -This panel is the same as ETM0700G0DH6 except for the touchscreen. -ET070080DH6 is the model with resistive touch. - -This binding is compatible with the simple-panel binding, which is specified -in simple-panel.txt in this directory. diff --git a/Documentation/devicetree/bindings/display/panel/edt,etm0700g0dh6.txt b/Documentation/devicetree/bindings/display/panel/edt,etm0700g0dh6.txt deleted file mode 100644 index ee4b18053e40e..0000000000000 --- a/Documentation/devicetree/bindings/display/panel/edt,etm0700g0dh6.txt +++ /dev/null @@ -1,10 +0,0 @@ -Emerging Display Technology Corp. ETM0700G0DH6 7.0" WVGA TFT LCD panel - -Required properties: -- compatible: should be "edt,etm0700g0dh6" - -This panel is the same as ET070080DH6 except for the touchscreen. -ETM0700G0DH6 is the model with capacitive multitouch. - -This binding is compatible with the simple-panel binding, which is specified -in simple-panel.txt in this directory. -- GitLab From aa7e6455e1ef75113d47889badb21730f1436714 Mon Sep 17 00:00:00 2001 From: Jan Tuerk <jan.tuerk@emtrion.com> Date: Tue, 19 Jun 2018 11:55:44 +0200 Subject: [PATCH 0932/1506] drm/panel: Add support for the EDT ETM0700G0BDH6 The Emerging Display Technology ETM0700G0BDH6 is exactly the same display as the ETM0700G0DH6, exept the pixelclock polarity. Therefore re-use the ETM0700G0DH6 modes. It is used by default on emtrion Avari based development kits. Signed-off-by: Jan Tuerk <jan.tuerk@emtrion.com> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180619095546.24445-2-jan.tuerk@emtrion.com --- drivers/gpu/drm/panel/panel-simple.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 884fd534c8b39..e05321d3442aa 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -936,6 +936,18 @@ static const struct panel_desc edt_etm0700g0dh6 = { .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_NEGEDGE, }; +static const struct panel_desc edt_etm0700g0bdh6 = { + .modes = &edt_etm0700g0dh6_mode, + .num_modes = 1, + .bpc = 6, + .size = { + .width = 152, + .height = 91, + }, + .bus_format = MEDIA_BUS_FMT_RGB666_1X18, + .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_POSEDGE, +}; + static const struct drm_display_mode foxlink_fl500wvr00_a0t_mode = { .clock = 32260, .hdisplay = 800, @@ -2217,6 +2229,9 @@ static const struct of_device_id platform_of_match[] = { }, { .compatible = "edt,etm0700g0dh6", .data = &edt_etm0700g0dh6, + }, { + .compatible = "edt,etm0700g0bdh6", + .data = &edt_etm0700g0bdh6, }, { .compatible = "foxlink,fl500wvr00-a0t", .data = &foxlink_fl500wvr00_a0t, -- GitLab From aad34de22e6325727f7c716e2e7aa396031ceed5 Mon Sep 17 00:00:00 2001 From: Jan Tuerk <jan.tuerk@emtrion.com> Date: Tue, 19 Jun 2018 11:55:45 +0200 Subject: [PATCH 0933/1506] drm/panel: Add support for the EDT ETM0700G0EDH6 The Emerging Display Technology ETM0700G0EDH6 is the uses the same panel as the ETM0700G0BDH6. It differs in the hardware design for the backlight and the touchscreen i2c interface. As the new display type has different requirements for drive-strengths on the i2c-bus, add an additional compatible to allow the handling of it or warn about incompatible cpu and display combinations. Signed-off-by: Jan Tuerk <jan.tuerk@emtrion.com> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180619095546.24445-3-jan.tuerk@emtrion.com --- drivers/gpu/drm/panel/panel-simple.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index e05321d3442aa..5eb506256d424 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -2232,6 +2232,9 @@ static const struct of_device_id platform_of_match[] = { }, { .compatible = "edt,etm0700g0bdh6", .data = &edt_etm0700g0bdh6, + }, { + .compatible = "edt,etm0700g0edh6", + .data = &edt_etm0700g0bdh6, }, { .compatible = "foxlink,fl500wvr00-a0t", .data = &foxlink_fl500wvr00_a0t, -- GitLab From 7a6aca49358a8b678304f7444ec615dbb1175ce8 Mon Sep 17 00:00:00 2001 From: Philipp Zabel <p.zabel@pengutronix.de> Date: Wed, 23 May 2018 11:25:03 +0200 Subject: [PATCH 0934/1506] dt-bindings: Add vendor prefix for DLC Display Co., Ltd. DLC provides a wide range of display solutions. Website: http://www.dlcdisplay.com/ Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de> Signed-off-by: Marco Felsch <m.felsch@pengutronix.de> Reviewed-by: Rob Herring <robh@kernel.org> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180523092504.5142-2-m.felsch@pengutronix.de --- Documentation/devicetree/bindings/vendor-prefixes.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 6984539437895..10fb0df60b6ae 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -94,6 +94,7 @@ dh DH electronics GmbH digi Digi International Inc. digilent Diglent, Inc. dioo Dioo Microcircuit Co., Ltd +dlc DLC Display Co., Ltd. dlg Dialog Semiconductor dlink D-Link Corporation dmo Data Modul AG -- GitLab From 0ca0c827efdf248dfb4bbd4b9066acb6337e07ac Mon Sep 17 00:00:00 2001 From: Philipp Zabel <p.zabel@pengutronix.de> Date: Wed, 23 May 2018 11:25:04 +0200 Subject: [PATCH 0935/1506] drm/panel: simple: Add DLC DLC0700YZG-1 panel This patch adds support for DLC DLC0700YZG-1 1024x600 LVDS panels to the simple-panel driver. Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de> [m.felsch@pengutronix.de: fix typo in compatible dt-binding] [m.felsch@pengutronix.de: add property bindings] Signed-off-by: Marco Felsch <m.felsch@pengutronix.de> Reviewed-by: Eric Anholt <eric@anholt.net> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180523092504.5142-3-m.felsch@pengutronix.de --- .../display/panel/dlc,dlc0700yzg-1.txt | 13 ++++++++ drivers/gpu/drm/panel/panel-simple.c | 32 +++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/panel/dlc,dlc0700yzg-1.txt diff --git a/Documentation/devicetree/bindings/display/panel/dlc,dlc0700yzg-1.txt b/Documentation/devicetree/bindings/display/panel/dlc,dlc0700yzg-1.txt new file mode 100644 index 0000000000000..bf06bb025b086 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/dlc,dlc0700yzg-1.txt @@ -0,0 +1,13 @@ +DLC Display Co. DLC0700YZG-1 7.0" WSVGA TFT LCD panel + +Required properties: +- compatible: should be "dlc,dlc0700yzg-1" +- power-supply: See simple-panel.txt + +Optional properties: +- reset-gpios: See panel-common.txt +- enable-gpios: See simple-panel.txt +- backlight: See simple-panel.txt + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 5eb506256d424..230f030d1ea94 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -884,6 +884,35 @@ static const struct panel_desc chunghwa_claa101wb01 = { }, }; +static const struct display_timing dlc_dlc0700yzg_1_timing = { + .pixelclock = { 45000000, 51200000, 57000000 }, + .hactive = { 1024, 1024, 1024 }, + .hfront_porch = { 100, 106, 113 }, + .hback_porch = { 100, 106, 113 }, + .hsync_len = { 100, 108, 114 }, + .vactive = { 600, 600, 600 }, + .vfront_porch = { 8, 11, 15 }, + .vback_porch = { 8, 11, 15 }, + .vsync_len = { 9, 13, 15 }, + .flags = DISPLAY_FLAGS_DE_HIGH, +}; + +static const struct panel_desc dlc_dlc0700yzg_1 = { + .timings = &dlc_dlc0700yzg_1_timing, + .num_timings = 1, + .bpc = 6, + .size = { + .width = 154, + .height = 86, + }, + .delay = { + .prepare = 30, + .enable = 200, + .disable = 200, + }, + .bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, +}; + static const struct drm_display_mode edt_et057090dhu_mode = { .clock = 25175, .hdisplay = 640, @@ -2220,6 +2249,9 @@ static const struct of_device_id platform_of_match[] = { }, { .compatible = "chunghwa,claa101wb01", .data = &chunghwa_claa101wb01 + }, { + .compatible = "dlc,dlc0700yzg-1", + .data = &dlc_dlc0700yzg_1, }, { .compatible = "edt,et057090dhu", .data = &edt_et057090dhu, -- GitLab From 5fa8e4a22182df8ea39adeba4bd518506e26a96d Mon Sep 17 00:00:00 2001 From: Boris Brezillon <boris.brezillon@bootlin.com> Date: Wed, 9 May 2018 15:00:39 +0200 Subject: [PATCH 0936/1506] drm/panel: Make of_drm_find_panel() return an ERR_PTR() instead of NULL Right now, the DRM panel logic returns NULL when a panel pointing to the passed OF node is not present in the list of registered panels. Most drivers interpret this NULL value as -EPROBE_DEFER, but we are about to modify the semantic of of_drm_find_panel() and let the framework return -ENODEV when the device node we're pointing to has a status property that is not equal to "okay" or "ok". Let's first patch the of_drm_find_panel() implementation to return ERR_PTR(-EPROBE_DEFER) instead of NULL and patch all callers to replace the '!panel' check by an 'IS_ERR(panel)' one. Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180509130042.9435-2-boris.brezillon@bootlin.com --- drivers/gpu/drm/bridge/cdns-dsi.c | 2 +- drivers/gpu/drm/bridge/lvds-encoder.c | 4 ++-- drivers/gpu/drm/drm_of.c | 4 +++- drivers/gpu/drm/drm_panel.c | 6 ++++-- drivers/gpu/drm/exynos/exynos_dp.c | 6 ++++-- drivers/gpu/drm/exynos/exynos_drm_dpi.c | 4 ++-- drivers/gpu/drm/exynos/exynos_drm_dsi.c | 3 +++ drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c | 5 +++-- drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c | 4 ++-- drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c | 5 ++++- drivers/gpu/drm/msm/dsi/dsi_host.c | 2 +- drivers/gpu/drm/rcar-du/rcar_lvds.c | 4 ++-- drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 2 +- drivers/gpu/drm/sti/sti_dvo.c | 4 +++- drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 4 ++-- drivers/gpu/drm/tegra/dsi.c | 3 +++ drivers/gpu/drm/tegra/output.c | 4 ++-- include/drm/drm_panel.h | 2 +- 18 files changed, 43 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/bridge/cdns-dsi.c b/drivers/gpu/drm/bridge/cdns-dsi.c index f2d43f24acfbe..ce9496d139869 100644 --- a/drivers/gpu/drm/bridge/cdns-dsi.c +++ b/drivers/gpu/drm/bridge/cdns-dsi.c @@ -1152,7 +1152,7 @@ static int cdns_dsi_attach(struct mipi_dsi_host *host, np = of_node_get(dev->dev.of_node); panel = of_drm_find_panel(np); - if (panel) { + if (!IS_ERR(panel)) { bridge = drm_panel_bridge_add(panel, DRM_MODE_CONNECTOR_DSI); } else { bridge = of_drm_find_bridge(dev->dev.of_node); diff --git a/drivers/gpu/drm/bridge/lvds-encoder.c b/drivers/gpu/drm/bridge/lvds-encoder.c index 75b0d3f6e4de9..f56c92f7af7c4 100644 --- a/drivers/gpu/drm/bridge/lvds-encoder.c +++ b/drivers/gpu/drm/bridge/lvds-encoder.c @@ -68,9 +68,9 @@ static int lvds_encoder_probe(struct platform_device *pdev) panel = of_drm_find_panel(panel_node); of_node_put(panel_node); - if (!panel) { + if (IS_ERR(panel)) { dev_dbg(&pdev->dev, "panel not found, deferring probe\n"); - return -EPROBE_DEFER; + return PTR_ERR(panel); } lvds_encoder->panel_bridge = diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c index 3b8c7a6a5720d..1f4a16772583a 100644 --- a/drivers/gpu/drm/drm_of.c +++ b/drivers/gpu/drm/drm_of.c @@ -241,8 +241,10 @@ int drm_of_find_panel_or_bridge(const struct device_node *np, if (panel) { *panel = of_drm_find_panel(remote); - if (*panel) + if (!IS_ERR(*panel)) ret = 0; + else + *panel = NULL; } /* No panel found yet, check for a bridge next. */ diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c index 965530a6f4cd3..7e5530a048464 100644 --- a/drivers/gpu/drm/drm_panel.c +++ b/drivers/gpu/drm/drm_panel.c @@ -151,7 +151,9 @@ EXPORT_SYMBOL(drm_panel_detach); * tree node. If a matching panel is found, return a pointer to it. * * Return: A pointer to the panel registered for the specified device tree - * node or NULL if no panel matching the device tree node can be found. + * node or an ERR_PTR() if no panel matching the device tree node can be found. + * The only error that can be reported is -EPROBE_DEFER, meaning that the panel + * device has not been probed yet, and the caller should retry later. */ struct drm_panel *of_drm_find_panel(const struct device_node *np) { @@ -167,7 +169,7 @@ struct drm_panel *of_drm_find_panel(const struct device_node *np) } mutex_unlock(&panel_lock); - return NULL; + return ERR_PTR(-EPROBE_DEFER); } EXPORT_SYMBOL(of_drm_find_panel); #endif diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c index 86330f396784d..af7ab1ceb50f4 100644 --- a/drivers/gpu/drm/exynos/exynos_dp.c +++ b/drivers/gpu/drm/exynos/exynos_dp.c @@ -232,9 +232,11 @@ static int exynos_dp_probe(struct platform_device *pdev) np = of_parse_phandle(dev->of_node, "panel", 0); if (np) { dp->plat_data.panel = of_drm_find_panel(np); + of_node_put(np); - if (!dp->plat_data.panel) - return -EPROBE_DEFER; + if (IS_ERR(dp->plat_data.panel)) + return PTR_ERR(dp->plat_data.panel); + goto out; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c index 66945e0dc57fc..5887e8522b700 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c @@ -240,8 +240,8 @@ struct drm_encoder *exynos_dpi_probe(struct device *dev) if (ctx->panel_node) { ctx->panel = of_drm_find_panel(ctx->panel_node); - if (!ctx->panel) - return ERR_PTR(-EPROBE_DEFER); + if (IS_ERR(ctx->panel)) + return ERR_CAST(ctx->panel); } return &ctx->encoder; diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 6d29777884f93..809e1e0447dfe 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -1519,6 +1519,9 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host, dsi->format = device->format; dsi->mode_flags = device->mode_flags; dsi->panel = of_drm_find_panel(device->dev.of_node); + if (IS_ERR(dsi->panel)) + dsi->panel = NULL; + if (dsi->panel) { drm_panel_attach(dsi->panel, &dsi->connector); dsi->connector.status = connector_status_connected; diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c index c54806d08dd78..681e2a07d03be 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c @@ -148,8 +148,9 @@ int fsl_dcu_create_outputs(struct fsl_dcu_drm_device *fsl_dev) if (panel_node) { fsl_dev->connector.panel = of_drm_find_panel(panel_node); of_node_put(panel_node); - if (!fsl_dev->connector.panel) - return -EPROBE_DEFER; + if (IS_ERR(fsl_dev->connector.panel)) + return PTR_ERR(fsl_dev->connector.panel); + return fsl_dcu_attach_panel(fsl_dev, fsl_dev->connector.panel); } diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c index 4a645926edb7d..2bfb39082f54d 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c @@ -341,7 +341,7 @@ static void mdp4_lcdc_encoder_disable(struct drm_encoder *encoder) mdp4_write(mdp4_kms, REG_MDP4_LCDC_ENABLE, 0); panel = of_drm_find_panel(mdp4_lcdc_encoder->panel_node); - if (panel) { + if (!IS_ERR(panel)) { drm_panel_disable(panel); drm_panel_unprepare(panel); } @@ -410,7 +410,7 @@ static void mdp4_lcdc_encoder_enable(struct drm_encoder *encoder) dev_err(dev->dev, "failed to enable lcdc_clk: %d\n", ret); panel = of_drm_find_panel(mdp4_lcdc_encoder->panel_node); - if (panel) { + if (!IS_ERR(panel)) { drm_panel_prepare(panel); drm_panel_enable(panel); } diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c index e3b1c86b7aaea..32fba5664b0ee 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c @@ -34,9 +34,12 @@ static enum drm_connector_status mdp4_lvds_connector_detect( struct mdp4_lvds_connector *mdp4_lvds_connector = to_mdp4_lvds_connector(connector); - if (!mdp4_lvds_connector->panel) + if (!mdp4_lvds_connector->panel) { mdp4_lvds_connector->panel = of_drm_find_panel(mdp4_lvds_connector->panel_node); + if (IS_ERR(mdp4_lvds_connector->panel)) + mdp4_lvds_connector->panel = NULL; + } return mdp4_lvds_connector->panel ? connector_status_connected : diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index 2f1a2780658a4..29841f440111e 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -1898,7 +1898,7 @@ int msm_dsi_host_register(struct mipi_dsi_host *host, bool check_defer) * output */ if (check_defer && msm_host->device_node) { - if (!of_drm_find_panel(msm_host->device_node)) + if (IS_ERR(of_drm_find_panel(msm_host->device_node))) if (!of_drm_find_bridge(msm_host->device_node)) return -EPROBE_DEFER; } diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c index 155ad840f3c59..5d8e391e75f42 100644 --- a/drivers/gpu/drm/rcar-du/rcar_lvds.c +++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c @@ -434,8 +434,8 @@ static int rcar_lvds_parse_dt(struct rcar_lvds *lvds) ret = -EPROBE_DEFER; } else { lvds->panel = of_drm_find_panel(remote); - if (!lvds->panel) - ret = -EPROBE_DEFER; + if (IS_ERR(lvds->panel)) + ret = PTR_ERR(lvds->panel); } done: diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index d53d5a09547f1..01642aaf61273 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -595,7 +595,7 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host, dsi->format = device->format; dsi->mode_flags = device->mode_flags; dsi->panel = of_drm_find_panel(device->dev.of_node); - if (dsi->panel) + if (!IS_ERR(dsi->panel)) return drm_panel_attach(dsi->panel, &dsi->connector); return -EINVAL; diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c index a5979cd25cc7d..030da55a8d301 100644 --- a/drivers/gpu/drm/sti/sti_dvo.c +++ b/drivers/gpu/drm/sti/sti_dvo.c @@ -387,7 +387,9 @@ sti_dvo_connector_detect(struct drm_connector *connector, bool force) if (!dvo->panel) { dvo->panel = of_drm_find_panel(dvo->panel_node); - if (dvo->panel) + if (IS_ERR(dvo->panel)) + dvo->panel = NULL; + else drm_panel_attach(dvo->panel, connector); } diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c index da9814f94d008..2b40d1f6aee89 100644 --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c @@ -833,8 +833,8 @@ static int sun6i_dsi_attach(struct mipi_dsi_host *host, dsi->device = device; dsi->panel = of_drm_find_panel(device->dev.of_node); - if (!dsi->panel) - return -EINVAL; + if (IS_ERR(dsi->panel)) + return PTR_ERR(dsi->panel); dev_info(host->dev, "Attached device %s\n", device->name); diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index 87c5d89bc9baf..ad88ec2303297 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -1411,6 +1411,9 @@ static int tegra_dsi_host_attach(struct mipi_dsi_host *host, struct tegra_output *output = &dsi->output; output->panel = of_drm_find_panel(device->dev.of_node); + if (IS_ERR(output->panel)) + output->panel = NULL; + if (output->panel && output->connector.dev) { drm_panel_attach(output->panel, &output->connector); drm_helper_hpd_irq_event(output->connector.dev); diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c index ffe34bd0bb9d1..0c0936511bb48 100644 --- a/drivers/gpu/drm/tegra/output.c +++ b/drivers/gpu/drm/tegra/output.c @@ -110,8 +110,8 @@ int tegra_output_probe(struct tegra_output *output) panel = of_parse_phandle(output->of_node, "nvidia,panel", 0); if (panel) { output->panel = of_drm_find_panel(panel); - if (!output->panel) - return -EPROBE_DEFER; + if (IS_ERR(output->panel)) + return PTR_ERR(output->panel); of_node_put(panel); } diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h index 26a1b5fd8796c..582a0ec0aa704 100644 --- a/include/drm/drm_panel.h +++ b/include/drm/drm_panel.h @@ -200,7 +200,7 @@ struct drm_panel *of_drm_find_panel(const struct device_node *np); #else static inline struct drm_panel *of_drm_find_panel(const struct device_node *np) { - return NULL; + return ERR_PTR(-ENODEV); } #endif -- GitLab From c59eb3cfde1faed960fe6de5040c4bd4310fb1cd Mon Sep 17 00:00:00 2001 From: Boris Brezillon <boris.brezillon@bootlin.com> Date: Wed, 9 May 2018 15:00:40 +0200 Subject: [PATCH 0937/1506] drm/panel: Let of_drm_find_panel() return -ENODEV when the panel is disabled DT nodes might be present in the DT but with a status property set to "disabled" or "fail". In this case, we should not return -EPROBE_DEFER when the caller asks for a drm_panel instance. Return -ENODEV instead. Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com> Reviewed-by: Thierry Reding <treding@nvidia.com> Acked-by: Thierry Reding <treding@nvidia.com> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180509130042.9435-3-boris.brezillon@bootlin.com --- drivers/gpu/drm/drm_panel.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c index 7e5530a048464..b902361dee6e1 100644 --- a/drivers/gpu/drm/drm_panel.c +++ b/drivers/gpu/drm/drm_panel.c @@ -152,13 +152,18 @@ EXPORT_SYMBOL(drm_panel_detach); * * Return: A pointer to the panel registered for the specified device tree * node or an ERR_PTR() if no panel matching the device tree node can be found. - * The only error that can be reported is -EPROBE_DEFER, meaning that the panel - * device has not been probed yet, and the caller should retry later. + * Possible error codes returned by this function: + * - EPROBE_DEFER: the panel device has not been probed yet, and the caller + * should retry later + * - ENODEV: the device is not available (status != "okay" or "ok") */ struct drm_panel *of_drm_find_panel(const struct device_node *np) { struct drm_panel *panel; + if (!of_device_is_available(np)) + return ERR_PTR(-ENODEV); + mutex_lock(&panel_lock); list_for_each_entry(panel, &panel_list, list) { -- GitLab From 2e64a174179a144742fa70f09803a012aceca476 Mon Sep 17 00:00:00 2001 From: Boris Brezillon <boris.brezillon@bootlin.com> Date: Wed, 9 May 2018 15:00:41 +0200 Subject: [PATCH 0938/1506] drm/of: Make drm_of_find_panel_or_bridge() fail when the device is disabled There's no point searching for a drm_bridge or drm_panel if the OF node we're pointing has a status property that is not "okay" or "ok". Just return -ENODEV in this case. Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com> Reviewed-by: Thierry Reding <treding@nvidia.com> Acked-by: Thierry Reding <treding@nvidia.com> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180509130042.9435-4-boris.brezillon@bootlin.com --- drivers/gpu/drm/drm_of.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c index 1f4a16772583a..260612958cbe6 100644 --- a/drivers/gpu/drm/drm_of.c +++ b/drivers/gpu/drm/drm_of.c @@ -239,6 +239,11 @@ int drm_of_find_panel_or_bridge(const struct device_node *np, if (!remote) return -ENODEV; + if (!of_device_is_available(remote)) { + of_node_put(remote); + return -ENODEV; + } + if (panel) { *panel = of_drm_find_panel(remote); if (!IS_ERR(*panel)) -- GitLab From 1b9883eae82251b742627ebd9d544d1b1bddf121 Mon Sep 17 00:00:00 2001 From: Boris Brezillon <boris.brezillon@bootlin.com> Date: Wed, 9 May 2018 15:00:42 +0200 Subject: [PATCH 0939/1506] drm/vc4: Support the case where the DSI device is disabled Having a device with a status property != "okay" in the DT is a valid use case, and we should not prevent the registration of the DRM device when the DSI device connected to the DSI controller is disabled. Consider the ENODEV return code as a valid result and do not expose the DSI encoder/connector when it happens. Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com> Reviewed-by: Eric Anholt <eric@anholt.net> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180509130042.9435-5-boris.brezillon@bootlin.com --- drivers/gpu/drm/vc4/vc4_dsi.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c index 9c8e89372d1c0..0c607eb33d7e0 100644 --- a/drivers/gpu/drm/vc4/vc4_dsi.c +++ b/drivers/gpu/drm/vc4/vc4_dsi.c @@ -1612,8 +1612,18 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, &panel, &dsi->bridge); - if (ret) + if (ret) { + /* If the bridge or panel pointed by dev->of_node is not + * enabled, just return 0 here so that we don't prevent the DRM + * dev from being registered. Of course that means the DSI + * encoder won't be exposed, but that's not a problem since + * nothing is connected to it. + */ + if (ret == -ENODEV) + return 0; + return ret; + } if (panel) { dsi->bridge = devm_drm_panel_bridge_add(dev, panel, @@ -1664,7 +1674,8 @@ static void vc4_dsi_unbind(struct device *dev, struct device *master, struct vc4_dev *vc4 = to_vc4_dev(drm); struct vc4_dsi *dsi = dev_get_drvdata(dev); - pm_runtime_disable(dev); + if (dsi->bridge) + pm_runtime_disable(dev); vc4_dsi_encoder_destroy(dsi->encoder); -- GitLab From b0b7aa407e929b8e25a2982bff428eacd50f1630 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda <a.hajda@samsung.com> Date: Tue, 19 Jun 2018 10:19:25 +0200 Subject: [PATCH 0940/1506] dt-bindings: display: Add DT bindings for BOE HV070WSA-100 panel The patch adds bindings to BOE HV070-WSA WSVGA panel. Bindings are compatible with simple panel bindings. Signed-off-by: Andrzej Hajda <a.hajda@samsung.com> Signed-off-by: Maciej Purski <m.purski@samsung.com> Reviewed-by: Rob Herring <robh@kernel.org> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/1529396370-18761-5-git-send-email-m.purski@samsung.com --- .../display/panel/boe,hv070wsa-100.txt | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/panel/boe,hv070wsa-100.txt diff --git a/Documentation/devicetree/bindings/display/panel/boe,hv070wsa-100.txt b/Documentation/devicetree/bindings/display/panel/boe,hv070wsa-100.txt new file mode 100644 index 0000000000000..55183d360032c --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/boe,hv070wsa-100.txt @@ -0,0 +1,28 @@ +BOE HV070WSA-100 7.01" WSVGA TFT LCD panel + +Required properties: +- compatible: should be "boe,hv070wsa-100" +- power-supply: regulator to provide the VCC supply voltage (3.3 volts) +- enable-gpios: GPIO pin to enable and disable panel (active high) + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. + +The device node can contain one 'port' child node with one child +'endpoint' node, according to the bindings defined in [1]. This +node should describe panel's video bus. + +[1]: Documentation/devicetree/bindings/media/video-interfaces.txt + +Example: + + panel: panel { + compatible = "boe,hv070wsa-100"; + power-supply = <&vcc_3v3_reg>; + enable-gpios = <&gpd1 3 GPIO_ACTIVE_HIGH>; + port { + panel_ep: endpoint { + remote-endpoint = <&bridge_out_ep>; + }; + }; + }; -- GitLab From ae8cf41b6a5e3a0847cf5ef9bf6feb82e75ab5eb Mon Sep 17 00:00:00 2001 From: Andrzej Hajda <a.hajda@samsung.com> Date: Tue, 19 Jun 2018 10:19:26 +0200 Subject: [PATCH 0941/1506] drm/panel: simple: Add support for BOE HV070WSA-100 panel to simple-panel The patch adds support for BOE HV070WSA-100 WSVGA 7.01 inch panel to the panel-simple driver. The panel is used in Exynos5250-arndale boards. Signed-off-by: Andrzej Hajda <a.hajda@samsung.com> Signed-off-by: Maciej Purski <m.purski@samsung.com> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/1529396370-18761-6-git-send-email-m.purski@samsung.com --- drivers/gpu/drm/panel/panel-simple.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 230f030d1ea94..cca1168f08815 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -772,6 +772,28 @@ static const struct panel_desc avic_tm070ddh03 = { }, }; +static const struct drm_display_mode boe_hv070wsa_mode = { + .clock = 40800, + .hdisplay = 1024, + .hsync_start = 1024 + 90, + .hsync_end = 1024 + 90 + 90, + .htotal = 1024 + 90 + 90 + 90, + .vdisplay = 600, + .vsync_start = 600 + 3, + .vsync_end = 600 + 3 + 4, + .vtotal = 600 + 3 + 4 + 3, + .vrefresh = 60, +}; + +static const struct panel_desc boe_hv070wsa = { + .modes = &boe_hv070wsa_mode, + .num_modes = 1, + .size = { + .width = 154, + .height = 90, + }, +}; + static const struct drm_display_mode boe_nv101wxmn51_modes[] = { { .clock = 71900, @@ -2237,6 +2259,9 @@ static const struct of_device_id platform_of_match[] = { }, { .compatible = "avic,tm070ddh03", .data = &avic_tm070ddh03, + }, { + .compatible = "boe,hv070wsa-100", + .data = &boe_hv070wsa }, { .compatible = "boe,nv101wxmn51", .data = &boe_nv101wxmn51, -- GitLab From 955f60db0f2b87094f64df3d7f608fdac4a6ebb1 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi <peter.ujfalusi@ti.com> Date: Mon, 18 Jun 2018 16:22:34 +0300 Subject: [PATCH 0942/1506] drm: Add support for extracting sync signal drive edge from videomode The sync in some panels needs to be driven by different edge of the pixel clock compared to data. This is reflected by the DISPLAY_FLAGS_SYNC_(POS|NEG)EDGE in videmode flags. Add similar similar definitions for bus_flags and convert the sync drive edge via drm_bus_flags_from_videomode(). Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com> Signed-off-by: Jyri Sarha <jsarha@ti.com> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180618132242.8673-2-tomi.valkeinen@ti.com --- drivers/gpu/drm/drm_modes.c | 15 +++++++++++---- include/drm/drm_connector.h | 4 ++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index 7f552d5fa88ee..f8f7eae738ab6 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -659,10 +659,12 @@ EXPORT_SYMBOL_GPL(drm_display_mode_to_videomode); * drm_bus_flags_from_videomode - extract information about pixelclk and * DE polarity from videomode and store it in a separate variable * @vm: videomode structure to use - * @bus_flags: information about pixelclk and DE polarity will be stored here + * @bus_flags: information about pixelclk, sync and DE polarity will be stored + * here * - * Sets DRM_BUS_FLAG_DE_(LOW|HIGH) and DRM_BUS_FLAG_PIXDATA_(POS|NEG)EDGE - * in @bus_flags according to DISPLAY_FLAGS found in @vm + * Sets DRM_BUS_FLAG_DE_(LOW|HIGH), DRM_BUS_FLAG_PIXDATA_(POS|NEG)EDGE and + * DISPLAY_FLAGS_SYNC_(POS|NEG)EDGE in @bus_flags according to DISPLAY_FLAGS + * found in @vm */ void drm_bus_flags_from_videomode(const struct videomode *vm, u32 *bus_flags) { @@ -672,6 +674,11 @@ void drm_bus_flags_from_videomode(const struct videomode *vm, u32 *bus_flags) if (vm->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE) *bus_flags |= DRM_BUS_FLAG_PIXDATA_NEGEDGE; + if (vm->flags & DISPLAY_FLAGS_SYNC_POSEDGE) + *bus_flags |= DRM_BUS_FLAG_SYNC_POSEDGE; + if (vm->flags & DISPLAY_FLAGS_SYNC_NEGEDGE) + *bus_flags |= DRM_BUS_FLAG_SYNC_NEGEDGE; + if (vm->flags & DISPLAY_FLAGS_DE_LOW) *bus_flags |= DRM_BUS_FLAG_DE_LOW; if (vm->flags & DISPLAY_FLAGS_DE_HIGH) @@ -684,7 +691,7 @@ EXPORT_SYMBOL_GPL(drm_bus_flags_from_videomode); * of_get_drm_display_mode - get a drm_display_mode from devicetree * @np: device_node with the timing specification * @dmode: will be set to the return value - * @bus_flags: information about pixelclk and DE polarity + * @bus_flags: information about pixelclk, sync and DE polarity * @index: index into the list of display timings in devicetree * * This function is expensive and should only be used, if only one mode is to be diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index ad397dfc042b1..a5179eb9e56fe 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -290,6 +290,10 @@ struct drm_display_info { #define DRM_BUS_FLAG_DATA_MSB_TO_LSB (1<<4) /* data is transmitted LSB to MSB on the bus */ #define DRM_BUS_FLAG_DATA_LSB_TO_MSB (1<<5) +/* drive sync on pos. edge */ +#define DRM_BUS_FLAG_SYNC_POSEDGE (1<<6) +/* drive sync on neg. edge */ +#define DRM_BUS_FLAG_SYNC_NEGEDGE (1<<7) /** * @bus_flags: Additional information (like pixel signal polarity) for -- GitLab From 3b39ad7a553f3ecdf16374973e4b0971b861769d Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen <tomi.valkeinen@ti.com> Date: Mon, 18 Jun 2018 16:22:40 +0300 Subject: [PATCH 0943/1506] drm/panel: simple: Add newhaven, nhd-4.3-480272ef-atxl LCD Add support for newhaven,nhd-4.3-480272ef-atxl to panel-simple. Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com> Cc: Thierry Reding <thierry.reding@gmail.com> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180618132242.8673-8-tomi.valkeinen@ti.com --- .../panel/newhaven,nhd-4.3-480272ef-atxl.txt | 7 +++++ drivers/gpu/drm/panel/panel-simple.c | 30 +++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/panel/newhaven,nhd-4.3-480272ef-atxl.txt diff --git a/Documentation/devicetree/bindings/display/panel/newhaven,nhd-4.3-480272ef-atxl.txt b/Documentation/devicetree/bindings/display/panel/newhaven,nhd-4.3-480272ef-atxl.txt new file mode 100644 index 0000000000000..e78292b1a131e --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/newhaven,nhd-4.3-480272ef-atxl.txt @@ -0,0 +1,7 @@ +Newhaven Display International 480 x 272 TFT LCD panel + +Required properties: +- compatible: should be "newhaven,nhd-4.3-480272ef-atxl" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index cca1168f08815..2c4857e08a769 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -1625,6 +1625,33 @@ static const struct panel_desc netron_dy_e231732 = { .bus_format = MEDIA_BUS_FMT_RGB666_1X18, }; +static const struct drm_display_mode newhaven_nhd_43_480272ef_atxl_mode = { + .clock = 9000, + .hdisplay = 480, + .hsync_start = 480 + 2, + .hsync_end = 480 + 2 + 41, + .htotal = 480 + 2 + 41 + 2, + .vdisplay = 272, + .vsync_start = 272 + 2, + .vsync_end = 272 + 2 + 10, + .vtotal = 272 + 2 + 10 + 2, + .vrefresh = 60, + .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC, +}; + +static const struct panel_desc newhaven_nhd_43_480272ef_atxl = { + .modes = &newhaven_nhd_43_480272ef_atxl_mode, + .num_modes = 1, + .bpc = 8, + .size = { + .width = 95, + .height = 54, + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X24, + .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_POSEDGE | + DRM_BUS_FLAG_SYNC_POSEDGE, +}; + static const struct display_timing nlt_nl192108ac18_02d_timing = { .pixelclock = { 130000000, 148350000, 163000000 }, .hactive = { 1920, 1920, 1920 }, @@ -2367,6 +2394,9 @@ static const struct of_device_id platform_of_match[] = { }, { .compatible = "netron-dy,e231732", .data = &netron_dy_e231732, + }, { + .compatible = "newhaven,nhd-4.3-480272ef-atxl", + .data = &newhaven_nhd_43_480272ef_atxl, }, { .compatible = "nlt,nl192108ac18-02d", .data = &nlt_nl192108ac18_02d, -- GitLab From a5d2ade627dcaa825707e20da6994e79c95e2434 Mon Sep 17 00:00:00 2001 From: Christoph Fritz <chf.fritz@googlemail.com> Date: Mon, 4 Jun 2018 13:16:48 +0200 Subject: [PATCH 0944/1506] drm/panel: simple: Add support for Innolux G070Y2-L01 This patch adds support for Innolux G070Y2-L01 7" WVGA (800x480) TFT LCD panel. Signed-off-by: Christoph Fritz <chf.fritz@googlemail.com> Reviewed-by: Rob Herring <robh@kernel.org> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/1528111008.2818.20.camel@googlemail.com --- .../display/panel/innolux,g070y2-l01.txt | 12 ++++++ drivers/gpu/drm/panel/panel-simple.c | 37 ++++++++++++++++++- 2 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 Documentation/devicetree/bindings/display/panel/innolux,g070y2-l01.txt diff --git a/Documentation/devicetree/bindings/display/panel/innolux,g070y2-l01.txt b/Documentation/devicetree/bindings/display/panel/innolux,g070y2-l01.txt new file mode 100644 index 0000000000000..7c234cf68e116 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/innolux,g070y2-l01.txt @@ -0,0 +1,12 @@ +Innolux G070Y2-L01 7" WVGA (800x480) TFT LCD panel + +Required properties: +- compatible: should be "innolux,g070y2-l01" +- power-supply: as specified in the base binding + +Optional properties: +- backlight: as specified in the base binding +- enable-gpios: as specified in the base binding + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 2c4857e08a769..da7fbd2b2a75a 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -1176,6 +1176,36 @@ static const struct panel_desc innolux_at070tn92 = { .bus_format = MEDIA_BUS_FMT_RGB888_1X24, }; +static const struct display_timing innolux_g070y2_l01_timing = { + .pixelclock = { 28000000, 29500000, 32000000 }, + .hactive = { 800, 800, 800 }, + .hfront_porch = { 61, 91, 141 }, + .hback_porch = { 60, 90, 140 }, + .hsync_len = { 12, 12, 12 }, + .vactive = { 480, 480, 480 }, + .vfront_porch = { 4, 9, 30 }, + .vback_porch = { 4, 8, 28 }, + .vsync_len = { 2, 2, 2 }, + .flags = DISPLAY_FLAGS_DE_HIGH, +}; + +static const struct panel_desc innolux_g070y2_l01 = { + .timings = &innolux_g070y2_l01_timing, + .num_timings = 1, + .bpc = 6, + .size = { + .width = 152, + .height = 91, + }, + .delay = { + .prepare = 10, + .enable = 100, + .disable = 100, + .unprepare = 800, + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, +}; + static const struct display_timing innolux_g101ice_l01_timing = { .pixelclock = { 60400000, 71100000, 74700000 }, .hactive = { 1280, 1280, 1280 }, @@ -2341,10 +2371,13 @@ static const struct of_device_id platform_of_match[] = { .compatible = "innolux,at070tn92", .data = &innolux_at070tn92, }, { - .compatible ="innolux,g101ice-l01", + .compatible = "innolux,g070y2-l01", + .data = &innolux_g070y2_l01, + }, { + .compatible = "innolux,g101ice-l01", .data = &innolux_g101ice_l01 }, { - .compatible ="innolux,g121i1-l01", + .compatible = "innolux,g121i1-l01", .data = &innolux_g121i1_l01 }, { .compatible = "innolux,g121x1-l03", -- GitLab From 03fa9aa384940b006cabb03fe25a073f394f60d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Vok=C3=A1=C4=8D?= <michal.vokac@ysoft.com> Date: Mon, 25 Jun 2018 14:41:29 +0200 Subject: [PATCH 0945/1506] dt-bindings: Add DataImage, Inc. vendor prefix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DataImage is a Taiwan-based manufacturer of LCD panels. Signed-off-by: Michal VokÃ¡Ä <michal.vokac@ysoft.com> Reviewed-by: Rob Herring <robh@kernel.org> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/1529930490-11874-1-git-send-email-michal.vokac@ysoft.com --- Documentation/devicetree/bindings/vendor-prefixes.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 10fb0df60b6ae..5fd6c539e8984 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -86,6 +86,7 @@ cubietech Cubietech, Ltd. cypress Cypress Semiconductor Corporation cznic CZ.NIC, z.s.p.o. dallas Maxim Integrated Products (formerly Dallas Semiconductor) +dataimage DataImage, Inc. davicom DAVICOM Semiconductor, Inc. delta Delta Electronics, Inc. denx Denx Software Engineering -- GitLab From 97ceb1fb08b6a2f78aa44a7c229ca280964860c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Vok=C3=A1=C4=8D?= <michal.vokac@ysoft.com> Date: Mon, 25 Jun 2018 14:41:30 +0200 Subject: [PATCH 0946/1506] drm/panel: simple: Add support for DataImage SCF0700C48GGU18 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds support for the DataImage SCF0700C48GGU18 7.0" WVGA (800x480) TFT LCD panel. The panel has 24-bit parallel interface and can be supported by the simple panel driver. Signed-off-by: Michal VokÃ¡Ä <michal.vokac@ysoft.com> Reviewed-by: Rob Herring <robh@kernel.org> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/1529930490-11874-2-git-send-email-michal.vokac@ysoft.com --- .../panel/dataimage,scf0700c48ggu18.txt | 8 +++++ drivers/gpu/drm/panel/panel-simple.c | 29 +++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/panel/dataimage,scf0700c48ggu18.txt diff --git a/Documentation/devicetree/bindings/display/panel/dataimage,scf0700c48ggu18.txt b/Documentation/devicetree/bindings/display/panel/dataimage,scf0700c48ggu18.txt new file mode 100644 index 0000000000000..897085ee3cd4b --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/dataimage,scf0700c48ggu18.txt @@ -0,0 +1,8 @@ +DataImage, Inc. 7" WVGA (800x480) TFT LCD panel with 24-bit parallel interface. + +Required properties: +- compatible: should be "dataimage,scf0700c48ggu18" +- power-supply: as specified in the base binding + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index da7fbd2b2a75a..3b226ad8acadd 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -906,6 +906,32 @@ static const struct panel_desc chunghwa_claa101wb01 = { }, }; +static const struct drm_display_mode dataimage_scf0700c48ggu18_mode = { + .clock = 33260, + .hdisplay = 800, + .hsync_start = 800 + 40, + .hsync_end = 800 + 40 + 128, + .htotal = 800 + 40 + 128 + 88, + .vdisplay = 480, + .vsync_start = 480 + 10, + .vsync_end = 480 + 10 + 2, + .vtotal = 480 + 10 + 2 + 33, + .vrefresh = 60, + .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC, +}; + +static const struct panel_desc dataimage_scf0700c48ggu18 = { + .modes = &dataimage_scf0700c48ggu18_mode, + .num_modes = 1, + .bpc = 8, + .size = { + .width = 152, + .height = 91, + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X24, + .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_POSEDGE, +}; + static const struct display_timing dlc_dlc0700yzg_1_timing = { .pixelclock = { 45000000, 51200000, 57000000 }, .hactive = { 1024, 1024, 1024 }, @@ -2331,6 +2357,9 @@ static const struct of_device_id platform_of_match[] = { }, { .compatible = "chunghwa,claa101wb01", .data = &chunghwa_claa101wb01 + }, { + .compatible = "dataimage,scf0700c48ggu18", + .data = &dataimage_scf0700c48ggu18, }, { .compatible = "dlc,dlc0700yzg-1", .data = &dlc_dlc0700yzg_1, -- GitLab From 3d5664f95ebe264c16f3ebfadce9eee6fee9acf7 Mon Sep 17 00:00:00 2001 From: Colin Ian King <colin.king@canonical.com> Date: Tue, 26 Jun 2018 17:03:54 +0100 Subject: [PATCH 0947/1506] drm/panel: ili9881c: Fix missing assignment to error return ret Currently, ret is being checked for an error condition however it is not being assigned in the previous statement on the call of function mipi_dsi_dcs_exit_sleep_mode. Add in the missing assignment of ret. Detected by CoverityScan, CID#1470174, 1470178 ("Unchecked return value") Fixes: 26aec25593c2 ("drm/panel: Add Ilitek ILI9881c panel driver") Signed-off-by: Colin Ian King <colin.king@canonical.com> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180626160354.1363-1-colin.king@canonical.com --- drivers/gpu/drm/panel/panel-ilitek-ili9881c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c index e848af235df57..3ad4a46c4e945 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c @@ -334,7 +334,7 @@ static int ili9881c_prepare(struct drm_panel *panel) if (ret) return ret; - mipi_dsi_dcs_exit_sleep_mode(ctx->dsi); + ret = mipi_dsi_dcs_exit_sleep_mode(ctx->dsi); if (ret) return ret; -- GitLab From 7ad4e4636c54dcfbcaf43c8737af3c294ed17d11 Mon Sep 17 00:00:00 2001 From: Lin Huang <hl@rock-chips.com> Date: Mon, 2 Jul 2018 12:27:18 +0200 Subject: [PATCH 0948/1506] drm/panel: p079zca: Refactor panel driver to support multiple panels Refactor Innolux P079ZCA panel driver, let it support multi panels from Innolux that share similar power sequences. Panels may require different power supplies so use regulator bulk interfaces and define per panel supply-names. Changes in v2: - Change regulator property name to meet the panel datasheet Changes in v3: - this patch only refactor P079ZCA panel to support multi panel, support P097PFG panel in another patch Changes in v4: - Modify the patch which suggest by Thierry Changes in v5: - use regulator_bulk to handle different supply number Signed-off-by: Lin Huang <hl@rock-chips.com> Signed-off-by: Heiko Stuebner <heiko@sntech.de> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180702102721.3546-2-heiko@sntech.de --- drivers/gpu/drm/panel/panel-innolux-p079zca.c | 143 +++++++++++++----- 1 file changed, 102 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-innolux-p079zca.c b/drivers/gpu/drm/panel/panel-innolux-p079zca.c index bb53e08507643..185a550601950 100644 --- a/drivers/gpu/drm/panel/panel-innolux-p079zca.c +++ b/drivers/gpu/drm/panel/panel-innolux-p079zca.c @@ -20,12 +20,29 @@ #include <video/mipi_display.h> +struct panel_desc { + const struct drm_display_mode *mode; + unsigned int bpc; + struct { + unsigned int width; + unsigned int height; + } size; + + unsigned long flags; + enum mipi_dsi_pixel_format format; + unsigned int lanes; + const char * const *supply_names; + unsigned int num_supplies; +}; + struct innolux_panel { struct drm_panel base; struct mipi_dsi_device *link; + const struct panel_desc *desc; struct backlight_device *backlight; - struct regulator *supply; + struct regulator_bulk_data *supplies; + unsigned int num_supplies; struct gpio_desc *enable_gpio; bool prepared; @@ -77,7 +94,8 @@ static int innolux_panel_unprepare(struct drm_panel *panel) /* T8: 80ms - 1000ms */ msleep(80); - err = regulator_disable(innolux->supply); + err = regulator_bulk_disable(innolux->desc->num_supplies, + innolux->supplies); if (err < 0) return err; @@ -89,14 +107,15 @@ static int innolux_panel_unprepare(struct drm_panel *panel) static int innolux_panel_prepare(struct drm_panel *panel) { struct innolux_panel *innolux = to_innolux_panel(panel); - int err, regulator_err; + int err; if (innolux->prepared) return 0; gpiod_set_value_cansleep(innolux->enable_gpio, 0); - err = regulator_enable(innolux->supply); + err = regulator_bulk_enable(innolux->desc->num_supplies, + innolux->supplies); if (err < 0) return err; @@ -133,12 +152,9 @@ static int innolux_panel_prepare(struct drm_panel *panel) return 0; poweroff: - regulator_err = regulator_disable(innolux->supply); - if (regulator_err) - DRM_DEV_ERROR(panel->dev, "failed to disable regulator: %d\n", - regulator_err); - gpiod_set_value_cansleep(innolux->enable_gpio, 0); + regulator_bulk_disable(innolux->desc->num_supplies, innolux->supplies); + return err; } @@ -162,7 +178,11 @@ static int innolux_panel_enable(struct drm_panel *panel) return 0; } -static const struct drm_display_mode default_mode = { +static const char * const innolux_p079zca_supply_names[] = { + "power", +}; + +static const struct drm_display_mode innolux_p079zca_mode = { .clock = 56900, .hdisplay = 768, .hsync_start = 768 + 40, @@ -175,15 +195,31 @@ static const struct drm_display_mode default_mode = { .vrefresh = 60, }; +static const struct panel_desc innolux_p079zca_panel_desc = { + .mode = &innolux_p079zca_mode, + .bpc = 8, + .size = { + .width = 120, + .height = 160, + }, + .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | + MIPI_DSI_MODE_LPM, + .format = MIPI_DSI_FMT_RGB888, + .lanes = 4, + .supply_names = innolux_p079zca_supply_names, + .num_supplies = ARRAY_SIZE(innolux_p079zca_supply_names), +}; + static int innolux_panel_get_modes(struct drm_panel *panel) { + struct innolux_panel *innolux = to_innolux_panel(panel); + const struct drm_display_mode *m = innolux->desc->mode; struct drm_display_mode *mode; - mode = drm_mode_duplicate(panel->drm, &default_mode); + mode = drm_mode_duplicate(panel->drm, m); if (!mode) { DRM_DEV_ERROR(panel->drm->dev, "failed to add mode %ux%ux@%u\n", - default_mode.hdisplay, default_mode.vdisplay, - default_mode.vrefresh); + m->hdisplay, m->vdisplay, m->vrefresh); return -ENOMEM; } @@ -191,9 +227,11 @@ static int innolux_panel_get_modes(struct drm_panel *panel) drm_mode_probed_add(panel->connector, mode); - panel->connector->display_info.width_mm = 120; - panel->connector->display_info.height_mm = 160; - panel->connector->display_info.bpc = 8; + panel->connector->display_info.width_mm = + innolux->desc->size.width; + panel->connector->display_info.height_mm = + innolux->desc->size.height; + panel->connector->display_info.bpc = innolux->desc->bpc; return 1; } @@ -207,19 +245,39 @@ static const struct drm_panel_funcs innolux_panel_funcs = { }; static const struct of_device_id innolux_of_match[] = { - { .compatible = "innolux,p079zca", }, + { .compatible = "innolux,p079zca", + .data = &innolux_p079zca_panel_desc + }, { } }; MODULE_DEVICE_TABLE(of, innolux_of_match); -static int innolux_panel_add(struct innolux_panel *innolux) +static int innolux_panel_add(struct mipi_dsi_device *dsi, + const struct panel_desc *desc) { - struct device *dev = &innolux->link->dev; - int err; + struct innolux_panel *innolux; + struct device *dev = &dsi->dev; + int err, i; + + innolux = devm_kzalloc(dev, sizeof(*innolux), GFP_KERNEL); + if (!innolux) + return -ENOMEM; + + innolux->desc = desc; + + innolux->supplies = devm_kcalloc(dev, desc->num_supplies, + sizeof(*innolux->supplies), + GFP_KERNEL); + if (!innolux->supplies) + return -ENOMEM; - innolux->supply = devm_regulator_get(dev, "power"); - if (IS_ERR(innolux->supply)) - return PTR_ERR(innolux->supply); + for (i = 0; i < desc->num_supplies; i++) + innolux->supplies[i].supply = desc->supply_names[i]; + + err = devm_regulator_bulk_get(dev, desc->num_supplies, + innolux->supplies); + if (err < 0) + return err; innolux->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH); @@ -230,15 +288,21 @@ static int innolux_panel_add(struct innolux_panel *innolux) } innolux->backlight = devm_of_find_backlight(dev); - if (IS_ERR(innolux->backlight)) return PTR_ERR(innolux->backlight); drm_panel_init(&innolux->base); innolux->base.funcs = &innolux_panel_funcs; - innolux->base.dev = &innolux->link->dev; + innolux->base.dev = dev; + + err = drm_panel_add(&innolux->base); + if (err < 0) + return err; + + mipi_dsi_set_drvdata(dsi, innolux); + innolux->link = dsi; - return drm_panel_add(&innolux->base); + return 0; } static void innolux_panel_del(struct innolux_panel *innolux) @@ -249,28 +313,24 @@ static void innolux_panel_del(struct innolux_panel *innolux) static int innolux_panel_probe(struct mipi_dsi_device *dsi) { - struct innolux_panel *innolux; + const struct panel_desc *desc; + const struct of_device_id *id; int err; - dsi->lanes = 4; - dsi->format = MIPI_DSI_FMT_RGB888; - dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | - MIPI_DSI_MODE_LPM; + id = of_match_node(innolux_of_match, dsi->dev.of_node); + if (!id) + return -ENODEV; - innolux = devm_kzalloc(&dsi->dev, sizeof(*innolux), GFP_KERNEL); - if (!innolux) - return -ENOMEM; + desc = id->data; + dsi->mode_flags = desc->flags; + dsi->format = desc->format; + dsi->lanes = desc->lanes; - mipi_dsi_set_drvdata(dsi, innolux); - - innolux->link = dsi; - - err = innolux_panel_add(innolux); + err = innolux_panel_add(dsi, desc); if (err < 0) return err; - err = mipi_dsi_attach(dsi); - return err; + return mipi_dsi_attach(dsi); } static int innolux_panel_remove(struct mipi_dsi_device *dsi) @@ -317,5 +377,6 @@ static struct mipi_dsi_driver innolux_panel_driver = { module_mipi_dsi_driver(innolux_panel_driver); MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>"); +MODULE_AUTHOR("Lin Huang <hl@rock-chips.com>"); MODULE_DESCRIPTION("Innolux P079ZCA panel driver"); MODULE_LICENSE("GPL v2"); -- GitLab From 48bd379aa23d0d6249490137e5ebe7f8aeeb887d Mon Sep 17 00:00:00 2001 From: Lin Huang <hl@rock-chips.com> Date: Mon, 2 Jul 2018 12:27:19 +0200 Subject: [PATCH 0949/1506] drm/panel: p079zca: Add variable unprepare_delay properties When panel power down, p079zca need delay between reset and disable power supply, but p097pfg does not need it. Similarly p097zca needs a delay after entering panel sleep mode. So add two delay properties, so we can meet these two panel power down sequence. Signed-off-by: Lin Huang <hl@rock-chips.com> [add sleep-mode delay] Signed-off-by: Heiko Stuebner <heiko@sntech.de> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180702102721.3546-3-heiko@sntech.de --- drivers/gpu/drm/panel/panel-innolux-p079zca.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-innolux-p079zca.c b/drivers/gpu/drm/panel/panel-innolux-p079zca.c index 185a550601950..69bee4413aae2 100644 --- a/drivers/gpu/drm/panel/panel-innolux-p079zca.c +++ b/drivers/gpu/drm/panel/panel-innolux-p079zca.c @@ -33,6 +33,8 @@ struct panel_desc { unsigned int lanes; const char * const *supply_names; unsigned int num_supplies; + unsigned int sleep_mode_delay; + unsigned int power_down_delay; }; struct innolux_panel { @@ -89,10 +91,13 @@ static int innolux_panel_unprepare(struct drm_panel *panel) return err; } + if (innolux->desc->sleep_mode_delay) + msleep(innolux->desc->sleep_mode_delay); + gpiod_set_value_cansleep(innolux->enable_gpio, 0); - /* T8: 80ms - 1000ms */ - msleep(80); + if (innolux->desc->power_down_delay) + msleep(innolux->desc->power_down_delay); err = regulator_bulk_disable(innolux->desc->num_supplies, innolux->supplies); @@ -208,6 +213,7 @@ static const struct panel_desc innolux_p079zca_panel_desc = { .lanes = 4, .supply_names = innolux_p079zca_supply_names, .num_supplies = ARRAY_SIZE(innolux_p079zca_supply_names), + .power_down_delay = 80, /* T8: 80ms - 1000ms */ }; static int innolux_panel_get_modes(struct drm_panel *panel) -- GitLab From 731edd4ce5d3fb477c808e2fc16f398c9ff3576b Mon Sep 17 00:00:00 2001 From: Lin Huang <hl@rock-chips.com> Date: Mon, 2 Jul 2018 12:27:20 +0200 Subject: [PATCH 0950/1506] dt-bindings: Add Innolux P097PFG panel bindings The Innolux P097PFG panel is 9.7" panel with 1536X2048 resolution, it reuse P079ZCA panel driver, so improve p079ZCA dt-binding to support P097PFG. Changes in v2: - None Changes in v3: - None Changes in v4: - None Changes in v5: - use separate file for binding - keep power supplies as required Signed-off-by: Lin Huang <hl@rock-chips.com> Signed-off-by: Heiko Stuebner <heiko@sntech.de> Reviewed-by: Rob Herring <robh@kernel.org> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180702102721.3546-4-heiko@sntech.de --- .../display/panel/innolux,p097pfg.txt | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/panel/innolux,p097pfg.txt diff --git a/Documentation/devicetree/bindings/display/panel/innolux,p097pfg.txt b/Documentation/devicetree/bindings/display/panel/innolux,p097pfg.txt new file mode 100644 index 0000000000000..595d9dfeffd3f --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/innolux,p097pfg.txt @@ -0,0 +1,24 @@ +Innolux P097PFG 9.7" 1536x2048 TFT LCD panel + +Required properties: +- compatible: should be "innolux,p097pfg" +- reg: DSI virtual channel of the peripheral +- avdd-supply: phandle of the regulator that provides positive voltage +- avee-supply: phandle of the regulator that provides negative voltage +- enable-gpios: panel enable gpio + +Optional properties: +- backlight: phandle of the backlight device attached to the panel + +Example: + + &mipi_dsi { + panel { + compatible = "innolux,p079zca"; + reg = <0>; + avdd-supply = <...>; + avee-supply = <...>; + backlight = <&backlight>; + enable-gpios = <&gpio1 13 GPIO_ACTIVE_HIGH>; + }; + }; -- GitLab From de04a462fdcee724462bd656c13d461fba5ece51 Mon Sep 17 00:00:00 2001 From: Lin Huang <hl@rock-chips.com> Date: Mon, 2 Jul 2018 12:27:21 +0200 Subject: [PATCH 0951/1506] drm/panel: p079zca: Support Innolux P097PFG panel Support Innolux P097PFG 9.7" 1536x2048 TFT LCD panel, it reuse the Innolux P079ZCA panel driver. Changes in v2: - None Changes in v3: - None Changes in v4: - None Changes in v5: - Document source of init-commands - 4 lanes per DSI interface Signed-off-by: Lin Huang <hl@rock-chips.com> Signed-off-by: Heiko Stuebner <heiko@sntech.de> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180702102721.3546-5-heiko@sntech.de --- drivers/gpu/drm/panel/panel-innolux-p079zca.c | 200 +++++++++++++++++- 1 file changed, 196 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-innolux-p079zca.c b/drivers/gpu/drm/panel/panel-innolux-p079zca.c index 69bee4413aae2..424d0bf3c5957 100644 --- a/drivers/gpu/drm/panel/panel-innolux-p079zca.c +++ b/drivers/gpu/drm/panel/panel-innolux-p079zca.c @@ -20,6 +20,15 @@ #include <video/mipi_display.h> +struct panel_init_cmd { + size_t len; + const char *data; +}; + +#define _INIT_CMD(...) { \ + .len = sizeof((char[]){__VA_ARGS__}), \ + .data = (char[]){__VA_ARGS__} } + struct panel_desc { const struct drm_display_mode *mode; unsigned int bpc; @@ -30,6 +39,7 @@ struct panel_desc { unsigned long flags; enum mipi_dsi_pixel_format format; + const struct panel_init_cmd *init_cmds; unsigned int lanes; const char * const *supply_names; unsigned int num_supplies; @@ -124,13 +134,43 @@ static int innolux_panel_prepare(struct drm_panel *panel) if (err < 0) return err; - /* T2: 15ms - 1000ms */ - usleep_range(15000, 16000); + /* p079zca: t2 (20ms), p097pfg: t4 (15ms) */ + usleep_range(20000, 21000); gpiod_set_value_cansleep(innolux->enable_gpio, 1); - /* T4: 15ms - 1000ms */ - usleep_range(15000, 16000); + /* p079zca: t4, p097pfg: t5 */ + usleep_range(20000, 21000); + + if (innolux->desc->init_cmds) { + const struct panel_init_cmd *cmds = + innolux->desc->init_cmds; + unsigned int i; + + for (i = 0; cmds[i].len != 0; i++) { + const struct panel_init_cmd *cmd = &cmds[i]; + + err = mipi_dsi_generic_write(innolux->link, cmd->data, + cmd->len); + if (err < 0) { + dev_err(panel->dev, + "failed to write command %u\n", i); + goto poweroff; + } + + /* + * Included by random guessing, because without this + * (or at least, some delay), the panel sometimes + * didn't appear to pick up the command sequence. + */ + err = mipi_dsi_dcs_nop(innolux->link); + if (err < 0) { + dev_err(panel->dev, + "failed to send DCS nop: %d\n", err); + goto poweroff; + } + } + } err = mipi_dsi_dcs_exit_sleep_mode(innolux->link); if (err < 0) { @@ -216,6 +256,155 @@ static const struct panel_desc innolux_p079zca_panel_desc = { .power_down_delay = 80, /* T8: 80ms - 1000ms */ }; +static const char * const innolux_p097pfg_supply_names[] = { + "avdd", + "avee", +}; + +static const struct drm_display_mode innolux_p097pfg_mode = { + .clock = 229000, + .hdisplay = 1536, + .hsync_start = 1536 + 100, + .hsync_end = 1536 + 100 + 24, + .htotal = 1536 + 100 + 24 + 100, + .vdisplay = 2048, + .vsync_start = 2048 + 100, + .vsync_end = 2048 + 100 + 2, + .vtotal = 2048 + 100 + 2 + 18, + .vrefresh = 60, +}; + +/* + * Display manufacturer failed to provide init sequencing according to + * https://chromium-review.googlesource.com/c/chromiumos/third_party/coreboot/+/892065/ + * so the init sequence stems from a register dump of a working panel. + */ +static const struct panel_init_cmd innolux_p097pfg_init_cmds[] = { + /* page 0 */ + _INIT_CMD(0xF0, 0x55, 0xAA, 0x52, 0x08, 0x00), + _INIT_CMD(0xB1, 0xE8, 0x11), + _INIT_CMD(0xB2, 0x25, 0x02), + _INIT_CMD(0xB5, 0x08, 0x00), + _INIT_CMD(0xBC, 0x0F, 0x00), + _INIT_CMD(0xB8, 0x03, 0x06, 0x00, 0x00), + _INIT_CMD(0xBD, 0x01, 0x90, 0x14, 0x14), + _INIT_CMD(0x6F, 0x01), + _INIT_CMD(0xC0, 0x03), + _INIT_CMD(0x6F, 0x02), + _INIT_CMD(0xC1, 0x0D), + _INIT_CMD(0xD9, 0x01, 0x09, 0x70), + _INIT_CMD(0xC5, 0x12, 0x21, 0x00), + _INIT_CMD(0xBB, 0x93, 0x93), + + /* page 1 */ + _INIT_CMD(0xF0, 0x55, 0xAA, 0x52, 0x08, 0x01), + _INIT_CMD(0xB3, 0x3C, 0x3C), + _INIT_CMD(0xB4, 0x0F, 0x0F), + _INIT_CMD(0xB9, 0x45, 0x45), + _INIT_CMD(0xBA, 0x14, 0x14), + _INIT_CMD(0xCA, 0x02), + _INIT_CMD(0xCE, 0x04), + _INIT_CMD(0xC3, 0x9B, 0x9B), + _INIT_CMD(0xD8, 0xC0, 0x03), + _INIT_CMD(0xBC, 0x82, 0x01), + _INIT_CMD(0xBD, 0x9E, 0x01), + + /* page 2 */ + _INIT_CMD(0xF0, 0x55, 0xAA, 0x52, 0x08, 0x02), + _INIT_CMD(0xB0, 0x82), + _INIT_CMD(0xD1, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x82, 0x00, 0xA5, + 0x00, 0xC1, 0x00, 0xEA, 0x01, 0x0D, 0x01, 0x40), + _INIT_CMD(0xD2, 0x01, 0x6A, 0x01, 0xA8, 0x01, 0xDC, 0x02, 0x29, + 0x02, 0x67, 0x02, 0x68, 0x02, 0xA8, 0x02, 0xF0), + _INIT_CMD(0xD3, 0x03, 0x19, 0x03, 0x49, 0x03, 0x67, 0x03, 0x8C, + 0x03, 0xA6, 0x03, 0xC7, 0x03, 0xDE, 0x03, 0xEC), + _INIT_CMD(0xD4, 0x03, 0xFF, 0x03, 0xFF), + _INIT_CMD(0xE0, 0x00, 0x00, 0x00, 0x86, 0x00, 0xC5, 0x00, 0xE5, + 0x00, 0xFF, 0x01, 0x26, 0x01, 0x45, 0x01, 0x75), + _INIT_CMD(0xE1, 0x01, 0x9C, 0x01, 0xD5, 0x02, 0x05, 0x02, 0x4D, + 0x02, 0x86, 0x02, 0x87, 0x02, 0xC3, 0x03, 0x03), + _INIT_CMD(0xE2, 0x03, 0x2A, 0x03, 0x56, 0x03, 0x72, 0x03, 0x94, + 0x03, 0xAC, 0x03, 0xCB, 0x03, 0xE0, 0x03, 0xED), + _INIT_CMD(0xE3, 0x03, 0xFF, 0x03, 0xFF), + + /* page 3 */ + _INIT_CMD(0xF0, 0x55, 0xAA, 0x52, 0x08, 0x03), + _INIT_CMD(0xB0, 0x00, 0x00, 0x00, 0x00), + _INIT_CMD(0xB1, 0x00, 0x00, 0x00, 0x00), + _INIT_CMD(0xB2, 0x00, 0x00, 0x06, 0x04, 0x01, 0x40, 0x85), + _INIT_CMD(0xB3, 0x10, 0x07, 0xFC, 0x04, 0x01, 0x40, 0x80), + _INIT_CMD(0xB6, 0xF0, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, + 0x40, 0x80), + _INIT_CMD(0xBA, 0xC5, 0x07, 0x00, 0x04, 0x11, 0x25, 0x8C), + _INIT_CMD(0xBB, 0xC5, 0x07, 0x00, 0x03, 0x11, 0x25, 0x8C), + _INIT_CMD(0xC0, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x80, 0x80), + _INIT_CMD(0xC1, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x80, 0x80), + _INIT_CMD(0xC4, 0x00, 0x00), + _INIT_CMD(0xEF, 0x41), + + /* page 4 */ + _INIT_CMD(0xF0, 0x55, 0xAA, 0x52, 0x08, 0x04), + _INIT_CMD(0xEC, 0x4C), + + /* page 5 */ + _INIT_CMD(0xF0, 0x55, 0xAA, 0x52, 0x08, 0x05), + _INIT_CMD(0xB0, 0x13, 0x03, 0x03, 0x01), + _INIT_CMD(0xB1, 0x30, 0x00), + _INIT_CMD(0xB2, 0x02, 0x02, 0x00), + _INIT_CMD(0xB3, 0x82, 0x23, 0x82, 0x9D), + _INIT_CMD(0xB4, 0xC5, 0x75, 0x24, 0x57), + _INIT_CMD(0xB5, 0x00, 0xD4, 0x72, 0x11, 0x11, 0xAB, 0x0A), + _INIT_CMD(0xB6, 0x00, 0x00, 0xD5, 0x72, 0x24, 0x56), + _INIT_CMD(0xB7, 0x5C, 0xDC, 0x5C, 0x5C), + _INIT_CMD(0xB9, 0x0C, 0x00, 0x00, 0x01, 0x00), + _INIT_CMD(0xC0, 0x75, 0x11, 0x11, 0x54, 0x05), + _INIT_CMD(0xC6, 0x00, 0x00, 0x00, 0x00), + _INIT_CMD(0xD0, 0x00, 0x48, 0x08, 0x00, 0x00), + _INIT_CMD(0xD1, 0x00, 0x48, 0x09, 0x00, 0x00), + + /* page 6 */ + _INIT_CMD(0xF0, 0x55, 0xAA, 0x52, 0x08, 0x06), + _INIT_CMD(0xB0, 0x02, 0x32, 0x32, 0x08, 0x2F), + _INIT_CMD(0xB1, 0x2E, 0x15, 0x14, 0x13, 0x12), + _INIT_CMD(0xB2, 0x11, 0x10, 0x00, 0x3D, 0x3D), + _INIT_CMD(0xB3, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D), + _INIT_CMD(0xB4, 0x3D, 0x32), + _INIT_CMD(0xB5, 0x03, 0x32, 0x32, 0x09, 0x2F), + _INIT_CMD(0xB6, 0x2E, 0x1B, 0x1A, 0x19, 0x18), + _INIT_CMD(0xB7, 0x17, 0x16, 0x01, 0x3D, 0x3D), + _INIT_CMD(0xB8, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D), + _INIT_CMD(0xB9, 0x3D, 0x32), + _INIT_CMD(0xC0, 0x01, 0x32, 0x32, 0x09, 0x2F), + _INIT_CMD(0xC1, 0x2E, 0x1A, 0x1B, 0x16, 0x17), + _INIT_CMD(0xC2, 0x18, 0x19, 0x03, 0x3D, 0x3D), + _INIT_CMD(0xC3, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D), + _INIT_CMD(0xC4, 0x3D, 0x32), + _INIT_CMD(0xC5, 0x00, 0x32, 0x32, 0x08, 0x2F), + _INIT_CMD(0xC6, 0x2E, 0x14, 0x15, 0x10, 0x11), + _INIT_CMD(0xC7, 0x12, 0x13, 0x02, 0x3D, 0x3D), + _INIT_CMD(0xC8, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D), + _INIT_CMD(0xC9, 0x3D, 0x32), + + {}, +}; + +static const struct panel_desc innolux_p097pfg_panel_desc = { + .mode = &innolux_p097pfg_mode, + .bpc = 8, + .size = { + .width = 147, + .height = 196, + }, + .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | + MIPI_DSI_MODE_LPM, + .format = MIPI_DSI_FMT_RGB888, + .init_cmds = innolux_p097pfg_init_cmds, + .lanes = 4, + .supply_names = innolux_p097pfg_supply_names, + .num_supplies = ARRAY_SIZE(innolux_p097pfg_supply_names), + .sleep_mode_delay = 100, /* T15 */ +}; + static int innolux_panel_get_modes(struct drm_panel *panel) { struct innolux_panel *innolux = to_innolux_panel(panel); @@ -254,6 +443,9 @@ static const struct of_device_id innolux_of_match[] = { { .compatible = "innolux,p079zca", .data = &innolux_p079zca_panel_desc }, + { .compatible = "innolux,p097pfg", + .data = &innolux_p097pfg_panel_desc + }, { } }; MODULE_DEVICE_TABLE(of, innolux_of_match); -- GitLab From 2bb7a39c1581a22efd6a6f21bbce9d5575ce9224 Mon Sep 17 00:00:00 2001 From: Nickey Yang <nickey.yang@rock-chips.com> Date: Mon, 2 Jul 2018 12:32:27 +0200 Subject: [PATCH 0952/1506] dt-bindings: Add vendor prefix for kingdisplay Kingdisplay Technology Co., Ltd, established in China Shenzhen in 2006, is a national high-tech enterprise specializing in the R&D, manufacturing and marketing of TFT-LCM and touch panel. Signed-off-by: Nickey Yang <nickey.yang@rock-chips.com> Acked-by: Rob Herring <robh@kernel.org> Signed-off-by: Heiko Stuebner <heiko@sntech.de> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180702103229.3952-2-heiko@sntech.de --- Documentation/devicetree/bindings/vendor-prefixes.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 5fd6c539e8984..2afaa633ffc89 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -191,6 +191,7 @@ keymile Keymile GmbH khadas Khadas kiebackpeter Kieback & Peter GmbH kinetic Kinetic Technologies +kingdisplay King & Display Technology Co., Ltd. kingnovel Kingnovel Technology Co., Ltd. koe Kaohsiung Opto-Electronics Inc. kosagi Sutajio Ko-Usagi PTE Ltd. -- GitLab From ebc950fdff6d5f9250cd5a5a348af97f7d8508df Mon Sep 17 00:00:00 2001 From: Nickey Yang <nickey.yang@rock-chips.com> Date: Mon, 2 Jul 2018 12:32:28 +0200 Subject: [PATCH 0953/1506] dt-bindings: Add KINGDISPLAY KD097D04 panel bindings The KINGDISPLAY KD097D04 is a 9.7" panel with a 1536x2048 resolution and connected to DSI using 8 lanes. Signed-off-by: Nickey Yang <nickey.yang@rock-chips.com> Acked-by: Rob Herring <robh@kernel.org> Signed-off-by: Heiko Stuebner <heiko@sntech.de> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180702103229.3952-3-heiko@sntech.de --- .../display/panel/kingdisplay,kd097d04.txt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/panel/kingdisplay,kd097d04.txt diff --git a/Documentation/devicetree/bindings/display/panel/kingdisplay,kd097d04.txt b/Documentation/devicetree/bindings/display/panel/kingdisplay,kd097d04.txt new file mode 100644 index 0000000000000..164a5fa236daf --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/kingdisplay,kd097d04.txt @@ -0,0 +1,22 @@ +Kingdisplay KD097D04 9.7" 1536x2048 TFT LCD panel + +Required properties: +- compatible: should be "kingdisplay,kd097d04" +- reg: DSI virtual channel of the peripheral +- power-supply: phandle of the regulator that provides the supply voltage +- enable-gpios: panel enable gpio + +Optional properties: +- backlight: phandle of the backlight device attached to the panel + +Example: + + &mipi_dsi { + panel { + compatible = "kingdisplay,kd097d04"; + reg = <0>; + power-supply = <...>; + backlight = <&backlight>; + enable-gpios = <&gpio1 13 GPIO_ACTIVE_HIGH>; + }; + }; -- GitLab From cd0e0ca69109d025b1a1b6609f70682db62138b0 Mon Sep 17 00:00:00 2001 From: Dan Carpenter <dan.carpenter@oracle.com> Date: Wed, 4 Jul 2018 12:38:09 +0300 Subject: [PATCH 0954/1506] drm/panel: type promotion bug in s6e8aa0_read_mtp_id() The ARRAY_SIZE() macro is type size_t. If s6e8aa0_dcs_read() returns a negative error code, then "ret < ARRAY_SIZE(id)" is false because the negative error code is type promoted to a high positive value. Fixes: 02051ca06371 ("drm/panel: add S6E8AA0 driver") Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com> Reviewed-by: Andrzej Hajda <a.hajda@samsung.com> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180704093807.s3lqsb2v6dg2k43d@kili.mountain --- drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c b/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c index a188a3959f1ad..6ad827b93ae19 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c @@ -823,7 +823,7 @@ static void s6e8aa0_read_mtp_id(struct s6e8aa0 *ctx) int ret, i; ret = s6e8aa0_dcs_read(ctx, 0xd1, id, ARRAY_SIZE(id)); - if (ret < ARRAY_SIZE(id) || id[0] == 0x00) { + if (ret < 0 || ret < ARRAY_SIZE(id) || id[0] == 0x00) { dev_err(ctx->dev, "read id failed\n"); ctx->error = -EIO; return; -- GitLab From b6d83fccd877221416658fbdb59ba4d1628ba800 Mon Sep 17 00:00:00 2001 From: Thierry Reding <treding@nvidia.com> Date: Tue, 10 Jul 2018 12:51:38 +0200 Subject: [PATCH 0955/1506] drm/panel: p079zca: Use of_device_get_match_data() Use this helper to get rid of some extra boilerplate code. Reviewed-by: Heiko Stuebner <heiko@sntech.de> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180710110127.12315-1-thierry.reding@gmail.com --- drivers/gpu/drm/panel/panel-innolux-p079zca.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-innolux-p079zca.c b/drivers/gpu/drm/panel/panel-innolux-p079zca.c index 424d0bf3c5957..72edb334d9976 100644 --- a/drivers/gpu/drm/panel/panel-innolux-p079zca.c +++ b/drivers/gpu/drm/panel/panel-innolux-p079zca.c @@ -11,6 +11,7 @@ #include <linux/gpio/consumer.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/regulator/consumer.h> #include <drm/drmP.h> @@ -512,14 +513,9 @@ static void innolux_panel_del(struct innolux_panel *innolux) static int innolux_panel_probe(struct mipi_dsi_device *dsi) { const struct panel_desc *desc; - const struct of_device_id *id; int err; - id = of_match_node(innolux_of_match, dsi->dev.of_node); - if (!id) - return -ENODEV; - - desc = id->data; + desc = of_device_get_match_data(&dsi->dev); dsi->mode_flags = desc->flags; dsi->format = desc->format; dsi->lanes = desc->lanes; -- GitLab From 7b7c6c81b3a370b46b0c48f4ab7ac3be83237a12 Mon Sep 17 00:00:00 2001 From: Junwei Zhang <Jerry.Zhang@amd.com> Date: Mon, 25 Jun 2018 12:51:14 +0800 Subject: [PATCH 0956/1506] drm/amdgpu: separate gpu address from bo pin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It could be got by amdgpu_bo_gpu_offset() if need Signed-off-by: Junwei Zhang <Jerry.Zhang@amd.com> Reviewed-by: Michel Dänzer <michel.daenzer@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 6 ++---- .../gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_benchmark.c | 6 ++++-- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 5 ++--- drivers/gpu/drm/amd/amdgpu/amdgpu_display.c | 5 ++--- drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c | 6 ++---- drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 17 ++++++----------- drivers/gpu/drm/amd/amdgpu/amdgpu_object.h | 5 ++--- drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_test.c | 6 ++++-- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 2 +- drivers/gpu/drm/amd/amdgpu/dce_v10_0.c | 10 +++++----- drivers/gpu/drm/amd/amdgpu/dce_v11_0.c | 10 +++++----- drivers/gpu/drm/amd/amdgpu/dce_v6_0.c | 10 +++++----- drivers/gpu/drm/amd/amdgpu/dce_v8_0.c | 10 +++++----- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 ++- 17 files changed, 50 insertions(+), 57 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index 305143fcc1cee..98e3bf890d5be 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -251,7 +251,6 @@ int alloc_gtt_mem(struct kgd_dev *kgd, size_t size, struct amdgpu_bo *bo = NULL; struct amdgpu_bo_param bp; int r; - uint64_t gpu_addr_tmp = 0; void *cpu_ptr_tmp = NULL; memset(&bp, 0, sizeof(bp)); @@ -275,8 +274,7 @@ int alloc_gtt_mem(struct kgd_dev *kgd, size_t size, goto allocate_mem_reserve_bo_failed; } - r = amdgpu_bo_pin(bo, AMDGPU_GEM_DOMAIN_GTT, - &gpu_addr_tmp); + r = amdgpu_bo_pin(bo, AMDGPU_GEM_DOMAIN_GTT); if (r) { dev_err(adev->dev, "(%d) failed to pin bo for amdkfd\n", r); goto allocate_mem_pin_bo_failed; @@ -290,7 +288,7 @@ int alloc_gtt_mem(struct kgd_dev *kgd, size_t size, } *mem_obj = bo; - *gpu_addr = gpu_addr_tmp; + *gpu_addr = amdgpu_bo_gpu_offset(bo); *cpu_ptr = cpu_ptr_tmp; amdgpu_bo_unreserve(bo); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index ff8fd75f7ca51..079af8ac2636d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -1587,7 +1587,7 @@ int amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel(struct kgd_dev *kgd, goto bo_reserve_failed; } - ret = amdgpu_bo_pin(bo, AMDGPU_GEM_DOMAIN_GTT, NULL); + ret = amdgpu_bo_pin(bo, AMDGPU_GEM_DOMAIN_GTT); if (ret) { pr_err("Failed to pin bo. ret %d\n", ret); goto pin_failed; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_benchmark.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_benchmark.c index 19cfff31f2e16..cb88d7e8b96b1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_benchmark.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_benchmark.c @@ -95,7 +95,8 @@ static void amdgpu_benchmark_move(struct amdgpu_device *adev, unsigned size, r = amdgpu_bo_reserve(sobj, false); if (unlikely(r != 0)) goto out_cleanup; - r = amdgpu_bo_pin(sobj, sdomain, &saddr); + r = amdgpu_bo_pin(sobj, sdomain); + saddr = amdgpu_bo_gpu_offset(sobj); amdgpu_bo_unreserve(sobj); if (r) { goto out_cleanup; @@ -108,7 +109,8 @@ static void amdgpu_benchmark_move(struct amdgpu_device *adev, unsigned size, r = amdgpu_bo_reserve(dobj, false); if (unlikely(r != 0)) goto out_cleanup; - r = amdgpu_bo_pin(dobj, ddomain, &daddr); + r = amdgpu_bo_pin(dobj, ddomain); + daddr = amdgpu_bo_gpu_offset(dobj); amdgpu_bo_unreserve(dobj); if (r) { goto out_cleanup; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 9883fa9bb41be..2720444ff23a0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -2758,11 +2758,10 @@ int amdgpu_device_resume(struct drm_device *dev, bool resume, bool fbcon) struct amdgpu_bo *aobj = gem_to_amdgpu_bo(amdgpu_crtc->cursor_bo); r = amdgpu_bo_reserve(aobj, true); if (r == 0) { - r = amdgpu_bo_pin(aobj, - AMDGPU_GEM_DOMAIN_VRAM, - &amdgpu_crtc->cursor_addr); + r = amdgpu_bo_pin(aobj, AMDGPU_GEM_DOMAIN_VRAM); if (r != 0) DRM_ERROR("Failed to pin cursor BO (%d)\n", r); + amdgpu_crtc->cursor_addr = amdgpu_bo_gpu_offset(aobj); amdgpu_bo_unreserve(aobj); } } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c index 76ee8e04ff117..a80407cf099b7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c @@ -157,7 +157,6 @@ int amdgpu_display_crtc_page_flip_target(struct drm_crtc *crtc, struct amdgpu_bo *new_abo; unsigned long flags; u64 tiling_flags; - u64 base; int i, r; work = kzalloc(sizeof *work, GFP_KERNEL); @@ -189,7 +188,7 @@ int amdgpu_display_crtc_page_flip_target(struct drm_crtc *crtc, goto cleanup; } - r = amdgpu_bo_pin(new_abo, amdgpu_display_supported_domains(adev), &base); + r = amdgpu_bo_pin(new_abo, amdgpu_display_supported_domains(adev)); if (unlikely(r != 0)) { DRM_ERROR("failed to pin new abo buffer before flip\n"); goto unreserve; @@ -206,7 +205,7 @@ int amdgpu_display_crtc_page_flip_target(struct drm_crtc *crtc, amdgpu_bo_get_tiling_flags(new_abo, &tiling_flags); amdgpu_bo_unreserve(new_abo); - work->base = base; + work->base = amdgpu_bo_gpu_offset(new_abo); work->target_vblank = target - (uint32_t)drm_crtc_vblank_count(crtc) + amdgpu_get_vblank_counter_kms(dev, work->crtc_id); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c index 811c62927c382..c93fd9a6b59cb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c @@ -168,7 +168,7 @@ static int amdgpufb_create_pinned_object(struct amdgpu_fbdev *rfbdev, } - ret = amdgpu_bo_pin(abo, domain, NULL); + ret = amdgpu_bo_pin(abo, domain); if (ret) { amdgpu_bo_unreserve(abo); goto out_unref; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c index 36113cb60ca2f..a54d5655a191a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c @@ -143,14 +143,12 @@ int amdgpu_gart_table_vram_alloc(struct amdgpu_device *adev) */ int amdgpu_gart_table_vram_pin(struct amdgpu_device *adev) { - uint64_t gpu_addr; int r; r = amdgpu_bo_reserve(adev->gart.robj, false); if (unlikely(r != 0)) return r; - r = amdgpu_bo_pin(adev->gart.robj, - AMDGPU_GEM_DOMAIN_VRAM, &gpu_addr); + r = amdgpu_bo_pin(adev->gart.robj, AMDGPU_GEM_DOMAIN_VRAM); if (r) { amdgpu_bo_unreserve(adev->gart.robj); return r; @@ -159,7 +157,7 @@ int amdgpu_gart_table_vram_pin(struct amdgpu_device *adev) if (r) amdgpu_bo_unpin(adev->gart.robj); amdgpu_bo_unreserve(adev->gart.robj); - adev->gart.table_addr = gpu_addr; + adev->gart.table_addr = amdgpu_bo_gpu_offset(adev->gart.robj); return r; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 512f598364369..79cdbf1b9dc98 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -252,11 +252,13 @@ int amdgpu_bo_create_reserved(struct amdgpu_device *adev, goto error_free; } - r = amdgpu_bo_pin(*bo_ptr, domain, gpu_addr); + r = amdgpu_bo_pin(*bo_ptr, domain); if (r) { dev_err(adev->dev, "(%d) kernel bo pin failed\n", r); goto error_unreserve; } + if (gpu_addr) + *gpu_addr = amdgpu_bo_gpu_offset(*bo_ptr); if (cpu_addr) { r = amdgpu_bo_kmap(*bo_ptr, cpu_addr); @@ -817,7 +819,6 @@ void amdgpu_bo_unref(struct amdgpu_bo **bo) * @domain: domain to be pinned to * @min_offset: the start of requested address range * @max_offset: the end of requested address range - * @gpu_addr: GPU offset of the &amdgpu_bo buffer object * * Pins the buffer object according to requested domain and address range. If * the memory is unbound gart memory, binds the pages into gart table. Adjusts @@ -835,8 +836,7 @@ void amdgpu_bo_unref(struct amdgpu_bo **bo) * 0 for success or a negative error code on failure. */ int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain, - u64 min_offset, u64 max_offset, - u64 *gpu_addr) + u64 min_offset, u64 max_offset) { struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); struct ttm_operation_ctx ctx = { false, false }; @@ -868,8 +868,6 @@ int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain, return -EINVAL; bo->pin_count++; - if (gpu_addr) - *gpu_addr = amdgpu_bo_gpu_offset(bo); if (max_offset != 0) { u64 domain_start = bo->tbo.bdev->man[mem_type].gpu_offset; @@ -912,8 +910,6 @@ int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain, } bo->pin_count = 1; - if (gpu_addr != NULL) - *gpu_addr = amdgpu_bo_gpu_offset(bo); domain = amdgpu_mem_type_to_domain(bo->tbo.mem.mem_type); if (domain == AMDGPU_GEM_DOMAIN_VRAM) { @@ -931,7 +927,6 @@ int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain, * amdgpu_bo_pin - pin an &amdgpu_bo buffer object * @bo: &amdgpu_bo buffer object to be pinned * @domain: domain to be pinned to - * @gpu_addr: GPU offset of the &amdgpu_bo buffer object * * A simple wrapper to amdgpu_bo_pin_restricted(). * Provides a simpler API for buffers that do not have any strict restrictions @@ -940,9 +935,9 @@ int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain, * Returns: * 0 for success or a negative error code on failure. */ -int amdgpu_bo_pin(struct amdgpu_bo *bo, u32 domain, u64 *gpu_addr) +int amdgpu_bo_pin(struct amdgpu_bo *bo, u32 domain) { - return amdgpu_bo_pin_restricted(bo, domain, 0, 0, gpu_addr); + return amdgpu_bo_pin_restricted(bo, domain, 0, 0); } /** diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h index 731748033878b..9c3e29a04eb18 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h @@ -252,10 +252,9 @@ void *amdgpu_bo_kptr(struct amdgpu_bo *bo); void amdgpu_bo_kunmap(struct amdgpu_bo *bo); struct amdgpu_bo *amdgpu_bo_ref(struct amdgpu_bo *bo); void amdgpu_bo_unref(struct amdgpu_bo **bo); -int amdgpu_bo_pin(struct amdgpu_bo *bo, u32 domain, u64 *gpu_addr); +int amdgpu_bo_pin(struct amdgpu_bo *bo, u32 domain); int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain, - u64 min_offset, u64 max_offset, - u64 *gpu_addr); + u64 min_offset, u64 max_offset); int amdgpu_bo_unpin(struct amdgpu_bo *bo); int amdgpu_bo_evict_vram(struct amdgpu_device *adev); int amdgpu_bo_init(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c index df7226ad64b52..3ed02f4720035 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c @@ -232,7 +232,7 @@ static int amdgpu_gem_map_attach(struct dma_buf *dma_buf, } /* pin buffer into GTT */ - r = amdgpu_bo_pin(bo, AMDGPU_GEM_DOMAIN_GTT, NULL); + r = amdgpu_bo_pin(bo, AMDGPU_GEM_DOMAIN_GTT); if (r) goto error_unreserve; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c index 57b14dccd8e02..007d70cd69ddb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c @@ -76,11 +76,12 @@ static void amdgpu_do_test_moves(struct amdgpu_device *adev) r = amdgpu_bo_reserve(vram_obj, false); if (unlikely(r != 0)) goto out_unref; - r = amdgpu_bo_pin(vram_obj, AMDGPU_GEM_DOMAIN_VRAM, &vram_addr); + r = amdgpu_bo_pin(vram_obj, AMDGPU_GEM_DOMAIN_VRAM); if (r) { DRM_ERROR("Failed to pin VRAM object\n"); goto out_unres; } + vram_addr = amdgpu_bo_gpu_offset(vram_obj); for (i = 0; i < n; i++) { void *gtt_map, *vram_map; void **gart_start, **gart_end; @@ -97,11 +98,12 @@ static void amdgpu_do_test_moves(struct amdgpu_device *adev) r = amdgpu_bo_reserve(gtt_obj[i], false); if (unlikely(r != 0)) goto out_lclean_unref; - r = amdgpu_bo_pin(gtt_obj[i], AMDGPU_GEM_DOMAIN_GTT, &gart_addr); + r = amdgpu_bo_pin(gtt_obj[i], AMDGPU_GEM_DOMAIN_GTT); if (r) { DRM_ERROR("Failed to pin GTT object %d\n", i); goto out_lclean_unres; } + gart_addr = amdgpu_bo_gpu_offset(gtt_obj[i]); r = amdgpu_bo_kmap(gtt_obj[i], >t_map); if (r) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 0246cb87d9e4e..0e47f15b0f977 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -1695,7 +1695,7 @@ static int amdgpu_ttm_fw_reserve_vram_init(struct amdgpu_device *adev) AMDGPU_GEM_DOMAIN_VRAM, adev->fw_vram_usage.start_offset, (adev->fw_vram_usage.start_offset + - adev->fw_vram_usage.size), NULL); + adev->fw_vram_usage.size)); if (r) goto error_pin; r = amdgpu_bo_kmap(adev->fw_vram_usage.reserved_bo, diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c index ada241bfeee96..ab043228d8da0 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c @@ -1855,15 +1855,14 @@ static int dce_v10_0_crtc_do_set_base(struct drm_crtc *crtc, if (unlikely(r != 0)) return r; - if (atomic) { - fb_location = amdgpu_bo_gpu_offset(abo); - } else { - r = amdgpu_bo_pin(abo, AMDGPU_GEM_DOMAIN_VRAM, &fb_location); + if (!atomic) { + r = amdgpu_bo_pin(abo, AMDGPU_GEM_DOMAIN_VRAM); if (unlikely(r != 0)) { amdgpu_bo_unreserve(abo); return -EINVAL; } } + fb_location = amdgpu_bo_gpu_offset(abo); amdgpu_bo_get_tiling_flags(abo, &tiling_flags); amdgpu_bo_unreserve(abo); @@ -2370,13 +2369,14 @@ static int dce_v10_0_crtc_cursor_set2(struct drm_crtc *crtc, return ret; } - ret = amdgpu_bo_pin(aobj, AMDGPU_GEM_DOMAIN_VRAM, &amdgpu_crtc->cursor_addr); + ret = amdgpu_bo_pin(aobj, AMDGPU_GEM_DOMAIN_VRAM); amdgpu_bo_unreserve(aobj); if (ret) { DRM_ERROR("Failed to pin new cursor BO (%d)\n", ret); drm_gem_object_put_unlocked(obj); return ret; } + amdgpu_crtc->cursor_addr = amdgpu_bo_gpu_offset(aobj); dce_v10_0_lock_cursor(crtc, true); diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c index a5b96eac30332..1778512647547 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c @@ -1897,15 +1897,14 @@ static int dce_v11_0_crtc_do_set_base(struct drm_crtc *crtc, if (unlikely(r != 0)) return r; - if (atomic) { - fb_location = amdgpu_bo_gpu_offset(abo); - } else { - r = amdgpu_bo_pin(abo, AMDGPU_GEM_DOMAIN_VRAM, &fb_location); + if (!atomic) { + r = amdgpu_bo_pin(abo, AMDGPU_GEM_DOMAIN_VRAM); if (unlikely(r != 0)) { amdgpu_bo_unreserve(abo); return -EINVAL; } } + fb_location = amdgpu_bo_gpu_offset(abo); amdgpu_bo_get_tiling_flags(abo, &tiling_flags); amdgpu_bo_unreserve(abo); @@ -2449,13 +2448,14 @@ static int dce_v11_0_crtc_cursor_set2(struct drm_crtc *crtc, return ret; } - ret = amdgpu_bo_pin(aobj, AMDGPU_GEM_DOMAIN_VRAM, &amdgpu_crtc->cursor_addr); + ret = amdgpu_bo_pin(aobj, AMDGPU_GEM_DOMAIN_VRAM); amdgpu_bo_unreserve(aobj); if (ret) { DRM_ERROR("Failed to pin new cursor BO (%d)\n", ret); drm_gem_object_put_unlocked(obj); return ret; } + amdgpu_crtc->cursor_addr = amdgpu_bo_gpu_offset(aobj); dce_v11_0_lock_cursor(crtc, true); diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c index 394cc1e8fe20e..c9adc627305da 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c @@ -1811,15 +1811,14 @@ static int dce_v6_0_crtc_do_set_base(struct drm_crtc *crtc, if (unlikely(r != 0)) return r; - if (atomic) { - fb_location = amdgpu_bo_gpu_offset(abo); - } else { - r = amdgpu_bo_pin(abo, AMDGPU_GEM_DOMAIN_VRAM, &fb_location); + if (!atomic) { + r = amdgpu_bo_pin(abo, AMDGPU_GEM_DOMAIN_VRAM); if (unlikely(r != 0)) { amdgpu_bo_unreserve(abo); return -EINVAL; } } + fb_location = amdgpu_bo_gpu_offset(abo); amdgpu_bo_get_tiling_flags(abo, &tiling_flags); amdgpu_bo_unreserve(abo); @@ -2263,13 +2262,14 @@ static int dce_v6_0_crtc_cursor_set2(struct drm_crtc *crtc, return ret; } - ret = amdgpu_bo_pin(aobj, AMDGPU_GEM_DOMAIN_VRAM, &amdgpu_crtc->cursor_addr); + ret = amdgpu_bo_pin(aobj, AMDGPU_GEM_DOMAIN_VRAM); amdgpu_bo_unreserve(aobj); if (ret) { DRM_ERROR("Failed to pin new cursor BO (%d)\n", ret); drm_gem_object_put_unlocked(obj); return ret; } + amdgpu_crtc->cursor_addr = amdgpu_bo_gpu_offset(aobj); dce_v6_0_lock_cursor(crtc, true); diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c index c9b9ab8f1b059..50cd03beac7d6 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c @@ -1786,15 +1786,14 @@ static int dce_v8_0_crtc_do_set_base(struct drm_crtc *crtc, if (unlikely(r != 0)) return r; - if (atomic) { - fb_location = amdgpu_bo_gpu_offset(abo); - } else { - r = amdgpu_bo_pin(abo, AMDGPU_GEM_DOMAIN_VRAM, &fb_location); + if (!atomic) { + r = amdgpu_bo_pin(abo, AMDGPU_GEM_DOMAIN_VRAM); if (unlikely(r != 0)) { amdgpu_bo_unreserve(abo); return -EINVAL; } } + fb_location = amdgpu_bo_gpu_offset(abo); amdgpu_bo_get_tiling_flags(abo, &tiling_flags); amdgpu_bo_unreserve(abo); @@ -2274,13 +2273,14 @@ static int dce_v8_0_crtc_cursor_set2(struct drm_crtc *crtc, return ret; } - ret = amdgpu_bo_pin(aobj, AMDGPU_GEM_DOMAIN_VRAM, &amdgpu_crtc->cursor_addr); + ret = amdgpu_bo_pin(aobj, AMDGPU_GEM_DOMAIN_VRAM); amdgpu_bo_unreserve(aobj); if (ret) { DRM_ERROR("Failed to pin new cursor BO (%d)\n", ret); drm_gem_object_put_unlocked(obj); return ret; } + amdgpu_crtc->cursor_addr = amdgpu_bo_gpu_offset(aobj); dce_v8_0_lock_cursor(crtc, true); 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 ca017c1dd4dab..02d83c97f10b5 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -3094,7 +3094,7 @@ static int dm_plane_helper_prepare_fb(struct drm_plane *plane, else domain = AMDGPU_GEM_DOMAIN_VRAM; - r = amdgpu_bo_pin(rbo, domain, &afb->address); + r = amdgpu_bo_pin(rbo, domain); amdgpu_bo_unreserve(rbo); if (unlikely(r != 0)) { @@ -3102,6 +3102,7 @@ static int dm_plane_helper_prepare_fb(struct drm_plane *plane, DRM_ERROR("Failed to pin framebuffer with error %d\n", r); return r; } + afb->address = amdgpu_bo_gpu_offset(rbo); amdgpu_bo_ref(rbo); -- GitLab From bb812f1ea87dd7a4f336242212219268393ed308 Mon Sep 17 00:00:00 2001 From: Junwei Zhang <Jerry.Zhang@amd.com> Date: Mon, 25 Jun 2018 13:32:24 +0800 Subject: [PATCH 0957/1506] drm/amdgpu: allocate gart memory when it's required (v3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of calling gart address space on every bo pin, allocates it on demand v2: fix error handling v3: drop the change on amdgpu_amdkfd_gpuvm.c, not needed. Signed-off-by: Junwei Zhang <Jerry.Zhang@amd.com> Acked-by: Felix Kuehling <Felix.Kuehling@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 6 ++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_benchmark.c | 14 ++++++++++++-- drivers/gpu/drm/amd/amdgpu/amdgpu_display.c | 6 ++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c | 8 ++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 15 +++++++++------ drivers/gpu/drm/amd/amdgpu/amdgpu_test.c | 5 +++++ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 13 +++++++++++-- 7 files changed, 57 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index 98e3bf890d5be..e3ed08dca7b7d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -280,6 +280,12 @@ int alloc_gtt_mem(struct kgd_dev *kgd, size_t size, goto allocate_mem_pin_bo_failed; } + r = amdgpu_ttm_alloc_gart(&bo->tbo); + if (r) { + dev_err(adev->dev, "%p bind failed\n", bo); + goto allocate_mem_kmap_bo_failed; + } + r = amdgpu_bo_kmap(bo, &cpu_ptr_tmp); if (r) { dev_err(adev->dev, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_benchmark.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_benchmark.c index cb88d7e8b96b1..3079ea8523c55 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_benchmark.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_benchmark.c @@ -96,11 +96,16 @@ static void amdgpu_benchmark_move(struct amdgpu_device *adev, unsigned size, if (unlikely(r != 0)) goto out_cleanup; r = amdgpu_bo_pin(sobj, sdomain); - saddr = amdgpu_bo_gpu_offset(sobj); + if (r) { + amdgpu_bo_unreserve(sobj); + goto out_cleanup; + } + r = amdgpu_ttm_alloc_gart(&sobj->tbo); amdgpu_bo_unreserve(sobj); if (r) { goto out_cleanup; } + saddr = amdgpu_bo_gpu_offset(sobj); bp.domain = ddomain; r = amdgpu_bo_create(adev, &bp, &dobj); if (r) { @@ -110,11 +115,16 @@ static void amdgpu_benchmark_move(struct amdgpu_device *adev, unsigned size, if (unlikely(r != 0)) goto out_cleanup; r = amdgpu_bo_pin(dobj, ddomain); - daddr = amdgpu_bo_gpu_offset(dobj); + if (r) { + amdgpu_bo_unreserve(sobj); + goto out_cleanup; + } + r = amdgpu_ttm_alloc_gart(&dobj->tbo); amdgpu_bo_unreserve(dobj); if (r) { goto out_cleanup; } + daddr = amdgpu_bo_gpu_offset(dobj); if (adev->mman.buffer_funcs) { time = amdgpu_benchmark_do_move(adev, size, saddr, daddr, n); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c index a80407cf099b7..6748cd7fc129b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c @@ -194,6 +194,12 @@ int amdgpu_display_crtc_page_flip_target(struct drm_crtc *crtc, goto unreserve; } + r = amdgpu_ttm_alloc_gart(&new_abo->tbo); + if (unlikely(r != 0)) { + DRM_ERROR("%p bind failed\n", new_abo); + goto unpin; + } + r = reservation_object_get_fences_rcu(new_abo->tbo.resv, &work->excl, &work->shared_count, &work->shared); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c index c93fd9a6b59cb..d44b76455e896 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c @@ -173,6 +173,14 @@ static int amdgpufb_create_pinned_object(struct amdgpu_fbdev *rfbdev, amdgpu_bo_unreserve(abo); goto out_unref; } + + ret = amdgpu_ttm_alloc_gart(&abo->tbo); + if (ret) { + amdgpu_bo_unreserve(abo); + dev_err(adev->dev, "%p bind failed\n", abo); + goto out_unref; + } + ret = amdgpu_bo_kmap(abo, NULL); amdgpu_bo_unreserve(abo); if (ret) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 79cdbf1b9dc98..7f7c2212aeddf 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -257,6 +257,13 @@ int amdgpu_bo_create_reserved(struct amdgpu_device *adev, dev_err(adev->dev, "(%d) kernel bo pin failed\n", r); goto error_unreserve; } + + r = amdgpu_ttm_alloc_gart(&(*bo_ptr)->tbo); + if (r) { + dev_err(adev->dev, "%p bind failed\n", *bo_ptr); + goto error_unpin; + } + if (gpu_addr) *gpu_addr = amdgpu_bo_gpu_offset(*bo_ptr); @@ -270,6 +277,8 @@ int amdgpu_bo_create_reserved(struct amdgpu_device *adev, return 0; +error_unpin: + amdgpu_bo_unpin(*bo_ptr); error_unreserve: amdgpu_bo_unreserve(*bo_ptr); @@ -903,12 +912,6 @@ int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain, goto error; } - r = amdgpu_ttm_alloc_gart(&bo->tbo); - if (unlikely(r)) { - dev_err(adev->dev, "%p bind failed\n", bo); - goto error; - } - bo->pin_count = 1; domain = amdgpu_mem_type_to_domain(bo->tbo.mem.mem_type); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c index 007d70cd69ddb..8904e62dca7ae 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c @@ -103,6 +103,11 @@ static void amdgpu_do_test_moves(struct amdgpu_device *adev) DRM_ERROR("Failed to pin GTT object %d\n", i); goto out_lclean_unres; } + r = amdgpu_ttm_alloc_gart(>t_obj[i]->tbo); + if (r) { + DRM_ERROR("%p bind failed\n", gtt_obj[i]); + goto out_lclean_unpin; + } gart_addr = amdgpu_bo_gpu_offset(gtt_obj[i]); r = amdgpu_bo_kmap(gtt_obj[i], >t_map); 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 02d83c97f10b5..d2cc32add5f76 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -3095,13 +3095,22 @@ static int dm_plane_helper_prepare_fb(struct drm_plane *plane, domain = AMDGPU_GEM_DOMAIN_VRAM; r = amdgpu_bo_pin(rbo, domain); - amdgpu_bo_unreserve(rbo); - if (unlikely(r != 0)) { if (r != -ERESTARTSYS) DRM_ERROR("Failed to pin framebuffer with error %d\n", r); + amdgpu_bo_unreserve(rbo); + return r; + } + + r = amdgpu_ttm_alloc_gart(&rbo->tbo); + if (unlikely(r != 0)) { + amdgpu_bo_unpin(rbo); + amdgpu_bo_unreserve(rbo); + DRM_ERROR("%p bind failed\n", rbo); return r; } + amdgpu_bo_unreserve(rbo); + afb->address = amdgpu_bo_gpu_offset(rbo); amdgpu_bo_ref(rbo); -- GitLab From dc407ee0bda07e1e992ed7c93c1faef13a1125bd Mon Sep 17 00:00:00 2001 From: Junwei Zhang <Jerry.Zhang@amd.com> Date: Tue, 26 Jun 2018 16:23:48 +0800 Subject: [PATCH 0958/1506] drm/amdgpu: fix kmap error handling for bo creations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit kmap happens after bo pin, so unpin is required on error Signed-off-by: Junwei Zhang <Jerry.Zhang@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 7f7c2212aeddf..9ee678d638906 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -271,7 +271,7 @@ int amdgpu_bo_create_reserved(struct amdgpu_device *adev, r = amdgpu_bo_kmap(*bo_ptr, cpu_addr); if (r) { dev_err(adev->dev, "(%d) kernel bo map failed\n", r); - goto error_unreserve; + goto error_unpin; } } -- GitLab From 02374bbd3bfa38cc6922fe56736716308c48f538 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= <michel.daenzer@amd.com> Date: Mon, 25 Jun 2018 11:07:17 +0200 Subject: [PATCH 0959/1506] drm/amdgpu: Reserve VM root shared fence slot for command submission (v3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without this, there could not be enough slots, which could trigger the BUG_ON in reservation_object_add_shared_fence. v2: * Jump to the error label instead of returning directly (Jerry Zhang) v3: * Reserve slots for command submission after VM updates (Christian König) Cc: stable@vger.kernel.org Bugzilla: https://bugs.freedesktop.org/106418 Reported-by: mikhail.v.gavrilov@gmail.com Signed-off-by: Michel Dänzer <michel.daenzer@amd.com> Signed-off-by: Junwei Zhang <Jerry.Zhang@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 7a625f3989a00..1bc02816989d7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -928,6 +928,10 @@ static int amdgpu_cs_ib_vm_chunk(struct amdgpu_device *adev, r = amdgpu_bo_vm_update_pte(p); if (r) return r; + + r = reservation_object_reserve_shared(vm->root.base.bo->tbo.resv); + if (r) + return r; } return amdgpu_cs_sync_rings(p); -- GitLab From 73b1917454b3639ac1926c869f51e0dc20a0d22f Mon Sep 17 00:00:00 2001 From: Rex Zhu <rex.zhu@amd.com> Date: Thu, 5 Jul 2018 16:34:13 +0800 Subject: [PATCH 0960/1506] drm/amdgpu: Add CLK IP base offset so we can read/write the registers in CLK domain through RREG32/WREG32_SOC15 Reviewed-by: Evan Quan <evan.quan@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 1 + drivers/gpu/drm/amd/amdgpu/vega10_reg_init.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 8a440b9fa0fdc..b38c170fb95c6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1398,6 +1398,7 @@ enum amd_hw_ip_block_type { PWR_HWIP, NBIF_HWIP, THM_HWIP, + CLK_HWIP, MAX_HWIP }; diff --git a/drivers/gpu/drm/amd/amdgpu/vega10_reg_init.c b/drivers/gpu/drm/amd/amdgpu/vega10_reg_init.c index 45aafca7f3156..c5c9b2bc190d5 100644 --- a/drivers/gpu/drm/amd/amdgpu/vega10_reg_init.c +++ b/drivers/gpu/drm/amd/amdgpu/vega10_reg_init.c @@ -51,6 +51,7 @@ int vega10_reg_base_init(struct amdgpu_device *adev) adev->reg_offset[PWR_HWIP][i] = (uint32_t *)(&(PWR_BASE.instance[i])); adev->reg_offset[NBIF_HWIP][i] = (uint32_t *)(&(NBIF_BASE.instance[i])); adev->reg_offset[THM_HWIP][i] = (uint32_t *)(&(THM_BASE.instance[i])); + adev->reg_offset[CLK_HWIP][i] = (uint32_t *)(&(CLK_BASE.instance[i])); } return 0; } -- GitLab From ed0926647daf855abd605525a123eb11a62f5498 Mon Sep 17 00:00:00 2001 From: Rex Zhu <rex.zhu@amd.com> Date: Thu, 5 Jul 2018 16:45:21 +0800 Subject: [PATCH 0961/1506] drm/amd/pp: Convert 10KHz to KHz as variable name The default clock unit in powerplay is 10KHz. Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c | 2 +- drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c index 5e771bc119d69..eb37316cfbf73 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c @@ -3801,7 +3801,7 @@ static int vega10_notify_smc_display_config_after_ps_adjustment( if (i < dpm_table->count) { clock_req.clock_type = amd_pp_dcef_clock; - clock_req.clock_freq_in_khz = dpm_table->dpm_levels[i].value; + clock_req.clock_freq_in_khz = dpm_table->dpm_levels[i].value * 10; if (!vega10_display_clock_voltage_request(hwmgr, &clock_req)) { smum_send_msg_to_smc_with_parameter( hwmgr, PPSMC_MSG_SetMinDeepSleepDcefclk, diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c index 57492878874fa..ed17c560b5ef6 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c @@ -1361,7 +1361,6 @@ int vega12_display_clock_voltage_request(struct pp_hwmgr *hwmgr, if (data->smu_features[GNLD_DPM_DCEFCLK].enabled) { switch (clk_type) { case amd_pp_dcef_clock: - clk_freq = clock_req->clock_freq_in_khz / 100; clk_select = PPCLK_DCEFCLK; break; case amd_pp_disp_clock: @@ -1410,7 +1409,7 @@ static int vega12_notify_smc_display_config_after_ps_adjustment( if (data->smu_features[GNLD_DPM_DCEFCLK].supported) { clock_req.clock_type = amd_pp_dcef_clock; - clock_req.clock_freq_in_khz = min_clocks.dcefClock; + clock_req.clock_freq_in_khz = min_clocks.dcefClock/10; if (!vega12_display_clock_voltage_request(hwmgr, &clock_req)) { if (data->smu_features[GNLD_DS_DCEFCLK].supported) PP_ASSERT_WITH_CODE( -- GitLab From 10e7fddd4aebf95a9468f20fc1a87e6238b7d8d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Fri, 6 Jul 2018 13:46:05 +0200 Subject: [PATCH 0962/1506] drm/amd/display: fix invalid function table override MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Otherwise we try to program hardware with the wrong watermark functions when multiple DCE generations are installed in one system. Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../drm/amd/display/dc/dce/dce_mem_input.c | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.c b/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.c index b235a75355b85..bae752332a9f7 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.c @@ -741,6 +741,29 @@ static struct mem_input_funcs dce_mi_funcs = { .mem_input_is_flip_pending = dce_mi_is_flip_pending }; +static struct mem_input_funcs dce112_mi_funcs = { + .mem_input_program_display_marks = dce112_mi_program_display_marks, + .allocate_mem_input = dce_mi_allocate_dmif, + .free_mem_input = dce_mi_free_dmif, + .mem_input_program_surface_flip_and_addr = + dce_mi_program_surface_flip_and_addr, + .mem_input_program_pte_vm = dce_mi_program_pte_vm, + .mem_input_program_surface_config = + dce_mi_program_surface_config, + .mem_input_is_flip_pending = dce_mi_is_flip_pending +}; + +static struct mem_input_funcs dce120_mi_funcs = { + .mem_input_program_display_marks = dce120_mi_program_display_marks, + .allocate_mem_input = dce_mi_allocate_dmif, + .free_mem_input = dce_mi_free_dmif, + .mem_input_program_surface_flip_and_addr = + dce_mi_program_surface_flip_and_addr, + .mem_input_program_pte_vm = dce_mi_program_pte_vm, + .mem_input_program_surface_config = + dce_mi_program_surface_config, + .mem_input_is_flip_pending = dce_mi_is_flip_pending +}; void dce_mem_input_construct( struct dce_mem_input *dce_mi, @@ -769,7 +792,7 @@ void dce112_mem_input_construct( const struct dce_mem_input_mask *mi_mask) { dce_mem_input_construct(dce_mi, ctx, inst, regs, mi_shift, mi_mask); - dce_mi->base.funcs->mem_input_program_display_marks = dce112_mi_program_display_marks; + dce_mi->base.funcs = &dce112_mi_funcs; } void dce120_mem_input_construct( @@ -781,5 +804,5 @@ void dce120_mem_input_construct( const struct dce_mem_input_mask *mi_mask) { dce_mem_input_construct(dce_mi, ctx, inst, regs, mi_shift, mi_mask); - dce_mi->base.funcs->mem_input_program_display_marks = dce120_mi_program_display_marks; + dce_mi->base.funcs = &dce120_mi_funcs; } -- GitLab From a14cc8422a2601348bc5279c1d849920e91170f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Fri, 6 Jul 2018 14:19:07 +0200 Subject: [PATCH 0963/1506] drm/amd/display: make function tables const MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is good practice to make global function tables const to avoid accidental override. Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.c | 6 +++--- drivers/gpu/drm/amd/display/dc/dce110/dce110_mem_input_v.c | 2 +- drivers/gpu/drm/amd/display/dc/inc/hw/mem_input.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.c b/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.c index bae752332a9f7..85686d9176364 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.c @@ -729,7 +729,7 @@ static bool dce_mi_program_surface_flip_and_addr( return true; } -static struct mem_input_funcs dce_mi_funcs = { +static const struct mem_input_funcs dce_mi_funcs = { .mem_input_program_display_marks = dce_mi_program_display_marks, .allocate_mem_input = dce_mi_allocate_dmif, .free_mem_input = dce_mi_free_dmif, @@ -741,7 +741,7 @@ static struct mem_input_funcs dce_mi_funcs = { .mem_input_is_flip_pending = dce_mi_is_flip_pending }; -static struct mem_input_funcs dce112_mi_funcs = { +static const struct mem_input_funcs dce112_mi_funcs = { .mem_input_program_display_marks = dce112_mi_program_display_marks, .allocate_mem_input = dce_mi_allocate_dmif, .free_mem_input = dce_mi_free_dmif, @@ -753,7 +753,7 @@ static struct mem_input_funcs dce112_mi_funcs = { .mem_input_is_flip_pending = dce_mi_is_flip_pending }; -static struct mem_input_funcs dce120_mi_funcs = { +static const struct mem_input_funcs dce120_mi_funcs = { .mem_input_program_display_marks = dce120_mi_program_display_marks, .allocate_mem_input = dce_mi_allocate_dmif, .free_mem_input = dce_mi_free_dmif, diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_mem_input_v.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_mem_input_v.c index 0564c8e312529..9b9fc3d96c071 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_mem_input_v.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_mem_input_v.c @@ -1011,7 +1011,7 @@ void dce110_free_mem_input_v( { } -static struct mem_input_funcs dce110_mem_input_v_funcs = { +static const struct mem_input_funcs dce110_mem_input_v_funcs = { .mem_input_program_display_marks = dce_mem_input_v_program_display_marks, .mem_input_program_chroma_display_marks = diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/mem_input.h b/drivers/gpu/drm/amd/display/dc/inc/hw/mem_input.h index 47f1dc5a43b74..da89c2edb07c7 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/mem_input.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/mem_input.h @@ -64,7 +64,7 @@ struct stutter_modes { }; struct mem_input { - struct mem_input_funcs *funcs; + const struct mem_input_funcs *funcs; struct dc_context *ctx; struct dc_plane_address request_address; struct dc_plane_address current_address; -- GitLab From bd4e725084189a198ca47d369d85100216d29b7e Mon Sep 17 00:00:00 2001 From: Harry Wentland <harry.wentland@amd.com> Date: Fri, 6 Jul 2018 09:49:05 -0400 Subject: [PATCH 0964/1506] drm/amd/display: Make function pointer structs const MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit const to avoid hard-to-find bugs where some function overrides a function pointer. Signed-off-by: Harry Wentland <harry.wentland@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c | 2 +- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.c | 2 +- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.c | 2 +- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c | 4 ++-- drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) 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 93f52c58bc695..a281bed9b413a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c @@ -1125,7 +1125,7 @@ void hubp1_vtg_sel(struct hubp *hubp, uint32_t otg_inst) REG_UPDATE(DCHUBP_CNTL, HUBP_VTG_SEL, otg_inst); } -static struct hubp_funcs dcn10_hubp_funcs = { +static const struct hubp_funcs dcn10_hubp_funcs = { .hubp_program_surface_flip_and_addr = hubp1_program_surface_flip_and_addr, .hubp_program_surface_config = diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.c index 9ca51ae46de74..958994edf2c49 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.c @@ -428,7 +428,7 @@ void mpc1_read_mpcc_state( MPCC_BUSY, &s->busy); } -const struct mpc_funcs dcn10_mpc_funcs = { +static const struct mpc_funcs dcn10_mpc_funcs = { .read_mpcc_state = mpc1_read_mpcc_state, .insert_plane = mpc1_insert_plane, .remove_mpcc = mpc1_remove_mpcc, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.c index 77a1a9d541a41..ab958cff3b760 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.c @@ -385,7 +385,7 @@ void opp1_destroy(struct output_pixel_processor **opp) *opp = NULL; } -static struct opp_funcs dcn10_opp_funcs = { +static const struct opp_funcs dcn10_opp_funcs = { .opp_set_dyn_expansion = opp1_set_dyn_expansion, .opp_program_fmt = opp1_program_fmt, .opp_program_bit_depth_reduction = opp1_program_bit_depth_reduction, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c index 771e0cf29bbaa..84581b3c392ba 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c @@ -1035,11 +1035,11 @@ static enum dc_status dcn10_validate_plane(const struct dc_plane_state *plane_st return DC_OK; } -static struct dc_cap_funcs cap_funcs = { +static const struct dc_cap_funcs cap_funcs = { .get_dcc_compression_cap = dcn10_get_dcc_compression_cap }; -static struct resource_funcs dcn10_res_pool_funcs = { +static const struct resource_funcs dcn10_res_pool_funcs = { .destroy = dcn10_destroy_resource_pool, .link_enc_create = dcn10_link_encoder_create, .validate_bandwidth = dcn_validate_bandwidth, 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 97df82cddf829..5b7976f6861ab 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h @@ -43,7 +43,7 @@ enum cursor_lines_per_chunk { }; struct hubp { - struct hubp_funcs *funcs; + const struct hubp_funcs *funcs; struct dc_context *ctx; struct dc_plane_address request_address; struct dc_plane_address current_address; -- GitLab From 2aa37bf58838fd0251e0e6819767ffc8a83eac38 Mon Sep 17 00:00:00 2001 From: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Date: Thu, 28 Jun 2018 22:51:32 -0400 Subject: [PATCH 0965/1506] drm/amdgpu: Add support for logging process info in amdgpu_vm. Add process and thread names and pids and a function to extract this info from relevant amdgpu_vm. v2: Add documentation and fix identation. v3: Add getter and setter functions for amdgpu_task_info. Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Acked-by: Jim Qu <Jim.Qu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 39 ++++++++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h | 16 +++++++++++ 2 files changed, 55 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 712af5c1a5d69..d18f24748b344 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -2942,3 +2942,42 @@ int amdgpu_vm_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) return 0; } + +/** + * amdgpu_vm_get_task_info - Extracts task info for a PASID. + * + * @dev: drm device pointer + * @pasid: PASID identifier for VM + * @task_info: task_info to fill. + */ +void amdgpu_vm_get_task_info(struct amdgpu_device *adev, unsigned int pasid, + struct amdgpu_task_info *task_info) +{ + struct amdgpu_vm *vm; + + spin_lock(&adev->vm_manager.pasid_lock); + + vm = idr_find(&adev->vm_manager.pasid_idr, pasid); + if (vm) + *task_info = vm->task_info; + + spin_unlock(&adev->vm_manager.pasid_lock); +} + +/** + * amdgpu_vm_set_task_info - Sets VMs task info. + * + * @vm: vm for which to set the info + */ +void amdgpu_vm_set_task_info(struct amdgpu_vm *vm) +{ + if (!vm->task_info.pid) { + vm->task_info.pid = current->pid; + get_task_comm(vm->task_info.task_name, current); + + if (current->group_leader->mm == current->mm) { + vm->task_info.tgid = current->group_leader->pid; + get_task_comm(vm->task_info.process_name, current->group_leader); + } + } +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h index 061b99a18cb81..d416f895233d3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h @@ -164,6 +164,14 @@ struct amdgpu_vm_pt { #define AMDGPU_VM_FAULT_PASID(fault) ((u64)(fault) >> 48) #define AMDGPU_VM_FAULT_ADDR(fault) ((u64)(fault) & 0xfffffffff000ULL) + +struct amdgpu_task_info { + char process_name[TASK_COMM_LEN]; + char task_name[TASK_COMM_LEN]; + pid_t pid; + pid_t tgid; +}; + struct amdgpu_vm { /* tree of virtual addresses mapped */ struct rb_root_cached va; @@ -215,6 +223,9 @@ struct amdgpu_vm { /* Valid while the PD is reserved or fenced */ uint64_t pd_phys_addr; + + /* Some basic info about the task */ + struct amdgpu_task_info task_info; }; struct amdgpu_vm_manager { @@ -317,4 +328,9 @@ bool amdgpu_vm_need_pipeline_sync(struct amdgpu_ring *ring, struct amdgpu_job *job); void amdgpu_vm_check_compute_bug(struct amdgpu_device *adev); +void amdgpu_vm_get_task_info(struct amdgpu_device *adev, unsigned int pasid, + struct amdgpu_task_info *task_info); + +void amdgpu_vm_set_task_info(struct amdgpu_vm *vm); + #endif -- GitLab From efaa96463929684ceca4be96d0959e9ced1fa093 Mon Sep 17 00:00:00 2001 From: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Date: Thu, 28 Jun 2018 22:55:27 -0400 Subject: [PATCH 0966/1506] drm/amdgpu: Present amdgpu_task_info in VM_FAULTS. Extract and present the reposnsible process and thread when VM_FAULT happens. v2: Use getter and setter functions. Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Acked-by: Jim Qu <Jim.Qu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 4 ++++ drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c | 10 +++++++--- drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c | 9 +++++++-- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 1bc02816989d7..9881a1e55df3e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -187,6 +187,10 @@ static int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data) if (p->uf_entry.robj) p->job->uf_addr = uf_offset; kfree(chunk_array); + + /* Use this opportunity to fill in task info for the vm */ + amdgpu_vm_set_task_info(vm); + return 0; free_all_kdata: diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c index 1edbe6b477b56..a86332f36c3e0 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c @@ -44,7 +44,6 @@ #include "amdgpu_atombios.h" - static void gmc_v8_0_set_gmc_funcs(struct amdgpu_device *adev); static void gmc_v8_0_set_irq_funcs(struct amdgpu_device *adev); static int gmc_v8_0_wait_for_idle(void *handle); @@ -1447,8 +1446,13 @@ static int gmc_v8_0_process_interrupt(struct amdgpu_device *adev, gmc_v8_0_set_fault_enable_default(adev, false); if (printk_ratelimit()) { - dev_err(adev->dev, "GPU fault detected: %d 0x%08x\n", - entry->src_id, entry->src_data[0]); + struct amdgpu_task_info task_info = { 0 }; + + amdgpu_vm_get_task_info(adev, entry->pasid, &task_info); + + dev_err(adev->dev, "GPU fault detected: %d 0x%08x for process %s pid %d thread %s pid %d\n", + entry->src_id, entry->src_data[0], task_info.process_name, + task_info.tgid, task_info.task_name, task_info.pid); dev_err(adev->dev, " VM_CONTEXT1_PROTECTION_FAULT_ADDR 0x%08X\n", addr); dev_err(adev->dev, " VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n", diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c index 3c0a85d4e4ab9..7f238149ba54a 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c @@ -257,11 +257,16 @@ static int gmc_v9_0_process_interrupt(struct amdgpu_device *adev, } if (printk_ratelimit()) { + struct amdgpu_task_info task_info = { 0 }; + + amdgpu_vm_get_task_info(adev, entry->pasid, &task_info); + dev_err(adev->dev, - "[%s] VMC page fault (src_id:%u ring:%u vmid:%u pasid:%u)\n", + "[%s] VMC page fault (src_id:%u ring:%u vmid:%u pasid:%u, for process %s pid %d thread %s pid %d\n)\n", entry->vmid_src ? "mmhub" : "gfxhub", entry->src_id, entry->ring_id, entry->vmid, - entry->pasid); + entry->pasid, task_info.process_name, task_info.tgid, + task_info.task_name, task_info.pid); dev_err(adev->dev, " at page 0x%016llx from %d\n", addr, entry->client_id); if (!amdgpu_sriov_vf(adev)) -- GitLab From e85115786ae1bdcfd86da759928a2b644204d42a Mon Sep 17 00:00:00 2001 From: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Date: Thu, 5 Jul 2018 14:49:34 -0400 Subject: [PATCH 0967/1506] drm/amdgpu: Verify root PD is mapped into kernel address space (v4) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: When PD/PT update made by CPU root PD was not yet mapped causing page fault. Fix: Verify root PD is mapped into CPU address space. v2: Make sure that we add the root PD to the relocated list since then it's get mapped into CPU address space bt default in amdgpu_vm_update_directories. v3: Drop change to not move kernel type BOs to evicted list. v4: Remove redundant bo move to relocated list. Link: https://bugs.freedesktop.org/show_bug.cgi?id=107065 Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Reviewed-by: Junwei Zhang <Jerry.Zhang@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index d18f24748b344..0fd0a718763b6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -156,6 +156,9 @@ static void amdgpu_vm_bo_base_init(struct amdgpu_vm_bo_base *base, return; list_add_tail(&base->bo_list, &bo->va); + if (bo->tbo.type == ttm_bo_type_kernel) + list_move(&base->vm_status, &vm->relocated); + if (bo->tbo.resv != vm->root.base.bo->tbo.resv) return; @@ -540,7 +543,6 @@ static int amdgpu_vm_alloc_levels(struct amdgpu_device *adev, pt->parent = amdgpu_bo_ref(parent->base.bo); amdgpu_vm_bo_base_init(&entry->base, vm, pt); - list_move(&entry->base.vm_status, &vm->relocated); } if (level < AMDGPU_VM_PTB) { -- GitLab From c3cb424a086921f6bb0449b10d998352a756d6d5 Mon Sep 17 00:00:00 2001 From: Harry Wentland <harry.wentland@amd.com> Date: Mon, 9 Jul 2018 13:48:12 -0400 Subject: [PATCH 0968/1506] drm/amd/pp: Send khz clock values to DC for smu7/8 The previous change wasn't covering smu 7 and 8 and therefore DC was seeing wrong clock values. This fixes an issue where the pipes seem to hang with a 4k DP and 1080p HDMI display. Fixes: c3df50abc84b ("drm/amd/pp: Convert clock unit to KHz as defined") Signed-off-by: Harry Wentland <harry.wentland@amd.com> Acked-by: Alex Deucher <alexander.deucher@amd.com> Cc:rex.zhu@amd.com Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c | 8 ++++---- drivers/gpu/drm/amd/powerplay/hwmgr/smu8_hwmgr.c | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c index 077b79938528d..2f7e70730e3cc 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c @@ -4610,12 +4610,12 @@ static int smu7_get_sclks(struct pp_hwmgr *hwmgr, struct amd_pp_clocks *clocks) return -EINVAL; dep_sclk_table = table_info->vdd_dep_on_sclk; for (i = 0; i < dep_sclk_table->count; i++) - clocks->clock[i] = dep_sclk_table->entries[i].clk; + clocks->clock[i] = dep_sclk_table->entries[i].clk * 10; clocks->count = dep_sclk_table->count; } else if (hwmgr->pp_table_version == PP_TABLE_V0) { sclk_table = hwmgr->dyn_state.vddc_dependency_on_sclk; for (i = 0; i < sclk_table->count; i++) - clocks->clock[i] = sclk_table->entries[i].clk; + clocks->clock[i] = sclk_table->entries[i].clk * 10; clocks->count = sclk_table->count; } @@ -4647,7 +4647,7 @@ static int smu7_get_mclks(struct pp_hwmgr *hwmgr, struct amd_pp_clocks *clocks) return -EINVAL; dep_mclk_table = table_info->vdd_dep_on_mclk; for (i = 0; i < dep_mclk_table->count; i++) { - clocks->clock[i] = dep_mclk_table->entries[i].clk; + clocks->clock[i] = dep_mclk_table->entries[i].clk * 10; clocks->latency[i] = smu7_get_mem_latency(hwmgr, dep_mclk_table->entries[i].clk); } @@ -4655,7 +4655,7 @@ static int smu7_get_mclks(struct pp_hwmgr *hwmgr, struct amd_pp_clocks *clocks) } else if (hwmgr->pp_table_version == PP_TABLE_V0) { mclk_table = hwmgr->dyn_state.vddc_dependency_on_mclk; for (i = 0; i < mclk_table->count; i++) - clocks->clock[i] = mclk_table->entries[i].clk; + clocks->clock[i] = mclk_table->entries[i].clk * 10; clocks->count = mclk_table->count; } return 0; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu8_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu8_hwmgr.c index 50690c72b2ea1..288802f209dd9 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu8_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu8_hwmgr.c @@ -1604,17 +1604,17 @@ static int smu8_get_clock_by_type(struct pp_hwmgr *hwmgr, enum amd_pp_clock_type switch (type) { case amd_pp_disp_clock: for (i = 0; i < clocks->count; i++) - clocks->clock[i] = data->sys_info.display_clock[i]; + clocks->clock[i] = data->sys_info.display_clock[i] * 10; break; case amd_pp_sys_clock: table = hwmgr->dyn_state.vddc_dependency_on_sclk; for (i = 0; i < clocks->count; i++) - clocks->clock[i] = table->entries[i].clk; + clocks->clock[i] = table->entries[i].clk * 10; break; case amd_pp_mem_clock: clocks->count = SMU8_NUM_NBPMEMORYCLOCK; for (i = 0; i < clocks->count; i++) - clocks->clock[i] = data->sys_info.nbp_memory_clock[clocks->count - 1 - i]; + clocks->clock[i] = data->sys_info.nbp_memory_clock[clocks->count - 1 - i] * 10; break; default: return -1; -- GitLab From 31e1c59796c8abeba8bbb961bc329a6aa5f5847c Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" <gustavo@embeddedor.com> Date: Mon, 9 Jul 2018 10:24:47 -0500 Subject: [PATCH 0969/1506] drm/ttm: use swap macro in ttm_bo_handle_move_mem MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make use of the swap macro and remove unnecessary variable *tmp_mem*. This makes the code easier to read and maintain. Also, reduces the stack usage. This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva <gustavo@embeddedor.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/ttm/ttm_bo.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 5d8688e522d1a..5142dcb8ce394 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -287,12 +287,9 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo, if (ret) { if (bdev->driver->move_notify) { - struct ttm_mem_reg tmp_mem = *mem; - *mem = bo->mem; - bo->mem = tmp_mem; + swap(*mem, bo->mem); bdev->driver->move_notify(bo, false, mem); - bo->mem = *mem; - *mem = tmp_mem; + swap(*mem, bo->mem); } goto out_err; -- GitLab From 89c815ef07a1db0ac2cc09d06cb2d5c3d86d6322 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann <contact@tzimmermann.org> Date: Thu, 21 Jun 2018 15:21:35 +0200 Subject: [PATCH 0970/1506] drm/ttm: Introduce ttm_bo_get() and ttm_bo_put() for ref counting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The TTM buffer-object interface provides ttm_bo_reference() and ttm_bo_unref() for managing reference counts. Replacing them with ttm_bo_get() and ttm_bo_put() aligns the API with conventions used throughout the Linux kernel. The implementation of ttm_bo_unref() clears the supplied pointer to NULL. This leads to workarounds where the caller saves the pointer's value before de-referencing the BO. ttm_bo_put() does not clear the supplied pointer. Signed-off-by: Thomas Zimmermann <contact@tzimmermann.org> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/ttm/ttm_bo.c | 8 +++++++- include/drm/ttm/ttm_bo_api.h | 25 ++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 5142dcb8ce394..183e67c4197a6 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -587,12 +587,18 @@ static void ttm_bo_release(struct kref *kref) kref_put(&bo->list_kref, ttm_bo_release_list); } +void ttm_bo_put(struct ttm_buffer_object *bo) +{ + kref_put(&bo->kref, ttm_bo_release); +} +EXPORT_SYMBOL(ttm_bo_put); + void ttm_bo_unref(struct ttm_buffer_object **p_bo) { struct ttm_buffer_object *bo = *p_bo; *p_bo = NULL; - kref_put(&bo->kref, ttm_bo_release); + ttm_bo_put(bo); } EXPORT_SYMBOL(ttm_bo_unref); diff --git a/include/drm/ttm/ttm_bo_api.h b/include/drm/ttm/ttm_bo_api.h index c67977aa1a0eb..a01ba2032f0ef 100644 --- a/include/drm/ttm/ttm_bo_api.h +++ b/include/drm/ttm/ttm_bo_api.h @@ -283,18 +283,30 @@ struct ttm_operation_ctx { /* when serving page fault or suspend, allow alloc anyway */ #define TTM_OPT_FLAG_FORCE_ALLOC 0x2 +/** + * ttm_bo_get - reference a struct ttm_buffer_object + * + * @bo: The buffer object. + */ +static inline void ttm_bo_get(struct ttm_buffer_object *bo) +{ + kref_get(&bo->kref); +} + /** * ttm_bo_reference - reference a struct ttm_buffer_object * * @bo: The buffer object. * * Returns a refcounted pointer to a buffer object. + * + * This function is deprecated. Use @ttm_bo_get instead. */ static inline struct ttm_buffer_object * ttm_bo_reference(struct ttm_buffer_object *bo) { - kref_get(&bo->kref); + ttm_bo_get(bo); return bo; } @@ -345,12 +357,23 @@ int ttm_bo_validate(struct ttm_buffer_object *bo, struct ttm_placement *placement, struct ttm_operation_ctx *ctx); +/** + * ttm_bo_put + * + * @bo: The buffer object. + * + * Unreference a buffer object. + */ +void ttm_bo_put(struct ttm_buffer_object *bo); + /** * ttm_bo_unref * * @bo: The buffer object. * * Unreference and clear a pointer to a buffer object. + * + * This function is deprecated. Use @ttm_bo_put instead. */ void ttm_bo_unref(struct ttm_buffer_object **bo); -- GitLab From 8129fdad387ae3cf6373d74a6afb5372bf773cbd Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann <contact@tzimmermann.org> Date: Thu, 21 Jun 2018 15:21:36 +0200 Subject: [PATCH 0971/1506] drm/ttm: Replace ttm_bo_reference() with ttm_bo_get() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Zimmermann <contact@tzimmermann.org> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/ttm/ttm_bo_util.c | 3 ++- drivers/gpu/drm/ttm/ttm_bo_vm.c | 10 ++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c index f2c167702eef5..897c799832f6d 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c @@ -492,8 +492,9 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo, if (!fbo) return -ENOMEM; + ttm_bo_get(bo); fbo->base = *bo; - fbo->bo = ttm_bo_reference(bo); + fbo->bo = bo; /** * Fix up members that we shouldn't copy directly: diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c index 0ca0ec47334e2..9eaca0acb650f 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_vm.c +++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c @@ -68,7 +68,7 @@ static vm_fault_t ttm_bo_vm_fault_idle(struct ttm_buffer_object *bo, if (vmf->flags & FAULT_FLAG_RETRY_NOWAIT) goto out_unlock; - ttm_bo_reference(bo); + ttm_bo_get(bo); up_read(&vmf->vma->vm_mm->mmap_sem); (void) dma_fence_wait(bo->moving, true); ttm_bo_unreserve(bo); @@ -138,7 +138,7 @@ static vm_fault_t ttm_bo_vm_fault(struct vm_fault *vmf) if (vmf->flags & FAULT_FLAG_ALLOW_RETRY) { if (!(vmf->flags & FAULT_FLAG_RETRY_NOWAIT)) { - ttm_bo_reference(bo); + ttm_bo_get(bo); up_read(&vmf->vma->vm_mm->mmap_sem); (void) ttm_bo_wait_unreserved(bo); ttm_bo_unref(&bo); @@ -302,7 +302,7 @@ static void ttm_bo_vm_open(struct vm_area_struct *vma) WARN_ON(bo->bdev->dev_mapping != vma->vm_file->f_mapping); - (void)ttm_bo_reference(bo); + ttm_bo_get(bo); } static void ttm_bo_vm_close(struct vm_area_struct *vma) @@ -471,8 +471,10 @@ int ttm_fbdev_mmap(struct vm_area_struct *vma, struct ttm_buffer_object *bo) if (vma->vm_pgoff != 0) return -EACCES; + ttm_bo_get(bo); + vma->vm_ops = &ttm_bo_vm_ops; - vma->vm_private_data = ttm_bo_reference(bo); + vma->vm_private_data = bo; vma->vm_flags |= VM_MIXEDMAP; vma->vm_flags |= VM_IO | VM_DONTEXPAND; return 0; -- GitLab From f44907593d746d42821543992b7c7085d2cbeafb Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann <contact@tzimmermann.org> Date: Thu, 21 Jun 2018 15:21:37 +0200 Subject: [PATCH 0972/1506] drm/ttm: Replace ttm_bo_unref() with ttm_bo_put() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A call to ttm_bo_unref() clears the supplied pointer to NULL, while ttm_bo_put() does not. None of the converted call sites requires the pointer to become NULL, so the respective assign operations has been left out from the patch. Signed-off-by: Thomas Zimmermann <contact@tzimmermann.org> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/ttm/ttm_bo.c | 2 +- drivers/gpu/drm/ttm/ttm_bo_util.c | 8 ++++---- drivers/gpu/drm/ttm/ttm_bo_vm.c | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 183e67c4197a6..7c484729f9b21 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -1204,7 +1204,7 @@ int ttm_bo_init_reserved(struct ttm_bo_device *bdev, if (!resv) ttm_bo_unreserve(bo); - ttm_bo_unref(&bo); + ttm_bo_put(bo); return ret; } diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c index 897c799832f6d..046a6dda690a2 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c @@ -463,7 +463,7 @@ static void ttm_transfered_destroy(struct ttm_buffer_object *bo) struct ttm_transfer_obj *fbo; fbo = container_of(bo, struct ttm_transfer_obj, base); - ttm_bo_unref(&fbo->bo); + ttm_bo_put(fbo->bo); kfree(fbo); } @@ -731,7 +731,7 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo, bo->ttm = NULL; ttm_bo_unreserve(ghost_obj); - ttm_bo_unref(&ghost_obj); + ttm_bo_put(ghost_obj); } *old_mem = *new_mem; @@ -787,7 +787,7 @@ int ttm_bo_pipeline_move(struct ttm_buffer_object *bo, bo->ttm = NULL; ttm_bo_unreserve(ghost_obj); - ttm_bo_unref(&ghost_obj); + ttm_bo_put(ghost_obj); } else if (from->flags & TTM_MEMTYPE_FLAG_FIXED) { @@ -852,7 +852,7 @@ int ttm_bo_pipeline_gutting(struct ttm_buffer_object *bo) bo->ttm = NULL; ttm_bo_unreserve(ghost); - ttm_bo_unref(&ghost); + ttm_bo_put(ghost); return 0; } diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c index 9eaca0acb650f..6fe91c1b692d6 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_vm.c +++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c @@ -72,7 +72,7 @@ static vm_fault_t ttm_bo_vm_fault_idle(struct ttm_buffer_object *bo, up_read(&vmf->vma->vm_mm->mmap_sem); (void) dma_fence_wait(bo->moving, true); ttm_bo_unreserve(bo); - ttm_bo_unref(&bo); + ttm_bo_put(bo); goto out_unlock; } @@ -141,7 +141,7 @@ static vm_fault_t ttm_bo_vm_fault(struct vm_fault *vmf) ttm_bo_get(bo); up_read(&vmf->vma->vm_mm->mmap_sem); (void) ttm_bo_wait_unreserved(bo); - ttm_bo_unref(&bo); + ttm_bo_put(bo); } return VM_FAULT_RETRY; @@ -309,7 +309,7 @@ static void ttm_bo_vm_close(struct vm_area_struct *vma) { struct ttm_buffer_object *bo = (struct ttm_buffer_object *)vma->vm_private_data; - ttm_bo_unref(&bo); + ttm_bo_put(bo); vma->vm_private_data = NULL; } @@ -461,7 +461,7 @@ int ttm_bo_mmap(struct file *filp, struct vm_area_struct *vma, vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP; return 0; out_unref: - ttm_bo_unref(&bo); + ttm_bo_put(bo); return ret; } EXPORT_SYMBOL(ttm_bo_mmap); -- GitLab From 7b4e54a9729d0a57cf036af801aa1e78ef315982 Mon Sep 17 00:00:00 2001 From: Leo Liu <leo.liu@amd.com> Date: Mon, 9 Jul 2018 11:59:01 -0400 Subject: [PATCH 0973/1506] drm/amdgpu: Take VCN jpeg ring into account in idle work handler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VCN won't get power off when only jpeg active Signed-off-by: Leo Liu <leo.liu@amd.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c index a66cd521a8754..4a3457236e856 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c @@ -211,6 +211,8 @@ static void amdgpu_vcn_idle_work_handler(struct work_struct *work) fences += amdgpu_fence_count_emitted(&adev->vcn.ring_enc[i]); } + fences += amdgpu_fence_count_emitted(&adev->vcn.ring_jpeg); + if (fences == 0) { if (adev->pm.dpm_enabled) amdgpu_dpm_enable_uvd(adev, false); -- GitLab From d02f16058e661608566e444e1a433db8b0a32c0b Mon Sep 17 00:00:00 2001 From: Leo Liu <leo.liu@amd.com> Date: Wed, 4 Jul 2018 13:43:38 -0400 Subject: [PATCH 0974/1506] drm/amdgpu: move cache window setup after power and clock resume MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To make register read/write reliable Signed-off-by: Leo Liu <leo.liu@amd.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c index b82c92084b6f4..ca4265bc10b99 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c @@ -600,12 +600,12 @@ static int vcn_v1_0_start(struct amdgpu_device *adev) /* disable byte swapping */ lmi_swap_cntl = 0; - vcn_v1_0_mc_resume(adev); - vcn_1_0_disable_static_power_gating(adev); /* disable clock gating */ vcn_v1_0_disable_clock_gating(adev); + vcn_v1_0_mc_resume(adev); + /* disable interupt */ WREG32_P(SOC15_REG_OFFSET(UVD, 0, mmUVD_MASTINT_EN), 0, ~UVD_MASTINT_EN__VCPU_EN_MASK); -- GitLab From c1ee15b39fedbeb856cb5867762dd3f3fb779611 Mon Sep 17 00:00:00 2001 From: Leo Liu <leo.liu@amd.com> Date: Wed, 4 Jul 2018 13:35:56 -0400 Subject: [PATCH 0975/1506] drm/amdgpu: get VCN start to process in the dpm disabled case MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: 22cc6c5e19 (drm/amdgpu: Add runtime VCN PG support) Signed-off-by: Leo Liu <leo.liu@amd.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c index 4a3457236e856..769c6723c9caf 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c @@ -229,7 +229,7 @@ void amdgpu_vcn_ring_begin_use(struct amdgpu_ring *ring) struct amdgpu_device *adev = ring->adev; bool set_clocks = !cancel_delayed_work_sync(&adev->vcn.idle_work); - if (set_clocks && adev->pm.dpm_enabled) { + if (set_clocks) { if (adev->pm.dpm_enabled) amdgpu_dpm_enable_uvd(adev, true); else -- GitLab From 0d7f824b3342c774ea18062f5f0f39d542947c34 Mon Sep 17 00:00:00 2001 From: kbuild test robot <fengguang.wu@intel.com> Date: Wed, 11 Jul 2018 01:11:08 +0800 Subject: [PATCH 0976/1506] drm/amd/pp: fix semicolon.cocci warnings drivers/gpu/drm/amd/amdgpu/../powerplay/amd_powerplay.c:1209:17-18: Unneeded semicolon Remove unneeded semicolon. Generated by: scripts/coccinelle/misc/semicolon.cocci Fixes: ea870e44415a ("drm/amd/pp: Export notify_smu_enable_pwe to display") CC: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: kbuild test robot <fengguang.wu@intel.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/powerplay/amd_powerplay.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c index 145e5c403bea5..75c208283e5f9 100644 --- a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c +++ b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c @@ -1206,7 +1206,7 @@ static int pp_notify_smu_enable_pwe(void *handle) struct pp_hwmgr *hwmgr = handle; if (!hwmgr || !hwmgr->pm_en) - return -EINVAL;; + return -EINVAL; if (hwmgr->hwmgr_func->smus_notify_pwe == NULL) { pr_info("%s was not implemented.\n", __func__); -- GitLab From db0c8d8b031d2b5960f6407f7f2ca20e97e00605 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni <paulo.r.zanoni@intel.com> Date: Fri, 4 May 2018 13:32:51 -0700 Subject: [PATCH 0977/1506] x86/gpu: reserve ICL's graphics stolen memory ICL changes the registers and addresses to 64 bits. I also briefly looked at implementing an u64 version of the PCI config read functions, but I concluded this wouldn't be trivial, so it's not worth doing it for a single user that can't have any racing problems while reading the register in two separate operations. v2: - Scrub the development (non-public) changelog (Joonas). - Remove the i915.ko bits so this can be easily backported in order to properly avoid stolen memory even on machines without i915.ko (Joonas). - CC stable for the reasons above. Issue: VIZ-9250 CC: stable@vger.kernel.org Cc: Ingo Molnar <mingo@kernel.org> Cc: H. Peter Anvin <hpa@zytor.com> Cc: x86@kernel.org Cc: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Fixes: 412310019a20 ("drm/i915/icl: Add initial Icelake definitions.") Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Acked-by: Ingo Molnar <mingo@kernel.org> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180504203252.28048-1-paulo.r.zanoni@intel.com --- arch/x86/kernel/early-quirks.c | 18 ++++++++++++++++++ include/drm/i915_drm.h | 4 +++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c index bae0d32e327b5..72c2cf961d44b 100644 --- a/arch/x86/kernel/early-quirks.c +++ b/arch/x86/kernel/early-quirks.c @@ -340,6 +340,18 @@ static resource_size_t __init gen3_stolen_base(int num, int slot, int func, return bsm & INTEL_BSM_MASK; } +static resource_size_t __init gen11_stolen_base(int num, int slot, int func, + resource_size_t stolen_size) +{ + u64 bsm; + + bsm = read_pci_config(num, slot, func, INTEL_GEN11_BSM_DW0); + bsm &= INTEL_BSM_MASK; + bsm |= (u64)read_pci_config(num, slot, func, INTEL_GEN11_BSM_DW1) << 32; + + return bsm; +} + static resource_size_t __init i830_stolen_size(int num, int slot, int func) { u16 gmch_ctrl; @@ -500,6 +512,11 @@ static const struct intel_early_ops chv_early_ops __initconst = { .stolen_size = chv_stolen_size, }; +static const struct intel_early_ops gen11_early_ops __initconst = { + .stolen_base = gen11_stolen_base, + .stolen_size = gen9_stolen_size, +}; + static const struct pci_device_id intel_early_ids[] __initconst = { INTEL_I830_IDS(&i830_early_ops), INTEL_I845G_IDS(&i845_early_ops), @@ -531,6 +548,7 @@ static const struct pci_device_id intel_early_ids[] __initconst = { INTEL_CFL_IDS(&gen9_early_ops), INTEL_GLK_IDS(&gen9_early_ops), INTEL_CNL_IDS(&gen9_early_ops), + INTEL_ICL_11_IDS(&gen11_early_ops), }; struct resource intel_graphics_stolen_res __ro_after_init = DEFINE_RES_MEM(0, 0); diff --git a/include/drm/i915_drm.h b/include/drm/i915_drm.h index c9e5a6621b954..c44703f471b37 100644 --- a/include/drm/i915_drm.h +++ b/include/drm/i915_drm.h @@ -95,7 +95,9 @@ extern struct resource intel_graphics_stolen_res; #define I845_TSEG_SIZE_512K (2 << 1) #define I845_TSEG_SIZE_1M (3 << 1) -#define INTEL_BSM 0x5c +#define INTEL_BSM 0x5c +#define INTEL_GEN11_BSM_DW0 0xc0 +#define INTEL_GEN11_BSM_DW1 0xc4 #define INTEL_BSM_MASK (-(1u << 20)) #endif /* _I915_DRM_H_ */ -- GitLab From 185441e03aa9dde9fb99e6a015441fc9b312d2ef Mon Sep 17 00:00:00 2001 From: Paulo Zanoni <paulo.r.zanoni@intel.com> Date: Fri, 4 May 2018 13:32:52 -0700 Subject: [PATCH 0978/1506] drm/i915: use the ICL stolen memory Now that our stolen memory is already reserved by the x86 subsystem (since commit "x86/gpu: reserve ICL's graphics stolen memory"), make use of it. Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com> Cc: x86@kernel.org Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180504203252.28048-2-paulo.r.zanoni@intel.com --- drivers/gpu/drm/i915/i915_gem_stolen.c | 38 +++++++++++++++++++++++++- drivers/gpu/drm/i915/i915_reg.h | 1 + 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index 055f8687776d0..53440bf876501 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -344,6 +344,35 @@ static void bdw_get_stolen_reserved(struct drm_i915_private *dev_priv, *size = stolen_top - *base; } +static void icl_get_stolen_reserved(struct drm_i915_private *dev_priv, + resource_size_t *base, + resource_size_t *size) +{ + u64 reg_val = I915_READ64(GEN6_STOLEN_RESERVED); + + DRM_DEBUG_DRIVER("GEN6_STOLEN_RESERVED = 0x%016llx\n", reg_val); + + *base = reg_val & GEN11_STOLEN_RESERVED_ADDR_MASK; + + switch (reg_val & GEN8_STOLEN_RESERVED_SIZE_MASK) { + case GEN8_STOLEN_RESERVED_1M: + *size = 1024 * 1024; + break; + case GEN8_STOLEN_RESERVED_2M: + *size = 2 * 1024 * 1024; + break; + case GEN8_STOLEN_RESERVED_4M: + *size = 4 * 1024 * 1024; + break; + case GEN8_STOLEN_RESERVED_8M: + *size = 8 * 1024 * 1024; + break; + default: + *size = 8 * 1024 * 1024; + MISSING_CASE(reg_val & GEN8_STOLEN_RESERVED_SIZE_MASK); + } +} + int i915_gem_init_stolen(struct drm_i915_private *dev_priv) { resource_size_t reserved_base, stolen_top; @@ -400,7 +429,9 @@ int i915_gem_init_stolen(struct drm_i915_private *dev_priv) gen7_get_stolen_reserved(dev_priv, &reserved_base, &reserved_size); break; - default: + case 8: + case 9: + case 10: if (IS_LP(dev_priv)) chv_get_stolen_reserved(dev_priv, &reserved_base, &reserved_size); @@ -408,6 +439,11 @@ int i915_gem_init_stolen(struct drm_i915_private *dev_priv) bdw_get_stolen_reserved(dev_priv, &reserved_base, &reserved_size); break; + case 11: + default: + icl_get_stolen_reserved(dev_priv, &reserved_base, + &reserved_size); + break; } /* diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 0424e45f88dbc..b95bab7a3d24a 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -412,6 +412,7 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define GEN8_STOLEN_RESERVED_4M (2 << 7) #define GEN8_STOLEN_RESERVED_8M (3 << 7) #define GEN6_STOLEN_RESERVED_ENABLE (1 << 0) +#define GEN11_STOLEN_RESERVED_ADDR_MASK (0xFFFFFFFFFFFULL << 20) /* VGA stuff */ -- GitLab From decac6b00542ea2b95b68863fe3890ed134e5b57 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec <jernej.skrabec@siol.net> Date: Tue, 10 Jul 2018 22:34:54 +0200 Subject: [PATCH 0979/1506] dt-bindings: display: sun4i-drm: Add R40 display engine compatible R40 has pretty unique display pipeline. It supports two outputs at the same time. Possible outputs: - 1x HDMI, - 2x TV output - 1x VGA, - 1x MIPI DSI and - 2x LCD outputs That is the biggest number of possible outputs from all Allwinner SoC. Because of that, add new compatible for it. Reviewed-by: Chen-Yu Tsai <wens@csie.org> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180710203511.18454-2-jernej.skrabec@siol.net --- Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt index 5a9319ad8861c..288b4cbc255e0 100644 --- a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt +++ b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt @@ -399,6 +399,7 @@ Required properties: * allwinner,sun8i-a33-display-engine * allwinner,sun8i-a83t-display-engine * allwinner,sun8i-h3-display-engine + * allwinner,sun8i-r40-display-engine * allwinner,sun8i-v3s-display-engine * allwinner,sun9i-a80-display-engine -- GitLab From d978a94b0a9e011dc3a7528fc9a34f0553ad0890 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec <jernej.skrabec@siol.net> Date: Tue, 10 Jul 2018 22:34:55 +0200 Subject: [PATCH 0980/1506] drm/sun4i: Add R40 display engine compatible R40 has versatile display pipeline. It supports two simultanious outputs on various outputs (TVE, VGA, HDMI, MIPI DSI, LCD). Reviewed-by: Chen-Yu Tsai <wens@csie.org> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180710203511.18454-3-jernej.skrabec@siol.net --- drivers/gpu/drm/sun4i/sun4i_drv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c index 6ddf4eaccb400..a15feb8073938 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.c +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c @@ -417,6 +417,7 @@ static const struct of_device_id sun4i_drv_of_table[] = { { .compatible = "allwinner,sun8i-a33-display-engine" }, { .compatible = "allwinner,sun8i-a83t-display-engine" }, { .compatible = "allwinner,sun8i-h3-display-engine" }, + { .compatible = "allwinner,sun8i-r40-display-engine" }, { .compatible = "allwinner,sun8i-v3s-display-engine" }, { .compatible = "allwinner,sun9i-a80-display-engine" }, { } -- GitLab From af11942ee44ed9d61ce7d8b1bd3277195ec4c1c1 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec <jernej.skrabec@siol.net> Date: Tue, 10 Jul 2018 22:34:57 +0200 Subject: [PATCH 0981/1506] drm/sun4i: tcon-top: Cleanup clock handling There is no need to acquire reference to clock just to get its name. This commit just cleans up the code. There is no functional change. Reviewed-by: Chen-Yu Tsai <wens@csie.org> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net> [Maxime: Fixed the of_property_match_string error check] Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180710203511.18454-5-jernej.skrabec@siol.net --- drivers/gpu/drm/sun4i/sun8i_tcon_top.c | 48 ++++++-------------------- 1 file changed, 11 insertions(+), 37 deletions(-) diff --git a/drivers/gpu/drm/sun4i/sun8i_tcon_top.c b/drivers/gpu/drm/sun4i/sun8i_tcon_top.c index 8da0460e0028c..ab2591a92ef0a 100644 --- a/drivers/gpu/drm/sun4i/sun8i_tcon_top.c +++ b/drivers/gpu/drm/sun4i/sun8i_tcon_top.c @@ -44,15 +44,20 @@ static int sun8i_tcon_top_get_connected_ep_id(struct device_node *node, } static struct clk_hw *sun8i_tcon_top_register_gate(struct device *dev, - struct clk *parent, + const char *parent, void __iomem *regs, spinlock_t *lock, u8 bit, int name_index) { const char *clk_name, *parent_name; - int ret; + int ret, index; + + index = of_property_match_string(dev->of_node, "clock-names", parent); + if (index < 0) + return index; + + parent_name = of_clk_get_parent_name(dev->of_node, index); - parent_name = __clk_get_name(parent); ret = of_property_read_string_index(dev->of_node, "clock-output-names", name_index, &clk_name); @@ -69,7 +74,6 @@ static int sun8i_tcon_top_bind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); - struct clk *dsi, *tcon_tv0, *tcon_tv1, *tve0, *tve1; struct clk_hw_onecell_data *clk_data; struct sun8i_tcon_top *tcon_top; bool mixer0_unused = false; @@ -103,36 +107,6 @@ static int sun8i_tcon_top_bind(struct device *dev, struct device *master, return PTR_ERR(tcon_top->bus); } - dsi = devm_clk_get(dev, "dsi"); - if (IS_ERR(dsi)) { - dev_err(dev, "Couldn't get the dsi clock\n"); - return PTR_ERR(dsi); - } - - tcon_tv0 = devm_clk_get(dev, "tcon-tv0"); - if (IS_ERR(tcon_tv0)) { - dev_err(dev, "Couldn't get the tcon-tv0 clock\n"); - return PTR_ERR(tcon_tv0); - } - - tcon_tv1 = devm_clk_get(dev, "tcon-tv1"); - if (IS_ERR(tcon_tv1)) { - dev_err(dev, "Couldn't get the tcon-tv1 clock\n"); - return PTR_ERR(tcon_tv1); - } - - tve0 = devm_clk_get(dev, "tve0"); - if (IS_ERR(tve0)) { - dev_err(dev, "Couldn't get the tve0 clock\n"); - return PTR_ERR(tve0); - } - - tve1 = devm_clk_get(dev, "tve1"); - if (IS_ERR(tve1)) { - dev_err(dev, "Couldn't get the tve1 clock\n"); - return PTR_ERR(tve1); - } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = devm_ioremap_resource(dev, res); if (IS_ERR(regs)) @@ -203,17 +177,17 @@ static int sun8i_tcon_top_bind(struct device *dev, struct device *master, * to TVE clock parent. */ clk_data->hws[CLK_TCON_TOP_TV0] = - sun8i_tcon_top_register_gate(dev, tcon_tv0, regs, + sun8i_tcon_top_register_gate(dev, "tcon-tv0", regs, &tcon_top->reg_lock, TCON_TOP_TCON_TV0_GATE, 0); clk_data->hws[CLK_TCON_TOP_TV1] = - sun8i_tcon_top_register_gate(dev, tcon_tv1, regs, + sun8i_tcon_top_register_gate(dev, "tcon-tv1", regs, &tcon_top->reg_lock, TCON_TOP_TCON_TV1_GATE, 1); clk_data->hws[CLK_TCON_TOP_DSI] = - sun8i_tcon_top_register_gate(dev, dsi, regs, + sun8i_tcon_top_register_gate(dev, "dsi", regs, &tcon_top->reg_lock, TCON_TOP_TCON_DSI_GATE, 2); -- GitLab From da82107ecf328d4914d316872866ceeb683c01eb Mon Sep 17 00:00:00 2001 From: Jernej Skrabec <jernej.skrabec@siol.net> Date: Tue, 10 Jul 2018 22:34:58 +0200 Subject: [PATCH 0982/1506] drm/sun4i: tcon: Release node when traversing of graph Function sun4i_tcon_find_engine_traverse() doesn't release node if it needs to traverse of graph deeper than 1 level. Fix this by calling of_node_put(). Fixes: 49836b11fe71 ("drm/sun4i: tcon: Generalize engine search algorithm") Reviewed-by: Chen-Yu Tsai <wens@csie.org> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180710203511.18454-6-jernej.skrabec@siol.net --- drivers/gpu/drm/sun4i/sun4i_tcon.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c index aacc841d3dc6f..3fb084f802e29 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c @@ -811,6 +811,7 @@ sun4i_tcon_find_engine_traverse(struct sun4i_drv *drv, * remote output id. If this for some reason can't be done, 0 * is used as input port id. */ + of_node_put(port); port = of_graph_get_remote_port(ep); if (!of_property_read_u32(port, "reg", ®) && reg > 0) reg -= 1; -- GitLab From 7a6677753413440781f07e372fd6f06a4b589c88 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec <jernej.skrabec@siol.net> Date: Tue, 10 Jul 2018 22:34:59 +0200 Subject: [PATCH 0983/1506] dt-bindings: display: sun4i-drm: Add R40 TV TCON description TCON description is expanded with R40 TV TCON compatible. It is a bit special, because it is connected to TCON TOP instead directly to mixer and it needs special handling. Reviewed-by: Chen-Yu Tsai <wens@csie.org> Acked-by: Rob Herring <robh@kernel.org> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180710203511.18454-7-jernej.skrabec@siol.net --- Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt index 288b4cbc255e0..7e2451396a284 100644 --- a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt +++ b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt @@ -147,6 +147,7 @@ Required properties: * allwinner,sun8i-a33-tcon * allwinner,sun8i-a83t-tcon-lcd * allwinner,sun8i-a83t-tcon-tv + * allwinner,sun8i-r40-tcon-tv * allwinner,sun8i-v3s-tcon * allwinner,sun9i-a80-tcon-lcd * allwinner,sun9i-a80-tcon-tv @@ -181,7 +182,7 @@ For TCONs with channel 0, there is one more clock required: For TCONs with channel 1, there is one more clock required: - 'tcon-ch1': The clock driving the TCON channel 1 -When TCON support LVDS (all TCONs except TV TCON on A83T and those found +When TCON support LVDS (all TCONs except TV TCONs on A83T, R40 and those found in A13, H3, H5 and V3s SoCs), you need one more reset line: - 'lvds': The reset line driving the LVDS logic -- GitLab From 4a068c5c17e8e33518de0b102c0d23ed3615286b Mon Sep 17 00:00:00 2001 From: Jernej Skrabec <jernej.skrabec@siol.net> Date: Tue, 10 Jul 2018 22:35:00 +0200 Subject: [PATCH 0984/1506] drm/sun4i: DW HDMI: Release nodes if error happens during CRTC search If error happens in sun8i_dw_hdmi_find_possible_crtcs(), nodes are not released with of_node_put() before returning. Fix that by calling of_node_put() when necessary. While on it, clean up the code by using of_graph_get_remote_node() which also lowers number of cases where error handling has to be performed. Fixes: 57e23de02f48 ("drm/sun4i: DW HDMI: Expand algorithm for possible crtcs") Reviewed-by: Chen-Yu Tsai <wens@csie.org> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180710203511.18454-8-jernej.skrabec@siol.net --- drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c index 3459b9ec56c9b..21dc9ebad0b43 100644 --- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c +++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c @@ -53,22 +53,14 @@ static u32 sun8i_dw_hdmi_find_possible_crtcs(struct drm_device *drm, struct device_node *port, *ep, *remote, *remote_port; u32 crtcs = 0; - port = of_graph_get_port_by_id(node, 0); - if (!port) - return 0; - - ep = of_get_next_available_child(port, NULL); - if (!ep) - return 0; - - remote = of_graph_get_remote_port_parent(ep); + remote = of_graph_get_remote_node(node, 0, -1); if (!remote) return 0; if (sun8i_dw_hdmi_node_is_tcon_top(remote)) { port = of_graph_get_port_by_id(remote, 4); if (!port) - return 0; + goto crtcs_exit; for_each_child_of_node(port, ep) { remote_port = of_graph_get_remote_port(ep); @@ -81,6 +73,9 @@ static u32 sun8i_dw_hdmi_find_possible_crtcs(struct drm_device *drm, crtcs = drm_of_find_possible_crtcs(drm, node); } +crtcs_exit: + of_node_put(remote); + return crtcs; } -- GitLab From e0f56782bc2d715d6386f77df40e31e64e2b80b7 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec <jernej.skrabec@siol.net> Date: Tue, 10 Jul 2018 22:35:02 +0200 Subject: [PATCH 0985/1506] drm/sun4i: mixer: Order includes alphabetically Includes are not alphabetically ordered. Reorder them. Reviewed-by: Chen-Yu Tsai <wens@csie.org> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180710203511.18454-10-jernej.skrabec@siol.net --- drivers/gpu/drm/sun4i/sun8i_mixer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c index ee8febb25903c..aa81b9838ae83 100644 --- a/drivers/gpu/drm/sun4i/sun8i_mixer.c +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c @@ -21,8 +21,8 @@ #include <linux/component.h> #include <linux/dma-mapping.h> -#include <linux/reset.h> #include <linux/of_device.h> +#include <linux/reset.h> #include "sun4i_drv.h" #include "sun8i_mixer.h" -- GitLab From 05db311a792d65633ab77950e520eaa5f031cf80 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec <jernej.skrabec@siol.net> Date: Tue, 10 Jul 2018 22:35:04 +0200 Subject: [PATCH 0986/1506] drm/sun4i: tcon-top: Add helpers for mux switching We want to be able to set TCON TOP muxes at runtime. Add helpers for that. Old, static configuration of muxes at probe time is preserved for now. It will be removed when R40 TCON starts using them. Reviewed-by: Chen-Yu Tsai <wens@csie.org> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180710203511.18454-12-jernej.skrabec@siol.net --- drivers/gpu/drm/sun4i/sun8i_tcon_top.c | 74 ++++++++++++++++++++++++++ drivers/gpu/drm/sun4i/sun8i_tcon_top.h | 4 ++ 2 files changed, 78 insertions(+) diff --git a/drivers/gpu/drm/sun4i/sun8i_tcon_top.c b/drivers/gpu/drm/sun4i/sun8i_tcon_top.c index ab2591a92ef0a..14add8801cda8 100644 --- a/drivers/gpu/drm/sun4i/sun8i_tcon_top.c +++ b/drivers/gpu/drm/sun4i/sun8i_tcon_top.c @@ -14,6 +14,79 @@ #include "sun8i_tcon_top.h" +static bool sun8i_tcon_top_node_is_tcon_top(struct device_node *node) +{ + return !!of_match_node(sun8i_tcon_top_of_table, node); +} + +int sun8i_tcon_top_set_hdmi_src(struct device *dev, int tcon) +{ + struct sun8i_tcon_top *tcon_top = dev_get_drvdata(dev); + unsigned long flags; + u32 val; + + if (!sun8i_tcon_top_node_is_tcon_top(dev->of_node)) { + dev_err(dev, "Device is not TCON TOP!\n"); + return -EINVAL; + } + + if (tcon < 2 || tcon > 3) { + dev_err(dev, "TCON index must be 2 or 3!\n"); + return -EINVAL; + } + + spin_lock_irqsave(&tcon_top->reg_lock, flags); + + val = readl(tcon_top->regs + TCON_TOP_GATE_SRC_REG); + val &= ~TCON_TOP_HDMI_SRC_MSK; + val |= FIELD_PREP(TCON_TOP_HDMI_SRC_MSK, tcon - 1); + writel(val, tcon_top->regs + TCON_TOP_GATE_SRC_REG); + + spin_unlock_irqrestore(&tcon_top->reg_lock, flags); + + return 0; +} +EXPORT_SYMBOL(sun8i_tcon_top_set_hdmi_src); + +int sun8i_tcon_top_de_config(struct device *dev, int mixer, int tcon) +{ + struct sun8i_tcon_top *tcon_top = dev_get_drvdata(dev); + unsigned long flags; + u32 reg; + + if (!sun8i_tcon_top_node_is_tcon_top(dev->of_node)) { + dev_err(dev, "Device is not TCON TOP!\n"); + return -EINVAL; + } + + if (mixer > 1) { + dev_err(dev, "Mixer index is too high!\n"); + return -EINVAL; + } + + if (tcon > 3) { + dev_err(dev, "TCON index is too high!\n"); + return -EINVAL; + } + + spin_lock_irqsave(&tcon_top->reg_lock, flags); + + reg = readl(tcon_top->regs + TCON_TOP_PORT_SEL_REG); + if (mixer == 0) { + reg &= ~TCON_TOP_PORT_DE0_MSK; + reg |= FIELD_PREP(TCON_TOP_PORT_DE0_MSK, tcon); + } else { + reg &= ~TCON_TOP_PORT_DE1_MSK; + reg |= FIELD_PREP(TCON_TOP_PORT_DE1_MSK, tcon); + } + writel(reg, tcon_top->regs + TCON_TOP_PORT_SEL_REG); + + spin_unlock_irqrestore(&tcon_top->reg_lock, flags); + + return 0; +} +EXPORT_SYMBOL(sun8i_tcon_top_de_config); + static int sun8i_tcon_top_get_connected_ep_id(struct device_node *node, int port_id) { @@ -109,6 +182,7 @@ static int sun8i_tcon_top_bind(struct device *dev, struct device *master, res = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = devm_ioremap_resource(dev, res); + tcon_top->regs = regs; if (IS_ERR(regs)) return PTR_ERR(regs); diff --git a/drivers/gpu/drm/sun4i/sun8i_tcon_top.h b/drivers/gpu/drm/sun4i/sun8i_tcon_top.h index 39838bbfeaee9..0390584a330e5 100644 --- a/drivers/gpu/drm/sun4i/sun8i_tcon_top.h +++ b/drivers/gpu/drm/sun4i/sun8i_tcon_top.h @@ -26,6 +26,7 @@ struct sun8i_tcon_top { struct clk *bus; struct clk_hw_onecell_data *clk_data; + void __iomem *regs; struct reset_control *rst; /* @@ -37,4 +38,7 @@ struct sun8i_tcon_top { extern const struct of_device_id sun8i_tcon_top_of_table[]; +int sun8i_tcon_top_set_hdmi_src(struct device *dev, int tcon); +int sun8i_tcon_top_de_config(struct device *dev, int mixer, int tcon); + #endif /* _SUN8I_TCON_TOP_H_ */ -- GitLab From 5e4965667a6edcf0d5b27fb982ecc07d3d0854f8 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec <jernej.skrabec@siol.net> Date: Tue, 10 Jul 2018 22:35:10 +0200 Subject: [PATCH 0987/1506] drm/sun4i: tcon-top: Remove mux configuration at probe time Now that R40 TCON migrated to runtime mux configuration, old code can be removed. Reviewed-by: Chen-Yu Tsai <wens@csie.org> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180710203511.18454-18-jernej.skrabec@siol.net --- drivers/gpu/drm/sun4i/sun8i_tcon_top.c | 76 +------------------------- 1 file changed, 1 insertion(+), 75 deletions(-) diff --git a/drivers/gpu/drm/sun4i/sun8i_tcon_top.c b/drivers/gpu/drm/sun4i/sun8i_tcon_top.c index 14add8801cda8..046f8dd66f90d 100644 --- a/drivers/gpu/drm/sun4i/sun8i_tcon_top.c +++ b/drivers/gpu/drm/sun4i/sun8i_tcon_top.c @@ -87,34 +87,6 @@ int sun8i_tcon_top_de_config(struct device *dev, int mixer, int tcon) } EXPORT_SYMBOL(sun8i_tcon_top_de_config); -static int sun8i_tcon_top_get_connected_ep_id(struct device_node *node, - int port_id) -{ - struct device_node *ep, *remote, *port; - struct of_endpoint endpoint; - - port = of_graph_get_port_by_id(node, port_id); - if (!port) - return -ENOENT; - - for_each_available_child_of_node(port, ep) { - remote = of_graph_get_remote_port_parent(ep); - if (!remote) - continue; - - if (of_device_is_available(remote)) { - of_graph_parse_endpoint(ep, &endpoint); - - of_node_put(remote); - - return endpoint.id; - } - - of_node_put(remote); - } - - return -ENOENT; -} static struct clk_hw *sun8i_tcon_top_register_gate(struct device *dev, const char *parent, @@ -149,11 +121,9 @@ static int sun8i_tcon_top_bind(struct device *dev, struct device *master, struct platform_device *pdev = to_platform_device(dev); struct clk_hw_onecell_data *clk_data; struct sun8i_tcon_top *tcon_top; - bool mixer0_unused = false; struct resource *res; void __iomem *regs; - int ret, i, id; - u32 val; + int ret, i; tcon_top = devm_kzalloc(dev, sizeof(*tcon_top), GFP_KERNEL); if (!tcon_top) @@ -198,50 +168,6 @@ static int sun8i_tcon_top_bind(struct device *dev, struct device *master, goto err_assert_reset; } - val = 0; - - /* check if HDMI mux output is connected */ - if (sun8i_tcon_top_get_connected_ep_id(dev->of_node, 5) >= 0) { - /* find HDMI input endpoint id, if it is connected at all*/ - id = sun8i_tcon_top_get_connected_ep_id(dev->of_node, 4); - if (id >= 0) - val = FIELD_PREP(TCON_TOP_HDMI_SRC_MSK, id + 1); - else - DRM_DEBUG_DRIVER("TCON TOP HDMI input is not connected\n"); - } else { - DRM_DEBUG_DRIVER("TCON TOP HDMI output is not connected\n"); - } - - writel(val, regs + TCON_TOP_GATE_SRC_REG); - - val = 0; - - /* process mixer0 mux output */ - id = sun8i_tcon_top_get_connected_ep_id(dev->of_node, 1); - if (id >= 0) { - val = FIELD_PREP(TCON_TOP_PORT_DE0_MSK, id); - } else { - DRM_DEBUG_DRIVER("TCON TOP mixer0 output is not connected\n"); - mixer0_unused = true; - } - - /* process mixer1 mux output */ - id = sun8i_tcon_top_get_connected_ep_id(dev->of_node, 3); - if (id >= 0) { - val |= FIELD_PREP(TCON_TOP_PORT_DE1_MSK, id); - - /* - * mixer0 mux has priority over mixer1 mux. We have to - * make sure mixer0 doesn't overtake TCON from mixer1. - */ - if (mixer0_unused && id == 0) - val |= FIELD_PREP(TCON_TOP_PORT_DE0_MSK, 1); - } else { - DRM_DEBUG_DRIVER("TCON TOP mixer1 output is not connected\n"); - } - - writel(val, regs + TCON_TOP_PORT_SEL_REG); - /* * TCON TOP has two muxes, which select parent clock for each TCON TV * channel clock. Parent could be either TCON TV or TVE clock. For now -- GitLab From ac1fe1322530ccca0771e3f680e8a6269c48c449 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec <jernej.skrabec@siol.net> Date: Tue, 10 Jul 2018 22:35:11 +0200 Subject: [PATCH 0988/1506] dt-bindings: display: sun4i-drm: Fix order of DW HDMI PHY compatibles They are currently sorted alphabetically. However, they should be sorted by release date of the family and then alphabetically. Fixes: 03c35dbf73e0 ("dt-bindings: display: sun4i-drm: Add description of A64 HDMI PHY") Reviewed-by: Chen-Yu Tsai <wens@csie.org> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180710203511.18454-19-jernej.skrabec@siol.net --- Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt index 7e2451396a284..f8773ecb75252 100644 --- a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt +++ b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt @@ -101,9 +101,9 @@ DWC HDMI PHY Required properties: - compatible: value must be one of: - * allwinner,sun50i-a64-hdmi-phy * allwinner,sun8i-a83t-hdmi-phy * allwinner,sun8i-h3-hdmi-phy + * allwinner,sun50i-a64-hdmi-phy - reg: base address and size of memory-mapped region - clocks: phandles to the clocks feeding the HDMI PHY * bus: the HDMI PHY interface clock -- GitLab From 0337976f40b0a9605c24797762b95b3414619d71 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann <arnd@arndb.de> Date: Wed, 11 Jul 2018 14:41:00 +0200 Subject: [PATCH 0989/1506] drm/admkfd use modern ktime accessors getrawmonotonic64() and get_monotonic_boottime64() are deprecated because of the nonstandard naming. The replacement functions ktime_get_raw_ns() and ktime_get_boot_ns() also simplify the callers. Reviewed-by: Felix Kuehling <Felix.Kuehling@amd.com>. Signed-off-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com> --- drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index f64c5551cdba0..7e717716b90e8 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -754,7 +754,6 @@ static int kfd_ioctl_get_clock_counters(struct file *filep, { struct kfd_ioctl_get_clock_counters_args *args = data; struct kfd_dev *dev; - struct timespec64 time; dev = kfd_device_by_id(args->gpu_id); if (dev) @@ -766,11 +765,8 @@ static int kfd_ioctl_get_clock_counters(struct file *filep, args->gpu_clock_counter = 0; /* No access to rdtsc. Using raw monotonic time */ - getrawmonotonic64(&time); - args->cpu_clock_counter = (uint64_t)timespec64_to_ns(&time); - - get_monotonic_boottime64(&time); - args->system_clock_counter = (uint64_t)timespec64_to_ns(&time); + args->cpu_clock_counter = ktime_get_raw_ns(); + args->system_clock_counter = ktime_get_boot_ns(); /* Since the counter is in nano-seconds we use 1GHz frequency */ args->system_clock_freq = 1000000000; -- GitLab From 19bb33c756edee5e3f0fb126895f6ec23e60dd08 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Wed, 11 Jul 2018 08:36:02 +0100 Subject: [PATCH 0990/1506] drm/i915: Introduce i915_address_space.mutex Add a mutex into struct i915_address_space to be used while operating on the vma and their lists for a particular vm. As this may be called from the shrinker, we taint the mutex with fs_reclaim so that from the start lockdep warns us if we are caught holding the mutex across an allocation. (With such small steps we will eventually rid ourselves of struct_mutex recursion!) Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180711073608.20286-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_gem_gtt.c | 10 ++++++++++ drivers/gpu/drm/i915/i915_gem_gtt.h | 2 ++ drivers/gpu/drm/i915/i915_gem_shrinker.c | 12 ++++++++++++ 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index a90a37ce2ef9c..48b350116cbae 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3307,7 +3307,7 @@ unsigned long i915_gem_shrink(struct drm_i915_private *i915, unsigned long i915_gem_shrink_all(struct drm_i915_private *i915); void i915_gem_shrinker_register(struct drm_i915_private *i915); void i915_gem_shrinker_unregister(struct drm_i915_private *i915); - +void i915_gem_shrinker_taints_mutex(struct mutex *mutex); /* i915_gem_tiling.c */ static inline bool i915_gem_object_needs_bit17_swizzle(struct drm_i915_gem_object *obj) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 210baf3c8d112..502353b9bf846 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -531,6 +531,14 @@ static void vm_free_page(struct i915_address_space *vm, struct page *page) static void i915_address_space_init(struct i915_address_space *vm, struct drm_i915_private *dev_priv) { + /* + * The vm->mutex must be reclaim safe (for use in the shrinker). + * Do a dummy acquire now under fs_reclaim so that any allocation + * attempt holding the lock is immediately reported by lockdep. + */ + mutex_init(&vm->mutex); + i915_gem_shrinker_taints_mutex(&vm->mutex); + GEM_BUG_ON(!vm->total); drm_mm_init(&vm->mm, 0, vm->total); vm->mm.head_node.color = I915_COLOR_UNEVICTABLE; @@ -551,6 +559,8 @@ static void i915_address_space_fini(struct i915_address_space *vm) spin_unlock(&vm->free_pages.lock); drm_mm_takedown(&vm->mm); + + mutex_destroy(&vm->mutex); } static int __setup_page_dma(struct i915_address_space *vm, diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index feda45dfd4811..14e62651010b0 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -293,6 +293,8 @@ struct i915_address_space { bool closed; + struct mutex mutex; /* protects vma and our lists */ + struct i915_page_dma scratch_page; struct i915_page_table *scratch_pt; struct i915_page_directory *scratch_pd; diff --git a/drivers/gpu/drm/i915/i915_gem_shrinker.c b/drivers/gpu/drm/i915/i915_gem_shrinker.c index c61f5b80fee3a..ea90d3a0d5114 100644 --- a/drivers/gpu/drm/i915/i915_gem_shrinker.c +++ b/drivers/gpu/drm/i915/i915_gem_shrinker.c @@ -23,6 +23,7 @@ */ #include <linux/oom.h> +#include <linux/sched/mm.h> #include <linux/shmem_fs.h> #include <linux/slab.h> #include <linux/swap.h> @@ -531,3 +532,14 @@ void i915_gem_shrinker_unregister(struct drm_i915_private *i915) WARN_ON(unregister_oom_notifier(&i915->mm.oom_notifier)); unregister_shrinker(&i915->mm.shrinker); } + +void i915_gem_shrinker_taints_mutex(struct mutex *mutex) +{ + if (!IS_ENABLED(CONFIG_LOCKDEP)) + return; + + fs_reclaim_acquire(GFP_KERNEL); + mutex_lock(mutex); + mutex_unlock(mutex); + fs_reclaim_release(GFP_KERNEL); +} -- GitLab From cb4dc8daf4cb72d7833148a6087b425b5c20e903 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Wed, 11 Jul 2018 13:29:52 +0100 Subject: [PATCH 0991/1506] drm/i915/selftests: Add a safety net to live_workarounds Since live_workarounds poke around the w/a registers and checks to see if they survive across a reset, we are prone to fouling the machine and leaving it in a non-recoverable state. Wrap the probe inside a timeout to abort the test if the reset fails. v2: Include GEM_TRACE on declaring wedged. v3: Add a few includes to make the header look standalone. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=107188 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180711122952.18448-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/selftests/igt_wedge_me.h | 58 +++++++++++++++++++ .../drm/i915/selftests/intel_workarounds.c | 8 ++- 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/i915/selftests/igt_wedge_me.h diff --git a/drivers/gpu/drm/i915/selftests/igt_wedge_me.h b/drivers/gpu/drm/i915/selftests/igt_wedge_me.h new file mode 100644 index 0000000000000..08e5ff11bbd9d --- /dev/null +++ b/drivers/gpu/drm/i915/selftests/igt_wedge_me.h @@ -0,0 +1,58 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright © 2018 Intel Corporation + */ + +#ifndef IGT_WEDGE_ME_H +#define IGT_WEDGE_ME_H + +#include <linux/workqueue.h> + +#include "../i915_gem.h" + +struct drm_i915_private; + +struct igt_wedge_me { + struct delayed_work work; + struct drm_i915_private *i915; + const char *name; +}; + +static void __igt_wedge_me(struct work_struct *work) +{ + struct igt_wedge_me *w = container_of(work, typeof(*w), work.work); + + pr_err("%s timed out, cancelling test.\n", w->name); + + GEM_TRACE("%s timed out.\n", w->name); + GEM_TRACE_DUMP(); + + i915_gem_set_wedged(w->i915); +} + +static void __igt_init_wedge(struct igt_wedge_me *w, + struct drm_i915_private *i915, + long timeout, + const char *name) +{ + w->i915 = i915; + w->name = name; + + INIT_DELAYED_WORK_ONSTACK(&w->work, __igt_wedge_me); + schedule_delayed_work(&w->work, timeout); +} + +static void __igt_fini_wedge(struct igt_wedge_me *w) +{ + cancel_delayed_work_sync(&w->work); + destroy_delayed_work_on_stack(&w->work); + w->i915 = NULL; +} + +#define igt_wedge_on_timeout(W, DEV, TIMEOUT) \ + for (__igt_init_wedge((W), (DEV), (TIMEOUT), __func__); \ + (W)->i915; \ + __igt_fini_wedge((W))) + +#endif /* IGT_WEDGE_ME_H */ diff --git a/drivers/gpu/drm/i915/selftests/intel_workarounds.c b/drivers/gpu/drm/i915/selftests/intel_workarounds.c index fafdec3fe83eb..0d39b3bf0c0d0 100644 --- a/drivers/gpu/drm/i915/selftests/intel_workarounds.c +++ b/drivers/gpu/drm/i915/selftests/intel_workarounds.c @@ -6,6 +6,7 @@ #include "../i915_selftest.h" +#include "igt_wedge_me.h" #include "mock_context.h" static struct drm_i915_gem_object * @@ -111,6 +112,7 @@ static int check_whitelist(const struct whitelist *w, struct intel_engine_cs *engine) { struct drm_i915_gem_object *results; + struct igt_wedge_me wedge; u32 *vaddr; int err; int i; @@ -119,7 +121,11 @@ static int check_whitelist(const struct whitelist *w, if (IS_ERR(results)) return PTR_ERR(results); - err = i915_gem_object_set_to_cpu_domain(results, false); + err = 0; + igt_wedge_on_timeout(&wedge, ctx->i915, HZ / 5) /* a safety net! */ + err = i915_gem_object_set_to_cpu_domain(results, false); + if (i915_terminally_wedged(&ctx->i915->gpu_error)) + err = -EIO; if (err) goto out_put; -- GitLab From 655250a8d1aa3b18949a72869858d07ceac12799 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 29 Jun 2018 08:53:20 +0100 Subject: [PATCH 0992/1506] drm/i915/execlists: Switch to rb_root_cached The kernel recently gained an augmented rbtree with the purpose of cacheing the leftmost element of the rbtree, a frequent optimisation to avoid calls to rb_first() which is also employed by the execlists->queue. Switch from our open-coded cache to the library. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180629075348.27358-9-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_engine_cs.c | 7 ++--- drivers/gpu/drm/i915/intel_guc_submission.c | 12 +++----- drivers/gpu/drm/i915/intel_lrc.c | 32 +++++++-------------- drivers/gpu/drm/i915/intel_ringbuffer.h | 7 +---- 4 files changed, 19 insertions(+), 39 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index 0ac497275a513..220050107c486 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -467,8 +467,7 @@ static void intel_engine_init_execlist(struct intel_engine_cs *engine) GEM_BUG_ON(execlists_num_ports(execlists) > EXECLIST_MAX_PORTS); execlists->queue_priority = INT_MIN; - execlists->queue = RB_ROOT; - execlists->first = NULL; + execlists->queue = RB_ROOT_CACHED; } /** @@ -1004,7 +1003,7 @@ bool intel_engine_is_idle(struct intel_engine_cs *engine) } /* ELSP is empty, but there are ready requests? E.g. after reset */ - if (READ_ONCE(engine->execlists.first)) + if (!RB_EMPTY_ROOT(&engine->execlists.queue.rb_root)) return false; /* Ring stopped? */ @@ -1540,7 +1539,7 @@ void intel_engine_dump(struct intel_engine_cs *engine, last = NULL; count = 0; drm_printf(m, "\t\tQueue priority: %d\n", execlists->queue_priority); - for (rb = execlists->first; rb; rb = rb_next(rb)) { + for (rb = rb_first_cached(&execlists->queue); rb; rb = rb_next(rb)) { struct i915_priolist *p = rb_entry(rb, typeof(*p), node); diff --git a/drivers/gpu/drm/i915/intel_guc_submission.c b/drivers/gpu/drm/i915/intel_guc_submission.c index f3945258fe1b5..3952656f4c9a3 100644 --- a/drivers/gpu/drm/i915/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/intel_guc_submission.c @@ -695,9 +695,6 @@ static bool __guc_dequeue(struct intel_engine_cs *engine) lockdep_assert_held(&engine->timeline.lock); - rb = execlists->first; - GEM_BUG_ON(rb_first(&execlists->queue) != rb); - if (port_isset(port)) { if (intel_engine_has_preemption(engine)) { struct guc_preempt_work *preempt_work = @@ -719,7 +716,7 @@ static bool __guc_dequeue(struct intel_engine_cs *engine) } GEM_BUG_ON(port_isset(port)); - while (rb) { + while ((rb = rb_first_cached(&execlists->queue))) { struct i915_priolist *p = to_priolist(rb); struct i915_request *rq, *rn; @@ -744,15 +741,13 @@ static bool __guc_dequeue(struct intel_engine_cs *engine) submit = true; } - rb = rb_next(rb); - rb_erase(&p->node, &execlists->queue); + rb_erase_cached(&p->node, &execlists->queue); INIT_LIST_HEAD(&p->requests); if (p->priority != I915_PRIORITY_NORMAL) kmem_cache_free(engine->i915->priorities, p); } done: execlists->queue_priority = rb ? to_priolist(rb)->priority : INT_MIN; - execlists->first = rb; if (submit) port_assign(port, last); if (last) @@ -761,7 +756,8 @@ static bool __guc_dequeue(struct intel_engine_cs *engine) /* We must always keep the beast fed if we have work piled up */ GEM_BUG_ON(port_isset(execlists->port) && !execlists_is_active(execlists, EXECLISTS_ACTIVE_USER)); - GEM_BUG_ON(execlists->first && !port_isset(execlists->port)); + GEM_BUG_ON(rb_first_cached(&execlists->queue) && + !port_isset(execlists->port)); return submit; } diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index d937a21da2d80..ad436d200758c 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -273,7 +273,7 @@ lookup_priolist(struct intel_engine_cs *engine, int prio) find_priolist: /* most positive priority is scheduled first, equal priorities fifo */ rb = NULL; - parent = &execlists->queue.rb_node; + parent = &execlists->queue.rb_root.rb_node; while (*parent) { rb = *parent; p = to_priolist(rb); @@ -311,10 +311,7 @@ lookup_priolist(struct intel_engine_cs *engine, int prio) p->priority = prio; INIT_LIST_HEAD(&p->requests); rb_link_node(&p->node, rb, parent); - rb_insert_color(&p->node, &execlists->queue); - - if (first) - execlists->first = &p->node; + rb_insert_color_cached(&p->node, &execlists->queue, first); return p; } @@ -602,9 +599,6 @@ static void execlists_dequeue(struct intel_engine_cs *engine) * and context switches) submission. */ - rb = execlists->first; - GEM_BUG_ON(rb_first(&execlists->queue) != rb); - if (last) { /* * Don't resubmit or switch until all outstanding @@ -666,7 +660,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine) last->tail = last->wa_tail; } - while (rb) { + while ((rb = rb_first_cached(&execlists->queue))) { struct i915_priolist *p = to_priolist(rb); struct i915_request *rq, *rn; @@ -725,8 +719,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine) submit = true; } - rb = rb_next(rb); - rb_erase(&p->node, &execlists->queue); + rb_erase_cached(&p->node, &execlists->queue); INIT_LIST_HEAD(&p->requests); if (p->priority != I915_PRIORITY_NORMAL) kmem_cache_free(engine->i915->priorities, p); @@ -752,14 +745,14 @@ static void execlists_dequeue(struct intel_engine_cs *engine) execlists->queue_priority = port != execlists->port ? rq_prio(last) : INT_MIN; - execlists->first = rb; if (submit) { port_assign(port, last); execlists_submit_ports(engine); } /* We must always keep the beast fed if we have work piled up */ - GEM_BUG_ON(execlists->first && !port_isset(execlists->port)); + GEM_BUG_ON(rb_first_cached(&execlists->queue) && + !port_isset(execlists->port)); /* Re-evaluate the executing context setup after each preemptive kick */ if (last) @@ -922,8 +915,7 @@ static void execlists_cancel_requests(struct intel_engine_cs *engine) } /* Flush the queued requests to the timeline list (for retiring). */ - rb = execlists->first; - while (rb) { + while ((rb = rb_first_cached(&execlists->queue))) { struct i915_priolist *p = to_priolist(rb); list_for_each_entry_safe(rq, rn, &p->requests, sched.link) { @@ -933,8 +925,7 @@ static void execlists_cancel_requests(struct intel_engine_cs *engine) __i915_request_submit(rq); } - rb = rb_next(rb); - rb_erase(&p->node, &execlists->queue); + rb_erase_cached(&p->node, &execlists->queue); INIT_LIST_HEAD(&p->requests); if (p->priority != I915_PRIORITY_NORMAL) kmem_cache_free(engine->i915->priorities, p); @@ -943,8 +934,7 @@ static void execlists_cancel_requests(struct intel_engine_cs *engine) /* Remaining _unready_ requests will be nop'ed when submitted */ execlists->queue_priority = INT_MIN; - execlists->queue = RB_ROOT; - execlists->first = NULL; + execlists->queue = RB_ROOT_CACHED; GEM_BUG_ON(port_isset(execlists->port)); spin_unlock_irqrestore(&engine->timeline.lock, flags); @@ -1192,7 +1182,7 @@ static void execlists_submit_request(struct i915_request *request) queue_request(engine, &request->sched, rq_prio(request)); - GEM_BUG_ON(!engine->execlists.first); + GEM_BUG_ON(RB_EMPTY_ROOT(&engine->execlists.queue.rb_root)); GEM_BUG_ON(list_empty(&request->sched.link)); submit_queue(engine, rq_prio(request)); @@ -2044,7 +2034,7 @@ static void execlists_reset_finish(struct intel_engine_cs *engine) struct intel_engine_execlists * const execlists = &engine->execlists; /* After a GPU reset, we may have requests to replay */ - if (execlists->first) + if (!RB_EMPTY_ROOT(&execlists->queue.rb_root)) tasklet_schedule(&execlists->tasklet); /* diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index ce6cc2a6cf7af..d1eee08e5f6bb 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -292,12 +292,7 @@ struct intel_engine_execlists { /** * @queue: queue of requests, in priority lists */ - struct rb_root queue; - - /** - * @first: leftmost level in priority @queue - */ - struct rb_node *first; + struct rb_root_cached queue; /** * @csb_read: control register for Context Switch buffer -- GitLab From 03e3ec9ad1ee484f872bad6d673d46c9742e71ef Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy <vz@mleia.com> Date: Fri, 6 Jul 2018 21:51:01 +0300 Subject: [PATCH 0993/1506] drm/panel: simple: Add Sharp LQ035Q7DB03 panel support The change adds support for Sharp LQ035Q7DB03 3.5" QVGA TFT panel. Note that this aged panel is already found in the kernel sources, for instance in board mach files mach-mx21ads.c, mach-mx27ads.c, mach-pcm043.c, lpd270.c and imx27-phytec-phycore-rdk.dts. Signed-off-by: Vladimir Zapolskiy <vz@mleia.com> Reviewed-by: Rob Herring <robh@kernel.org> Signed-off-by: Thierry Reding <treding@nvidia.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180706185101.31186-1-vz@mleia.com --- .../display/panel/sharp,lq035q7db03.txt | 12 +++++++++ drivers/gpu/drm/panel/panel-simple.c | 27 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/panel/sharp,lq035q7db03.txt diff --git a/Documentation/devicetree/bindings/display/panel/sharp,lq035q7db03.txt b/Documentation/devicetree/bindings/display/panel/sharp,lq035q7db03.txt new file mode 100644 index 0000000000000..0753f6967279b --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/sharp,lq035q7db03.txt @@ -0,0 +1,12 @@ +Sharp LQ035Q7DB03 3.5" QVGA TFT LCD panel + +Required properties: +- compatible: should be "sharp,lq035q7db03" +- power-supply: phandle of the regulator that provides the supply voltage + +Optional properties: +- enable-gpios: GPIO pin to enable or disable the panel +- backlight: phandle of the backlight device attached to the panel + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 3b226ad8acadd..86fec03dd2604 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -1991,6 +1991,30 @@ static const struct panel_desc samsung_ltn140at29_301 = { }, }; +static const struct drm_display_mode sharp_lq035q7db03_mode = { + .clock = 5500, + .hdisplay = 240, + .hsync_start = 240 + 16, + .hsync_end = 240 + 16 + 7, + .htotal = 240 + 16 + 7 + 5, + .vdisplay = 320, + .vsync_start = 320 + 9, + .vsync_end = 320 + 9 + 1, + .vtotal = 320 + 9 + 1 + 7, + .vrefresh = 60, +}; + +static const struct panel_desc sharp_lq035q7db03 = { + .modes = &sharp_lq035q7db03_mode, + .num_modes = 1, + .bpc = 6, + .size = { + .width = 54, + .height = 72, + }, + .bus_format = MEDIA_BUS_FMT_RGB666_1X18, +}; + static const struct display_timing sharp_lq101k1ly04_timing = { .pixelclock = { 60000000, 65000000, 80000000 }, .hactive = { 1280, 1280, 1280 }, @@ -2492,6 +2516,9 @@ static const struct of_device_id platform_of_match[] = { }, { .compatible = "samsung,ltn140at29-301", .data = &samsung_ltn140at29_301, + }, { + .compatible = "sharp,lq035q7db03", + .data = &sharp_lq035q7db03, }, { .compatible = "sharp,lq101k1ly04", .data = &sharp_lq101k1ly04, -- GitLab From 5685ca0ca292b656086085dc3847f10e7ff85225 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org> Date: Tue, 10 Jul 2018 17:05:18 +0200 Subject: [PATCH 0994/1506] drm/tinydrm: Fix doc build warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit include/drm/tinydrm/tinydrm.h:34: warning: Function parameter or member 'fb_dirty' not described in 'tinydrm_device' drivers/gpu/drm/tinydrm/mipi-dbi.c:272: warning: Function parameter or member 'crtc_state' not described in 'mipi_dbi_enable_flush' drivers/gpu/drm/tinydrm/mipi-dbi.c:272: warning: Function parameter or member 'plane_state' not described in 'mipi_dbi_enable_flush' Move struct member docs inline so it's not missed next time. Cc: David Lechner <david@lechnology.com> Signed-off-by: Noralf Trønnes <noralf@tronnes.org> Reviewed-by: David Lechner <david@lechnology.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180710150518.10528-1-noralf@tronnes.org --- drivers/gpu/drm/tinydrm/mipi-dbi.c | 2 ++ include/drm/tinydrm/tinydrm.h | 23 +++++++++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/tinydrm/mipi-dbi.c b/drivers/gpu/drm/tinydrm/mipi-dbi.c index 4d1fb31a781ff..cb3441e51d5f0 100644 --- a/drivers/gpu/drm/tinydrm/mipi-dbi.c +++ b/drivers/gpu/drm/tinydrm/mipi-dbi.c @@ -260,6 +260,8 @@ static const struct drm_framebuffer_funcs mipi_dbi_fb_funcs = { /** * mipi_dbi_enable_flush - MIPI DBI enable helper * @mipi: MIPI DBI structure + * @crtc_state: CRTC state + * @plane_state: Plane state * * This function sets &mipi_dbi->enabled, flushes the whole framebuffer and * enables the backlight. Drivers can use this in their diff --git a/include/drm/tinydrm/tinydrm.h b/include/drm/tinydrm/tinydrm.h index 56e4a916b5e85..fe9827d0ca8a5 100644 --- a/include/drm/tinydrm/tinydrm.h +++ b/include/drm/tinydrm/tinydrm.h @@ -16,16 +16,31 @@ /** * struct tinydrm_device - tinydrm device - * @drm: DRM device - * @pipe: Display pipe structure - * @dirty_lock: Serializes framebuffer flushing - * @fb_funcs: Framebuffer functions used when creating framebuffers */ struct tinydrm_device { + /** + * @drm: DRM device + */ struct drm_device *drm; + + /** + * @pipe: Display pipe structure + */ struct drm_simple_display_pipe pipe; + + /** + * @dirty_lock: Serializes framebuffer flushing + */ struct mutex dirty_lock; + + /** + * @fb_funcs: Framebuffer functions used when creating framebuffers + */ const struct drm_framebuffer_funcs *fb_funcs; + + /** + * @fb_dirty: Framebuffer dirty callback + */ int (*fb_dirty)(struct drm_framebuffer *framebuffer, struct drm_file *file_priv, unsigned flags, unsigned color, struct drm_clip_rect *clips, -- GitLab From ae61f61fa802c829fa8d505587f9b337e63ea586 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org> Date: Wed, 11 Jul 2018 17:56:32 +0200 Subject: [PATCH 0995/1506] drm/client: Fix: drm_client_new: Don't require DRM to be registered MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 894a677f4b3e ("drm/cma-helper: Use the generic fbdev emulation") broke almost all drivers that use the CMA helper. The reason is that drm_client_new() requires that the DRM device has been registered, but the drivers register fbdev before registering DRM. Remove the requirement that DRM should be registered when creating a new client. Fixes: c76f0f7cb546 ("drm: Begin an API for in-kernel clients") Cc: Maxime Ripard <maxime.ripard@bootlin.com> Cc: Icenowy Zheng <icenowy@aosc.io> Cc: Chen-Yu Tsai <wens@csie.org> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Noralf Trønnes <noralf@tronnes.org> Tested-by: Icenowy Zheng <icenowy@aosc.io> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180711155632.37437-1-noralf@tronnes.org --- drivers/gpu/drm/drm_client.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c index 4039a4d103a83..9b142f58d489f 100644 --- a/drivers/gpu/drm/drm_client.c +++ b/drivers/gpu/drm/drm_client.c @@ -78,7 +78,6 @@ EXPORT_SYMBOL(drm_client_close); int drm_client_new(struct drm_device *dev, struct drm_client_dev *client, const char *name, const struct drm_client_funcs *funcs) { - bool registered; int ret; if (!drm_core_check_feature(dev, DRIVER_MODESET) || @@ -97,21 +96,13 @@ int drm_client_new(struct drm_device *dev, struct drm_client_dev *client, goto err_put_module; mutex_lock(&dev->clientlist_mutex); - registered = dev->registered; - if (registered) - list_add(&client->list, &dev->clientlist); + list_add(&client->list, &dev->clientlist); mutex_unlock(&dev->clientlist_mutex); - if (!registered) { - ret = -ENODEV; - goto err_close; - } drm_dev_get(dev); return 0; -err_close: - drm_client_close(client); err_put_module: if (funcs) module_put(funcs->owner); -- GitLab From efeaed4d98eb4dc9ce01e1dca6d3778d180b272c Mon Sep 17 00:00:00 2001 From: Felix Kuehling <Felix.Kuehling@amd.com> Date: Wed, 11 Jul 2018 22:32:44 -0400 Subject: [PATCH 0996/1506] drm/amdkfd: Reliably prevent reclaim-FS while holding DQM lock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is needed to prevent deadlocks when MMU notifiers run in reclaim-FS context and take the DQM lock for userptr evictions. Previously this was done by making all memory allocations under DQM locks GFP_NOIO. This is error prone. Using memalloc_nofs_save/restore will reliably affect all memory allocations anywhere in the kernel while the DQM lock is held. Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com> Acked-by: Christian König <christian.koenig@amd.com> Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com> --- .../drm/amd/amdkfd/kfd_device_queue_manager.c | 85 ++++++++++--------- .../drm/amd/amdkfd/kfd_device_queue_manager.h | 20 ++++- 2 files changed, 62 insertions(+), 43 deletions(-) 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 668ad07ebe1fd..f2f81d26db0c3 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -240,7 +240,7 @@ static int create_queue_nocpsch(struct device_queue_manager *dqm, print_queue(q); - mutex_lock(&dqm->lock); + dqm_lock(dqm); if (dqm->total_queue_count >= max_num_of_queues_per_device) { pr_warn("Can't create new usermode queue because %d queues were already created\n", @@ -297,7 +297,7 @@ static int create_queue_nocpsch(struct device_queue_manager *dqm, dqm->total_queue_count); out_unlock: - mutex_unlock(&dqm->lock); + dqm_unlock(dqm); return retval; } @@ -457,9 +457,9 @@ static int destroy_queue_nocpsch(struct device_queue_manager *dqm, { int retval; - mutex_lock(&dqm->lock); + dqm_lock(dqm); retval = destroy_queue_nocpsch_locked(dqm, qpd, q); - mutex_unlock(&dqm->lock); + dqm_unlock(dqm); return retval; } @@ -471,7 +471,7 @@ static int update_queue(struct device_queue_manager *dqm, struct queue *q) struct kfd_process_device *pdd; bool prev_active = false; - mutex_lock(&dqm->lock); + dqm_lock(dqm); pdd = kfd_get_process_device_data(q->device, q->process); if (!pdd) { retval = -ENODEV; @@ -537,7 +537,7 @@ static int update_queue(struct device_queue_manager *dqm, struct queue *q) &q->properties, q->process->mm); out_unlock: - mutex_unlock(&dqm->lock); + dqm_unlock(dqm); return retval; } @@ -570,7 +570,7 @@ static int evict_process_queues_nocpsch(struct device_queue_manager *dqm, struct kfd_process_device *pdd; int retval = 0; - mutex_lock(&dqm->lock); + dqm_lock(dqm); if (qpd->evicted++ > 0) /* already evicted, do nothing */ goto out; @@ -600,7 +600,7 @@ static int evict_process_queues_nocpsch(struct device_queue_manager *dqm, } out: - mutex_unlock(&dqm->lock); + dqm_unlock(dqm); return retval; } @@ -611,7 +611,7 @@ static int evict_process_queues_cpsch(struct device_queue_manager *dqm, struct kfd_process_device *pdd; int retval = 0; - mutex_lock(&dqm->lock); + dqm_lock(dqm); if (qpd->evicted++ > 0) /* already evicted, do nothing */ goto out; @@ -633,7 +633,7 @@ static int evict_process_queues_cpsch(struct device_queue_manager *dqm, KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES, 0); out: - mutex_unlock(&dqm->lock); + dqm_unlock(dqm); return retval; } @@ -650,7 +650,7 @@ static int restore_process_queues_nocpsch(struct device_queue_manager *dqm, /* Retrieve PD base */ pd_base = dqm->dev->kfd2kgd->get_process_page_dir(pdd->vm); - mutex_lock(&dqm->lock); + dqm_lock(dqm); if (WARN_ON_ONCE(!qpd->evicted)) /* already restored, do nothing */ goto out; if (qpd->evicted > 1) { /* ref count still > 0, decrement & quit */ @@ -695,7 +695,7 @@ static int restore_process_queues_nocpsch(struct device_queue_manager *dqm, } qpd->evicted = 0; out: - mutex_unlock(&dqm->lock); + dqm_unlock(dqm); return retval; } @@ -711,7 +711,7 @@ static int restore_process_queues_cpsch(struct device_queue_manager *dqm, /* Retrieve PD base */ pd_base = dqm->dev->kfd2kgd->get_process_page_dir(pdd->vm); - mutex_lock(&dqm->lock); + dqm_lock(dqm); if (WARN_ON_ONCE(!qpd->evicted)) /* already restored, do nothing */ goto out; if (qpd->evicted > 1) { /* ref count still > 0, decrement & quit */ @@ -739,7 +739,7 @@ static int restore_process_queues_cpsch(struct device_queue_manager *dqm, if (!retval) qpd->evicted = 0; out: - mutex_unlock(&dqm->lock); + dqm_unlock(dqm); return retval; } @@ -761,7 +761,7 @@ static int register_process(struct device_queue_manager *dqm, /* Retrieve PD base */ pd_base = dqm->dev->kfd2kgd->get_process_page_dir(pdd->vm); - mutex_lock(&dqm->lock); + dqm_lock(dqm); list_add(&n->list, &dqm->queues); /* Update PD Base in QPD */ @@ -771,7 +771,7 @@ static int register_process(struct device_queue_manager *dqm, dqm->processes_count++; - mutex_unlock(&dqm->lock); + dqm_unlock(dqm); return retval; } @@ -786,7 +786,7 @@ static int unregister_process(struct device_queue_manager *dqm, list_empty(&qpd->queues_list) ? "empty" : "not empty"); retval = 0; - mutex_lock(&dqm->lock); + dqm_lock(dqm); list_for_each_entry_safe(cur, next, &dqm->queues, list) { if (qpd == cur->qpd) { @@ -799,7 +799,7 @@ static int unregister_process(struct device_queue_manager *dqm, /* qpd not found in dqm list */ retval = 1; out: - mutex_unlock(&dqm->lock); + dqm_unlock(dqm); return retval; } @@ -838,7 +838,7 @@ static int initialize_nocpsch(struct device_queue_manager *dqm) if (!dqm->allocated_queues) return -ENOMEM; - mutex_init(&dqm->lock); + mutex_init(&dqm->lock_hidden); INIT_LIST_HEAD(&dqm->queues); dqm->queue_count = dqm->next_pipe_to_allocate = 0; dqm->sdma_queue_count = 0; @@ -867,7 +867,7 @@ static void uninitialize(struct device_queue_manager *dqm) kfree(dqm->allocated_queues); for (i = 0 ; i < KFD_MQD_TYPE_MAX ; i++) kfree(dqm->mqds[i]); - mutex_destroy(&dqm->lock); + mutex_destroy(&dqm->lock_hidden); kfd_gtt_sa_free(dqm->dev, dqm->pipeline_mem); } @@ -1003,7 +1003,7 @@ static int initialize_cpsch(struct device_queue_manager *dqm) { pr_debug("num of pipes: %d\n", get_pipes_per_mec(dqm)); - mutex_init(&dqm->lock); + mutex_init(&dqm->lock_hidden); INIT_LIST_HEAD(&dqm->queues); dqm->queue_count = dqm->processes_count = 0; dqm->sdma_queue_count = 0; @@ -1041,9 +1041,9 @@ static int start_cpsch(struct device_queue_manager *dqm) init_interrupts(dqm); - mutex_lock(&dqm->lock); + dqm_lock(dqm); execute_queues_cpsch(dqm, KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES, 0); - mutex_unlock(&dqm->lock); + dqm_unlock(dqm); return 0; fail_allocate_vidmem: @@ -1055,9 +1055,9 @@ static int start_cpsch(struct device_queue_manager *dqm) static int stop_cpsch(struct device_queue_manager *dqm) { - mutex_lock(&dqm->lock); + dqm_lock(dqm); unmap_queues_cpsch(dqm, KFD_UNMAP_QUEUES_FILTER_ALL_QUEUES, 0); - mutex_unlock(&dqm->lock); + dqm_unlock(dqm); kfd_gtt_sa_free(dqm->dev, dqm->fence_mem); pm_uninit(&dqm->packets); @@ -1069,11 +1069,11 @@ static int create_kernel_queue_cpsch(struct device_queue_manager *dqm, struct kernel_queue *kq, struct qcm_process_device *qpd) { - mutex_lock(&dqm->lock); + dqm_lock(dqm); if (dqm->total_queue_count >= max_num_of_queues_per_device) { pr_warn("Can't create new kernel queue because %d queues were already created\n", dqm->total_queue_count); - mutex_unlock(&dqm->lock); + dqm_unlock(dqm); return -EPERM; } @@ -1089,7 +1089,7 @@ static int create_kernel_queue_cpsch(struct device_queue_manager *dqm, dqm->queue_count++; qpd->is_debug = true; execute_queues_cpsch(dqm, KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES, 0); - mutex_unlock(&dqm->lock); + dqm_unlock(dqm); return 0; } @@ -1098,7 +1098,7 @@ static void destroy_kernel_queue_cpsch(struct device_queue_manager *dqm, struct kernel_queue *kq, struct qcm_process_device *qpd) { - mutex_lock(&dqm->lock); + dqm_lock(dqm); list_del(&kq->list); dqm->queue_count--; qpd->is_debug = false; @@ -1110,7 +1110,7 @@ static void destroy_kernel_queue_cpsch(struct device_queue_manager *dqm, dqm->total_queue_count--; pr_debug("Total of %d queues are accountable so far\n", dqm->total_queue_count); - mutex_unlock(&dqm->lock); + dqm_unlock(dqm); } static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q, @@ -1121,7 +1121,7 @@ static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q, retval = 0; - mutex_lock(&dqm->lock); + dqm_lock(dqm); if (dqm->total_queue_count >= max_num_of_queues_per_device) { pr_warn("Can't create new usermode queue because %d queues were already created\n", @@ -1188,7 +1188,7 @@ static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q, pr_debug("Total of %d queues are accountable so far\n", dqm->total_queue_count); - mutex_unlock(&dqm->lock); + dqm_unlock(dqm); return retval; out_deallocate_doorbell: @@ -1197,7 +1197,8 @@ static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q, if (q->properties.type == KFD_QUEUE_TYPE_SDMA) deallocate_sdma_queue(dqm, q->sdma_id); out_unlock: - mutex_unlock(&dqm->lock); + dqm_unlock(dqm); + return retval; } @@ -1314,7 +1315,7 @@ static int destroy_queue_cpsch(struct device_queue_manager *dqm, retval = 0; /* remove queue from list to prevent rescheduling after preemption */ - mutex_lock(&dqm->lock); + dqm_lock(dqm); if (qpd->is_debug) { /* @@ -1360,14 +1361,14 @@ static int destroy_queue_cpsch(struct device_queue_manager *dqm, pr_debug("Total of %d queues are accountable so far\n", dqm->total_queue_count); - mutex_unlock(&dqm->lock); + dqm_unlock(dqm); return retval; failed: failed_try_destroy_debugged_queue: - mutex_unlock(&dqm->lock); + dqm_unlock(dqm); return retval; } @@ -1391,7 +1392,7 @@ static bool set_cache_memory_policy(struct device_queue_manager *dqm, if (!dqm->asic_ops.set_cache_memory_policy) return retval; - mutex_lock(&dqm->lock); + dqm_lock(dqm); if (alternate_aperture_size == 0) { /* base > limit disables APE1 */ @@ -1437,7 +1438,7 @@ static bool set_cache_memory_policy(struct device_queue_manager *dqm, qpd->sh_mem_ape1_limit); out: - mutex_unlock(&dqm->lock); + dqm_unlock(dqm); return retval; } @@ -1468,7 +1469,7 @@ static int process_termination_nocpsch(struct device_queue_manager *dqm, struct device_process_node *cur, *next_dpn; int retval = 0; - mutex_lock(&dqm->lock); + dqm_lock(dqm); /* Clear all user mode queues */ list_for_each_entry_safe(q, next, &qpd->queues_list, list) { @@ -1489,7 +1490,7 @@ static int process_termination_nocpsch(struct device_queue_manager *dqm, } } - mutex_unlock(&dqm->lock); + dqm_unlock(dqm); return retval; } @@ -1507,7 +1508,7 @@ static int process_termination_cpsch(struct device_queue_manager *dqm, retval = 0; - mutex_lock(&dqm->lock); + dqm_lock(dqm); /* Clean all kernel queues */ list_for_each_entry_safe(kq, kq_next, &qpd->priv_queue_list, list) { @@ -1562,7 +1563,7 @@ static int process_termination_cpsch(struct device_queue_manager *dqm, } out: - mutex_unlock(&dqm->lock); + dqm_unlock(dqm); return retval; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h index 59a6b1956932f..0a23ddac345e4 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h @@ -26,6 +26,8 @@ #include <linux/rwsem.h> #include <linux/list.h> +#include <linux/mutex.h> +#include <linux/sched/mm.h> #include "kfd_priv.h" #include "kfd_mqd_manager.h" @@ -173,8 +175,9 @@ struct device_queue_manager { struct mqd_manager *mqds[KFD_MQD_TYPE_MAX]; struct packet_manager packets; struct kfd_dev *dev; - struct mutex lock; + struct mutex lock_hidden; /* use dqm_lock/unlock(dqm) */ struct list_head queues; + unsigned int saved_flags; unsigned int processes_count; unsigned int queue_count; unsigned int sdma_queue_count; @@ -219,4 +222,19 @@ get_sh_mem_bases_nybble_64(struct kfd_process_device *pdd) return (pdd->lds_base >> 60) & 0x0E; } +/* The DQM lock can be taken in MMU notifiers. Make sure no reclaim-FS + * happens while holding this lock anywhere to prevent deadlocks when + * an MMU notifier runs in reclaim-FS context. + */ +static inline void dqm_lock(struct device_queue_manager *dqm) +{ + mutex_lock(&dqm->lock_hidden); + dqm->saved_flags = memalloc_nofs_save(); +} +static inline void dqm_unlock(struct device_queue_manager *dqm) +{ + memalloc_nofs_restore(dqm->saved_flags); + mutex_unlock(&dqm->lock_hidden); +} + #endif /* KFD_DEVICE_QUEUE_MANAGER_H_ */ -- GitLab From 1cd106ecfc1f048db3795cc6aed8acb156ba6d4d Mon Sep 17 00:00:00 2001 From: Felix Kuehling <Felix.Kuehling@amd.com> Date: Wed, 11 Jul 2018 22:32:45 -0400 Subject: [PATCH 0997/1506] drm/amdkfd: Stop using GFP_NOIO explicitly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is no longer needed with the memalloc_nofs_save/restore in dqm_lock/unlock. Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com> Acked-by: Christian König <christian.koenig@amd.com> Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com> --- drivers/gpu/drm/amd/amdkfd/kfd_device.c | 4 ++-- drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c | 2 +- drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c | 4 ++-- drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index 7ee6cec2c0602..48c505e83217e 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -739,8 +739,8 @@ int kfd_gtt_sa_allocate(struct kfd_dev *kfd, unsigned int size, if (size > kfd->gtt_sa_num_of_chunks * kfd->gtt_sa_chunk_size) return -ENOMEM; - *mem_obj = kzalloc(sizeof(struct kfd_mem_obj), GFP_NOIO); - if ((*mem_obj) == NULL) + *mem_obj = kzalloc(sizeof(struct kfd_mem_obj), GFP_KERNEL); + if (!(*mem_obj)) return -ENOMEM; pr_debug("Allocated mem_obj = %p for size = %d\n", *mem_obj, size); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c index 06eaa218eba65..4872574f7a046 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c @@ -408,7 +408,7 @@ struct mqd_manager *mqd_manager_init_cik(enum KFD_MQD_TYPE type, if (WARN_ON(type >= KFD_MQD_TYPE_MAX)) return NULL; - mqd = kzalloc(sizeof(*mqd), GFP_NOIO); + mqd = kzalloc(sizeof(*mqd), GFP_KERNEL); if (!mqd) return NULL; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c index 684054ff02cdc..ad5c9f80cccd5 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c @@ -55,7 +55,7 @@ static int init_mqd(struct mqd_manager *mm, void **mqd, * instead of sub-allocation function. */ if (kfd->cwsr_enabled && (q->type == KFD_QUEUE_TYPE_COMPUTE)) { - *mqd_mem_obj = kzalloc(sizeof(struct kfd_mem_obj), GFP_NOIO); + *mqd_mem_obj = kzalloc(sizeof(struct kfd_mem_obj), GFP_KERNEL); if (!*mqd_mem_obj) return -ENOMEM; retval = kfd->kfd2kgd->init_gtt_mem_allocation(kfd->kgd, @@ -393,7 +393,7 @@ struct mqd_manager *mqd_manager_init_v9(enum KFD_MQD_TYPE type, if (WARN_ON(type >= KFD_MQD_TYPE_MAX)) return NULL; - mqd = kzalloc(sizeof(*mqd), GFP_NOIO); + mqd = kzalloc(sizeof(*mqd), GFP_KERNEL); if (!mqd) return NULL; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c index 481307b8b4dbd..89e4242e43e71 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c @@ -394,7 +394,7 @@ struct mqd_manager *mqd_manager_init_vi(enum KFD_MQD_TYPE type, if (WARN_ON(type >= KFD_MQD_TYPE_MAX)) return NULL; - mqd = kzalloc(sizeof(*mqd), GFP_NOIO); + mqd = kzalloc(sizeof(*mqd), GFP_KERNEL); if (!mqd) return NULL; -- GitLab From a60d811b2bf45f2e776e00d71f0dc3c5043245d9 Mon Sep 17 00:00:00 2001 From: Jay Cornwall <Jay.Cornwall@amd.com> Date: Wed, 11 Jul 2018 22:32:46 -0400 Subject: [PATCH 0998/1506] drm/amdkfd: Fix race between scheduler and context restore MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The scheduler may raise SQ_WAVE_STATUS.SPI_PRIO via SQ_CMD before context restore has completed. Restoring SPI_PRIO=0 after this point may cause context save to fail as the lower priority wavefronts are not selected for execution among spin-waiting wavefronts. Leave SPI_PRIO at its SPI-initialized or scheduler-raised value. v2: Also fix race with exception handler Signed-off-by: Jay Cornwall <Jay.Cornwall@amd.com> Reviewed-by: Felix Kuehling <Felix.Kuehling@amd.com> Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com> Acked-by: Christian König <christian.koenig@amd.com> Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com> --- .../gpu/drm/amd/amdkfd/cwsr_trap_handler.h | 458 +++++++++--------- .../drm/amd/amdkfd/cwsr_trap_handler_gfx8.asm | 18 +- .../drm/amd/amdkfd/cwsr_trap_handler_gfx9.asm | 16 +- 3 files changed, 262 insertions(+), 230 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h index f68aef02fc1fc..3621efbd57595 100644 --- a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h +++ b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h @@ -21,18 +21,21 @@ */ static const uint32_t cwsr_trap_gfx8_hex[] = { - 0xbf820001, 0xbf820125, + 0xbf820001, 0xbf82012b, 0xb8f4f802, 0x89748674, 0xb8f5f803, 0x8675ff75, - 0x00000400, 0xbf850011, + 0x00000400, 0xbf850017, 0xc00a1e37, 0x00000000, 0xbf8c007f, 0x87777978, - 0xbf840002, 0xb974f802, - 0xbe801d78, 0xb8f5f803, - 0x8675ff75, 0x000001ff, - 0xbf850002, 0x80708470, - 0x82718071, 0x8671ff71, - 0x0000ffff, 0xb974f802, + 0xbf840005, 0x8f728374, + 0xb972e0c2, 0xbf800002, + 0xb9740002, 0xbe801d78, + 0xb8f5f803, 0x8675ff75, + 0x000001ff, 0xbf850002, + 0x80708470, 0x82718071, + 0x8671ff71, 0x0000ffff, + 0x8f728374, 0xb972e0c2, + 0xbf800002, 0xb9740002, 0xbe801f70, 0xb8f5f803, 0x8675ff75, 0x00000100, 0xbf840006, 0xbefa0080, @@ -168,7 +171,7 @@ static const uint32_t cwsr_trap_gfx8_hex[] = { 0x807c847c, 0x806eff6e, 0x00000400, 0xbf0a757c, 0xbf85ffef, 0xbf9c0000, - 0xbf8200ca, 0xbef8007e, + 0xbf8200cd, 0xbef8007e, 0x8679ff7f, 0x0000ffff, 0x8779ff79, 0x00040000, 0xbefa0080, 0xbefb00ff, @@ -268,16 +271,18 @@ static const uint32_t cwsr_trap_gfx8_hex[] = { 0x8f739773, 0xb976f807, 0x8671ff71, 0x0000ffff, 0x86fe7e7e, 0x86ea6a6a, - 0xb974f802, 0xbf8a0000, - 0x95807370, 0xbf810000, + 0x8f768374, 0xb976e0c2, + 0xbf800002, 0xb9740002, + 0xbf8a0000, 0x95807370, + 0xbf810000, 0x00000000, }; static const uint32_t cwsr_trap_gfx9_hex[] = { - 0xbf820001, 0xbf82015a, + 0xbf820001, 0xbf82015d, 0xb8f8f802, 0x89788678, 0xb8f1f803, 0x866eff71, - 0x00000400, 0xbf850034, + 0x00000400, 0xbf850037, 0x866eff71, 0x00000800, 0xbf850003, 0x866eff71, 0x00000100, 0xbf840008, @@ -303,258 +308,261 @@ static const uint32_t cwsr_trap_gfx9_hex[] = { 0x8f6e8b77, 0x866eff6e, 0x001f8000, 0xb96ef807, 0x86fe7e7e, 0x86ea6a6a, - 0xb978f802, 0xbe801f6c, - 0x866dff6d, 0x0000ffff, - 0xbef00080, 0xb9700283, - 0xb8f02407, 0x8e709c70, - 0x876d706d, 0xb8f003c7, - 0x8e709b70, 0x876d706d, - 0xb8f0f807, 0x8670ff70, - 0x00007fff, 0xb970f807, - 0xbeee007e, 0xbeef007f, - 0xbefe0180, 0xbf900004, - 0x87708478, 0xb970f802, - 0xbf8e0002, 0xbf88fffe, - 0xb8f02a05, 0x80708170, - 0x8e708a70, 0xb8f11605, - 0x80718171, 0x8e718671, - 0x80707170, 0x80707e70, - 0x8271807f, 0x8671ff71, - 0x0000ffff, 0xc0471cb8, - 0x00000040, 0xbf8cc07f, - 0xc04b1d38, 0x00000048, - 0xbf8cc07f, 0xc0431e78, - 0x00000058, 0xbf8cc07f, - 0xc0471eb8, 0x0000005c, - 0xbf8cc07f, 0xbef4007e, - 0x8675ff7f, 0x0000ffff, - 0x8775ff75, 0x00040000, - 0xbef60080, 0xbef700ff, - 0x00807fac, 0x8670ff7f, - 0x08000000, 0x8f708370, - 0x87777077, 0x8670ff7f, - 0x70000000, 0x8f708170, - 0x87777077, 0xbefb007c, - 0xbefa0080, 0xb8fa2a05, - 0x807a817a, 0x8e7a8a7a, - 0xb8f01605, 0x80708170, - 0x8e708670, 0x807a707a, - 0xbef60084, 0xbef600ff, - 0x01000000, 0xbefe007c, - 0xbefc007a, 0xc0611efa, - 0x0000007c, 0xbf8cc07f, - 0x807a847a, 0xbefc007e, + 0x8f6e8378, 0xb96ee0c2, + 0xbf800002, 0xb9780002, + 0xbe801f6c, 0x866dff6d, + 0x0000ffff, 0xbef00080, + 0xb9700283, 0xb8f02407, + 0x8e709c70, 0x876d706d, + 0xb8f003c7, 0x8e709b70, + 0x876d706d, 0xb8f0f807, + 0x8670ff70, 0x00007fff, + 0xb970f807, 0xbeee007e, + 0xbeef007f, 0xbefe0180, + 0xbf900004, 0x87708478, + 0xb970f802, 0xbf8e0002, + 0xbf88fffe, 0xb8f02a05, + 0x80708170, 0x8e708a70, + 0xb8f11605, 0x80718171, + 0x8e718671, 0x80707170, + 0x80707e70, 0x8271807f, + 0x8671ff71, 0x0000ffff, + 0xc0471cb8, 0x00000040, + 0xbf8cc07f, 0xc04b1d38, + 0x00000048, 0xbf8cc07f, + 0xc0431e78, 0x00000058, + 0xbf8cc07f, 0xc0471eb8, + 0x0000005c, 0xbf8cc07f, + 0xbef4007e, 0x8675ff7f, + 0x0000ffff, 0x8775ff75, + 0x00040000, 0xbef60080, + 0xbef700ff, 0x00807fac, + 0x8670ff7f, 0x08000000, + 0x8f708370, 0x87777077, + 0x8670ff7f, 0x70000000, + 0x8f708170, 0x87777077, + 0xbefb007c, 0xbefa0080, + 0xb8fa2a05, 0x807a817a, + 0x8e7a8a7a, 0xb8f01605, + 0x80708170, 0x8e708670, + 0x807a707a, 0xbef60084, + 0xbef600ff, 0x01000000, 0xbefe007c, 0xbefc007a, - 0xc0611b3a, 0x0000007c, + 0xc0611efa, 0x0000007c, 0xbf8cc07f, 0x807a847a, 0xbefc007e, 0xbefe007c, - 0xbefc007a, 0xc0611b7a, + 0xbefc007a, 0xc0611b3a, 0x0000007c, 0xbf8cc07f, 0x807a847a, 0xbefc007e, 0xbefe007c, 0xbefc007a, - 0xc0611bba, 0x0000007c, + 0xc0611b7a, 0x0000007c, 0xbf8cc07f, 0x807a847a, 0xbefc007e, 0xbefe007c, - 0xbefc007a, 0xc0611bfa, + 0xbefc007a, 0xc0611bba, 0x0000007c, 0xbf8cc07f, 0x807a847a, 0xbefc007e, 0xbefe007c, 0xbefc007a, - 0xc0611e3a, 0x0000007c, - 0xbf8cc07f, 0x807a847a, - 0xbefc007e, 0xb8f1f803, - 0xbefe007c, 0xbefc007a, - 0xc0611c7a, 0x0000007c, + 0xc0611bfa, 0x0000007c, 0xbf8cc07f, 0x807a847a, 0xbefc007e, 0xbefe007c, - 0xbefc007a, 0xc0611a3a, + 0xbefc007a, 0xc0611e3a, + 0x0000007c, 0xbf8cc07f, + 0x807a847a, 0xbefc007e, + 0xb8f1f803, 0xbefe007c, + 0xbefc007a, 0xc0611c7a, 0x0000007c, 0xbf8cc07f, 0x807a847a, 0xbefc007e, 0xbefe007c, 0xbefc007a, - 0xc0611a7a, 0x0000007c, - 0xbf8cc07f, 0x807a847a, - 0xbefc007e, 0xb8fbf801, - 0xbefe007c, 0xbefc007a, - 0xc0611efa, 0x0000007c, + 0xc0611a3a, 0x0000007c, 0xbf8cc07f, 0x807a847a, - 0xbefc007e, 0x8670ff7f, - 0x04000000, 0xbeef0080, - 0x876f6f70, 0xb8fa2a05, + 0xbefc007e, 0xbefe007c, + 0xbefc007a, 0xc0611a7a, + 0x0000007c, 0xbf8cc07f, + 0x807a847a, 0xbefc007e, + 0xb8fbf801, 0xbefe007c, + 0xbefc007a, 0xc0611efa, + 0x0000007c, 0xbf8cc07f, + 0x807a847a, 0xbefc007e, + 0x8670ff7f, 0x04000000, + 0xbeef0080, 0x876f6f70, + 0xb8fa2a05, 0x807a817a, + 0x8e7a8a7a, 0xb8f11605, + 0x80718171, 0x8e718471, + 0x8e768271, 0xbef600ff, + 0x01000000, 0xbef20174, + 0x80747a74, 0x82758075, + 0xbefc0080, 0xbf800000, + 0xbe802b00, 0xbe822b02, + 0xbe842b04, 0xbe862b06, + 0xbe882b08, 0xbe8a2b0a, + 0xbe8c2b0c, 0xbe8e2b0e, + 0xc06b003a, 0x00000000, + 0xbf8cc07f, 0xc06b013a, + 0x00000010, 0xbf8cc07f, + 0xc06b023a, 0x00000020, + 0xbf8cc07f, 0xc06b033a, + 0x00000030, 0xbf8cc07f, + 0x8074c074, 0x82758075, + 0x807c907c, 0xbf0a717c, + 0xbf85ffe7, 0xbef40172, + 0xbefa0080, 0xbefe00c1, + 0xbeff00c1, 0xbee80080, + 0xbee90080, 0xbef600ff, + 0x01000000, 0xe0724000, + 0x7a1d0000, 0xe0724100, + 0x7a1d0100, 0xe0724200, + 0x7a1d0200, 0xe0724300, + 0x7a1d0300, 0xbefe00c1, + 0xbeff00c1, 0xb8f14306, + 0x8671c171, 0xbf84002c, + 0xbf8a0000, 0x8670ff6f, + 0x04000000, 0xbf840028, + 0x8e718671, 0x8e718271, + 0xbef60071, 0xb8fa2a05, 0x807a817a, 0x8e7a8a7a, - 0xb8f11605, 0x80718171, - 0x8e718471, 0x8e768271, + 0xb8f01605, 0x80708170, + 0x8e708670, 0x807a707a, + 0x807aff7a, 0x00000080, 0xbef600ff, 0x01000000, - 0xbef20174, 0x80747a74, - 0x82758075, 0xbefc0080, - 0xbf800000, 0xbe802b00, - 0xbe822b02, 0xbe842b04, - 0xbe862b06, 0xbe882b08, - 0xbe8a2b0a, 0xbe8c2b0c, - 0xbe8e2b0e, 0xc06b003a, - 0x00000000, 0xbf8cc07f, - 0xc06b013a, 0x00000010, - 0xbf8cc07f, 0xc06b023a, - 0x00000020, 0xbf8cc07f, - 0xc06b033a, 0x00000030, - 0xbf8cc07f, 0x8074c074, - 0x82758075, 0x807c907c, - 0xbf0a717c, 0xbf85ffe7, - 0xbef40172, 0xbefa0080, + 0xbefc0080, 0xd28c0002, + 0x000100c1, 0xd28d0003, + 0x000204c1, 0xd1060002, + 0x00011103, 0x7e0602ff, + 0x00000200, 0xbefc00ff, + 0x00010000, 0xbe800077, + 0x8677ff77, 0xff7fffff, + 0x8777ff77, 0x00058000, + 0xd8ec0000, 0x00000002, + 0xbf8cc07f, 0xe0765000, + 0x7a1d0002, 0x68040702, + 0xd0c9006a, 0x0000e302, + 0xbf87fff7, 0xbef70000, + 0xbefa00ff, 0x00000400, 0xbefe00c1, 0xbeff00c1, - 0xbee80080, 0xbee90080, + 0xb8f12a05, 0x80718171, + 0x8e718271, 0x8e768871, 0xbef600ff, 0x01000000, + 0xbefc0084, 0xbf0a717c, + 0xbf840015, 0xbf11017c, + 0x8071ff71, 0x00001000, + 0x7e000300, 0x7e020301, + 0x7e040302, 0x7e060303, 0xe0724000, 0x7a1d0000, 0xe0724100, 0x7a1d0100, 0xe0724200, 0x7a1d0200, 0xe0724300, 0x7a1d0300, + 0x807c847c, 0x807aff7a, + 0x00000400, 0xbf0a717c, + 0xbf85ffef, 0xbf9c0000, + 0xbf8200dc, 0xbef4007e, + 0x8675ff7f, 0x0000ffff, + 0x8775ff75, 0x00040000, + 0xbef60080, 0xbef700ff, + 0x00807fac, 0x866eff7f, + 0x08000000, 0x8f6e836e, + 0x87776e77, 0x866eff7f, + 0x70000000, 0x8f6e816e, + 0x87776e77, 0x866eff7f, + 0x04000000, 0xbf84001e, 0xbefe00c1, 0xbeff00c1, - 0xb8f14306, 0x8671c171, - 0xbf84002c, 0xbf8a0000, - 0x8670ff6f, 0x04000000, - 0xbf840028, 0x8e718671, - 0x8e718271, 0xbef60071, - 0xb8fa2a05, 0x807a817a, - 0x8e7a8a7a, 0xb8f01605, - 0x80708170, 0x8e708670, - 0x807a707a, 0x807aff7a, + 0xb8ef4306, 0x866fc16f, + 0xbf840019, 0x8e6f866f, + 0x8e6f826f, 0xbef6006f, + 0xb8f82a05, 0x80788178, + 0x8e788a78, 0xb8ee1605, + 0x806e816e, 0x8e6e866e, + 0x80786e78, 0x8078ff78, 0x00000080, 0xbef600ff, 0x01000000, 0xbefc0080, - 0xd28c0002, 0x000100c1, - 0xd28d0003, 0x000204c1, - 0xd1060002, 0x00011103, - 0x7e0602ff, 0x00000200, - 0xbefc00ff, 0x00010000, - 0xbe800077, 0x8677ff77, - 0xff7fffff, 0x8777ff77, - 0x00058000, 0xd8ec0000, - 0x00000002, 0xbf8cc07f, - 0xe0765000, 0x7a1d0002, - 0x68040702, 0xd0c9006a, - 0x0000e302, 0xbf87fff7, - 0xbef70000, 0xbefa00ff, - 0x00000400, 0xbefe00c1, - 0xbeff00c1, 0xb8f12a05, - 0x80718171, 0x8e718271, - 0x8e768871, 0xbef600ff, - 0x01000000, 0xbefc0084, - 0xbf0a717c, 0xbf840015, - 0xbf11017c, 0x8071ff71, - 0x00001000, 0x7e000300, + 0xe0510000, 0x781d0000, + 0xe0510100, 0x781d0000, + 0x807cff7c, 0x00000200, + 0x8078ff78, 0x00000200, + 0xbf0a6f7c, 0xbf85fff6, + 0xbef80080, 0xbefe00c1, + 0xbeff00c1, 0xb8ef2a05, + 0x806f816f, 0x8e6f826f, + 0x8e76886f, 0xbef600ff, + 0x01000000, 0xbeee0078, + 0x8078ff78, 0x00000400, + 0xbefc0084, 0xbf11087c, + 0x806fff6f, 0x00008000, + 0xe0524000, 0x781d0000, + 0xe0524100, 0x781d0100, + 0xe0524200, 0x781d0200, + 0xe0524300, 0x781d0300, + 0xbf8c0f70, 0x7e000300, 0x7e020301, 0x7e040302, - 0x7e060303, 0xe0724000, - 0x7a1d0000, 0xe0724100, - 0x7a1d0100, 0xe0724200, - 0x7a1d0200, 0xe0724300, - 0x7a1d0300, 0x807c847c, - 0x807aff7a, 0x00000400, - 0xbf0a717c, 0xbf85ffef, - 0xbf9c0000, 0xbf8200d9, - 0xbef4007e, 0x8675ff7f, - 0x0000ffff, 0x8775ff75, - 0x00040000, 0xbef60080, - 0xbef700ff, 0x00807fac, - 0x866eff7f, 0x08000000, - 0x8f6e836e, 0x87776e77, - 0x866eff7f, 0x70000000, - 0x8f6e816e, 0x87776e77, - 0x866eff7f, 0x04000000, - 0xbf84001e, 0xbefe00c1, - 0xbeff00c1, 0xb8ef4306, - 0x866fc16f, 0xbf840019, - 0x8e6f866f, 0x8e6f826f, - 0xbef6006f, 0xb8f82a05, + 0x7e060303, 0x807c847c, + 0x8078ff78, 0x00000400, + 0xbf0a6f7c, 0xbf85ffee, + 0xbf9c0000, 0xe0524000, + 0x6e1d0000, 0xe0524100, + 0x6e1d0100, 0xe0524200, + 0x6e1d0200, 0xe0524300, + 0x6e1d0300, 0xb8f82a05, 0x80788178, 0x8e788a78, 0xb8ee1605, 0x806e816e, 0x8e6e866e, 0x80786e78, - 0x8078ff78, 0x00000080, - 0xbef600ff, 0x01000000, - 0xbefc0080, 0xe0510000, - 0x781d0000, 0xe0510100, - 0x781d0000, 0x807cff7c, - 0x00000200, 0x8078ff78, - 0x00000200, 0xbf0a6f7c, - 0xbf85fff6, 0xbef80080, - 0xbefe00c1, 0xbeff00c1, - 0xb8ef2a05, 0x806f816f, - 0x8e6f826f, 0x8e76886f, - 0xbef600ff, 0x01000000, - 0xbeee0078, 0x8078ff78, - 0x00000400, 0xbefc0084, - 0xbf11087c, 0x806fff6f, - 0x00008000, 0xe0524000, - 0x781d0000, 0xe0524100, - 0x781d0100, 0xe0524200, - 0x781d0200, 0xe0524300, - 0x781d0300, 0xbf8c0f70, - 0x7e000300, 0x7e020301, - 0x7e040302, 0x7e060303, - 0x807c847c, 0x8078ff78, - 0x00000400, 0xbf0a6f7c, - 0xbf85ffee, 0xbf9c0000, - 0xe0524000, 0x6e1d0000, - 0xe0524100, 0x6e1d0100, - 0xe0524200, 0x6e1d0200, - 0xe0524300, 0x6e1d0300, + 0x80f8c078, 0xb8ef1605, + 0x806f816f, 0x8e6f846f, + 0x8e76826f, 0xbef600ff, + 0x01000000, 0xbefc006f, + 0xc031003a, 0x00000078, + 0x80f8c078, 0xbf8cc07f, + 0x80fc907c, 0xbf800000, + 0xbe802d00, 0xbe822d02, + 0xbe842d04, 0xbe862d06, + 0xbe882d08, 0xbe8a2d0a, + 0xbe8c2d0c, 0xbe8e2d0e, + 0xbf06807c, 0xbf84fff0, 0xb8f82a05, 0x80788178, 0x8e788a78, 0xb8ee1605, 0x806e816e, 0x8e6e866e, - 0x80786e78, 0x80f8c078, - 0xb8ef1605, 0x806f816f, - 0x8e6f846f, 0x8e76826f, + 0x80786e78, 0xbef60084, 0xbef600ff, 0x01000000, - 0xbefc006f, 0xc031003a, - 0x00000078, 0x80f8c078, - 0xbf8cc07f, 0x80fc907c, - 0xbf800000, 0xbe802d00, - 0xbe822d02, 0xbe842d04, - 0xbe862d06, 0xbe882d08, - 0xbe8a2d0a, 0xbe8c2d0c, - 0xbe8e2d0e, 0xbf06807c, - 0xbf84fff0, 0xb8f82a05, - 0x80788178, 0x8e788a78, - 0xb8ee1605, 0x806e816e, - 0x8e6e866e, 0x80786e78, - 0xbef60084, 0xbef600ff, - 0x01000000, 0xc0211bfa, + 0xc0211bfa, 0x00000078, + 0x80788478, 0xc0211b3a, 0x00000078, 0x80788478, - 0xc0211b3a, 0x00000078, - 0x80788478, 0xc0211b7a, + 0xc0211b7a, 0x00000078, + 0x80788478, 0xc0211eba, 0x00000078, 0x80788478, - 0xc0211eba, 0x00000078, - 0x80788478, 0xc0211efa, + 0xc0211efa, 0x00000078, + 0x80788478, 0xc0211c3a, 0x00000078, 0x80788478, - 0xc0211c3a, 0x00000078, - 0x80788478, 0xc0211c7a, + 0xc0211c7a, 0x00000078, + 0x80788478, 0xc0211a3a, 0x00000078, 0x80788478, - 0xc0211a3a, 0x00000078, - 0x80788478, 0xc0211a7a, + 0xc0211a7a, 0x00000078, + 0x80788478, 0xc0211cfa, 0x00000078, 0x80788478, - 0xc0211cfa, 0x00000078, - 0x80788478, 0xbf8cc07f, - 0xbefc006f, 0xbefe007a, - 0xbeff007b, 0x866f71ff, - 0x000003ff, 0xb96f4803, - 0x866f71ff, 0xfffff800, - 0x8f6f8b6f, 0xb96fa2c3, - 0xb973f801, 0xb8ee2a05, - 0x806e816e, 0x8e6e8a6e, - 0xb8ef1605, 0x806f816f, - 0x8e6f866f, 0x806e6f6e, - 0x806e746e, 0x826f8075, - 0x866fff6f, 0x0000ffff, - 0xc0071cb7, 0x00000040, - 0xc00b1d37, 0x00000048, - 0xc0031e77, 0x00000058, - 0xc0071eb7, 0x0000005c, - 0xbf8cc07f, 0x866fff6d, - 0xf0000000, 0x8f6f9c6f, - 0x8e6f906f, 0xbeee0080, - 0x876e6f6e, 0x866fff6d, - 0x08000000, 0x8f6f9b6f, - 0x8e6f8f6f, 0x876e6f6e, - 0x866fff70, 0x00800000, - 0x8f6f976f, 0xb96ef807, - 0x866dff6d, 0x0000ffff, - 0x86fe7e7e, 0x86ea6a6a, - 0xb970f802, 0xbf8a0000, + 0xbf8cc07f, 0xbefc006f, + 0xbefe007a, 0xbeff007b, + 0x866f71ff, 0x000003ff, + 0xb96f4803, 0x866f71ff, + 0xfffff800, 0x8f6f8b6f, + 0xb96fa2c3, 0xb973f801, + 0xb8ee2a05, 0x806e816e, + 0x8e6e8a6e, 0xb8ef1605, + 0x806f816f, 0x8e6f866f, + 0x806e6f6e, 0x806e746e, + 0x826f8075, 0x866fff6f, + 0x0000ffff, 0xc0071cb7, + 0x00000040, 0xc00b1d37, + 0x00000048, 0xc0031e77, + 0x00000058, 0xc0071eb7, + 0x0000005c, 0xbf8cc07f, + 0x866fff6d, 0xf0000000, + 0x8f6f9c6f, 0x8e6f906f, + 0xbeee0080, 0x876e6f6e, + 0x866fff6d, 0x08000000, + 0x8f6f9b6f, 0x8e6f8f6f, + 0x876e6f6e, 0x866fff70, + 0x00800000, 0x8f6f976f, + 0xb96ef807, 0x866dff6d, + 0x0000ffff, 0x86fe7e7e, + 0x86ea6a6a, 0x8f6e8370, + 0xb96ee0c2, 0xbf800002, + 0xb9700002, 0xbf8a0000, 0x95806f6c, 0xbf810000, }; diff --git a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx8.asm b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx8.asm index a2a04bb64096f..abe1a5da29fb3 100644 --- a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx8.asm +++ b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx8.asm @@ -103,6 +103,10 @@ var SQ_WAVE_STATUS_INST_ATC_SHIFT = 23 var SQ_WAVE_STATUS_INST_ATC_MASK = 0x00800000 var SQ_WAVE_STATUS_SPI_PRIO_SHIFT = 1 var SQ_WAVE_STATUS_SPI_PRIO_MASK = 0x00000006 +var SQ_WAVE_STATUS_PRE_SPI_PRIO_SHIFT = 0 +var SQ_WAVE_STATUS_PRE_SPI_PRIO_SIZE = 1 +var SQ_WAVE_STATUS_POST_SPI_PRIO_SHIFT = 3 +var SQ_WAVE_STATUS_POST_SPI_PRIO_SIZE = 29 var SQ_WAVE_LDS_ALLOC_LDS_SIZE_SHIFT = 12 var SQ_WAVE_LDS_ALLOC_LDS_SIZE_SIZE = 9 @@ -251,7 +255,7 @@ if (!EMU_RUN_HACK) s_waitcnt lgkmcnt(0) s_or_b32 ttmp7, ttmp8, ttmp9 s_cbranch_scc0 L_NO_NEXT_TRAP //next level trap handler not been set - s_setreg_b32 hwreg(HW_REG_STATUS), s_save_status //restore HW status(SCC) + set_status_without_spi_prio(s_save_status, ttmp2) //restore HW status(SCC) s_setpc_b64 [ttmp8,ttmp9] //jump to next level trap handler L_NO_NEXT_TRAP: @@ -262,7 +266,7 @@ L_NO_NEXT_TRAP: s_addc_u32 ttmp1, ttmp1, 0 L_EXCP_CASE: s_and_b32 ttmp1, ttmp1, 0xFFFF - s_setreg_b32 hwreg(HW_REG_STATUS), s_save_status //restore HW status(SCC) + set_status_without_spi_prio(s_save_status, ttmp2) //restore HW status(SCC) s_rfe_b64 [ttmp0, ttmp1] end // ********* End handling of non-CWSR traps ******************* @@ -1053,7 +1057,7 @@ end s_and_b32 s_restore_pc_hi, s_restore_pc_hi, 0x0000ffff //pc[47:32] //Do it here in order not to affect STATUS s_and_b64 exec, exec, exec // Restore STATUS.EXECZ, not writable by s_setreg_b32 s_and_b64 vcc, vcc, vcc // Restore STATUS.VCCZ, not writable by s_setreg_b32 - s_setreg_b32 hwreg(HW_REG_STATUS), s_restore_status // SCC is included, which is changed by previous salu + set_status_without_spi_prio(s_restore_status, s_restore_tmp) // SCC is included, which is changed by previous salu s_barrier //barrier to ensure the readiness of LDS before access attempts from any other wave in the same TG //FIXME not performance-optimal at this time @@ -1134,3 +1138,11 @@ end function get_hwreg_size_bytes return 128 //HWREG size 128 bytes end + +function set_status_without_spi_prio(status, tmp) + // Do not restore STATUS.SPI_PRIO since scheduler may have raised it. + s_lshr_b32 tmp, status, SQ_WAVE_STATUS_POST_SPI_PRIO_SHIFT + s_setreg_b32 hwreg(HW_REG_STATUS, SQ_WAVE_STATUS_POST_SPI_PRIO_SHIFT, SQ_WAVE_STATUS_POST_SPI_PRIO_SIZE), tmp + s_nop 0x2 // avoid S_SETREG => S_SETREG hazard + s_setreg_b32 hwreg(HW_REG_STATUS, SQ_WAVE_STATUS_PRE_SPI_PRIO_SHIFT, SQ_WAVE_STATUS_PRE_SPI_PRIO_SIZE), status +end diff --git a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx9.asm b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx9.asm index 998be96be7361..0bb9c577b3a2c 100644 --- a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx9.asm +++ b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx9.asm @@ -103,6 +103,10 @@ var SQ_WAVE_STATUS_INST_ATC_MASK = 0x00800000 var SQ_WAVE_STATUS_SPI_PRIO_SHIFT = 1 var SQ_WAVE_STATUS_SPI_PRIO_MASK = 0x00000006 var SQ_WAVE_STATUS_HALT_MASK = 0x2000 +var SQ_WAVE_STATUS_PRE_SPI_PRIO_SHIFT = 0 +var SQ_WAVE_STATUS_PRE_SPI_PRIO_SIZE = 1 +var SQ_WAVE_STATUS_POST_SPI_PRIO_SHIFT = 3 +var SQ_WAVE_STATUS_POST_SPI_PRIO_SIZE = 29 var SQ_WAVE_LDS_ALLOC_LDS_SIZE_SHIFT = 12 var SQ_WAVE_LDS_ALLOC_LDS_SIZE_SIZE = 9 @@ -317,7 +321,7 @@ L_EXCP_CASE: // Restore SQ_WAVE_STATUS. s_and_b64 exec, exec, exec // Restore STATUS.EXECZ, not writable by s_setreg_b32 s_and_b64 vcc, vcc, vcc // Restore STATUS.VCCZ, not writable by s_setreg_b32 - s_setreg_b32 hwreg(HW_REG_STATUS), s_save_status + set_status_without_spi_prio(s_save_status, ttmp2) s_rfe_b64 [ttmp0, ttmp1] end @@ -1120,7 +1124,7 @@ end s_and_b32 s_restore_pc_hi, s_restore_pc_hi, 0x0000ffff //pc[47:32] //Do it here in order not to affect STATUS s_and_b64 exec, exec, exec // Restore STATUS.EXECZ, not writable by s_setreg_b32 s_and_b64 vcc, vcc, vcc // Restore STATUS.VCCZ, not writable by s_setreg_b32 - s_setreg_b32 hwreg(HW_REG_STATUS), s_restore_status // SCC is included, which is changed by previous salu + set_status_without_spi_prio(s_restore_status, s_restore_tmp) // SCC is included, which is changed by previous salu s_barrier //barrier to ensure the readiness of LDS before access attempts from any other wave in the same TG //FIXME not performance-optimal at this time @@ -1212,3 +1216,11 @@ function ack_sqc_store_workaround s_waitcnt lgkmcnt(0) end end + +function set_status_without_spi_prio(status, tmp) + // Do not restore STATUS.SPI_PRIO since scheduler may have raised it. + s_lshr_b32 tmp, status, SQ_WAVE_STATUS_POST_SPI_PRIO_SHIFT + s_setreg_b32 hwreg(HW_REG_STATUS, SQ_WAVE_STATUS_POST_SPI_PRIO_SHIFT, SQ_WAVE_STATUS_POST_SPI_PRIO_SIZE), tmp + s_nop 0x2 // avoid S_SETREG => S_SETREG hazard + s_setreg_b32 hwreg(HW_REG_STATUS, SQ_WAVE_STATUS_PRE_SPI_PRIO_SHIFT, SQ_WAVE_STATUS_PRE_SPI_PRIO_SIZE), status +end -- GitLab From e47cb828eb3fca3e8999a0b9aa053dda18552071 Mon Sep 17 00:00:00 2001 From: Wei Lu <wei.lu2@amd.com> Date: Wed, 11 Jul 2018 22:32:47 -0400 Subject: [PATCH 0999/1506] drm/amdkfd: Fix error codes in kfd_get_process MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Return ERR_PTR(-EINVAL) if kfd_get_process fails to find the process. This fixes kernel oopses when a child process calls KFD ioctls with a file descriptor inherited from the parent process. Signed-off-by: Wei Lu <wei.lu2@amd.com> Reviewed-by: Felix Kuehling <Felix.Kuehling@amd.com> Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com> Acked-by: Christian König <christian.koenig@amd.com> Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com> --- drivers/gpu/drm/amd/amdkfd/kfd_process.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c index 1d80b4f7c681c..4694386cc6236 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c @@ -244,6 +244,8 @@ struct kfd_process *kfd_get_process(const struct task_struct *thread) return ERR_PTR(-EINVAL); process = find_process(thread); + if (!process) + return ERR_PTR(-EINVAL); return process; } -- GitLab From 101fee63cbb0a3df9e54aaafbfad0ab5821a34e6 Mon Sep 17 00:00:00 2001 From: Moses Reuben <moses.reuben@amd.com> Date: Wed, 11 Jul 2018 22:32:48 -0400 Subject: [PATCH 1000/1506] drm/amdkfd: send SIGSEGV to process upon KFD_EVENT_TYPE_MEMORY MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Moses Reuben <moses.reuben@amd.com> Reviewed-by: Felix Kuehling <Felix.Kuehling@amd.com> Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com> Acked-by: Christian König <christian.koenig@amd.com> Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com> --- drivers/gpu/drm/amd/amdkfd/kfd_events.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_events.c index 5562e94e786ae..3d5a8332e8c01 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_events.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_events.c @@ -850,6 +850,13 @@ static void lookup_events_by_type_and_signal(struct kfd_process *p, ev->memory_exception_data = *ev_data; } + if (type == KFD_EVENT_TYPE_MEMORY) { + dev_warn(kfd_device, + "Sending SIGSEGV to HSA Process with PID %d ", + p->lead_thread->pid); + send_sig(SIGSEGV, p->lead_thread, 0); + } + /* Send SIGTERM no event of type "type" has been found*/ if (send_signal) { if (send_sigterm) { -- GitLab From b97dfa27ef3ad3eddd2cb97a3b6a140d7037827a Mon Sep 17 00:00:00 2001 From: shaoyunl <Shaoyun.Liu@amd.com> Date: Wed, 11 Jul 2018 22:32:49 -0400 Subject: [PATCH 1001/1506] drm/amdgpu: save vm fault information for amdkfd MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit amdgpu save the vm fault related information for KFD usage and keep the copy until KFD read it. Signed-off-by: shaoyun liu <shaoyun.liu@amd.com> Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com> Acked-by: Christian König <christian.koenig@amd.com> Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h | 3 ++ .../gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c | 1 + .../gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c | 1 + .../gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c | 14 ++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h | 2 ++ drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c | 33 ++++++++++++++++++- drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c | 33 ++++++++++++++++++- .../gpu/drm/amd/include/kgd_kfd_interface.h | 20 +++++++++++ 8 files changed, 105 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h index a8418a3f4e9d3..3dc76d9b4d129 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h @@ -183,6 +183,9 @@ int amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel(struct kgd_dev *kgd, int amdgpu_amdkfd_gpuvm_restore_process_bos(void *process_info, struct dma_fence **ef); +int amdgpu_amdkfd_gpuvm_get_vm_fault_info(struct kgd_dev *kgd, + struct kfd_vm_fault_info *info); + void amdgpu_amdkfd_gpuvm_init_mem_limits(void); void amdgpu_amdkfd_unreserve_system_memory_limit(struct amdgpu_bo *bo); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c index ea79908dac4cb..befc7c48b1cfa 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c @@ -216,6 +216,7 @@ static const struct kfd2kgd_calls kfd2kgd = { .invalidate_tlbs = invalidate_tlbs, .invalidate_tlbs_vmid = invalidate_tlbs_vmid, .submit_ib = amdgpu_amdkfd_submit_ib, + .get_vm_fault_info = amdgpu_amdkfd_gpuvm_get_vm_fault_info }; struct kfd2kgd_calls *amdgpu_amdkfd_gfx_7_get_functions(void) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c index 19dd665e73071..c68ef85f77538 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c @@ -176,6 +176,7 @@ static const struct kfd2kgd_calls kfd2kgd = { .invalidate_tlbs = invalidate_tlbs, .invalidate_tlbs_vmid = invalidate_tlbs_vmid, .submit_ib = amdgpu_amdkfd_submit_ib, + .get_vm_fault_info = amdgpu_amdkfd_gpuvm_get_vm_fault_info }; struct kfd2kgd_calls *amdgpu_amdkfd_gfx_8_0_get_functions(void) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index fa38a960ce004..8a707d8bbb1c3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -1621,6 +1621,20 @@ int amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel(struct kgd_dev *kgd, return ret; } +int amdgpu_amdkfd_gpuvm_get_vm_fault_info(struct kgd_dev *kgd, + struct kfd_vm_fault_info *mem) +{ + struct amdgpu_device *adev; + + adev = (struct amdgpu_device *)kgd; + if (atomic_read(&adev->gmc.vm_fault_info_updated) == 1) { + *mem = *adev->gmc.vm_fault_info; + mb(); + atomic_set(&adev->gmc.vm_fault_info_updated, 0); + } + return 0; +} + /* Evict a userptr BO by stopping the queues if necessary * * Runs in MMU notifier, may be in RECLAIM_FS context. This means it diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h index 6cb4948233cbe..bb5a47a457907 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h @@ -105,6 +105,8 @@ struct amdgpu_gmc { /* protects concurrent invalidation */ spinlock_t invalidate_lock; bool translate_further; + struct kfd_vm_fault_info *vm_fault_info; + atomic_t vm_fault_info_updated; const struct amdgpu_gmc_funcs *gmc_funcs; }; diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c index 10920f0bd85ff..36dc367c4b45e 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c @@ -28,6 +28,7 @@ #include "cik.h" #include "gmc_v7_0.h" #include "amdgpu_ucode.h" +#include "amdgpu_amdkfd.h" #include "bif/bif_4_1_d.h" #include "bif/bif_4_1_sh_mask.h" @@ -1078,6 +1079,12 @@ static int gmc_v7_0_sw_init(void *handle) adev->vm_manager.vram_base_offset = 0; } + adev->gmc.vm_fault_info = kmalloc(sizeof(struct kfd_vm_fault_info), + GFP_KERNEL); + if (!adev->gmc.vm_fault_info) + return -ENOMEM; + atomic_set(&adev->gmc.vm_fault_info_updated, 0); + return 0; } @@ -1087,6 +1094,7 @@ static int gmc_v7_0_sw_fini(void *handle) amdgpu_gem_force_release(adev); amdgpu_vm_manager_fini(adev); + kfree(adev->gmc.vm_fault_info); gmc_v7_0_gart_fini(adev); amdgpu_bo_fini(adev); release_firmware(adev->gmc.fw); @@ -1276,7 +1284,7 @@ static int gmc_v7_0_process_interrupt(struct amdgpu_device *adev, struct amdgpu_irq_src *source, struct amdgpu_iv_entry *entry) { - u32 addr, status, mc_client; + u32 addr, status, mc_client, vmid; addr = RREG32(mmVM_CONTEXT1_PROTECTION_FAULT_ADDR); status = RREG32(mmVM_CONTEXT1_PROTECTION_FAULT_STATUS); @@ -1301,6 +1309,29 @@ static int gmc_v7_0_process_interrupt(struct amdgpu_device *adev, entry->pasid); } + vmid = REG_GET_FIELD(status, VM_CONTEXT1_PROTECTION_FAULT_STATUS, + VMID); + if (amdgpu_amdkfd_is_kfd_vmid(adev, vmid) + && !atomic_read(&adev->gmc.vm_fault_info_updated)) { + struct kfd_vm_fault_info *info = adev->gmc.vm_fault_info; + u32 protections = REG_GET_FIELD(status, + VM_CONTEXT1_PROTECTION_FAULT_STATUS, + PROTECTIONS); + + info->vmid = vmid; + info->mc_id = REG_GET_FIELD(status, + VM_CONTEXT1_PROTECTION_FAULT_STATUS, + MEMORY_CLIENT_ID); + info->status = status; + info->page_addr = addr; + info->prot_valid = protections & 0x7 ? true : false; + info->prot_read = protections & 0x8 ? true : false; + info->prot_write = protections & 0x10 ? true : false; + info->prot_exec = protections & 0x20 ? true : false; + mb(); + atomic_set(&adev->gmc.vm_fault_info_updated, 1); + } + return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c index 75f3ffb2891e9..70fc97b59b4f2 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c @@ -26,6 +26,7 @@ #include "amdgpu.h" #include "gmc_v8_0.h" #include "amdgpu_ucode.h" +#include "amdgpu_amdkfd.h" #include "gmc/gmc_8_1_d.h" #include "gmc/gmc_8_1_sh_mask.h" @@ -1182,6 +1183,12 @@ static int gmc_v8_0_sw_init(void *handle) adev->vm_manager.vram_base_offset = 0; } + adev->gmc.vm_fault_info = kmalloc(sizeof(struct kfd_vm_fault_info), + GFP_KERNEL); + if (!adev->gmc.vm_fault_info) + return -ENOMEM; + atomic_set(&adev->gmc.vm_fault_info_updated, 0); + return 0; } @@ -1191,6 +1198,7 @@ static int gmc_v8_0_sw_fini(void *handle) amdgpu_gem_force_release(adev); amdgpu_vm_manager_fini(adev); + kfree(adev->gmc.vm_fault_info); gmc_v8_0_gart_fini(adev); amdgpu_bo_fini(adev); release_firmware(adev->gmc.fw); @@ -1426,7 +1434,7 @@ static int gmc_v8_0_process_interrupt(struct amdgpu_device *adev, struct amdgpu_irq_src *source, struct amdgpu_iv_entry *entry) { - u32 addr, status, mc_client; + u32 addr, status, mc_client, vmid; if (amdgpu_sriov_vf(adev)) { dev_err(adev->dev, "GPU fault detected: %d 0x%08x\n", @@ -1463,6 +1471,29 @@ static int gmc_v8_0_process_interrupt(struct amdgpu_device *adev, entry->pasid); } + vmid = REG_GET_FIELD(status, VM_CONTEXT1_PROTECTION_FAULT_STATUS, + VMID); + if (amdgpu_amdkfd_is_kfd_vmid(adev, vmid) + && !atomic_read(&adev->gmc.vm_fault_info_updated)) { + struct kfd_vm_fault_info *info = adev->gmc.vm_fault_info; + u32 protections = REG_GET_FIELD(status, + VM_CONTEXT1_PROTECTION_FAULT_STATUS, + PROTECTIONS); + + info->vmid = vmid; + info->mc_id = REG_GET_FIELD(status, + VM_CONTEXT1_PROTECTION_FAULT_STATUS, + MEMORY_CLIENT_ID); + info->status = status; + info->page_addr = addr; + info->prot_valid = protections & 0x7 ? true : false; + info->prot_read = protections & 0x8 ? true : false; + info->prot_write = protections & 0x10 ? true : false; + info->prot_exec = protections & 0x20 ? true : false; + mb(); + atomic_set(&adev->gmc.vm_fault_info_updated, 1); + } + return 0; } diff --git a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h index 5733fbee07f7f..28b11d1052884 100644 --- a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h @@ -47,6 +47,17 @@ enum kfd_preempt_type { KFD_PREEMPT_TYPE_WAVEFRONT_RESET, }; +struct kfd_vm_fault_info { + uint64_t page_addr; + uint32_t vmid; + uint32_t mc_id; + uint32_t status; + bool prot_valid; + bool prot_read; + bool prot_write; + bool prot_exec; +}; + struct kfd_cu_info { uint32_t num_shader_engines; uint32_t num_shader_arrays_per_engine; @@ -259,6 +270,12 @@ struct tile_config { * IB to the corresponding ring (ring type). The IB is executed with the * specified VMID in a user mode context. * + * @get_vm_fault_info: Return information about a recent VM fault on + * GFXv7 and v8. If multiple VM faults occurred since the last call of + * this function, it will return information about the first of those + * faults. On GFXv9 VM fault information is fully contained in the IH + * packet and this function is not needed. + * * This structure contains function pointers to services that the kgd driver * provides to amdkfd driver. * @@ -374,6 +391,9 @@ struct kfd2kgd_calls { int (*submit_ib)(struct kgd_dev *kgd, enum kgd_engine_type engine, uint32_t vmid, uint64_t gpu_addr, uint32_t *ib_cmd, uint32_t ib_len); + + int (*get_vm_fault_info)(struct kgd_dev *kgd, + struct kfd_vm_fault_info *info); }; /** -- GitLab From 2640c3facbd6e21e63c95f19588cc24913a263cd Mon Sep 17 00:00:00 2001 From: shaoyunl <Shaoyun.Liu@amd.com> Date: Wed, 11 Jul 2018 22:32:50 -0400 Subject: [PATCH 1002/1506] drm/amdkfd: Handle VM faults in KFD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Pre-GFX9 the amdgpu ISR saves the vm-fault status and address per per-vmid. amdkfd needs to get the information from amdgpu through the new get_vm_fault_info interface. On GFX9 and later, all the required information is in the IH ring 2. amdkfd unmaps all queues from the faulting process and create new run-list without the guilty process 3. amdkfd notifies the runtime of the vm fault trap via EVENT_TYPE_MEMORY Signed-off-by: shaoyun liu <shaoyun.liu@amd.com> Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com> Acked-by: Christian König <christian.koenig@amd.com> Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com> --- .../gpu/drm/amd/amdkfd/cik_event_interrupt.c | 25 +++++++++++-- drivers/gpu/drm/amd/amdkfd/cik_int.h | 2 + .../drm/amd/amdkfd/kfd_device_queue_manager.c | 17 +++++++++ drivers/gpu/drm/amd/amdkfd/kfd_events.c | 37 +++++++++++++++++++ .../gpu/drm/amd/amdkfd/kfd_int_process_v9.c | 18 ++++++++- drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 4 ++ include/uapi/linux/kfd_ioctl.h | 2 +- 7 files changed, 98 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c b/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c index 49df6c791cfcc..cc33870e7edb9 100644 --- a/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c +++ b/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c @@ -48,18 +48,19 @@ static bool cik_event_interrupt_isr(struct kfd_dev *dev, return ihre->source_id == CIK_INTSRC_CP_END_OF_PIPE || ihre->source_id == CIK_INTSRC_SDMA_TRAP || ihre->source_id == CIK_INTSRC_SQ_INTERRUPT_MSG || - ihre->source_id == CIK_INTSRC_CP_BAD_OPCODE; + ihre->source_id == CIK_INTSRC_CP_BAD_OPCODE || + ihre->source_id == CIK_INTSRC_GFX_PAGE_INV_FAULT || + ihre->source_id == CIK_INTSRC_GFX_MEM_PROT_FAULT; } static void cik_event_interrupt_wq(struct kfd_dev *dev, const uint32_t *ih_ring_entry) { - unsigned int pasid; const struct cik_ih_ring_entry *ihre = (const struct cik_ih_ring_entry *)ih_ring_entry; uint32_t context_id = ihre->data & 0xfffffff; - - pasid = (ihre->ring_id & 0xffff0000) >> 16; + unsigned int vmid = (ihre->ring_id & 0x0000ff00) >> 8; + unsigned int pasid = (ihre->ring_id & 0xffff0000) >> 16; if (pasid == 0) return; @@ -72,6 +73,22 @@ static void cik_event_interrupt_wq(struct kfd_dev *dev, kfd_signal_event_interrupt(pasid, context_id & 0xff, 8); else if (ihre->source_id == CIK_INTSRC_CP_BAD_OPCODE) kfd_signal_hw_exception_event(pasid); + else if (ihre->source_id == CIK_INTSRC_GFX_PAGE_INV_FAULT || + ihre->source_id == CIK_INTSRC_GFX_MEM_PROT_FAULT) { + struct kfd_vm_fault_info info; + + kfd_process_vm_fault(dev->dqm, pasid); + + memset(&info, 0, sizeof(info)); + dev->kfd2kgd->get_vm_fault_info(dev->kgd, &info); + if (!info.page_addr && !info.status) + return; + + if (info.vmid == vmid) + kfd_signal_vm_fault_event(dev, pasid, &info); + else + kfd_signal_vm_fault_event(dev, pasid, NULL); + } } const struct kfd_event_interrupt_class event_interrupt_class_cik = { diff --git a/drivers/gpu/drm/amd/amdkfd/cik_int.h b/drivers/gpu/drm/amd/amdkfd/cik_int.h index 109298b9d507d..a2079a04a6735 100644 --- a/drivers/gpu/drm/amd/amdkfd/cik_int.h +++ b/drivers/gpu/drm/amd/amdkfd/cik_int.h @@ -37,6 +37,8 @@ struct cik_ih_ring_entry { #define CIK_INTSRC_DEQUEUE_COMPLETE 0xC6 #define CIK_INTSRC_SDMA_TRAP 0xE0 #define CIK_INTSRC_SQ_INTERRUPT_MSG 0xEF +#define CIK_INTSRC_GFX_PAGE_INV_FAULT 0x92 +#define CIK_INTSRC_GFX_MEM_PROT_FAULT 0x93 #endif 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 f2f81d26db0c3..44fc2038770ee 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -1684,6 +1684,23 @@ void device_queue_manager_uninit(struct device_queue_manager *dqm) kfree(dqm); } +int kfd_process_vm_fault(struct device_queue_manager *dqm, + unsigned int pasid) +{ + struct kfd_process_device *pdd; + struct kfd_process *p = kfd_lookup_process_by_pasid(pasid); + int ret = 0; + + if (!p) + return -EINVAL; + pdd = kfd_get_process_device_data(dqm->dev, p); + if (pdd) + ret = dqm->ops.evict_process_queues(dqm, &pdd->qpd); + kfd_unref_process(p); + + return ret; +} + #if defined(CONFIG_DEBUG_FS) static void seq_reg_dump(struct seq_file *m, diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_events.c index 3d5a8332e8c01..b58a0e665ebc3 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_events.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_events.c @@ -963,3 +963,40 @@ void kfd_signal_hw_exception_event(unsigned int pasid) mutex_unlock(&p->event_mutex); kfd_unref_process(p); } + +void kfd_signal_vm_fault_event(struct kfd_dev *dev, unsigned int pasid, + struct kfd_vm_fault_info *info) +{ + struct kfd_event *ev; + uint32_t id; + struct kfd_process *p = kfd_lookup_process_by_pasid(pasid); + struct kfd_hsa_memory_exception_data memory_exception_data; + + if (!p) + return; /* Presumably process exited. */ + memset(&memory_exception_data, 0, sizeof(memory_exception_data)); + memory_exception_data.gpu_id = dev->id; + memory_exception_data.failure.imprecise = 1; + /* Set failure reason */ + if (info) { + memory_exception_data.va = (info->page_addr) << PAGE_SHIFT; + memory_exception_data.failure.NotPresent = + info->prot_valid ? 1 : 0; + memory_exception_data.failure.NoExecute = + info->prot_exec ? 1 : 0; + memory_exception_data.failure.ReadOnly = + info->prot_write ? 1 : 0; + memory_exception_data.failure.imprecise = 0; + } + mutex_lock(&p->event_mutex); + + id = KFD_FIRST_NONSIGNAL_EVENT_ID; + idr_for_each_entry_continue(&p->event_idr, ev, id) + if (ev->type == KFD_EVENT_TYPE_MEMORY) { + ev->memory_exception_data = memory_exception_data; + set_event(ev); + } + + mutex_unlock(&p->event_mutex); + kfd_unref_process(p); +} 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 37029baa33460..d6b64e6927608 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c @@ -57,7 +57,9 @@ static bool event_interrupt_isr_v9(struct kfd_dev *dev, return source_id == SOC15_INTSRC_CP_END_OF_PIPE || source_id == SOC15_INTSRC_SDMA_TRAP || source_id == SOC15_INTSRC_SQ_INTERRUPT_MSG || - source_id == SOC15_INTSRC_CP_BAD_OPCODE; + source_id == SOC15_INTSRC_CP_BAD_OPCODE || + client_id == SOC15_IH_CLIENTID_VMC || + client_id == SOC15_IH_CLIENTID_UTCL2; } static void event_interrupt_wq_v9(struct kfd_dev *dev, @@ -82,7 +84,19 @@ static void event_interrupt_wq_v9(struct kfd_dev *dev, kfd_signal_hw_exception_event(pasid); else if (client_id == SOC15_IH_CLIENTID_VMC || client_id == SOC15_IH_CLIENTID_UTCL2) { - /* TODO */ + struct kfd_vm_fault_info info = {0}; + uint16_t ring_id = SOC15_RING_ID_FROM_IH_ENTRY(ih_ring_entry); + + info.vmid = vmid; + info.mc_id = client_id; + info.page_addr = ih_ring_entry[4] | + (uint64_t)(ih_ring_entry[5] & 0xf) << 32; + info.prot_valid = ring_id & 0x08; + info.prot_read = ring_id & 0x10; + info.prot_write = ring_id & 0x20; + + kfd_process_vm_fault(dev->dqm, pasid); + kfd_signal_vm_fault_event(dev, pasid, &info); } } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index 5e3990bb4c4be..91a3368421b1f 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -838,6 +838,7 @@ void device_queue_manager_uninit(struct device_queue_manager *dqm); struct kernel_queue *kernel_queue_init(struct kfd_dev *dev, enum kfd_queue_type type); void kernel_queue_uninit(struct kernel_queue *kq); +int kfd_process_vm_fault(struct device_queue_manager *dqm, unsigned int pasid); /* Process Queue Manager */ struct process_queue_node { @@ -964,6 +965,9 @@ int kfd_event_create(struct file *devkfd, struct kfd_process *p, uint64_t *event_page_offset, uint32_t *event_slot_index); int kfd_event_destroy(struct kfd_process *p, uint32_t event_id); +void kfd_signal_vm_fault_event(struct kfd_dev *dev, unsigned int pasid, + struct kfd_vm_fault_info *info); + void kfd_flush_tlb(struct kfd_process_device *pdd); int dbgdev_wave_reset_wavefronts(struct kfd_dev *dev, struct kfd_process *p); diff --git a/include/uapi/linux/kfd_ioctl.h b/include/uapi/linux/kfd_ioctl.h index b4f5073dbac25..46a54ab1e7287 100644 --- a/include/uapi/linux/kfd_ioctl.h +++ b/include/uapi/linux/kfd_ioctl.h @@ -219,7 +219,7 @@ struct kfd_memory_exception_failure { __u32 NotPresent; /* Page not present or supervisor privilege */ __u32 ReadOnly; /* Write access to a read-only page */ __u32 NoExecute; /* Execute access to a page marked NX */ - __u32 pad; + __u32 imprecise; /* Can't determine the exact fault address */ }; /* memory exception data*/ -- GitLab From 58e698861255129a00765b69c0499bc0d044feb4 Mon Sep 17 00:00:00 2001 From: Lan Xiao <Lan.Xiao@amd.com> Date: Wed, 11 Jul 2018 22:32:51 -0400 Subject: [PATCH 1003/1506] drm/amdkfd: fix zero reading of VMID and PASID for Hawaii MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Upon VM Fault, the VMID and PASID written by HW are zeros in Hawaii. Instead of reading from ih_ring_entry, read directly from the registers. This workaround fix the soft hang issues caused by mishandled VM Fault in Hawaii. Signed-off-by: Lan Xiao <Lan.Xiao@amd.com> Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com> Acked-by: Christian König <christian.koenig@amd.com> Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com> --- .../gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c | 20 ++++++++++++- .../gpu/drm/amd/amdkfd/cik_event_interrupt.c | 29 ++++++++++++++++++- drivers/gpu/drm/amd/amdkfd/kfd_device.c | 14 +++++++-- .../gpu/drm/amd/amdkfd/kfd_int_process_v9.c | 4 ++- drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c | 6 ++-- drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 9 ++++-- .../gpu/drm/amd/include/kgd_kfd_interface.h | 5 ++++ 7 files changed, 77 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c index befc7c48b1cfa..b4a05c510c75f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c @@ -145,6 +145,7 @@ static void set_vm_context_page_table_base(struct kgd_dev *kgd, uint32_t vmid, uint32_t page_table_base); static int invalidate_tlbs(struct kgd_dev *kgd, uint16_t pasid); static int invalidate_tlbs_vmid(struct kgd_dev *kgd, uint16_t vmid); +static uint32_t read_vmid_from_vmfault_reg(struct kgd_dev *kgd); /* Because of REG_GET_FIELD() being used, we put this function in the * asic specific file. @@ -216,7 +217,8 @@ static const struct kfd2kgd_calls kfd2kgd = { .invalidate_tlbs = invalidate_tlbs, .invalidate_tlbs_vmid = invalidate_tlbs_vmid, .submit_ib = amdgpu_amdkfd_submit_ib, - .get_vm_fault_info = amdgpu_amdkfd_gpuvm_get_vm_fault_info + .get_vm_fault_info = amdgpu_amdkfd_gpuvm_get_vm_fault_info, + .read_vmid_from_vmfault_reg = read_vmid_from_vmfault_reg }; struct kfd2kgd_calls *amdgpu_amdkfd_gfx_7_get_functions(void) @@ -912,3 +914,19 @@ static int invalidate_tlbs_vmid(struct kgd_dev *kgd, uint16_t vmid) RREG32(mmVM_INVALIDATE_RESPONSE); return 0; } + + /** + * read_vmid_from_vmfault_reg - read vmid from register + * + * adev: amdgpu_device pointer + * @vmid: vmid pointer + * read vmid from register (CIK). + */ +static uint32_t read_vmid_from_vmfault_reg(struct kgd_dev *kgd) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + + uint32_t status = RREG32(mmVM_CONTEXT1_PROTECTION_FAULT_STATUS); + + return REG_GET_FIELD(status, VM_CONTEXT1_PROTECTION_FAULT_STATUS, VMID); +} diff --git a/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c b/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c index cc33870e7edb9..5d2475d5392ce 100644 --- a/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c +++ b/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c @@ -25,12 +25,39 @@ #include "cik_int.h" static bool cik_event_interrupt_isr(struct kfd_dev *dev, - const uint32_t *ih_ring_entry) + const uint32_t *ih_ring_entry, + uint32_t *patched_ihre, + bool *patched_flag) { const struct cik_ih_ring_entry *ihre = (const struct cik_ih_ring_entry *)ih_ring_entry; + const struct kfd2kgd_calls *f2g = dev->kfd2kgd; unsigned int vmid, pasid; + /* This workaround is due to HW/FW limitation on Hawaii that + * VMID and PASID are not written into ih_ring_entry + */ + if ((ihre->source_id == CIK_INTSRC_GFX_PAGE_INV_FAULT || + ihre->source_id == CIK_INTSRC_GFX_MEM_PROT_FAULT) && + dev->device_info->asic_family == CHIP_HAWAII) { + struct cik_ih_ring_entry *tmp_ihre = + (struct cik_ih_ring_entry *)patched_ihre; + + *patched_flag = true; + *tmp_ihre = *ihre; + + vmid = f2g->read_vmid_from_vmfault_reg(dev->kgd); + pasid = f2g->get_atc_vmid_pasid_mapping_pasid(dev->kgd, vmid); + + tmp_ihre->ring_id &= 0x000000ff; + tmp_ihre->ring_id |= vmid << 8; + tmp_ihre->ring_id |= pasid << 16; + + return (pasid != 0) && + vmid >= dev->vm_info.first_vmid_kfd && + vmid <= dev->vm_info.last_vmid_kfd; + } + /* Only handle interrupts from KFD VMIDs */ vmid = (ihre->ring_id & 0x0000ff00) >> 8; if (vmid < dev->vm_info.first_vmid_kfd || diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index 48c505e83217e..6007511757606 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -577,14 +577,24 @@ static int kfd_resume(struct kfd_dev *kfd) /* This is called directly from KGD at ISR. */ void kgd2kfd_interrupt(struct kfd_dev *kfd, const void *ih_ring_entry) { + uint32_t patched_ihre[KFD_MAX_RING_ENTRY_SIZE]; + bool is_patched = false; + if (!kfd->init_complete) return; + if (kfd->device_info->ih_ring_entry_size > sizeof(patched_ihre)) { + dev_err_once(kfd_device, "Ring entry too small\n"); + return; + } + spin_lock(&kfd->interrupt_lock); if (kfd->interrupts_active - && interrupt_is_wanted(kfd, ih_ring_entry) - && enqueue_ih_ring_entry(kfd, ih_ring_entry)) + && interrupt_is_wanted(kfd, ih_ring_entry, + patched_ihre, &is_patched) + && enqueue_ih_ring_entry(kfd, + is_patched ? patched_ihre : ih_ring_entry)) queue_work(kfd->ih_wq, &kfd->interrupt_work); spin_unlock(&kfd->interrupt_lock); 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 d6b64e6927608..f836897bbf583 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c @@ -26,7 +26,9 @@ static bool event_interrupt_isr_v9(struct kfd_dev *dev, - const uint32_t *ih_ring_entry) + const uint32_t *ih_ring_entry, + uint32_t *patched_ihre, + bool *patched_flag) { uint16_t source_id, client_id, pasid, vmid; const uint32_t *data = ih_ring_entry; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c b/drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c index db6d9336b80d2..c56ac47cd3189 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c @@ -151,13 +151,15 @@ static void interrupt_wq(struct work_struct *work) ih_ring_entry); } -bool interrupt_is_wanted(struct kfd_dev *dev, const uint32_t *ih_ring_entry) +bool interrupt_is_wanted(struct kfd_dev *dev, + const uint32_t *ih_ring_entry, + uint32_t *patched_ihre, bool *flag) { /* integer and bitwise OR so there is no boolean short-circuiting */ unsigned int wanted = 0; wanted |= dev->device_info->event_interrupt_class->interrupt_isr(dev, - ih_ring_entry); + ih_ring_entry, patched_ihre, flag); return wanted != 0; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index 91a3368421b1f..cd5121d925e04 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -180,9 +180,10 @@ enum cache_policy { struct kfd_event_interrupt_class { bool (*interrupt_isr)(struct kfd_dev *dev, - const uint32_t *ih_ring_entry); + const uint32_t *ih_ring_entry, uint32_t *patched_ihre, + bool *patched_flag); void (*interrupt_wq)(struct kfd_dev *dev, - const uint32_t *ih_ring_entry); + const uint32_t *ih_ring_entry); }; struct kfd_device_info { @@ -806,7 +807,9 @@ int kfd_interrupt_init(struct kfd_dev *dev); void kfd_interrupt_exit(struct kfd_dev *dev); void kgd2kfd_interrupt(struct kfd_dev *kfd, const void *ih_ring_entry); bool enqueue_ih_ring_entry(struct kfd_dev *kfd, const void *ih_ring_entry); -bool interrupt_is_wanted(struct kfd_dev *dev, const uint32_t *ih_ring_entry); +bool interrupt_is_wanted(struct kfd_dev *dev, + const uint32_t *ih_ring_entry, + uint32_t *patched_ihre, bool *flag); /* Power Management */ void kgd2kfd_suspend(struct kfd_dev *kfd); diff --git a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h index 28b11d1052884..76a30cbeee19a 100644 --- a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h @@ -276,6 +276,10 @@ struct tile_config { * faults. On GFXv9 VM fault information is fully contained in the IH * packet and this function is not needed. * + * @read_vmid_from_vmfault_reg: On Hawaii the VMID is not set in the + * IH ring entry. This function allows the KFD ISR to get the VMID + * from the fault status register as early as possible. + * * This structure contains function pointers to services that the kgd driver * provides to amdkfd driver. * @@ -394,6 +398,7 @@ struct kfd2kgd_calls { int (*get_vm_fault_info)(struct kgd_dev *kgd, struct kfd_vm_fault_info *info); + uint32_t (*read_vmid_from_vmfault_reg)(struct kgd_dev *kgd); }; /** -- GitLab From 6d15ca0af0e070e67863c46b54d14f3664d925b4 Mon Sep 17 00:00:00 2001 From: Shaoyun Liu <Shaoyun.Liu@amd.com> Date: Wed, 11 Jul 2018 22:32:52 -0400 Subject: [PATCH 1004/1506] drm/amd: Add gpu reset interfaces between amdgpu and amdkfd MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Shaoyun Liu <Shaoyun.Liu@amd.com> Reviewed-by: Felix Kuehling <Felix.Kuehling@amd.com> Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com> Acked-by: Christian König <christian.koenig@amd.com> Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com> --- drivers/gpu/drm/amd/include/kgd_kfd_interface.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h index 76a30cbeee19a..7df5e4ab839f5 100644 --- a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h @@ -280,6 +280,8 @@ struct tile_config { * IH ring entry. This function allows the KFD ISR to get the VMID * from the fault status register as early as possible. * + * @gpu_recover: let kgd reset gpu after kfd detect CPC hang + * * This structure contains function pointers to services that the kgd driver * provides to amdkfd driver. * @@ -399,6 +401,8 @@ struct kfd2kgd_calls { int (*get_vm_fault_info)(struct kgd_dev *kgd, struct kfd_vm_fault_info *info); uint32_t (*read_vmid_from_vmfault_reg)(struct kgd_dev *kgd); + + void (*gpu_recover)(struct kgd_dev *kgd); }; /** @@ -424,6 +428,10 @@ struct kfd2kgd_calls { * @schedule_evict_and_restore_process: Schedules work queue that will prepare * for safe eviction of KFD BOs that belong to the specified process. * + * @pre_reset: Notifies amdkfd that amdgpu about to reset the gpu + * + * @post_reset: Notify amdkfd that amgpu successfully reseted the gpu + * * This structure contains function callback pointers so the kgd driver * will notify to the amdkfd about certain status changes. * @@ -442,6 +450,8 @@ struct kgd2kfd_calls { int (*resume_mm)(struct mm_struct *mm); int (*schedule_evict_and_restore_process)(struct mm_struct *mm, struct dma_fence *fence); + int (*pre_reset)(struct kfd_dev *kfd); + int (*post_reset)(struct kfd_dev *kfd); }; int kgd2kfd_init(unsigned interface_version, -- GitLab From 0c119abad7f0d7987c3ce4ea76b30bde76d0436e Mon Sep 17 00:00:00 2001 From: Shaoyun Liu <Shaoyun.Liu@amd.com> Date: Wed, 11 Jul 2018 22:32:53 -0400 Subject: [PATCH 1005/1506] drm/amd: Add kfd ioctl defines for hw_exception event MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Shaoyun Liu <Shaoyun.Liu@amd.com> Reviewed-by: Felix Kuehling <Felix.Kuehling@amd.com> Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com> Acked-by: Christian König <christian.koenig@amd.com> Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com> --- include/uapi/linux/kfd_ioctl.h | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/kfd_ioctl.h b/include/uapi/linux/kfd_ioctl.h index 46a54ab1e7287..88d17c39dbf9a 100644 --- a/include/uapi/linux/kfd_ioctl.h +++ b/include/uapi/linux/kfd_ioctl.h @@ -189,6 +189,15 @@ struct kfd_ioctl_dbg_wave_control_args { #define KFD_SIGNAL_EVENT_LIMIT 4096 +/* For kfd_event_data.hw_exception_data.reset_type. */ +#define KFD_HW_EXCEPTION_WHOLE_GPU_RESET 0 +#define KFD_HW_EXCEPTION_PER_ENGINE_RESET 1 + +/* For kfd_event_data.hw_exception_data.reset_cause. */ +#define KFD_HW_EXCEPTION_GPU_HANG 0 +#define KFD_HW_EXCEPTION_ECC 1 + + struct kfd_ioctl_create_event_args { __u64 event_page_offset; /* from KFD */ __u32 event_trigger_data; /* from KFD - signal events only */ @@ -230,10 +239,19 @@ struct kfd_hsa_memory_exception_data { __u32 pad; }; -/* Event data*/ +/* hw exception data */ +struct kfd_hsa_hw_exception_data { + uint32_t reset_type; + uint32_t reset_cause; + uint32_t memory_lost; + uint32_t gpu_id; +}; + +/* Event data */ struct kfd_event_data { union { struct kfd_hsa_memory_exception_data memory_exception_data; + struct kfd_hsa_hw_exception_data hw_exception_data; }; /* From KFD */ __u64 kfd_event_data_ext; /* pointer to an extension structure for future exception types */ -- GitLab From e3b7a967743c2e10457442ffafcb715a41255f28 Mon Sep 17 00:00:00 2001 From: Shaoyun Liu <Shaoyun.Liu@amd.com> Date: Wed, 11 Jul 2018 22:32:54 -0400 Subject: [PATCH 1006/1506] drm/amdkfd: Add gpu reset interface and place holder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Shaoyun Liu <Shaoyun.Liu@amd.com> Reviewed-by: Felix Kuehling <Felix.Kuehling@amd.com> Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com> Acked-by: Christian König <christian.koenig@amd.com> Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com> --- drivers/gpu/drm/amd/amdkfd/kfd_device.c | 10 ++++++++++ drivers/gpu/drm/amd/amdkfd/kfd_module.c | 2 ++ drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 4 ++++ 3 files changed, 16 insertions(+) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index 6007511757606..a8226d8b86cc0 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -514,6 +514,16 @@ void kgd2kfd_device_exit(struct kfd_dev *kfd) kfree(kfd); } +int kgd2kfd_pre_reset(struct kfd_dev *kfd) +{ + return 0; +} + +int kgd2kfd_post_reset(struct kfd_dev *kfd) +{ + return 0; +} + void kgd2kfd_suspend(struct kfd_dev *kfd) { if (!kfd->init_complete) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_module.c b/drivers/gpu/drm/amd/amdkfd/kfd_module.c index 76bf2dc8aec43..ee7bf07db4723 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_module.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_module.c @@ -47,6 +47,8 @@ static const struct kgd2kfd_calls kgd2kfd = { .resume_mm = kgd2kfd_resume_mm, .schedule_evict_and_restore_process = kgd2kfd_schedule_evict_and_restore_process, + .pre_reset = kgd2kfd_pre_reset, + .post_reset = kgd2kfd_post_reset, }; int sched_policy = KFD_SCHED_POLICY_HWS; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index cd5121d925e04..4bc8d5af419de 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -815,6 +815,10 @@ bool interrupt_is_wanted(struct kfd_dev *dev, void kgd2kfd_suspend(struct kfd_dev *kfd); int kgd2kfd_resume(struct kfd_dev *kfd); +/* GPU reset */ +int kgd2kfd_pre_reset(struct kfd_dev *kfd); +int kgd2kfd_post_reset(struct kfd_dev *kfd); + /* amdkfd Apertures */ int kfd_init_apertures(struct kfd_process *process); -- GitLab From 5c6dd71e597f33d517710affe3b8d8de253bc86d Mon Sep 17 00:00:00 2001 From: Shaoyun Liu <Shaoyun.Liu@amd.com> Date: Wed, 11 Jul 2018 22:32:55 -0400 Subject: [PATCH 1007/1506] drm/amdgpu: Call KFD reset handlers during GPU reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Shaoyun Liu <Shaoyun.Liu@amd.com> Reviewed-by: Felix Kuehling <Felix.Kuehling@amd.com> Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com> Acked-by: Christian König <christian.koenig@amd.com> Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 20 ++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h | 4 ++++ drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 5 +++++ 3 files changed, 29 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index e3ed08dca7b7d..f3a3aba08c2ff 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -243,6 +243,26 @@ int amdgpu_amdkfd_resume(struct amdgpu_device *adev) return r; } +int amdgpu_amdkfd_pre_reset(struct amdgpu_device *adev) +{ + int r = 0; + + if (adev->kfd) + r = kgd2kfd->pre_reset(adev->kfd); + + return r; +} + +int amdgpu_amdkfd_post_reset(struct amdgpu_device *adev) +{ + int r = 0; + + if (adev->kfd) + r = kgd2kfd->post_reset(adev->kfd); + + return r; +} + int alloc_gtt_mem(struct kgd_dev *kgd, size_t size, void **mem_obj, uint64_t *gpu_addr, void **cpu_ptr) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h index 3dc76d9b4d129..7dc551b8f682e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h @@ -126,6 +126,10 @@ struct kfd2kgd_calls *amdgpu_amdkfd_gfx_9_0_get_functions(void); bool amdgpu_amdkfd_is_kfd_vmid(struct amdgpu_device *adev, u32 vmid); +int amdgpu_amdkfd_pre_reset(struct amdgpu_device *adev); + +int amdgpu_amdkfd_post_reset(struct amdgpu_device *adev); + /* Shared API */ int alloc_gtt_mem(struct kgd_dev *kgd, size_t size, void **mem_obj, uint64_t *gpu_addr, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index ec53d8f96d063..b895584bb99f3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -3307,6 +3307,9 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, atomic_inc(&adev->gpu_reset_counter); adev->in_gpu_reset = 1; + /* Block kfd */ + amdgpu_amdkfd_pre_reset(adev); + /* block TTM */ resched = ttm_bo_lock_delayed_workqueue(&adev->mman.bdev); @@ -3363,6 +3366,8 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, dev_info(adev->dev, "GPU reset(%d) succeeded!\n",atomic_read(&adev->gpu_reset_counter)); } + /*unlock kfd */ + amdgpu_amdkfd_post_reset(adev); amdgpu_vf_error_trans_all(adev); adev->in_gpu_reset = 0; mutex_unlock(&adev->lock_reset); -- GitLab From e42051d2133b7912db99bd3a307c9219a88fe7c2 Mon Sep 17 00:00:00 2001 From: Shaoyun Liu <Shaoyun.Liu@amd.com> Date: Wed, 11 Jul 2018 22:32:56 -0400 Subject: [PATCH 1008/1506] drm/amdkfd: Implement GPU reset handlers in KFD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Lock KFD and evict existing queues on reset. Notify user mode by signaling hw_exception events. Signed-off-by: Shaoyun Liu <Shaoyun.Liu@amd.com> Reviewed-by: Felix Kuehling <Felix.Kuehling@amd.com> Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com> Acked-by: Christian König <christian.koenig@amd.com> Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com> --- drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 3 ++ drivers/gpu/drm/amd/amdkfd/kfd_device.c | 43 ++++++++++++++++++++++-- drivers/gpu/drm/amd/amdkfd/kfd_events.c | 27 +++++++++++++++ drivers/gpu/drm/amd/amdkfd/kfd_events.h | 1 + drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 4 +++ 5 files changed, 75 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index 7e717716b90e8..b5338bff8cef4 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -122,6 +122,9 @@ static int kfd_open(struct inode *inode, struct file *filep) if (IS_ERR(process)) return PTR_ERR(process); + if (kfd_is_locked()) + return -EAGAIN; + dev_dbg(kfd_device, "process %d opened, compat mode (32 bit) - %d\n", process->pasid, process->is_32bit_user_mode); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index a8226d8b86cc0..9f63ac366284b 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -30,7 +30,13 @@ #include "kfd_iommu.h" #define MQD_SIZE_ALIGNED 768 -static atomic_t kfd_device_suspended = ATOMIC_INIT(0); + +/* + * kfd_locked is used to lock the kfd driver during suspend or reset + * once locked, kfd driver will stop any further GPU execution. + * create process (open) will return -EAGAIN. + */ +static atomic_t kfd_locked = ATOMIC_INIT(0); #ifdef KFD_SUPPORT_IOMMU_V2 static const struct kfd_device_info kaveri_device_info = { @@ -516,21 +522,52 @@ void kgd2kfd_device_exit(struct kfd_dev *kfd) int kgd2kfd_pre_reset(struct kfd_dev *kfd) { + if (!kfd->init_complete) + return 0; + kgd2kfd_suspend(kfd); + + /* hold dqm->lock to prevent further execution*/ + dqm_lock(kfd->dqm); + + kfd_signal_reset_event(kfd); return 0; } +/* + * Fix me. KFD won't be able to resume existing process for now. + * We will keep all existing process in a evicted state and + * wait the process to be terminated. + */ + int kgd2kfd_post_reset(struct kfd_dev *kfd) { + int ret, count; + + if (!kfd->init_complete) + return 0; + + dqm_unlock(kfd->dqm); + + ret = kfd_resume(kfd); + if (ret) + return ret; + count = atomic_dec_return(&kfd_locked); + WARN_ONCE(count != 0, "KFD reset ref. error"); return 0; } +bool kfd_is_locked(void) +{ + return (atomic_read(&kfd_locked) > 0); +} + void kgd2kfd_suspend(struct kfd_dev *kfd) { if (!kfd->init_complete) return; /* For first KFD device suspend all the KFD processes */ - if (atomic_inc_return(&kfd_device_suspended) == 1) + if (atomic_inc_return(&kfd_locked) == 1) kfd_suspend_all_processes(); kfd->dqm->ops.stop(kfd->dqm); @@ -549,7 +586,7 @@ int kgd2kfd_resume(struct kfd_dev *kfd) if (ret) return ret; - count = atomic_dec_return(&kfd_device_suspended); + count = atomic_dec_return(&kfd_locked); WARN_ONCE(count < 0, "KFD suspend / resume ref. error"); if (count == 0) ret = kfd_resume_all_processes(); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_events.c index b58a0e665ebc3..820133cdef83e 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_events.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_events.c @@ -1000,3 +1000,30 @@ void kfd_signal_vm_fault_event(struct kfd_dev *dev, unsigned int pasid, mutex_unlock(&p->event_mutex); kfd_unref_process(p); } + +void kfd_signal_reset_event(struct kfd_dev *dev) +{ + struct kfd_hsa_hw_exception_data hw_exception_data; + struct kfd_process *p; + struct kfd_event *ev; + unsigned int temp; + uint32_t id, idx; + + /* Whole gpu reset caused by GPU hang and memory is lost */ + memset(&hw_exception_data, 0, sizeof(hw_exception_data)); + hw_exception_data.gpu_id = dev->id; + hw_exception_data.memory_lost = 1; + + idx = srcu_read_lock(&kfd_processes_srcu); + hash_for_each_rcu(kfd_processes_table, temp, p, kfd_processes) { + mutex_lock(&p->event_mutex); + id = KFD_FIRST_NONSIGNAL_EVENT_ID; + idr_for_each_entry_continue(&p->event_idr, ev, id) + if (ev->type == KFD_EVENT_TYPE_HW_EXCEPTION) { + ev->hw_exception_data = hw_exception_data; + set_event(ev); + } + mutex_unlock(&p->event_mutex); + } + srcu_read_unlock(&kfd_processes_srcu, idx); +} diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_events.h b/drivers/gpu/drm/amd/amdkfd/kfd_events.h index abca5bfebbff1..c7ac6c73af86e 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_events.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_events.h @@ -66,6 +66,7 @@ struct kfd_event { /* type specific data */ union { struct kfd_hsa_memory_exception_data memory_exception_data; + struct kfd_hsa_hw_exception_data hw_exception_data; }; }; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index 4bc8d5af419de..2e03d6c80aa0d 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -975,10 +975,14 @@ int kfd_event_destroy(struct kfd_process *p, uint32_t event_id); void kfd_signal_vm_fault_event(struct kfd_dev *dev, unsigned int pasid, struct kfd_vm_fault_info *info); +void kfd_signal_reset_event(struct kfd_dev *dev); + void kfd_flush_tlb(struct kfd_process_device *pdd); int dbgdev_wave_reset_wavefronts(struct kfd_dev *dev, struct kfd_process *p); +bool kfd_is_locked(void); + /* Debugfs */ #if defined(CONFIG_DEBUG_FS) -- GitLab From 24da5a9ca6c225ecdc33ea9c7c1b3aa0debed203 Mon Sep 17 00:00:00 2001 From: Shaoyun Liu <Shaoyun.Liu@amd.com> Date: Wed, 11 Jul 2018 22:32:57 -0400 Subject: [PATCH 1009/1506] drm/amdgpu: Enable the gpu reset from KFD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hook up the gpu_recover callback from KFD to amdgpu to enable handling of GPU hangs detected by KFD. Signed-off-by: Shaoyun Liu <Shaoyun.Liu@amd.com> Reviewed-by: Felix Kuehling <Felix.Kuehling@amd.com> Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com> Acked-by: Christian König <christian.koenig@amd.com> Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 7 +++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h | 2 ++ drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c | 3 ++- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c | 3 ++- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c | 1 + 5 files changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index f3a3aba08c2ff..454c22c722c24 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -263,6 +263,13 @@ int amdgpu_amdkfd_post_reset(struct amdgpu_device *adev) return r; } +void amdgpu_amdkfd_gpu_reset(struct kgd_dev *kgd) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)kgd; + + amdgpu_device_gpu_recover(adev, NULL, false); +} + int alloc_gtt_mem(struct kgd_dev *kgd, size_t size, void **mem_obj, uint64_t *gpu_addr, void **cpu_ptr) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h index 7dc551b8f682e..60207ea48bf5d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h @@ -130,6 +130,8 @@ int amdgpu_amdkfd_pre_reset(struct amdgpu_device *adev); int amdgpu_amdkfd_post_reset(struct amdgpu_device *adev); +void amdgpu_amdkfd_gpu_reset(struct kgd_dev *kgd); + /* Shared API */ int alloc_gtt_mem(struct kgd_dev *kgd, size_t size, void **mem_obj, uint64_t *gpu_addr, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c index b4a05c510c75f..70b275a711c22 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c @@ -218,7 +218,8 @@ static const struct kfd2kgd_calls kfd2kgd = { .invalidate_tlbs_vmid = invalidate_tlbs_vmid, .submit_ib = amdgpu_amdkfd_submit_ib, .get_vm_fault_info = amdgpu_amdkfd_gpuvm_get_vm_fault_info, - .read_vmid_from_vmfault_reg = read_vmid_from_vmfault_reg + .read_vmid_from_vmfault_reg = read_vmid_from_vmfault_reg, + .gpu_recover = amdgpu_amdkfd_gpu_reset }; struct kfd2kgd_calls *amdgpu_amdkfd_gfx_7_get_functions(void) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c index c68ef85f77538..6053b1d143ae0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c @@ -176,7 +176,8 @@ static const struct kfd2kgd_calls kfd2kgd = { .invalidate_tlbs = invalidate_tlbs, .invalidate_tlbs_vmid = invalidate_tlbs_vmid, .submit_ib = amdgpu_amdkfd_submit_ib, - .get_vm_fault_info = amdgpu_amdkfd_gpuvm_get_vm_fault_info + .get_vm_fault_info = amdgpu_amdkfd_gpuvm_get_vm_fault_info, + .gpu_recover = amdgpu_amdkfd_gpu_reset }; struct kfd2kgd_calls *amdgpu_amdkfd_gfx_8_0_get_functions(void) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c index 1db60aa5b7f0e..56d29cfd8227b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c @@ -213,6 +213,7 @@ static const struct kfd2kgd_calls kfd2kgd = { .invalidate_tlbs = invalidate_tlbs, .invalidate_tlbs_vmid = invalidate_tlbs_vmid, .submit_ib = amdgpu_amdkfd_submit_ib, + .gpu_recover = amdgpu_amdkfd_gpu_reset }; struct kfd2kgd_calls *amdgpu_amdkfd_gfx_9_0_get_functions(void) -- GitLab From 73ea648d921ed5c58895c8592321456fe12b697f Mon Sep 17 00:00:00 2001 From: Shaoyun Liu <Shaoyun.Liu@amd.com> Date: Wed, 11 Jul 2018 22:32:58 -0400 Subject: [PATCH 1010/1506] drm/amdkfd: Implement hang detection in KFD and call amdgpu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The reset will be performed in a new hw_exception work thread to handle HWS hang without blocking the thread that detected the hang. Signed-off-by: Shaoyun Liu <Shaoyun.Liu@amd.com> Reviewed-by: Felix Kuehling <Felix.Kuehling@amd.com> Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com> Acked-by: Christian König <christian.koenig@amd.com> Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com> --- .../drm/amd/amdkfd/kfd_device_queue_manager.c | 21 ++++++++++++++++++- .../drm/amd/amdkfd/kfd_device_queue_manager.h | 4 ++++ 2 files changed, 24 insertions(+), 1 deletion(-) 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 44fc2038770ee..6b59eab39fbe1 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -61,6 +61,8 @@ static int create_sdma_queue_nocpsch(struct device_queue_manager *dqm, static void deallocate_sdma_queue(struct device_queue_manager *dqm, unsigned int sdma_queue_id); +static void kfd_process_hw_exception(struct work_struct *work); + static inline enum KFD_MQD_TYPE get_mqd_type_from_queue_type(enum kfd_queue_type type) { @@ -1010,6 +1012,8 @@ static int initialize_cpsch(struct device_queue_manager *dqm) dqm->active_runlist = false; dqm->sdma_bitmap = (1 << CIK_SDMA_QUEUES) - 1; + INIT_WORK(&dqm->hw_exception_work, kfd_process_hw_exception); + return 0; } @@ -1042,6 +1046,8 @@ static int start_cpsch(struct device_queue_manager *dqm) init_interrupts(dqm); dqm_lock(dqm); + /* clear hang status when driver try to start the hw scheduler */ + dqm->is_hws_hang = false; execute_queues_cpsch(dqm, KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES, 0); dqm_unlock(dqm); @@ -1255,6 +1261,8 @@ static int unmap_queues_cpsch(struct device_queue_manager *dqm, { int retval = 0; + if (dqm->is_hws_hang) + return -EIO; if (!dqm->active_runlist) return retval; @@ -1293,9 +1301,13 @@ static int execute_queues_cpsch(struct device_queue_manager *dqm, { int retval; + if (dqm->is_hws_hang) + return -EIO; retval = unmap_queues_cpsch(dqm, filter, filter_param); if (retval) { pr_err("The cp might be in an unrecoverable state due to an unsuccessful queues preemption\n"); + dqm->is_hws_hang = true; + schedule_work(&dqm->hw_exception_work); return retval; } @@ -1543,7 +1555,7 @@ static int process_termination_cpsch(struct device_queue_manager *dqm, } retval = execute_queues_cpsch(dqm, filter, 0); - if (retval || qpd->reset_wavefronts) { + if ((!dqm->is_hws_hang) && (retval || qpd->reset_wavefronts)) { pr_warn("Resetting wave fronts (cpsch) on dev %p\n", dqm->dev); dbgdev_wave_reset_wavefronts(dqm->dev, qpd->pqm->process); qpd->reset_wavefronts = false; @@ -1701,6 +1713,13 @@ int kfd_process_vm_fault(struct device_queue_manager *dqm, return ret; } +static void kfd_process_hw_exception(struct work_struct *work) +{ + struct device_queue_manager *dqm = container_of(work, + struct device_queue_manager, hw_exception_work); + dqm->dev->kfd2kgd->gpu_recover(dqm->dev->kgd); +} + #if defined(CONFIG_DEBUG_FS) static void seq_reg_dump(struct seq_file *m, diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h index 0a23ddac345e4..70179a6826f4e 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h @@ -193,6 +193,10 @@ struct device_queue_manager { struct kfd_mem_obj *fence_mem; bool active_runlist; int sched_policy; + + /* hw exception */ + bool is_hws_hang; + struct work_struct hw_exception_work; }; void device_queue_manager_init_cik( -- GitLab From b5d21aac33179e55807d0fb0c0e1f694c1dce2c3 Mon Sep 17 00:00:00 2001 From: Shaoyun Liu <Shaoyun.Liu@amd.com> Date: Wed, 11 Jul 2018 22:32:59 -0400 Subject: [PATCH 1011/1506] drm/amdgpu: Don't use shadow BO for compute context MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Compute contexts cannot keep going after a GPU reset. Currently the process must terminate. In the future a process may be able recreate its context from scratch. Either way, there is no need to restore the GPUVM page table from shadow BOs. Signed-off-by: Shaoyun Liu <Shaoyun.Liu@amd.com> Reviewed-by: Felix Kuehling <Felix.Kuehling@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com> Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 5d7d7900ccabb..9eedc98100046 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -495,11 +495,12 @@ static int amdgpu_vm_alloc_levels(struct amdgpu_device *adev, eaddr = eaddr & ((1 << shift) - 1); flags = AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS; + if (vm->root.base.bo->shadow) + flags |= AMDGPU_GEM_CREATE_SHADOW; if (vm->use_cpu_for_update) flags |= AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED; else - flags |= (AMDGPU_GEM_CREATE_NO_CPU_ACCESS | - AMDGPU_GEM_CREATE_SHADOW); + flags |= AMDGPU_GEM_CREATE_NO_CPU_ACCESS; /* walk over the address space and allocate the page tables */ for (pt_idx = from; pt_idx <= to; ++pt_idx) { @@ -2587,7 +2588,7 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm, flags = AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS; if (vm->use_cpu_for_update) flags |= AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED; - else + else if (vm_context != AMDGPU_VM_CONTEXT_COMPUTE) flags |= AMDGPU_GEM_CREATE_SHADOW; size = amdgpu_vm_bo_size(adev, adev->vm_manager.root_level); @@ -2662,8 +2663,7 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm, * - pasid (old PASID is released, because compute manages its own PASIDs) * * Reinitializes the page directory to reflect the changed ATS - * setting. May leave behind an unused shadow BO for the page - * directory when switching from SDMA updates to CPU updates. + * setting. * * Returns: * 0 for success, -errno for errors. @@ -2713,6 +2713,9 @@ int amdgpu_vm_make_compute(struct amdgpu_device *adev, struct amdgpu_vm *vm) vm->pasid = 0; } + /* Free the shadow bo for compute VM */ + amdgpu_bo_unref(&vm->root.base.bo->shadow); + error: amdgpu_bo_unreserve(vm->root.base.bo); return r; -- GitLab From 67ccea60591a0515c885af9bf8dfb932a905457f Mon Sep 17 00:00:00 2001 From: Shaoyun Liu <Shaoyun.Liu@amd.com> Date: Wed, 11 Jul 2018 22:33:00 -0400 Subject: [PATCH 1012/1506] drm/amdgpu: Check NULL pointer for job before reset job's ring MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit job could be NULL when amdgpu_device_gpu_recover is called Signed-off-by: Shaoyun Liu <Shaoyun.Liu@amd.com> Reviewed-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com> Acked-by: Christian König <christian.koenig@amd.com> Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index b895584bb99f3..13acef526c5ba 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -3325,7 +3325,7 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, if (job && job->base.sched == &ring->sched) continue; - drm_sched_hw_job_reset(&ring->sched, &job->base); + drm_sched_hw_job_reset(&ring->sched, job ? &job->base : NULL); /* after all hw jobs are reset, hw fence is meaningless, so force_completion */ amdgpu_fence_driver_force_completion(ring); -- GitLab From 951df6d9cfd07f205f1905bf3b27d994612e0614 Mon Sep 17 00:00:00 2001 From: Shaoyun Liu <Shaoyun.Liu@amd.com> Date: Wed, 11 Jul 2018 22:33:01 -0400 Subject: [PATCH 1013/1506] drm/amdkfd: Fix kernel queue 64 bit doorbell offset calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The bitmap index calculation should reverse the logic used on allocation so it will clear the same bit used on allocation Signed-off-by: Shaoyun Liu <Shaoyun.Liu@amd.com> Reviewed-by: Felix Kuehling <Felix.Kuehling@amd.com> Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com> Acked-by: Christian König <christian.koenig@amd.com> Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com> --- drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c b/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c index c3744d89352c1..ebe79bf00145b 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c @@ -188,9 +188,9 @@ void __iomem *kfd_get_kernel_doorbell(struct kfd_dev *kfd, *doorbell_off = kfd->doorbell_id_offset + inx; pr_debug("Get kernel queue doorbell\n" - " doorbell offset == 0x%08X\n" - " kernel address == %p\n", - *doorbell_off, (kfd->doorbell_kernel_ptr + inx)); + " doorbell offset == 0x%08X\n" + " doorbell index == 0x%x\n", + *doorbell_off, inx); return kfd->doorbell_kernel_ptr + inx; } @@ -199,7 +199,8 @@ void kfd_release_kernel_doorbell(struct kfd_dev *kfd, u32 __iomem *db_addr) { unsigned int inx; - inx = (unsigned int)(db_addr - kfd->doorbell_kernel_ptr); + inx = (unsigned int)(db_addr - kfd->doorbell_kernel_ptr) + * sizeof(u32) / kfd->device_info->doorbell_size; mutex_lock(&kfd->doorbell_mutex); __clear_bit(inx, kfd->doorbell_available_index); -- GitLab From bff418a2ee5df84bd75ac43659af7289ec1bab1c Mon Sep 17 00:00:00 2001 From: Shaoyun Liu <Shaoyun.Liu@amd.com> Date: Wed, 11 Jul 2018 22:33:02 -0400 Subject: [PATCH 1014/1506] drm/amdgpu: Avoid invalidate tlbs when gpu is on reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Shaoyun Liu <Shaoyun.Liu@amd.com> Reviewed-by: Felix Kuehling <Felix.Kuehling@amd.com> Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com> Acked-by: Christian König <christian.koenig@amd.com> Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c | 3 +++ drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c | 3 +++ drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c | 3 +++ 3 files changed, 9 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c index 70b275a711c22..2551a45473936 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c @@ -886,6 +886,9 @@ static int invalidate_tlbs(struct kgd_dev *kgd, uint16_t pasid) int vmid; unsigned int tmp; + if (adev->in_gpu_reset) + return -EIO; + for (vmid = 0; vmid < 16; vmid++) { if (!amdgpu_amdkfd_is_kfd_vmid(adev, vmid)) continue; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c index 6053b1d143ae0..55749ce4f1660 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c @@ -846,6 +846,9 @@ static int invalidate_tlbs(struct kgd_dev *kgd, uint16_t pasid) int vmid; unsigned int tmp; + if (adev->in_gpu_reset) + return -EIO; + for (vmid = 0; vmid < 16; vmid++) { if (!amdgpu_amdkfd_is_kfd_vmid(adev, vmid)) continue; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c index 56d29cfd8227b..847f6c1e36246 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c @@ -867,6 +867,9 @@ static int invalidate_tlbs(struct kgd_dev *kgd, uint16_t pasid) int vmid; struct amdgpu_ring *ring = &adev->gfx.kiq.ring; + if (adev->in_gpu_reset) + return -EIO; + if (ring->ready) return invalidate_tlbs_with_kiq(adev, pasid); -- GitLab From 1b0bfcff463f390c4032ebe36a4d5fb777c00a4c Mon Sep 17 00:00:00 2001 From: Shaoyun Liu <Shaoyun.Liu@amd.com> Date: Wed, 11 Jul 2018 22:33:03 -0400 Subject: [PATCH 1015/1506] drm/amdgpu: Avoid destroy hqd when GPU is on reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Shaoyun Liu <Shaoyun.Liu@amd.com> Reviewed-by: Felix Kuehling <Felix.Kuehling@amd.com> Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com> Acked-by: Christian König <christian.koenig@amd.com> Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c | 3 +++ drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c | 3 +++ drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c | 3 +++ 3 files changed, 9 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c index 2551a45473936..98eac00e5d325 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c @@ -575,6 +575,9 @@ static int kgd_hqd_destroy(struct kgd_dev *kgd, void *mqd, unsigned long flags, end_jiffies; int retry; + if (adev->in_gpu_reset) + return -EIO; + acquire_queue(kgd, pipe_id, queue_id); WREG32(mmCP_HQD_PQ_DOORBELL_CONTROL, 0); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c index 55749ce4f1660..ad563b1ee5474 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c @@ -570,6 +570,9 @@ static int kgd_hqd_destroy(struct kgd_dev *kgd, void *mqd, int retry; struct vi_mqd *m = get_mqd(mqd); + if (adev->in_gpu_reset) + return -EIO; + acquire_queue(kgd, pipe_id, queue_id); if (m->cp_hqd_vmid == 0) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c index 847f6c1e36246..3b07d37b6fd45 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c @@ -680,6 +680,9 @@ static int kgd_hqd_destroy(struct kgd_dev *kgd, void *mqd, uint32_t temp; struct v9_mqd *m = get_mqd(mqd); + if (adev->in_gpu_reset) + return -EIO; + acquire_queue(kgd, pipe_id, queue_id); if (m->cp_hqd_vmid == 0) -- GitLab From a29ec470b19e58044005973301f233e0b20ed8c4 Mon Sep 17 00:00:00 2001 From: Shaoyun Liu <Shaoyun.Liu@amd.com> Date: Wed, 11 Jul 2018 22:33:04 -0400 Subject: [PATCH 1016/1506] drm/amdkfd: Add debugfs interface to trigger HWS hang MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Shaoyun Liu <Shaoyun.Liu@amd.com> Reviewed-by: Felix Kuehling <Felix.Kuehling@amd.com> Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com> Acked-by: Christian König <christian.koenig@amd.com> Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com> --- drivers/gpu/drm/amd/amdkfd/kfd_debugfs.c | 48 +++++++++++++++++++ drivers/gpu/drm/amd/amdkfd/kfd_device.c | 23 +++++++++ .../drm/amd/amdkfd/kfd_device_queue_manager.c | 12 +++++ .../gpu/drm/amd/amdkfd/kfd_packet_manager.c | 26 ++++++++++ drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 4 ++ 5 files changed, 113 insertions(+) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_debugfs.c b/drivers/gpu/drm/amd/amdkfd/kfd_debugfs.c index 4bd6ebfaf425b..ab37d36d9cd69 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_debugfs.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_debugfs.c @@ -21,6 +21,8 @@ */ #include <linux/debugfs.h> +#include <linux/uaccess.h> + #include "kfd_priv.h" static struct dentry *debugfs_root; @@ -32,6 +34,38 @@ static int kfd_debugfs_open(struct inode *inode, struct file *file) return single_open(file, show, NULL); } +static ssize_t kfd_debugfs_hang_hws_write(struct file *file, + const char __user *user_buf, size_t size, loff_t *ppos) +{ + struct kfd_dev *dev; + char tmp[16]; + uint32_t gpu_id; + int ret = -EINVAL; + + memset(tmp, 0, 16); + if (size >= 16) { + pr_err("Invalid input for gpu id.\n"); + goto out; + } + if (copy_from_user(tmp, user_buf, size)) { + ret = -EFAULT; + goto out; + } + if (kstrtoint(tmp, 10, &gpu_id)) { + pr_err("Invalid input for gpu id.\n"); + goto out; + } + dev = kfd_device_by_id(gpu_id); + if (dev) { + kfd_debugfs_hang_hws(dev); + ret = size; + } else + pr_err("Cannot find device %d.\n", gpu_id); + +out: + return ret; +} + static const struct file_operations kfd_debugfs_fops = { .owner = THIS_MODULE, .open = kfd_debugfs_open, @@ -40,6 +74,15 @@ static const struct file_operations kfd_debugfs_fops = { .release = single_release, }; +static const struct file_operations kfd_debugfs_hang_hws_fops = { + .owner = THIS_MODULE, + .open = kfd_debugfs_open, + .read = seq_read, + .write = kfd_debugfs_hang_hws_write, + .llseek = seq_lseek, + .release = single_release, +}; + void kfd_debugfs_init(void) { struct dentry *ent; @@ -65,6 +108,11 @@ void kfd_debugfs_init(void) ent = debugfs_create_file("rls", S_IFREG | 0444, debugfs_root, kfd_debugfs_rls_by_device, &kfd_debugfs_fops); + + ent = debugfs_create_file("hang_hws", S_IFREG | 0644, debugfs_root, + NULL, + &kfd_debugfs_hang_hws_fops); + if (!ent) pr_warn("Failed to create rls in kfd debugfs\n"); } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index 9f63ac366284b..8faa8db3eba52 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -914,3 +914,26 @@ int kfd_gtt_sa_free(struct kfd_dev *kfd, struct kfd_mem_obj *mem_obj) kfree(mem_obj); return 0; } + +#if defined(CONFIG_DEBUG_FS) + +/* This function will send a package to HIQ to hang the HWS + * which will trigger a GPU reset and bring the HWS back to normal state + */ +int kfd_debugfs_hang_hws(struct kfd_dev *dev) +{ + int r = 0; + + if (dev->dqm->sched_policy != KFD_SCHED_POLICY_HWS) { + pr_err("HWS is not enabled"); + return -EINVAL; + } + + r = pm_debugfs_hang_hws(&dev->dqm->packets); + if (!r) + r = dqm_debugfs_execute_queues(dev->dqm); + + return r; +} + +#endif 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 6b59eab39fbe1..32e93b53e7e87 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -1801,4 +1801,16 @@ int dqm_debugfs_hqds(struct seq_file *m, void *data) return r; } +int dqm_debugfs_execute_queues(struct device_queue_manager *dqm) +{ + int r = 0; + + dqm_lock(dqm); + dqm->active_runlist = true; + r = execute_queues_cpsch(dqm, KFD_UNMAP_QUEUES_FILTER_ALL_QUEUES, 0); + dqm_unlock(dqm); + + return r; +} + #endif diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c index c317feb43f69d..1092631765cb5 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c @@ -418,4 +418,30 @@ int pm_debugfs_runlist(struct seq_file *m, void *data) return 0; } +int pm_debugfs_hang_hws(struct packet_manager *pm) +{ + uint32_t *buffer, size; + int r = 0; + + size = pm->pmf->query_status_size; + mutex_lock(&pm->lock); + pm->priv_queue->ops.acquire_packet_buffer(pm->priv_queue, + size / sizeof(uint32_t), (unsigned int **)&buffer); + if (!buffer) { + pr_err("Failed to allocate buffer on kernel queue\n"); + r = -ENOMEM; + goto out; + } + memset(buffer, 0x55, size); + pm->priv_queue->ops.submit_packet(pm->priv_queue); + + pr_info("Submitting %x %x %x %x %x %x %x to HIQ to hang the HWS.", + buffer[0], buffer[1], buffer[2], buffer[3], + buffer[4], buffer[5], buffer[6]); +out: + mutex_unlock(&pm->lock); + return r; +} + + #endif diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index 2e03d6c80aa0d..d9bf70b528570 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -995,6 +995,10 @@ int dqm_debugfs_hqds(struct seq_file *m, void *data); int kfd_debugfs_rls_by_device(struct seq_file *m, void *data); int pm_debugfs_runlist(struct seq_file *m, void *data); +int kfd_debugfs_hang_hws(struct kfd_dev *dev); +int pm_debugfs_hang_hws(struct packet_manager *pm); +int dqm_debugfs_execute_queues(struct device_queue_manager *dqm); + #else static inline void kfd_debugfs_init(void) {} -- GitLab From 0e9a860c72ec387140a0feb4b8d9a6d0004e9316 Mon Sep 17 00:00:00 2001 From: Yong Zhao <yong.zhao@amd.com> Date: Wed, 11 Jul 2018 22:33:05 -0400 Subject: [PATCH 1017/1506] drm/amdkfd: Introduce KFD module parameter halt_if_hws_hang MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This avoids triggering a GPU reset or otherwise changing the HW state. Instead KFD will hang, which allows HW debugging tools to analyze the problem. Signed-off-by: Yong Zhao <yong.zhao@amd.com> Reviewed-by: Felix Kuehling <Felix.Kuehling@amd.com> Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com> Acked-by: Christian König <christian.koenig@amd.com> Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com> --- drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c | 7 +++++++ drivers/gpu/drm/amd/amdkfd/kfd_module.c | 4 ++++ drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 5 +++++ 3 files changed, 16 insertions(+) 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 32e93b53e7e87..5d05d125c3c14 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -1217,6 +1217,13 @@ int amdkfd_fence_wait_timeout(unsigned int *fence_addr, while (*fence_addr != fence_value) { if (time_after(jiffies, end_jiffies)) { pr_err("qcm fence wait loop timeout expired\n"); + /* In HWS case, this is used to halt the driver thread + * in order not to mess up CP states before doing + * scandumps for FW debugging. + */ + while (halt_if_hws_hang) + schedule(); + return -ETIME; } schedule(); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_module.c b/drivers/gpu/drm/amd/amdkfd/kfd_module.c index ee7bf07db4723..3a8c15ad0c64d 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_module.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_module.c @@ -92,6 +92,10 @@ MODULE_PARM_DESC(noretry, static int amdkfd_init_completed; +int halt_if_hws_hang; +module_param(halt_if_hws_hang, int, 0644); +MODULE_PARM_DESC(halt_if_hws_hang, "Halt if HWS hang is detected (0 = off (default), 1 = on)"); + int kgd2kfd_init(unsigned int interface_version, const struct kgd2kfd_calls **g2f) { diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index d9bf70b528570..8473e7b3dcc23 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -144,6 +144,11 @@ extern int ignore_crat; */ extern int vega10_noretry; +/* + * Halt if HWS hang is detected + */ +extern int halt_if_hws_hang; + /** * enum kfd_sched_policy * -- GitLab From 2b281977f5e072171bbd9e562c1dd27f0fe8461f Mon Sep 17 00:00:00 2001 From: Yong Zhao <yong.zhao@amd.com> Date: Wed, 11 Jul 2018 22:33:06 -0400 Subject: [PATCH 1018/1506] drm/amdkfd: Use module parameters noretry as the internal variable name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes all module parameters use the same form. Meanwhile clean up the surrounding code. Signed-off-by: Yong Zhao <yong.zhao@amd.com> Reviewed-by: Felix Kuehling <Felix.Kuehling@amd.com> Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com> Acked-by: Christian König <christian.koenig@amd.com> Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com> --- .../drm/amd/amdkfd/kfd_device_queue_manager_v9.c | 2 +- drivers/gpu/drm/amd/amdkfd/kfd_module.c | 14 ++++++++------ drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v9.c index 79e5bcf6367cc..417515332c351 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v9.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v9.c @@ -60,7 +60,7 @@ static int update_qpd_v9(struct device_queue_manager *dqm, qpd->sh_mem_config = SH_MEM_ALIGNMENT_MODE_UNALIGNED << SH_MEM_CONFIG__ALIGNMENT_MODE__SHIFT; - if (vega10_noretry && + if (noretry && !dqm->dev->device_info->needs_iommu_device) qpd->sh_mem_config |= 1 << SH_MEM_CONFIG__RETRY_DISABLE__SHIFT; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_module.c b/drivers/gpu/drm/amd/amdkfd/kfd_module.c index 3a8c15ad0c64d..6e1f5c7c2d4be 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_module.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_module.c @@ -63,7 +63,7 @@ MODULE_PARM_DESC(hws_max_conc_proc, int cwsr_enable = 1; module_param(cwsr_enable, int, 0444); -MODULE_PARM_DESC(cwsr_enable, "CWSR enable (0 = Off, 1 = On (Default))"); +MODULE_PARM_DESC(cwsr_enable, "CWSR enable (0 = off, 1 = on (default))"); int max_num_of_queues_per_device = KFD_MAX_NUM_OF_QUEUES_PER_DEVICE_DEFAULT; module_param(max_num_of_queues_per_device, int, 0444); @@ -85,17 +85,19 @@ module_param(ignore_crat, int, 0444); MODULE_PARM_DESC(ignore_crat, "Ignore CRAT table during KFD initialization (0 = use CRAT (default), 1 = ignore CRAT)"); -int vega10_noretry; -module_param_named(noretry, vega10_noretry, int, 0644); +int noretry; +module_param(noretry, int, 0644); MODULE_PARM_DESC(noretry, - "Set sh_mem_config.retry_disable on Vega10 (0 = retry enabled (default), 1 = retry disabled)"); - -static int amdkfd_init_completed; + "Set sh_mem_config.retry_disable on GFXv9+ dGPUs (0 = retry enabled (default), 1 = retry disabled)"); int halt_if_hws_hang; module_param(halt_if_hws_hang, int, 0644); MODULE_PARM_DESC(halt_if_hws_hang, "Halt if HWS hang is detected (0 = off (default), 1 = on)"); + +static int amdkfd_init_completed; + + int kgd2kfd_init(unsigned int interface_version, const struct kgd2kfd_calls **g2f) { diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index 8473e7b3dcc23..0646eda473df3 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -142,7 +142,7 @@ extern int ignore_crat; /* * Set sh_mem_config.retry_disable on Vega10 */ -extern int vega10_noretry; +extern int noretry; /* * Halt if HWS hang is detected -- GitLab From 8d5f355290880331e265d4c3f3b66c805969f18e Mon Sep 17 00:00:00 2001 From: Yong Zhao <yong.zhao@amd.com> Date: Wed, 11 Jul 2018 22:33:07 -0400 Subject: [PATCH 1019/1506] drm/amdkfd: Replace mqd with mqd_mgr as the variable name for mqd_manager MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will make reading code much easier. Signed-off-by: Yong Zhao <yong.zhao@amd.com> Reviewed-by: Felix Kuehling <Felix.Kuehling@amd.com> Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com> Acked-by: Christian König <christian.koenig@amd.com> Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com> --- .../drm/amd/amdkfd/kfd_device_queue_manager.c | 105 +++++++++--------- .../drm/amd/amdkfd/kfd_device_queue_manager.h | 2 +- drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c | 17 +-- drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.h | 2 +- .../amd/amdkfd/kfd_process_queue_manager.c | 8 +- 5 files changed, 68 insertions(+), 66 deletions(-) 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 5d05d125c3c14..97c9f10ff473a 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -348,10 +348,10 @@ static int create_compute_queue_nocpsch(struct device_queue_manager *dqm, struct qcm_process_device *qpd) { int retval; - struct mqd_manager *mqd; + struct mqd_manager *mqd_mgr; - 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) return -ENOMEM; retval = allocate_hqd(dqm, q); @@ -362,7 +362,7 @@ static int create_compute_queue_nocpsch(struct device_queue_manager *dqm, if (retval) goto out_deallocate_hqd; - retval = mqd->init_mqd(mqd, &q->mqd, &q->mqd_mem_obj, + retval = mqd_mgr->init_mqd(mqd_mgr, &q->mqd, &q->mqd_mem_obj, &q->gart_mqd_addr, &q->properties); if (retval) goto out_deallocate_doorbell; @@ -376,15 +376,15 @@ static int create_compute_queue_nocpsch(struct device_queue_manager *dqm, if (!q->properties.is_active) return 0; - retval = mqd->load_mqd(mqd, q->mqd, q->pipe, q->queue, &q->properties, - q->process->mm); + retval = mqd_mgr->load_mqd(mqd_mgr, q->mqd, q->pipe, q->queue, + &q->properties, q->process->mm); if (retval) goto out_uninit_mqd; return 0; out_uninit_mqd: - mqd->uninit_mqd(mqd, q->mqd, q->mqd_mem_obj); + mqd_mgr->uninit_mqd(mqd_mgr, q->mqd, q->mqd_mem_obj); out_deallocate_doorbell: deallocate_doorbell(qpd, q); out_deallocate_hqd: @@ -401,11 +401,11 @@ static int destroy_queue_nocpsch_locked(struct device_queue_manager *dqm, struct queue *q) { int retval; - struct mqd_manager *mqd; + struct mqd_manager *mqd_mgr; - mqd = dqm->ops.get_mqd_manager(dqm, + mqd_mgr = dqm->ops.get_mqd_manager(dqm, get_mqd_type_from_queue_type(q->properties.type)); - if (!mqd) + if (!mqd_mgr) return -ENOMEM; if (q->properties.type == KFD_QUEUE_TYPE_COMPUTE) { @@ -422,14 +422,14 @@ static int destroy_queue_nocpsch_locked(struct device_queue_manager *dqm, deallocate_doorbell(qpd, q); - retval = mqd->destroy_mqd(mqd, q->mqd, + retval = mqd_mgr->destroy_mqd(mqd_mgr, q->mqd, KFD_PREEMPT_TYPE_WAVEFRONT_RESET, KFD_UNMAP_LATENCY_MS, q->pipe, q->queue); if (retval == -ETIME) qpd->reset_wavefronts = true; - mqd->uninit_mqd(mqd, q->mqd, q->mqd_mem_obj); + mqd_mgr->uninit_mqd(mqd_mgr, q->mqd, q->mqd_mem_obj); list_del(&q->list); if (list_empty(&qpd->queues_list)) { @@ -469,7 +469,7 @@ static int destroy_queue_nocpsch(struct device_queue_manager *dqm, static int update_queue(struct device_queue_manager *dqm, struct queue *q) { int retval; - struct mqd_manager *mqd; + struct mqd_manager *mqd_mgr; struct kfd_process_device *pdd; bool prev_active = false; @@ -479,9 +479,9 @@ static int update_queue(struct device_queue_manager *dqm, struct queue *q) retval = -ENODEV; goto out_unlock; } - mqd = dqm->ops.get_mqd_manager(dqm, + mqd_mgr = dqm->ops.get_mqd_manager(dqm, get_mqd_type_from_queue_type(q->properties.type)); - if (!mqd) { + if (!mqd_mgr) { retval = -ENOMEM; goto out_unlock; } @@ -508,7 +508,7 @@ static int update_queue(struct device_queue_manager *dqm, struct queue *q) } else if (prev_active && (q->properties.type == KFD_QUEUE_TYPE_COMPUTE || q->properties.type == KFD_QUEUE_TYPE_SDMA)) { - retval = mqd->destroy_mqd(mqd, q->mqd, + retval = mqd_mgr->destroy_mqd(mqd_mgr, q->mqd, KFD_PREEMPT_TYPE_WAVEFRONT_DRAIN, KFD_UNMAP_LATENCY_MS, q->pipe, q->queue); if (retval) { @@ -517,7 +517,7 @@ static int update_queue(struct device_queue_manager *dqm, struct queue *q) } } - retval = mqd->update_mqd(mqd, q->mqd, &q->properties); + retval = mqd_mgr->update_mqd(mqd_mgr, q->mqd, &q->properties); /* * check active state vs. the previous state and modify @@ -535,7 +535,7 @@ static int update_queue(struct device_queue_manager *dqm, struct queue *q) else if (q->properties.is_active && (q->properties.type == KFD_QUEUE_TYPE_COMPUTE || q->properties.type == KFD_QUEUE_TYPE_SDMA)) - retval = mqd->load_mqd(mqd, q->mqd, q->pipe, q->queue, + retval = mqd_mgr->load_mqd(mqd_mgr, q->mqd, q->pipe, q->queue, &q->properties, q->process->mm); out_unlock: @@ -546,29 +546,29 @@ static int update_queue(struct device_queue_manager *dqm, struct queue *q) static struct mqd_manager *get_mqd_manager( struct device_queue_manager *dqm, enum KFD_MQD_TYPE type) { - struct mqd_manager *mqd; + struct mqd_manager *mqd_mgr; if (WARN_ON(type >= KFD_MQD_TYPE_MAX)) return NULL; pr_debug("mqd type %d\n", type); - mqd = dqm->mqds[type]; - if (!mqd) { - mqd = mqd_manager_init(type, dqm->dev); - if (!mqd) + mqd_mgr = dqm->mqd_mgrs[type]; + if (!mqd_mgr) { + mqd_mgr = mqd_manager_init(type, dqm->dev); + if (!mqd_mgr) pr_err("mqd manager is NULL"); - dqm->mqds[type] = mqd; + dqm->mqd_mgrs[type] = mqd_mgr; } - return mqd; + return mqd_mgr; } static int evict_process_queues_nocpsch(struct device_queue_manager *dqm, struct qcm_process_device *qpd) { struct queue *q; - struct mqd_manager *mqd; + struct mqd_manager *mqd_mgr; struct kfd_process_device *pdd; int retval = 0; @@ -584,16 +584,16 @@ static int evict_process_queues_nocpsch(struct device_queue_manager *dqm, list_for_each_entry(q, &qpd->queues_list, list) { if (!q->properties.is_active) continue; - mqd = dqm->ops.get_mqd_manager(dqm, + mqd_mgr = dqm->ops.get_mqd_manager(dqm, get_mqd_type_from_queue_type(q->properties.type)); - if (!mqd) { /* should not be here */ + if (!mqd_mgr) { /* should not be here */ pr_err("Cannot evict queue, mqd mgr is NULL\n"); retval = -ENOMEM; goto out; } q->properties.is_evicted = true; q->properties.is_active = false; - retval = mqd->destroy_mqd(mqd, q->mqd, + retval = mqd_mgr->destroy_mqd(mqd_mgr, q->mqd, KFD_PREEMPT_TYPE_WAVEFRONT_DRAIN, KFD_UNMAP_LATENCY_MS, q->pipe, q->queue); if (retval) @@ -643,7 +643,7 @@ static int restore_process_queues_nocpsch(struct device_queue_manager *dqm, struct qcm_process_device *qpd) { struct queue *q; - struct mqd_manager *mqd; + struct mqd_manager *mqd_mgr; struct kfd_process_device *pdd; uint32_t pd_base; int retval = 0; @@ -679,16 +679,16 @@ static int restore_process_queues_nocpsch(struct device_queue_manager *dqm, list_for_each_entry(q, &qpd->queues_list, list) { if (!q->properties.is_evicted) continue; - mqd = dqm->ops.get_mqd_manager(dqm, + mqd_mgr = dqm->ops.get_mqd_manager(dqm, get_mqd_type_from_queue_type(q->properties.type)); - if (!mqd) { /* should not be here */ + if (!mqd_mgr) { /* should not be here */ pr_err("Cannot restore queue, mqd mgr is NULL\n"); retval = -ENOMEM; goto out; } q->properties.is_evicted = false; q->properties.is_active = true; - retval = mqd->load_mqd(mqd, q->mqd, q->pipe, + retval = mqd_mgr->load_mqd(mqd_mgr, q->mqd, q->pipe, q->queue, &q->properties, q->process->mm); if (retval) @@ -868,7 +868,7 @@ static void uninitialize(struct device_queue_manager *dqm) kfree(dqm->allocated_queues); for (i = 0 ; i < KFD_MQD_TYPE_MAX ; i++) - kfree(dqm->mqds[i]); + kfree(dqm->mqd_mgrs[i]); mutex_destroy(&dqm->lock_hidden); kfd_gtt_sa_free(dqm->dev, dqm->pipeline_mem); } @@ -912,11 +912,11 @@ static int create_sdma_queue_nocpsch(struct device_queue_manager *dqm, struct queue *q, struct qcm_process_device *qpd) { - struct mqd_manager *mqd; + struct mqd_manager *mqd_mgr; int retval; - mqd = dqm->ops.get_mqd_manager(dqm, KFD_MQD_TYPE_SDMA); - if (!mqd) + mqd_mgr = dqm->ops.get_mqd_manager(dqm, KFD_MQD_TYPE_SDMA); + if (!mqd_mgr) return -ENOMEM; retval = allocate_sdma_queue(dqm, &q->sdma_id); @@ -935,19 +935,20 @@ static int create_sdma_queue_nocpsch(struct device_queue_manager *dqm, pr_debug("SDMA engine id: %d\n", q->properties.sdma_engine_id); dqm->asic_ops.init_sdma_vm(dqm, q, qpd); - retval = mqd->init_mqd(mqd, &q->mqd, &q->mqd_mem_obj, + retval = mqd_mgr->init_mqd(mqd_mgr, &q->mqd, &q->mqd_mem_obj, &q->gart_mqd_addr, &q->properties); if (retval) goto out_deallocate_doorbell; - retval = mqd->load_mqd(mqd, q->mqd, 0, 0, &q->properties, NULL); + retval = mqd_mgr->load_mqd(mqd_mgr, q->mqd, 0, 0, &q->properties, + NULL); if (retval) goto out_uninit_mqd; return 0; out_uninit_mqd: - mqd->uninit_mqd(mqd, q->mqd, q->mqd_mem_obj); + mqd_mgr->uninit_mqd(mqd_mgr, q->mqd, q->mqd_mem_obj); out_deallocate_doorbell: deallocate_doorbell(qpd, q); out_deallocate_sdma_queue: @@ -1123,7 +1124,7 @@ static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q, struct qcm_process_device *qpd) { int retval; - struct mqd_manager *mqd; + struct mqd_manager *mqd_mgr; retval = 0; @@ -1150,10 +1151,10 @@ static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q, if (retval) goto out_deallocate_sdma_queue; - mqd = dqm->ops.get_mqd_manager(dqm, + mqd_mgr = dqm->ops.get_mqd_manager(dqm, get_mqd_type_from_queue_type(q->properties.type)); - if (!mqd) { + if (!mqd_mgr) { retval = -ENOMEM; goto out_deallocate_doorbell; } @@ -1170,7 +1171,7 @@ static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q, q->properties.tba_addr = qpd->tba_addr; q->properties.tma_addr = qpd->tma_addr; - retval = mqd->init_mqd(mqd, &q->mqd, &q->mqd_mem_obj, + retval = mqd_mgr->init_mqd(mqd_mgr, &q->mqd, &q->mqd_mem_obj, &q->gart_mqd_addr, &q->properties); if (retval) goto out_deallocate_doorbell; @@ -1326,7 +1327,7 @@ static int destroy_queue_cpsch(struct device_queue_manager *dqm, struct queue *q) { int retval; - struct mqd_manager *mqd; + struct mqd_manager *mqd_mgr; bool preempt_all_queues; preempt_all_queues = false; @@ -1346,9 +1347,9 @@ static int destroy_queue_cpsch(struct device_queue_manager *dqm, } - mqd = dqm->ops.get_mqd_manager(dqm, + mqd_mgr = dqm->ops.get_mqd_manager(dqm, get_mqd_type_from_queue_type(q->properties.type)); - if (!mqd) { + if (!mqd_mgr) { retval = -ENOMEM; goto failed; } @@ -1370,7 +1371,7 @@ static int destroy_queue_cpsch(struct device_queue_manager *dqm, qpd->reset_wavefronts = true; } - mqd->uninit_mqd(mqd, q->mqd, q->mqd_mem_obj); + mqd_mgr->uninit_mqd(mqd_mgr, q->mqd, q->mqd_mem_obj); /* * Unconditionally decrement this counter, regardless of the queue's @@ -1520,7 +1521,7 @@ static int process_termination_cpsch(struct device_queue_manager *dqm, int retval; struct queue *q, *next; struct kernel_queue *kq, *kq_next; - struct mqd_manager *mqd; + struct mqd_manager *mqd_mgr; struct device_process_node *cur, *next_dpn; enum kfd_unmap_queues_filter filter = KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES; @@ -1570,15 +1571,15 @@ static int process_termination_cpsch(struct device_queue_manager *dqm, /* lastly, free mqd resources */ list_for_each_entry_safe(q, next, &qpd->queues_list, list) { - mqd = dqm->ops.get_mqd_manager(dqm, + mqd_mgr = dqm->ops.get_mqd_manager(dqm, get_mqd_type_from_queue_type(q->properties.type)); - if (!mqd) { + if (!mqd_mgr) { retval = -ENOMEM; goto out; } list_del(&q->list); qpd->queue_count--; - mqd->uninit_mqd(mqd, q->mqd, q->mqd_mem_obj); + mqd_mgr->uninit_mqd(mqd_mgr, q->mqd, q->mqd_mem_obj); } out: diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h index 70179a6826f4e..52e708c4f9a53 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h @@ -172,7 +172,7 @@ struct device_queue_manager { struct device_queue_manager_ops ops; struct device_queue_manager_asic_ops asic_ops; - struct mqd_manager *mqds[KFD_MQD_TYPE_MAX]; + struct mqd_manager *mqd_mgrs[KFD_MQD_TYPE_MAX]; struct packet_manager packets; struct kfd_dev *dev; struct mutex lock_hidden; /* use dqm_lock/unlock(dqm) */ diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c index 476951d8c91cc..2c8897e9073d3 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c @@ -59,7 +59,7 @@ static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev, switch (type) { case KFD_QUEUE_TYPE_DIQ: case KFD_QUEUE_TYPE_HIQ: - kq->mqd = dev->dqm->ops.get_mqd_manager(dev->dqm, + kq->mqd_mgr = dev->dqm->ops.get_mqd_manager(dev->dqm, KFD_MQD_TYPE_HIQ); break; default: @@ -67,7 +67,7 @@ static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev, return false; } - if (!kq->mqd) + if (!kq->mqd_mgr) return false; prop.doorbell_ptr = kfd_get_kernel_doorbell(dev, &prop.doorbell_off); @@ -130,7 +130,7 @@ static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev, kq->queue->device = dev; kq->queue->process = kfd_get_process(current); - retval = kq->mqd->init_mqd(kq->mqd, &kq->queue->mqd, + retval = kq->mqd_mgr->init_mqd(kq->mqd_mgr, &kq->queue->mqd, &kq->queue->mqd_mem_obj, &kq->queue->gart_mqd_addr, &kq->queue->properties); @@ -142,9 +142,9 @@ static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev, pr_debug("Assigning hiq to hqd\n"); kq->queue->pipe = KFD_CIK_HIQ_PIPE; kq->queue->queue = KFD_CIK_HIQ_QUEUE; - kq->mqd->load_mqd(kq->mqd, kq->queue->mqd, kq->queue->pipe, - kq->queue->queue, &kq->queue->properties, - NULL); + kq->mqd_mgr->load_mqd(kq->mqd_mgr, kq->queue->mqd, + kq->queue->pipe, kq->queue->queue, + &kq->queue->properties, NULL); } else { /* allocate fence for DIQ */ @@ -182,7 +182,7 @@ static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev, static void uninitialize(struct kernel_queue *kq) { if (kq->queue->properties.type == KFD_QUEUE_TYPE_HIQ) - kq->mqd->destroy_mqd(kq->mqd, + kq->mqd_mgr->destroy_mqd(kq->mqd_mgr, kq->queue->mqd, KFD_PREEMPT_TYPE_WAVEFRONT_RESET, KFD_UNMAP_LATENCY_MS, @@ -191,7 +191,8 @@ static void uninitialize(struct kernel_queue *kq) else if (kq->queue->properties.type == KFD_QUEUE_TYPE_DIQ) kfd_gtt_sa_free(kq->dev, kq->fence_mem_obj); - kq->mqd->uninit_mqd(kq->mqd, kq->queue->mqd, kq->queue->mqd_mem_obj); + kq->mqd_mgr->uninit_mqd(kq->mqd_mgr, kq->queue->mqd, + kq->queue->mqd_mem_obj); kfd_gtt_sa_free(kq->dev, kq->rptr_mem); kfd_gtt_sa_free(kq->dev, kq->wptr_mem); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.h b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.h index 97aff2041a5d1..a7116a9390295 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.h @@ -70,7 +70,7 @@ struct kernel_queue { /* data */ struct kfd_dev *dev; - struct mqd_manager *mqd; + struct mqd_manager *mqd_mgr; struct queue *queue; uint64_t pending_wptr64; uint32_t pending_wptr; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c index d65ce0436b31b..f85e5c06010e7 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c @@ -387,7 +387,7 @@ int pqm_debugfs_mqds(struct seq_file *m, void *data) struct process_queue_node *pqn; struct queue *q; enum KFD_MQD_TYPE mqd_type; - struct mqd_manager *mqd_manager; + struct mqd_manager *mqd_mgr; int r = 0; list_for_each_entry(pqn, &pqm->queues, process_queue_list) { @@ -410,11 +410,11 @@ int pqm_debugfs_mqds(struct seq_file *m, void *data) q->properties.type, q->device->id); continue; } - mqd_manager = q->device->dqm->ops.get_mqd_manager( + mqd_mgr = q->device->dqm->ops.get_mqd_manager( q->device->dqm, mqd_type); } else if (pqn->kq) { q = pqn->kq->queue; - mqd_manager = pqn->kq->mqd; + mqd_mgr = pqn->kq->mqd_mgr; switch (q->properties.type) { case KFD_QUEUE_TYPE_DIQ: seq_printf(m, " DIQ on device %x\n", @@ -434,7 +434,7 @@ int pqm_debugfs_mqds(struct seq_file *m, void *data) continue; } - r = mqd_manager->debugfs_show_mqd(m, q->mqd); + r = mqd_mgr->debugfs_show_mqd(m, q->mqd); if (r != 0) break; } -- GitLab From e7016d8e6f1b92888cc6093fd4e09d9f85934eb9 Mon Sep 17 00:00:00 2001 From: Yong Zhao <yong.zhao@amd.com> Date: Wed, 11 Jul 2018 22:33:08 -0400 Subject: [PATCH 1020/1506] drm/amdkfd: Clean up reference of radeon MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Yong Zhao <yong.zhao@amd.com> Reviewed-by: Felix Kuehling <Felix.Kuehling@amd.com> Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com> Acked-by: Christian König <christian.koenig@amd.com> Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com> --- drivers/gpu/drm/amd/amdkfd/cik_int.h | 5 +-- drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.c | 1 - drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.h | 37 +++++++++++++++++++ drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 2 +- .../amd/amdkfd/kfd_process_queue_manager.c | 2 +- 5 files changed, 41 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/cik_int.h b/drivers/gpu/drm/amd/amdkfd/cik_int.h index a2079a04a6735..76f8677a7926c 100644 --- a/drivers/gpu/drm/amd/amdkfd/cik_int.h +++ b/drivers/gpu/drm/amd/amdkfd/cik_int.h @@ -20,8 +20,8 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef HSA_RADEON_CIK_INT_H_INCLUDED -#define HSA_RADEON_CIK_INT_H_INCLUDED +#ifndef CIK_INT_H_INCLUDED +#define CIK_INT_H_INCLUDED #include <linux/types.h> @@ -34,7 +34,6 @@ struct cik_ih_ring_entry { #define CIK_INTSRC_CP_END_OF_PIPE 0xB5 #define CIK_INTSRC_CP_BAD_OPCODE 0xB7 -#define CIK_INTSRC_DEQUEUE_COMPLETE 0xC6 #define CIK_INTSRC_SDMA_TRAP 0xE0 #define CIK_INTSRC_SQ_INTERRUPT_MSG 0xEF #define CIK_INTSRC_GFX_PAGE_INV_FAULT 0x92 diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.c b/drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.c index afb26f205d297..a3441b0e385b7 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.c @@ -38,7 +38,6 @@ #include "kfd_dbgmgr.h" #include "kfd_dbgdev.h" #include "kfd_device_queue_manager.h" -#include "../../radeon/cik_reg.h" static void dbgdev_address_watch_disable_nodiq(struct kfd_dev *dev) { diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.h b/drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.h index 03424c20920cc..0619c777b47e6 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_dbgdev.h @@ -60,6 +60,9 @@ enum { SH_REG_SIZE = SH_REG_END - SH_REG_BASE }; +/* SQ_CMD definitions */ +#define SQ_CMD 0x8DEC + enum SQ_IND_CMD_CMD { SQ_IND_CMD_CMD_NULL = 0x00000000, SQ_IND_CMD_CMD_HALT = 0x00000001, @@ -190,4 +193,38 @@ union ULARGE_INTEGER { void kfd_dbgdev_init(struct kfd_dbgdev *pdbgdev, struct kfd_dev *pdev, enum DBGDEV_TYPE type); +union TCP_WATCH_CNTL_BITS { + struct { + uint32_t mask:24; + uint32_t vmid:4; + uint32_t atc:1; + uint32_t mode:2; + uint32_t valid:1; + } bitfields, bits; + uint32_t u32All; + signed int i32All; + float f32All; +}; + +enum { + ADDRESS_WATCH_REG_CNTL_ATC_BIT = 0x10000000UL, + ADDRESS_WATCH_REG_CNTL_DEFAULT_MASK = 0x00FFFFFF, + ADDRESS_WATCH_REG_ADDLOW_MASK_EXTENSION = 0x03000000, + /* extend the mask to 26 bits in order to match the low address field */ + ADDRESS_WATCH_REG_ADDLOW_SHIFT = 6, + ADDRESS_WATCH_REG_ADDHIGH_MASK = 0xFFFF +}; + +enum { + MAX_TRAPID = 8, /* 3 bits in the bitfield. */ + MAX_WATCH_ADDRESSES = 4 +}; + +enum { + ADDRESS_WATCH_REG_ADDR_HI = 0, + ADDRESS_WATCH_REG_ADDR_LO, + ADDRESS_WATCH_REG_CNTL, + ADDRESS_WATCH_REG_MAX +}; + #endif /* KFD_DBGDEV_H_ */ diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index 0646eda473df3..37d179ed51dc1 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -73,7 +73,7 @@ /* * When working with cp scheduler we should assign the HIQ manually or via - * the radeon driver to a fixed hqd slot, here are the fixed HIQ hqd slot + * the amdgpu driver to a fixed hqd slot, here are the fixed HIQ hqd slot * definitions for Kaveri. In Kaveri only the first ME queues participates * in the cp scheduling taking that in mind we set the HIQ slot in the * second ME. diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c index f85e5c06010e7..1303b1457950c 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c @@ -209,7 +209,7 @@ int pqm_create_queue(struct process_queue_manager *pqm, KFD_SCHED_POLICY_HWS_NO_OVERSUBSCRIPTION) && ((dev->dqm->processes_count >= dev->vm_info.vmid_num_kfd) || (dev->dqm->queue_count >= get_queues_num(dev->dqm)))) { - pr_err("Over-subscription is not allowed in radeon_kfd.sched_policy == 1\n"); + pr_debug("Over-subscription is not allowed when amdkfd.sched_policy == 1\n"); retval = -EPERM; goto err_create_queue; } -- GitLab From 559e50fd34d1c556d42016cbb9affce89cee9ea4 Mon Sep 17 00:00:00 2001 From: Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com> Date: Wed, 11 Jul 2018 23:01:47 -0300 Subject: [PATCH 1021/1506] drm/vkms: Add dumb operations VKMS currently does not handle dumb data, and as a consequence, it does not provide mechanisms for handling gem. This commit adds the necessary support for gem object/handler and the dumb functions. Changes since V1: Daniel Vetter: - Add dumb buffer support to the same patchset Changes since V2: Haneen: - Add missing gem_free_object_unlocked callback to fix the warning "Memory manager not clean during takedown" Signed-off-by: Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/70b7becc91c6a323dbc15cb5fc912cbdfe4ef7d9.1531359228.git.rodrigosiqueiramelo@gmail.com --- drivers/gpu/drm/vkms/Makefile | 2 +- drivers/gpu/drm/vkms/vkms_drv.c | 10 ++ drivers/gpu/drm/vkms/vkms_drv.h | 23 ++++ drivers/gpu/drm/vkms/vkms_gem.c | 179 ++++++++++++++++++++++++++++++++ 4 files changed, 213 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/vkms/vkms_gem.c diff --git a/drivers/gpu/drm/vkms/Makefile b/drivers/gpu/drm/vkms/Makefile index 3f774a6a9c581..986297da51bff 100644 --- a/drivers/gpu/drm/vkms/Makefile +++ b/drivers/gpu/drm/vkms/Makefile @@ -1,3 +1,3 @@ -vkms-y := vkms_drv.o vkms_plane.o vkms_output.o vkms_crtc.o +vkms-y := vkms_drv.o vkms_plane.o vkms_output.o vkms_crtc.o vkms_gem.o obj-$(CONFIG_DRM_VKMS) += vkms.o diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c index 740a4cbfed91c..6ea2fd97bef94 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.c +++ b/drivers/gpu/drm/vkms/vkms_drv.c @@ -37,6 +37,12 @@ static const struct file_operations vkms_driver_fops = { .release = drm_release, }; +static const struct vm_operations_struct vkms_gem_vm_ops = { + .fault = vkms_gem_fault, + .open = drm_gem_vm_open, + .close = drm_gem_vm_close, +}; + static void vkms_release(struct drm_device *dev) { struct vkms_device *vkms = container_of(dev, struct vkms_device, drm); @@ -50,6 +56,10 @@ static struct drm_driver vkms_driver = { .driver_features = DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_GEM, .release = vkms_release, .fops = &vkms_driver_fops, + .dumb_create = vkms_dumb_create, + .dumb_map_offset = vkms_dumb_map, + .gem_vm_ops = &vkms_gem_vm_ops, + .gem_free_object_unlocked = vkms_gem_free_object, .name = DRIVER_NAME, .desc = DRIVER_DESC, diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h index b0f9d2e61a422..cce4694cafb94 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.h +++ b/drivers/gpu/drm/vkms/vkms_drv.h @@ -3,6 +3,7 @@ #include <drm/drmP.h> #include <drm/drm.h> +#include <drm/drm_gem.h> #include <drm/drm_encoder.h> static const u32 vkms_formats[] = { @@ -21,6 +22,12 @@ struct vkms_device { struct vkms_output output; }; +struct vkms_gem_object { + struct drm_gem_object gem; + struct mutex pages_lock; /* Page lock used in page fault handler */ + struct page **pages; +}; + int vkms_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, struct drm_plane *primary, struct drm_plane *cursor); @@ -28,4 +35,20 @@ int vkms_output_init(struct vkms_device *vkmsdev); struct drm_plane *vkms_plane_init(struct vkms_device *vkmsdev); +/* Gem stuff */ +struct drm_gem_object *vkms_gem_create(struct drm_device *dev, + struct drm_file *file, + u32 *handle, + u64 size); + +int vkms_gem_fault(struct vm_fault *vmf); + +int vkms_dumb_create(struct drm_file *file, struct drm_device *dev, + struct drm_mode_create_dumb *args); + +int vkms_dumb_map(struct drm_file *file, struct drm_device *dev, + u32 handle, u64 *offset); + +void vkms_gem_free_object(struct drm_gem_object *obj); + #endif /* _VKMS_DRV_H_ */ diff --git a/drivers/gpu/drm/vkms/vkms_gem.c b/drivers/gpu/drm/vkms/vkms_gem.c new file mode 100644 index 0000000000000..c7e38368602b7 --- /dev/null +++ b/drivers/gpu/drm/vkms/vkms_gem.c @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/shmem_fs.h> + +#include "vkms_drv.h" + +static struct vkms_gem_object *__vkms_gem_create(struct drm_device *dev, + u64 size) +{ + struct vkms_gem_object *obj; + int ret; + + obj = kzalloc(sizeof(*obj), GFP_KERNEL); + if (!obj) + return ERR_PTR(-ENOMEM); + + size = roundup(size, PAGE_SIZE); + ret = drm_gem_object_init(dev, &obj->gem, size); + if (ret) { + kfree(obj); + return ERR_PTR(ret); + } + + mutex_init(&obj->pages_lock); + + return obj; +} + +void vkms_gem_free_object(struct drm_gem_object *obj) +{ + struct vkms_gem_object *gem = container_of(obj, struct vkms_gem_object, + gem); + + kvfree(gem->pages); + mutex_destroy(&gem->pages_lock); + drm_gem_object_release(obj); + kfree(gem); +} + +int vkms_gem_fault(struct vm_fault *vmf) +{ + struct vm_area_struct *vma = vmf->vma; + struct vkms_gem_object *obj = vma->vm_private_data; + unsigned long vaddr = vmf->address; + pgoff_t page_offset; + loff_t num_pages; + int ret; + + page_offset = (vaddr - vma->vm_start) >> PAGE_SHIFT; + num_pages = DIV_ROUND_UP(obj->gem.size, PAGE_SIZE); + + if (page_offset > num_pages) + return VM_FAULT_SIGBUS; + + ret = -ENOENT; + mutex_lock(&obj->pages_lock); + if (obj->pages) { + get_page(obj->pages[page_offset]); + vmf->page = obj->pages[page_offset]; + ret = 0; + } + mutex_unlock(&obj->pages_lock); + if (ret) { + struct page *page; + struct address_space *mapping; + + mapping = file_inode(obj->gem.filp)->i_mapping; + page = shmem_read_mapping_page(mapping, page_offset); + + if (!IS_ERR(page)) { + vmf->page = page; + ret = 0; + } else { + switch (PTR_ERR(page)) { + case -ENOSPC: + case -ENOMEM: + ret = VM_FAULT_OOM; + break; + case -EBUSY: + ret = VM_FAULT_RETRY; + break; + case -EFAULT: + case -EINVAL: + ret = VM_FAULT_SIGBUS; + break; + default: + WARN_ON(PTR_ERR(page)); + ret = VM_FAULT_SIGBUS; + break; + } + } + } + return ret; +} + +struct drm_gem_object *vkms_gem_create(struct drm_device *dev, + struct drm_file *file, + u32 *handle, + u64 size) +{ + struct vkms_gem_object *obj; + int ret; + + if (!file || !dev || !handle) + return ERR_PTR(-EINVAL); + + obj = __vkms_gem_create(dev, size); + if (IS_ERR(obj)) + return ERR_CAST(obj); + + ret = drm_gem_handle_create(file, &obj->gem, handle); + drm_gem_object_put_unlocked(&obj->gem); + if (ret) { + drm_gem_object_release(&obj->gem); + kfree(obj); + return ERR_PTR(ret); + } + + return &obj->gem; +} + +int vkms_dumb_create(struct drm_file *file, struct drm_device *dev, + struct drm_mode_create_dumb *args) +{ + struct drm_gem_object *gem_obj; + u64 pitch, size; + + if (!args || !dev || !file) + return -EINVAL; + + pitch = args->width * DIV_ROUND_UP(args->bpp, 8); + size = pitch * args->height; + + if (!size) + return -EINVAL; + + gem_obj = vkms_gem_create(dev, file, &args->handle, size); + if (IS_ERR(gem_obj)) + return PTR_ERR(gem_obj); + + args->size = gem_obj->size; + args->pitch = pitch; + + DRM_DEBUG_DRIVER("Created object of size %lld\n", size); + + return 0; +} + +int vkms_dumb_map(struct drm_file *file, struct drm_device *dev, + u32 handle, u64 *offset) +{ + struct drm_gem_object *obj; + int ret; + + obj = drm_gem_object_lookup(file, handle); + if (!obj) + return -ENOENT; + + if (!obj->filp) { + ret = -EINVAL; + goto unref; + } + + ret = drm_gem_create_mmap_offset(obj); + if (ret) + goto unref; + + *offset = drm_vma_node_offset_addr(&obj->vma_node); +unref: + drm_gem_object_put_unlocked(obj); + + return ret; +} -- GitLab From 657cd71e8eb3ac9ba91b8e1e403632b24d6cfdf9 Mon Sep 17 00:00:00 2001 From: Eames Trinh <eamestrinh@gmail.com> Date: Tue, 10 Jul 2018 15:00:21 +0200 Subject: [PATCH 1022/1506] drm: gma500: Changed __attribute__((packed)) to __packed Signed-off-by: Eames Trinh <eamestrinh@gmail.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180710130021.4499-1-eamestrinh@gmail.com --- drivers/gpu/drm/gma500/intel_bios.h | 38 ++++++++++++++--------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/gma500/intel_bios.h b/drivers/gpu/drm/gma500/intel_bios.h index 978ae4b25e822..e0ccf1d19a4dc 100644 --- a/drivers/gpu/drm/gma500/intel_bios.h +++ b/drivers/gpu/drm/gma500/intel_bios.h @@ -34,7 +34,7 @@ struct vbt_header { u8 reserved0; u32 bdb_offset; /**< from beginning of VBT */ u32 aim_offset[4]; /**< from beginning of VBT */ -} __attribute__((packed)); +} __packed; struct bdb_header { @@ -61,7 +61,7 @@ struct vbios_data { u8 rsvd4; /* popup memory size */ u8 resize_pci_bios; u8 rsvd5; /* is crt already on ddc2 */ -} __attribute__((packed)); +} __packed; /* * There are several types of BIOS data blocks (BDBs), each block has @@ -133,7 +133,7 @@ struct bdb_general_features { u8 dp_ssc_enb:1; /* PCH attached eDP supports SSC */ u8 dp_ssc_freq:1; /* SSC freq for PCH attached eDP */ u8 rsvd11:3; /* finish byte */ -} __attribute__((packed)); +} __packed; /* pre-915 */ #define GPIO_PIN_DVI_LVDS 0x03 /* "DVI/LVDS DDC GPIO pins" */ @@ -213,7 +213,7 @@ struct child_device_config { u8 dvo2_wiring; u16 extended_type; u8 dvo_function; -} __attribute__((packed)); +} __packed; struct bdb_general_definitions { @@ -256,7 +256,7 @@ struct bdb_lvds_options { u8 lvds_edid:1; u8 rsvd2:1; u8 rsvd4; -} __attribute__((packed)); +} __packed; struct bdb_lvds_backlight { u8 type:2; @@ -268,7 +268,7 @@ struct bdb_lvds_backlight { u8 i2caddr; u8 brightnesscmd; /*FIXME: more...*/ -} __attribute__((packed)); +} __packed; /* LFP pointer table contains entries to the struct below */ struct bdb_lvds_lfp_data_ptr { @@ -278,12 +278,12 @@ struct bdb_lvds_lfp_data_ptr { u8 dvo_table_size; u16 panel_pnp_id_offset; u8 pnp_table_size; -} __attribute__((packed)); +} __packed; struct bdb_lvds_lfp_data_ptrs { u8 lvds_entries; /* followed by one or more lvds_data_ptr structs */ struct bdb_lvds_lfp_data_ptr ptr[16]; -} __attribute__((packed)); +} __packed; /* LFP data has 3 blocks per entry */ struct lvds_fp_timing { @@ -300,7 +300,7 @@ struct lvds_fp_timing { u32 pfit_reg; u32 pfit_reg_val; u16 terminator; -} __attribute__((packed)); +} __packed; struct lvds_dvo_timing { u16 clock; /**< In 10khz */ @@ -328,7 +328,7 @@ struct lvds_dvo_timing { u8 vsync_positive:1; u8 hsync_positive:1; u8 rsvd2:1; -} __attribute__((packed)); +} __packed; struct lvds_pnp_id { u16 mfg_name; @@ -336,17 +336,17 @@ struct lvds_pnp_id { u32 serial; u8 mfg_week; u8 mfg_year; -} __attribute__((packed)); +} __packed; struct bdb_lvds_lfp_data_entry { struct lvds_fp_timing fp_timing; struct lvds_dvo_timing dvo_timing; struct lvds_pnp_id pnp_id; -} __attribute__((packed)); +} __packed; struct bdb_lvds_lfp_data { struct bdb_lvds_lfp_data_entry data[16]; -} __attribute__((packed)); +} __packed; struct aimdb_header { char signature[16]; @@ -354,12 +354,12 @@ struct aimdb_header { u16 aimdb_version; u16 aimdb_header_size; u16 aimdb_size; -} __attribute__((packed)); +} __packed; struct aimdb_block { u8 aimdb_id; u16 aimdb_size; -} __attribute__((packed)); +} __packed; struct vch_panel_data { u16 fp_timing_offset; @@ -370,12 +370,12 @@ struct vch_panel_data { u8 text_fitting_size; u16 graphics_fitting_offset; u8 graphics_fitting_size; -} __attribute__((packed)); +} __packed; struct vch_bdb_22 { struct aimdb_block aimdb_block; struct vch_panel_data panels[16]; -} __attribute__((packed)); +} __packed; struct bdb_sdvo_lvds_options { u8 panel_backlight; @@ -391,7 +391,7 @@ struct bdb_sdvo_lvds_options { u8 panel_misc_bits_2; u8 panel_misc_bits_3; u8 panel_misc_bits_4; -} __attribute__((packed)); +} __packed; #define BDB_DRIVER_FEATURE_NO_LVDS 0 #define BDB_DRIVER_FEATURE_INT_LVDS 1 @@ -436,7 +436,7 @@ struct bdb_driver_features { u8 hdmi_termination; u8 custom_vbt_version; -} __attribute__((packed)); +} __packed; #define EDP_18BPP 0 #define EDP_24BPP 1 -- GitLab From d16489307a52f028dcb072addf681f9280f585c6 Mon Sep 17 00:00:00 2001 From: Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com> Date: Wed, 11 Jul 2018 23:02:14 -0300 Subject: [PATCH 1023/1506] drm/vkms: Add connectors helpers This patch adds the struct drm_connector_helper_funcs with some necessary hooks. Additionally, it also adds some missing hooks at drm_connector_funcs. Changes since V1: - None Change since V2: Daniel Vetter: - Remove vkms_conn_mode_valid Signed-off-by: Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/c8ee28b889234e866ef18bce4216385661c48041.1531359228.git.rodrigosiqueiramelo@gmail.com --- drivers/gpu/drm/vkms/vkms_drv.c | 6 ------ drivers/gpu/drm/vkms/vkms_drv.h | 9 +++++++++ drivers/gpu/drm/vkms/vkms_output.c | 20 ++++++++++++++++++++ 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c index 6ea2fd97bef94..8236932355454 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.c +++ b/drivers/gpu/drm/vkms/vkms_drv.c @@ -17,12 +17,6 @@ #define DRIVER_MAJOR 1 #define DRIVER_MINOR 0 -#define XRES_MIN 32 -#define YRES_MIN 32 - -#define XRES_MAX 8192 -#define YRES_MAX 8192 - static struct vkms_device *vkms_device; static const struct file_operations vkms_driver_fops = { diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h index cce4694cafb94..57d7367fd8144 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.h +++ b/drivers/gpu/drm/vkms/vkms_drv.h @@ -6,6 +6,15 @@ #include <drm/drm_gem.h> #include <drm/drm_encoder.h> +#define XRES_MIN 32 +#define YRES_MIN 32 + +#define XRES_DEF 1024 +#define YRES_DEF 768 + +#define XRES_MAX 8192 +#define YRES_MAX 8192 + static const u32 vkms_formats[] = { DRM_FORMAT_XRGB8888, }; diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c index 48143eac3c12e..a7c0ec9b643f1 100644 --- a/drivers/gpu/drm/vkms/vkms_output.c +++ b/drivers/gpu/drm/vkms/vkms_output.c @@ -8,6 +8,7 @@ #include "vkms_drv.h" #include <drm/drm_crtc_helper.h> +#include <drm/drm_atomic_helper.h> static void vkms_connector_destroy(struct drm_connector *connector) { @@ -18,12 +19,29 @@ static void vkms_connector_destroy(struct drm_connector *connector) static const struct drm_connector_funcs vkms_connector_funcs = { .fill_modes = drm_helper_probe_single_connector_modes, .destroy = vkms_connector_destroy, + .reset = drm_atomic_helper_connector_reset, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; static const struct drm_encoder_funcs vkms_encoder_funcs = { .destroy = drm_encoder_cleanup, }; +static int vkms_conn_get_modes(struct drm_connector *connector) +{ + int count; + + count = drm_add_modes_noedid(connector, XRES_MAX, YRES_MAX); + drm_set_preferred_mode(connector, XRES_DEF, YRES_DEF); + + return count; +} + +static const struct drm_connector_helper_funcs vkms_conn_helper_funcs = { + .get_modes = vkms_conn_get_modes, +}; + int vkms_output_init(struct vkms_device *vkmsdev) { struct vkms_output *output = &vkmsdev->output; @@ -49,6 +67,8 @@ int vkms_output_init(struct vkms_device *vkmsdev) goto err_connector; } + drm_connector_helper_add(connector, &vkms_conn_helper_funcs); + ret = drm_connector_register(connector); if (ret) { DRM_ERROR("Failed to register connector\n"); -- GitLab From 3a0709928b172a4123a76078f70e0a706265690c Mon Sep 17 00:00:00 2001 From: Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com> Date: Wed, 11 Jul 2018 23:02:26 -0300 Subject: [PATCH 1024/1506] drm/vkms: Add vblank events simulated by hrtimers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds regular vblank events simulated through hrtimers, which is a feature required by VKMS to mimic real hardware. Additionally, all the vblank event send after pageflip is kept in the atomic_flush function. Changes since V1: - Compute the vblank timer interval per interruption Ville Syrjälä and Daniel Vetter: - Removes hardcoded vblank interval to get it from user space Changes since V2: Chris Wilson - Removes unnecessary algorithm to compute the next period Daniel Vetter: - Uses drm_calc_timestamping_constants to get the vblank interval instead of calculating it manually - Adds disable_vblank helper that turns of crtc - Simplifies implementation by using drm_crtc_arm_vblank_event - Replaces the code in atomic_begin to atomic_flush - Removes unnecessary field in vkms_output Changes since V3: Daniel Vetter: - Squash "drm/vkms: Add atomic helpers functions" into the commit that handling vblank events simulated by hrtimers Signed-off-by: Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/7709bba40782ec06332d57fff337797b272581fc.1531359228.git.rodrigosiqueiramelo@gmail.com --- drivers/gpu/drm/vkms/vkms_crtc.c | 95 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/vkms/vkms_drv.c | 9 +++ drivers/gpu/drm/vkms/vkms_drv.h | 15 +++++ 3 files changed, 119 insertions(+) diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c b/drivers/gpu/drm/vkms/vkms_crtc.c index bf76cd39ece79..875fca662ac0c 100644 --- a/drivers/gpu/drm/vkms/vkms_crtc.c +++ b/drivers/gpu/drm/vkms/vkms_crtc.c @@ -10,6 +10,60 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc_helper.h> +static enum hrtimer_restart vkms_vblank_simulate(struct hrtimer *timer) +{ + struct vkms_output *output = container_of(timer, struct vkms_output, + vblank_hrtimer); + struct drm_crtc *crtc = &output->crtc; + int ret_overrun; + bool ret; + + ret = drm_crtc_handle_vblank(crtc); + if (!ret) + DRM_ERROR("vkms failure on handling vblank"); + + ret_overrun = hrtimer_forward_now(&output->vblank_hrtimer, + output->period_ns); + + return HRTIMER_RESTART; +} + +static int vkms_enable_vblank(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + unsigned int pipe = drm_crtc_index(crtc); + struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; + struct vkms_output *out = drm_crtc_to_vkms_output(crtc); + + drm_calc_timestamping_constants(crtc, &crtc->mode); + + hrtimer_init(&out->vblank_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + out->vblank_hrtimer.function = &vkms_vblank_simulate; + out->period_ns = ktime_set(0, vblank->framedur_ns); + hrtimer_start(&out->vblank_hrtimer, out->period_ns, HRTIMER_MODE_REL); + + return 0; +} + +static void vkms_disable_vblank(struct drm_crtc *crtc) +{ + struct vkms_output *out = drm_crtc_to_vkms_output(crtc); + + hrtimer_cancel(&out->vblank_hrtimer); +} + +bool vkms_get_vblank_timestamp(struct drm_device *dev, unsigned int pipe, + int *max_error, ktime_t *vblank_time, + bool in_vblank_irq) +{ + struct vkms_device *vkmsdev = drm_device_to_vkms_device(dev); + struct vkms_output *output = &vkmsdev->output; + + *vblank_time = output->vblank_hrtimer.node.expires; + + return true; +} + static const struct drm_crtc_funcs vkms_crtc_funcs = { .set_config = drm_atomic_helper_set_config, .destroy = drm_crtc_cleanup, @@ -17,6 +71,45 @@ static const struct drm_crtc_funcs vkms_crtc_funcs = { .reset = drm_atomic_helper_crtc_reset, .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, + .enable_vblank = vkms_enable_vblank, + .disable_vblank = vkms_disable_vblank, +}; + +static void vkms_crtc_atomic_enable(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) +{ + drm_crtc_vblank_on(crtc); +} + +static void vkms_crtc_atomic_disable(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) +{ + drm_crtc_vblank_off(crtc); +} + +static void vkms_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) +{ + unsigned long flags; + + if (crtc->state->event) { + spin_lock_irqsave(&crtc->dev->event_lock, flags); + + if (drm_crtc_vblank_get(crtc) != 0) + drm_crtc_send_vblank_event(crtc, crtc->state->event); + else + drm_crtc_arm_vblank_event(crtc, crtc->state->event); + + spin_unlock_irqrestore(&crtc->dev->event_lock, flags); + + crtc->state->event = NULL; + } +} + +static const struct drm_crtc_helper_funcs vkms_crtc_helper_funcs = { + .atomic_flush = vkms_crtc_atomic_flush, + .atomic_enable = vkms_crtc_atomic_enable, + .atomic_disable = vkms_crtc_atomic_disable, }; int vkms_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, @@ -31,5 +124,7 @@ int vkms_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, return ret; } + drm_crtc_helper_add(crtc, &vkms_crtc_helper_funcs); + return ret; } diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c index 8236932355454..a1448fb568933 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.c +++ b/drivers/gpu/drm/vkms/vkms_drv.c @@ -54,6 +54,7 @@ static struct drm_driver vkms_driver = { .dumb_map_offset = vkms_dumb_map, .gem_vm_ops = &vkms_gem_vm_ops, .gem_free_object_unlocked = vkms_gem_free_object, + .get_vblank_timestamp = vkms_get_vblank_timestamp, .name = DRIVER_NAME, .desc = DRIVER_DESC, @@ -100,6 +101,14 @@ static int __init vkms_init(void) goto out_fini; } + vkms_device->drm.irq_enabled = true; + + ret = drm_vblank_init(&vkms_device->drm, 1); + if (ret) { + DRM_ERROR("Failed to vblank\n"); + goto out_fini; + } + ret = vkms_modeset_init(vkms_device); if (ret) goto out_unregister; diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h index 57d7367fd8144..07be29f2dc441 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.h +++ b/drivers/gpu/drm/vkms/vkms_drv.h @@ -5,6 +5,7 @@ #include <drm/drm.h> #include <drm/drm_gem.h> #include <drm/drm_encoder.h> +#include <linux/hrtimer.h> #define XRES_MIN 32 #define YRES_MIN 32 @@ -23,6 +24,9 @@ struct vkms_output { struct drm_crtc crtc; struct drm_encoder encoder; struct drm_connector connector; + struct hrtimer vblank_hrtimer; + ktime_t period_ns; + struct drm_pending_vblank_event *event; }; struct vkms_device { @@ -37,9 +41,20 @@ struct vkms_gem_object { struct page **pages; }; +#define drm_crtc_to_vkms_output(target) \ + container_of(target, struct vkms_output, crtc) + +#define drm_device_to_vkms_device(target) \ + container_of(target, struct vkms_device, drm) + +/* CRTC */ int vkms_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, struct drm_plane *primary, struct drm_plane *cursor); +bool vkms_get_vblank_timestamp(struct drm_device *dev, unsigned int pipe, + int *max_error, ktime_t *vblank_time, + bool in_vblank_irq); + int vkms_output_init(struct vkms_device *vkmsdev); struct drm_plane *vkms_plane_init(struct vkms_device *vkmsdev); -- GitLab From c089af18b2bdc859f0c923bc6c026d96532797b4 Mon Sep 17 00:00:00 2001 From: Wei Yongjun <weiyongjun1@huawei.com> Date: Wed, 11 Jul 2018 13:22:47 +0000 Subject: [PATCH 1025/1506] drm/sun4i: DW HDMI: Make symbol sun8i_dw_hdmi_pltfm_driver static Fixes the following sparse warning: drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c:228:24: warning: symbol 'sun8i_dw_hdmi_pltfm_driver' was not declared. Should it be static? Signed-off-by: Wei Yongjun <weiyongjun1@huawei.com> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/1531315367-190647-1-git-send-email-weiyongjun1@huawei.com --- drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c index 21dc9ebad0b43..4cbe744e15a9a 100644 --- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c +++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c @@ -220,7 +220,7 @@ static const struct of_device_id sun8i_dw_hdmi_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, sun8i_dw_hdmi_dt_ids); -struct platform_driver sun8i_dw_hdmi_pltfm_driver = { +static struct platform_driver sun8i_dw_hdmi_pltfm_driver = { .probe = sun8i_dw_hdmi_probe, .remove = sun8i_dw_hdmi_remove, .driver = { -- GitLab From 7da9b2e47fefb419a21e1c4c5a0682846b41b4a0 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec <jernej.skrabec@siol.net> Date: Wed, 11 Jul 2018 13:27:06 +0200 Subject: [PATCH 1026/1506] drm/sun4i: mixer: Read id from DT Currently, TCON supports 2 ways to match TCON with engine (mixer in this case). Old way is to just traverse of graph backwards and compare node pointer. New way is to match TCON and engine by their respective ids. All SoCs with DE2 enabled till now used the old way, which means mixer id was never used and thus never implemented. However, for R40, only the new way will be used. To prepare for that, implement mixer id fetching from DT. Reviewed-by: Chen-Yu Tsai <wens@csie.org> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180711112706.30222-1-jernej.skrabec@siol.net --- drivers/gpu/drm/sun4i/sun8i_mixer.c | 49 +++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c index aa81b9838ae83..da34fc394902a 100644 --- a/drivers/gpu/drm/sun4i/sun8i_mixer.c +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c @@ -22,6 +22,7 @@ #include <linux/component.h> #include <linux/dma-mapping.h> #include <linux/of_device.h> +#include <linux/of_graph.h> #include <linux/reset.h> #include "sun4i_drv.h" @@ -322,6 +323,42 @@ static struct regmap_config sun8i_mixer_regmap_config = { .max_register = 0xbfffc, /* guessed */ }; +static int sun8i_mixer_of_get_id(struct device_node *node) +{ + struct device_node *port, *ep; + int ret = -EINVAL; + + /* output is port 1 */ + port = of_graph_get_port_by_id(node, 1); + if (!port) + return -EINVAL; + + /* try to find downstream endpoint */ + for_each_available_child_of_node(port, ep) { + struct device_node *remote; + u32 reg; + + remote = of_graph_get_remote_endpoint(ep); + if (!remote) + continue; + + ret = of_property_read_u32(remote, "reg", ®); + if (!ret) { + of_node_put(remote); + of_node_put(ep); + of_node_put(port); + + return reg; + } + + of_node_put(remote); + } + + of_node_put(port); + + return ret; +} + static int sun8i_mixer_bind(struct device *dev, struct device *master, void *data) { @@ -353,8 +390,16 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master, dev_set_drvdata(dev, mixer); mixer->engine.ops = &sun8i_engine_ops; mixer->engine.node = dev->of_node; - /* The ID of the mixer currently doesn't matter */ - mixer->engine.id = -1; + + /* + * While this function can fail, we shouldn't do anything + * if this happens. Some early DE2 DT entries don't provide + * mixer id but work nevertheless because matching between + * TCON and mixer is done by comparing node pointers (old + * way) instead comparing ids. If this function fails and + * id is needed, it will fail during id matching anyway. + */ + mixer->engine.id = sun8i_mixer_of_get_id(dev->of_node); mixer->cfg = of_device_get_match_data(dev); if (!mixer->cfg) -- GitLab From 58d4d29823d9a6c4593c48a1a24e6a9dcec8e3ff Mon Sep 17 00:00:00 2001 From: Arnd Bergmann <arnd@arndb.de> Date: Wed, 11 Jul 2018 16:43:10 +0200 Subject: [PATCH 1027/1506] drm/sun4i: fix build failure with CONFIG_DRM_SUN8I_MIXER=m Having DRM_SUN4I built-in but DRM_SUN8I_MIXER as a loadable module results in a link error, as we try to access a symbol from the sun8i_tcon_top.ko module: ERROR: "sun8i_tcon_top_of_table" [drivers/gpu/drm/sun4i/sun8i-drm-hdmi.ko] undefined! ERROR: "sun8i_tcon_top_of_table" [drivers/gpu/drm/sun4i/sun4i-drm.ko] undefined! This solves the problem by adding a silent symbol for the tcon_top module, building it as a separate module in exactly the cases that we need it, but in a way that it is reachable by the other modules. Fixes: 57e23de02f48 ("drm/sun4i: DW HDMI: Expand algorithm for possible crtcs") Fixes: ef0cf6441fbb ("drm/sun4i: Add support for traversing graph with TCON TOP") Signed-off-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180711144403.1022829-1-arnd@arndb.de --- drivers/gpu/drm/sun4i/Kconfig | 7 +++++++ drivers/gpu/drm/sun4i/Makefile | 3 ++- drivers/gpu/drm/sun4i/sun4i_drv.c | 3 ++- drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c | 3 ++- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/sun4i/Kconfig b/drivers/gpu/drm/sun4i/Kconfig index 156a865c3e6d0..c2c042287c19c 100644 --- a/drivers/gpu/drm/sun4i/Kconfig +++ b/drivers/gpu/drm/sun4i/Kconfig @@ -68,4 +68,11 @@ config DRM_SUN8I_MIXER graphics mixture and feed graphics to TCON, If M is selected the module will be called sun8i-mixer. +config DRM_SUN8I_TCON_TOP + tristate + default DRM_SUN4I if DRM_SUN8I_MIXER!=n + help + TCON TOP is responsible for configuring display pipeline for + HTMI, TVE and LCD. + endif diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile index 14f420f1d4ae9..b04ea0f3da75a 100644 --- a/drivers/gpu/drm/sun4i/Makefile +++ b/drivers/gpu/drm/sun4i/Makefile @@ -36,4 +36,5 @@ obj-$(CONFIG_DRM_SUN4I_BACKEND) += sun4i-backend.o sun4i-frontend.o obj-$(CONFIG_DRM_SUN4I_HDMI) += sun4i-drm-hdmi.o obj-$(CONFIG_DRM_SUN6I_DSI) += sun6i-dsi.o obj-$(CONFIG_DRM_SUN8I_DW_HDMI) += sun8i-drm-hdmi.o -obj-$(CONFIG_DRM_SUN8I_MIXER) += sun8i-mixer.o sun8i_tcon_top.o +obj-$(CONFIG_DRM_SUN8I_MIXER) += sun8i-mixer.o +obj-$(CONFIG_DRM_SUN8I_TCON_TOP) += sun8i_tcon_top.o diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c index a15feb8073938..03ffbcc98dd07 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.c +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c @@ -216,7 +216,8 @@ static bool sun4i_drv_node_is_tcon_with_ch0(struct device_node *node) static bool sun4i_drv_node_is_tcon_top(struct device_node *node) { - return !!of_match_node(sun8i_tcon_top_of_table, node); + return IS_ENABLED(CONFIG_DRM_SUN8I_TCON_TOP) && + !!of_match_node(sun8i_tcon_top_of_table, node); } static int compare_of(struct device *dev, void *data) diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c index 4cbe744e15a9a..31875b636434a 100644 --- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c +++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c @@ -44,7 +44,8 @@ sun8i_dw_hdmi_mode_valid(struct drm_connector *connector, static bool sun8i_dw_hdmi_node_is_tcon_top(struct device_node *node) { - return !!of_match_node(sun8i_tcon_top_of_table, node); + return IS_ENABLED(CONFIG_DRM_SUN8I_TCON_TOP) && + !!of_match_node(sun8i_tcon_top_of_table, node); } static u32 sun8i_dw_hdmi_find_possible_crtcs(struct drm_device *drm, -- GitLab From d6b4ea866b8117c1c4a048e2e2dadf0c83776a84 Mon Sep 17 00:00:00 2001 From: Dominique Martinet <asmadeus@codewreck.org> Date: Thu, 12 Jul 2018 08:41:03 +0100 Subject: [PATCH 1028/1506] drm/i915/tv: fix strncpy truncation warning Change it to use strlcpy instead Signed-off-by: Dominique Martinet <asmadeus@codewreck.org> Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20180712074103.21571-1-chris@chris-wilson.co.uk Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> --- drivers/gpu/drm/i915/intel_tv.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 24dc368fdaa1d..b5b04cb892e94 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1347,8 +1347,7 @@ intel_tv_get_modes(struct drm_connector *connector) mode_ptr = drm_mode_create(connector->dev); if (!mode_ptr) continue; - strncpy(mode_ptr->name, input->name, DRM_DISPLAY_MODE_LEN); - mode_ptr->name[DRM_DISPLAY_MODE_LEN - 1] = '\0'; + strlcpy(mode_ptr->name, input->name, DRM_DISPLAY_MODE_LEN); mode_ptr->hdisplay = hactive_s; mode_ptr->hsync_start = hactive_s + 1; -- GitLab From 818fed4f25bbfa729096d2adcdc779c52c932fa7 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 12 Jul 2018 11:54:54 +0100 Subject: [PATCH 1029/1506] drm/i915: Silence warning for no vlv powercontext Along a module load error path, we may try to cleanup the powercontext even before we have allocated it. Reorganising GT powermanagement is an on going process, so for simplicity handle it. [ 522.733832] WARN_ON(!dev_priv->vlv_pctx) [ 522.733986] WARNING: CPU: 1 PID: 3856 at drivers/gpu/drm/i915/intel_pm.c:7350 intel_cleanup_gt_powersave+0x5f/0x70 [i915] [ 522.733991] Modules linked in: i915(+) vgem snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_codec_generic btusb btrtl btbcm btintel intel_powerclamp coretemp crct10dif_pclmul crc32_pclmul bluetooth snd_hda_codec ghash_clmulni_intel snd_hwdep snd_hda_core ecdh_generic lpc_ich r8169 snd_pcm mii i2c_hid prime_numbers [last unloaded: i915] [ 522.734105] CPU: 1 PID: 3856 Comm: drv_module_relo Tainted: G U 4.18.0-rc4-CI-CI_DRM_4474+ #1 [ 522.734110] Hardware name: \xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff \xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff/DN2820FYK, BIOS FYBYT10H.86A.0059.2017.0607.2130 06/07/2017 [ 522.734193] RIP: 0010:intel_cleanup_gt_powersave+0x5f/0x70 [i915] [ 522.734197] Code: 00 74 0d 48 c7 83 68 a6 00 00 00 00 00 00 eb c8 e8 36 6f 37 e1 eb ec 48 c7 c6 c5 7a 3d a0 48 c7 c7 b5 78 3d a0 e8 71 04 e0 e0 <0f> 0b eb aa 0f 1f 00 66 2e 0f 1f 84 00 00 00 00 00 f3 c3 0f 1f 40 [ 522.734445] RSP: 0018:ffffc900004f3af0 EFLAGS: 00010282 [ 522.734453] RAX: 0000000000000000 RBX: ffff880106360000 RCX: 0000000000000001 [ 522.734458] RDX: 0000000080000001 RSI: ffffffff820c65c4 RDI: 00000000ffffffff [ 522.734463] RBP: ffff880106360000 R08: 000000009f79baee R09: 0000000000000000 [ 522.734467] R10: 0000000000000000 R11: 0000000000000000 R12: ffff88013b3133f8 [ 522.734472] R13: 00000000ffffffed R14: ffff880106360d58 R15: ffff88013b3133f8 [ 522.734477] FS: 00007f43f70af980(0000) GS:ffff88013fd00000(0000) knlGS:0000000000000000 [ 522.734481] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 522.734486] CR2: 000055a13a787580 CR3: 00000001325e6000 CR4: 00000000001006e0 [ 522.734490] Call Trace: [ 522.734595] intel_modeset_cleanup+0xcf/0x140 [i915] [ 522.734682] i915_driver_load+0xc85/0x10a0 [i915] [ 522.734694] ? _raw_spin_unlock_irqrestore+0x4c/0x60 [ 522.734703] ? trace_hardirqs_on_caller+0xe0/0x1b0 [ 522.734790] i915_pci_probe+0x29/0x90 [i915] [ 522.734801] pci_device_probe+0xa1/0x130 [ 522.734813] driver_probe_device+0x306/0x480 [ 522.734824] __driver_attach+0xdb/0x100 [ 522.734830] ? driver_probe_device+0x480/0x480 [ 522.734836] ? driver_probe_device+0x480/0x480 [ 522.734844] bus_for_each_dev+0x74/0xc0 [ 522.734855] bus_add_driver+0x15f/0x250 [ 522.734863] ? 0xffffffffa0793000 [ 522.734870] driver_register+0x56/0xe0 [ 522.734877] ? 0xffffffffa0793000 [ 522.734883] do_one_initcall+0x58/0x370 [ 522.734893] ? do_init_module+0x1d/0x1ea [ 522.734900] ? rcu_read_lock_sched_held+0x6f/0x80 [ 522.734906] ? kmem_cache_alloc_trace+0x282/0x2e0 [ 522.734918] do_init_module+0x56/0x1ea [ 522.734927] load_module+0x2435/0x2b20 [ 522.734965] ? __se_sys_finit_module+0xd3/0xf0 [ 522.734972] __se_sys_finit_module+0xd3/0xf0 [ 522.734995] do_syscall_64+0x55/0x190 [ 522.735003] entry_SYSCALL_64_after_hwframe+0x49/0xbe [ 522.735009] RIP: 0033:0x7f43f675d839 [ 522.735014] Code: 00 f3 c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 1f f6 2c 00 f7 d8 64 89 01 48 [ 522.735260] RSP: 002b:00007ffe69384238 EFLAGS: 00000246 ORIG_RAX: 0000000000000139 [ 522.735269] RAX: ffffffffffffffda RBX: 000056100e387090 RCX: 00007f43f675d839 [ 522.735273] RDX: 0000000000000000 RSI: 000056100e37bff0 RDI: 0000000000000003 [ 522.735278] RBP: 000056100e37bff0 R08: 0000000000000000 R09: 0000000000000000 [ 522.735282] R10: 0000000000000003 R11: 0000000000000246 R12: 0000000000000000 [ 522.735286] R13: 000056100e37c890 R14: 0000000000000020 R15: 0000000000000027 [ 522.735309] irq event stamp: 1389594 [ 522.735316] hardirqs last enabled at (1389593): [<ffffffff810f896c>] console_unlock+0x3fc/0x600 [ 522.735323] hardirqs last disabled at (1389594): [<ffffffff81a0111c>] error_entry+0x7c/0x100 [ 522.735329] softirqs last enabled at (1389356): [<ffffffff81c0034f>] __do_softirq+0x34f/0x505 [ 522.735336] softirqs last disabled at (1389335): [<ffffffff8108c7b9>] irq_exit+0xa9/0xc0 [ 522.735432] WARNING: CPU: 1 PID: 3856 at drivers/gpu/drm/i915/intel_pm.c:7350 intel_cleanup_gt_powersave+0x5f/0x70 [i915] Testcase: igt/drv_module_reload/basic-reload-inject Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Matthew Auld <matthew.auld@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180712105454.16091-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_pm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 53aaaa3e6886d..7312ecb734151 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -7347,11 +7347,11 @@ static void valleyview_setup_pctx(struct drm_i915_private *dev_priv) static void valleyview_cleanup_pctx(struct drm_i915_private *dev_priv) { - if (WARN_ON(!dev_priv->vlv_pctx)) - return; + struct drm_i915_gem_object *pctx; - i915_gem_object_put(dev_priv->vlv_pctx); - dev_priv->vlv_pctx = NULL; + pctx = fetch_and_zero(&dev_priv->vlv_pctx); + if (pctx) + i915_gem_object_put(pctx); } static void vlv_init_gpll_ref_freq(struct drm_i915_private *dev_priv) -- GitLab From 5bfbeacf1983de58782b3aeb59b87d216091751c Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 12 Jul 2018 11:58:30 +0100 Subject: [PATCH 1030/1506] drm/i915/guc: Skip cleaning up the doorbells on error-before-allocate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we fail the module load, we may try and cleanup before we even allocate the GuC clients. KISS in order to try and re-enable drv_module_reload for BAT. Testcase: igt/drv_module_reload/basic-reload-inject Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: MichaÅ‚ Winiarski <michal.winiarski@intel.com> Cc: Michal Wajdeczko <michal.wajdeczko@intel.com> Reviewed-by: MichaÅ‚ Winiarski <michal.winiarski@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180712105830.20390-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_guc_submission.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_guc_submission.c b/drivers/gpu/drm/i915/intel_guc_submission.c index 3952656f4c9a3..cd51be8ff0257 100644 --- a/drivers/gpu/drm/i915/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/intel_guc_submission.c @@ -910,8 +910,12 @@ static void guc_clients_doorbell_fini(struct intel_guc *guc) __update_doorbell_desc(guc->preempt_client, GUC_DOORBELL_INVALID); } - __destroy_doorbell(guc->execbuf_client); - __update_doorbell_desc(guc->execbuf_client, GUC_DOORBELL_INVALID); + + if (guc->execbuf_client) { + __destroy_doorbell(guc->execbuf_client); + __update_doorbell_desc(guc->execbuf_client, + GUC_DOORBELL_INVALID); + } } /** -- GitLab From 60c0a66ee96cbdb22e029da70ec42e249f1996a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Winiarski?= <michal.winiarski@intel.com> Date: Thu, 12 Jul 2018 14:48:10 +0200 Subject: [PATCH 1031/1506] drm/i915: Tidy error handling in i915_gem_init_hw MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's reorder things so that we can do onion teardown rather than double goto. References: b96f6ebfd024 ("drm/i915: Correctly handle error path in i915_gem_init_hw") Signed-off-by: MichaÅ‚ Winiarski <michal.winiarski@intel.com> Cc: Michal Wajdeczko <michal.wajdeczko@intel.com> Cc: Sagar Arun Kamble <sagar.a.kamble@intel.com> Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20180712124810.25241-1-michal.winiarski@intel.com --- drivers/gpu/drm/i915/i915_gem.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 07a92ca61dbfc..ed2be33ec58a3 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5313,13 +5313,17 @@ int i915_gem_init_hw(struct drm_i915_private *dev_priv) ret = __i915_gem_restart_engines(dev_priv); if (ret) goto cleanup_uc; -out: + intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL); - return ret; + + return 0; cleanup_uc: intel_uc_fini_hw(dev_priv); - goto out; +out: + intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL); + + return ret; } static int __intel_engines_record_defaults(struct drm_i915_private *i915) -- GitLab From a63983f26008804e8db12457e429e5fc18841894 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Winiarski?= <michal.winiarski@intel.com> Date: Thu, 12 Jul 2018 12:20:13 +0100 Subject: [PATCH 1032/1506] drm/i915/selftests: Fixup GuC FW negative test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since: 0d4b78b3d2c0 ("drm/i915/guc: Assert we have the doorbell before setting it up") We have asserts in GuC doorbell related functions, which is a good thing. Unfortunately, we were using those to check whether GuC FW is refusing to allocate invalid doorbell - which makes the test fail. Well, it would make the test WARN, except we fumbled cleanup ordering and eat the BUG_ON instead. Let's keep the asserts and use the internal implementation in the test. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=107186 Signed-off-by: MichaÅ‚ Winiarski <michal.winiarski@intel.com> Cc: Chris Wilson <chris@chris-wilson.co.uk> Cc: Michel Thierry <michel.thierry@intel.com> Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20180712112013.3253-1-chris@chris-wilson.co.uk Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> --- drivers/gpu/drm/i915/selftests/intel_guc.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/selftests/intel_guc.c b/drivers/gpu/drm/i915/selftests/intel_guc.c index fb74e2cf8a0a9..407c98fb91705 100644 --- a/drivers/gpu/drm/i915/selftests/intel_guc.c +++ b/drivers/gpu/drm/i915/selftests/intel_guc.c @@ -196,19 +196,23 @@ static int igt_guc_clients(void *args) } unreserve_doorbell(guc->execbuf_client); - err = guc_clients_doorbell_init(guc); + + __create_doorbell(guc->execbuf_client); + err = __guc_allocate_doorbell(guc, guc->execbuf_client->stage_id); if (err != -EIO) { pr_err("unexpected (err = %d)", err); - goto out; + goto out_db; } if (!available_dbs(guc, guc->execbuf_client->priority)) { pr_err("doorbell not available when it should\n"); err = -EIO; - goto out; + goto out_db; } +out_db: /* clean after test */ + __destroy_doorbell(guc->execbuf_client); err = reserve_doorbell(guc->execbuf_client); if (err) { pr_err("failed to reserve back the doorbell back\n"); -- GitLab From 42ac03213b7f102682157c2821e3fd9657ce4eb7 Mon Sep 17 00:00:00 2001 From: Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com> Date: Thu, 12 Jul 2018 10:41:02 -0300 Subject: [PATCH 1033/1506] drm/vkms: Add framebuffer and plane helpers This patch appends the minimum helpers related to framebuffer and plane to make vkms minimally usable. Changes since V1: - None Changes since V2: - Squash "Add plane helper struct" and "Add helper for framebuffer create" Changes since V3: Daniel Vetter: - Remove atomic_check from plane helper Signed-off-by: Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/d37807da7d3b39444b4c9abb149fe3c518d07c61.1531402095.git.rodrigosiqueiramelo@gmail.com --- drivers/gpu/drm/vkms/vkms_drv.c | 3 +++ drivers/gpu/drm/vkms/vkms_plane.c | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c index a1448fb568933..37aa2ef33b213 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.c +++ b/drivers/gpu/drm/vkms/vkms_drv.c @@ -9,6 +9,8 @@ #include <drm/drm_gem.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_fb_helper.h> #include "vkms_drv.h" #define DRIVER_NAME "vkms" @@ -64,6 +66,7 @@ static struct drm_driver vkms_driver = { }; static const struct drm_mode_config_funcs vkms_mode_funcs = { + .fb_create = drm_gem_fb_create, .atomic_check = drm_atomic_helper_check, .atomic_commit = drm_atomic_helper_commit, }; diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_plane.c index 2c25b1d6ab5be..9f75b1e2c1c4b 100644 --- a/drivers/gpu/drm/vkms/vkms_plane.c +++ b/drivers/gpu/drm/vkms/vkms_plane.c @@ -19,6 +19,15 @@ static const struct drm_plane_funcs vkms_plane_funcs = { .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, }; +static void vkms_primary_plane_update(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ +} + +static const struct drm_plane_helper_funcs vkms_primary_helper_funcs = { + .atomic_update = vkms_primary_plane_update, +}; + struct drm_plane *vkms_plane_init(struct vkms_device *vkmsdev) { struct drm_device *dev = &vkmsdev->drm; @@ -42,5 +51,7 @@ struct drm_plane *vkms_plane_init(struct vkms_device *vkmsdev) return ERR_PTR(ret); } + drm_plane_helper_add(plane, &vkms_primary_helper_funcs); + return plane; } -- GitLab From 73675cf6979bb80534641b1814a971eaf9f649b5 Mon Sep 17 00:00:00 2001 From: Ramalingam C <ramalingam.c@intel.com> Date: Thu, 28 Jun 2018 19:04:48 +0530 Subject: [PATCH 1034/1506] drm/i915/gmbus: Increase the Bytes per Rd/Wr Op GMBUS HW supports 511Bytes as Max Bytes per single RD/WR op. Instead of enabling the 511Bytes per RD/WR cycle on legacy platforms for no absolute ROIs, this change allows the max bytes per op upto 511Bytes from Gen9 onwards. v2: No Change. v3: Inline function for max_xfer_size and renaming of the macro.[Jani] v4: Extra brackets removed [ville] Commit msg is modified. v5: Collecting the Reviewed-By received. Cc: Jani Nikula <jani.nikula@intel.com> Cc: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Ramalingam C <ramalingam.c@intel.com> Reviewed-by: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/1530192889-5789-2-git-send-email-ramalingam.c@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_i2c.c | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index b95bab7a3d24a..2da870a8948e7 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3152,6 +3152,7 @@ enum i915_power_well_id { #define GMBUS_CYCLE_STOP (4 << 25) #define GMBUS_BYTE_COUNT_SHIFT 16 #define GMBUS_BYTE_COUNT_MAX 256U +#define GEN9_GMBUS_BYTE_COUNT_MAX 511U #define GMBUS_SLAVE_INDEX_SHIFT 8 #define GMBUS_SLAVE_ADDR_SHIFT 1 #define GMBUS_SLAVE_READ (1 << 0) diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 97606c1be70da..82bb9c33ab1cf 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -361,6 +361,13 @@ gmbus_wait_idle(struct drm_i915_private *dev_priv) return ret; } +static inline +unsigned int gmbus_max_xfer_size(struct drm_i915_private *dev_priv) +{ + return INTEL_GEN(dev_priv) >= 9 ? GEN9_GMBUS_BYTE_COUNT_MAX : + GMBUS_BYTE_COUNT_MAX; +} + static int gmbus_xfer_read_chunk(struct drm_i915_private *dev_priv, unsigned short addr, u8 *buf, unsigned int len, @@ -400,7 +407,7 @@ gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg, int ret; do { - len = min(rx_size, GMBUS_BYTE_COUNT_MAX); + len = min(rx_size, gmbus_max_xfer_size(dev_priv)); ret = gmbus_xfer_read_chunk(dev_priv, msg->addr, buf, len, gmbus1_index); @@ -462,7 +469,7 @@ gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg, int ret; do { - len = min(tx_size, GMBUS_BYTE_COUNT_MAX); + len = min(tx_size, gmbus_max_xfer_size(dev_priv)); ret = gmbus_xfer_write_chunk(dev_priv, msg->addr, buf, len, gmbus1_index); -- GitLab From d5dc0f43f268bf2b6bb61f109a18a652a49c6f4e Mon Sep 17 00:00:00 2001 From: Ramalingam C <ramalingam.c@intel.com> Date: Thu, 28 Jun 2018 19:04:49 +0530 Subject: [PATCH 1035/1506] drm/i915/gmbus: Enable burst read MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Support for Burst read in HW is added for HDCP2.2 compliance requirement. This patch enables the burst read for all the gmbus read of more than 511Bytes, on capable platforms. v2: Extra line is removed. v3: Macro is added for detecting the BURST_READ Support [Jani] Runtime detection of the need for burst_read [Jani] Calculation enhancement. v4: GMBUS0 reg val is passed from caller [ville] Removed a extra var [ville] Extra brackets are removed [ville] Implemented the handling of 512Bytes Burst Read. v5: Burst read max length is fixed at 767Bytes [Ville] v6: Collecting the received reviewed-by. Signed-off-by: Ramalingam C <ramalingam.c@intel.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/1530192889-5789-3-git-send-email-ramalingam.c@intel.com --- drivers/gpu/drm/i915/i915_drv.h | 3 ++ drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_i2c.c | 61 ++++++++++++++++++++++++++------ 3 files changed, 55 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 48b350116cbae..a6c6decd05465 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2560,6 +2560,9 @@ intel_info(const struct drm_i915_private *dev_priv) IS_SKL_GT3(dev_priv) || IS_SKL_GT4(dev_priv)) #define HAS_GMBUS_IRQ(dev_priv) (INTEL_GEN(dev_priv) >= 4) +#define HAS_GMBUS_BURST_READ(dev_priv) (INTEL_GEN(dev_priv) >= 10 || \ + IS_GEMINILAKE(dev_priv) || \ + IS_KABYLAKE(dev_priv)) /* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte * rows, which changed the alignment requirements and fence programming. diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 2da870a8948e7..1f222af0324da 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3123,6 +3123,7 @@ enum i915_power_well_id { #define GMBUS_RATE_400KHZ (2 << 8) /* reserved on Pineview */ #define GMBUS_RATE_1MHZ (3 << 8) /* reserved on Pineview */ #define GMBUS_HOLD_EXT (1 << 7) /* 300ns hold time, rsvd on Pineview */ +#define GMBUS_BYTE_CNT_OVERRIDE (1 << 6) #define GMBUS_PIN_DISABLED 0 #define GMBUS_PIN_SSC 1 #define GMBUS_PIN_VGADDC 2 diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 82bb9c33ab1cf..bef32b7c248e0 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -371,12 +371,29 @@ unsigned int gmbus_max_xfer_size(struct drm_i915_private *dev_priv) static int gmbus_xfer_read_chunk(struct drm_i915_private *dev_priv, unsigned short addr, u8 *buf, unsigned int len, - u32 gmbus1_index) + u32 gmbus0_reg, u32 gmbus1_index) { + unsigned int size = len; + bool burst_read = len > gmbus_max_xfer_size(dev_priv); + bool extra_byte_added = false; + + if (burst_read) { + /* + * As per HW Spec, for 512Bytes need to read extra Byte and + * Ignore the extra byte read. + */ + if (len == 512) { + extra_byte_added = true; + len++; + } + size = len % 256 + 256; + I915_WRITE_FW(GMBUS0, gmbus0_reg | GMBUS_BYTE_CNT_OVERRIDE); + } + I915_WRITE_FW(GMBUS1, gmbus1_index | GMBUS_CYCLE_WAIT | - (len << GMBUS_BYTE_COUNT_SHIFT) | + (size << GMBUS_BYTE_COUNT_SHIFT) | (addr << GMBUS_SLAVE_ADDR_SHIFT) | GMBUS_SLAVE_READ | GMBUS_SW_RDY); while (len) { @@ -389,17 +406,34 @@ gmbus_xfer_read_chunk(struct drm_i915_private *dev_priv, val = I915_READ_FW(GMBUS3); do { + if (extra_byte_added && len == 1) + break; + *buf++ = val & 0xff; val >>= 8; } while (--len && ++loop < 4); + + if (burst_read && len == size - 4) + /* Reset the override bit */ + I915_WRITE_FW(GMBUS0, gmbus0_reg); } return 0; } +/* + * HW spec says that 512Bytes in Burst read need special treatment. + * But it doesn't talk about other multiple of 256Bytes. And couldn't locate + * an I2C slave, which supports such a lengthy burst read too for experiments. + * + * So until things get clarified on HW support, to avoid the burst read length + * in fold of 256Bytes except 512, max burst read length is fixed at 767Bytes. + */ +#define INTEL_GMBUS_BURST_READ_MAX_LEN 767U + static int gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg, - u32 gmbus1_index) + u32 gmbus0_reg, u32 gmbus1_index) { u8 *buf = msg->buf; unsigned int rx_size = msg->len; @@ -407,10 +441,13 @@ gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg, int ret; do { - len = min(rx_size, gmbus_max_xfer_size(dev_priv)); + if (HAS_GMBUS_BURST_READ(dev_priv)) + len = min(rx_size, INTEL_GMBUS_BURST_READ_MAX_LEN); + else + len = min(rx_size, gmbus_max_xfer_size(dev_priv)); - ret = gmbus_xfer_read_chunk(dev_priv, msg->addr, - buf, len, gmbus1_index); + ret = gmbus_xfer_read_chunk(dev_priv, msg->addr, buf, len, + gmbus0_reg, gmbus1_index); if (ret) return ret; @@ -498,7 +535,8 @@ gmbus_is_index_xfer(struct i2c_msg *msgs, int i, int num) } static int -gmbus_index_xfer(struct drm_i915_private *dev_priv, struct i2c_msg *msgs) +gmbus_index_xfer(struct drm_i915_private *dev_priv, struct i2c_msg *msgs, + u32 gmbus0_reg) { u32 gmbus1_index = 0; u32 gmbus5 = 0; @@ -516,7 +554,8 @@ gmbus_index_xfer(struct drm_i915_private *dev_priv, struct i2c_msg *msgs) I915_WRITE_FW(GMBUS5, gmbus5); if (msgs[1].flags & I2C_M_RD) - ret = gmbus_xfer_read(dev_priv, &msgs[1], gmbus1_index); + ret = gmbus_xfer_read(dev_priv, &msgs[1], gmbus0_reg, + gmbus1_index); else ret = gmbus_xfer_write(dev_priv, &msgs[1], gmbus1_index); @@ -551,10 +590,12 @@ do_gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num, for (; i < num; i += inc) { inc = 1; if (gmbus_is_index_xfer(msgs, i, num)) { - ret = gmbus_index_xfer(dev_priv, &msgs[i]); + ret = gmbus_index_xfer(dev_priv, &msgs[i], + gmbus0_source | bus->reg0); inc = 2; /* an index transmission is two msgs */ } else if (msgs[i].flags & I2C_M_RD) { - ret = gmbus_xfer_read(dev_priv, &msgs[i], 0); + ret = gmbus_xfer_read(dev_priv, &msgs[i], + gmbus0_source | bus->reg0, 0); } else { ret = gmbus_xfer_write(dev_priv, &msgs[i], 0); } -- GitLab From f88c5ee77496886071e76b5b9fdfee7158f6d079 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec <jernej.skrabec@siol.net> Date: Fri, 6 Jul 2018 18:47:32 +0200 Subject: [PATCH 1036/1506] drm/sun4i: Implement zpos for DE2 Initial implementation of DE2 planes only supported fixed zpos. Expand implementation with configurable zpos property. Implementation background: Channel in DE2 driver represents one DRM plane, whereas pipe is just mapped channel to known Z position. Pipe 0 will always be at the bottom, pipe 1 just above pipe 0 and so on. If, for example, channel 1 is mapped at pipe 0 and channel 0 at pipe 1, whatever is on channel 0 will appear on top. Before this commit, channel id was used for addressing channel related registers (prefixed with SUN8I_MIXER_CHAN_UI_ or SUN8I_MIXER_CHAN_VI_) and pipe registers (prefixed with SUN8I_MIXER_BLEND_). Additionally, register SUN8I_MIXER_BLEND_ROUTE, which takes care for mapping channels to pipes had fixed value. It mapped channel 0 to pipe 0, 1 to 1 and so on. Consequence of all that was fixed Z order of planes. With this commit, pipe registers are using zpos property as index and channel related registers still use channel id as index. Pipe mapping register is now set dynamically too and pipe enable register is rebuild every time to make sure only active pipes are enabled. Testing was done to confirm that there is no issues if bottom plane contains pixels with alpha value < 0xff and if it doesn't whole screen. Tested-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180706164732.24166-1-jernej.skrabec@siol.net --- drivers/gpu/drm/sun4i/sun8i_mixer.c | 15 +++++++-- drivers/gpu/drm/sun4i/sun8i_mixer.h | 4 +++ drivers/gpu/drm/sun4i/sun8i_ui_layer.c | 45 ++++++++++++++++---------- drivers/gpu/drm/sun4i/sun8i_vi_layer.c | 45 ++++++++++++++++---------- 4 files changed, 72 insertions(+), 37 deletions(-) diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c index da34fc394902a..f76a5576c0e62 100644 --- a/drivers/gpu/drm/sun4i/sun8i_mixer.c +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c @@ -261,6 +261,17 @@ const struct de2_fmt_info *sun8i_mixer_format_info(u32 format) return NULL; } +static void sun8i_mixer_atomic_begin(struct sunxi_engine *engine, + struct drm_crtc_state *old_state) +{ + /* + * Disable all pipes at the beginning. They will be enabled + * again if needed in plane update callback. + */ + regmap_update_bits(engine->regs, SUN8I_MIXER_BLEND_PIPE_CTL, + SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK, 0); +} + static void sun8i_mixer_commit(struct sunxi_engine *engine) { DRM_DEBUG_DRIVER("Committing changes\n"); @@ -312,6 +323,7 @@ static struct drm_plane **sun8i_layers_init(struct drm_device *drm, } static const struct sunxi_engine_ops sun8i_engine_ops = { + .atomic_begin = sun8i_mixer_atomic_begin, .commit = sun8i_mixer_commit, .layers_init = sun8i_layers_init, }; @@ -477,9 +489,6 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master, regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ATTR_FCOLOR(0), SUN8I_MIXER_BLEND_COLOR_BLACK); - /* Fixed zpos for now */ - regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ROUTE, 0x43210); - plane_cnt = mixer->cfg->vi_num + mixer->cfg->ui_num; for (i = 0; i < plane_cnt; i++) regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_MODE(i), diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.h b/drivers/gpu/drm/sun4i/sun8i_mixer.h index f34e70c42adf4..406c42e752d75 100644 --- a/drivers/gpu/drm/sun4i/sun8i_mixer.h +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.h @@ -44,6 +44,7 @@ #define SUN8I_MIXER_BLEND_CK_MIN(x) (0x10e0 + 0x04 * (x)) #define SUN8I_MIXER_BLEND_OUTCTL 0x10fc +#define SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK GENMASK(12, 8) #define SUN8I_MIXER_BLEND_PIPE_CTL_EN(pipe) BIT(8 + pipe) #define SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(pipe) BIT(pipe) /* colors are always in AARRGGBB format */ @@ -51,6 +52,9 @@ /* The following numbers are some still unknown magic numbers */ #define SUN8I_MIXER_BLEND_MODE_DEF 0x03010301 +#define SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(n) (0xf << ((n) << 2)) +#define SUN8I_MIXER_BLEND_ROUTE_PIPE_SHIFT(n) ((n) << 2) + #define SUN8I_MIXER_BLEND_OUTCTL_INTERLACED BIT(1) #define SUN8I_MIXER_FBFMT_ARGB8888 0 diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c index 9a540330cb798..518e1921f47e6 100644 --- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c +++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c @@ -27,7 +27,7 @@ #include "sun8i_ui_scaler.h" static void sun8i_ui_layer_enable(struct sun8i_mixer *mixer, int channel, - int overlay, bool enable) + int overlay, bool enable, unsigned int zpos) { u32 val; @@ -43,18 +43,24 @@ static void sun8i_ui_layer_enable(struct sun8i_mixer *mixer, int channel, SUN8I_MIXER_CHAN_UI_LAYER_ATTR(channel, overlay), SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN, val); - if (enable) - val = SUN8I_MIXER_BLEND_PIPE_CTL_EN(channel); - else - val = 0; + if (enable) { + val = SUN8I_MIXER_BLEND_PIPE_CTL_EN(zpos); - regmap_update_bits(mixer->engine.regs, - SUN8I_MIXER_BLEND_PIPE_CTL, - SUN8I_MIXER_BLEND_PIPE_CTL_EN(channel), val); + regmap_update_bits(mixer->engine.regs, + SUN8I_MIXER_BLEND_PIPE_CTL, val, val); + + val = channel << SUN8I_MIXER_BLEND_ROUTE_PIPE_SHIFT(zpos); + + regmap_update_bits(mixer->engine.regs, + SUN8I_MIXER_BLEND_ROUTE, + SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(zpos), + val); + } } static int sun8i_ui_layer_update_coord(struct sun8i_mixer *mixer, int channel, - int overlay, struct drm_plane *plane) + int overlay, struct drm_plane *plane, + unsigned int zpos) { struct drm_plane_state *state = plane->state; u32 src_w, src_h, dst_w, dst_h; @@ -137,10 +143,10 @@ static int sun8i_ui_layer_update_coord(struct sun8i_mixer *mixer, int channel, state->dst.x1, state->dst.y1); DRM_DEBUG_DRIVER("Layer destination size W: %d H: %d\n", dst_w, dst_h); regmap_write(mixer->engine.regs, - SUN8I_MIXER_BLEND_ATTR_COORD(channel), + SUN8I_MIXER_BLEND_ATTR_COORD(zpos), SUN8I_MIXER_COORD(state->dst.x1, state->dst.y1)); regmap_write(mixer->engine.regs, - SUN8I_MIXER_BLEND_ATTR_INSIZE(channel), + SUN8I_MIXER_BLEND_ATTR_INSIZE(zpos), outsize); return 0; @@ -238,28 +244,30 @@ static void sun8i_ui_layer_atomic_disable(struct drm_plane *plane, struct sun8i_ui_layer *layer = plane_to_sun8i_ui_layer(plane); struct sun8i_mixer *mixer = layer->mixer; - sun8i_ui_layer_enable(mixer, layer->channel, layer->overlay, false); + sun8i_ui_layer_enable(mixer, layer->channel, layer->overlay, false, 0); } static void sun8i_ui_layer_atomic_update(struct drm_plane *plane, struct drm_plane_state *old_state) { struct sun8i_ui_layer *layer = plane_to_sun8i_ui_layer(plane); + unsigned int zpos = plane->state->normalized_zpos; struct sun8i_mixer *mixer = layer->mixer; if (!plane->state->visible) { sun8i_ui_layer_enable(mixer, layer->channel, - layer->overlay, false); + layer->overlay, false, 0); return; } sun8i_ui_layer_update_coord(mixer, layer->channel, - layer->overlay, plane); + layer->overlay, plane, zpos); sun8i_ui_layer_update_formats(mixer, layer->channel, layer->overlay, plane); sun8i_ui_layer_update_buffer(mixer, layer->channel, layer->overlay, plane); - sun8i_ui_layer_enable(mixer, layer->channel, layer->overlay, true); + sun8i_ui_layer_enable(mixer, layer->channel, layer->overlay, + true, zpos); } static struct drm_plane_helper_funcs sun8i_ui_layer_helper_funcs = { @@ -307,6 +315,7 @@ struct sun8i_ui_layer *sun8i_ui_layer_init_one(struct drm_device *drm, enum drm_plane_type type = DRM_PLANE_TYPE_OVERLAY; int channel = mixer->cfg->vi_num + index; struct sun8i_ui_layer *layer; + unsigned int plane_cnt; int ret; layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL); @@ -327,8 +336,10 @@ struct sun8i_ui_layer *sun8i_ui_layer_init_one(struct drm_device *drm, return ERR_PTR(ret); } - /* fixed zpos for now */ - ret = drm_plane_create_zpos_immutable_property(&layer->plane, channel); + plane_cnt = mixer->cfg->ui_num + mixer->cfg->vi_num; + + ret = drm_plane_create_zpos_property(&layer->plane, channel, + 0, plane_cnt - 1); if (ret) { dev_err(drm->dev, "Couldn't add zpos property\n"); return ERR_PTR(ret); diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c index 5877f8ef5895f..17e0d00cfd8a4 100644 --- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c +++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c @@ -21,7 +21,7 @@ #include "sun8i_vi_scaler.h" static void sun8i_vi_layer_enable(struct sun8i_mixer *mixer, int channel, - int overlay, bool enable) + int overlay, bool enable, unsigned int zpos) { u32 val; @@ -37,18 +37,24 @@ static void sun8i_vi_layer_enable(struct sun8i_mixer *mixer, int channel, SUN8I_MIXER_CHAN_VI_LAYER_ATTR(channel, overlay), SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN, val); - if (enable) - val = SUN8I_MIXER_BLEND_PIPE_CTL_EN(channel); - else - val = 0; + if (enable) { + val = SUN8I_MIXER_BLEND_PIPE_CTL_EN(zpos); - regmap_update_bits(mixer->engine.regs, - SUN8I_MIXER_BLEND_PIPE_CTL, - SUN8I_MIXER_BLEND_PIPE_CTL_EN(channel), val); + regmap_update_bits(mixer->engine.regs, + SUN8I_MIXER_BLEND_PIPE_CTL, val, val); + + val = channel << SUN8I_MIXER_BLEND_ROUTE_PIPE_SHIFT(zpos); + + regmap_update_bits(mixer->engine.regs, + SUN8I_MIXER_BLEND_ROUTE, + SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(zpos), + val); + } } static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel, - int overlay, struct drm_plane *plane) + int overlay, struct drm_plane *plane, + unsigned int zpos) { struct drm_plane_state *state = plane->state; const struct drm_format_info *format = state->fb->format; @@ -130,10 +136,10 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel, state->dst.x1, state->dst.y1); DRM_DEBUG_DRIVER("Layer destination size W: %d H: %d\n", dst_w, dst_h); regmap_write(mixer->engine.regs, - SUN8I_MIXER_BLEND_ATTR_COORD(channel), + SUN8I_MIXER_BLEND_ATTR_COORD(zpos), SUN8I_MIXER_COORD(state->dst.x1, state->dst.y1)); regmap_write(mixer->engine.regs, - SUN8I_MIXER_BLEND_ATTR_INSIZE(channel), + SUN8I_MIXER_BLEND_ATTR_INSIZE(zpos), outsize); return 0; @@ -266,28 +272,30 @@ static void sun8i_vi_layer_atomic_disable(struct drm_plane *plane, struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane); struct sun8i_mixer *mixer = layer->mixer; - sun8i_vi_layer_enable(mixer, layer->channel, layer->overlay, false); + sun8i_vi_layer_enable(mixer, layer->channel, layer->overlay, false, 0); } static void sun8i_vi_layer_atomic_update(struct drm_plane *plane, struct drm_plane_state *old_state) { struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane); + unsigned int zpos = plane->state->normalized_zpos; struct sun8i_mixer *mixer = layer->mixer; if (!plane->state->visible) { sun8i_vi_layer_enable(mixer, layer->channel, - layer->overlay, false); + layer->overlay, false, 0); return; } sun8i_vi_layer_update_coord(mixer, layer->channel, - layer->overlay, plane); + layer->overlay, plane, zpos); sun8i_vi_layer_update_formats(mixer, layer->channel, layer->overlay, plane); sun8i_vi_layer_update_buffer(mixer, layer->channel, layer->overlay, plane); - sun8i_vi_layer_enable(mixer, layer->channel, layer->overlay, true); + sun8i_vi_layer_enable(mixer, layer->channel, layer->overlay, + true, zpos); } static struct drm_plane_helper_funcs sun8i_vi_layer_helper_funcs = { @@ -351,6 +359,7 @@ struct sun8i_vi_layer *sun8i_vi_layer_init_one(struct drm_device *drm, int index) { struct sun8i_vi_layer *layer; + unsigned int plane_cnt; int ret; layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL); @@ -368,8 +377,10 @@ struct sun8i_vi_layer *sun8i_vi_layer_init_one(struct drm_device *drm, return ERR_PTR(ret); } - /* fixed zpos for now */ - ret = drm_plane_create_zpos_immutable_property(&layer->plane, index); + plane_cnt = mixer->cfg->ui_num + mixer->cfg->vi_num; + + ret = drm_plane_create_zpos_property(&layer->plane, index, + 0, plane_cnt - 1); if (ret) { dev_err(drm->dev, "Couldn't add zpos property\n"); return ERR_PTR(ret); -- GitLab From b7178ffe7eb86fb9d428801509a5bd54d3ba94da Mon Sep 17 00:00:00 2001 From: Maxime Ripard <maxime.ripard@bootlin.com> Date: Thu, 12 Jul 2018 10:08:18 +0200 Subject: [PATCH 1037/1506] drm/sun4i: tcon-top: Fix return type warning When commit af11942ee44e ("drm/sun4i: tcon-top: Cleanup clock handling") was merged, the error handling path of the of_property_match_string was changed to take into account the fact that the returned value of that function wasn't an error pointer but an error code. Unfortunately, this introduced a warning since the now returned value is an integer, while the sun8i_tcon_top_register_gate function should return an error pointer. Fix that by calling ERR_PTR. Cc: Jernej Skrabec <jernej.skrabec@siol.net> Cc: Chen-Yu Tsai <wens@csie.org> Fixes: af11942ee44e ("drm/sun4i: tcon-top: Cleanup clock handling") Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Reported-by: kbuild test robot <lkp@intel.com> Reported-by: Stephen Rothwell <sfr@canb.auug.org.au> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180712080818.3571-1-maxime.ripard@bootlin.com --- drivers/gpu/drm/sun4i/sun8i_tcon_top.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/sun4i/sun8i_tcon_top.c b/drivers/gpu/drm/sun4i/sun8i_tcon_top.c index 046f8dd66f90d..55fe398d8290d 100644 --- a/drivers/gpu/drm/sun4i/sun8i_tcon_top.c +++ b/drivers/gpu/drm/sun4i/sun8i_tcon_top.c @@ -99,7 +99,7 @@ static struct clk_hw *sun8i_tcon_top_register_gate(struct device *dev, index = of_property_match_string(dev->of_node, "clock-names", parent); if (index < 0) - return index; + return ERR_PTR(index); parent_name = of_clk_get_parent_name(dev->of_node, index); -- GitLab From 77c56fd3c8cf5adcba9cffcc29ead295211bdae8 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann <arnd@arndb.de> Date: Mon, 9 Jul 2018 17:20:29 +0200 Subject: [PATCH 1038/1506] drm/tinydrm: add backlight dependency for ili9341 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This tinydrm driver fails to link without the backlight support: drivers/gpu/drm/tinydrm/ili9341.o: In function `ili9341_probe': ili9341.c:(.text+0x578): undefined reference to `devm_of_find_backlight' Fixes: 3fa0e8f6f960 ("drm/tinydrm: new driver for ILI9341 display panels") Signed-off-by: Arnd Bergmann <arnd@arndb.de> Acked-by: Noralf Trønnes <noralf@tronnes.org> Signed-off-by: David Lechner <david@lechnology.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180709152106.990066-1-arnd@arndb.de --- drivers/gpu/drm/tinydrm/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/tinydrm/Kconfig b/drivers/gpu/drm/tinydrm/Kconfig index 7a8008b0783fc..16f4b5c91f1b6 100644 --- a/drivers/gpu/drm/tinydrm/Kconfig +++ b/drivers/gpu/drm/tinydrm/Kconfig @@ -23,6 +23,7 @@ config TINYDRM_ILI9225 config TINYDRM_ILI9341 tristate "DRM support for ILI9341 display panels" depends on DRM_TINYDRM && SPI + depends on BACKLIGHT_CLASS_DEVICE select TINYDRM_MIPI_DBI help DRM driver for the following Ilitek ILI9341 panels: -- GitLab From c3d433617d2048f5fc3ee1135bce1a9bc2375662 Mon Sep 17 00:00:00 2001 From: Tarun Vyas <tarun.vyas@intel.com> Date: Wed, 11 Jul 2018 22:33:23 -0700 Subject: [PATCH 1039/1506] drm/i915: Use crtc_state->has_psr instead of CAN_PSR for pipe update In commit "drm/i915: Wait for PSR exit before checking for vblank evasion", the idea was to limit the PSR IDLE checks when PSR is actually supported. While CAN_PSR does do that check, it doesn't applies on a per-crtc basis. crtc_state->has_psr is a more granular check that only applies to pipe(s) that have PSR enabled. Without the has_psr check, we end up waiting on the eDP transcoder's PSR_STATUS register irrespective of whether the pipe being updated is driving it or not. v2: Remove unnecessary parantheses, make checkpatch happy. v3: Move the has_psr check to intel_psr_wait_for_idle and commit message changes (DK). v4: Derive dev_priv from intel_crtc_state (DK) v5: Commit message changes to reflect the HW behavior (DK) Fixes: a608987970b9 ("drm/i915: Wait for PSR exit before checking for vblank evasion") Reviewed-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Signed-off-by: Tarun Vyas <tarun.vyas@intel.com> Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180712053323.26266-1-tarun.vyas@intel.com --- drivers/gpu/drm/i915/intel_drv.h | 2 +- drivers/gpu/drm/i915/intel_psr.c | 7 ++++++- drivers/gpu/drm/i915/intel_sprite.c | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index e283e9e901c2d..1375cad8bf83a 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1922,7 +1922,7 @@ void intel_psr_compute_config(struct intel_dp *intel_dp, void intel_psr_irq_control(struct drm_i915_private *dev_priv, bool debug); void intel_psr_irq_handler(struct drm_i915_private *dev_priv, u32 psr_iir); void intel_psr_short_pulse(struct intel_dp *intel_dp); -int intel_psr_wait_for_idle(struct drm_i915_private *dev_priv); +int intel_psr_wait_for_idle(const struct intel_crtc_state *new_crtc_state); /* intel_runtime_pm.c */ int intel_power_domains_init(struct drm_i915_private *); diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 23acc9ac8d4d0..e97db5dd75b1c 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -717,11 +717,16 @@ void intel_psr_disable(struct intel_dp *intel_dp, cancel_work_sync(&dev_priv->psr.work); } -int intel_psr_wait_for_idle(struct drm_i915_private *dev_priv) +int intel_psr_wait_for_idle(const struct intel_crtc_state *new_crtc_state) { + struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->base.crtc); + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); i915_reg_t reg; u32 mask; + if (!new_crtc_state->has_psr) + return 0; + /* * The sole user right now is intel_pipe_update_start(), * which won't race with psr_enable/disable, which is diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index e2328d0402d88..3a4a26dd770fc 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -118,7 +118,7 @@ void intel_pipe_update_start(const struct intel_crtc_state *new_crtc_state) * VBL interrupts will start the PSR exit and prevent a PSR * re-entry as well. */ - if (CAN_PSR(dev_priv) && intel_psr_wait_for_idle(dev_priv)) + if (intel_psr_wait_for_idle(new_crtc_state)) DRM_ERROR("PSR idle timed out, atomic update may fail\n"); local_irq_disable(); -- GitLab From 5b7b30864d1d18605e9ad81f2cd1eee6927399df Mon Sep 17 00:00:00 2001 From: Dhinakaran Pandiyan <dhinakaran.pandiyan@gmail.com> Date: Wed, 4 Jul 2018 17:31:21 -0700 Subject: [PATCH 1040/1506] drm/i915/psr: Split sink status into a separate debugfs node MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows to read i915_edp_psr_status from tests without triggering any AUX communication. Take this opportunity to move this under the eDP-1 connector directory as the status we print is of the sink. Cc: Rodrigo Vivi <rodrigo.vivi@intel.com> Cc: José Roberto de Souza <jose.souza@intel.com> Suggested-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180705003121.2478-1-dhinakaran.pandiyan@intel.com --- drivers/gpu/drm/i915/i915_debugfs.c | 69 ++++++++++++++++------------- 1 file changed, 39 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 099f97ef23039..54509e44a8567 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2592,6 +2592,41 @@ static const struct file_operations i915_guc_log_relay_fops = { .release = i915_guc_log_relay_release, }; +static int i915_psr_sink_status_show(struct seq_file *m, void *data) +{ + u8 val; + static const char * const sink_status[] = { + "inactive", + "transition to active, capture and display", + "active, display from RFB", + "active, capture and display on sink device timings", + "transition to inactive, capture and display, timing re-sync", + "reserved", + "reserved", + "sink internal error", + }; + struct drm_connector *connector = m->private; + struct intel_dp *intel_dp = + enc_to_intel_dp(&intel_attached_encoder(connector)->base); + + if (connector->status != connector_status_connected) + return -ENODEV; + + if (drm_dp_dpcd_readb(&intel_dp->aux, DP_PSR_STATUS, &val) == 1) { + const char *str = "unknown"; + + val &= DP_PSR_SINK_STATE_MASK; + if (val < ARRAY_SIZE(sink_status)) + str = sink_status[val]; + seq_printf(m, "Sink PSR status: 0x%x [%s]\n", val, str); + } else { + DRM_ERROR("dpcd read (at %u) failed\n", DP_PSR_STATUS); + } + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(i915_psr_sink_status); + static void psr_source_status(struct drm_i915_private *dev_priv, struct seq_file *m) { @@ -2643,26 +2678,6 @@ psr_source_status(struct drm_i915_private *dev_priv, struct seq_file *m) seq_printf(m, "Source PSR status: 0x%x [%s]\n", psr_status, "unknown"); } -static const char *psr_sink_status(u8 val) -{ - static const char * const sink_status[] = { - "inactive", - "transition to active, capture and display", - "active, display from RFB", - "active, capture and display on sink device timings", - "transition to inactive, capture and display, timing re-sync", - "reserved", - "reserved", - "sink internal error" - }; - - val &= DP_PSR_SINK_STATE_MASK; - if (val < ARRAY_SIZE(sink_status)) - return sink_status[val]; - - return "unknown"; -} - static int i915_edp_psr_status(struct seq_file *m, void *data) { struct drm_i915_private *dev_priv = node_to_i915(m->private); @@ -2706,15 +2721,6 @@ static int i915_edp_psr_status(struct seq_file *m, void *data) } psr_source_status(dev_priv, m); - - if (dev_priv->psr.enabled) { - struct drm_dp_aux *aux = &dev_priv->psr.enabled->aux; - u8 val; - - if (drm_dp_dpcd_readb(aux, DP_PSR_STATUS, &val) == 1) - seq_printf(m, "Sink PSR status: 0x%x [%s]\n", val, - psr_sink_status(val)); - } mutex_unlock(&dev_priv->psr.lock); if (READ_ONCE(dev_priv->psr.debug)) { @@ -4968,9 +4974,12 @@ int i915_debugfs_connector_add(struct drm_connector *connector) debugfs_create_file("i915_dpcd", S_IRUGO, root, connector, &i915_dpcd_fops); - if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) + if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { debugfs_create_file("i915_panel_timings", S_IRUGO, root, connector, &i915_panel_fops); + debugfs_create_file("i915_psr_sink_status", S_IRUGO, root, + connector, &i915_psr_sink_status_fops); + } return 0; } -- GitLab From 521715f903783e324b0067c521baf4f9776d7561 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi <rodrigo.vivi@intel.com> Date: Wed, 11 Jul 2018 15:00:50 -0700 Subject: [PATCH 1041/1506] drm/i915/psr: Remove useless function calls. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PSR is no longer supported on VLV/CHV so this is just dead code. Cc: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Reviewed-by: José Roberto de Souza <jose.souza@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180711220050.21809-1-rodrigo.vivi@intel.com --- drivers/gpu/drm/i915/intel_dp.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 5be07e1d816d7..7d40bfcb1bbb4 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2830,10 +2830,6 @@ static void vlv_disable_dp(struct intel_encoder *encoder, const struct intel_crtc_state *old_crtc_state, const struct drm_connector_state *old_conn_state) { - struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); - - intel_psr_disable(intel_dp, old_crtc_state); - intel_disable_dp(encoder, old_crtc_state, old_conn_state); } @@ -3046,10 +3042,7 @@ static void vlv_enable_dp(struct intel_encoder *encoder, const struct intel_crtc_state *pipe_config, const struct drm_connector_state *conn_state) { - struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); - intel_edp_backlight_on(pipe_config, conn_state); - intel_psr_enable(intel_dp, pipe_config); } static void g4x_pre_enable_dp(struct intel_encoder *encoder, -- GitLab From 9306b62b43c460923ba4a32b66aeb7d0e4c02adf Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi <rodrigo.vivi@intel.com> Date: Wed, 11 Jul 2018 22:27:15 -0700 Subject: [PATCH 1042/1506] drm/i915/psr: Remove few mod parameters option. Reduce the module parameter to enable or disable. The link stand by vs full link off was used only once. And it was actually masking another bug fixed by commit '84bb2916a683 ("drm/i915/psr: Check for SET_POWER_CAPABLE bit at PSR init time.")' So, let's remove these options for now. End goal is to fully remove the mod param, moving it to a debugfs interface in upcoming patches. Cc: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Cc: Tarun Vyas <tarun.vyas@intel.com> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Reviewed-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180712052715.8177-1-rodrigo.vivi@intel.com --- drivers/gpu/drm/i915/i915_params.c | 2 +- drivers/gpu/drm/i915/intel_psr.c | 10 ---------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 49fcc4679db67..817576701ed75 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -92,7 +92,7 @@ i915_param_named_unsafe(enable_ppgtt, int, 0400, i915_param_named_unsafe(enable_psr, int, 0600, "Enable PSR " - "(0=disabled, 1=enabled - link mode chosen per-platform, 2=force link-standby mode, 3=force link-off mode) " + "(0=disabled, 1=enabled) " "Default: -1 (use per-chip default)"); i915_param_named_unsafe(alpha_support, bool, 0400, diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index e97db5dd75b1c..4bd5768731ee2 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -971,16 +971,6 @@ void intel_psr_init(struct drm_i915_private *dev_priv) /* For new platforms let's respect VBT back again */ dev_priv->psr.link_standby = dev_priv->vbt.psr.full_link; - /* Override link_standby x link_off defaults */ - if (i915_modparams.enable_psr == 2 && !dev_priv->psr.link_standby) { - DRM_DEBUG_KMS("PSR: Forcing link standby\n"); - dev_priv->psr.link_standby = true; - } - if (i915_modparams.enable_psr == 3 && dev_priv->psr.link_standby) { - DRM_DEBUG_KMS("PSR: Forcing main link off\n"); - dev_priv->psr.link_standby = false; - } - INIT_WORK(&dev_priv->psr.work, intel_psr_work); mutex_init(&dev_priv->psr.lock); } -- GitLab From f7cf1a1829f9ff776fb5504c9c5ffa0e9d2baf79 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi <rodrigo.vivi@intel.com> Date: Thu, 12 Jul 2018 23:54:26 -0700 Subject: [PATCH 1043/1506] drm/i915: Update DRIVER_DATE to 20180712 Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com> --- drivers/gpu/drm/i915/i915_drv.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index a6c6decd05465..1616e994b9a59 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -86,8 +86,8 @@ #define DRIVER_NAME "i915" #define DRIVER_DESC "Intel Graphics" -#define DRIVER_DATE "20180709" -#define DRIVER_TIMESTAMP 1531175967 +#define DRIVER_DATE "20180712" +#define DRIVER_TIMESTAMP 1531464866 /* Use I915_STATE_WARN(x) and I915_STATE_WARN_ON() (rather than WARN() and * WARN_ON()) for hw state sanity checks to check for unexpected conditions -- GitLab From 55fe0768f53ecc6c0a1bbfa3b0c688090cfa0360 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 12 Jul 2018 21:20:27 +0100 Subject: [PATCH 1044/1506] drm/i915/guc: Protect against NULL client dereference in error path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After aborting a module load, we may try and disable guc before we have finished setting it. Long term plan is to ensure perfect onion unwind, but in the short term we want to fix the oops to re-enable drv_module_reload. [ 317.401239] BUG: unable to handle kernel NULL pointer dereference at 0000000000000030 [ 317.401279] Oops: 0000 [#1] PREEMPT SMP PTI [ 317.401294] CPU: 5 PID: 4275 Comm: drv_module_relo Tainted: G U 4.18.0-rc4-CI-CI_DRM_4476+ #1 [ 317.401317] Hardware name: System manufacturer System Product Name/Z170M-PLUS, BIOS 3610 03/29/2018 [ 317.401440] RIP: 0010:unreserve_doorbell+0x0/0x80 [i915] [ 317.401454] Code: bb e0 48 8b 35 21 4d 18 00 49 c7 c0 a8 e5 62 a0 b9 cc 00 00 00 48 c7 c2 d8 41 5f a0 48 c7 c7 c9 f6 53 a0 e8 a2 3d c2 e0 0f 0b <0f> b7 47 30 66 3d 00 01 74 20 48 8b 57 18 48 0f a3 82 40 05 00 00 [ 317.401602] RSP: 0018:ffffc900003d3da0 EFLAGS: 00010246 [ 317.401619] RAX: ffffffff8223b300 RBX: 0000000000000000 RCX: 0000000000000000 [ 317.401636] RDX: 0000001fffffffc0 RSI: ffff880219f115f0 RDI: 0000000000000000 [ 317.401654] RBP: ffff880219f11838 R08: 0000000000000000 R09: 0000000000000000 [ 317.401671] R10: 0000000000000000 R11: 0000000000000000 R12: ffff880219f11300 [ 317.401689] R13: ffff880219f17770 R14: ffff88022c1daef8 R15: ffffffffa06ae950 [ 317.401707] FS: 00007febf77a9980(0000) GS:ffff880236d40000(0000) knlGS:0000000000000000 [ 317.401727] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 317.401743] CR2: 0000000000000030 CR3: 0000000222072003 CR4: 00000000003606e0 [ 317.401761] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 317.401779] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 317.401796] Call Trace: [ 317.401894] guc_client_free+0x9/0x130 [i915] [ 317.401993] intel_guc_submission_fini+0x50/0x90 [i915] [ 317.402092] intel_uc_fini+0x34/0xd0 [i915] [ 317.402179] i915_gem_fini+0x5c/0x100 [i915] [ 317.402249] i915_driver_unload+0xd2/0x110 [i915] [ 317.402321] i915_pci_remove+0x10/0x20 [i915] [ 317.402341] pci_device_remove+0x36/0xb0 [ 317.402357] device_release_driver_internal+0x185/0x250 [ 317.402374] driver_detach+0x35/0x70 [ 317.402390] bus_remove_driver+0x53/0xd0 [ 317.402404] pci_unregister_driver+0x25/0xa0 [ 317.402423] __se_sys_delete_module+0x162/0x210 [ 317.402439] ? do_syscall_64+0xd/0x190 [ 317.402454] do_syscall_64+0x55/0x190 [ 317.402470] entry_SYSCALL_64_after_hwframe+0x49/0xbe [ 317.402485] RIP: 0033:0x7febf6e5d1b7 [ 317.402496] Code: 73 01 c3 48 8b 0d d1 8c 2c 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 b8 b0 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d a1 8c 2c 00 f7 d8 64 89 01 48 [ 317.402646] RSP: 002b:00007fffb5e72798 EFLAGS: 00000206 ORIG_RAX: 00000000000000b0 [ 317.402667] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007febf6e5d1b7 [ 317.402686] RDX: 0000000000000000 RSI: 0000000000000800 RDI: 0000562da1addd98 [ 317.402703] RBP: 0000562da1addd30 R08: 0000562da1addd9c R09: 00007fffb5e727d8 [ 317.402721] R10: 00007fffb5e71794 R11: 0000000000000206 R12: 0000562da0ff6470 Testcase: igt/drv_module_reload/basic-reload-inject Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: MichaÅ‚ Winiarski <michal.winiarski@intel.com> Cc: Michal Wajdeczko <michal.wajdeczko@intel.com> Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180712202027.19801-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_guc_submission.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_guc_submission.c b/drivers/gpu/drm/i915/intel_guc_submission.c index cd51be8ff0257..22367131d6a12 100644 --- a/drivers/gpu/drm/i915/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/intel_guc_submission.c @@ -1128,7 +1128,8 @@ static void guc_clients_destroy(struct intel_guc *guc) guc_client_free(client); client = fetch_and_zero(&guc->execbuf_client); - guc_client_free(client); + if (client) + guc_client_free(client); } /* -- GitLab From a1a6fa3dcda11d068f5e629c7a18ef7282bf0c7d Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann <tzimmermann@suse.de> Date: Fri, 13 Jul 2018 10:06:25 +0200 Subject: [PATCH 1045/1506] drm/stm: 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 <tzimmermann@suse.de> Acked-by: Philippe Cornu <philippe.cornu@st.com> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org> Link: https://patchwork.freedesktop.org/patch/msgid/20180713080625.18256-1-tzimmermann@suse.de --- drivers/gpu/drm/stm/drv.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/stm/drv.c b/drivers/gpu/drm/stm/drv.c index 8698e08313e1e..f2021b23554d3 100644 --- a/drivers/gpu/drm/stm/drv.c +++ b/drivers/gpu/drm/stm/drv.c @@ -148,16 +148,16 @@ static int stm_drm_platform_probe(struct platform_device *pdev) ret = drv_load(ddev); if (ret) - goto err_unref; + goto err_put; ret = drm_dev_register(ddev, 0); if (ret) - goto err_unref; + goto err_put; return 0; -err_unref: - drm_dev_unref(ddev); +err_put: + drm_dev_put(ddev); return ret; } @@ -170,7 +170,7 @@ static int stm_drm_platform_remove(struct platform_device *pdev) drm_dev_unregister(ddev); drv_unload(ddev); - drm_dev_unref(ddev); + drm_dev_put(ddev); return 0; } -- GitLab From a08eac479b4e6de3700d8d1c7c664d4ffc0535c7 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann <tzimmermann@suse.de> Date: Thu, 12 Jul 2018 17:26:39 +0200 Subject: [PATCH 1046/1506] drm/sti: 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 <tzimmermann@suse.de> Acked-by: Benjamin Gaignard <benjamin.gaignard@linaro.org> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org> Link: https://patchwork.freedesktop.org/patch/msgid/20180712152639.30934-1-tzimmermann@suse.de --- drivers/gpu/drm/sti/sti_drv.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/sti/sti_drv.c b/drivers/gpu/drm/sti/sti_drv.c index 90c46b49c9315..832fc43960ee4 100644 --- a/drivers/gpu/drm/sti/sti_drv.c +++ b/drivers/gpu/drm/sti/sti_drv.c @@ -224,7 +224,7 @@ static int sti_bind(struct device *dev) ret = sti_init(ddev); if (ret) - goto err_drm_dev_unref; + goto err_drm_dev_put; ret = component_bind_all(ddev->dev, ddev); if (ret) @@ -248,8 +248,8 @@ static int sti_bind(struct device *dev) drm_mode_config_cleanup(ddev); err_cleanup: sti_cleanup(ddev); -err_drm_dev_unref: - drm_dev_unref(ddev); +err_drm_dev_put: + drm_dev_put(ddev); return ret; } @@ -259,7 +259,7 @@ static void sti_unbind(struct device *dev) drm_dev_unregister(ddev); sti_cleanup(ddev); - drm_dev_unref(ddev); + drm_dev_put(ddev); } static const struct component_master_ops sti_ops = { -- GitLab From cf19fa2cfa4e9b5458b6f3503c5317dd1a2bfbae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org> Date: Thu, 12 Jul 2018 17:04:14 +0200 Subject: [PATCH 1047/1506] drm/client: Fix double free in error path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes a static checker warning: drivers/gpu/drm/drm_client.c:289 drm_client_buffer_create() error: double free of 'buffer' Extend drm_client_buffer_delete() to handle the case when there's no dumb buffer attached and drop the extra kfree. Fixes: c76f0f7cb546 ("drm: Begin an API for in-kernel clients") Reported-by: Dan Carpenter <dan.carpenter@oracle.com> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Noralf Trønnes <noralf@tronnes.org> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180712150414.46908-1-noralf@tronnes.org --- drivers/gpu/drm/drm_client.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c index 9b142f58d489f..baff50a4c2349 100644 --- a/drivers/gpu/drm/drm_client.c +++ b/drivers/gpu/drm/drm_client.c @@ -218,7 +218,9 @@ static void drm_client_buffer_delete(struct drm_client_buffer *buffer) if (buffer->gem) drm_gem_object_put_unlocked(buffer->gem); - drm_mode_destroy_dumb(dev, buffer->handle, buffer->client->file); + if (buffer->handle) + drm_mode_destroy_dumb(dev, buffer->handle, buffer->client->file); + kfree(buffer); } @@ -243,7 +245,7 @@ drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u dumb_args.bpp = drm_format_plane_cpp(format, 0) * 8; ret = drm_mode_create_dumb(dev, &dumb_args, client->file); if (ret) - goto err_free; + goto err_delete; buffer->handle = dumb_args.handle; buffer->pitch = dumb_args.pitch; @@ -276,8 +278,6 @@ drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u err_delete: drm_client_buffer_delete(buffer); -err_free: - kfree(buffer); return ERR_PTR(ret); } -- GitLab From 90c3e2198777aaa355b6994a31a79c636c8d4306 Mon Sep 17 00:00:00 2001 From: Clint Taylor <clinton.a.taylor@intel.com> Date: Tue, 10 Jul 2018 13:02:05 -0700 Subject: [PATCH 1048/1506] drm/i915/glk: Add Quirk for GLK NUC HDMI port issues. On GLK NUC platforms the HDMI retiming buffer needs additional disabled time to correctly sync to a faster incoming signal. When measured on a scope the highspeed lines of the HDMI clock turn off for ~400uS during a normal resolution change. The HDMI retimer on the GLK NUC appears to require at least a full frame of quiet time before a new faster clock can be correctly sync'd. Wait 100ms due to msleep inaccuracies while waiting for a completed frame. Add a quirk to the driver for GLK boards that use ITE66317 HDMI retimers. V2: Add more devices to the quirk list V3: Delay increased to 100ms, check to confirm crtc type is HDMI. V4: crtc type check extended to include _DDI and whitespace fixes v5: Fix white spaces, remove the macro for delay. Revert the crtc type check introduced in v4. Cc: Imre Deak <imre.deak@intel.com> Cc: <stable@vger.kernel.org> # v4.14+ Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=105887 Signed-off-by: Clint Taylor <clinton.a.taylor@intel.com> Tested-by: Daniel Scheller <d.scheller.oss@gmail.com> Signed-off-by: Radhakrishna Sripada <radhakrishna.sripada@intel.com> Signed-off-by: Imre Deak <imre.deak@intel.com> Reviewed-by: Imre Deak <imre.deak@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180710200205.1478-1-radhakrishna.sripada@intel.com --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_ddi.c | 13 +++++++++++-- drivers/gpu/drm/i915/intel_display.c | 21 ++++++++++++++++++++- drivers/gpu/drm/i915/intel_drv.h | 3 +-- 4 files changed, 33 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 1616e994b9a59..f519485fcd736 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -650,6 +650,7 @@ enum intel_sbi_destination { #define QUIRK_BACKLIGHT_PRESENT (1<<3) #define QUIRK_PIN_SWIZZLED_PAGES (1<<5) #define QUIRK_INCREASE_T12_DELAY (1<<6) +#define QUIRK_INCREASE_DDI_DISABLED_TIME (1<<7) struct intel_fbdev; struct intel_fbc_work; diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 32838ed89ee7a..e4caa902d88e2 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1808,15 +1808,24 @@ void intel_ddi_enable_transcoder_func(const struct intel_crtc_state *crtc_state) I915_WRITE(TRANS_DDI_FUNC_CTL(cpu_transcoder), temp); } -void intel_ddi_disable_transcoder_func(struct drm_i915_private *dev_priv, - enum transcoder cpu_transcoder) +void intel_ddi_disable_transcoder_func(const struct intel_crtc_state *crtc_state) { + struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; i915_reg_t reg = TRANS_DDI_FUNC_CTL(cpu_transcoder); uint32_t val = I915_READ(reg); val &= ~(TRANS_DDI_FUNC_ENABLE | TRANS_DDI_PORT_MASK | TRANS_DDI_DP_VC_PAYLOAD_ALLOC); val |= TRANS_DDI_PORT_NONE; I915_WRITE(reg, val); + + if (dev_priv->quirks & QUIRK_INCREASE_DDI_DISABLED_TIME && + intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) { + DRM_DEBUG_KMS("Quirk Increase DDI disabled time\n"); + /* Quirk time at 100ms for reliable operation */ + msleep(100); + } } int intel_ddi_toggle_hdcp_signalling(struct intel_encoder *intel_encoder, diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 694975afe394a..8bd9080fce346 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5838,7 +5838,7 @@ static void haswell_crtc_disable(struct intel_crtc_state *old_crtc_state, intel_ddi_set_vc_payload_alloc(old_crtc_state, false); if (!transcoder_is_dsi(cpu_transcoder)) - intel_ddi_disable_transcoder_func(dev_priv, cpu_transcoder); + intel_ddi_disable_transcoder_func(old_crtc_state); if (INTEL_GEN(dev_priv) >= 9) skylake_scaler_disable(intel_crtc); @@ -14806,6 +14806,18 @@ static void quirk_increase_t12_delay(struct drm_device *dev) DRM_INFO("Applying T12 delay quirk\n"); } +/* + * GeminiLake NUC HDMI outputs require additional off time + * this allows the onboard retimer to correctly sync to signal + */ +static void quirk_increase_ddi_disabled_time(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = to_i915(dev); + + dev_priv->quirks |= QUIRK_INCREASE_DDI_DISABLED_TIME; + DRM_INFO("Applying Increase DDI Disabled quirk\n"); +} + struct intel_quirk { int device; int subsystem_vendor; @@ -14892,6 +14904,13 @@ static struct intel_quirk intel_quirks[] = { /* Toshiba Satellite P50-C-18C */ { 0x191B, 0x1179, 0xF840, quirk_increase_t12_delay }, + + /* GeminiLake NUC */ + { 0x3185, 0x8086, 0x2072, quirk_increase_ddi_disabled_time }, + { 0x3184, 0x8086, 0x2072, quirk_increase_ddi_disabled_time }, + /* ASRock ITX*/ + { 0x3185, 0x1849, 0x2212, quirk_increase_ddi_disabled_time }, + { 0x3184, 0x1849, 0x2212, quirk_increase_ddi_disabled_time }, }; static void intel_init_quirks(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 1375cad8bf83a..a0e9a35b56582 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1384,8 +1384,7 @@ void hsw_fdi_link_train(struct intel_crtc *crtc, void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port); bool intel_ddi_get_hw_state(struct intel_encoder *encoder, enum pipe *pipe); void intel_ddi_enable_transcoder_func(const struct intel_crtc_state *crtc_state); -void intel_ddi_disable_transcoder_func(struct drm_i915_private *dev_priv, - enum transcoder cpu_transcoder); +void intel_ddi_disable_transcoder_func(const struct intel_crtc_state *crtc_state); void intel_ddi_enable_pipe_clock(const struct intel_crtc_state *crtc_state); void intel_ddi_disable_pipe_clock(const struct intel_crtc_state *crtc_state); void intel_ddi_set_pipe_settings(const struct intel_crtc_state *crtc_state); -- GitLab From 2c6d1fffa1d9b0a5b5ac1a23be9ad64abe60910d Mon Sep 17 00:00:00 2001 From: Hans Verkuil <hans.verkuil@cisco.com> Date: Wed, 11 Jul 2018 15:29:07 +0200 Subject: [PATCH 1049/1506] drm: add support for DisplayPort CEC-Tunneling-over-AUX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds support for the DisplayPort CEC-Tunneling-over-AUX feature that is part of the DisplayPort 1.3 standard. Unfortunately, not all DisplayPort/USB-C to HDMI adapters with a chip that has this capability actually hook up the CEC pin, so even though a CEC device is created, it may not actually work. Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180711132909.25409-2-hverkuil@xs4all.nl --- drivers/gpu/drm/Kconfig | 10 + drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/drm_dp_cec.c | 428 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/drm_dp_helper.c | 1 + include/drm/drm_dp_helper.h | 56 +++++ 5 files changed, 496 insertions(+) create mode 100644 drivers/gpu/drm/drm_dp_cec.c diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index a8054dde49b50..cb88528e7b10c 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -122,6 +122,16 @@ config DRM_LOAD_EDID_FIRMWARE default case is N. Details and instructions how to build your own EDID data are given in Documentation/EDID/HOWTO.txt. +config DRM_DP_CEC + bool "Enable DisplayPort CEC-Tunneling-over-AUX HDMI support" + select CEC_CORE + help + Choose this option if you want to enable HDMI CEC support for + DisplayPort/USB-C to HDMI adapters. + + Note: not all adapters support this feature, and even for those + that do support this they often do not hook up the CEC pin. + config DRM_TTM tristate depends on DRM && MMU diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 0e0a3ef1abadc..a6771cef85e25 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -41,6 +41,7 @@ drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o drm_kms_helper-$(CONFIG_DRM_KMS_CMA_HELPER) += drm_fb_cma_helper.o drm_kms_helper-$(CONFIG_DRM_DP_AUX_CHARDEV) += drm_dp_aux_dev.o +drm_kms_helper-$(CONFIG_DRM_DP_CEC) += drm_dp_cec.o obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o obj-$(CONFIG_DRM_DEBUG_SELFTEST) += selftests/ diff --git a/drivers/gpu/drm/drm_dp_cec.c b/drivers/gpu/drm/drm_dp_cec.c new file mode 100644 index 0000000000000..ddb1c5adebb96 --- /dev/null +++ b/drivers/gpu/drm/drm_dp_cec.c @@ -0,0 +1,428 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DisplayPort CEC-Tunneling-over-AUX support + * + * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <drm/drm_dp_helper.h> +#include <media/cec.h> + +/* + * Unfortunately it turns out that we have a chicken-and-egg situation + * here. Quite a few active (mini-)DP-to-HDMI or USB-C-to-HDMI adapters + * have a converter chip that supports CEC-Tunneling-over-AUX (usually the + * Parade PS176), but they do not wire up the CEC pin, thus making CEC + * useless. + * + * Sadly there is no way for this driver to know this. What happens is + * that a /dev/cecX device is created that is isolated and unable to see + * any of the other CEC devices. Quite literally the CEC wire is cut + * (or in this case, never connected in the first place). + * + * The reason so few adapters support this is that this tunneling protocol + * was never supported by any OS. So there was no easy way of testing it, + * and no incentive to correctly wire up the CEC pin. + * + * Hopefully by creating this driver it will be easier for vendors to + * finally fix their adapters and test the CEC functionality. + * + * I keep a list of known working adapters here: + * + * https://hverkuil.home.xs4all.nl/cec-status.txt + * + * Please mail me (hverkuil@xs4all.nl) if you find an adapter that works + * and is not yet listed there. + * + * Note that the current implementation does not support CEC over an MST hub. + * As far as I can see there is no mechanism defined in the DisplayPort + * standard to transport CEC interrupts over an MST device. It might be + * possible to do this through polling, but I have not been able to get that + * to work. + */ + +/** + * DOC: dp cec helpers + * + * These functions take care of supporting the CEC-Tunneling-over-AUX + * feature of DisplayPort-to-HDMI adapters. + */ + +/* + * When the EDID is unset because the HPD went low, then the CEC DPCD registers + * typically can no longer be read (true for a DP-to-HDMI adapter since it is + * powered by the HPD). However, some displays toggle the HPD off and on for a + * short period for one reason or another, and that would cause the CEC adapter + * to be removed and added again, even though nothing else changed. + * + * This module parameter sets a delay in seconds before the CEC adapter is + * actually unregistered. Only if the HPD does not return within that time will + * the CEC adapter be unregistered. + * + * If it is set to a value >= NEVER_UNREG_DELAY, then the CEC adapter will never + * be unregistered for as long as the connector remains registered. + * + * If it is set to 0, then the CEC adapter will be unregistered immediately as + * soon as the HPD disappears. + * + * The default is one second to prevent short HPD glitches from unregistering + * the CEC adapter. + * + * Note that for integrated HDMI branch devices that support CEC the DPCD + * registers remain available even if the HPD goes low since it is not powered + * by the HPD. In that case the CEC adapter will never be unregistered during + * the life time of the connector. At least, this is the theory since I do not + * have hardware with an integrated HDMI branch device that supports CEC. + */ +#define NEVER_UNREG_DELAY 1000 +static unsigned int drm_dp_cec_unregister_delay = 1; +module_param(drm_dp_cec_unregister_delay, uint, 0600); +MODULE_PARM_DESC(drm_dp_cec_unregister_delay, + "CEC unregister delay in seconds, 0: no delay, >= 1000: never unregister"); + +static int drm_dp_cec_adap_enable(struct cec_adapter *adap, bool enable) +{ + struct drm_dp_aux *aux = cec_get_drvdata(adap); + u32 val = enable ? DP_CEC_TUNNELING_ENABLE : 0; + ssize_t err = 0; + + err = drm_dp_dpcd_writeb(aux, DP_CEC_TUNNELING_CONTROL, val); + return (enable && err < 0) ? err : 0; +} + +static int drm_dp_cec_adap_log_addr(struct cec_adapter *adap, u8 addr) +{ + struct drm_dp_aux *aux = cec_get_drvdata(adap); + /* Bit 15 (logical address 15) should always be set */ + u16 la_mask = 1 << CEC_LOG_ADDR_BROADCAST; + u8 mask[2]; + ssize_t err; + + if (addr != CEC_LOG_ADDR_INVALID) + la_mask |= adap->log_addrs.log_addr_mask | (1 << addr); + mask[0] = la_mask & 0xff; + mask[1] = la_mask >> 8; + err = drm_dp_dpcd_write(aux, DP_CEC_LOGICAL_ADDRESS_MASK, mask, 2); + return (addr != CEC_LOG_ADDR_INVALID && err < 0) ? err : 0; +} + +static int drm_dp_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, + u32 signal_free_time, struct cec_msg *msg) +{ + struct drm_dp_aux *aux = cec_get_drvdata(adap); + unsigned int retries = min(5, attempts - 1); + ssize_t err; + + err = drm_dp_dpcd_write(aux, DP_CEC_TX_MESSAGE_BUFFER, + msg->msg, msg->len); + if (err < 0) + return err; + + err = drm_dp_dpcd_writeb(aux, DP_CEC_TX_MESSAGE_INFO, + (msg->len - 1) | (retries << 4) | + DP_CEC_TX_MESSAGE_SEND); + return err < 0 ? err : 0; +} + +static int drm_dp_cec_adap_monitor_all_enable(struct cec_adapter *adap, + bool enable) +{ + struct drm_dp_aux *aux = cec_get_drvdata(adap); + ssize_t err; + u8 val; + + if (!(adap->capabilities & CEC_CAP_MONITOR_ALL)) + return 0; + + err = drm_dp_dpcd_readb(aux, DP_CEC_TUNNELING_CONTROL, &val); + if (err >= 0) { + if (enable) + val |= DP_CEC_SNOOPING_ENABLE; + else + val &= ~DP_CEC_SNOOPING_ENABLE; + err = drm_dp_dpcd_writeb(aux, DP_CEC_TUNNELING_CONTROL, val); + } + return (enable && err < 0) ? err : 0; +} + +static void drm_dp_cec_adap_status(struct cec_adapter *adap, + struct seq_file *file) +{ + struct drm_dp_aux *aux = cec_get_drvdata(adap); + struct drm_dp_desc desc; + struct drm_dp_dpcd_ident *id = &desc.ident; + + if (drm_dp_read_desc(aux, &desc, true)) + return; + seq_printf(file, "OUI: %*pdH\n", + (int)sizeof(id->oui), id->oui); + seq_printf(file, "ID: %*pE\n", + (int)strnlen(id->device_id, sizeof(id->device_id)), + id->device_id); + seq_printf(file, "HW Rev: %d.%d\n", id->hw_rev >> 4, id->hw_rev & 0xf); + /* + * Show this both in decimal and hex: at least one vendor + * always reports this in hex. + */ + seq_printf(file, "FW/SW Rev: %d.%d (0x%02x.0x%02x)\n", + id->sw_major_rev, id->sw_minor_rev, + id->sw_major_rev, id->sw_minor_rev); +} + +static const struct cec_adap_ops drm_dp_cec_adap_ops = { + .adap_enable = drm_dp_cec_adap_enable, + .adap_log_addr = drm_dp_cec_adap_log_addr, + .adap_transmit = drm_dp_cec_adap_transmit, + .adap_monitor_all_enable = drm_dp_cec_adap_monitor_all_enable, + .adap_status = drm_dp_cec_adap_status, +}; + +static int drm_dp_cec_received(struct drm_dp_aux *aux) +{ + struct cec_adapter *adap = aux->cec.adap; + struct cec_msg msg; + u8 rx_msg_info; + ssize_t err; + + err = drm_dp_dpcd_readb(aux, DP_CEC_RX_MESSAGE_INFO, &rx_msg_info); + if (err < 0) + return err; + + if (!(rx_msg_info & DP_CEC_RX_MESSAGE_ENDED)) + return 0; + + msg.len = (rx_msg_info & DP_CEC_RX_MESSAGE_LEN_MASK) + 1; + err = drm_dp_dpcd_read(aux, DP_CEC_RX_MESSAGE_BUFFER, msg.msg, msg.len); + if (err < 0) + return err; + + cec_received_msg(adap, &msg); + return 0; +} + +static void drm_dp_cec_handle_irq(struct drm_dp_aux *aux) +{ + struct cec_adapter *adap = aux->cec.adap; + u8 flags; + + if (drm_dp_dpcd_readb(aux, DP_CEC_TUNNELING_IRQ_FLAGS, &flags) < 0) + return; + + if (flags & DP_CEC_RX_MESSAGE_INFO_VALID) + drm_dp_cec_received(aux); + + if (flags & DP_CEC_TX_MESSAGE_SENT) + cec_transmit_attempt_done(adap, CEC_TX_STATUS_OK); + else if (flags & DP_CEC_TX_LINE_ERROR) + cec_transmit_attempt_done(adap, CEC_TX_STATUS_ERROR | + CEC_TX_STATUS_MAX_RETRIES); + else if (flags & + (DP_CEC_TX_ADDRESS_NACK_ERROR | DP_CEC_TX_DATA_NACK_ERROR)) + cec_transmit_attempt_done(adap, CEC_TX_STATUS_NACK | + CEC_TX_STATUS_MAX_RETRIES); + drm_dp_dpcd_writeb(aux, DP_CEC_TUNNELING_IRQ_FLAGS, flags); +} + +/** + * drm_dp_cec_irq() - handle CEC interrupt, if any + * @aux: DisplayPort AUX channel + * + * Should be called when handling an IRQ_HPD request. If CEC-tunneling-over-AUX + * is present, then it will check for a CEC_IRQ and handle it accordingly. + */ +void drm_dp_cec_irq(struct drm_dp_aux *aux) +{ + u8 cec_irq; + int ret; + + mutex_lock(&aux->cec.lock); + if (!aux->cec.adap) + goto unlock; + + ret = drm_dp_dpcd_readb(aux, DP_DEVICE_SERVICE_IRQ_VECTOR_ESI1, + &cec_irq); + if (ret < 0 || !(cec_irq & DP_CEC_IRQ)) + goto unlock; + + drm_dp_cec_handle_irq(aux); + drm_dp_dpcd_writeb(aux, DP_DEVICE_SERVICE_IRQ_VECTOR_ESI1, DP_CEC_IRQ); +unlock: + mutex_unlock(&aux->cec.lock); +} +EXPORT_SYMBOL(drm_dp_cec_irq); + +static bool drm_dp_cec_cap(struct drm_dp_aux *aux, u8 *cec_cap) +{ + u8 cap = 0; + + if (drm_dp_dpcd_readb(aux, DP_CEC_TUNNELING_CAPABILITY, &cap) != 1 || + !(cap & DP_CEC_TUNNELING_CAPABLE)) + return false; + if (cec_cap) + *cec_cap = cap; + return true; +} + +/* + * Called if the HPD was low for more than drm_dp_cec_unregister_delay + * seconds. This unregisters the CEC adapter. + */ +static void drm_dp_cec_unregister_work(struct work_struct *work) +{ + struct drm_dp_aux *aux = container_of(work, struct drm_dp_aux, + cec.unregister_work.work); + + mutex_lock(&aux->cec.lock); + cec_unregister_adapter(aux->cec.adap); + aux->cec.adap = NULL; + mutex_unlock(&aux->cec.lock); +} + +/* + * A new EDID is set. If there is no CEC adapter, then create one. If + * there was a CEC adapter, then check if the CEC adapter properties + * were unchanged and just update the CEC physical address. Otherwise + * unregister the old CEC adapter and create a new one. + */ +void drm_dp_cec_set_edid(struct drm_dp_aux *aux, const struct edid *edid) +{ + u32 cec_caps = CEC_CAP_DEFAULTS | CEC_CAP_NEEDS_HPD; + unsigned int num_las = 1; + u8 cap; + +#ifndef CONFIG_MEDIA_CEC_RC + /* + * CEC_CAP_RC is part of CEC_CAP_DEFAULTS, but it is stripped by + * cec_allocate_adapter() if CONFIG_MEDIA_CEC_RC is undefined. + * + * Do this here as well to ensure the tests against cec_caps are + * correct. + */ + cec_caps &= ~CEC_CAP_RC; +#endif + cancel_delayed_work_sync(&aux->cec.unregister_work); + + mutex_lock(&aux->cec.lock); + if (!drm_dp_cec_cap(aux, &cap)) { + /* CEC is not supported, unregister any existing adapter */ + cec_unregister_adapter(aux->cec.adap); + aux->cec.adap = NULL; + goto unlock; + } + + if (cap & DP_CEC_SNOOPING_CAPABLE) + cec_caps |= CEC_CAP_MONITOR_ALL; + if (cap & DP_CEC_MULTIPLE_LA_CAPABLE) + num_las = CEC_MAX_LOG_ADDRS; + + if (aux->cec.adap) { + if (aux->cec.adap->capabilities == cec_caps && + aux->cec.adap->available_log_addrs == num_las) { + /* Unchanged, so just set the phys addr */ + cec_s_phys_addr_from_edid(aux->cec.adap, edid); + goto unlock; + } + /* + * The capabilities changed, so unregister the old + * adapter first. + */ + cec_unregister_adapter(aux->cec.adap); + } + + /* Create a new adapter */ + aux->cec.adap = cec_allocate_adapter(&drm_dp_cec_adap_ops, + aux, aux->cec.name, cec_caps, + num_las); + if (IS_ERR(aux->cec.adap)) { + aux->cec.adap = NULL; + goto unlock; + } + if (cec_register_adapter(aux->cec.adap, aux->cec.parent)) { + cec_delete_adapter(aux->cec.adap); + aux->cec.adap = NULL; + } else { + /* + * Update the phys addr for the new CEC adapter. When called + * from drm_dp_cec_register_connector() edid == NULL, so in + * that case the phys addr is just invalidated. + */ + cec_s_phys_addr_from_edid(aux->cec.adap, edid); + } +unlock: + mutex_unlock(&aux->cec.lock); +} +EXPORT_SYMBOL(drm_dp_cec_set_edid); + +/* + * The EDID disappeared (likely because of the HPD going down). + */ +void drm_dp_cec_unset_edid(struct drm_dp_aux *aux) +{ + cancel_delayed_work_sync(&aux->cec.unregister_work); + + mutex_lock(&aux->cec.lock); + if (!aux->cec.adap) + goto unlock; + + cec_phys_addr_invalidate(aux->cec.adap); + /* + * We're done if we want to keep the CEC device + * (drm_dp_cec_unregister_delay is >= NEVER_UNREG_DELAY) or if the + * DPCD still indicates the CEC capability (expected for an integrated + * HDMI branch device). + */ + if (drm_dp_cec_unregister_delay < NEVER_UNREG_DELAY && + !drm_dp_cec_cap(aux, NULL)) { + /* + * Unregister the CEC adapter after drm_dp_cec_unregister_delay + * seconds. This to debounce short HPD off-and-on cycles from + * displays. + */ + schedule_delayed_work(&aux->cec.unregister_work, + drm_dp_cec_unregister_delay * HZ); + } +unlock: + mutex_unlock(&aux->cec.lock); +} +EXPORT_SYMBOL(drm_dp_cec_unset_edid); + +/** + * drm_dp_cec_register_connector() - register a new connector + * @aux: DisplayPort AUX channel + * @name: name of the CEC device + * @parent: parent device + * + * A new connector was registered with associated CEC adapter name and + * CEC adapter parent device. After registering the name and parent + * drm_dp_cec_set_edid() is called to check if the connector supports + * CEC and to register a CEC adapter if that is the case. + */ +void drm_dp_cec_register_connector(struct drm_dp_aux *aux, const char *name, + struct device *parent) +{ + WARN_ON(aux->cec.adap); + aux->cec.name = name; + aux->cec.parent = parent; + INIT_DELAYED_WORK(&aux->cec.unregister_work, + drm_dp_cec_unregister_work); + + drm_dp_cec_set_edid(aux, NULL); +} +EXPORT_SYMBOL(drm_dp_cec_register_connector); + +/** + * drm_dp_cec_unregister_connector() - unregister the CEC adapter, if any + * @aux: DisplayPort AUX channel + */ +void drm_dp_cec_unregister_connector(struct drm_dp_aux *aux) +{ + if (!aux->cec.adap) + return; + cancel_delayed_work_sync(&aux->cec.unregister_work); + cec_unregister_adapter(aux->cec.adap); + aux->cec.adap = NULL; +} +EXPORT_SYMBOL(drm_dp_cec_unregister_connector); diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index a7ba602a43a82..f4a06b54aa7df 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -1087,6 +1087,7 @@ static void drm_dp_aux_crc_work(struct work_struct *work) void drm_dp_aux_init(struct drm_dp_aux *aux) { mutex_init(&aux->hw_mutex); + mutex_init(&aux->cec.lock); INIT_WORK(&aux->crc_work, drm_dp_aux_crc_work); aux->ddc.algo = &drm_dp_i2c_algo; diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index c01564991a9f9..05cc31b5db161 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -1078,6 +1078,25 @@ struct drm_dp_aux_msg { size_t size; }; +struct cec_adapter; +struct edid; + +/** + * struct drm_dp_aux_cec - DisplayPort CEC-Tunneling-over-AUX + * @lock: mutex protecting this struct + * @adap: the CEC adapter for CEC-Tunneling-over-AUX support. + * @name: name of the CEC adapter + * @parent: parent device of the CEC adapter + * @unregister_work: unregister the CEC adapter + */ +struct drm_dp_aux_cec { + struct mutex lock; + struct cec_adapter *adap; + const char *name; + struct device *parent; + struct delayed_work unregister_work; +}; + /** * struct drm_dp_aux - DisplayPort AUX channel * @name: user-visible name of this AUX channel and the I2C-over-AUX adapter @@ -1136,6 +1155,10 @@ struct drm_dp_aux { * @i2c_defer_count: Counts I2C DEFERs, used for DP validation. */ unsigned i2c_defer_count; + /** + * @cec: struct containing fields used for CEC-Tunneling-over-AUX. + */ + struct drm_dp_aux_cec cec; }; ssize_t drm_dp_dpcd_read(struct drm_dp_aux *aux, unsigned int offset, @@ -1258,4 +1281,37 @@ drm_dp_has_quirk(const struct drm_dp_desc *desc, enum drm_dp_quirk quirk) return desc->quirks & BIT(quirk); } +#ifdef CONFIG_DRM_DP_CEC +void drm_dp_cec_irq(struct drm_dp_aux *aux); +void drm_dp_cec_register_connector(struct drm_dp_aux *aux, const char *name, + struct device *parent); +void drm_dp_cec_unregister_connector(struct drm_dp_aux *aux); +void drm_dp_cec_set_edid(struct drm_dp_aux *aux, const struct edid *edid); +void drm_dp_cec_unset_edid(struct drm_dp_aux *aux); +#else +static inline void drm_dp_cec_irq(struct drm_dp_aux *aux) +{ +} + +static inline void drm_dp_cec_register_connector(struct drm_dp_aux *aux, + const char *name, + struct device *parent) +{ +} + +static inline void drm_dp_cec_unregister_connector(struct drm_dp_aux *aux) +{ +} + +static inline void drm_dp_cec_set_edid(struct drm_dp_aux *aux, + const struct edid *edid) +{ +} + +static inline void drm_dp_cec_unset_edid(struct drm_dp_aux *aux) +{ +} + +#endif + #endif /* _DRM_DP_HELPER_H_ */ -- GitLab From d2e2d265211cdb423406dd693c8f6fa4ca62674f Mon Sep 17 00:00:00 2001 From: Hans Verkuil <hans.verkuil@cisco.com> Date: Wed, 11 Jul 2018 15:29:08 +0200 Subject: [PATCH 1050/1506] drm-kms-helpers.rst: document the DP CEC helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document the Display Port CEC helper functions. Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180711132909.25409-3-hverkuil@xs4all.nl --- Documentation/gpu/drm-kms-helpers.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst index e37557b30f620..62de583e9efe1 100644 --- a/Documentation/gpu/drm-kms-helpers.rst +++ b/Documentation/gpu/drm-kms-helpers.rst @@ -169,6 +169,15 @@ Display Port Helper Functions Reference .. kernel-doc:: drivers/gpu/drm/drm_dp_helper.c :export: +Display Port CEC Helper Functions Reference +=========================================== + +.. kernel-doc:: drivers/gpu/drm/drm_dp_cec.c + :doc: dp cec helpers + +.. kernel-doc:: drivers/gpu/drm/drm_dp_cec.c + :export: + Display Port Dual Mode Adaptor Helper Functions Reference ========================================================= -- GitLab From 82e00d113639ac810568060b060462e0a7583c9d Mon Sep 17 00:00:00 2001 From: Hans Verkuil <hans.verkuil@cisco.com> Date: Wed, 11 Jul 2018 15:29:09 +0200 Subject: [PATCH 1051/1506] drm/i915: add DisplayPort CEC-Tunneling-over-AUX support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement support for this DisplayPort feature. Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180711132909.25409-4-hverkuil@xs4all.nl --- drivers/gpu/drm/i915/intel_dp.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 6ac6c8787dcf6..b021801dbd48a 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -4495,6 +4495,9 @@ intel_dp_short_pulse(struct intel_dp *intel_dp) DRM_DEBUG_DRIVER("CP or sink specific irq unhandled\n"); } + /* Handle CEC interrupts, if any */ + drm_dp_cec_irq(&intel_dp->aux); + /* defer to the hotplug work for link retraining if needed */ if (intel_dp_needs_link_retrain(intel_dp)) return false; @@ -4809,6 +4812,7 @@ intel_dp_set_edid(struct intel_dp *intel_dp) intel_connector->detect_edid = edid; intel_dp->has_audio = drm_detect_monitor_audio(edid); + drm_dp_cec_set_edid(&intel_dp->aux, edid); } static void @@ -4816,6 +4820,7 @@ intel_dp_unset_edid(struct intel_dp *intel_dp) { struct intel_connector *intel_connector = intel_dp->attached_connector; + drm_dp_cec_unset_edid(&intel_dp->aux); kfree(intel_connector->detect_edid); intel_connector->detect_edid = NULL; @@ -5004,6 +5009,7 @@ static int intel_dp_connector_register(struct drm_connector *connector) { struct intel_dp *intel_dp = intel_attached_dp(connector); + struct drm_device *dev = connector->dev; int ret; ret = intel_connector_register(connector); @@ -5016,13 +5022,20 @@ intel_dp_connector_register(struct drm_connector *connector) intel_dp->aux.name, connector->kdev->kobj.name); intel_dp->aux.dev = connector->kdev; - return drm_dp_aux_register(&intel_dp->aux); + ret = drm_dp_aux_register(&intel_dp->aux); + if (!ret) + drm_dp_cec_register_connector(&intel_dp->aux, + connector->name, dev->dev); + return ret; } static void intel_dp_connector_unregister(struct drm_connector *connector) { - drm_dp_aux_unregister(&intel_attached_dp(connector)->aux); + struct intel_dp *intel_dp = intel_attached_dp(connector); + + drm_dp_cec_unregister_connector(&intel_dp->aux); + drm_dp_aux_unregister(&intel_dp->aux); intel_connector_unregister(connector); } -- GitLab From 4dd4677c2d3d34a2bcd511c088da4535ea58e360 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Thu, 28 Jun 2018 16:54:55 +0300 Subject: [PATCH 1052/1506] drm: Extract __setplane_check() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pull all the error checking out from __set_plane_internal() to a helper function. We'll have another user of this soon. Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180628135457.14647-1-ville.syrjala@linux.intel.com Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> --- drivers/gpu/drm/drm_plane.c | 80 +++++++++++++++++++++++-------------- 1 file changed, 49 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index df0b4ebbedbf4..5c97a01314840 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -583,6 +583,52 @@ int drm_plane_check_pixel_format(struct drm_plane *plane, return 0; } +static int __setplane_check(struct drm_plane *plane, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, + int32_t crtc_x, int32_t crtc_y, + uint32_t crtc_w, uint32_t crtc_h, + uint32_t src_x, uint32_t src_y, + uint32_t src_w, uint32_t src_h) +{ + int ret; + + /* Check whether this plane is usable on this CRTC */ + if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) { + DRM_DEBUG_KMS("Invalid crtc for plane\n"); + return -EINVAL; + } + + /* Check whether this plane supports the fb pixel format. */ + ret = drm_plane_check_pixel_format(plane, fb->format->format, + fb->modifier); + if (ret) { + struct drm_format_name_buf format_name; + + DRM_DEBUG_KMS("Invalid pixel format %s, modifier 0x%llx\n", + drm_get_format_name(fb->format->format, + &format_name), + fb->modifier); + return ret; + } + + /* Give drivers some help against integer overflows */ + if (crtc_w > INT_MAX || + crtc_x > INT_MAX - (int32_t) crtc_w || + crtc_h > INT_MAX || + crtc_y > INT_MAX - (int32_t) crtc_h) { + DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n", + crtc_w, crtc_h, crtc_x, crtc_y); + return -ERANGE; + } + + ret = drm_framebuffer_check_src_coords(src_x, src_y, src_w, src_h, fb); + if (ret) + return ret; + + return 0; +} + /* * __setplane_internal - setplane handler for internal callers * @@ -616,37 +662,9 @@ static int __setplane_internal(struct drm_plane *plane, goto out; } - /* Check whether this plane is usable on this CRTC */ - if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) { - DRM_DEBUG_KMS("Invalid crtc for plane\n"); - ret = -EINVAL; - goto out; - } - - /* Check whether this plane supports the fb pixel format. */ - ret = drm_plane_check_pixel_format(plane, fb->format->format, - fb->modifier); - if (ret) { - struct drm_format_name_buf format_name; - DRM_DEBUG_KMS("Invalid pixel format %s, modifier 0x%llx\n", - drm_get_format_name(fb->format->format, - &format_name), - fb->modifier); - goto out; - } - - /* Give drivers some help against integer overflows */ - if (crtc_w > INT_MAX || - crtc_x > INT_MAX - (int32_t) crtc_w || - crtc_h > INT_MAX || - crtc_y > INT_MAX - (int32_t) crtc_h) { - DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n", - crtc_w, crtc_h, crtc_x, crtc_y); - ret = -ERANGE; - goto out; - } - - ret = drm_framebuffer_check_src_coords(src_x, src_y, src_w, src_h, fb); + ret = __setplane_check(plane, crtc, fb, + crtc_x, crtc_y, crtc_w, crtc_h, + src_x, src_y, src_w, src_h); if (ret) goto out; -- GitLab From e7695eb6ea70ed143fafbcd12ce69886be3aa03d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Thu, 5 Jul 2018 21:59:07 +0300 Subject: [PATCH 1053/1506] drm: Introduce __setplane_atomic() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All the plane->fb/old_fb/crtc dance of __setplane_internal() is pointless on atomic drivers. So let's just introduce a simpler version that skips all that. Ideally we could also skip the __setplane_check() as drm_atomic_plane_check() already checks for everything, but the legacy cursor/"async" .update_plane() tricks bypass that so we still need to call __setplane_check(). Toss in a FIXME to remind someone to clean this up later. v2: Use drm_drv_uses_atomic_modeset() (Daniel) Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180705185907.9524-1-ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_plane.c | 68 +++++++++++++++++++++++++++++++------ 1 file changed, 57 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index 5c97a01314840..6153cbda239fe 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -649,6 +649,8 @@ static int __setplane_internal(struct drm_plane *plane, { int ret = 0; + WARN_ON(drm_drv_uses_atomic_modeset(plane->dev)); + /* No fb means shut it down */ if (!fb) { plane->old_fb = plane->fb; @@ -673,11 +675,9 @@ static int __setplane_internal(struct drm_plane *plane, crtc_x, crtc_y, crtc_w, crtc_h, src_x, src_y, src_w, src_h, ctx); if (!ret) { - if (!plane->state) { - plane->crtc = crtc; - plane->fb = fb; - drm_framebuffer_get(plane->fb); - } + plane->crtc = crtc; + plane->fb = fb; + drm_framebuffer_get(plane->fb); } else { plane->old_fb = NULL; } @@ -690,6 +690,41 @@ static int __setplane_internal(struct drm_plane *plane, return ret; } +static int __setplane_atomic(struct drm_plane *plane, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, + int32_t crtc_x, int32_t crtc_y, + uint32_t crtc_w, uint32_t crtc_h, + uint32_t src_x, uint32_t src_y, + uint32_t src_w, uint32_t src_h, + struct drm_modeset_acquire_ctx *ctx) +{ + int ret; + + WARN_ON(!drm_drv_uses_atomic_modeset(plane->dev)); + + /* No fb means shut it down */ + if (!fb) + return plane->funcs->disable_plane(plane, ctx); + + /* + * FIXME: This is redundant with drm_atomic_plane_check(), + * but the legacy cursor/"async" .update_plane() tricks + * don't call that so we still need this here. Should remove + * this when all .update_plane() implementations have been + * fixed to call drm_atomic_plane_check(). + */ + ret = __setplane_check(plane, crtc, fb, + crtc_x, crtc_y, crtc_w, crtc_h, + src_x, src_y, src_w, src_h); + if (ret) + return ret; + + return plane->funcs->update_plane(plane, crtc, fb, + crtc_x, crtc_y, crtc_w, crtc_h, + src_x, src_y, src_w, src_h, ctx); +} + static int setplane_internal(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, @@ -707,9 +742,15 @@ static int setplane_internal(struct drm_plane *plane, ret = drm_modeset_lock_all_ctx(plane->dev, &ctx); if (ret) goto fail; - ret = __setplane_internal(plane, crtc, fb, - crtc_x, crtc_y, crtc_w, crtc_h, - src_x, src_y, src_w, src_h, &ctx); + + if (drm_drv_uses_atomic_modeset(plane->dev)) + ret = __setplane_atomic(plane, crtc, fb, + crtc_x, crtc_y, crtc_w, crtc_h, + src_x, src_y, src_w, src_h, &ctx); + else + ret = __setplane_internal(plane, crtc, fb, + crtc_x, crtc_y, crtc_w, crtc_h, + src_x, src_y, src_w, src_h, &ctx); fail: if (ret == -EDEADLK) { @@ -841,9 +882,14 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc, src_h = fb->height << 16; } - ret = __setplane_internal(plane, crtc, fb, - crtc_x, crtc_y, crtc_w, crtc_h, - 0, 0, src_w, src_h, ctx); + if (drm_drv_uses_atomic_modeset(dev)) + ret = __setplane_atomic(plane, crtc, fb, + crtc_x, crtc_y, crtc_w, crtc_h, + 0, 0, src_w, src_h, ctx); + else + ret = __setplane_internal(plane, crtc, fb, + crtc_x, crtc_y, crtc_w, crtc_h, + 0, 0, src_w, src_h, ctx); if (fb) drm_framebuffer_put(fb); -- GitLab From 69a8a1961c7bf59b70ec958f8a408ba448fe62a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Thu, 5 Jul 2018 22:00:10 +0300 Subject: [PATCH 1054/1506] drm: Skip __drm_mode_set_config_internal() on atomic drivers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Everything (apart from the actual ->set_config() call) __drm_mode_set_config_internal() does is now useless on atomic drivers. So let's just skip all the foreplay. v2: Use drm_drv_uses_atomic_modeset() (Daniel) Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180705190010.19836-1-ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_crtc.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index a6906c4ab880f..bae43938c8f61 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -461,6 +461,8 @@ static int __drm_mode_set_config_internal(struct drm_mode_set *set, struct drm_crtc *tmp; int ret; + WARN_ON(drm_drv_uses_atomic_modeset(crtc->dev)); + /* * NOTE: ->set_config can also disable other crtcs (if we steal all * connectors from it), hence we need to refcount the fbs across all @@ -478,10 +480,8 @@ static int __drm_mode_set_config_internal(struct drm_mode_set *set, if (ret == 0) { struct drm_plane *plane = crtc->primary; - if (!plane->state) { - plane->crtc = fb ? crtc : NULL; - plane->fb = fb; - } + plane->crtc = fb ? crtc : NULL; + plane->fb = fb; } drm_for_each_crtc(tmp, crtc->dev) { @@ -496,6 +496,7 @@ static int __drm_mode_set_config_internal(struct drm_mode_set *set, return ret; } + /** * drm_mode_set_config_internal - helper to call &drm_mode_config_funcs.set_config * @set: modeset config to set @@ -740,7 +741,11 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, set.connectors = connector_set; set.num_connectors = crtc_req->count_connectors; set.fb = fb; - ret = __drm_mode_set_config_internal(&set, &ctx); + + if (drm_drv_uses_atomic_modeset(dev)) + ret = crtc->funcs->set_config(&set, &ctx); + else + ret = __drm_mode_set_config_internal(&set, &ctx); out: if (fb) -- GitLab From 25dda4dabeeb12af5209b0183c788ef2a88dabbe Mon Sep 17 00:00:00 2001 From: Jon Bloomfield <jon.bloomfield@intel.com> Date: Thu, 12 Jul 2018 19:53:10 +0100 Subject: [PATCH 1055/1506] drm/i915/gtt: Add read only pages to gen8_pte_encode We can set a bit inside the ppGTT PTE to indicate a page is read-only; writes from the GPU will be discarded. We can use this to protect pages and in particular support read-only userptr mappings (necessary for importing PROT_READ vma). Signed-off-by: Jon Bloomfield <jon.bloomfield@intel.com> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Matthew Auld <matthew.william.auld@gmail.com> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Reviewed-by: Matthew Auld <matthew.william.auld@gmail.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180712185315.3288-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_gtt.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 502353b9bf846..b74f1ed03baec 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -244,10 +244,13 @@ static void clear_pages(struct i915_vma *vma) } static gen8_pte_t gen8_pte_encode(dma_addr_t addr, - enum i915_cache_level level) + enum i915_cache_level level, + u32 flags) { - gen8_pte_t pte = _PAGE_PRESENT | _PAGE_RW; - pte |= addr; + gen8_pte_t pte = addr | _PAGE_PRESENT | _PAGE_RW; + + if (unlikely(flags & PTE_READ_ONLY)) + pte &= ~_PAGE_RW; switch (level) { case I915_CACHE_NONE: @@ -721,7 +724,7 @@ static void gen8_initialize_pt(struct i915_address_space *vm, struct i915_page_table *pt) { fill_px(vm, pt, - gen8_pte_encode(vm->scratch_page.daddr, I915_CACHE_LLC)); + gen8_pte_encode(vm->scratch_page.daddr, I915_CACHE_LLC, 0)); } static void gen6_initialize_pt(struct gen6_hw_ppgtt *ppgtt, @@ -869,7 +872,7 @@ static bool gen8_ppgtt_clear_pt(struct i915_address_space *vm, unsigned int pte = gen8_pte_index(start); unsigned int pte_end = pte + num_entries; const gen8_pte_t scratch_pte = - gen8_pte_encode(vm->scratch_page.daddr, I915_CACHE_LLC); + gen8_pte_encode(vm->scratch_page.daddr, I915_CACHE_LLC, 0); gen8_pte_t *vaddr; GEM_BUG_ON(num_entries > pt->used_ptes); @@ -1044,7 +1047,7 @@ gen8_ppgtt_insert_pte_entries(struct i915_hw_ppgtt *ppgtt, enum i915_cache_level cache_level) { struct i915_page_directory *pd; - const gen8_pte_t pte_encode = gen8_pte_encode(0, cache_level); + const gen8_pte_t pte_encode = gen8_pte_encode(0, cache_level, 0); gen8_pte_t *vaddr; bool ret; @@ -1112,7 +1115,7 @@ static void gen8_ppgtt_insert_huge_entries(struct i915_vma *vma, struct sgt_dma *iter, enum i915_cache_level cache_level) { - const gen8_pte_t pte_encode = gen8_pte_encode(0, cache_level); + const gen8_pte_t pte_encode = gen8_pte_encode(0, cache_level, 0); u64 start = vma->node.start; dma_addr_t rem = iter->sg->length; @@ -1578,7 +1581,7 @@ static void gen8_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m) { struct i915_address_space *vm = &ppgtt->vm; const gen8_pte_t scratch_pte = - gen8_pte_encode(vm->scratch_page.daddr, I915_CACHE_LLC); + gen8_pte_encode(vm->scratch_page.daddr, I915_CACHE_LLC, 0); u64 start = 0, length = ppgtt->vm.total; if (use_4lvl(vm)) { @@ -2461,7 +2464,7 @@ static void gen8_ggtt_insert_page(struct i915_address_space *vm, gen8_pte_t __iomem *pte = (gen8_pte_t __iomem *)ggtt->gsm + (offset >> PAGE_SHIFT); - gen8_set_pte(pte, gen8_pte_encode(addr, level)); + gen8_set_pte(pte, gen8_pte_encode(addr, level, 0)); ggtt->invalidate(vm->i915); } @@ -2474,7 +2477,7 @@ static void gen8_ggtt_insert_entries(struct i915_address_space *vm, struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm); struct sgt_iter sgt_iter; gen8_pte_t __iomem *gtt_entries; - const gen8_pte_t pte_encode = gen8_pte_encode(0, level); + const gen8_pte_t pte_encode = gen8_pte_encode(0, level, 0); dma_addr_t addr; gtt_entries = (gen8_pte_t __iomem *)ggtt->gsm; @@ -2542,7 +2545,7 @@ static void gen8_ggtt_clear_range(struct i915_address_space *vm, unsigned first_entry = start >> PAGE_SHIFT; unsigned num_entries = length >> PAGE_SHIFT; const gen8_pte_t scratch_pte = - gen8_pte_encode(vm->scratch_page.daddr, I915_CACHE_LLC); + gen8_pte_encode(vm->scratch_page.daddr, I915_CACHE_LLC, 0); gen8_pte_t __iomem *gtt_base = (gen8_pte_t __iomem *)ggtt->gsm + first_entry; const int max_entries = ggtt_total_entries(ggtt) - first_entry; -- GitLab From 250f8c8140ac0a5e5acb91891d6813f12778b224 Mon Sep 17 00:00:00 2001 From: Jon Bloomfield <jon.bloomfield@intel.com> Date: Thu, 12 Jul 2018 19:53:11 +0100 Subject: [PATCH 1056/1506] drm/i915/gtt: Read-only pages for insert_entries on bdw+ Hook up the flags to allow read-only ppGTT mappings for gen8+ v2: Include a selftest to check that writes to a readonly PTE are dropped v3: Don't duplicate cpu_check() as we can just reuse it, and even worse don't wholesale copy the theory-of-operation comment from igt_ctx_exec without changing it to explain the intention behind the new test! v4: Joonas really likes magic mystery values Signed-off-by: Jon Bloomfield <jon.bloomfield@intel.com> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Matthew Auld <matthew.william.auld@gmail.com> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Reviewed-by: Matthew Auld <matthew.william.auld@gmail.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180712185315.3288-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_gtt.c | 45 ++++--- drivers/gpu/drm/i915/i915_gem_gtt.h | 7 +- drivers/gpu/drm/i915/intel_ringbuffer.c | 11 +- .../gpu/drm/i915/selftests/i915_gem_context.c | 112 +++++++++++++++++- 4 files changed, 153 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index b74f1ed03baec..734b67f7853c9 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -204,7 +204,7 @@ static int ppgtt_bind_vma(struct i915_vma *vma, return err; } - /* Currently applicable only to VLV */ + /* Applicable to VLV, and gen8+ */ pte_flags = 0; if (vma->obj->gt_ro) pte_flags |= PTE_READ_ONLY; @@ -1044,10 +1044,11 @@ gen8_ppgtt_insert_pte_entries(struct i915_hw_ppgtt *ppgtt, struct i915_page_directory_pointer *pdp, struct sgt_dma *iter, struct gen8_insert_pte *idx, - enum i915_cache_level cache_level) + enum i915_cache_level cache_level, + u32 flags) { struct i915_page_directory *pd; - const gen8_pte_t pte_encode = gen8_pte_encode(0, cache_level, 0); + const gen8_pte_t pte_encode = gen8_pte_encode(0, cache_level, flags); gen8_pte_t *vaddr; bool ret; @@ -1098,14 +1099,14 @@ gen8_ppgtt_insert_pte_entries(struct i915_hw_ppgtt *ppgtt, static void gen8_ppgtt_insert_3lvl(struct i915_address_space *vm, struct i915_vma *vma, enum i915_cache_level cache_level, - u32 unused) + u32 flags) { struct i915_hw_ppgtt *ppgtt = i915_vm_to_ppgtt(vm); struct sgt_dma iter = sgt_dma(vma); struct gen8_insert_pte idx = gen8_insert_pte(vma->node.start); gen8_ppgtt_insert_pte_entries(ppgtt, &ppgtt->pdp, &iter, &idx, - cache_level); + cache_level, flags); vma->page_sizes.gtt = I915_GTT_PAGE_SIZE; } @@ -1113,9 +1114,10 @@ static void gen8_ppgtt_insert_3lvl(struct i915_address_space *vm, static void gen8_ppgtt_insert_huge_entries(struct i915_vma *vma, struct i915_page_directory_pointer **pdps, struct sgt_dma *iter, - enum i915_cache_level cache_level) + enum i915_cache_level cache_level, + u32 flags) { - const gen8_pte_t pte_encode = gen8_pte_encode(0, cache_level, 0); + const gen8_pte_t pte_encode = gen8_pte_encode(0, cache_level, flags); u64 start = vma->node.start; dma_addr_t rem = iter->sg->length; @@ -1231,19 +1233,21 @@ static void gen8_ppgtt_insert_huge_entries(struct i915_vma *vma, static void gen8_ppgtt_insert_4lvl(struct i915_address_space *vm, struct i915_vma *vma, enum i915_cache_level cache_level, - u32 unused) + u32 flags) { struct i915_hw_ppgtt *ppgtt = i915_vm_to_ppgtt(vm); struct sgt_dma iter = sgt_dma(vma); struct i915_page_directory_pointer **pdps = ppgtt->pml4.pdps; if (vma->page_sizes.sg > I915_GTT_PAGE_SIZE) { - gen8_ppgtt_insert_huge_entries(vma, pdps, &iter, cache_level); + gen8_ppgtt_insert_huge_entries(vma, pdps, &iter, cache_level, + flags); } else { struct gen8_insert_pte idx = gen8_insert_pte(vma->node.start); while (gen8_ppgtt_insert_pte_entries(ppgtt, pdps[idx.pml4e++], - &iter, &idx, cache_level)) + &iter, &idx, cache_level, + flags)) GEM_BUG_ON(idx.pml4e >= GEN8_PML4ES_PER_PML4); vma->page_sizes.gtt = I915_GTT_PAGE_SIZE; @@ -1658,6 +1662,9 @@ static struct i915_hw_ppgtt *gen8_ppgtt_create(struct drm_i915_private *i915) 1ULL << 48 : 1ULL << 32; + /* From bdw, there is support for read-only pages in the PPGTT */ + ppgtt->vm.has_read_only = true; + i915_address_space_init(&ppgtt->vm, i915); /* There are only few exceptions for gen >=6. chv and bxt. @@ -2472,7 +2479,7 @@ static void gen8_ggtt_insert_page(struct i915_address_space *vm, static void gen8_ggtt_insert_entries(struct i915_address_space *vm, struct i915_vma *vma, enum i915_cache_level level, - u32 unused) + u32 flags) { struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm); struct sgt_iter sgt_iter; @@ -2480,6 +2487,9 @@ static void gen8_ggtt_insert_entries(struct i915_address_space *vm, const gen8_pte_t pte_encode = gen8_pte_encode(0, level, 0); dma_addr_t addr; + /* The GTT does not support read-only mappings */ + GEM_BUG_ON(flags & PTE_READ_ONLY); + gtt_entries = (gen8_pte_t __iomem *)ggtt->gsm; gtt_entries += vma->node.start >> PAGE_SHIFT; for_each_sgt_dma(addr, sgt_iter, vma->pages) @@ -2606,13 +2616,14 @@ struct insert_entries { struct i915_address_space *vm; struct i915_vma *vma; enum i915_cache_level level; + u32 flags; }; static int bxt_vtd_ggtt_insert_entries__cb(void *_arg) { struct insert_entries *arg = _arg; - gen8_ggtt_insert_entries(arg->vm, arg->vma, arg->level, 0); + gen8_ggtt_insert_entries(arg->vm, arg->vma, arg->level, arg->flags); bxt_vtd_ggtt_wa(arg->vm); return 0; @@ -2621,9 +2632,9 @@ static int bxt_vtd_ggtt_insert_entries__cb(void *_arg) static void bxt_vtd_ggtt_insert_entries__BKL(struct i915_address_space *vm, struct i915_vma *vma, enum i915_cache_level level, - u32 unused) + u32 flags) { - struct insert_entries arg = { vm, vma, level }; + struct insert_entries arg = { vm, vma, level, flags }; stop_machine(bxt_vtd_ggtt_insert_entries__cb, &arg, NULL); } @@ -2714,7 +2725,7 @@ static int ggtt_bind_vma(struct i915_vma *vma, struct drm_i915_gem_object *obj = vma->obj; u32 pte_flags; - /* Currently applicable only to VLV */ + /* Applicable to VLV (gen8+ do not support RO in the GGTT) */ pte_flags = 0; if (obj->gt_ro) pte_flags |= PTE_READ_ONLY; @@ -3594,6 +3605,10 @@ int i915_ggtt_init_hw(struct drm_i915_private *dev_priv) */ mutex_lock(&dev_priv->drm.struct_mutex); i915_address_space_init(&ggtt->vm, dev_priv); + + /* Only VLV supports read-only GGTT mappings */ + ggtt->vm.has_read_only = IS_VALLEYVIEW(dev_priv); + if (!HAS_LLC(dev_priv) && !USES_PPGTT(dev_priv)) ggtt->vm.mm.color_adjust = i915_gtt_color_adjust; mutex_unlock(&dev_priv->drm.struct_mutex); diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index 14e62651010b0..2a116a91420bc 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -331,7 +331,12 @@ struct i915_address_space { struct list_head unbound_list; struct pagestash free_pages; - bool pt_kmap_wc; + + /* Some systems require uncached updates of the page directories */ + bool pt_kmap_wc:1; + + /* Some systems support read-only mappings for GGTT and/or PPGTT */ + bool has_read_only:1; /* FIXME: Need a more generic return type */ gen6_pte_t (*pte_encode)(dma_addr_t addr, diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index fab83e3c15029..6de88add508a4 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1085,6 +1085,7 @@ void intel_ring_unpin(struct intel_ring *ring) static struct i915_vma * intel_ring_create_vma(struct drm_i915_private *dev_priv, int size) { + struct i915_address_space *vm = &dev_priv->ggtt.vm; struct drm_i915_gem_object *obj; struct i915_vma *vma; @@ -1094,10 +1095,14 @@ intel_ring_create_vma(struct drm_i915_private *dev_priv, int size) if (IS_ERR(obj)) return ERR_CAST(obj); - /* mark ring buffers as read-only from GPU side by default */ - obj->gt_ro = 1; + /* + * Mark ring buffers as read-only from GPU side (so no stray overwrites) + * if supported by the platform's GGTT. + */ + if (vm->has_read_only) + obj->gt_ro = 1; - vma = i915_vma_instance(obj, &dev_priv->ggtt.vm, NULL); + vma = i915_vma_instance(obj, vm, NULL); if (IS_ERR(vma)) goto err; diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_context.c b/drivers/gpu/drm/i915/selftests/i915_gem_context.c index ab25902420333..2e2a3c44b8e92 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_context.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_context.c @@ -23,6 +23,7 @@ */ #include "../i915_selftest.h" +#include "i915_random.h" #include "igt_flush_test.h" #include "mock_drm.h" @@ -252,9 +253,9 @@ static int cpu_check(struct drm_i915_gem_object *obj, unsigned int max) } for (; m < DW_PER_PAGE; m++) { - if (map[m] != 0xdeadbeef) { + if (map[m] != STACK_MAGIC) { pr_err("Invalid value at page %d, offset %d: found %x expected %x\n", - n, m, map[m], 0xdeadbeef); + n, m, map[m], STACK_MAGIC); err = -EINVAL; goto out_unmap; } @@ -310,7 +311,7 @@ create_test_object(struct i915_gem_context *ctx, if (err) return ERR_PTR(err); - err = cpu_fill(obj, 0xdeadbeef); + err = cpu_fill(obj, STACK_MAGIC); if (err) { pr_err("Failed to fill object with cpu, err=%d\n", err); @@ -432,6 +433,110 @@ static int igt_ctx_exec(void *arg) return err; } +static int igt_ctx_readonly(void *arg) +{ + struct drm_i915_private *i915 = arg; + struct drm_i915_gem_object *obj = NULL; + struct drm_file *file; + I915_RND_STATE(prng); + IGT_TIMEOUT(end_time); + LIST_HEAD(objects); + struct i915_gem_context *ctx; + struct i915_hw_ppgtt *ppgtt; + unsigned long ndwords, dw; + int err = -ENODEV; + + /* + * Create a few read-only objects (with the occasional writable object) + * and try to write into these object checking that the GPU discards + * any write to a read-only object. + */ + + file = mock_file(i915); + if (IS_ERR(file)) + return PTR_ERR(file); + + mutex_lock(&i915->drm.struct_mutex); + + ctx = i915_gem_create_context(i915, file->driver_priv); + if (IS_ERR(ctx)) { + err = PTR_ERR(ctx); + goto out_unlock; + } + + ppgtt = ctx->ppgtt ?: i915->mm.aliasing_ppgtt; + if (!ppgtt || !ppgtt->vm.has_read_only) { + err = 0; + goto out_unlock; + } + + ndwords = 0; + dw = 0; + while (!time_after(jiffies, end_time)) { + struct intel_engine_cs *engine; + unsigned int id; + + for_each_engine(engine, i915, id) { + if (!intel_engine_can_store_dword(engine)) + continue; + + if (!obj) { + obj = create_test_object(ctx, file, &objects); + if (IS_ERR(obj)) { + err = PTR_ERR(obj); + goto out_unlock; + } + + obj->gt_ro = prandom_u32_state(&prng); + } + + intel_runtime_pm_get(i915); + err = gpu_fill(obj, ctx, engine, dw); + intel_runtime_pm_put(i915); + if (err) { + pr_err("Failed to fill dword %lu [%lu/%lu] with gpu (%s) in ctx %u [full-ppgtt? %s], err=%d\n", + ndwords, dw, max_dwords(obj), + engine->name, ctx->hw_id, + yesno(!!ctx->ppgtt), err); + goto out_unlock; + } + + if (++dw == max_dwords(obj)) { + obj = NULL; + dw = 0; + } + ndwords++; + } + } + pr_info("Submitted %lu dwords (across %u engines)\n", + ndwords, INTEL_INFO(i915)->num_rings); + + dw = 0; + list_for_each_entry(obj, &objects, st_link) { + unsigned int rem = + min_t(unsigned int, ndwords - dw, max_dwords(obj)); + unsigned int num_writes; + + num_writes = rem; + if (obj->gt_ro) + num_writes = 0; + + err = cpu_check(obj, num_writes); + if (err) + break; + + dw += rem; + } + +out_unlock: + if (igt_flush_test(i915, I915_WAIT_LOCKED)) + err = -EIO; + mutex_unlock(&i915->drm.struct_mutex); + + mock_file_free(i915, file); + return err; +} + static __maybe_unused const char * __engine_name(struct drm_i915_private *i915, unsigned int engines) { @@ -608,6 +713,7 @@ int i915_gem_context_live_selftests(struct drm_i915_private *dev_priv) static const struct i915_subtest tests[] = { SUBTEST(igt_switch_to_kernel_context), SUBTEST(igt_ctx_exec), + SUBTEST(igt_ctx_readonly), }; bool fake_alias = false; int err; -- GitLab From c9e666880de5a1fed04dc412b046916d542b72dd Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 12 Jul 2018 19:53:12 +0100 Subject: [PATCH 1057/1506] drm/i915/gtt: Disable read-only support under GVT GVT is not propagating the PTE bits, and is always setting the read-write bit, thus breaking read-only support. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Zhenyu Wang <zhenyuw@linux.intel.com> Cc: Jon Bloomfield <jon.bloomfield@intel.com> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Matthew Auld <matthew.william.auld@gmail.com> Reviewed-by: Jon Bloomfield <jon.bloomfield@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180712185315.3288-3-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_gtt.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 734b67f7853c9..86a9618bab248 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1662,8 +1662,12 @@ static struct i915_hw_ppgtt *gen8_ppgtt_create(struct drm_i915_private *i915) 1ULL << 48 : 1ULL << 32; - /* From bdw, there is support for read-only pages in the PPGTT */ - ppgtt->vm.has_read_only = true; + /* + * From bdw, there is support for read-only pages in the PPGTT. + * + * XXX GVT is not honouring the lack of RW in the PTE bits. + */ + ppgtt->vm.has_read_only = !intel_vgpu_active(i915); i915_address_space_init(&ppgtt->vm, i915); -- GitLab From 3e977ac6179b39faa3c0eda5fce4f00663ae298d Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 12 Jul 2018 19:53:13 +0100 Subject: [PATCH 1058/1506] drm/i915: Prevent writing into a read-only object via a GGTT mmap If the user has created a read-only object, they should not be allowed to circumvent the write protection by using a GGTT mmapping. Deny it. Also most machines do not support read-only GGTT PTEs, so again we have to reject attempted writes. Fortunately, this is known a priori, so we can at least reject in the call to create the mmap (with a sanity check in the fault handler). v2: Check the vma->vm_flags during mmap() to allow readonly access. v3: Remove VM_MAYWRITE to curtail mprotect() Testcase: igt/gem_userptr_blits/readonly_mmap* Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Jon Bloomfield <jon.bloomfield@intel.com> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Matthew Auld <matthew.william.auld@gmail.com> Cc: David Herrmann <dh.herrmann@gmail.com> Reviewed-by: Matthew Auld <matthew.william.auld@gmail.com> #v1 Reviewed-by: Jon Bloomfield <jon.bloomfield@intel.com> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180712185315.3288-4-chris@chris-wilson.co.uk --- drivers/gpu/drm/drm_gem.c | 9 +++++++++ drivers/gpu/drm/i915/i915_gem.c | 4 ++++ drivers/gpu/drm/i915/i915_gem_gtt.c | 12 +++++++----- drivers/gpu/drm/i915/i915_gem_object.h | 13 ++++++++++++- drivers/gpu/drm/i915/intel_ringbuffer.c | 2 +- drivers/gpu/drm/i915/selftests/i915_gem_context.c | 5 +++-- include/drm/drm_vma_manager.h | 1 + 7 files changed, 37 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 4a16d7b26c89c..bf90625df3c5b 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -1036,6 +1036,15 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) return -EACCES; } + if (node->readonly) { + if (vma->vm_flags & VM_WRITE) { + drm_gem_object_put_unlocked(obj); + return -EINVAL; + } + + vma->vm_flags &= ~VM_MAYWRITE; + } + ret = drm_gem_mmap_obj(obj, drm_vma_node_size(node) << PAGE_SHIFT, vma); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index ed2be33ec58a3..1910c66f48e28 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2012,6 +2012,10 @@ vm_fault_t i915_gem_fault(struct vm_fault *vmf) pgoff_t page_offset; int ret; + /* Sanity check that we allow writing into this object */ + if (i915_gem_object_is_readonly(obj) && write) + return VM_FAULT_SIGBUS; + /* We don't use vmf->pgoff since that has the fake offset */ page_offset = (vmf->address - area->vm_start) >> PAGE_SHIFT; diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 86a9618bab248..3d75f2bb56233 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -206,7 +206,7 @@ static int ppgtt_bind_vma(struct i915_vma *vma, /* Applicable to VLV, and gen8+ */ pte_flags = 0; - if (vma->obj->gt_ro) + if (i915_gem_object_is_readonly(vma->obj)) pte_flags |= PTE_READ_ONLY; vma->vm->insert_entries(vma->vm, vma, cache_level, pte_flags); @@ -2491,8 +2491,10 @@ static void gen8_ggtt_insert_entries(struct i915_address_space *vm, const gen8_pte_t pte_encode = gen8_pte_encode(0, level, 0); dma_addr_t addr; - /* The GTT does not support read-only mappings */ - GEM_BUG_ON(flags & PTE_READ_ONLY); + /* + * Note that we ignore PTE_READ_ONLY here. The caller must be careful + * not to allow the user to override access to a read only page. + */ gtt_entries = (gen8_pte_t __iomem *)ggtt->gsm; gtt_entries += vma->node.start >> PAGE_SHIFT; @@ -2731,7 +2733,7 @@ static int ggtt_bind_vma(struct i915_vma *vma, /* Applicable to VLV (gen8+ do not support RO in the GGTT) */ pte_flags = 0; - if (obj->gt_ro) + if (i915_gem_object_is_readonly(obj)) pte_flags |= PTE_READ_ONLY; intel_runtime_pm_get(i915); @@ -2769,7 +2771,7 @@ static int aliasing_gtt_bind_vma(struct i915_vma *vma, /* Currently applicable only to VLV */ pte_flags = 0; - if (vma->obj->gt_ro) + if (i915_gem_object_is_readonly(vma->obj)) pte_flags |= PTE_READ_ONLY; if (flags & I915_VMA_LOCAL_BIND) { diff --git a/drivers/gpu/drm/i915/i915_gem_object.h b/drivers/gpu/drm/i915/i915_gem_object.h index c3c6f2e588fbe..56e9f00d2c4c1 100644 --- a/drivers/gpu/drm/i915/i915_gem_object.h +++ b/drivers/gpu/drm/i915/i915_gem_object.h @@ -141,7 +141,6 @@ struct drm_i915_gem_object { * Is the object to be mapped as read-only to the GPU * Only honoured if hardware has relevant pte bit */ - unsigned long gt_ro:1; unsigned int cache_level:3; unsigned int cache_coherent:2; #define I915_BO_CACHE_COHERENT_FOR_READ BIT(0) @@ -358,6 +357,18 @@ static inline void i915_gem_object_unlock(struct drm_i915_gem_object *obj) reservation_object_unlock(obj->resv); } +static inline void +i915_gem_object_set_readonly(struct drm_i915_gem_object *obj) +{ + obj->base.vma_node.readonly = true; +} + +static inline bool +i915_gem_object_is_readonly(const struct drm_i915_gem_object *obj) +{ + return obj->base.vma_node.readonly; +} + static inline bool i915_gem_object_has_struct_page(const struct drm_i915_gem_object *obj) { diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 6de88add508a4..69bd7f697f6da 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1100,7 +1100,7 @@ intel_ring_create_vma(struct drm_i915_private *dev_priv, int size) * if supported by the platform's GGTT. */ if (vm->has_read_only) - obj->gt_ro = 1; + i915_gem_object_set_readonly(obj); vma = i915_vma_instance(obj, vm, NULL); if (IS_ERR(vma)) diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_context.c b/drivers/gpu/drm/i915/selftests/i915_gem_context.c index 2e2a3c44b8e92..1c92560d35da6 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_context.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_context.c @@ -487,7 +487,8 @@ static int igt_ctx_readonly(void *arg) goto out_unlock; } - obj->gt_ro = prandom_u32_state(&prng); + if (prandom_u32_state(&prng) & 1) + i915_gem_object_set_readonly(obj); } intel_runtime_pm_get(i915); @@ -518,7 +519,7 @@ static int igt_ctx_readonly(void *arg) unsigned int num_writes; num_writes = rem; - if (obj->gt_ro) + if (i915_gem_object_is_readonly(obj)) num_writes = 0; err = cpu_check(obj, num_writes); diff --git a/include/drm/drm_vma_manager.h b/include/drm/drm_vma_manager.h index 8758df94e9a0f..c7987daeaed08 100644 --- a/include/drm/drm_vma_manager.h +++ b/include/drm/drm_vma_manager.h @@ -41,6 +41,7 @@ struct drm_vma_offset_node { rwlock_t vm_lock; struct drm_mm_node vm_node; struct rb_root vm_files; + bool readonly:1; }; struct drm_vma_offset_manager { -- GitLab From f8c1cce36ccb21b5e5ecc87fac65de0e29693f01 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 12 Jul 2018 19:53:14 +0100 Subject: [PATCH 1059/1506] drm/i915: Reject attempted pwrites into a read-only object If the user created a read-only object, they should not be allowed to circumvent the write protection using the pwrite ioctl. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Jon Bloomfield <jon.bloomfield@intel.com> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Matthew Auld <matthew.william.auld@gmail.com> Reviewed-by: Jon Bloomfield <jon.bloomfield@intel.com> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Reviewed-by: Matthew Auld <matthew.william.auld@gmail.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180712185315.3288-5-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 1910c66f48e28..42d24410a98c6 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1627,6 +1627,12 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, goto err; } + /* Writes not allowed into this read-only object */ + if (i915_gem_object_is_readonly(obj)) { + ret = -EINVAL; + goto err; + } + trace_i915_gem_object_pwrite(obj, args->offset, args->size); ret = -ENODEV; -- GitLab From 0b100760e3e8cbb2b5d09c1c2bcb01d50201c142 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 12 Jul 2018 20:14:30 +0100 Subject: [PATCH 1060/1506] drm/i915/userptr: Enable read-only support on gen8+ On gen8 and onwards, we can mark GPU accesses through the ppGTT as being read-only, that is cause any GPU write onto that page to be discarded (not triggering a fault). This is all that we need to finally support the read-only flag for userptr! v2: Check default address space for read only support as a proxy for the user context/ppgtt. Testcase: igt/gem_userptr_blits/readonly* Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Jon Bloomfield <jon.bloomfield@intel.com> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Reviewed-by: Matthew Auld <matthew.william.auld@gmail.com> Reviewed-by: Jon Bloomfield <jon.bloomfield@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180712191430.9269-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem_object.h | 1 - drivers/gpu/drm/i915/i915_gem_userptr.c | 18 ++++++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_object.h b/drivers/gpu/drm/i915/i915_gem_object.h index 56e9f00d2c4c1..83e5e01fa9eaa 100644 --- a/drivers/gpu/drm/i915/i915_gem_object.h +++ b/drivers/gpu/drm/i915/i915_gem_object.h @@ -267,7 +267,6 @@ struct drm_i915_gem_object { union { struct i915_gem_userptr { uintptr_t ptr; - unsigned read_only :1; struct i915_mm_struct *mm; struct i915_mmu_object *mmu_object; diff --git a/drivers/gpu/drm/i915/i915_gem_userptr.c b/drivers/gpu/drm/i915/i915_gem_userptr.c index 854bd51b9478a..dcd6e230d16aa 100644 --- a/drivers/gpu/drm/i915/i915_gem_userptr.c +++ b/drivers/gpu/drm/i915/i915_gem_userptr.c @@ -507,7 +507,7 @@ __i915_gem_userptr_get_pages_worker(struct work_struct *_work) struct mm_struct *mm = obj->userptr.mm->mm; unsigned int flags = 0; - if (!obj->userptr.read_only) + if (!i915_gem_object_is_readonly(obj)) flags |= FOLL_WRITE; ret = -EFAULT; @@ -643,7 +643,7 @@ static int i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj) if (pvec) /* defer to worker if malloc fails */ pinned = __get_user_pages_fast(obj->userptr.ptr, num_pages, - !obj->userptr.read_only, + !i915_gem_object_is_readonly(obj), pvec); } @@ -789,10 +789,15 @@ i915_gem_userptr_ioctl(struct drm_device *dev, return -EFAULT; if (args->flags & I915_USERPTR_READ_ONLY) { - /* On almost all of the current hw, we cannot tell the GPU that a - * page is readonly, so this is just a placeholder in the uAPI. + struct i915_hw_ppgtt *ppgtt; + + /* + * On almost all of the older hw, we cannot tell the GPU that + * a page is readonly. */ - return -ENODEV; + ppgtt = dev_priv->kernel_context->ppgtt; + if (!ppgtt || !ppgtt->vm.has_read_only) + return -ENODEV; } obj = i915_gem_object_alloc(dev_priv); @@ -806,7 +811,8 @@ i915_gem_userptr_ioctl(struct drm_device *dev, i915_gem_object_set_cache_coherency(obj, I915_CACHE_LLC); obj->userptr.ptr = args->user_ptr; - obj->userptr.read_only = !!(args->flags & I915_USERPTR_READ_ONLY); + if (args->flags & I915_USERPTR_READ_ONLY) + i915_gem_object_set_readonly(obj); /* And keep a pointer to the current->mm for resolving the user pages * at binding. This means that we need to hook into the mmu_notifier -- GitLab From 14aa521c5eb615c802d51e9e8884f2dbd35993a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Thu, 5 Jul 2018 19:43:50 +0300 Subject: [PATCH 1061/1506] drm/i915: Introduce for_each_intel_dp() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a convenience macro for iterating DP encoders. Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180705164357.28512-2-ville.syrjala@linux.intel.com Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> --- drivers/gpu/drm/i915/intel_display.h | 4 +++ drivers/gpu/drm/i915/intel_dp.c | 38 +++++----------------------- drivers/gpu/drm/i915/intel_drv.h | 14 ++++++++++ 3 files changed, 25 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.h b/drivers/gpu/drm/i915/intel_display.h index a77dd29db2ecb..7559dfc235a24 100644 --- a/drivers/gpu/drm/i915/intel_display.h +++ b/drivers/gpu/drm/i915/intel_display.h @@ -289,6 +289,10 @@ struct intel_link_m_n { &(dev)->mode_config.encoder_list, \ base.head) +#define for_each_intel_dp(dev, intel_encoder) \ + for_each_intel_encoder(dev, intel_encoder) \ + for_each_if(intel_encoder_is_dp(intel_encoder)) + #define for_each_intel_connector_iter(intel_connector, iter) \ while ((intel_connector = to_intel_connector(drm_connector_list_iter_next(iter)))) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 7d40bfcb1bbb4..f4662b2fb7ab4 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -600,14 +600,8 @@ static enum pipe vlv_find_free_pps(struct drm_i915_private *dev_priv) * We don't have power sequencer currently. * Pick one that's not used by other ports. */ - for_each_intel_encoder(&dev_priv->drm, encoder) { - struct intel_dp *intel_dp; - - if (encoder->type != INTEL_OUTPUT_DP && - encoder->type != INTEL_OUTPUT_EDP) - continue; - - intel_dp = enc_to_intel_dp(&encoder->base); + for_each_intel_dp(&dev_priv->drm, encoder) { + struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); if (encoder->type == INTEL_OUTPUT_EDP) { WARN_ON(intel_dp->active_pipe != INVALID_PIPE && @@ -799,19 +793,8 @@ void intel_power_sequencer_reset(struct drm_i915_private *dev_priv) * should use them always. */ - for_each_intel_encoder(&dev_priv->drm, encoder) { - struct intel_dp *intel_dp; - - if (encoder->type != INTEL_OUTPUT_DP && - encoder->type != INTEL_OUTPUT_EDP && - encoder->type != INTEL_OUTPUT_DDI) - continue; - - intel_dp = enc_to_intel_dp(&encoder->base); - - /* Skip pure DVI/HDMI DDI encoders */ - if (!i915_mmio_reg_valid(intel_dp->output_reg)) - continue; + for_each_intel_dp(&dev_priv->drm, encoder) { + struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); WARN_ON(intel_dp->active_pipe != INVALID_PIPE); @@ -3097,16 +3080,9 @@ static void vlv_steal_power_sequencer(struct drm_i915_private *dev_priv, lockdep_assert_held(&dev_priv->pps_mutex); - for_each_intel_encoder(&dev_priv->drm, encoder) { - struct intel_dp *intel_dp; - enum port port; - - if (encoder->type != INTEL_OUTPUT_DP && - encoder->type != INTEL_OUTPUT_EDP) - continue; - - intel_dp = enc_to_intel_dp(&encoder->base); - port = dp_to_dig_port(intel_dp)->base.port; + for_each_intel_dp(&dev_priv->drm, encoder) { + struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); + enum port port = encoder->port; WARN(intel_dp->active_pipe == pipe, "stealing pipe %c power sequencer from active (e)DP port %c\n", diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index a0e9a35b56582..2740a0ef3f497 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1275,6 +1275,20 @@ static inline struct intel_dp *enc_to_intel_dp(struct drm_encoder *encoder) return &enc_to_dig_port(encoder)->dp; } +static inline bool intel_encoder_is_dp(struct intel_encoder *encoder) +{ + switch (encoder->type) { + case INTEL_OUTPUT_DP: + case INTEL_OUTPUT_EDP: + return true; + case INTEL_OUTPUT_DDI: + /* Skip pure HDMI/DVI DDI encoders */ + return i915_mmio_reg_valid(enc_to_intel_dp(&encoder->base)->output_reg); + default: + return false; + } +} + static inline struct intel_digital_port * dp_to_dig_port(struct intel_dp *intel_dp) { -- GitLab From 4ef03f8354f592b237cff1774cc50e4e4eb63652 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Thu, 5 Jul 2018 19:43:51 +0300 Subject: [PATCH 1062/1506] drm/i915: Introduce intel_encoder_is_dig_port() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add intel_encoder_is_dig_port() to match intel_encoder_is_dp(). Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180705164357.28512-3-ville.syrjala@linux.intel.com Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> --- drivers/gpu/drm/i915/intel_drv.h | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 2740a0ef3f497..987fbb2ef911e 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1245,23 +1245,29 @@ intel_attached_encoder(struct drm_connector *connector) return to_intel_connector(connector)->encoder; } -static inline struct intel_digital_port * -enc_to_dig_port(struct drm_encoder *encoder) +static inline bool intel_encoder_is_dig_port(struct intel_encoder *encoder) { - struct intel_encoder *intel_encoder = to_intel_encoder(encoder); - - switch (intel_encoder->type) { + switch (encoder->type) { case INTEL_OUTPUT_DDI: - WARN_ON(!HAS_DDI(to_i915(encoder->dev))); - /* fall through */ case INTEL_OUTPUT_DP: case INTEL_OUTPUT_EDP: case INTEL_OUTPUT_HDMI: + return true; + default: + return false; + } +} + +static inline struct intel_digital_port * +enc_to_dig_port(struct drm_encoder *encoder) +{ + struct intel_encoder *intel_encoder = to_intel_encoder(encoder); + + if (intel_encoder_is_dig_port(intel_encoder)) return container_of(encoder, struct intel_digital_port, base.base); - default: + else return NULL; - } } static inline struct intel_dp_mst_encoder * -- GitLab From 1a4313d13b69318d11e3418b7193be6add511f69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Thu, 5 Jul 2018 19:43:52 +0300 Subject: [PATCH 1063/1506] drm/i915: Rewrite mst suspend/resume in terms of encoders MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather than looping over all the ports and picking the encoder based on the port, let's just loop over all the encoders instead. Gets rid of some irq_port[] usage, which is a bit of an eye sore. Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180705164357.28512-4-ville.syrjala@linux.intel.com Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> --- drivers/gpu/drm/i915/i915_drv.c | 4 ++-- drivers/gpu/drm/i915/intel_dp.c | 41 +++++++++++++++++++------------- drivers/gpu/drm/i915/intel_drv.h | 4 ++-- 3 files changed, 28 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index f059aa332323e..cfa7583cf4088 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1586,7 +1586,7 @@ static int i915_drm_suspend(struct drm_device *dev) intel_display_suspend(dev); - intel_dp_mst_suspend(dev); + intel_dp_mst_suspend(dev_priv); intel_runtime_pm_disable_interrupts(dev_priv); intel_hpd_cancel_work(dev_priv); @@ -1751,7 +1751,7 @@ static int i915_drm_resume(struct drm_device *dev) dev_priv->display.hpd_irq_setup(dev_priv); spin_unlock_irq(&dev_priv->irq_lock); - intel_dp_mst_resume(dev); + intel_dp_mst_resume(dev_priv); intel_display_resume(dev); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index f4662b2fb7ab4..18bcdab24baa5 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -6483,37 +6483,44 @@ bool intel_dp_init(struct drm_i915_private *dev_priv, return false; } -void intel_dp_mst_suspend(struct drm_device *dev) +void intel_dp_mst_suspend(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = to_i915(dev); - int i; + struct intel_encoder *encoder; + + for_each_intel_encoder(&dev_priv->drm, encoder) { + struct intel_dp *intel_dp; + + if (encoder->type != INTEL_OUTPUT_DDI) + continue; - /* disable MST */ - for (i = 0; i < I915_MAX_PORTS; i++) { - struct intel_digital_port *intel_dig_port = dev_priv->hotplug.irq_port[i]; + intel_dp = enc_to_intel_dp(&encoder->base); - if (!intel_dig_port || !intel_dig_port->dp.can_mst) + if (!intel_dp->can_mst) continue; - if (intel_dig_port->dp.is_mst) - drm_dp_mst_topology_mgr_suspend(&intel_dig_port->dp.mst_mgr); + if (intel_dp->is_mst) + drm_dp_mst_topology_mgr_suspend(&intel_dp->mst_mgr); } } -void intel_dp_mst_resume(struct drm_device *dev) +void intel_dp_mst_resume(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = to_i915(dev); - int i; + struct intel_encoder *encoder; - for (i = 0; i < I915_MAX_PORTS; i++) { - struct intel_digital_port *intel_dig_port = dev_priv->hotplug.irq_port[i]; + for_each_intel_encoder(&dev_priv->drm, encoder) { + struct intel_dp *intel_dp; int ret; - if (!intel_dig_port || !intel_dig_port->dp.can_mst) + if (encoder->type != INTEL_OUTPUT_DDI) + continue; + + intel_dp = enc_to_intel_dp(&encoder->base); + + if (!intel_dp->can_mst) continue; - ret = drm_dp_mst_topology_mgr_resume(&intel_dig_port->dp.mst_mgr); + ret = drm_dp_mst_topology_mgr_resume(&intel_dp->mst_mgr); if (ret) - intel_dp_check_mst_status(&intel_dig_port->dp); + intel_dp_check_mst_status(intel_dp); } } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 987fbb2ef911e..33c15fbc9cc10 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1698,8 +1698,8 @@ void intel_edp_backlight_off(const struct drm_connector_state *conn_state); void intel_edp_panel_vdd_on(struct intel_dp *intel_dp); void intel_edp_panel_on(struct intel_dp *intel_dp); void intel_edp_panel_off(struct intel_dp *intel_dp); -void intel_dp_mst_suspend(struct drm_device *dev); -void intel_dp_mst_resume(struct drm_device *dev); +void intel_dp_mst_suspend(struct drm_i915_private *dev_priv); +void intel_dp_mst_resume(struct drm_i915_private *dev_priv); int intel_dp_max_link_rate(struct intel_dp *intel_dp); int intel_dp_max_lane_count(struct intel_dp *intel_dp); int intel_dp_rate_select(struct intel_dp *intel_dp, int rate); -- GitLab From b6ca3eee18ba1ec97cad54b7f476bcfaca50c17c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Thu, 5 Jul 2018 19:43:53 +0300 Subject: [PATCH 1064/1506] drm/i915: Nuke dev_priv->irq_port[] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of looping over ports and hpd_pins, let's loop over the encoders when doing hotplug processing. And instead of depending on dev_priv->irq_port[] to tell us whether the encoder has the ->hpd_pulse() hook or not, we can just check for that directly. So we can just nuke irq_port[] entirely. Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180705164357.28512-5-ville.syrjala@linux.intel.com Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> --- drivers/gpu/drm/i915/i915_drv.h | 1 - drivers/gpu/drm/i915/intel_ddi.c | 1 - drivers/gpu/drm/i915/intel_dp.c | 1 - drivers/gpu/drm/i915/intel_drv.h | 2 + drivers/gpu/drm/i915/intel_hotplug.c | 61 +++++++++++++++------------- 5 files changed, 34 insertions(+), 32 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index f519485fcd736..059cef73eb288 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -299,7 +299,6 @@ struct i915_hotplug { u32 event_bits; struct delayed_work reenable_work; - struct intel_digital_port *irq_port[I915_MAX_PORTS]; u32 long_port_mask; u32 short_port_mask; struct work_struct dig_port_work; diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index e4caa902d88e2..39d66f8493fae 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -3639,7 +3639,6 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port) goto err; intel_dig_port->hpd_pulse = intel_dp_hpd_pulse; - dev_priv->hotplug.irq_port[port] = intel_dig_port; } /* In theory we don't need the encoder->type check, but leave it just in diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 18bcdab24baa5..fc05c82265511 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -6464,7 +6464,6 @@ bool intel_dp_init(struct drm_i915_private *dev_priv, intel_encoder->port = port; intel_dig_port->hpd_pulse = intel_dp_hpd_pulse; - dev_priv->hotplug.irq_port[port] = intel_dig_port; if (port != PORT_A) intel_infoframe_init(intel_dig_port); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 33c15fbc9cc10..a45f6324dd9b5 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -304,6 +304,8 @@ struct intel_panel { } backlight; }; +struct intel_digital_port; + /* * This structure serves as a translation layer between the generic HDCP code * and the bus-specific code. What that means is that HDCP over HDMI differs diff --git a/drivers/gpu/drm/i915/intel_hotplug.c b/drivers/gpu/drm/i915/intel_hotplug.c index 43aa92beff2a6..f862441158e1b 100644 --- a/drivers/gpu/drm/i915/intel_hotplug.c +++ b/drivers/gpu/drm/i915/intel_hotplug.c @@ -301,13 +301,18 @@ bool intel_encoder_hotplug(struct intel_encoder *encoder, return true; } +static bool intel_encoder_has_hpd_pulse(struct intel_encoder *encoder) +{ + return intel_encoder_is_dig_port(encoder) && + enc_to_dig_port(&encoder->base)->hpd_pulse != NULL; +} + static void i915_digport_work_func(struct work_struct *work) { struct drm_i915_private *dev_priv = container_of(work, struct drm_i915_private, hotplug.dig_port_work); u32 long_port_mask, short_port_mask; - struct intel_digital_port *intel_dig_port; - int i; + struct intel_encoder *encoder; u32 old_bits = 0; spin_lock_irq(&dev_priv->irq_lock); @@ -317,27 +322,27 @@ static void i915_digport_work_func(struct work_struct *work) dev_priv->hotplug.short_port_mask = 0; spin_unlock_irq(&dev_priv->irq_lock); - for (i = 0; i < I915_MAX_PORTS; i++) { - bool valid = false; - bool long_hpd = false; - intel_dig_port = dev_priv->hotplug.irq_port[i]; - if (!intel_dig_port || !intel_dig_port->hpd_pulse) + for_each_intel_encoder(&dev_priv->drm, encoder) { + struct intel_digital_port *dig_port; + enum port port = encoder->port; + bool long_hpd, short_hpd; + enum irqreturn ret; + + if (!intel_encoder_has_hpd_pulse(encoder)) continue; - if (long_port_mask & (1 << i)) { - valid = true; - long_hpd = true; - } else if (short_port_mask & (1 << i)) - valid = true; + long_hpd = long_port_mask & BIT(port); + short_hpd = short_port_mask & BIT(port); + + if (!long_hpd && !short_hpd) + continue; - if (valid) { - enum irqreturn ret; + dig_port = enc_to_dig_port(&encoder->base); - ret = intel_dig_port->hpd_pulse(intel_dig_port, long_hpd); - if (ret == IRQ_NONE) { - /* fall back to old school hpd */ - old_bits |= (1 << intel_dig_port->base.hpd_pin); - } + ret = dig_port->hpd_pulse(dig_port, long_hpd); + if (ret == IRQ_NONE) { + /* fall back to old school hpd */ + old_bits |= BIT(encoder->hpd_pin); } } @@ -418,26 +423,24 @@ static void i915_hotplug_work_func(struct work_struct *work) void intel_hpd_irq_handler(struct drm_i915_private *dev_priv, u32 pin_mask, u32 long_mask) { - int i; - enum port port; + struct intel_encoder *encoder; bool storm_detected = false; bool queue_dig = false, queue_hp = false; - bool is_dig_port; if (!pin_mask) return; spin_lock(&dev_priv->irq_lock); - for_each_hpd_pin(i) { + for_each_intel_encoder(&dev_priv->drm, encoder) { + enum hpd_pin i = encoder->hpd_pin; + bool has_hpd_pulse = intel_encoder_has_hpd_pulse(encoder); + if (!(BIT(i) & pin_mask)) continue; - port = intel_hpd_pin_to_port(dev_priv, i); - is_dig_port = port != PORT_NONE && - dev_priv->hotplug.irq_port[port]; - - if (is_dig_port) { + if (has_hpd_pulse) { bool long_hpd = long_mask & BIT(i); + enum port port = encoder->port; DRM_DEBUG_DRIVER("digital hpd port %c - %s\n", port_name(port), long_hpd ? "long" : "short"); @@ -470,7 +473,7 @@ void intel_hpd_irq_handler(struct drm_i915_private *dev_priv, if (dev_priv->hotplug.stats[i].state != HPD_ENABLED) continue; - if (!is_dig_port) { + if (!has_hpd_pulse) { dev_priv->hotplug.event_bits |= BIT(i); queue_hp = true; } -- GitLab From e9be285051e1ff447f43d09da4102aa30d8645d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Thu, 5 Jul 2018 19:43:54 +0300 Subject: [PATCH 1065/1506] drm/i915: s/int i/enum hpd_pin pin/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the enum hpd_pin type when talking about HPD pins, and rename the variable from a very nondescript 'i' to 'pin', a name we already use in other parts of the code. Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180705164357.28512-6-ville.syrjala@linux.intel.com Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> --- drivers/gpu/drm/i915/i915_irq.c | 12 ++++++------ drivers/gpu/drm/i915/intel_hotplug.c | 28 ++++++++++++++-------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 495b9d27990e7..bd9c77c804ab7 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1712,20 +1712,20 @@ static void intel_get_hpd_pins(struct drm_i915_private *dev_priv, bool long_pulse_detect(enum port port, u32 val)) { enum port port; - int i; + enum hpd_pin pin; - for_each_hpd_pin(i) { - if ((hpd[i] & hotplug_trigger) == 0) + for_each_hpd_pin(pin) { + if ((hpd[pin] & hotplug_trigger) == 0) continue; - *pin_mask |= BIT(i); + *pin_mask |= BIT(pin); - port = intel_hpd_pin_to_port(dev_priv, i); + port = intel_hpd_pin_to_port(dev_priv, pin); if (port == PORT_NONE) continue; if (long_pulse_detect(port, dig_hotplug_reg)) - *long_mask |= BIT(i); + *long_mask |= BIT(pin); } DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x, dig 0x%08x, pins 0x%08x\n", diff --git a/drivers/gpu/drm/i915/intel_hotplug.c b/drivers/gpu/drm/i915/intel_hotplug.c index f862441158e1b..d9d61d11dd2bf 100644 --- a/drivers/gpu/drm/i915/intel_hotplug.c +++ b/drivers/gpu/drm/i915/intel_hotplug.c @@ -241,25 +241,25 @@ static void intel_hpd_irq_storm_reenable_work(struct work_struct *work) container_of(work, typeof(*dev_priv), hotplug.reenable_work.work); struct drm_device *dev = &dev_priv->drm; - int i; + enum hpd_pin pin; intel_runtime_pm_get(dev_priv); spin_lock_irq(&dev_priv->irq_lock); - for_each_hpd_pin(i) { + for_each_hpd_pin(pin) { struct drm_connector *connector; struct drm_connector_list_iter conn_iter; - if (dev_priv->hotplug.stats[i].state != HPD_DISABLED) + if (dev_priv->hotplug.stats[pin].state != HPD_DISABLED) continue; - dev_priv->hotplug.stats[i].state = HPD_ENABLED; + dev_priv->hotplug.stats[pin].state = HPD_ENABLED; drm_connector_list_iter_begin(dev, &conn_iter); drm_for_each_connector_iter(connector, &conn_iter) { struct intel_connector *intel_connector = to_intel_connector(connector); - if (intel_connector->encoder->hpd_pin == i) { + if (intel_connector->encoder->hpd_pin == pin) { if (connector->polled != intel_connector->polled) DRM_DEBUG_DRIVER("Reenabling HPD on connector %s\n", connector->name); @@ -432,14 +432,14 @@ void intel_hpd_irq_handler(struct drm_i915_private *dev_priv, spin_lock(&dev_priv->irq_lock); for_each_intel_encoder(&dev_priv->drm, encoder) { - enum hpd_pin i = encoder->hpd_pin; + enum hpd_pin pin = encoder->hpd_pin; bool has_hpd_pulse = intel_encoder_has_hpd_pulse(encoder); - if (!(BIT(i) & pin_mask)) + if (!(BIT(pin) & pin_mask)) continue; if (has_hpd_pulse) { - bool long_hpd = long_mask & BIT(i); + bool long_hpd = long_mask & BIT(pin); enum port port = encoder->port; DRM_DEBUG_DRIVER("digital hpd port %c - %s\n", port_name(port), @@ -458,7 +458,7 @@ void intel_hpd_irq_handler(struct drm_i915_private *dev_priv, } } - if (dev_priv->hotplug.stats[i].state == HPD_DISABLED) { + if (dev_priv->hotplug.stats[pin].state == HPD_DISABLED) { /* * On GMCH platforms the interrupt mask bits only * prevent irq generation, not the setting of the @@ -466,20 +466,20 @@ void intel_hpd_irq_handler(struct drm_i915_private *dev_priv, * interrupts on saner platforms. */ WARN_ONCE(!HAS_GMCH_DISPLAY(dev_priv), - "Received HPD interrupt on pin %d although disabled\n", i); + "Received HPD interrupt on pin %d although disabled\n", pin); continue; } - if (dev_priv->hotplug.stats[i].state != HPD_ENABLED) + if (dev_priv->hotplug.stats[pin].state != HPD_ENABLED) continue; if (!has_hpd_pulse) { - dev_priv->hotplug.event_bits |= BIT(i); + dev_priv->hotplug.event_bits |= BIT(pin); queue_hp = true; } - if (intel_hpd_irq_storm_detect(dev_priv, i)) { - dev_priv->hotplug.event_bits &= ~BIT(i); + if (intel_hpd_irq_storm_detect(dev_priv, pin)) { + dev_priv->hotplug.event_bits &= ~BIT(pin); storm_detected = true; } } -- GitLab From af92058ff021d5d8b0523baf76e709fe2fc3aa0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Thu, 5 Jul 2018 19:43:55 +0300 Subject: [PATCH 1066/1506] drm/i915: Pass hpd_pin to long_pulse_detect() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We're doing a pointless translation from hpd_pin to port simply for passing the thing to long_pulse_detect(). Let's pass the hpd_pin directly instead. This removes the assumption that the hpd_pin and port always match. The only other place where we make that assumption anymore is intel_hpd_pin_default() and that's fine as it's what determines the relationship between the two. If we ever get hardware where the hpd pins are wired in more interesting ways it should be trivial to handle from now on. This should also fix the IS_CNL_WITH_PORT_F() case as that mapped pin E back to port F and passed that to spt_port_hotplug2_long_detect() which would always return false for port F. Now that we pass in pin E directly it'll actually do the right thing. Cc: Rodrigo Vivi <rodrigo.vivi@intel.com> Fixes: cf53902f48c3 ("drm/i915/cnl: Add HPD support for Port F.") Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180705164357.28512-7-ville.syrjala@linux.intel.com Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> --- drivers/gpu/drm/i915/i915_drv.h | 2 - drivers/gpu/drm/i915/i915_irq.c | 95 +++++++++++++--------------- drivers/gpu/drm/i915/intel_hotplug.c | 31 --------- 3 files changed, 45 insertions(+), 83 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 059cef73eb288..08d4303abb146 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2745,8 +2745,6 @@ void intel_hpd_irq_handler(struct drm_i915_private *dev_priv, void intel_hpd_init(struct drm_i915_private *dev_priv); void intel_hpd_init_work(struct drm_i915_private *dev_priv); void intel_hpd_cancel_work(struct drm_i915_private *dev_priv); -enum port intel_hpd_pin_to_port(struct drm_i915_private *dev_priv, - enum hpd_pin pin); enum hpd_pin intel_hpd_pin_default(struct drm_i915_private *dev_priv, enum port port); bool intel_hpd_disable(struct drm_i915_private *dev_priv, enum hpd_pin pin); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index bd9c77c804ab7..6d80eb6b89985 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1576,122 +1576,122 @@ static void gen8_gt_irq_handler(struct drm_i915_private *i915, } } -static bool gen11_port_hotplug_long_detect(enum port port, u32 val) +static bool gen11_port_hotplug_long_detect(enum hpd_pin pin, u32 val) { - switch (port) { - case PORT_C: + switch (pin) { + case HPD_PORT_C: return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC1); - case PORT_D: + case HPD_PORT_D: return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC2); - case PORT_E: + case HPD_PORT_E: return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC3); - case PORT_F: + case HPD_PORT_F: return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC4); default: return false; } } -static bool bxt_port_hotplug_long_detect(enum port port, u32 val) +static bool bxt_port_hotplug_long_detect(enum hpd_pin pin, u32 val) { - switch (port) { - case PORT_A: + switch (pin) { + case HPD_PORT_A: return val & PORTA_HOTPLUG_LONG_DETECT; - case PORT_B: + case HPD_PORT_B: return val & PORTB_HOTPLUG_LONG_DETECT; - case PORT_C: + case HPD_PORT_C: return val & PORTC_HOTPLUG_LONG_DETECT; default: return false; } } -static bool icp_ddi_port_hotplug_long_detect(enum port port, u32 val) +static bool icp_ddi_port_hotplug_long_detect(enum hpd_pin pin, u32 val) { - switch (port) { - case PORT_A: + switch (pin) { + case HPD_PORT_A: return val & ICP_DDIA_HPD_LONG_DETECT; - case PORT_B: + case HPD_PORT_B: return val & ICP_DDIB_HPD_LONG_DETECT; default: return false; } } -static bool icp_tc_port_hotplug_long_detect(enum port port, u32 val) +static bool icp_tc_port_hotplug_long_detect(enum hpd_pin pin, u32 val) { - switch (port) { - case PORT_C: + switch (pin) { + case HPD_PORT_C: return val & ICP_TC_HPD_LONG_DETECT(PORT_TC1); - case PORT_D: + case HPD_PORT_D: return val & ICP_TC_HPD_LONG_DETECT(PORT_TC2); - case PORT_E: + case HPD_PORT_E: return val & ICP_TC_HPD_LONG_DETECT(PORT_TC3); - case PORT_F: + case HPD_PORT_F: return val & ICP_TC_HPD_LONG_DETECT(PORT_TC4); default: return false; } } -static bool spt_port_hotplug2_long_detect(enum port port, u32 val) +static bool spt_port_hotplug2_long_detect(enum hpd_pin pin, u32 val) { - switch (port) { - case PORT_E: + switch (pin) { + case HPD_PORT_E: return val & PORTE_HOTPLUG_LONG_DETECT; default: return false; } } -static bool spt_port_hotplug_long_detect(enum port port, u32 val) +static bool spt_port_hotplug_long_detect(enum hpd_pin pin, u32 val) { - switch (port) { - case PORT_A: + switch (pin) { + case HPD_PORT_A: return val & PORTA_HOTPLUG_LONG_DETECT; - case PORT_B: + case HPD_PORT_B: return val & PORTB_HOTPLUG_LONG_DETECT; - case PORT_C: + case HPD_PORT_C: return val & PORTC_HOTPLUG_LONG_DETECT; - case PORT_D: + case HPD_PORT_D: return val & PORTD_HOTPLUG_LONG_DETECT; default: return false; } } -static bool ilk_port_hotplug_long_detect(enum port port, u32 val) +static bool ilk_port_hotplug_long_detect(enum hpd_pin pin, u32 val) { - switch (port) { - case PORT_A: + switch (pin) { + case HPD_PORT_A: return val & DIGITAL_PORTA_HOTPLUG_LONG_DETECT; default: return false; } } -static bool pch_port_hotplug_long_detect(enum port port, u32 val) +static bool pch_port_hotplug_long_detect(enum hpd_pin pin, u32 val) { - switch (port) { - case PORT_B: + switch (pin) { + case HPD_PORT_B: return val & PORTB_HOTPLUG_LONG_DETECT; - case PORT_C: + case HPD_PORT_C: return val & PORTC_HOTPLUG_LONG_DETECT; - case PORT_D: + case HPD_PORT_D: return val & PORTD_HOTPLUG_LONG_DETECT; default: return false; } } -static bool i9xx_port_hotplug_long_detect(enum port port, u32 val) +static bool i9xx_port_hotplug_long_detect(enum hpd_pin pin, u32 val) { - switch (port) { - case PORT_B: + switch (pin) { + case HPD_PORT_B: return val & PORTB_HOTPLUG_INT_LONG_PULSE; - case PORT_C: + case HPD_PORT_C: return val & PORTC_HOTPLUG_INT_LONG_PULSE; - case PORT_D: + case HPD_PORT_D: return val & PORTD_HOTPLUG_INT_LONG_PULSE; default: return false; @@ -1709,9 +1709,8 @@ static void intel_get_hpd_pins(struct drm_i915_private *dev_priv, u32 *pin_mask, u32 *long_mask, u32 hotplug_trigger, u32 dig_hotplug_reg, const u32 hpd[HPD_NUM_PINS], - bool long_pulse_detect(enum port port, u32 val)) + bool long_pulse_detect(enum hpd_pin pin, u32 val)) { - enum port port; enum hpd_pin pin; for_each_hpd_pin(pin) { @@ -1720,11 +1719,7 @@ static void intel_get_hpd_pins(struct drm_i915_private *dev_priv, *pin_mask |= BIT(pin); - port = intel_hpd_pin_to_port(dev_priv, pin); - if (port == PORT_NONE) - continue; - - if (long_pulse_detect(port, dig_hotplug_reg)) + if (long_pulse_detect(pin, dig_hotplug_reg)) *long_mask |= BIT(pin); } diff --git a/drivers/gpu/drm/i915/intel_hotplug.c b/drivers/gpu/drm/i915/intel_hotplug.c index d9d61d11dd2bf..648a13c6043c0 100644 --- a/drivers/gpu/drm/i915/intel_hotplug.c +++ b/drivers/gpu/drm/i915/intel_hotplug.c @@ -76,37 +76,6 @@ * it will use i915_hotplug_work_func where this logic is handled. */ -/** - * intel_hpd_port - return port hard associated with certain pin. - * @dev_priv: private driver data pointer - * @pin: the hpd pin to get associated port - * - * Return port that is associatade with @pin and PORT_NONE if no port is - * hard associated with that @pin. - */ -enum port intel_hpd_pin_to_port(struct drm_i915_private *dev_priv, - enum hpd_pin pin) -{ - switch (pin) { - case HPD_PORT_A: - return PORT_A; - case HPD_PORT_B: - return PORT_B; - case HPD_PORT_C: - return PORT_C; - case HPD_PORT_D: - return PORT_D; - case HPD_PORT_E: - if (IS_CNL_WITH_PORT_F(dev_priv)) - return PORT_F; - return PORT_E; - case HPD_PORT_F: - return PORT_F; - default: - return PORT_NONE; /* no port for this pin */ - } -} - /** * intel_hpd_pin_default - return default pin associated with certain port. * @dev_priv: private driver data pointer -- GitLab From f88f047812c5977636a5c2ebb9c0b05fe788acf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Thu, 5 Jul 2018 19:43:57 +0300 Subject: [PATCH 1067/1506] drm/i915: Print the long_mask alongside the pin_mask MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We're printing out which pins got a hotplug, so why not also print out which pins detected the long pulse as opposed to a short pulse. Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180705164357.28512-9-ville.syrjala@linux.intel.com Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> --- drivers/gpu/drm/i915/i915_irq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 6d80eb6b89985..6975a169c4e4a 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1723,8 +1723,8 @@ static void intel_get_hpd_pins(struct drm_i915_private *dev_priv, *long_mask |= BIT(pin); } - DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x, dig 0x%08x, pins 0x%08x\n", - hotplug_trigger, dig_hotplug_reg, *pin_mask); + DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x, dig 0x%08x, pins 0x%08x, long 0x%08x\n", + hotplug_trigger, dig_hotplug_reg, *pin_mask, *long_mask); } -- GitLab From 90a460d5dd205b1b39dae3dad041a37cf7c4241d Mon Sep 17 00:00:00 2001 From: Sean Paul <seanpaul@chromium.org> Date: Fri, 13 Jul 2018 11:34:44 -0400 Subject: [PATCH 1068/1506] drm: Fix kerneldoc for DRM_MODE_PROP_IMMUTABLE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Noticed this while browsing the docs. Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Sean Paul <seanpaul@chromium.org> Link: https://patchwork.freedesktop.org/patch/msgid/20180713153444.95466-1-seanpaul@chromium.org --- include/drm/drm_property.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/drm/drm_property.h b/include/drm/drm_property.h index 1d5c0b2a8956a..c030f6ccab99c 100644 --- a/include/drm/drm_property.h +++ b/include/drm/drm_property.h @@ -147,10 +147,10 @@ struct drm_property { * properties are not exposed to legacy userspace. * * DRM_MODE_PROP_IMMUTABLE - * Set for properties where userspace cannot be changed by + * Set for properties whose values cannot be changed by * userspace. The kernel is allowed to update the value of these * properties. This is generally used to expose probe state to - * usersapce, e.g. the EDID, or the connector path property on DP + * userspace, e.g. the EDID, or the connector path property on DP * MST sinks. */ uint32_t flags; -- GitLab From ce6058039bca7f1f11f1723549eec1bc069dcb28 Mon Sep 17 00:00:00 2001 From: Ayan Kumar Halder <ayan.halder@arm.com> Date: Tue, 10 Jul 2018 14:18:54 +0100 Subject: [PATCH 1069/1506] drm/arm/malidp: Add modifier definitions for describing Arm Framebuffer Compression (AFBC). AFBC is a proprietary lossless image compression protocol and format. It provides fine-grained random access and minimizes the amount of data transferred between IP blocks. AFBC has several features which may be supported and/or used, which are represented using bits in the modifier. Not all combinations are valid, and different devices or use-cases may support different combinations. Changes from v2:- - Added ack by Maarten Lankhorst Signed-off-by: Rosen Zhelev <rosen.zhelev@arm.com> Signed-off-by: Ayan Kumar halder <ayan.halder@arm.com> Reviewed-by: Brian Starkey <brian.starkey@arm.com> Reviewed-by: Liviu Dudau <liviu.dudau@arm.com> Reviewed-by: James (Qian) Wang <james.qian.wang@arm.com> Acked-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Link: https://lkml.org/lkml/2018/7/10/360 --- include/uapi/drm/drm_fourcc.h | 83 +++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h index d5e52350a3aae..d43949b5bb3e3 100644 --- a/include/uapi/drm/drm_fourcc.h +++ b/include/uapi/drm/drm_fourcc.h @@ -183,6 +183,7 @@ extern "C" { #define DRM_FORMAT_MOD_VENDOR_QCOM 0x05 #define DRM_FORMAT_MOD_VENDOR_VIVANTE 0x06 #define DRM_FORMAT_MOD_VENDOR_BROADCOM 0x07 +#define DRM_FORMAT_MOD_VENDOR_ARM 0x08 /* add more to the end as needed */ #define DRM_FORMAT_RESERVED ((1ULL << 56) - 1) @@ -485,6 +486,88 @@ extern "C" { */ #define DRM_FORMAT_MOD_BROADCOM_UIF fourcc_mod_code(BROADCOM, 6) +/* + * Arm Framebuffer Compression (AFBC) modifiers + * + * AFBC is a proprietary lossless image compression protocol and format. + * It provides fine-grained random access and minimizes the amount of data + * transferred between IP blocks. + * + * AFBC has several features which may be supported and/or used, which are + * represented using bits in the modifier. Not all combinations are valid, + * and different devices or use-cases may support different combinations. + */ +#define DRM_FORMAT_MOD_ARM_AFBC(__afbc_mode) fourcc_mod_code(ARM, __afbc_mode) + +/* + * AFBC superblock size + * + * Indicates the superblock size(s) used for the AFBC buffer. The buffer + * size (in pixels) must be aligned to a multiple of the superblock size. + * Four lowest significant bits(LSBs) are reserved for block size. + */ +#define AFBC_FORMAT_MOD_BLOCK_SIZE_MASK 0xf +#define AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 (1ULL) +#define AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 (2ULL) + +/* + * AFBC lossless colorspace transform + * + * Indicates that the buffer makes use of the AFBC lossless colorspace + * transform. + */ +#define AFBC_FORMAT_MOD_YTR (1ULL << 4) + +/* + * AFBC block-split + * + * Indicates that the payload of each superblock is split. The second + * half of the payload is positioned at a predefined offset from the start + * of the superblock payload. + */ +#define AFBC_FORMAT_MOD_SPLIT (1ULL << 5) + +/* + * AFBC sparse layout + * + * This flag indicates that the payload of each superblock must be stored at a + * predefined position relative to the other superblocks in the same AFBC + * buffer. This order is the same order used by the header buffer. In this mode + * each superblock is given the same amount of space as an uncompressed + * superblock of the particular format would require, rounding up to the next + * multiple of 128 bytes in size. + */ +#define AFBC_FORMAT_MOD_SPARSE (1ULL << 6) + +/* + * AFBC copy-block restrict + * + * Buffers with this flag must obey the copy-block restriction. The restriction + * is such that there are no copy-blocks referring across the border of 8x8 + * blocks. For the subsampled data the 8x8 limitation is also subsampled. + */ +#define AFBC_FORMAT_MOD_CBR (1ULL << 7) + +/* + * AFBC tiled layout + * + * The tiled layout groups superblocks in 8x8 or 4x4 tiles, where all + * superblocks inside a tile are stored together in memory. 8x8 tiles are used + * for pixel formats up to and including 32 bpp while 4x4 tiles are used for + * larger bpp formats. The order between the tiles is scan line. + * When the tiled layout is used, the buffer size (in pixels) must be aligned + * to the tile size. + */ +#define AFBC_FORMAT_MOD_TILED (1ULL << 8) + +/* + * AFBC solid color blocks + * + * Indicates that the buffer makes use of solid-color blocks, whereby bandwidth + * can be reduced if a whole superblock is a single color. + */ +#define AFBC_FORMAT_MOD_SC (1ULL << 9) + #if defined(__cplusplus) } #endif -- GitLab From 3479fc248bf383549ff629c607df0486813e14fd Mon Sep 17 00:00:00 2001 From: Daniel Vetter <daniel.vetter@ffwll.ch> Date: Mon, 9 Jul 2018 10:40:02 +0200 Subject: [PATCH 1070/1506] drm: move drv test macros out of drmP.h Last bit the prevented us from starting to delete the drmP.h monster includes from source files! Also add kernel-doc while moving them. A nice consistent drm_dev_ prefix would be cute for these, but since they're used everywhere I've figured I'll leave this bikeshed aside for now. Reviewed-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180709084016.23750-2-daniel.vetter@ffwll.ch --- include/drm/drmP.h | 19 ------------------- include/drm/drm_drv.h | 29 +++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/include/drm/drmP.h b/include/drm/drmP.h index c5dfbdb7271d7..f7a19c2a7a807 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -102,25 +102,6 @@ struct pci_controller; #define DRM_SWITCH_POWER_CHANGING 2 #define DRM_SWITCH_POWER_DYNAMIC_OFF 3 -static inline bool drm_core_check_feature(struct drm_device *dev, int feature) -{ - return dev->driver->driver_features & feature; -} - -/** - * drm_drv_uses_atomic_modeset - check if the driver implements - * atomic_commit() - * @dev: DRM device - * - * This check is useful if drivers do not have DRIVER_ATOMIC set but - * have atomic modesetting internally implemented. - */ -static inline bool drm_drv_uses_atomic_modeset(struct drm_device *dev) -{ - return drm_core_check_feature(dev, DRIVER_ATOMIC) || - dev->mode_config.funcs->atomic_commit != NULL; -} - /* returns true if currently okay to sleep */ static inline bool drm_can_sleep(void) { diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h index 7e545f5f94d36..46a8009784df1 100644 --- a/include/drm/drm_drv.h +++ b/include/drm/drm_drv.h @@ -649,6 +649,35 @@ static inline bool drm_dev_is_unplugged(struct drm_device *dev) return true; } +/** + * drm_core_check_feature - check driver feature flags + * @dev: DRM device to check + * @feature: feature flag + * + * This checks @dev for driver features, see &drm_driver.driver_features and the + * various DRIVER_\* flags. + * + * Returns true if the @feature is supported, false otherwise. + */ +static inline bool drm_core_check_feature(struct drm_device *dev, int feature) +{ + return dev->driver->driver_features & feature; +} + +/** + * drm_drv_uses_atomic_modeset - check if the driver implements + * atomic_commit() + * @dev: DRM device + * + * This check is useful if drivers do not have DRIVER_ATOMIC set but + * have atomic modesetting internally implemented. + */ +static inline bool drm_drv_uses_atomic_modeset(struct drm_device *dev) +{ + return drm_core_check_feature(dev, DRIVER_ATOMIC) || + dev->mode_config.funcs->atomic_commit != NULL; +} + int drm_dev_set_unique(struct drm_device *dev, const char *name); -- GitLab From aab999a66e4bc448a439733d60c83c86bee4c2be Mon Sep 17 00:00:00 2001 From: Daniel Vetter <daniel.vetter@ffwll.ch> Date: Mon, 9 Jul 2018 10:40:04 +0200 Subject: [PATCH 1071/1506] drm/doc: switch drm_connector_state to inline comments For consistency. Also spelled out the docs for ->best_encoder a bit more while at it. Reviewed-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180709084016.23750-4-daniel.vetter@ffwll.ch --- include/drm/drm_connector.h | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index a5179eb9e56fe..99fd75d7a3a9b 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -378,12 +378,9 @@ struct drm_tv_connector_state { /** * struct drm_connector_state - mutable connector state - * @connector: backpointer to the connector - * @best_encoder: can be used by helpers and drivers to select the encoder - * @state: backpointer to global drm_atomic_state - * @tv: TV connector state */ struct drm_connector_state { + /** @connector: backpointer to the connector */ struct drm_connector *connector; /** @@ -394,6 +391,13 @@ struct drm_connector_state { */ struct drm_crtc *crtc; + /** + * @best_encoder: + * + * Used by the atomic helpers to select the encoder, through the + * &drm_connector_helper_funcs.atomic_best_encoder or + * &drm_connector_helper_funcs.best_encoder callbacks. + */ struct drm_encoder *best_encoder; /** @@ -402,6 +406,7 @@ struct drm_connector_state { */ enum drm_link_status link_status; + /** @state: backpointer to global drm_atomic_state */ struct drm_atomic_state *state; /** @@ -411,6 +416,7 @@ struct drm_connector_state { */ struct drm_crtc_commit *commit; + /** @tv: TV connector state */ struct drm_tv_connector_state tv; /** -- GitLab From 92e1d26324e095252f3baf2c953615715c7c2a89 Mon Sep 17 00:00:00 2001 From: Daniel Vetter <daniel.vetter@ffwll.ch> Date: Mon, 9 Jul 2018 10:40:05 +0200 Subject: [PATCH 1072/1506] drm/doc: polish for sturct drm_connector - switch everything over to inline comments - add notes about locking, links to functions and other related stuff - also include a note about Ville's soon-to-be-merged drm_connector_for_each_possible_encoder(). Also check that all the hyperlinks in drm_connector.h work and fix them as needed. Reviewed-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180709084016.23750-5-daniel.vetter@ffwll.ch --- include/drm/drm_connector.h | 191 ++++++++++++++++++++++-------------- 1 file changed, 120 insertions(+), 71 deletions(-) diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 99fd75d7a3a9b..e09e16b3e0542 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -561,8 +561,7 @@ struct drm_connector_funcs { * received for this output connector->edid must be NULL. * * Drivers using the probe helpers should use - * drm_helper_probe_single_connector_modes() or - * drm_helper_probe_single_connector_modes_nomerge() to implement this + * drm_helper_probe_single_connector_modes() to implement this * function. * * RETURNS: @@ -773,45 +772,6 @@ struct drm_cmdline_mode { /** * struct drm_connector - central DRM connector control structure - * @dev: parent DRM device - * @kdev: kernel device for sysfs attributes - * @attr: sysfs attributes - * @head: list management - * @base: base KMS object - * @name: human readable name, can be overwritten by the driver - * @connector_type: one of the DRM_MODE_CONNECTOR_<foo> types from drm_mode.h - * @connector_type_id: index into connector type enum - * @interlace_allowed: can this connector handle interlaced modes? - * @doublescan_allowed: can this connector handle doublescan? - * @stereo_allowed: can this connector handle stereo modes? - * @funcs: connector control functions - * @edid_blob_ptr: DRM property containing EDID if present - * @properties: property tracking for this connector - * @dpms: current dpms state - * @helper_private: mid-layer private data - * @cmdline_mode: mode line parsed from the kernel cmdline for this connector - * @force: a DRM_FORCE_<foo> state for forced mode sets - * @override_edid: has the EDID been overwritten through debugfs for testing? - * @encoder_ids: valid encoders for this connector - * @eld: EDID-like data, if present - * @latency_present: AV delay info from ELD, if found - * @video_latency: video latency info from ELD, if found - * @audio_latency: audio latency info from ELD, if found - * @null_edid_counter: track sinks that give us all zeros for the EDID - * @bad_edid_counter: track sinks that give us an EDID with invalid checksum - * @edid_corrupt: indicates whether the last read EDID was corrupt - * @debugfs_entry: debugfs directory for this connector - * @has_tile: is this connector connected to a tiled monitor - * @tile_group: tile group for the connected monitor - * @tile_is_single_monitor: whether the tile is one monitor housing - * @num_h_tile: number of horizontal tiles in the tile group - * @num_v_tile: number of vertical tiles in the tile group - * @tile_h_loc: horizontal location of this tile - * @tile_v_loc: vertical location of this tile - * @tile_h_size: horizontal size of this tile. - * @tile_v_size: vertical size of this tile. - * @scaling_mode_property: Optional atomic property to control the upscaling. - * @content_protection_property: Optional property to control content protection * * Each connector may be connected to one or more CRTCs, or may be clonable by * another connector if they can share a CRTC. Each connector also has a specific @@ -819,13 +779,27 @@ struct drm_cmdline_mode { * span multiple monitors). */ struct drm_connector { + /** @dev: parent DRM device */ struct drm_device *dev; + /** @kdev: kernel device for sysfs attributes */ struct device *kdev; + /** @attr: sysfs attributes */ struct device_attribute *attr; + + /** + * @head: + * + * List of all connectors on a @dev, linked from + * &drm_mode_config.connector_list. Protected by + * &drm_mode_config.connector_list_lock, but please only use + * &drm_connector_list_iter to walk this list. + */ struct list_head head; + /** @base: base KMS object */ struct drm_mode_object base; + /** @name: human readable name, can be overwritten by the driver */ char *name; /** @@ -843,10 +817,30 @@ struct drm_connector { */ unsigned index; + /** + * @connector_type: + * one of the DRM_MODE_CONNECTOR_<foo> types from drm_mode.h + */ int connector_type; + /** @connector_type_id: index into connector type enum */ int connector_type_id; + /** + * @interlace_allowed: + * Can this connector handle interlaced modes? Only used by + * drm_helper_probe_single_connector_modes() for mode filtering. + */ bool interlace_allowed; + /** + * @doublescan_allowed: + * Can this connector handle doublescan? Only used by + * drm_helper_probe_single_connector_modes() for mode filtering. + */ bool doublescan_allowed; + /** + * @stereo_allowed: + * Can this connector handle stereo modes? Only used by + * drm_helper_probe_single_connector_modes() for mode filtering. + */ bool stereo_allowed; /** @@ -895,45 +889,42 @@ struct drm_connector { * Protected by &drm_mode_config.mutex. */ struct drm_display_info display_info; + + /** @funcs: connector control functions */ const struct drm_connector_funcs *funcs; + /** + * @edid_blob_ptr: DRM property containing EDID if present. Protected by + * &drm_mode_config.mutex. This should be updated only by calling + * drm_mode_connector_update_edid_property(). + */ struct drm_property_blob *edid_blob_ptr; + + /** @properties: property tracking for this connector */ struct drm_object_properties properties; + /** + * @scaling_mode_property: Optional atomic property to control the + * upscaling. See drm_connector_attach_content_protection_property(). + */ struct drm_property *scaling_mode_property; /** * @content_protection_property: DRM ENUM property for content - * protection + * protection. See drm_connector_attach_content_protection_property(). */ struct drm_property *content_protection_property; /** * @path_blob_ptr: * - * DRM blob property data for the DP MST path property. + * DRM blob property data for the DP MST path property. This should only + * be updated by calling drm_mode_connector_set_path_property(). */ struct drm_property_blob *path_blob_ptr; - /** - * @tile_blob_ptr: - * - * DRM blob property data for the tile property (used mostly by DP MST). - * This is meant for screens which are driven through separate display - * pipelines represented by &drm_crtc, which might not be running with - * genlocked clocks. For tiled panels which are genlocked, like - * dual-link LVDS or dual-link DSI, the driver should try to not expose - * the tiling and virtualize both &drm_crtc and &drm_plane if needed. - */ - struct drm_property_blob *tile_blob_ptr; - -/* should we poll this connector for connects and disconnects */ -/* hot plug detectable */ #define DRM_CONNECTOR_POLL_HPD (1 << 0) -/* poll for connections */ #define DRM_CONNECTOR_POLL_CONNECT (1 << 1) -/* can cleanly poll for disconnections without flickering the screen */ -/* DACs should rarely do this without a lot of testing */ #define DRM_CONNECTOR_POLL_DISCONNECT (1 << 2) /** @@ -950,25 +941,40 @@ struct drm_connector { * Periodically poll the connector for connection. * * DRM_CONNECTOR_POLL_DISCONNECT - * Periodically poll the connector for disconnection. + * Periodically poll the connector for disconnection, without + * causing flickering even when the connector is in use. DACs should + * rarely do this without a lot of testing. * * Set to 0 for connectors that don't support connection status * discovery. */ uint8_t polled; - /* requested DPMS state */ + /** + * @dpms: Current dpms state. For legacy drivers the + * &drm_connector_funcs.dpms callback must update this. For atomic + * drivers, this is handled by the core atomic code, and drivers must + * only take &drm_crtc_state.active into account. + */ int dpms; + /** @helper_private: mid-layer private data */ const struct drm_connector_helper_funcs *helper_private; - /* forced on connector */ + /** @cmdline_mode: mode line parsed from the kernel cmdline for this connector */ struct drm_cmdline_mode cmdline_mode; + /** @force: a DRM_FORCE_<foo> state for forced mode sets */ enum drm_connector_force force; + /** @override_edid: has the EDID been overwritten through debugfs for testing? */ bool override_edid; #define DRM_CONNECTOR_MAX_ENCODER 3 + /** + * @encoder_ids: Valid encoders for this connector. Please only use + * drm_connector_for_each_possible_encoder() to enumerate these. + */ uint32_t encoder_ids[DRM_CONNECTOR_MAX_ENCODER]; + /** * @encoder: Currently bound encoder driving this connector, if any. * Only really meaningful for non-atomic drivers. Atomic drivers should @@ -978,19 +984,37 @@ struct drm_connector { struct drm_encoder *encoder; #define MAX_ELD_BYTES 128 - /* EDID bits */ + /** @eld: EDID-like data, if present */ uint8_t eld[MAX_ELD_BYTES]; + /** @latency_present: AV delay info from ELD, if found */ bool latency_present[2]; - int video_latency[2]; /* [0]: progressive, [1]: interlaced */ + /** + * @video_latency: Video latency info from ELD, if found. + * [0]: progressive, [1]: interlaced + */ + int video_latency[2]; + /** + * @audio_latency: audio latency info from ELD, if found + * [0]: progressive, [1]: interlaced + */ int audio_latency[2]; - int null_edid_counter; /* needed to workaround some HW bugs where we get all 0s */ + /** + * @null_edid_counter: track sinks that give us all zeros for the EDID. + * Needed to workaround some HW bugs where we get all 0s + */ + int null_edid_counter; + + /** @bad_edid_counter: track sinks that give us an EDID with invalid checksum */ unsigned bad_edid_counter; - /* Flag for raw EDID header corruption - used in Displayport - * compliance testing - * Displayport Link CTS Core 1.2 rev1.1 4.2.2.6 + /** + * @edid_corrupt: Indicates whether the last read EDID was corrupt. Used + * in Displayport compliance testing - Displayport Link CTS Core 1.2 + * rev1.1 4.2.2.6 */ bool edid_corrupt; + /** @debugfs_entry: debugfs directory for this connector */ struct dentry *debugfs_entry; /** @@ -998,7 +1022,7 @@ struct drm_connector { * * Current atomic state for this connector. * - * This is protected by @drm_mode_config.connection_mutex. Note that + * This is protected by &drm_mode_config.connection_mutex. Note that * nonblocking atomic commits access the current connector state without * taking locks. Either by going through the &struct drm_atomic_state * pointers, see for_each_oldnew_connector_in_state(), @@ -1009,19 +1033,44 @@ struct drm_connector { */ struct drm_connector_state *state; - /* DisplayID bits */ + /* DisplayID bits. FIXME: Extract into a substruct? */ + + /** + * @tile_blob_ptr: + * + * DRM blob property data for the tile property (used mostly by DP MST). + * This is meant for screens which are driven through separate display + * pipelines represented by &drm_crtc, which might not be running with + * genlocked clocks. For tiled panels which are genlocked, like + * dual-link LVDS or dual-link DSI, the driver should try to not expose + * the tiling and virtualize both &drm_crtc and &drm_plane if needed. + * + * This should only be updated by calling + * drm_mode_connector_set_tile_property(). + */ + struct drm_property_blob *tile_blob_ptr; + + /** @has_tile: is this connector connected to a tiled monitor */ bool has_tile; + /** @tile_group: tile group for the connected monitor */ struct drm_tile_group *tile_group; + /** @tile_is_single_monitor: whether the tile is one monitor housing */ bool tile_is_single_monitor; + /** @num_h_tile: number of horizontal tiles in the tile group */ + /** @num_v_tile: number of vertical tiles in the tile group */ uint8_t num_h_tile, num_v_tile; + /** @tile_h_loc: horizontal location of this tile */ + /** @tile_v_loc: vertical location of this tile */ uint8_t tile_h_loc, tile_v_loc; + /** @tile_h_size: horizontal size of this tile. */ + /** @tile_v_size: vertical size of this tile. */ uint16_t tile_h_size, tile_v_size; /** * @free_node: * - * List used only by &drm_connector_iter to be able to clean up a + * List used only by &drm_connector_list_iter to be able to clean up a * connector from any context, in conjunction with * &drm_mode_config.connector_free_work. */ -- GitLab From c555f02371c338b06752577aebf738dbdb6907bd Mon Sep 17 00:00:00 2001 From: Daniel Vetter <daniel.vetter@ffwll.ch> Date: Mon, 9 Jul 2018 10:40:06 +0200 Subject: [PATCH 1073/1506] drm: drop _mode_ from update_edit_property() Just makes it longer, and for most things in drm_connector.[hc] we just use the drm_connector_ prefix. Done with sed + a bit of manual fixup for the indenting. Reviewed-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180709084016.23750-6-daniel.vetter@ffwll.ch --- drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c | 4 ++-- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 4 ++-- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c | 4 ++-- drivers/gpu/drm/ast/ast_mode.c | 4 ++-- drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 2 +- drivers/gpu/drm/bridge/analogix-anx78xx.c | 4 ++-- drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 4 ++-- drivers/gpu/drm/bridge/dumb-vga-dac.c | 2 +- drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c | 2 +- drivers/gpu/drm/bridge/nxp-ptn3460.c | 2 +- drivers/gpu/drm/bridge/sii902x.c | 2 +- drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 2 +- drivers/gpu/drm/bridge/tc358767.c | 2 +- drivers/gpu/drm/bridge/ti-tfp410.c | 2 +- drivers/gpu/drm/drm_connector.c | 8 ++++---- drivers/gpu/drm/drm_debugfs.c | 4 ++-- drivers/gpu/drm/drm_probe_helper.c | 2 +- drivers/gpu/drm/exynos/exynos_drm_vidi.c | 2 +- drivers/gpu/drm/exynos/exynos_hdmi.c | 2 +- drivers/gpu/drm/gma500/cdv_intel_dp.c | 2 +- drivers/gpu/drm/gma500/cdv_intel_hdmi.c | 2 +- drivers/gpu/drm/gma500/oaktrail_hdmi.c | 2 +- drivers/gpu/drm/gma500/oaktrail_lvds.c | 2 +- drivers/gpu/drm/gma500/psb_intel_modes.c | 2 +- drivers/gpu/drm/gma500/psb_intel_sdvo.c | 2 +- drivers/gpu/drm/i2c/tda998x_drv.c | 2 +- drivers/gpu/drm/i915/intel_dp.c | 2 +- drivers/gpu/drm/i915/intel_lvds.c | 2 +- drivers/gpu/drm/i915/intel_modes.c | 2 +- drivers/gpu/drm/i915/intel_sdvo.c | 2 +- drivers/gpu/drm/imx/imx-ldb.c | 2 +- drivers/gpu/drm/imx/imx-tve.c | 2 +- drivers/gpu/drm/imx/parallel-display.c | 2 +- drivers/gpu/drm/mediatek/mtk_hdmi.c | 2 +- drivers/gpu/drm/mgag200/mgag200_mode.c | 2 +- drivers/gpu/drm/msm/edp/edp_connector.c | 2 +- drivers/gpu/drm/msm/hdmi/hdmi_connector.c | 2 +- drivers/gpu/drm/nouveau/dispnv50/disp.c | 2 +- drivers/gpu/drm/nouveau/nouveau_connector.c | 8 ++++---- drivers/gpu/drm/omapdrm/omap_connector.c | 4 ++-- drivers/gpu/drm/panel/panel-simple.c | 2 +- drivers/gpu/drm/radeon/radeon_connectors.c | 4 ++-- drivers/gpu/drm/radeon/radeon_dp_mst.c | 4 ++-- drivers/gpu/drm/rockchip/cdn-dp-core.c | 2 +- drivers/gpu/drm/rockchip/inno_hdmi.c | 2 +- drivers/gpu/drm/sti/sti_hdmi.c | 2 +- drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c | 2 +- drivers/gpu/drm/tegra/output.c | 2 +- drivers/gpu/drm/tilcdc/tilcdc_tfp410.c | 2 +- drivers/gpu/drm/udl/udl_connector.c | 2 +- drivers/gpu/drm/vc4/vc4_hdmi.c | 2 +- drivers/gpu/drm/zte/zx_hdmi.c | 2 +- drivers/gpu/drm/zte/zx_vga.c | 2 +- drivers/staging/vboxvideo/vbox_mode.c | 2 +- include/drm/drm_connector.h | 6 +++--- include/drm/drm_modeset_helper_vtables.h | 2 +- 56 files changed, 74 insertions(+), 74 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c index 881f7cb7ae6e6..c770d73352a79 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c @@ -334,11 +334,11 @@ static int amdgpu_connector_ddc_get_modes(struct drm_connector *connector) int ret; if (amdgpu_connector->edid) { - drm_mode_connector_update_edid_property(connector, amdgpu_connector->edid); + drm_connector_update_edid_property(connector, amdgpu_connector->edid); ret = drm_add_edid_modes(connector, amdgpu_connector->edid); return ret; } - drm_mode_connector_update_edid_property(connector, NULL); + drm_connector_update_edid_property(connector, NULL); return 0; } 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 66bd3cc3e3875..c4ab19831344c 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -900,14 +900,14 @@ amdgpu_dm_update_connector_after_detect(struct amdgpu_dm_connector *aconnector) (struct edid *) sink->dc_edid.raw_edid; - drm_mode_connector_update_edid_property(connector, + drm_connector_update_edid_property(connector, aconnector->edid); } amdgpu_dm_add_sink_to_freesync_module(connector, aconnector->edid); } else { amdgpu_dm_remove_sink_from_freesync_module(connector); - drm_mode_connector_update_edid_property(connector, NULL); + drm_connector_update_edid_property(connector, NULL); aconnector->num_modes = 0; aconnector->dc_sink = NULL; aconnector->edid = NULL; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index 4304d9e408b88..581bb75d08ebe 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -233,7 +233,7 @@ static int dm_dp_mst_get_modes(struct drm_connector *connector) edid = drm_dp_mst_get_edid(connector, &aconnector->mst_port->mst_mgr, aconnector->port); if (!edid) { - drm_mode_connector_update_edid_property( + drm_connector_update_edid_property( &aconnector->base, NULL); return ret; @@ -261,7 +261,7 @@ static int dm_dp_mst_get_modes(struct drm_connector *connector) connector, aconnector->edid); } - drm_mode_connector_update_edid_property( + drm_connector_update_edid_property( &aconnector->base, aconnector->edid); ret = drm_add_edid_modes(connector, aconnector->edid); diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index 036dff8a1f333..1bb8174ad1556 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -790,12 +790,12 @@ static int ast_get_modes(struct drm_connector *connector) if (!flags) edid = drm_get_edid(connector, &ast_connector->i2c->adapter); if (edid) { - drm_mode_connector_update_edid_property(&ast_connector->base, edid); + drm_connector_update_edid_property(&ast_connector->base, edid); ret = drm_add_edid_modes(connector, edid); kfree(edid); return ret; } else - drm_mode_connector_update_edid_property(&ast_connector->base, NULL); + drm_connector_update_edid_property(&ast_connector->base, NULL); return 0; } diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index 73021b388e12d..1f4745953aca6 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -601,7 +601,7 @@ static int adv7511_get_modes(struct adv7511 *adv7511, __adv7511_power_off(adv7511); - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); count = drm_add_edid_modes(connector, edid); adv7511_set_config_csc(adv7511, connector, adv7511->rgb, diff --git a/drivers/gpu/drm/bridge/analogix-anx78xx.c b/drivers/gpu/drm/bridge/analogix-anx78xx.c index b49043866be61..37f947dcadec0 100644 --- a/drivers/gpu/drm/bridge/analogix-anx78xx.c +++ b/drivers/gpu/drm/bridge/analogix-anx78xx.c @@ -969,8 +969,8 @@ static int anx78xx_get_modes(struct drm_connector *connector) goto unlock; } - err = drm_mode_connector_update_edid_property(connector, - anx78xx->edid); + err = drm_connector_update_edid_property(connector, + anx78xx->edid); if (err) { DRM_ERROR("Failed to update EDID property: %d\n", err); goto unlock; diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 2bcbfadb6ac55..288c015f7460a 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -1119,8 +1119,8 @@ static int analogix_dp_get_modes(struct drm_connector *connector) edid = drm_get_edid(connector, &dp->aux.ddc); pm_runtime_put(dp->dev); if (edid) { - drm_mode_connector_update_edid_property(&dp->connector, - edid); + drm_connector_update_edid_property(&dp->connector, + edid); num_modes += drm_add_edid_modes(&dp->connector, edid); kfree(edid); } diff --git a/drivers/gpu/drm/bridge/dumb-vga-dac.c b/drivers/gpu/drm/bridge/dumb-vga-dac.c index 9837c8d69e691..da99b8ba4ee1b 100644 --- a/drivers/gpu/drm/bridge/dumb-vga-dac.c +++ b/drivers/gpu/drm/bridge/dumb-vga-dac.c @@ -55,7 +55,7 @@ static int dumb_vga_get_modes(struct drm_connector *connector) goto fallback; } - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); kfree(edid); return ret; diff --git a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c index 7ccadba7c98cd..b49b543bd1f6c 100644 --- a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c +++ b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c @@ -152,7 +152,7 @@ static int ge_b850v3_lvds_get_modes(struct drm_connector *connector) ge_b850v3_lvds_ptr->edid = (struct edid *)stdp2690_get_edid(client); if (ge_b850v3_lvds_ptr->edid) { - drm_mode_connector_update_edid_property(connector, + drm_connector_update_edid_property(connector, ge_b850v3_lvds_ptr->edid); num_modes = drm_add_edid_modes(connector, ge_b850v3_lvds_ptr->edid); diff --git a/drivers/gpu/drm/bridge/nxp-ptn3460.c b/drivers/gpu/drm/bridge/nxp-ptn3460.c index d64a3283822ae..bd5c191858cb5 100644 --- a/drivers/gpu/drm/bridge/nxp-ptn3460.c +++ b/drivers/gpu/drm/bridge/nxp-ptn3460.c @@ -222,7 +222,7 @@ static int ptn3460_get_modes(struct drm_connector *connector) } ptn_bridge->edid = (struct edid *)edid; - drm_mode_connector_update_edid_property(connector, ptn_bridge->edid); + drm_connector_update_edid_property(connector, ptn_bridge->edid); num_modes = drm_add_edid_modes(connector, ptn_bridge->edid); diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c index 60373d7eb2202..cd331933c230c 100644 --- a/drivers/gpu/drm/bridge/sii902x.c +++ b/drivers/gpu/drm/bridge/sii902x.c @@ -170,7 +170,7 @@ static int sii902x_get_modes(struct drm_connector *connector) return ret; edid = drm_get_edid(connector, sii902x->i2c->adapter); - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); if (edid) { num = drm_add_edid_modes(connector, edid); kfree(edid); diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index 3c136f2b954fd..ab32aceb6f249 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -1922,7 +1922,7 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector) hdmi->sink_is_hdmi = drm_detect_hdmi_monitor(edid); hdmi->sink_has_audio = drm_detect_monitor_audio(edid); - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); cec_notifier_set_phys_addr_from_edid(hdmi->cec_notifier, edid); ret = drm_add_edid_modes(connector, edid); kfree(edid); diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 0fd9cf27542c3..ee2fd0a349b32 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -1140,7 +1140,7 @@ static int tc_connector_get_modes(struct drm_connector *connector) if (!edid) return 0; - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); count = drm_add_edid_modes(connector, edid); return count; diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c index acb857030951a..c81bf7910bbe0 100644 --- a/drivers/gpu/drm/bridge/ti-tfp410.c +++ b/drivers/gpu/drm/bridge/ti-tfp410.c @@ -62,7 +62,7 @@ static int tfp410_get_modes(struct drm_connector *connector) goto fallback; } - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); return drm_add_edid_modes(connector, edid); fallback: diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index 5ada0640de5ad..b2b182ffdbe93 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -814,7 +814,7 @@ DRM_ENUM_NAME_FN(drm_get_content_protection_name, drm_cp_enum_list) * Blob property which contains the current EDID read from the sink. This * is useful to parse sink identification information like vendor, model * and serial. Drivers should update this property by calling - * drm_mode_connector_update_edid_property(), usually after having parsed + * drm_connector_update_edid_property(), usually after having parsed * the EDID using drm_add_edid_modes(). Userspace cannot change this * property. * DPMS: @@ -1497,7 +1497,7 @@ int drm_mode_connector_set_tile_property(struct drm_connector *connector) EXPORT_SYMBOL(drm_mode_connector_set_tile_property); /** - * drm_mode_connector_update_edid_property - update the edid property of a connector + * drm_connector_update_edid_property - update the edid property of a connector * @connector: drm connector * @edid: new value of the edid property * @@ -1507,7 +1507,7 @@ EXPORT_SYMBOL(drm_mode_connector_set_tile_property); * Returns: * Zero on success, negative errno on failure. */ -int drm_mode_connector_update_edid_property(struct drm_connector *connector, +int drm_connector_update_edid_property(struct drm_connector *connector, const struct edid *edid) { struct drm_device *dev = connector->dev; @@ -1546,7 +1546,7 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector, dev->mode_config.edid_property); return ret; } -EXPORT_SYMBOL(drm_mode_connector_update_edid_property); +EXPORT_SYMBOL(drm_connector_update_edid_property); /** * drm_mode_connector_set_link_status_property - Set link status property of a connector diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index 50a20bfc07ead..6f28fe58f1696 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c @@ -314,13 +314,13 @@ static ssize_t edid_write(struct file *file, const char __user *ubuf, if (len == 5 && !strncmp(buf, "reset", 5)) { connector->override_edid = false; - ret = drm_mode_connector_update_edid_property(connector, NULL); + ret = drm_connector_update_edid_property(connector, NULL); } else if (len < EDID_LENGTH || EDID_LENGTH * (1 + edid->extensions) > len) ret = -EINVAL; else { connector->override_edid = false; - ret = drm_mode_connector_update_edid_property(connector, edid); + ret = drm_connector_update_edid_property(connector, edid); if (!ret) connector->override_edid = true; } diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 34fe2704a31c0..3d58e0eb26a47 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -472,7 +472,7 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, if (connector->status == connector_status_disconnected) { DRM_DEBUG_KMS("[CONNECTOR:%d:%s] disconnected\n", connector->base.id, connector->name); - drm_mode_connector_update_edid_property(connector, NULL); + drm_connector_update_edid_property(connector, NULL); verbose_prune = false; goto prune; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index e6b0940b1ac27..dfea61edba4a5 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -319,7 +319,7 @@ static int vidi_get_modes(struct drm_connector *connector) return -ENOMEM; } - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); return drm_add_edid_modes(connector, edid); } diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index db91932550cf7..6672d0ff0423a 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -888,7 +888,7 @@ static int hdmi_get_modes(struct drm_connector *connector) (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"), edid->width_cm, edid->height_cm); - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); cec_notifier_set_phys_addr_from_edid(hdata->notifier, edid); ret = drm_add_edid_modes(connector, edid); diff --git a/drivers/gpu/drm/gma500/cdv_intel_dp.c b/drivers/gpu/drm/gma500/cdv_intel_dp.c index 5ea785f07ba8e..90ed20083009f 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_dp.c +++ b/drivers/gpu/drm/gma500/cdv_intel_dp.c @@ -1770,7 +1770,7 @@ static int cdv_intel_dp_get_modes(struct drm_connector *connector) edid = drm_get_edid(connector, &intel_dp->adapter); if (edid) { - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); kfree(edid); } diff --git a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c index f0878998526ac..4e4e4a66eaee3 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c +++ b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c @@ -216,7 +216,7 @@ static int cdv_hdmi_get_modes(struct drm_connector *connector) edid = drm_get_edid(connector, &gma_encoder->i2c_bus->adapter); if (edid) { - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); kfree(edid); } diff --git a/drivers/gpu/drm/gma500/oaktrail_hdmi.c b/drivers/gpu/drm/gma500/oaktrail_hdmi.c index 78566a80ad255..c6d72de1c0548 100644 --- a/drivers/gpu/drm/gma500/oaktrail_hdmi.c +++ b/drivers/gpu/drm/gma500/oaktrail_hdmi.c @@ -578,7 +578,7 @@ static int oaktrail_hdmi_get_modes(struct drm_connector *connector) } if (edid) { - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); } return ret; diff --git a/drivers/gpu/drm/gma500/oaktrail_lvds.c b/drivers/gpu/drm/gma500/oaktrail_lvds.c index e6943fef0611d..83babb815a5d8 100644 --- a/drivers/gpu/drm/gma500/oaktrail_lvds.c +++ b/drivers/gpu/drm/gma500/oaktrail_lvds.c @@ -376,7 +376,7 @@ void oaktrail_lvds_init(struct drm_device *dev, * preferred mode is the right one. */ if (edid) { - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); drm_add_edid_modes(connector, edid); kfree(edid); diff --git a/drivers/gpu/drm/gma500/psb_intel_modes.c b/drivers/gpu/drm/gma500/psb_intel_modes.c index e5360726d80b7..fb4da3cd66816 100644 --- a/drivers/gpu/drm/gma500/psb_intel_modes.c +++ b/drivers/gpu/drm/gma500/psb_intel_modes.c @@ -66,7 +66,7 @@ int psb_intel_ddc_get_modes(struct drm_connector *connector, edid = drm_get_edid(connector, adapter); if (edid) { - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); kfree(edid); } diff --git a/drivers/gpu/drm/gma500/psb_intel_sdvo.c b/drivers/gpu/drm/gma500/psb_intel_sdvo.c index 1d40746ab6259..dd3cec0e3190c 100644 --- a/drivers/gpu/drm/gma500/psb_intel_sdvo.c +++ b/drivers/gpu/drm/gma500/psb_intel_sdvo.c @@ -1472,7 +1472,7 @@ static void psb_intel_sdvo_get_ddc_modes(struct drm_connector *connector) bool connector_is_digital = !!IS_TMDS(psb_intel_sdvo_connector); if (connector_is_digital == monitor_is_digital) { - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); drm_add_edid_modes(connector, edid); } diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index 0038c976536ac..d434f576e6b29 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -1243,7 +1243,7 @@ static int tda998x_connector_get_modes(struct drm_connector *connector) return 0; } - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); n = drm_add_edid_modes(connector, edid); kfree(edid); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index b021801dbd48a..c8268f3776029 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -6231,7 +6231,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, edid = drm_get_edid(connector, &intel_dp->aux.ddc); if (edid) { if (drm_add_edid_modes(connector, edid)) { - drm_mode_connector_update_edid_property(connector, + drm_connector_update_edid_property(connector, edid); } else { kfree(edid); diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index bb06744d28a43..ca55b0a82ba6d 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -1131,7 +1131,7 @@ void intel_lvds_init(struct drm_i915_private *dev_priv) intel_gmbus_get_adapter(dev_priv, pin)); if (edid) { if (drm_add_edid_modes(connector, edid)) { - drm_mode_connector_update_edid_property(connector, + drm_connector_update_edid_property(connector, edid); } else { kfree(edid); diff --git a/drivers/gpu/drm/i915/intel_modes.c b/drivers/gpu/drm/i915/intel_modes.c index b39846613e3c7..ca44bf368e242 100644 --- a/drivers/gpu/drm/i915/intel_modes.c +++ b/drivers/gpu/drm/i915/intel_modes.c @@ -40,7 +40,7 @@ int intel_connector_update_modes(struct drm_connector *connector, { int ret; - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); return ret; diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index e6a64b3ecd919..a88611a73b03c 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1913,7 +1913,7 @@ static void intel_sdvo_get_ddc_modes(struct drm_connector *connector) if (edid != NULL) { if (intel_sdvo_connector_matches_edid(to_intel_sdvo_connector(connector), edid)) { - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); drm_add_edid_modes(connector, edid); } diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c index 56dd7a9a8e254..ae81cbb75f515 100644 --- a/drivers/gpu/drm/imx/imx-ldb.c +++ b/drivers/gpu/drm/imx/imx-ldb.c @@ -143,7 +143,7 @@ static int imx_ldb_connector_get_modes(struct drm_connector *connector) imx_ldb_ch->edid = drm_get_edid(connector, imx_ldb_ch->ddc); if (imx_ldb_ch->edid) { - drm_mode_connector_update_edid_property(connector, + drm_connector_update_edid_property(connector, imx_ldb_ch->edid); num_modes = drm_add_edid_modes(connector, imx_ldb_ch->edid); } diff --git a/drivers/gpu/drm/imx/imx-tve.c b/drivers/gpu/drm/imx/imx-tve.c index bc27c26994641..1a4ced5c09b55 100644 --- a/drivers/gpu/drm/imx/imx-tve.c +++ b/drivers/gpu/drm/imx/imx-tve.c @@ -235,7 +235,7 @@ static int imx_tve_connector_get_modes(struct drm_connector *connector) edid = drm_get_edid(connector, tve->ddc); if (edid) { - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); kfree(edid); } diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c index aedecda9728a9..4fc1cf583435d 100644 --- a/drivers/gpu/drm/imx/parallel-display.c +++ b/drivers/gpu/drm/imx/parallel-display.c @@ -63,7 +63,7 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector) } if (imxpd->edid) { - drm_mode_connector_update_edid_property(connector, imxpd->edid); + drm_connector_update_edid_property(connector, imxpd->edid); num_modes = drm_add_edid_modes(connector, imxpd->edid); } diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c index 59a11026dceb4..835313940395d 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c @@ -1220,7 +1220,7 @@ static int mtk_hdmi_conn_get_modes(struct drm_connector *conn) hdmi->dvi_mode = !drm_detect_monitor_audio(edid); - drm_mode_connector_update_edid_property(conn, edid); + drm_connector_update_edid_property(conn, edid); ret = drm_add_edid_modes(conn, edid); kfree(edid); diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 8918539a19aa8..5f104f1391978 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -1553,7 +1553,7 @@ static int mga_vga_get_modes(struct drm_connector *connector) edid = drm_get_edid(connector, &mga_connector->i2c->adapter); if (edid) { - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); kfree(edid); } diff --git a/drivers/gpu/drm/msm/edp/edp_connector.c b/drivers/gpu/drm/msm/edp/edp_connector.c index 6f3fc6b0f0a31..0b5eac0541950 100644 --- a/drivers/gpu/drm/msm/edp/edp_connector.c +++ b/drivers/gpu/drm/msm/edp/edp_connector.c @@ -56,7 +56,7 @@ static int edp_connector_get_modes(struct drm_connector *connector) if (ret) return ret; - drm_mode_connector_update_edid_property(connector, drm_edid); + drm_connector_update_edid_property(connector, drm_edid); if (drm_edid) ret = drm_add_edid_modes(connector, drm_edid); diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c index c0848dfedd506..07feacc5a4414 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c @@ -392,7 +392,7 @@ static int msm_hdmi_connector_get_modes(struct drm_connector *connector) hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl); hdmi->hdmi_mode = drm_detect_hdmi_monitor(edid); - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); if (edid) { ret = drm_add_edid_modes(connector, edid); diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index b83465ae7c1bc..2fabb69e452b0 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -850,7 +850,7 @@ nv50_mstc_get_modes(struct drm_connector *connector) int ret = 0; mstc->edid = drm_dp_mst_get_edid(&mstc->connector, mstc->port->mgr, mstc->port); - drm_mode_connector_update_edid_property(&mstc->connector, mstc->edid); + drm_connector_update_edid_property(&mstc->connector, mstc->edid); if (mstc->edid) ret = drm_add_edid_modes(&mstc->connector, mstc->edid); diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index bb46c1d489cf4..22a15478d23dc 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -550,7 +550,7 @@ nouveau_connector_detect(struct drm_connector *connector, bool force) /* Cleanup the previous EDID block. */ if (nv_connector->edid) { - drm_mode_connector_update_edid_property(connector, NULL); + drm_connector_update_edid_property(connector, NULL); kfree(nv_connector->edid); nv_connector->edid = NULL; } @@ -575,7 +575,7 @@ nouveau_connector_detect(struct drm_connector *connector, bool force) else nv_connector->edid = drm_get_edid(connector, i2c); - drm_mode_connector_update_edid_property(connector, + drm_connector_update_edid_property(connector, nv_connector->edid); if (!nv_connector->edid) { NV_ERROR(drm, "DDC responded, but no EDID for %s\n", @@ -657,7 +657,7 @@ nouveau_connector_detect_lvds(struct drm_connector *connector, bool force) /* Cleanup the previous EDID block. */ if (nv_connector->edid) { - drm_mode_connector_update_edid_property(connector, NULL); + drm_connector_update_edid_property(connector, NULL); kfree(nv_connector->edid); nv_connector->edid = NULL; } @@ -721,7 +721,7 @@ nouveau_connector_detect_lvds(struct drm_connector *connector, bool force) status = connector_status_unknown; #endif - drm_mode_connector_update_edid_property(connector, nv_connector->edid); + drm_connector_update_edid_property(connector, nv_connector->edid); nouveau_connector_set_encoder(connector, nv_encoder); return status; } diff --git a/drivers/gpu/drm/omapdrm/omap_connector.c b/drivers/gpu/drm/omapdrm/omap_connector.c index 5cde26ac937bd..2ddb856666c46 100644 --- a/drivers/gpu/drm/omapdrm/omap_connector.c +++ b/drivers/gpu/drm/omapdrm/omap_connector.c @@ -126,14 +126,14 @@ static int omap_connector_get_modes(struct drm_connector *connector) if ((dssdrv->read_edid(dssdev, edid, MAX_EDID) > 0) && drm_edid_is_valid(edid)) { - drm_mode_connector_update_edid_property( + drm_connector_update_edid_property( connector, edid); n = drm_add_edid_modes(connector, edid); omap_connector->hdmi_mode = drm_detect_hdmi_monitor(edid); } else { - drm_mode_connector_update_edid_property( + drm_connector_update_edid_property( connector, NULL); } diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 86fec03dd2604..5b5d0a24e713e 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -252,7 +252,7 @@ static int panel_simple_get_modes(struct drm_panel *panel) /* probe EDID if a DDC bus is available */ if (p->ddc) { struct edid *edid = drm_get_edid(panel->connector, p->ddc); - drm_mode_connector_update_edid_property(panel->connector, edid); + drm_connector_update_edid_property(panel->connector, edid); if (edid) { num += drm_add_edid_modes(panel->connector, edid); kfree(edid); diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 0655698f29566..414642e5b7a31 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -368,11 +368,11 @@ static int radeon_ddc_get_modes(struct drm_connector *connector) int ret; if (radeon_connector->edid) { - drm_mode_connector_update_edid_property(connector, radeon_connector->edid); + drm_connector_update_edid_property(connector, radeon_connector->edid); ret = drm_add_edid_modes(connector, radeon_connector->edid); return ret; } - drm_mode_connector_update_edid_property(connector, NULL); + drm_connector_update_edid_property(connector, NULL); return 0; } diff --git a/drivers/gpu/drm/radeon/radeon_dp_mst.c b/drivers/gpu/drm/radeon/radeon_dp_mst.c index cd8a3ee16649f..37956cfc0b6d5 100644 --- a/drivers/gpu/drm/radeon/radeon_dp_mst.c +++ b/drivers/gpu/drm/radeon/radeon_dp_mst.c @@ -195,11 +195,11 @@ static int radeon_dp_mst_get_ddc_modes(struct drm_connector *connector) radeon_connector->edid = edid; DRM_DEBUG_KMS("edid retrieved %p\n", edid); if (radeon_connector->edid) { - drm_mode_connector_update_edid_property(&radeon_connector->base, radeon_connector->edid); + drm_connector_update_edid_property(&radeon_connector->base, radeon_connector->edid); ret = drm_add_edid_modes(&radeon_connector->base, radeon_connector->edid); return ret; } - drm_mode_connector_update_edid_property(&radeon_connector->base, NULL); + drm_connector_update_edid_property(&radeon_connector->base, NULL); return ret; } diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index c6fbdcd87c16d..a40cb2be50e13 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -275,7 +275,7 @@ static int cdn_dp_connector_get_modes(struct drm_connector *connector) dp->sink_has_audio = drm_detect_monitor_audio(edid); ret = drm_add_edid_modes(connector, edid); if (ret) - drm_mode_connector_update_edid_property(connector, + drm_connector_update_edid_property(connector, edid); } mutex_unlock(&dp->lock); diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 88d0774c97bdc..510fcb33e31d5 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -565,7 +565,7 @@ static int inno_hdmi_connector_get_modes(struct drm_connector *connector) if (edid) { hdmi->hdmi_data.sink_is_hdmi = drm_detect_hdmi_monitor(edid); hdmi->hdmi_data.sink_has_audio = drm_detect_monitor_audio(edid); - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); kfree(edid); } diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index 58f4311025128..0c3008356ab87 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c @@ -977,7 +977,7 @@ static int sti_hdmi_connector_get_modes(struct drm_connector *connector) cec_notifier_set_phys_addr_from_edid(hdmi->notifier, edid); count = drm_add_edid_modes(connector, edid); - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); kfree(edid); return count; diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c index fa4bcd092eaf2..9b4b1d0154232 100644 --- a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c +++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c @@ -220,7 +220,7 @@ static int sun4i_hdmi_get_modes(struct drm_connector *connector) DRM_DEBUG_DRIVER("Monitor is %s monitor\n", hdmi->hdmi_monitor ? "an HDMI" : "a DVI"); - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); cec_s_phys_addr_from_edid(hdmi->cec_adap, edid); ret = drm_add_edid_modes(connector, edid); kfree(edid); diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c index 0c0936511bb48..c662efc7e4139 100644 --- a/drivers/gpu/drm/tegra/output.c +++ b/drivers/gpu/drm/tegra/output.c @@ -37,7 +37,7 @@ int tegra_output_connector_get_modes(struct drm_connector *connector) edid = drm_get_edid(connector, output->ddc); cec_notifier_set_phys_addr_from_edid(output->notifier, edid); - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); if (edid) { err = drm_add_edid_modes(connector, edid); diff --git a/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c b/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c index c45cabb38db01..46dacca3cce88 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c @@ -173,7 +173,7 @@ static int tfp410_connector_get_modes(struct drm_connector *connector) edid = drm_get_edid(connector, tfp410_connector->mod->i2c); - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); if (edid) { ret = drm_add_edid_modes(connector, edid); diff --git a/drivers/gpu/drm/udl/udl_connector.c b/drivers/gpu/drm/udl/udl_connector.c index 09dc585aa46f8..8fac12e1a1a4d 100644 --- a/drivers/gpu/drm/udl/udl_connector.c +++ b/drivers/gpu/drm/udl/udl_connector.c @@ -99,7 +99,7 @@ static int udl_get_modes(struct drm_connector *connector) struct udl_drm_connector, connector); - drm_mode_connector_update_edid_property(connector, udl_connector->edid); + drm_connector_update_edid_property(connector, udl_connector->edid); if (udl_connector->edid) return drm_add_edid_modes(connector, udl_connector->edid); return 0; diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index b8d50533e2bb4..91f284e1b9081 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -285,7 +285,7 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector) drm_rgb_quant_range_selectable(edid); } - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); kfree(edid); diff --git a/drivers/gpu/drm/zte/zx_hdmi.c b/drivers/gpu/drm/zte/zx_hdmi.c index 13ea90f7a185a..d073c67375000 100644 --- a/drivers/gpu/drm/zte/zx_hdmi.c +++ b/drivers/gpu/drm/zte/zx_hdmi.c @@ -272,7 +272,7 @@ static int zx_hdmi_connector_get_modes(struct drm_connector *connector) hdmi->sink_is_hdmi = drm_detect_hdmi_monitor(edid); hdmi->sink_has_audio = drm_detect_monitor_audio(edid); - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); kfree(edid); diff --git a/drivers/gpu/drm/zte/zx_vga.c b/drivers/gpu/drm/zte/zx_vga.c index 3e7e33cd3dfa4..3e78ee21b8d00 100644 --- a/drivers/gpu/drm/zte/zx_vga.c +++ b/drivers/gpu/drm/zte/zx_vga.c @@ -109,7 +109,7 @@ static int zx_vga_connector_get_modes(struct drm_connector *connector) */ zx_writel(vga->mmio + VGA_AUTO_DETECT_SEL, VGA_DETECT_SEL_HAS_DEVICE); - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); kfree(edid); diff --git a/drivers/staging/vboxvideo/vbox_mode.c b/drivers/staging/vboxvideo/vbox_mode.c index 5c7ea237893e6..a943d2f683ed3 100644 --- a/drivers/staging/vboxvideo/vbox_mode.c +++ b/drivers/staging/vboxvideo/vbox_mode.c @@ -504,7 +504,7 @@ static void vbox_set_edid(struct drm_connector *connector, int width, for (i = 0; i < EDID_SIZE - 1; ++i) sum += edid[i]; edid[EDID_SIZE - 1] = (0x100 - (sum & 0xFF)) & 0xFF; - drm_mode_connector_update_edid_property(connector, (struct edid *)edid); + drm_connector_update_edid_property(connector, (struct edid *)edid); } static int vbox_get_modes(struct drm_connector *connector) diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index e09e16b3e0542..4411c0542871c 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -896,7 +896,7 @@ struct drm_connector { /** * @edid_blob_ptr: DRM property containing EDID if present. Protected by * &drm_mode_config.mutex. This should be updated only by calling - * drm_mode_connector_update_edid_property(). + * drm_connector_update_edid_property(). */ struct drm_property_blob *edid_blob_ptr; @@ -1194,8 +1194,8 @@ int drm_mode_create_suggested_offset_properties(struct drm_device *dev); int drm_mode_connector_set_path_property(struct drm_connector *connector, const char *path); int drm_mode_connector_set_tile_property(struct drm_connector *connector); -int drm_mode_connector_update_edid_property(struct drm_connector *connector, - const struct edid *edid); +int drm_connector_update_edid_property(struct drm_connector *connector, + const struct edid *edid); void drm_mode_connector_set_link_status_property(struct drm_connector *connector, uint64_t link_status); int drm_connector_init_panel_orientation_property( diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h index d0eb76c4b309a..61142aa0ab23a 100644 --- a/include/drm/drm_modeset_helper_vtables.h +++ b/include/drm/drm_modeset_helper_vtables.h @@ -785,7 +785,7 @@ struct drm_connector_helper_funcs { * * This function should fill in all modes currently valid for the sink * into the &drm_connector.probed_modes list. It should also update the - * EDID property by calling drm_mode_connector_update_edid_property(). + * EDID property by calling drm_connector_update_edid_property(). * * The usual way to implement this is to cache the EDID retrieved in the * probe callback somewhere in the driver-private connector structure. -- GitLab From cde4c44d8769c1be16074c097592c46c7d64092b Mon Sep 17 00:00:00 2001 From: Daniel Vetter <daniel.vetter@ffwll.ch> Date: Mon, 9 Jul 2018 10:40:07 +0200 Subject: [PATCH 1074/1506] drm: drop _mode_ from drm_mode_connector_attach_encoder Again to align with the usual prefix of just drm_connector_. Again done with sed + manual fixup for indent issues. Reviewed-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180709084016.23750-7-daniel.vetter@ffwll.ch --- Documentation/gpu/drm-kms.rst | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_encoders.c | 2 +- drivers/gpu/drm/amd/amdgpu/dce_virtual.c | 2 +- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 +- drivers/gpu/drm/arc/arcpgu_sim.c | 2 +- drivers/gpu/drm/ast/ast_mode.c | 2 +- drivers/gpu/drm/bochs/bochs_kms.c | 2 +- drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 2 +- drivers/gpu/drm/bridge/analogix-anx78xx.c | 4 ++-- drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 2 +- drivers/gpu/drm/bridge/dumb-vga-dac.c | 2 +- .../gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c | 2 +- drivers/gpu/drm/bridge/nxp-ptn3460.c | 2 +- drivers/gpu/drm/bridge/panel.c | 2 +- drivers/gpu/drm/bridge/parade-ps8622.c | 2 +- drivers/gpu/drm/bridge/sii902x.c | 2 +- drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 2 +- drivers/gpu/drm/bridge/tc358767.c | 2 +- drivers/gpu/drm/bridge/ti-tfp410.c | 2 +- drivers/gpu/drm/cirrus/cirrus_mode.c | 2 +- drivers/gpu/drm/drm_connector.c | 10 +++++----- drivers/gpu/drm/drm_simple_kms_helper.c | 2 +- drivers/gpu/drm/drm_writeback.c | 2 +- drivers/gpu/drm/exynos/exynos_drm_dpi.c | 2 +- drivers/gpu/drm/exynos/exynos_drm_dsi.c | 2 +- drivers/gpu/drm/exynos/exynos_drm_vidi.c | 2 +- drivers/gpu/drm/exynos/exynos_hdmi.c | 2 +- drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c | 2 +- drivers/gpu/drm/gma500/gma_display.c | 2 +- drivers/gpu/drm/gma500/mdfld_dsi_dpi.c | 2 +- drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c | 2 +- drivers/gpu/drm/i2c/tda998x_drv.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 3 +-- drivers/gpu/drm/i915/intel_dp_mst.c | 3 +-- drivers/gpu/drm/imx/imx-ldb.c | 3 +-- drivers/gpu/drm/imx/imx-tve.c | 2 +- drivers/gpu/drm/imx/parallel-display.c | 2 +- drivers/gpu/drm/mediatek/mtk_dsi.c | 2 +- drivers/gpu/drm/mediatek/mtk_hdmi.c | 2 +- drivers/gpu/drm/meson/meson_venc_cvbs.c | 2 +- drivers/gpu/drm/mgag200/mgag200_mode.c | 2 +- drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c | 2 +- drivers/gpu/drm/msm/dsi/dsi_manager.c | 2 +- drivers/gpu/drm/msm/edp/edp_connector.c | 2 +- drivers/gpu/drm/msm/hdmi/hdmi_connector.c | 2 +- drivers/gpu/drm/nouveau/dispnv04/dac.c | 2 +- drivers/gpu/drm/nouveau/dispnv04/dfp.c | 2 +- drivers/gpu/drm/nouveau/dispnv04/tvnv04.c | 2 +- drivers/gpu/drm/nouveau/dispnv04/tvnv17.c | 2 +- drivers/gpu/drm/nouveau/dispnv50/disp.c | 8 ++++---- drivers/gpu/drm/omapdrm/omap_drv.c | 2 +- drivers/gpu/drm/qxl/qxl_display.c | 2 +- drivers/gpu/drm/radeon/radeon_encoders.c | 2 +- drivers/gpu/drm/rcar-du/rcar_lvds.c | 2 +- drivers/gpu/drm/rockchip/cdn-dp-core.c | 2 +- drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 2 +- drivers/gpu/drm/rockchip/inno_hdmi.c | 2 +- drivers/gpu/drm/rockchip/rockchip_lvds.c | 2 +- drivers/gpu/drm/shmobile/shmob_drm_crtc.c | 2 +- drivers/gpu/drm/sti/sti_dvo.c | 2 +- drivers/gpu/drm/sti/sti_hda.c | 2 +- drivers/gpu/drm/sti/sti_hdmi.c | 2 +- drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c | 2 +- drivers/gpu/drm/sun4i/sun4i_lvds.c | 2 +- drivers/gpu/drm/sun4i/sun4i_rgb.c | 2 +- drivers/gpu/drm/sun4i/sun4i_tv.c | 2 +- drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 2 +- drivers/gpu/drm/tegra/dsi.c | 2 +- drivers/gpu/drm/tegra/hdmi.c | 2 +- drivers/gpu/drm/tegra/rgb.c | 2 +- drivers/gpu/drm/tegra/sor.c | 2 +- drivers/gpu/drm/tilcdc/tilcdc_panel.c | 2 +- drivers/gpu/drm/tilcdc/tilcdc_tfp410.c | 2 +- drivers/gpu/drm/udl/udl_connector.c | 2 +- drivers/gpu/drm/vc4/vc4_hdmi.c | 2 +- drivers/gpu/drm/vc4/vc4_vec.c | 2 +- drivers/gpu/drm/virtio/virtgpu_display.c | 2 +- drivers/gpu/drm/vkms/vkms_output.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 2 +- drivers/gpu/drm/zte/zx_hdmi.c | 2 +- drivers/gpu/drm/zte/zx_tvenc.c | 2 +- drivers/gpu/drm/zte/zx_vga.c | 2 +- drivers/staging/vboxvideo/vbox_mode.c | 2 +- include/drm/drm_connector.h | 2 +- 86 files changed, 94 insertions(+), 97 deletions(-) diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index 514939433004a..58eed08fbe31f 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -466,7 +466,7 @@ Output discovery and initialization example drm_encoder_init(dev, &intel_output->enc, &intel_crt_enc_funcs, DRM_MODE_ENCODER_DAC); - drm_mode_connector_attach_encoder(&intel_output->base, + drm_connector_attach_encoder(&intel_output->base, &intel_output->enc); /* Set up the DDC bus. */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_encoders.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_encoders.c index 94138abe093b1..ae8fac34f7a59 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_encoders.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_encoders.c @@ -46,7 +46,7 @@ amdgpu_link_encoder_connector(struct drm_device *dev) list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { amdgpu_encoder = to_amdgpu_encoder(encoder); if (amdgpu_encoder->devices & amdgpu_connector->devices) { - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { amdgpu_atombios_encoder_init_backlight(amdgpu_encoder, connector); adev->mode_info.bl_encoder = amdgpu_encoder; diff --git a/drivers/gpu/drm/amd/amdgpu/dce_virtual.c b/drivers/gpu/drm/amd/amdgpu/dce_virtual.c index 016f150931731..677e96a563302 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_virtual.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_virtual.c @@ -627,7 +627,7 @@ static int dce_virtual_connector_encoder_init(struct amdgpu_device *adev, drm_connector_register(connector); /* link them */ - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); return 0; } 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 c4ab19831344c..ae09331eed003 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -3615,7 +3615,7 @@ static int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm, link, link_index); - drm_mode_connector_attach_encoder( + drm_connector_attach_encoder( &aconnector->base, &aencoder->base); drm_connector_register(&aconnector->base); diff --git a/drivers/gpu/drm/arc/arcpgu_sim.c b/drivers/gpu/drm/arc/arcpgu_sim.c index b8f6f9a5dfbe3..68629e6149909 100644 --- a/drivers/gpu/drm/arc/arcpgu_sim.c +++ b/drivers/gpu/drm/arc/arcpgu_sim.c @@ -99,7 +99,7 @@ int arcpgu_drm_sim_init(struct drm_device *drm, struct device_node *np) goto error_encoder_cleanup; } - ret = drm_mode_connector_attach_encoder(connector, encoder); + ret = drm_connector_attach_encoder(connector, encoder); if (ret < 0) { dev_err(drm->dev, "could not attach connector to encoder\n"); drm_connector_unregister(connector); diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index 1bb8174ad1556..5e77d456d9bb9 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -900,7 +900,7 @@ static int ast_connector_init(struct drm_device *dev) connector->polled = DRM_CONNECTOR_POLL_CONNECT; encoder = list_first_entry(&dev->mode_config.encoder_list, struct drm_encoder, head); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); ast_connector->i2c = ast_i2c_create(dev); if (!ast_connector->i2c) diff --git a/drivers/gpu/drm/bochs/bochs_kms.c b/drivers/gpu/drm/bochs/bochs_kms.c index 233980a785912..ca5a9afdd5cfa 100644 --- a/drivers/gpu/drm/bochs/bochs_kms.c +++ b/drivers/gpu/drm/bochs/bochs_kms.c @@ -259,7 +259,7 @@ int bochs_kms_init(struct bochs_device *bochs) bochs_crtc_init(bochs->dev); bochs_encoder_init(bochs->dev); bochs_connector_init(bochs->dev); - drm_mode_connector_attach_encoder(&bochs->connector, + drm_connector_attach_encoder(&bochs->connector, &bochs->encoder); return 0; diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index 1f4745953aca6..6437b878724a1 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -860,7 +860,7 @@ static int adv7511_bridge_attach(struct drm_bridge *bridge) } drm_connector_helper_add(&adv->connector, &adv7511_connector_helper_funcs); - drm_mode_connector_attach_encoder(&adv->connector, bridge->encoder); + drm_connector_attach_encoder(&adv->connector, bridge->encoder); if (adv->type == ADV7533) ret = adv7533_attach_dsi(adv); diff --git a/drivers/gpu/drm/bridge/analogix-anx78xx.c b/drivers/gpu/drm/bridge/analogix-anx78xx.c index 37f947dcadec0..f8433c93f4634 100644 --- a/drivers/gpu/drm/bridge/analogix-anx78xx.c +++ b/drivers/gpu/drm/bridge/analogix-anx78xx.c @@ -1048,8 +1048,8 @@ static int anx78xx_bridge_attach(struct drm_bridge *bridge) anx78xx->connector.polled = DRM_CONNECTOR_POLL_HPD; - err = drm_mode_connector_attach_encoder(&anx78xx->connector, - bridge->encoder); + err = drm_connector_attach_encoder(&anx78xx->connector, + bridge->encoder); if (err) { DRM_ERROR("Failed to link up connector to encoder: %d\n", err); return err; diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 288c015f7460a..d68986cea1325 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -1210,7 +1210,7 @@ static int analogix_dp_bridge_attach(struct drm_bridge *bridge) drm_connector_helper_add(connector, &analogix_dp_connector_helper_funcs); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); } /* diff --git a/drivers/gpu/drm/bridge/dumb-vga-dac.c b/drivers/gpu/drm/bridge/dumb-vga-dac.c index da99b8ba4ee1b..9b706789a3417 100644 --- a/drivers/gpu/drm/bridge/dumb-vga-dac.c +++ b/drivers/gpu/drm/bridge/dumb-vga-dac.c @@ -122,7 +122,7 @@ static int dumb_vga_attach(struct drm_bridge *bridge) return ret; } - drm_mode_connector_attach_encoder(&vga->connector, + drm_connector_attach_encoder(&vga->connector, bridge->encoder); return 0; diff --git a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c index b49b543bd1f6c..2136c97aeb8ec 100644 --- a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c +++ b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c @@ -241,7 +241,7 @@ static int ge_b850v3_lvds_attach(struct drm_bridge *bridge) return ret; } - ret = drm_mode_connector_attach_encoder(connector, bridge->encoder); + ret = drm_connector_attach_encoder(connector, bridge->encoder); if (ret) return ret; diff --git a/drivers/gpu/drm/bridge/nxp-ptn3460.c b/drivers/gpu/drm/bridge/nxp-ptn3460.c index bd5c191858cb5..a3e817abace10 100644 --- a/drivers/gpu/drm/bridge/nxp-ptn3460.c +++ b/drivers/gpu/drm/bridge/nxp-ptn3460.c @@ -265,7 +265,7 @@ static int ptn3460_bridge_attach(struct drm_bridge *bridge) drm_connector_helper_add(&ptn_bridge->connector, &ptn3460_connector_helper_funcs); drm_connector_register(&ptn_bridge->connector); - drm_mode_connector_attach_encoder(&ptn_bridge->connector, + drm_connector_attach_encoder(&ptn_bridge->connector, bridge->encoder); if (ptn_bridge->panel) diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c index 6d99d4a3beb36..7cbaba213ef69 100644 --- a/drivers/gpu/drm/bridge/panel.c +++ b/drivers/gpu/drm/bridge/panel.c @@ -79,7 +79,7 @@ static int panel_bridge_attach(struct drm_bridge *bridge) return ret; } - drm_mode_connector_attach_encoder(&panel_bridge->connector, + drm_connector_attach_encoder(&panel_bridge->connector, bridge->encoder); ret = drm_panel_attach(panel_bridge->panel, &panel_bridge->connector); diff --git a/drivers/gpu/drm/bridge/parade-ps8622.c b/drivers/gpu/drm/bridge/parade-ps8622.c index 81198f5e9afac..7334d1b62b71f 100644 --- a/drivers/gpu/drm/bridge/parade-ps8622.c +++ b/drivers/gpu/drm/bridge/parade-ps8622.c @@ -503,7 +503,7 @@ static int ps8622_attach(struct drm_bridge *bridge) drm_connector_helper_add(&ps8622->connector, &ps8622_connector_helper_funcs); drm_connector_register(&ps8622->connector); - drm_mode_connector_attach_encoder(&ps8622->connector, + drm_connector_attach_encoder(&ps8622->connector, bridge->encoder); if (ps8622->panel) diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c index cd331933c230c..e59a135423336 100644 --- a/drivers/gpu/drm/bridge/sii902x.c +++ b/drivers/gpu/drm/bridge/sii902x.c @@ -324,7 +324,7 @@ static int sii902x_bridge_attach(struct drm_bridge *bridge) else sii902x->connector.polled = DRM_CONNECTOR_POLL_CONNECT; - drm_mode_connector_attach_encoder(&sii902x->connector, bridge->encoder); + drm_connector_attach_encoder(&sii902x->connector, bridge->encoder); return 0; } diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index ab32aceb6f249..5971976284bf9 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -1974,7 +1974,7 @@ static int dw_hdmi_bridge_attach(struct drm_bridge *bridge) drm_connector_init(bridge->dev, connector, &dw_hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); return 0; } diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index ee2fd0a349b32..8e28e738cb52d 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -1195,7 +1195,7 @@ static int tc_bridge_attach(struct drm_bridge *bridge) drm_display_info_set_bus_formats(&tc->connector.display_info, &bus_format, 1); - drm_mode_connector_attach_encoder(&tc->connector, tc->bridge.encoder); + drm_connector_attach_encoder(&tc->connector, tc->bridge.encoder); return 0; } diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c index c81bf7910bbe0..c3e32138c6bb0 100644 --- a/drivers/gpu/drm/bridge/ti-tfp410.c +++ b/drivers/gpu/drm/bridge/ti-tfp410.c @@ -132,7 +132,7 @@ static int tfp410_attach(struct drm_bridge *bridge) return ret; } - drm_mode_connector_attach_encoder(&dvi->connector, + drm_connector_attach_encoder(&dvi->connector, bridge->encoder); return 0; diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c index b529f8c8e2a63..336bfda401257 100644 --- a/drivers/gpu/drm/cirrus/cirrus_mode.c +++ b/drivers/gpu/drm/cirrus/cirrus_mode.c @@ -530,7 +530,7 @@ int cirrus_modeset_init(struct cirrus_device *cdev) return -1; } - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); ret = cirrus_fbdev_init(cdev); if (ret) { diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index b2b182ffdbe93..8997792e2e239 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -48,7 +48,7 @@ * * Connectors must be attached to an encoder to be used. For devices that map * connectors to encoders 1:1, the connector should be attached at - * initialization time with a call to drm_mode_connector_attach_encoder(). The + * initialization time with a call to drm_connector_attach_encoder(). The * driver must also set the &drm_connector.encoder field to point to the * attached encoder. * @@ -291,7 +291,7 @@ int drm_connector_init(struct drm_device *dev, EXPORT_SYMBOL(drm_connector_init); /** - * drm_mode_connector_attach_encoder - attach a connector to an encoder + * drm_connector_attach_encoder - attach a connector to an encoder * @connector: connector to attach * @encoder: encoder to attach @connector to * @@ -302,8 +302,8 @@ EXPORT_SYMBOL(drm_connector_init); * Returns: * Zero on success, negative errno on failure. */ -int drm_mode_connector_attach_encoder(struct drm_connector *connector, - struct drm_encoder *encoder) +int drm_connector_attach_encoder(struct drm_connector *connector, + struct drm_encoder *encoder) { int i; @@ -329,7 +329,7 @@ int drm_mode_connector_attach_encoder(struct drm_connector *connector, } return -ENOMEM; } -EXPORT_SYMBOL(drm_mode_connector_attach_encoder); +EXPORT_SYMBOL(drm_connector_attach_encoder); /** * drm_connector_has_possible_encoder - check if the connector and encoder are assosicated with each other diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c index b72fcf1e9605c..51fa978f0d236 100644 --- a/drivers/gpu/drm/drm_simple_kms_helper.c +++ b/drivers/gpu/drm/drm_simple_kms_helper.c @@ -287,7 +287,7 @@ int drm_simple_display_pipe_init(struct drm_device *dev, if (ret || !connector) return ret; - return drm_mode_connector_attach_encoder(connector, encoder); + return drm_connector_attach_encoder(connector, encoder); } EXPORT_SYMBOL(drm_simple_display_pipe_init); diff --git a/drivers/gpu/drm/drm_writeback.c b/drivers/gpu/drm/drm_writeback.c index 69e7a63cfcc31..169746f6b5677 100644 --- a/drivers/gpu/drm/drm_writeback.c +++ b/drivers/gpu/drm/drm_writeback.c @@ -202,7 +202,7 @@ int drm_writeback_connector_init(struct drm_device *dev, if (ret) goto connector_fail; - ret = drm_mode_connector_attach_encoder(connector, + ret = drm_connector_attach_encoder(connector, &wb_connector->encoder); if (ret) goto attach_fail; diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c index 5887e8522b700..2f0babb67c510 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c @@ -113,7 +113,7 @@ static int exynos_dpi_create_connector(struct drm_encoder *encoder) } drm_connector_helper_add(connector, &exynos_dpi_connector_helper_funcs); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); return 0; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 809e1e0447dfe..a1ed6146a3b5c 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -1479,7 +1479,7 @@ static int exynos_dsi_create_connector(struct drm_encoder *encoder) connector->status = connector_status_disconnected; drm_connector_helper_add(connector, &exynos_dsi_connector_helper_funcs); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); return 0; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index dfea61edba4a5..19697c1362d8f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -344,7 +344,7 @@ static int vidi_create_connector(struct drm_encoder *encoder) } drm_connector_helper_add(connector, &vidi_connector_helper_funcs); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); return 0; } diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 6672d0ff0423a..3a11c719a5808 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -951,7 +951,7 @@ static int hdmi_create_connector(struct drm_encoder *encoder) } drm_connector_helper_add(connector, &hdmi_connector_helper_funcs); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); if (hdata->bridge) { ret = drm_bridge_attach(encoder, hdata->bridge, NULL); diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c index 681e2a07d03be..2298ed2a9e1c0 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c @@ -117,7 +117,7 @@ static int fsl_dcu_attach_panel(struct fsl_dcu_drm_device *fsl_dev, if (ret < 0) goto err_cleanup; - ret = drm_mode_connector_attach_encoder(connector, encoder); + ret = drm_connector_attach_encoder(connector, encoder); if (ret < 0) goto err_sysfs; diff --git a/drivers/gpu/drm/gma500/gma_display.c b/drivers/gpu/drm/gma500/gma_display.c index 08f17f85b801d..09c1161a7ac63 100644 --- a/drivers/gpu/drm/gma500/gma_display.c +++ b/drivers/gpu/drm/gma500/gma_display.c @@ -665,7 +665,7 @@ void gma_connector_attach_encoder(struct gma_connector *connector, struct gma_encoder *encoder) { connector->encoder = encoder; - drm_mode_connector_attach_encoder(&connector->base, + drm_connector_attach_encoder(&connector->base, &encoder->base); } diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c b/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c index a05c020602bda..d0bf5a1e94e87 100644 --- a/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c +++ b/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c @@ -999,7 +999,7 @@ struct mdfld_dsi_encoder *mdfld_dsi_dpi_init(struct drm_device *dev, p_funcs->encoder_helper_funcs); /*attach to given connector*/ - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); /*set possible crtcs and clones*/ if (dsi_connector->pipe) { diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c index d2f4749ebf8dc..744956cea7496 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c @@ -133,7 +133,7 @@ int hibmc_vdac_init(struct hibmc_drm_private *priv) } drm_encoder_helper_add(encoder, &hibmc_encoder_helper_funcs); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); return 0; } diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index d434f576e6b29..eecdc327b9f88 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -1301,7 +1301,7 @@ static int tda998x_connector_init(struct tda998x_priv *priv, if (ret) return ret; - drm_mode_connector_attach_encoder(&priv->connector, &priv->encoder); + drm_connector_attach_encoder(&priv->connector, &priv->encoder); return 0; } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 694a4703042fe..fbe5a6572d7d2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -15899,8 +15899,7 @@ void intel_connector_attach_encoder(struct intel_connector *connector, struct intel_encoder *encoder) { connector->encoder = encoder; - drm_mode_connector_attach_encoder(&connector->base, - &encoder->base); + drm_connector_attach_encoder(&connector->base, &encoder->base); } /* diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index 0f012fbe34ebd..364330fc5d6a7 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -466,8 +466,7 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo struct drm_encoder *enc = &intel_dp->mst_encoders[pipe]->base.base; - ret = drm_mode_connector_attach_encoder(&intel_connector->base, - enc); + ret = drm_connector_attach_encoder(&intel_connector->base, enc); if (ret) goto err; } diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c index ae81cbb75f515..7312beb6f1fcc 100644 --- a/drivers/gpu/drm/imx/imx-ldb.c +++ b/drivers/gpu/drm/imx/imx-ldb.c @@ -471,8 +471,7 @@ static int imx_ldb_register(struct drm_device *drm, drm_connector_init(drm, &imx_ldb_ch->connector, &imx_ldb_connector_funcs, DRM_MODE_CONNECTOR_LVDS); - drm_mode_connector_attach_encoder(&imx_ldb_ch->connector, - encoder); + drm_connector_attach_encoder(&imx_ldb_ch->connector, encoder); } if (imx_ldb_ch->panel) { diff --git a/drivers/gpu/drm/imx/imx-tve.c b/drivers/gpu/drm/imx/imx-tve.c index 1a4ced5c09b55..cffd3310240e5 100644 --- a/drivers/gpu/drm/imx/imx-tve.c +++ b/drivers/gpu/drm/imx/imx-tve.c @@ -493,7 +493,7 @@ static int imx_tve_register(struct drm_device *drm, struct imx_tve *tve) drm_connector_init(drm, &tve->connector, &imx_tve_connector_funcs, DRM_MODE_CONNECTOR_VGA); - drm_mode_connector_attach_encoder(&tve->connector, &tve->encoder); + drm_connector_attach_encoder(&tve->connector, &tve->encoder); return 0; } diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c index 4fc1cf583435d..aefd04e18f935 100644 --- a/drivers/gpu/drm/imx/parallel-display.c +++ b/drivers/gpu/drm/imx/parallel-display.c @@ -197,7 +197,7 @@ static int imx_pd_register(struct drm_device *drm, return ret; } } else { - drm_mode_connector_attach_encoder(&imxpd->connector, encoder); + drm_connector_attach_encoder(&imxpd->connector, encoder); } return 0; diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c index aa0943ec32b00..66df1b1779592 100644 --- a/drivers/gpu/drm/mediatek/mtk_dsi.c +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c @@ -782,7 +782,7 @@ static int mtk_dsi_create_connector(struct drm_device *drm, struct mtk_dsi *dsi) drm_connector_helper_add(&dsi->conn, &mtk_dsi_connector_helper_funcs); dsi->conn.dpms = DRM_MODE_DPMS_OFF; - drm_mode_connector_attach_encoder(&dsi->conn, &dsi->encoder); + drm_connector_attach_encoder(&dsi->conn, &dsi->encoder); if (dsi->panel) { ret = drm_panel_attach(dsi->panel, &dsi->conn); diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c index 835313940395d..2d45d1dd9554a 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c @@ -1306,7 +1306,7 @@ static int mtk_hdmi_bridge_attach(struct drm_bridge *bridge) hdmi->conn.interlace_allowed = true; hdmi->conn.doublescan_allowed = false; - ret = drm_mode_connector_attach_encoder(&hdmi->conn, + ret = drm_connector_attach_encoder(&hdmi->conn, bridge->encoder); if (ret) { dev_err(hdmi->dev, diff --git a/drivers/gpu/drm/meson/meson_venc_cvbs.c b/drivers/gpu/drm/meson/meson_venc_cvbs.c index 79d95ca8a0c09..f7945bae3b4a9 100644 --- a/drivers/gpu/drm/meson/meson_venc_cvbs.c +++ b/drivers/gpu/drm/meson/meson_venc_cvbs.c @@ -282,7 +282,7 @@ int meson_venc_cvbs_create(struct meson_drm *priv) encoder->possible_crtcs = BIT(0); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); return 0; } diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 5f104f1391978..acf7bfe684549 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -1747,7 +1747,7 @@ int mgag200_modeset_init(struct mga_device *mdev) return -1; } - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); ret = mgag200_fbdev_init(mdev); if (ret) { diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c index 32fba5664b0ee..5368e621999ce 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c @@ -132,7 +132,7 @@ struct drm_connector *mdp4_lvds_connector_init(struct drm_device *dev, connector->interlace_allowed = 0; connector->doublescan_allowed = 0; - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); return connector; } diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c index 4beba3f7d0678..21e0dc51531da 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c @@ -684,7 +684,7 @@ struct drm_connector *msm_dsi_manager_connector_init(u8 id) connector->interlace_allowed = 0; connector->doublescan_allowed = 0; - drm_mode_connector_attach_encoder(connector, msm_dsi->encoder); + drm_connector_attach_encoder(connector, msm_dsi->encoder); return connector; } diff --git a/drivers/gpu/drm/msm/edp/edp_connector.c b/drivers/gpu/drm/msm/edp/edp_connector.c index 0b5eac0541950..058ff92a02076 100644 --- a/drivers/gpu/drm/msm/edp/edp_connector.c +++ b/drivers/gpu/drm/msm/edp/edp_connector.c @@ -134,7 +134,7 @@ struct drm_connector *msm_edp_connector_init(struct msm_edp *edp) connector->interlace_allowed = false; connector->doublescan_allowed = false; - drm_mode_connector_attach_encoder(connector, edp->encoder); + drm_connector_attach_encoder(connector, edp->encoder); return connector; } diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c index 07feacc5a4414..e9c9a0af508e8 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c @@ -477,7 +477,7 @@ struct drm_connector *msm_hdmi_connector_init(struct hdmi *hdmi) return ERR_PTR(ret); } - drm_mode_connector_attach_encoder(connector, hdmi->encoder); + drm_connector_attach_encoder(connector, hdmi->encoder); return connector; } diff --git a/drivers/gpu/drm/nouveau/dispnv04/dac.c b/drivers/gpu/drm/nouveau/dispnv04/dac.c index 4feab0a5419d7..e7af95d37ddb5 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/dac.c +++ b/drivers/gpu/drm/nouveau/dispnv04/dac.c @@ -556,6 +556,6 @@ nv04_dac_create(struct drm_connector *connector, struct dcb_output *entry) encoder->possible_crtcs = entry->heads; encoder->possible_clones = 0; - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); return 0; } diff --git a/drivers/gpu/drm/nouveau/dispnv04/dfp.c b/drivers/gpu/drm/nouveau/dispnv04/dfp.c index 9805d2cdc1a1d..73d41abbb5103 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/dfp.c +++ b/drivers/gpu/drm/nouveau/dispnv04/dfp.c @@ -716,6 +716,6 @@ nv04_dfp_create(struct drm_connector *connector, struct dcb_output *entry) entry->location != DCB_LOC_ON_CHIP) nv04_tmds_slave_init(encoder); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); return 0; } diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c b/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c index 01664357d3e18..de4490b4ed30c 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c +++ b/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c @@ -244,7 +244,7 @@ nv04_tv_create(struct drm_connector *connector, struct dcb_output *entry) /* Attach it to the specified connector. */ get_slave_funcs(encoder)->create_resources(encoder, connector); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); return 0; diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c index 6d99f11fee4e0..6a4ca139cf5d7 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c +++ b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c @@ -821,6 +821,6 @@ nv17_tv_create(struct drm_connector *connector, struct dcb_output *entry) encoder->possible_clones = 0; nv17_tv_create_resources(encoder, connector); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); return 0; } diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 2fabb69e452b0..475456c19b765 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -424,7 +424,7 @@ nv50_dac_create(struct drm_connector *connector, struct dcb_output *dcbe) "dac-%04x-%04x", dcbe->hasht, dcbe->hashm); drm_encoder_helper_add(encoder, &nv50_dac_help); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); return 0; } @@ -927,7 +927,7 @@ nv50_mstc_new(struct nv50_mstm *mstm, struct drm_dp_mst_port *port, nouveau_conn_attach_properties(&mstc->connector); for (i = 0; i < ARRAY_SIZE(mstm->msto) && mstm->msto[i]; i++) - drm_mode_connector_attach_encoder(&mstc->connector, &mstm->msto[i]->encoder); + drm_connector_attach_encoder(&mstc->connector, &mstm->msto[i]->encoder); drm_object_attach_property(&mstc->connector.base, dev->mode_config.path_property, 0); drm_object_attach_property(&mstc->connector.base, dev->mode_config.tile_property, 0); @@ -1418,7 +1418,7 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe) "sor-%04x-%04x", dcbe->hasht, dcbe->hashm); drm_encoder_helper_add(encoder, &nv50_sor_help); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); if (dcbe->type == DCB_OUTPUT_DP) { struct nv50_disp *disp = nv50_disp(encoder->dev); @@ -1576,7 +1576,7 @@ nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe) "pior-%04x-%04x", dcbe->hasht, dcbe->hashm); drm_encoder_helper_add(encoder, &nv50_pior_help); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); return 0; } diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index 5005ecc284d22..1b6601e9b1072 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -274,7 +274,7 @@ static int omap_modeset_init(struct drm_device *dev) if (IS_ERR(crtc)) return PTR_ERR(crtc); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); encoder->possible_crtcs = (1 << crtc_idx); priv->crtcs[priv->num_crtcs++] = crtc; diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index 768207fbbae3d..0570c6826bff4 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c @@ -1086,7 +1086,7 @@ static int qdev_output_init(struct drm_device *dev, int num_output) /* we get HPD via client monitors config */ connector->polled = DRM_CONNECTOR_POLL_HPD; encoder->possible_crtcs = 1 << num_output; - drm_mode_connector_attach_encoder(&qxl_output->base, + drm_connector_attach_encoder(&qxl_output->base, &qxl_output->enc); drm_encoder_helper_add(encoder, &qxl_enc_helper_funcs); drm_connector_helper_add(connector, &qxl_connector_helper_funcs); diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index c6ee80216cf4a..c341fb2a5b562 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -211,7 +211,7 @@ radeon_link_encoder_connector(struct drm_device *dev) list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { radeon_encoder = to_radeon_encoder(encoder); if (radeon_encoder->devices & radeon_connector->devices) { - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) radeon_encoder_add_backlight(radeon_encoder, connector); } diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c index 5d8e391e75f42..4c39de3f4f0f3 100644 --- a/drivers/gpu/drm/rcar-du/rcar_lvds.c +++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c @@ -353,7 +353,7 @@ static int rcar_lvds_attach(struct drm_bridge *bridge) drm_connector_helper_add(connector, &rcar_lvds_conn_helper_funcs); - ret = drm_mode_connector_attach_encoder(connector, encoder); + ret = drm_connector_attach_encoder(connector, encoder); if (ret < 0) return ret; diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index a40cb2be50e13..8ad0d773dc33a 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -1062,7 +1062,7 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data) drm_connector_helper_add(connector, &cdn_dp_connector_helper_funcs); - ret = drm_mode_connector_attach_encoder(connector, encoder); + ret = drm_connector_attach_encoder(connector, encoder); if (ret) { DRM_ERROR("failed to attach connector and encoder\n"); goto err_free_connector; diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index 01642aaf61273..662b6cb5d3f02 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -1129,7 +1129,7 @@ static int dw_mipi_dsi_register(struct drm_device *drm, &dw_mipi_dsi_atomic_connector_funcs, DRM_MODE_CONNECTOR_DSI); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); return 0; } diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 510fcb33e31d5..1c02b3e61299c 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -634,7 +634,7 @@ static int inno_hdmi_register(struct drm_device *drm, struct inno_hdmi *hdmi) drm_connector_init(drm, &hdmi->connector, &inno_hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA); - drm_mode_connector_attach_encoder(&hdmi->connector, encoder); + drm_connector_attach_encoder(&hdmi->connector, encoder); return 0; } diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c index b3f6f524b4020..456bd9f13baef 100644 --- a/drivers/gpu/drm/rockchip/rockchip_lvds.c +++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c @@ -434,7 +434,7 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master, drm_connector_helper_add(connector, &rockchip_lvds_connector_helper_funcs); - ret = drm_mode_connector_attach_encoder(connector, encoder); + ret = drm_connector_attach_encoder(connector, encoder); if (ret < 0) { DRM_DEV_ERROR(drm_dev->dev, "failed to attach encoder: %d\n", ret); diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c index 40df8887fc176..fc66167b06417 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c @@ -675,7 +675,7 @@ int shmob_drm_connector_create(struct shmob_drm_device *sdev, if (ret < 0) goto err_cleanup; - ret = drm_mode_connector_attach_encoder(connector, encoder); + ret = drm_connector_attach_encoder(connector, encoder); if (ret < 0) goto err_backlight; diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c index 030da55a8d301..b08376b7611b8 100644 --- a/drivers/gpu/drm/sti/sti_dvo.c +++ b/drivers/gpu/drm/sti/sti_dvo.c @@ -486,7 +486,7 @@ static int sti_dvo_bind(struct device *dev, struct device *master, void *data) drm_connector_helper_add(drm_connector, &sti_dvo_connector_helper_funcs); - err = drm_mode_connector_attach_encoder(drm_connector, encoder); + err = drm_connector_attach_encoder(drm_connector, encoder); if (err) { DRM_ERROR("Failed to attach a connector to a encoder\n"); goto err_sysfs; diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c index 67bbdb49fffc9..49438337f70dc 100644 --- a/drivers/gpu/drm/sti/sti_hda.c +++ b/drivers/gpu/drm/sti/sti_hda.c @@ -709,7 +709,7 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data) drm_connector_helper_add(drm_connector, &sti_hda_connector_helper_funcs); - err = drm_mode_connector_attach_encoder(drm_connector, encoder); + err = drm_connector_attach_encoder(drm_connector, encoder); if (err) { DRM_ERROR("Failed to attach a connector to a encoder\n"); goto err_sysfs; diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index 0c3008356ab87..34cdc46444350 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c @@ -1290,7 +1290,7 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data) hdmi->drm_connector = drm_connector; - err = drm_mode_connector_attach_encoder(drm_connector, encoder); + err = drm_connector_attach_encoder(drm_connector, encoder); if (err) { DRM_ERROR("Failed to attach a connector to a encoder\n"); goto err_sysfs; diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c index 9b4b1d0154232..061d2e0d9011e 100644 --- a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c +++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c @@ -623,7 +623,7 @@ static int sun4i_hdmi_bind(struct device *dev, struct device *master, ret = cec_register_adapter(hdmi->cec_adap, dev); if (ret < 0) goto err_cleanup_connector; - drm_mode_connector_attach_encoder(&hdmi->connector, &hdmi->encoder); + drm_connector_attach_encoder(&hdmi->connector, &hdmi->encoder); return 0; diff --git a/drivers/gpu/drm/sun4i/sun4i_lvds.c b/drivers/gpu/drm/sun4i/sun4i_lvds.c index a69fe2e1f9d1d..af7dcb6da3514 100644 --- a/drivers/gpu/drm/sun4i/sun4i_lvds.c +++ b/drivers/gpu/drm/sun4i/sun4i_lvds.c @@ -149,7 +149,7 @@ int sun4i_lvds_init(struct drm_device *drm, struct sun4i_tcon *tcon) goto err_cleanup_connector; } - drm_mode_connector_attach_encoder(&lvds->connector, + drm_connector_attach_encoder(&lvds->connector, &lvds->encoder); ret = drm_panel_attach(tcon->panel, &lvds->connector); diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c index 96d21b07f8fca..bf068da6b12e1 100644 --- a/drivers/gpu/drm/sun4i/sun4i_rgb.c +++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c @@ -215,7 +215,7 @@ int sun4i_rgb_init(struct drm_device *drm, struct sun4i_tcon *tcon) goto err_cleanup_connector; } - drm_mode_connector_attach_encoder(&rgb->connector, + drm_connector_attach_encoder(&rgb->connector, &rgb->encoder); ret = drm_panel_attach(tcon->panel, &rgb->connector); diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.c b/drivers/gpu/drm/sun4i/sun4i_tv.c index b070d522ed8da..1a838d2082110 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tv.c +++ b/drivers/gpu/drm/sun4i/sun4i_tv.c @@ -623,7 +623,7 @@ static int sun4i_tv_bind(struct device *dev, struct device *master, } tv->connector.interlace_allowed = true; - drm_mode_connector_attach_encoder(&tv->connector, &tv->encoder); + drm_connector_attach_encoder(&tv->connector, &tv->encoder); return 0; diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c index 2b40d1f6aee89..e3b34a3455460 100644 --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c @@ -941,7 +941,7 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master, goto err_cleanup_connector; } - drm_mode_connector_attach_encoder(&dsi->connector, &dsi->encoder); + drm_connector_attach_encoder(&dsi->connector, &dsi->encoder); drm_panel_attach(dsi->panel, &dsi->connector); return 0; diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index ad88ec2303297..ee6ca8fa1c655 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -1052,7 +1052,7 @@ static int tegra_dsi_init(struct host1x_client *client) drm_encoder_helper_add(&dsi->output.encoder, &tegra_dsi_encoder_helper_funcs); - drm_mode_connector_attach_encoder(&dsi->output.connector, + drm_connector_attach_encoder(&dsi->output.connector, &dsi->output.encoder); drm_connector_register(&dsi->output.connector); diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index 784739a9f497d..0082468f703c8 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c @@ -1488,7 +1488,7 @@ static int tegra_hdmi_init(struct host1x_client *client) drm_encoder_helper_add(&hdmi->output.encoder, &tegra_hdmi_encoder_helper_funcs); - drm_mode_connector_attach_encoder(&hdmi->output.connector, + drm_connector_attach_encoder(&hdmi->output.connector, &hdmi->output.encoder); drm_connector_register(&hdmi->output.connector); diff --git a/drivers/gpu/drm/tegra/rgb.c b/drivers/gpu/drm/tegra/rgb.c index 78ec5193741dd..28a78d3120bce 100644 --- a/drivers/gpu/drm/tegra/rgb.c +++ b/drivers/gpu/drm/tegra/rgb.c @@ -289,7 +289,7 @@ int tegra_dc_rgb_init(struct drm_device *drm, struct tegra_dc *dc) drm_encoder_helper_add(&output->encoder, &tegra_rgb_encoder_helper_funcs); - drm_mode_connector_attach_encoder(&output->connector, + drm_connector_attach_encoder(&output->connector, &output->encoder); drm_connector_register(&output->connector); diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index 7d2a955fc5152..d7fe9f15def1d 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -2622,7 +2622,7 @@ static int tegra_sor_init(struct host1x_client *client) encoder, NULL); drm_encoder_helper_add(&sor->output.encoder, helpers); - drm_mode_connector_attach_encoder(&sor->output.connector, + drm_connector_attach_encoder(&sor->output.connector, &sor->output.encoder); drm_connector_register(&sor->output.connector); diff --git a/drivers/gpu/drm/tilcdc/tilcdc_panel.c b/drivers/gpu/drm/tilcdc/tilcdc_panel.c index d616d64a67254..a1acab39d87f4 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_panel.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_panel.c @@ -223,7 +223,7 @@ static struct drm_connector *panel_connector_create(struct drm_device *dev, connector->interlace_allowed = 0; connector->doublescan_allowed = 0; - ret = drm_mode_connector_attach_encoder(connector, encoder); + ret = drm_connector_attach_encoder(connector, encoder); if (ret) goto fail; diff --git a/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c b/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c index 46dacca3cce88..daebf1aa6b0a8 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c @@ -240,7 +240,7 @@ static struct drm_connector *tfp410_connector_create(struct drm_device *dev, connector->interlace_allowed = 0; connector->doublescan_allowed = 0; - ret = drm_mode_connector_attach_encoder(connector, encoder); + ret = drm_connector_attach_encoder(connector, encoder); if (ret) goto fail; diff --git a/drivers/gpu/drm/udl/udl_connector.c b/drivers/gpu/drm/udl/udl_connector.c index 8fac12e1a1a4d..68e88bed77ca7 100644 --- a/drivers/gpu/drm/udl/udl_connector.c +++ b/drivers/gpu/drm/udl/udl_connector.c @@ -200,7 +200,7 @@ int udl_connector_init(struct drm_device *dev, struct drm_encoder *encoder) drm_connector_helper_add(connector, &udl_connector_helper_funcs); drm_connector_register(connector); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); connector->polled = DRM_CONNECTOR_POLL_HPD | DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 91f284e1b9081..fd5522fd179e5 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -329,7 +329,7 @@ static struct drm_connector *vc4_hdmi_connector_init(struct drm_device *dev, connector->interlace_allowed = 1; connector->doublescan_allowed = 0; - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); return connector; } diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c index 3a9a302247a2f..8e7facb6514ef 100644 --- a/drivers/gpu/drm/vc4/vc4_vec.c +++ b/drivers/gpu/drm/vc4/vc4_vec.c @@ -404,7 +404,7 @@ static struct drm_connector *vc4_vec_connector_init(struct drm_device *dev, VC4_VEC_TV_MODE_NTSC); vec->tv_mode = &vc4_vec_tv_modes[VC4_VEC_TV_MODE_NTSC]; - drm_mode_connector_attach_encoder(connector, vec->encoder); + drm_connector_attach_encoder(connector, vec->encoder); return connector; } diff --git a/drivers/gpu/drm/virtio/virtgpu_display.c b/drivers/gpu/drm/virtio/virtgpu_display.c index ff9933e794169..25503b9335991 100644 --- a/drivers/gpu/drm/virtio/virtgpu_display.c +++ b/drivers/gpu/drm/virtio/virtgpu_display.c @@ -292,7 +292,7 @@ static int vgdev_output_init(struct virtio_gpu_device *vgdev, int index) drm_encoder_helper_add(encoder, &virtio_gpu_enc_helper_funcs); encoder->possible_crtcs = 1 << index; - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); drm_connector_register(connector); return 0; } diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c index a7c0ec9b643f1..901012cb1af1d 100644 --- a/drivers/gpu/drm/vkms/vkms_output.c +++ b/drivers/gpu/drm/vkms/vkms_output.c @@ -83,7 +83,7 @@ int vkms_output_init(struct vkms_device *vkmsdev) } encoder->possible_crtcs = 1; - ret = drm_mode_connector_attach_encoder(connector, encoder); + ret = drm_connector_attach_encoder(connector, encoder); if (ret) { DRM_ERROR("Failed to attach connector to encoder\n"); goto err_attach; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index dc0cfda26b1b5..a234fe0e10612 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -438,7 +438,7 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) goto err_free_connector; } - (void) drm_mode_connector_attach_encoder(connector, encoder); + (void) drm_connector_attach_encoder(connector, encoder); encoder->possible_crtcs = (1 << unit); encoder->possible_clones = 0; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index 73cf3c6e1591f..dd417eb745242 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -695,7 +695,7 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit) goto err_free_connector; } - (void) drm_mode_connector_attach_encoder(connector, encoder); + (void) drm_connector_attach_encoder(connector, encoder); encoder->possible_crtcs = (1 << unit); encoder->possible_clones = 0; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index a474d87b1af31..4cca78cab03f6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -1486,7 +1486,7 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit) goto err_free_connector; } - (void) drm_mode_connector_attach_encoder(connector, encoder); + (void) drm_connector_attach_encoder(connector, encoder); encoder->possible_crtcs = (1 << unit); encoder->possible_clones = 0; diff --git a/drivers/gpu/drm/zte/zx_hdmi.c b/drivers/gpu/drm/zte/zx_hdmi.c index d073c67375000..78655269d8434 100644 --- a/drivers/gpu/drm/zte/zx_hdmi.c +++ b/drivers/gpu/drm/zte/zx_hdmi.c @@ -326,7 +326,7 @@ static int zx_hdmi_register(struct drm_device *drm, struct zx_hdmi *hdmi) drm_connector_helper_add(&hdmi->connector, &zx_hdmi_connector_helper_funcs); - drm_mode_connector_attach_encoder(&hdmi->connector, encoder); + drm_connector_attach_encoder(&hdmi->connector, encoder); return 0; } diff --git a/drivers/gpu/drm/zte/zx_tvenc.c b/drivers/gpu/drm/zte/zx_tvenc.c index 0de1a71ca4e08..b73afb212fb24 100644 --- a/drivers/gpu/drm/zte/zx_tvenc.c +++ b/drivers/gpu/drm/zte/zx_tvenc.c @@ -297,7 +297,7 @@ static int zx_tvenc_register(struct drm_device *drm, struct zx_tvenc *tvenc) DRM_MODE_CONNECTOR_Composite); drm_connector_helper_add(connector, &zx_tvenc_connector_helper_funcs); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); return 0; } diff --git a/drivers/gpu/drm/zte/zx_vga.c b/drivers/gpu/drm/zte/zx_vga.c index 3e78ee21b8d00..23d1ff4355a03 100644 --- a/drivers/gpu/drm/zte/zx_vga.c +++ b/drivers/gpu/drm/zte/zx_vga.c @@ -175,7 +175,7 @@ static int zx_vga_register(struct drm_device *drm, struct zx_vga *vga) drm_connector_helper_add(connector, &zx_vga_connector_helper_funcs); - ret = drm_mode_connector_attach_encoder(connector, encoder); + ret = drm_connector_attach_encoder(connector, encoder); if (ret) { DRM_DEV_ERROR(dev, "failed to attach encoder: %d\n", ret); goto clean_connector; diff --git a/drivers/staging/vboxvideo/vbox_mode.c b/drivers/staging/vboxvideo/vbox_mode.c index a943d2f683ed3..da4a93df8d75c 100644 --- a/drivers/staging/vboxvideo/vbox_mode.c +++ b/drivers/staging/vboxvideo/vbox_mode.c @@ -655,7 +655,7 @@ static int vbox_connector_init(struct drm_device *dev, dev->mode_config.suggested_y_property, 0); drm_connector_register(connector); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); return 0; } diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 4411c0542871c..f9a78a53bd9fe 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -1085,7 +1085,7 @@ int drm_connector_init(struct drm_device *dev, int connector_type); int drm_connector_register(struct drm_connector *connector); void drm_connector_unregister(struct drm_connector *connector); -int drm_mode_connector_attach_encoder(struct drm_connector *connector, +int drm_connector_attach_encoder(struct drm_connector *connector, struct drm_encoder *encoder); void drm_connector_cleanup(struct drm_connector *connector); -- GitLab From 97e14fbeb53fe060c5f6a7a07e37fd24c087ed0c Mon Sep 17 00:00:00 2001 From: Daniel Vetter <daniel.vetter@ffwll.ch> Date: Mon, 9 Jul 2018 10:40:08 +0200 Subject: [PATCH 1075/1506] drm: drop _mode_ from remaining connector functions Since there's very few callers of these I've decided to do them all in one patch. With this the unecessarily long drm_mode_connector_ prefix is gone from the codebase! The only exception being struct drm_mode_connector_set_property, which is part of the uapi so can't be renamed. Again done with sed+some manual fixups for indent issues. Reviewed-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180709084016.23750-8-daniel.vetter@ffwll.ch --- .../display/amdgpu_dm/amdgpu_dm_mst_types.c | 6 ++-- drivers/gpu/drm/drm_atomic_helper.c | 2 +- drivers/gpu/drm/drm_connector.c | 36 +++++++++---------- drivers/gpu/drm/drm_crtc_internal.h | 6 ++-- drivers/gpu/drm/drm_dp_mst_topology.c | 4 +-- drivers/gpu/drm/drm_ioctl.c | 2 +- drivers/gpu/drm/drm_mode_object.c | 3 +- drivers/gpu/drm/drm_modes.c | 6 ++-- drivers/gpu/drm/drm_probe_helper.c | 4 +-- drivers/gpu/drm/i915/intel_dp.c | 4 +-- drivers/gpu/drm/i915/intel_dp_mst.c | 2 +- drivers/gpu/drm/msm/dsi/dsi_manager.c | 2 +- drivers/gpu/drm/nouveau/dispnv50/disp.c | 2 +- drivers/gpu/drm/radeon/radeon_dp_mst.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 2 +- include/drm/drm_connector.h | 14 ++++---- include/drm/drm_modes.h | 2 +- 17 files changed, 49 insertions(+), 50 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index 581bb75d08ebe..65f210d3497bb 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -345,7 +345,7 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr, aconnector, connector->base.id, aconnector->mst_port); aconnector->port = port; - drm_mode_connector_set_path_property(connector, pathprop); + drm_connector_set_path_property(connector, pathprop); drm_connector_list_iter_end(&conn_iter); aconnector->mst_connected = true; @@ -393,7 +393,7 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr, dev->mode_config.tile_property, 0); - drm_mode_connector_set_path_property(connector, pathprop); + drm_connector_set_path_property(connector, pathprop); /* * Initialize connector state before adding the connectror to drm and @@ -441,7 +441,7 @@ static void dm_dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr) static void dm_dp_mst_link_status_reset(struct drm_connector *connector) { mutex_lock(&connector->dev->mode_config.mutex); - drm_mode_connector_set_link_status_property(connector, DRM_MODE_LINK_STATUS_BAD); + drm_connector_set_link_status_property(connector, DRM_MODE_LINK_STATUS_BAD); mutex_unlock(&connector->dev->mode_config.mutex); } diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 91fda6b8926e7..866a2cc72ef68 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -2867,7 +2867,7 @@ static int update_output_state(struct drm_atomic_state *state, * resets the "link-status" property to GOOD, to force any link * re-training. The SETCRTC ioctl does not define whether an update does * need a full modeset or just a plane update, hence we're allowed to do - * that. See also drm_mode_connector_set_link_status_property(). + * that. See also drm_connector_set_link_status_property(). * * Returns: * Returns 0 on success, negative errno numbers on failure. diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index 8997792e2e239..8f3f672a47b04 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -852,7 +852,7 @@ DRM_ENUM_NAME_FN(drm_get_content_protection_name, drm_cp_enum_list) * PATH: * Connector path property to identify how this sink is physically * connected. Used by DP MST. This should be set by calling - * drm_mode_connector_set_path_property(), in the case of DP MST with the + * drm_connector_set_path_property(), in the case of DP MST with the * path property the MST manager created. Userspace cannot change this * property. * TILE: @@ -863,14 +863,14 @@ DRM_ENUM_NAME_FN(drm_get_content_protection_name, drm_cp_enum_list) * are not gen-locked. Note that for tiled panels which are genlocked, like * dual-link LVDS or dual-link DSI, the driver should try to not expose the * tiling and virtualize both &drm_crtc and &drm_plane if needed. Drivers - * should update this value using drm_mode_connector_set_tile_property(). + * should update this value using drm_connector_set_tile_property(). * Userspace cannot change this property. * link-status: * Connector link-status property to indicate the status of link. The * default value of link-status is "GOOD". If something fails during or * after modeset, the kernel driver may set this to "BAD" and issue a * hotplug uevent. Drivers should update this value using - * drm_mode_connector_set_link_status_property(). + * drm_connector_set_link_status_property(). * non_desktop: * Indicates the output should be ignored for purposes of displaying a * standard desktop environment or console. This is most likely because @@ -1425,7 +1425,7 @@ int drm_mode_create_suggested_offset_properties(struct drm_device *dev) EXPORT_SYMBOL(drm_mode_create_suggested_offset_properties); /** - * drm_mode_connector_set_path_property - set tile property on connector + * drm_connector_set_path_property - set tile property on connector * @connector: connector to set property on. * @path: path to use for property; must not be NULL. * @@ -1437,8 +1437,8 @@ EXPORT_SYMBOL(drm_mode_create_suggested_offset_properties); * Returns: * Zero on success, negative errno on failure. */ -int drm_mode_connector_set_path_property(struct drm_connector *connector, - const char *path) +int drm_connector_set_path_property(struct drm_connector *connector, + const char *path) { struct drm_device *dev = connector->dev; int ret; @@ -1451,10 +1451,10 @@ int drm_mode_connector_set_path_property(struct drm_connector *connector, dev->mode_config.path_property); return ret; } -EXPORT_SYMBOL(drm_mode_connector_set_path_property); +EXPORT_SYMBOL(drm_connector_set_path_property); /** - * drm_mode_connector_set_tile_property - set tile property on connector + * drm_connector_set_tile_property - set tile property on connector * @connector: connector to set property on. * * This looks up the tile information for a connector, and creates a @@ -1464,7 +1464,7 @@ EXPORT_SYMBOL(drm_mode_connector_set_path_property); * Returns: * Zero on success, errno on failure. */ -int drm_mode_connector_set_tile_property(struct drm_connector *connector) +int drm_connector_set_tile_property(struct drm_connector *connector) { struct drm_device *dev = connector->dev; char tile[256]; @@ -1494,7 +1494,7 @@ int drm_mode_connector_set_tile_property(struct drm_connector *connector) dev->mode_config.tile_property); return ret; } -EXPORT_SYMBOL(drm_mode_connector_set_tile_property); +EXPORT_SYMBOL(drm_connector_set_tile_property); /** * drm_connector_update_edid_property - update the edid property of a connector @@ -1508,7 +1508,7 @@ EXPORT_SYMBOL(drm_mode_connector_set_tile_property); * Zero on success, negative errno on failure. */ int drm_connector_update_edid_property(struct drm_connector *connector, - const struct edid *edid) + const struct edid *edid) { struct drm_device *dev = connector->dev; size_t size = 0; @@ -1549,7 +1549,7 @@ int drm_connector_update_edid_property(struct drm_connector *connector, EXPORT_SYMBOL(drm_connector_update_edid_property); /** - * drm_mode_connector_set_link_status_property - Set link status property of a connector + * drm_connector_set_link_status_property - Set link status property of a connector * @connector: drm connector * @link_status: new value of link status property (0: Good, 1: Bad) * @@ -1567,8 +1567,8 @@ EXPORT_SYMBOL(drm_connector_update_edid_property); * it is not limited to DP or link training. For example, if we implement * asynchronous setcrtc, this property can be used to report any failures in that. */ -void drm_mode_connector_set_link_status_property(struct drm_connector *connector, - uint64_t link_status) +void drm_connector_set_link_status_property(struct drm_connector *connector, + uint64_t link_status) { struct drm_device *dev = connector->dev; @@ -1576,7 +1576,7 @@ void drm_mode_connector_set_link_status_property(struct drm_connector *connector connector->state->link_status = link_status; drm_modeset_unlock(&dev->mode_config.connection_mutex); } -EXPORT_SYMBOL(drm_mode_connector_set_link_status_property); +EXPORT_SYMBOL(drm_connector_set_link_status_property); /** * drm_connector_init_panel_orientation_property - @@ -1629,7 +1629,7 @@ int drm_connector_init_panel_orientation_property( } EXPORT_SYMBOL(drm_connector_init_panel_orientation_property); -int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj, +int drm_connector_set_obj_prop(struct drm_mode_object *obj, struct drm_property *property, uint64_t value) { @@ -1647,8 +1647,8 @@ int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj, return ret; } -int drm_mode_connector_property_set_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv) +int drm_connector_property_set_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) { struct drm_mode_connector_set_property *conn_set_prop = data; struct drm_mode_obj_set_property obj_set_prop = { diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index 235d40fce8b54..b61322763394a 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -148,7 +148,7 @@ void drm_connector_ida_init(void); void drm_connector_ida_destroy(void); void drm_connector_unregister_all(struct drm_device *dev); int drm_connector_register_all(struct drm_device *dev); -int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj, +int drm_connector_set_obj_prop(struct drm_mode_object *obj, struct drm_property *property, uint64_t value); int drm_connector_create_standard_properties(struct drm_device *dev); @@ -156,8 +156,8 @@ const char *drm_get_connector_force_name(enum drm_connector_force force); void drm_connector_free_work_fn(struct work_struct *work); /* IOCTL */ -int drm_mode_connector_property_set_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv); +int drm_connector_property_set_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv); int drm_mode_getconnector(struct drm_device *dev, void *data, struct drm_file *file_priv); diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 658830620ca36..7780567aa6692 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -1215,7 +1215,7 @@ static void drm_dp_add_port(struct drm_dp_mst_branch *mstb, port->pdt == DP_PEER_DEVICE_SST_SINK) && port->port_num >= DP_MST_LOGICAL_PORT_0) { port->cached_edid = drm_get_edid(port->connector, &port->aux.ddc); - drm_mode_connector_set_tile_property(port->connector); + drm_connector_set_tile_property(port->connector); } (*mstb->mgr->cbs->register_connector)(port->connector); } @@ -2559,7 +2559,7 @@ struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_ edid = drm_edid_duplicate(port->cached_edid); else { edid = drm_get_edid(connector, &port->aux.ddc); - drm_mode_connector_set_tile_property(connector); + drm_connector_set_tile_property(connector); } port->has_audio = drm_detect_monitor_audio(edid); drm_dp_put_port(port); diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 3c125041a597c..ea10e9a26aadd 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -641,7 +641,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_noop, DRM_MASTER|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_noop, DRM_MASTER|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_mode_connector_property_set_ioctl, DRM_MASTER|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_connector_property_set_ioctl, DRM_MASTER|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb_ioctl, DRM_UNLOCKED), diff --git a/drivers/gpu/drm/drm_mode_object.c b/drivers/gpu/drm/drm_mode_object.c index ce4d2fb328105..fcb0ab0abb755 100644 --- a/drivers/gpu/drm/drm_mode_object.c +++ b/drivers/gpu/drm/drm_mode_object.c @@ -433,8 +433,7 @@ static int set_property_legacy(struct drm_mode_object *obj, drm_modeset_lock_all(dev); switch (obj->type) { case DRM_MODE_OBJECT_CONNECTOR: - ret = drm_mode_connector_set_obj_prop(obj, prop, - prop_value); + ret = drm_connector_set_obj_prop(obj, prop, prop_value); break; case DRM_MODE_OBJECT_CRTC: ret = drm_mode_crtc_set_obj_prop(obj, prop, prop_value); diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index f8f7eae738ab6..02db9ac82d7a9 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -1353,7 +1353,7 @@ void drm_mode_sort(struct list_head *mode_list) EXPORT_SYMBOL(drm_mode_sort); /** - * drm_mode_connector_list_update - update the mode list for the connector + * drm_connector_list_update - update the mode list for the connector * @connector: the connector to update * * This moves the modes from the @connector probed_modes list @@ -1363,7 +1363,7 @@ EXPORT_SYMBOL(drm_mode_sort); * This is just a helper functions doesn't validate any modes itself and also * doesn't prune any invalid modes. Callers need to do that themselves. */ -void drm_mode_connector_list_update(struct drm_connector *connector) +void drm_connector_list_update(struct drm_connector *connector) { struct drm_display_mode *pmode, *pt; @@ -1412,7 +1412,7 @@ void drm_mode_connector_list_update(struct drm_connector *connector) } } } -EXPORT_SYMBOL(drm_mode_connector_list_update); +EXPORT_SYMBOL(drm_connector_list_update); /** * drm_mode_parse_command_line_for_connector - parse command line modeline for connector diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 3d58e0eb26a47..a1bb157bfdfae 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -360,7 +360,7 @@ EXPORT_SYMBOL(drm_helper_probe_detect); * using the VESA GTF/CVT formulas. * * 3. Modes are moved from the probed_modes list to the modes list. Potential - * duplicates are merged together (see drm_mode_connector_list_update()). + * duplicates are merged together (see drm_connector_list_update()). * After this step the probed_modes list will be empty again. * * 4. Any non-stale mode on the modes list then undergoes validation @@ -485,7 +485,7 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, if (count == 0) goto prune; - drm_mode_connector_list_update(connector); + drm_connector_list_update(connector); if (connector->interlace_allowed) mode_flags |= DRM_MODE_FLAG_INTERLACE; diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index c8268f3776029..8caf20fb65873 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -6320,8 +6320,8 @@ static void intel_dp_modeset_retry_work_fn(struct work_struct *work) /* Set connector link status to BAD and send a Uevent to notify * userspace to do a modeset. */ - drm_mode_connector_set_link_status_property(connector, - DRM_MODE_LINK_STATUS_BAD); + drm_connector_set_link_status_property(connector, + DRM_MODE_LINK_STATUS_BAD); mutex_unlock(&connector->dev->mode_config.mutex); /* Send Hotplug uevent so userspace can reprobe */ drm_kms_helper_hotplug_event(connector->dev); diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index 364330fc5d6a7..0095c197f155b 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -474,7 +474,7 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo drm_object_attach_property(&connector->base, dev->mode_config.path_property, 0); drm_object_attach_property(&connector->base, dev->mode_config.tile_property, 0); - ret = drm_mode_connector_set_path_property(connector, pathprop); + ret = drm_connector_set_path_property(connector, pathprop); if (ret) goto err; diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c index 21e0dc51531da..d5006d6923e01 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c @@ -393,7 +393,7 @@ static int dsi_mgr_connector_get_modes(struct drm_connector *connector) ret = dsi_dual_connector_tile_init(connector, id); if (ret) return ret; - ret = drm_mode_connector_set_tile_property(connector); + ret = drm_connector_set_tile_property(connector); if (ret) { pr_err("%s: set tile property failed, %d\n", __func__, ret); diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 475456c19b765..5a247eb71899d 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -931,7 +931,7 @@ nv50_mstc_new(struct nv50_mstm *mstm, struct drm_dp_mst_port *port, drm_object_attach_property(&mstc->connector.base, dev->mode_config.path_property, 0); drm_object_attach_property(&mstc->connector.base, dev->mode_config.tile_property, 0); - drm_mode_connector_set_path_property(&mstc->connector, path); + drm_connector_set_path_property(&mstc->connector, path); return 0; } diff --git a/drivers/gpu/drm/radeon/radeon_dp_mst.c b/drivers/gpu/drm/radeon/radeon_dp_mst.c index 37956cfc0b6d5..f920be236cc9d 100644 --- a/drivers/gpu/drm/radeon/radeon_dp_mst.c +++ b/drivers/gpu/drm/radeon/radeon_dp_mst.c @@ -290,7 +290,7 @@ static struct drm_connector *radeon_dp_add_mst_connector(struct drm_dp_mst_topol drm_object_attach_property(&connector->base, dev->mode_config.path_property, 0); drm_object_attach_property(&connector->base, dev->mode_config.tile_property, 0); - drm_mode_connector_set_path_property(connector, pathprop); + drm_connector_set_path_property(connector, pathprop); return connector; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index bc5fbd39cf9af..4a0f0f41afa1c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -2114,7 +2114,7 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector, drm_mode_probed_add(connector, mode); } - drm_mode_connector_list_update(connector); + drm_connector_list_update(connector); /* Move the prefered mode first, help apps pick the right mode. */ drm_mode_sort(&connector->modes); diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index f9a78a53bd9fe..97ea41dc678fe 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -919,7 +919,7 @@ struct drm_connector { * @path_blob_ptr: * * DRM blob property data for the DP MST path property. This should only - * be updated by calling drm_mode_connector_set_path_property(). + * be updated by calling drm_connector_set_path_property(). */ struct drm_property_blob *path_blob_ptr; @@ -1046,7 +1046,7 @@ struct drm_connector { * the tiling and virtualize both &drm_crtc and &drm_plane if needed. * * This should only be updated by calling - * drm_mode_connector_set_tile_property(). + * drm_connector_set_tile_property(). */ struct drm_property_blob *tile_blob_ptr; @@ -1191,13 +1191,13 @@ void drm_hdmi_avi_infoframe_content_type(struct hdmi_avi_infoframe *frame, int drm_mode_create_suggested_offset_properties(struct drm_device *dev); -int drm_mode_connector_set_path_property(struct drm_connector *connector, - const char *path); -int drm_mode_connector_set_tile_property(struct drm_connector *connector); +int drm_connector_set_path_property(struct drm_connector *connector, + const char *path); +int drm_connector_set_tile_property(struct drm_connector *connector); int drm_connector_update_edid_property(struct drm_connector *connector, const struct edid *edid); -void drm_mode_connector_set_link_status_property(struct drm_connector *connector, - uint64_t link_status); +void drm_connector_set_link_status_property(struct drm_connector *connector, + uint64_t link_status); int drm_connector_init_panel_orientation_property( struct drm_connector *connector, int width, int height); diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h index b159fe07fcf9e..baded65144563 100644 --- a/include/drm/drm_modes.h +++ b/include/drm/drm_modes.h @@ -530,7 +530,7 @@ drm_mode_validate_ycbcr420(const struct drm_display_mode *mode, void drm_mode_prune_invalid(struct drm_device *dev, struct list_head *mode_list, bool verbose); void drm_mode_sort(struct list_head *mode_list); -void drm_mode_connector_list_update(struct drm_connector *connector); +void drm_connector_list_update(struct drm_connector *connector); /* parsing cmdline modes */ bool -- GitLab From 2e784a91424892cc8c75853dd40b63c0d5855af9 Mon Sep 17 00:00:00 2001 From: Daniel Vetter <daniel.vetter@ffwll.ch> Date: Mon, 9 Jul 2018 10:40:09 +0200 Subject: [PATCH 1076/1506] drm: Switch drm_plane_state to inline kerneldoc style For consistency and to encourage more detailed documentation. While doing this also beefed up a few of the comments, linking at least to the setup function. Plus fixed all the hyperlinks. Reviewed-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180709084016.23750-9-daniel.vetter@ffwll.ch --- include/drm/drm_plane.h | 86 +++++++++++++++++++++++++++-------------- 1 file changed, 56 insertions(+), 30 deletions(-) diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index cee9dfaaa740e..1a647f8f5661b 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -34,31 +34,15 @@ struct drm_modeset_acquire_ctx; /** * struct drm_plane_state - mutable plane state - * @plane: backpointer to the plane - * @crtc_w: width of visible portion of plane on crtc - * @crtc_h: height of visible portion of plane on crtc - * @src_x: left position of visible portion of plane within - * plane (in 16.16) - * @src_y: upper position of visible portion of plane within - * plane (in 16.16) - * @src_w: width of visible portion of plane (in 16.16) - * @src_h: height of visible portion of plane (in 16.16) - * @alpha: opacity of the plane - * @rotation: rotation of the plane - * @zpos: priority of the given plane on crtc (optional) - * Note that multiple active planes on the same crtc can have an identical - * zpos value. The rule to solving the conflict is to compare the plane - * object IDs; the plane with a higher ID must be stacked on top of a - * plane with a lower ID. - * @normalized_zpos: normalized value of zpos: unique, range from 0 to N-1 - * where N is the number of active planes for given crtc. Note that - * the driver must set drm_mode_config.normalize_zpos or call - * drm_atomic_normalize_zpos() to update this before it can be trusted. - * @src: clipped source coordinates of the plane (in 16.16) - * @dst: clipped destination coordinates of the plane - * @state: backpointer to global drm_atomic_state + * + * Please not that the destination coordinates @crtc_x, @crtc_y, @crtc_h and + * @crtc_w and the source coordinates @src_x, @src_y, @src_h and @src_w are the + * raw coordinates provided by userspace. Drivers should use + * drm_atomic_helper_check_plane_state() and only use the derived rectangles in + * @src and @dst to program the hardware. */ struct drm_plane_state { + /** @plane: backpointer to the plane */ struct drm_plane *plane; /** @@ -87,7 +71,7 @@ struct drm_plane_state { * preserved. * * Drivers should store any implicit fence in this from their - * &drm_plane_helper.prepare_fb callback. See drm_gem_fb_prepare_fb() + * &drm_plane_helper_funcs.prepare_fb callback. See drm_gem_fb_prepare_fb() * and drm_gem_fb_simple_display_pipe_prepare_fb() for suitable helpers. */ struct dma_fence *fence; @@ -108,20 +92,60 @@ struct drm_plane_state { */ int32_t crtc_y; + /** @crtc_w: width of visible portion of plane on crtc */ + /** @crtc_h: height of visible portion of plane on crtc */ uint32_t crtc_w, crtc_h; - /* Source values are 16.16 fixed point */ - uint32_t src_x, src_y; + /** + * @src_x: left position of visible portion of plane within plane (in + * 16.16 fixed point). + */ + uint32_t src_x; + /** + * @src_y: upper position of visible portion of plane within plane (in + * 16.16 fixed point). + */ + uint32_t src_y; + /** @src_w: width of visible portion of plane (in 16.16) */ + /** @src_h: height of visible portion of plane (in 16.16) */ uint32_t src_h, src_w; - /* Plane opacity */ + /** + * @alpha: + * Opacity of the plane with 0 as completely transparent and 0xffff as + * completely opaque. See drm_plane_create_alpha_property() for more + * details. + */ u16 alpha; - /* Plane rotation */ + /** + * @rotation: + * Rotation of the plane. See drm_plane_create_rotation_property() for + * more details. + */ unsigned int rotation; - /* Plane zpos */ + /** + * @zpos: + * Priority of the given plane on crtc (optional). + * + * Note that multiple active planes on the same crtc can have an + * identical zpos value. The rule to solving the conflict is to compare + * the plane object IDs; the plane with a higher ID must be stacked on + * top of a plane with a lower ID. + * + * See drm_plane_create_zpos_property() and + * drm_plane_create_zpos_immutable_property() for more details. + */ unsigned int zpos; + + /** + * @normalized_zpos: + * Normalized value of zpos: unique, range from 0 to N-1 where N is the + * number of active planes for given crtc. Note that the driver must set + * &drm_mode_config.normalize_zpos or call drm_atomic_normalize_zpos() to + * update this before it can be trusted. + */ unsigned int normalized_zpos; /** @@ -138,7 +162,8 @@ struct drm_plane_state { */ enum drm_color_range color_range; - /* Clipped coordinates */ + /** @src: clipped source coordinates of the plane (in 16.16) */ + /** @dst: clipped destination coordinates of the plane */ struct drm_rect src, dst; /** @@ -157,6 +182,7 @@ struct drm_plane_state { */ struct drm_crtc_commit *commit; + /** @state: backpointer to global drm_atomic_state */ struct drm_atomic_state *state; }; -- GitLab From 268bc24e861efd6892d2911bf25a3d1192aa51f5 Mon Sep 17 00:00:00 2001 From: Daniel Vetter <daniel.vetter@ffwll.ch> Date: Mon, 9 Jul 2018 10:40:10 +0200 Subject: [PATCH 1077/1506] drm: switch drm_plane to inline comments And use that opportunity to polish the kernel doc all around: - Beef up some of the documentation. - Intro text for drm_plane and better links - Fix all the hyperlinks! v2: Fix linebreaks. Reviewed-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180709084016.23750-10-daniel.vetter@ffwll.ch --- Documentation/gpu/drm-kms.rst | 11 +++-- include/drm/drm_crtc.h | 4 +- include/drm/drm_plane.h | 88 +++++++++++++++++++++++++---------- 3 files changed, 72 insertions(+), 31 deletions(-) diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index 58eed08fbe31f..5dee6b8a4c125 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -56,11 +56,12 @@ Overview The basic object structure KMS presents to userspace is fairly simple. Framebuffers (represented by :c:type:`struct drm_framebuffer <drm_framebuffer>`, -see `Frame Buffer Abstraction`_) feed into planes. One or more (or even no) -planes feed their pixel data into a CRTC (represented by :c:type:`struct -drm_crtc <drm_crtc>`, see `CRTC Abstraction`_) for blending. The precise -blending step is explained in more detail in `Plane Composition Properties`_ and -related chapters. +see `Frame Buffer Abstraction`_) feed into planes. Planes are represented by +:c:type:`struct drm_plane <drm_plane>`, see `Plane Abstraction`_ for more +details. One or more (or even no) planes feed their pixel data into a CRTC +(represented by :c:type:`struct drm_crtc <drm_crtc>`, see `CRTC Abstraction`_) +for blending. The precise blending step is explained in more detail in `Plane +Composition Properties`_ and related chapters. For the output routing the first step is encoders (represented by :c:type:`struct drm_encoder <drm_encoder>`, see `Encoder Abstraction`_). Those diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 17f4f93340b84..71b276a05e366 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -965,8 +965,8 @@ static inline unsigned int drm_crtc_index(const struct drm_crtc *crtc) * drm_crtc_mask - find the mask of a registered CRTC * @crtc: CRTC to find mask for * - * Given a registered CRTC, return the mask bit of that CRTC for an - * encoder's possible_crtcs field. + * Given a registered CRTC, return the mask bit of that CRTC for the + * &drm_encoder.possible_crtcs and &drm_plane.possible_crtcs fields. */ static inline uint32_t drm_crtc_mask(const struct drm_crtc *crtc) { diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index 1a647f8f5661b..8a152dc16ea53 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -525,30 +525,27 @@ enum drm_plane_type { /** * struct drm_plane - central DRM plane control structure - * @dev: DRM device this plane belongs to - * @head: for list management - * @name: human readable name, can be overwritten by the driver - * @base: base mode object - * @possible_crtcs: pipes this plane can be bound to - * @format_types: array of formats supported by this plane - * @format_count: number of formats supported - * @format_default: driver hasn't supplied supported formats for the plane - * @modifiers: array of modifiers supported by this plane - * @modifier_count: number of modifiers supported - * @old_fb: Temporary tracking of the old fb while a modeset is ongoing. Used by - * drm_mode_set_config_internal() to implement correct refcounting. - * @funcs: helper functions - * @properties: property tracking for this plane - * @type: type of plane (overlay, primary, cursor) - * @alpha_property: alpha property for this plane - * @zpos_property: zpos property for this plane - * @rotation_property: rotation property for this plane - * @helper_private: mid-layer private data + * + * Planes represent the scanout hardware of a display block. They receive their + * input data from a &drm_framebuffer and feed it to a &drm_crtc. Planes control + * the color conversion, see `Plane Composition Properties`_ for more details, + * and are also involved in the color conversion of input pixels, see `Color + * Management Properties`_ for details on that. */ struct drm_plane { + /** @dev: DRM device this plane belongs to */ struct drm_device *dev; + + /** + * @head: + * + * List of all planes on @dev, linked from &drm_mode_config.plane_list. + * Invariant over the lifetime of @dev and therefore does not need + * locking. + */ struct list_head head; + /** @name: human readable name, can be overwritten by the driver */ char *name; /** @@ -562,35 +559,62 @@ struct drm_plane { */ struct drm_modeset_lock mutex; + /** @base: base mode object */ struct drm_mode_object base; + /** + * @possible_crtcs: pipes this plane can be bound to constructed from + * drm_crtc_mask() + */ uint32_t possible_crtcs; + /** @format_types: array of formats supported by this plane */ uint32_t *format_types; + /** @format_count: Size of the array pointed at by @format_types. */ unsigned int format_count; + /** + * @format_default: driver hasn't supplied supported formats for the + * plane. Used by the drm_plane_init compatibility wrapper only. + */ bool format_default; + /** @modifiers: array of modifiers supported by this plane */ uint64_t *modifiers; + /** @modifier_count: Size of the array pointed at by @modifier_count. */ unsigned int modifier_count; /** - * @crtc: Currently bound CRTC, only really meaningful for non-atomic - * drivers. Atomic drivers should instead check &drm_plane_state.crtc. + * @crtc: + * + * Currently bound CRTC, only meaningful for non-atomic drivers. For + * atomic drivers this is forced to be NULL, atomic drivers should + * instead check &drm_plane_state.crtc. */ struct drm_crtc *crtc; /** - * @fb: Currently bound framebuffer, only really meaningful for - * non-atomic drivers. Atomic drivers should instead check - * &drm_plane_state.fb. + * @fb: + * + * Currently bound framebuffer, only meaningful for non-atomic drivers. + * For atomic drivers this is forced to be NULL, atomic drivers should + * instead check &drm_plane_state.fb. */ struct drm_framebuffer *fb; + /** + * @old_fb: + * + * Temporary tracking of the old fb while a modeset is ongoing. Only + * used by non-atomic drivers, forced to be NULL for atomic drivers. + */ struct drm_framebuffer *old_fb; + /** @funcs: plane control functions */ const struct drm_plane_funcs *funcs; + /** @properties: property tracking for this plane */ struct drm_object_properties properties; + /** @type: Type of plane, see &enum drm_plane_type for details. */ enum drm_plane_type type; /** @@ -599,6 +623,7 @@ struct drm_plane { */ unsigned index; + /** @helper_private: mid-layer private data */ const struct drm_plane_helper_funcs *helper_private; /** @@ -616,8 +641,23 @@ struct drm_plane { */ struct drm_plane_state *state; + /** + * @alpha_property: + * Optional alpha property for this plane. See + * drm_plane_create_alpha_property(). + */ struct drm_property *alpha_property; + /** + * @zpos_property: + * Optional zpos property for this plane. See + * drm_plane_create_zpos_property(). + */ struct drm_property *zpos_property; + /** + * @rotation_property: + * Optional rotation property for this plane. See + * drm_plane_create_rotation_property(). + */ struct drm_property *rotation_property; /** -- GitLab From 15185aa20cbdf4404198b74f86a1ce9f6fe0fad7 Mon Sep 17 00:00:00 2001 From: Daniel Vetter <daniel.vetter@ffwll.ch> Date: Mon, 9 Jul 2018 10:40:12 +0200 Subject: [PATCH 1078/1506] drm/doc: move struct drm_crtc to in-line comments And clean them up a bit, as usual. v2: Fix nits (Sean). Reviewed-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180709084016.23750-12-daniel.vetter@ffwll.ch --- include/drm/drm_crtc.h | 126 +++++++++++++++++++++++++++++++---------- 1 file changed, 97 insertions(+), 29 deletions(-) diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 71b276a05e366..7fe06ad6e5f08 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -747,35 +747,25 @@ struct drm_crtc_funcs { /** * struct drm_crtc - central CRTC control structure - * @dev: parent DRM device - * @port: OF node used by drm_of_find_possible_crtcs() - * @head: list management - * @name: human readable name, can be overwritten by the driver - * @mutex: per-CRTC locking - * @base: base KMS object for ID tracking etc. - * @primary: primary plane for this CRTC - * @cursor: cursor plane for this CRTC - * @cursor_x: current x position of the cursor, used for universal cursor planes - * @cursor_y: current y position of the cursor, used for universal cursor planes - * @enabled: is this CRTC enabled? - * @mode: current mode timings - * @hwmode: mode timings as programmed to hw regs - * @x: x position on screen - * @y: y position on screen - * @funcs: CRTC control functions - * @gamma_size: size of gamma ramp - * @gamma_store: gamma ramp values - * @helper_private: mid-layer private data - * @properties: property tracking for this CRTC * * Each CRTC may have one or more connectors associated with it. This structure * allows the CRTC to be controlled. */ struct drm_crtc { + /** @dev: parent DRM device */ struct drm_device *dev; + /** @port: OF node used by drm_of_find_possible_crtcs(). */ struct device_node *port; + /** + * @head: + * + * List of all CRTCs on @dev, linked from &drm_mode_config.crtc_list. + * Invariant over the lifetime of @dev and therefore does not need + * locking. + */ struct list_head head; + /** @name: human readable name, can be overwritten by the driver */ char *name; /** @@ -790,10 +780,25 @@ struct drm_crtc { */ struct drm_modeset_lock mutex; + /** @base: base KMS object for ID tracking etc. */ struct drm_mode_object base; - /* primary and cursor planes for CRTC */ + /** + * @primary: + * Primary plane for this CRTC. Note that this is only + * relevant for legacy IOCTL, it specifies the plane implicitly used by + * the SETCRTC and PAGE_FLIP IOCTLs. It does not have any significance + * beyond that. + */ struct drm_plane *primary; + + /** + * @cursor: + * Cursor plane for this CRTC. Note that this is only relevant for + * legacy IOCTL, it specifies the plane implicitly used by the SETCURSOR + * and SETCURSOR2 IOCTLs. It does not have any significance + * beyond that. + */ struct drm_plane *cursor; /** @@ -802,30 +807,94 @@ struct drm_crtc { */ unsigned index; - /* position of cursor plane on crtc */ + /** + * @cursor_x: Current x position of the cursor, used for universal + * cursor planes because the SETCURSOR IOCTL only can update the + * framebuffer without supplying the coordinates. Drivers should not use + * this directly, atomic drivers should look at &drm_plane_state.crtc_x + * of the cursor plane instead. + */ int cursor_x; + /** + * @cursor_y: Current y position of the cursor, used for universal + * cursor planes because the SETCURSOR IOCTL only can update the + * framebuffer without supplying the coordinates. Drivers should not use + * this directly, atomic drivers should look at &drm_plane_state.crtc_y + * of the cursor plane instead. + */ int cursor_y; + /** + * @enabled: + * + * Is this CRTC enabled? Should only be used by legacy drivers, atomic + * drivers should instead consult &drm_crtc_state.enable and + * &drm_crtc_state.active. Atomic drivers can update this by calling + * drm_atomic_helper_update_legacy_modeset_state(). + */ bool enabled; - /* Requested mode from modesetting. */ + /** + * @mode: + * + * Current mode timings. Should only be used by legacy drivers, atomic + * drivers should instead consult &drm_crtc_state.mode. Atomic drivers + * can update this by calling + * drm_atomic_helper_update_legacy_modeset_state(). + */ struct drm_display_mode mode; - /* Programmed mode in hw, after adjustments for encoders, - * crtc, panel scaling etc. Needed for timestamping etc. + /** + * @hwmode: + * + * Programmed mode in hw, after adjustments for encoders, crtc, panel + * scaling etc. Should only be used by legacy drivers, for high + * precision vblank timestamps in + * drm_calc_vbltimestamp_from_scanoutpos(). + * + * Note that atomic drivers should not use this, but instead use + * &drm_crtc_state.adjusted_mode. And for high-precision timestamps + * drm_calc_vbltimestamp_from_scanoutpos() used &drm_vblank_crtc.hwmode, + * which is filled out by calling drm_calc_timestamping_constants(). */ struct drm_display_mode hwmode; - int x, y; + /** + * @x: + * x position on screen. Should only be used by legacy drivers, atomic + * drivers should look at &drm_plane_state.crtc_x of the primary plane + * instead. Updated by calling + * drm_atomic_helper_update_legacy_modeset_state(). + */ + int x; + /** + * @y: + * y position on screen. Should only be used by legacy drivers, atomic + * drivers should look at &drm_plane_state.crtc_y of the primary plane + * instead. Updated by calling + * drm_atomic_helper_update_legacy_modeset_state(). + */ + int y; + + /** @funcs: CRTC control functions */ const struct drm_crtc_funcs *funcs; - /* Legacy FB CRTC gamma size for reporting to userspace */ + /** + * @gamma_size: Size of legacy gamma ramp reported to userspace. Set up + * by calling drm_mode_crtc_set_gamma_size(). + */ uint32_t gamma_size; + + /** + * @gamma_store: Gamma ramp values used by the legacy SETGAMMA and + * GETGAMMA IOCTls. Set up by calling drm_mode_crtc_set_gamma_size(). + */ uint16_t *gamma_store; - /* if you are using the helper */ + /** @helper_private: mid-layer private data */ const struct drm_crtc_helper_funcs *helper_private; + /** @properties: property tracking for this CRTC */ struct drm_object_properties properties; /** @@ -895,7 +964,6 @@ struct drm_crtc { * * spinlock to protect the fences in the fence_context. */ - spinlock_t fence_lock; /** * @fence_seqno: -- GitLab From 9bea6dd081d1f1411a37da8ff066caf4aeb5ab31 Mon Sep 17 00:00:00 2001 From: Daniel Vetter <daniel.vetter@ffwll.ch> Date: Mon, 9 Jul 2018 10:40:13 +0200 Subject: [PATCH 1079/1506] drm/doc: Group the fb gem helpers better MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of spreading them all over the place. Cc: Noralf Trønnes <noralf@tronnes.org> Acked-by: Noralf Trønnes <noralf@tronnes.org> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180709084016.23750-13-daniel.vetter@ffwll.ch --- Documentation/gpu/drm-kms-helpers.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst index 62de583e9efe1..a0a75342d732e 100644 --- a/Documentation/gpu/drm-kms-helpers.rst +++ b/Documentation/gpu/drm-kms-helpers.rst @@ -109,6 +109,15 @@ Framebuffer CMA Helper Functions Reference .. _drm_bridges: +Framebuffer GEM Helper Reference +================================ + +.. kernel-doc:: drivers/gpu/drm/drm_gem_framebuffer_helper.c + :doc: overview + +.. kernel-doc:: drivers/gpu/drm/drm_gem_framebuffer_helper.c + :export: + Bridges ======= @@ -291,15 +300,6 @@ Auxiliary Modeset Helpers .. kernel-doc:: drivers/gpu/drm/drm_modeset_helper.c :export: -Framebuffer GEM Helper Reference -================================ - -.. kernel-doc:: drivers/gpu/drm/drm_gem_framebuffer_helper.c - :doc: overview - -.. kernel-doc:: drivers/gpu/drm/drm_gem_framebuffer_helper.c - :export: - Legacy Plane Helper Reference ============================= -- GitLab From 7f9e7ec92be93e73ef552e6185a3ada72a90e1a9 Mon Sep 17 00:00:00 2001 From: Daniel Vetter <daniel.vetter@ffwll.ch> Date: Mon, 9 Jul 2018 10:40:14 +0200 Subject: [PATCH 1080/1506] drm/doc: Include drm_of.c helpers Fixes a dead link I spotted in the struct drm_crtc docs. Comments themselves are in a surprisingly good state. v2: Fix subject typo (Sean). Reviewed-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180709084016.23750-14-daniel.vetter@ffwll.ch --- Documentation/gpu/drm-kms-helpers.rst | 9 +++++++++ drivers/gpu/drm/drm_of.c | 9 ++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst index a0a75342d732e..f9cfcdcdf024f 100644 --- a/Documentation/gpu/drm-kms-helpers.rst +++ b/Documentation/gpu/drm-kms-helpers.rst @@ -300,6 +300,15 @@ Auxiliary Modeset Helpers .. kernel-doc:: drivers/gpu/drm/drm_modeset_helper.c :export: +OF/DT Helpers +============= + +.. kernel-doc:: drivers/gpu/drm/drm_of.c + :doc: overview + +.. kernel-doc:: drivers/gpu/drm/drm_of.c + :export: + Legacy Plane Helper Reference ============================= diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c index 260612958cbe6..2763a5ec845b0 100644 --- a/drivers/gpu/drm/drm_of.c +++ b/drivers/gpu/drm/drm_of.c @@ -9,6 +9,13 @@ #include <drm/drm_panel.h> #include <drm/drm_of.h> +/** + * DOC: overview + * + * A set of helper functions to aid DRM drivers in parsing standard DT + * properties. + */ + static void drm_release_of(struct device *dev, void *data) { of_node_put(data); @@ -94,7 +101,7 @@ EXPORT_SYMBOL_GPL(drm_of_component_match_add); * drm_of_component_probe - Generic probe function for a component based master * @dev: master device containing the OF node * @compare_of: compare function used for matching components - * @master_ops: component master ops to be used + * @m_ops: component master ops to be used * * Parse the platform device OF node and bind all the components associated * with the master. Interface ports are added before the encoders in order to -- GitLab From 620eec75f35ce470cb59410b2ed91ad750b867a2 Mon Sep 17 00:00:00 2001 From: Daniel Vetter <daniel.vetter@ffwll.ch> Date: Mon, 9 Jul 2018 10:40:15 +0200 Subject: [PATCH 1081/1506] drm/doc: use inline kerneldoc style for drm_crtc_state Lots of added text here since I think the various control flow bits are worth explaining a bit better. v2: Fix conflict with Boris' no_vblank addition. Reviewed-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180709084016.23750-15-daniel.vetter@ffwll.ch --- include/drm/drm_crtc.h | 110 ++++++++++++++++++++++++++++++++--------- 1 file changed, 86 insertions(+), 24 deletions(-) diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 7fe06ad6e5f08..92e7fc7f05a44 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -77,21 +77,6 @@ struct drm_plane_helper_funcs; /** * struct drm_crtc_state - mutable CRTC state - * @crtc: backpointer to the CRTC - * @enable: whether the CRTC should be enabled, gates all other state - * @active: whether the CRTC is actively displaying (used for DPMS) - * @planes_changed: planes on this crtc are updated - * @mode_changed: @mode or @enable has been changed - * @active_changed: @active has been toggled. - * @connectors_changed: connectors to this crtc have been updated - * @zpos_changed: zpos values of planes on this crtc have been updated - * @color_mgmt_changed: color management properties have changed (degamma or - * gamma LUT or CSC matrix) - * @plane_mask: bitmask of (1 << drm_plane_index(plane)) of attached planes - * @connector_mask: bitmask of (1 << drm_connector_index(connector)) of attached connectors - * @encoder_mask: bitmask of (1 << drm_encoder_index(encoder)) of attached encoders - * @mode_blob: &drm_property_blob for @mode - * @state: backpointer to global drm_atomic_state * * Note that the distinction between @enable and @active is rather subtile: * Flipping @active while @enable is set without changing anything else may @@ -102,21 +87,86 @@ struct drm_plane_helper_funcs; * * The three booleans active_changed, connectors_changed and mode_changed are * intended to indicate whether a full modeset is needed, rather than strictly - * describing what has changed in a commit. - * See also: drm_atomic_crtc_needs_modeset() + * describing what has changed in a commit. See also: + * drm_atomic_crtc_needs_modeset() + * + * WARNING: Transitional helpers (like drm_helper_crtc_mode_set() or + * drm_helper_crtc_mode_set_base()) do not maintain many of the derived control + * state like @plane_mask so drivers not converted over to atomic helpers should + * not rely on these being accurate! */ struct drm_crtc_state { + /** @crtc: backpointer to the CRTC */ struct drm_crtc *crtc; + /** + * @enable: Whether the CRTC should be enabled, gates all other state. + * This controls reservations of shared resources. Actual hardware state + * is controlled by @active. + */ bool enable; + + /** + * @active: Whether the CRTC is actively displaying (used for DPMS). + * Implies that @enable is set. The driver must not release any shared + * resources if @active is set to false but @enable still true, because + * userspace expects that a DPMS ON always succeeds. + * + * Hence drivers must not consult @active in their various + * &drm_mode_config_funcs.atomic_check callback to reject an atomic + * commit. They can consult it to aid in the computation of derived + * hardware state, since even in the DPMS OFF state the display hardware + * should be as much powered down as when the CRTC is completely + * disabled through setting @enable to false. + */ bool active; - /* computed state bits used by helpers and drivers */ + /** + * @planes_changed: Planes on this crtc are updated. Used by the atomic + * helpers and drivers to steer the atomic commit control flow. + */ bool planes_changed : 1; + + /** + * @mode_changed: @mode or @enable has been changed. Used by the atomic + * helpers and drivers to steer the atomic commit control flow. See also + * drm_atomic_crtc_needs_modeset(). + * + * Drivers are supposed to set this for any CRTC state changes that + * require a full modeset. They can also reset it to false if e.g. a + * @mode change can be done without a full modeset by only changing + * scaler settings. + */ bool mode_changed : 1; + + /** + * @active_changed: @active has been toggled. Used by the atomic + * helpers and drivers to steer the atomic commit control flow. See also + * drm_atomic_crtc_needs_modeset(). + */ bool active_changed : 1; + + /** + * @connectors_changed: Connectors to this crtc have been updated, + * either in their state or routing. Used by the atomic + * helpers and drivers to steer the atomic commit control flow. See also + * drm_atomic_crtc_needs_modeset(). + * + * Drivers are supposed to set this as-needed from their own atomic + * check code, e.g. from &drm_encoder_helper_funcs.atomic_check + */ bool connectors_changed : 1; + /** + * @zpos_changed: zpos values of planes on this crtc have been updated. + * Used by the atomic helpers and drivers to steer the atomic commit + * control flow. + */ bool zpos_changed : 1; + /** + * @color_mgmt_changed: Color management properties have changed + * (@gamma_lut, @degamma_lut or @ctm). Used by the atomic helpers and + * drivers to steer the atomic commit control flow. + */ bool color_mgmt_changed : 1; /** @@ -142,14 +192,22 @@ struct drm_crtc_state { */ bool no_vblank : 1; - /* attached planes bitmask: - * WARNING: transitional helpers do not maintain plane_mask so - * drivers not converted over to atomic helpers should not rely - * on plane_mask being accurate! + /** + * @plane_mask: Bitmask of drm_plane_mask(plane) of planes attached to + * this CRTC. */ u32 plane_mask; + /** + * @connector_mask: Bitmask of drm_connector_mask(connector) of + * connectors attached to this CRTC. + */ u32 connector_mask; + + /** + * @encoder_mask: Bitmask of drm_encoder_mask(encoder) of encoders + * attached to this CRTC. + */ u32 encoder_mask; /** @@ -159,7 +217,7 @@ struct drm_crtc_state { * differences between the mode requested by userspace in @mode and what * is actually programmed into the hardware. * - * For drivers using drm_bridge, this stores hardware display timings + * For drivers using &drm_bridge, this stores hardware display timings * used between the CRTC and the first bridge. For other drivers, the * meaning of the adjusted_mode field is purely driver implementation * defined information, and will usually be used to store the hardware @@ -184,7 +242,10 @@ struct drm_crtc_state { */ struct drm_display_mode mode; - /* blob property to expose current mode to atomic userspace */ + /** + * @mode_blob: &drm_property_blob for @mode, for exposing the mode to + * atomic userspace. + */ struct drm_property_blob *mode_blob; /** @@ -288,6 +349,7 @@ struct drm_crtc_state { */ struct drm_crtc_commit *commit; + /** @state: backpointer to global drm_atomic_state */ struct drm_atomic_state *state; }; -- GitLab From 6710fcfca5ccb690e02d72376950c61b19570525 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 13 Jul 2018 18:26:58 +0100 Subject: [PATCH 1082/1506] drm/i915/guc: Protect against no desc-pool on premature shutdown MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hopefully the final hack to get guc fault-injection happy before we can clean it up again, starting from a known good baseline... [ 383.017530] BUG: unable to handle kernel NULL pointer dereference at 00000000000000a0 [ 383.017556] Oops: 0000 [#1] PREEMPT SMP PTI [ 383.017566] CPU: 7 PID: 4725 Comm: drv_module_relo Tainted: G U 4.18.0-rc4-CI-CI_DRM_4485+ #1 [ 383.017581] Hardware name: Micro-Star International Co., Ltd. MS-7B54/Z370M MORTAR (MS-7B54), BIOS 1.10 12/28/2017 [ 383.017664] RIP: 0010:guc_stage_desc_pool_destroy+0x17/0xe0 [i915] [ 383.017674] Code: 59 a0 c6 05 02 59 18 00 01 e8 5e 01 c3 e0 eb b1 0f 1f 00 53 48 89 fb 48 81 c7 90 02 00 00 e8 60 64 45 e1 48 8b 83 80 02 00 00 <48> 8b 80 a0 00 00 00 48 8b 90 68 02 00 00 48 83 ea 01 48 81 fa ff [ 383.017771] RSP: 0018:ffffc900004bbdd0 EFLAGS: 00010282 [ 383.017782] RAX: 0000000000000000 RBX: ffff88012ff41300 RCX: 0000000000000000 [ 383.017794] RDX: 0000000000000000 RSI: ffffc900004bbd80 RDI: 0000000000000000 [ 383.017805] RBP: ffff88012ff40000 R08: 00000000d876ee11 R09: 0000000000000000 [ 383.017817] R10: 0000000000000000 R11: 0000000000000000 R12: ffff88012ff47770 [ 383.017828] R13: ffff88012ff40068 R14: ffff880264392ef8 R15: ffffffffa0639950 [ 383.017840] FS: 00007fb9c18c8980(0000) GS:ffff8802663c0000(0000) knlGS:0000000000000000 [ 383.017853] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 383.017864] CR2: 00000000000000a0 CR3: 00000001df6cc003 CR4: 00000000003606e0 [ 383.017875] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 383.017887] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 383.017898] Call Trace: [ 383.017962] intel_uc_fini+0x34/0xd0 [i915] [ 383.018020] i915_gem_fini+0x5c/0x100 [i915] [ 383.018093] i915_driver_unload+0xd2/0x110 [i915] [ 383.018150] i915_pci_remove+0x10/0x20 [i915] [ 383.018165] pci_device_remove+0x36/0xb0 [ 383.018179] device_release_driver_internal+0x185/0x250 [ 383.018193] driver_detach+0x35/0x70 [ 383.018205] bus_remove_driver+0x53/0xd0 [ 383.018217] pci_unregister_driver+0x25/0xa0 [ 383.018232] __se_sys_delete_module+0x162/0x210 [ 383.018245] ? do_syscall_64+0xd/0x190 [ 383.018257] do_syscall_64+0x55/0x190 [ 383.018270] entry_SYSCALL_64_after_hwframe+0x49/0xbe [ 383.018282] RIP: 0033:0x7fb9c0f7c1b7 [ 383.018290] Code: 73 01 c3 48 8b 0d d1 8c 2c 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 b8 b0 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d a1 8c 2c 00 f7 d8 64 89 01 48 [ 383.018408] RSP: 002b:00007fffa01c2aa8 EFLAGS: 00000206 ORIG_RAX: 00000000000000b0 [ 383.018425] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fb9c0f7c1b7 [ 383.018440] RDX: 0000000000000000 RSI: 0000000000000800 RDI: 0000560b96856d48 [ 383.018454] RBP: 0000560b96856ce0 R08: 0000560b96856d4c R09: 00007fffa01c2ae8 [ 383.018468] R10: 00007fffa01c1aa4 R11: 0000000000000206 R12: 0000560b954f7470 Testcase: igt/drv_module_reload/basic-reload-inject Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: MichaÅ‚ Winiarski <michal.winiarski@intel.com> Cc: Michal Wajdeczko <michal.wajdeczko@intel.com> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com> Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Reviewed-by: Michal Wajdeczko <michal.wajdeczko@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180713172658.14070-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_guc_submission.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_guc_submission.c b/drivers/gpu/drm/i915/intel_guc_submission.c index 22367131d6a12..cc444dc5f3adb 100644 --- a/drivers/gpu/drm/i915/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/intel_guc_submission.c @@ -1184,7 +1184,8 @@ void intel_guc_submission_fini(struct intel_guc *guc) guc_clients_destroy(guc); WARN_ON(!guc_verify_doorbells(guc)); - guc_stage_desc_pool_destroy(guc); + if (guc->stage_desc_pool) + guc_stage_desc_pool_destroy(guc); } static void guc_interrupts_capture(struct drm_i915_private *dev_priv) -- GitLab From 137dc4b9060e99a22dce59b42ca71912cf0180f3 Mon Sep 17 00:00:00 2001 From: Evan Quan <evan.quan@amd.com> Date: Wed, 4 Jul 2018 16:21:52 +0800 Subject: [PATCH 1083/1506] drm/amdgpu: pin the csb buffer on hw init v2 Without this pin, the csb buffer will be filled with inconsistent data after S3 resume. And that will causes gfx hang on gfxoff exit since this csb will be executed then. v2: fit amdgpu_bo_pin change(take one less argument) Signed-off-by: Evan Quan <evan.quan@amd.com> Reviewed-by: Huang Rui <ray.huang@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 40 +++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index ac46eabe3bcde..82f457a061fe7 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -943,6 +943,7 @@ static int gfx_v9_0_rlc_init(struct amdgpu_device *adev) dst_ptr = adev->gfx.rlc.cs_ptr; gfx_v9_0_get_csb_buffer(adev, dst_ptr); amdgpu_bo_kunmap(adev->gfx.rlc.clear_state_obj); + amdgpu_bo_unpin(adev->gfx.rlc.clear_state_obj); amdgpu_bo_unreserve(adev->gfx.rlc.clear_state_obj); } @@ -971,6 +972,39 @@ static int gfx_v9_0_rlc_init(struct amdgpu_device *adev) return 0; } +static int gfx_v9_0_csb_vram_pin(struct amdgpu_device *adev) +{ + int r; + + r = amdgpu_bo_reserve(adev->gfx.rlc.clear_state_obj, false); + if (unlikely(r != 0)) + return r; + + r = amdgpu_bo_pin(adev->gfx.rlc.clear_state_obj, + AMDGPU_GEM_DOMAIN_VRAM); + if (!r) + adev->gfx.rlc.clear_state_gpu_addr = + amdgpu_bo_gpu_offset(adev->gfx.rlc.clear_state_obj); + + amdgpu_bo_unreserve(adev->gfx.rlc.clear_state_obj); + + return r; +} + +static void gfx_v9_0_csb_vram_unpin(struct amdgpu_device *adev) +{ + int r; + + if (!adev->gfx.rlc.clear_state_obj) + return; + + r = amdgpu_bo_reserve(adev->gfx.rlc.clear_state_obj, true); + if (likely(r == 0)) { + amdgpu_bo_unpin(adev->gfx.rlc.clear_state_obj); + amdgpu_bo_unreserve(adev->gfx.rlc.clear_state_obj); + } +} + static void gfx_v9_0_mec_fini(struct amdgpu_device *adev) { amdgpu_bo_free_kernel(&adev->gfx.mec.hpd_eop_obj, NULL, NULL); @@ -3116,6 +3150,10 @@ static int gfx_v9_0_hw_init(void *handle) gfx_v9_0_gpu_init(adev); + r = gfx_v9_0_csb_vram_pin(adev); + if (r) + return r; + r = gfx_v9_0_rlc_resume(adev); if (r) return r; @@ -3224,6 +3262,8 @@ static int gfx_v9_0_hw_fini(void *handle) gfx_v9_0_cp_enable(adev, false); gfx_v9_0_rlc_stop(adev); + gfx_v9_0_csb_vram_unpin(adev); + return 0; } -- GitLab From af356b6d32c8dd065393e4c8cd5576c15e48df4d Mon Sep 17 00:00:00 2001 From: Evan Quan <evan.quan@amd.com> Date: Thu, 5 Jul 2018 11:17:48 +0800 Subject: [PATCH 1084/1506] drm/amdgpu: init CSIB regardless of rlc version and pg status CSIB init has no relation with rlc version and pg status. It should be needed regardless of them. Signed-off-by: Evan Quan <evan.quan@amd.com> Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index 82f457a061fe7..e4ae92618b62f 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -2182,6 +2182,8 @@ static void gfx_v9_0_enable_gfx_dynamic_mg_power_gating(struct amdgpu_device *ad static void gfx_v9_0_init_pg(struct amdgpu_device *adev) { + gfx_v9_0_init_csb(adev); + if (!adev->gfx.rlc.is_rlc_v2_1) return; @@ -2191,7 +2193,6 @@ static void gfx_v9_0_init_pg(struct amdgpu_device *adev) AMD_PG_SUPPORT_CP | AMD_PG_SUPPORT_GDS | AMD_PG_SUPPORT_RLC_SMU_HS)) { - gfx_v9_0_init_csb(adev); gfx_v9_1_init_rlc_save_restore_list(adev); gfx_v9_0_enable_save_restore_machine(adev); -- GitLab From b58b65cf7ac09b3d9a979a6a9bbe41abfc425a2a Mon Sep 17 00:00:00 2001 From: Evan Quan <evan.quan@amd.com> Date: Thu, 5 Jul 2018 11:24:20 +0800 Subject: [PATCH 1085/1506] drm/amdgpu: correct rlc save restore list initialization for v2_1 The save restore list initialization does not have to be pg guarded. And for some asic(e.g. Vega12), it does not have cntl/gpm/srm lists. Signed-off-by: Evan Quan <evan.quan@amd.com> Acked-by: Huang Rui <ray.huang@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index e4ae92618b62f..5e92002e72e2a 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -648,7 +648,10 @@ static int gfx_v9_0_init_microcode(struct amdgpu_device *adev) adev->firmware.fw_size += ALIGN(le32_to_cpu(header->ucode_size_bytes), PAGE_SIZE); - if (adev->gfx.rlc.is_rlc_v2_1) { + if (adev->gfx.rlc.is_rlc_v2_1 && + adev->gfx.rlc.save_restore_list_cntl_size_bytes && + adev->gfx.rlc.save_restore_list_gpm_size_bytes && + adev->gfx.rlc.save_restore_list_srm_size_bytes) { info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_RESTORE_LIST_CNTL]; info->ucode_id = AMDGPU_UCODE_ID_RLC_RESTORE_LIST_CNTL; info->fw = adev->gfx.rlc_fw; @@ -2184,8 +2187,14 @@ static void gfx_v9_0_init_pg(struct amdgpu_device *adev) { gfx_v9_0_init_csb(adev); - if (!adev->gfx.rlc.is_rlc_v2_1) - return; + /* + * Rlc save restore list is workable since v2_1. + * And it's needed by gfxoff feature. + */ + if (adev->gfx.rlc.is_rlc_v2_1) { + gfx_v9_1_init_rlc_save_restore_list(adev); + gfx_v9_0_enable_save_restore_machine(adev); + } if (adev->pg_flags & (AMD_PG_SUPPORT_GFX_PG | AMD_PG_SUPPORT_GFX_SMG | @@ -2193,9 +2202,6 @@ static void gfx_v9_0_init_pg(struct amdgpu_device *adev) AMD_PG_SUPPORT_CP | AMD_PG_SUPPORT_GDS | AMD_PG_SUPPORT_RLC_SMU_HS)) { - gfx_v9_1_init_rlc_save_restore_list(adev); - gfx_v9_0_enable_save_restore_machine(adev); - WREG32(mmRLC_JUMP_TABLE_RESTORE, adev->gfx.rlc.cp_table_gpu_addr >> 8); gfx_v9_0_init_gfx_power_gating(adev); -- GitLab From d26031c113acf8289d118bae9a8a293b2f9f6a34 Mon Sep 17 00:00:00 2001 From: Evan Quan <evan.quan@amd.com> Date: Wed, 4 Jul 2018 17:06:38 +0800 Subject: [PATCH 1086/1506] drm/amdgpu: drop mmRLC_PG_CNTL clear v2 SMU owns this register so the driver should not set it to avoid breaking gfxoff. v2: update description Signed-off-by: Evan Quan <evan.quan@amd.com> Reviewed-by: Alex Deucher <alexander.deucher at amd.com> Reviewed-by: Huang Rui <ray.huang at amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index 5e92002e72e2a..6439e65af55b7 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -2293,9 +2293,6 @@ static int gfx_v9_0_rlc_resume(struct amdgpu_device *adev) /* disable CG */ WREG32_SOC15(GC, 0, mmRLC_CGCG_CGLS_CTRL, 0); - /* disable PG */ - WREG32_SOC15(GC, 0, mmRLC_PG_CNTL, 0); - gfx_v9_0_rlc_reset(adev); gfx_v9_0_init_pg(adev); -- GitLab From c3693768174e90481b1b074fcc1dc68d36dd98d4 Mon Sep 17 00:00:00 2001 From: Evan Quan <evan.quan@amd.com> Date: Thu, 5 Jul 2018 10:26:48 +0800 Subject: [PATCH 1087/1506] drm/amdgpu: no touch for the reserved bit of RLC_CGTT_MGCG_OVERRIDE On vega12, the bit0 of RLC_CGTT_MGCG_OVERRIDE is reserved. Signed-off-by: Evan Quan <evan.quan@amd.com> Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index 6439e65af55b7..1f88eb2566bf7 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -3554,8 +3554,11 @@ static void gfx_v9_0_update_medium_grain_clock_gating(struct amdgpu_device *adev if (enable && (adev->cg_flags & AMD_CG_SUPPORT_GFX_MGCG)) { /* 1 - RLC_CGTT_MGCG_OVERRIDE */ def = data = RREG32_SOC15(GC, 0, mmRLC_CGTT_MGCG_OVERRIDE); - data &= ~(RLC_CGTT_MGCG_OVERRIDE__CPF_CGTT_SCLK_OVERRIDE_MASK | - RLC_CGTT_MGCG_OVERRIDE__GRBM_CGTT_SCLK_OVERRIDE_MASK | + + if (adev->asic_type != CHIP_VEGA12) + data &= ~RLC_CGTT_MGCG_OVERRIDE__CPF_CGTT_SCLK_OVERRIDE_MASK; + + data &= ~(RLC_CGTT_MGCG_OVERRIDE__GRBM_CGTT_SCLK_OVERRIDE_MASK | RLC_CGTT_MGCG_OVERRIDE__GFXIP_MGCG_OVERRIDE_MASK | RLC_CGTT_MGCG_OVERRIDE__GFXIP_MGLS_OVERRIDE_MASK); @@ -3585,11 +3588,15 @@ static void gfx_v9_0_update_medium_grain_clock_gating(struct amdgpu_device *adev } else { /* 1 - MGCG_OVERRIDE */ def = data = RREG32_SOC15(GC, 0, mmRLC_CGTT_MGCG_OVERRIDE); - data |= (RLC_CGTT_MGCG_OVERRIDE__CPF_CGTT_SCLK_OVERRIDE_MASK | - RLC_CGTT_MGCG_OVERRIDE__RLC_CGTT_SCLK_OVERRIDE_MASK | + + if (adev->asic_type != CHIP_VEGA12) + data |= RLC_CGTT_MGCG_OVERRIDE__CPF_CGTT_SCLK_OVERRIDE_MASK; + + data |= (RLC_CGTT_MGCG_OVERRIDE__RLC_CGTT_SCLK_OVERRIDE_MASK | RLC_CGTT_MGCG_OVERRIDE__GRBM_CGTT_SCLK_OVERRIDE_MASK | RLC_CGTT_MGCG_OVERRIDE__GFXIP_MGCG_OVERRIDE_MASK | RLC_CGTT_MGCG_OVERRIDE__GFXIP_MGLS_OVERRIDE_MASK); + if (def != data) WREG32_SOC15(GC, 0, mmRLC_CGTT_MGCG_OVERRIDE, data); -- GitLab From a5aedc2d18bcb33816545f39f13a37a0c86b3b3d Mon Sep 17 00:00:00 2001 From: Evan Quan <evan.quan@amd.com> Date: Thu, 5 Jul 2018 10:30:36 +0800 Subject: [PATCH 1088/1506] drm/amdgpu: reduce the idle period that RLC has to wait before request CGCG Gfxoff feature may depends on the CGCG(on vega12, that's the case). This change will help to enable gfxoff feature more frequently. Signed-off-by: Evan Quan <evan.quan@amd.com> Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index 1f88eb2566bf7..ff754bf1875ce 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -3632,9 +3632,11 @@ static void gfx_v9_0_update_3d_clock_gating(struct amdgpu_device *adev, /* update CGCG and CGLS override bits */ if (def != data) WREG32_SOC15(GC, 0, mmRLC_CGTT_MGCG_OVERRIDE, data); - /* enable 3Dcgcg FSM(0x0020003f) */ + + /* enable 3Dcgcg FSM(0x0000363f) */ def = RREG32_SOC15(GC, 0, mmRLC_CGCG_CGLS_CTRL_3D); - data = (0x2000 << RLC_CGCG_CGLS_CTRL_3D__CGCG_GFX_IDLE_THRESHOLD__SHIFT) | + + data = (0x36 << RLC_CGCG_CGLS_CTRL_3D__CGCG_GFX_IDLE_THRESHOLD__SHIFT) | RLC_CGCG_CGLS_CTRL_3D__CGCG_EN_MASK; if (adev->cg_flags & AMD_CG_SUPPORT_GFX_3D_CGLS) data |= (0x000F << RLC_CGCG_CGLS_CTRL_3D__CGLS_REP_COMPANSAT_DELAY__SHIFT) | @@ -3681,9 +3683,10 @@ static void gfx_v9_0_update_coarse_grain_clock_gating(struct amdgpu_device *adev if (def != data) WREG32_SOC15(GC, 0, mmRLC_CGTT_MGCG_OVERRIDE, data); - /* enable cgcg FSM(0x0020003F) */ + /* enable cgcg FSM(0x0000363F) */ def = RREG32_SOC15(GC, 0, mmRLC_CGCG_CGLS_CTRL); - data = (0x2000 << RLC_CGCG_CGLS_CTRL__CGCG_GFX_IDLE_THRESHOLD__SHIFT) | + + data = (0x36 << RLC_CGCG_CGLS_CTRL__CGCG_GFX_IDLE_THRESHOLD__SHIFT) | RLC_CGCG_CGLS_CTRL__CGCG_EN_MASK; if (adev->cg_flags & AMD_CG_SUPPORT_GFX_CGLS) data |= (0x000F << RLC_CGCG_CGLS_CTRL__CGLS_REP_COMPANSAT_DELAY__SHIFT) | -- GitLab From 991a6b32ce647e9827acc0c72a998e4ffed1d753 Mon Sep 17 00:00:00 2001 From: Evan Quan <evan.quan@amd.com> Date: Wed, 4 Jul 2018 16:44:07 +0800 Subject: [PATCH 1089/1506] drm/amd/powerplay: add vega12 SMU gfxoff support v3 Export apis for enabling/disabling SMU gfxoff support. v2: fit the latest gfxoff support framework v3: add feature_mask control Signed-off-by: Evan Quan <evan.quan@amd.com> Reviewed-by: Huang Rui <ray.huang at amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 5 +++ .../drm/amd/powerplay/hwmgr/vega12_hwmgr.c | 38 +++++++++++++++++++ .../drm/amd/powerplay/hwmgr/vega12_hwmgr.h | 3 ++ 3 files changed, 46 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index ff754bf1875ce..e6d19e7fbfbda 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -3769,6 +3769,11 @@ static int gfx_v9_0_set_powergating_state(void *handle, /* update mgcg state */ gfx_v9_0_update_gfx_mg_power_gating(adev, enable); + /* set gfx off through smu */ + if (enable && adev->powerplay.pp_funcs->set_powergating_by_smu) + amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_GFX, true); + break; + case CHIP_VEGA12: /* set gfx off through smu */ if (enable && adev->powerplay.pp_funcs->set_powergating_by_smu) amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_GFX, true); diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c index ed17c560b5ef6..cae76fe658811 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c @@ -423,6 +423,11 @@ static int vega12_hwmgr_backend_init(struct pp_hwmgr *hwmgr) hwmgr->thermal_controller.advanceFanControlParameters.usFanPWMMinLimit * hwmgr->thermal_controller.fanInfo.ulMaxRPM / 100; + if (hwmgr->feature_mask & PP_GFXOFF_MASK) + data->gfxoff_controlled_by_driver = true; + else + data->gfxoff_controlled_by_driver = false; + return result; } @@ -2328,6 +2333,38 @@ static int vega12_get_thermal_temperature_range(struct pp_hwmgr *hwmgr, return 0; } +static int vega12_enable_gfx_off(struct pp_hwmgr *hwmgr) +{ + struct vega12_hwmgr *data = + (struct vega12_hwmgr *)(hwmgr->backend); + int ret = 0; + + if (data->gfxoff_controlled_by_driver) + ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_AllowGfxOff); + + return ret; +} + +static int vega12_disable_gfx_off(struct pp_hwmgr *hwmgr) +{ + struct vega12_hwmgr *data = + (struct vega12_hwmgr *)(hwmgr->backend); + int ret = 0; + + if (data->gfxoff_controlled_by_driver) + ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_DisallowGfxOff); + + return ret; +} + +static int vega12_gfx_off_control(struct pp_hwmgr *hwmgr, bool enable) +{ + if (enable) + return vega12_enable_gfx_off(hwmgr); + else + return vega12_disable_gfx_off(hwmgr); +} + static const struct pp_hwmgr_func vega12_hwmgr_funcs = { .backend_init = vega12_hwmgr_backend_init, .backend_fini = vega12_hwmgr_backend_fini, @@ -2377,6 +2414,7 @@ static const struct pp_hwmgr_func vega12_hwmgr_funcs = { .get_thermal_temperature_range = vega12_get_thermal_temperature_range, .register_irq_handlers = smu9_register_irq_handlers, .start_thermal_controller = vega12_start_thermal_controller, + .powergate_gfx = vega12_gfx_off_control, }; int vega12_hwmgr_init(struct pp_hwmgr *hwmgr) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.h b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.h index e17237c90eeaa..b3e424d289941 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.h @@ -393,6 +393,9 @@ struct vega12_hwmgr { struct vega12_smc_state_table smc_state_table; struct vega12_clock_range clk_range[PPCLK_COUNT]; + + /* ---- Gfxoff ---- */ + bool gfxoff_controlled_by_driver; }; #define VEGA12_DPM2_NEAR_TDP_DEC 10 -- GitLab From 3f2e6bf89cab5f7c84dafc62f478874fdc08d161 Mon Sep 17 00:00:00 2001 From: Evan Quan <evan.quan@amd.com> Date: Thu, 5 Jul 2018 10:44:33 +0800 Subject: [PATCH 1090/1506] drm/amd/powerplay: no need to mask workable gfxoff feature for vega12 Gfxoff feature for vega12 is workable. So, there is no need to mask it any more. Signed-off-by: Evan Quan <evan.quan@amd.com> Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c index 9b675d9bd162d..8994aa5c8cf80 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c @@ -147,10 +147,10 @@ int hwmgr_early_init(struct pp_hwmgr *hwmgr) smu7_init_function_pointers(hwmgr); break; case AMDGPU_FAMILY_AI: - hwmgr->feature_mask &= ~PP_GFXOFF_MASK; switch (hwmgr->chip_id) { case CHIP_VEGA10: case CHIP_VEGA20: + hwmgr->feature_mask &= ~PP_GFXOFF_MASK; hwmgr->smumgr_funcs = &vega10_smu_funcs; vega10_hwmgr_init(hwmgr); break; -- GitLab From ed515ce2748007385347d70ec2779d6aef2cf5f0 Mon Sep 17 00:00:00 2001 From: Evan Quan <evan.quan@amd.com> Date: Tue, 10 Jul 2018 11:35:16 +0800 Subject: [PATCH 1091/1506] drm/amd/powerplay: convert the sclk/mclk into Mhz for comparation Convert the clocks into right Mhz unit. Otherwise, it will miss the equal situation. Signed-off-by: Evan Quan <evan.quan@amd.com> Reviewed-by: Huang Rui <ray.huang@amd.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c index cae76fe658811..c0ceb69a23b0d 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c @@ -1881,7 +1881,7 @@ static int vega12_print_clock_levels(struct pp_hwmgr *hwmgr, for (i = 0; i < clocks.num_levels; i++) size += sprintf(buf + size, "%d: %uMhz %s\n", i, clocks.data[i].clocks_in_khz / 1000, - (clocks.data[i].clocks_in_khz / 1000 == now) ? "*" : ""); + (clocks.data[i].clocks_in_khz / 1000 == now / 100) ? "*" : ""); break; case PP_MCLK: @@ -1897,7 +1897,7 @@ static int vega12_print_clock_levels(struct pp_hwmgr *hwmgr, for (i = 0; i < clocks.num_levels; i++) size += sprintf(buf + size, "%d: %uMhz %s\n", i, clocks.data[i].clocks_in_khz / 1000, - (clocks.data[i].clocks_in_khz / 1000 == now) ? "*" : ""); + (clocks.data[i].clocks_in_khz / 1000 == now / 100) ? "*" : ""); break; case PP_PCIE: -- GitLab From 530e7a660fb795452357b36cce26b839a9a187a9 Mon Sep 17 00:00:00 2001 From: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Date: Wed, 11 Jul 2018 17:34:35 -0400 Subject: [PATCH 1092/1506] drm/amd: Add interrupt source definitions for VI v3. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stop using 'magic numbers' when registering interrupt sources. v2: Clean redundant comments. Switch to kernel style comments. v3: Add CP_ECC_ERROR define Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Acked-by: Christian König <christian.koenig@amd.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../amd/include/ivsrcid/ivsrcid_vislands30.h | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/drivers/gpu/drm/amd/include/ivsrcid/ivsrcid_vislands30.h b/drivers/gpu/drm/amd/include/ivsrcid/ivsrcid_vislands30.h index c6b6f97de9de5..aaed7f59e0e23 100644 --- a/drivers/gpu/drm/amd/include/ivsrcid/ivsrcid_vislands30.h +++ b/drivers/gpu/drm/amd/include/ivsrcid/ivsrcid_vislands30.h @@ -198,4 +198,102 @@ #define VISLANDS30_IV_SRCID_HPD_RX_F 42 // 0x2a #define VISLANDS30_IV_EXTID_HPD_RX_F 11 +#define VISLANDS30_IV_SRCID_GPIO_19 0x00000053 /* 83 */ + +#define VISLANDS30_IV_SRCID_SRBM_READ_TIMEOUT_ERR 0x00000060 /* 96 */ +#define VISLANDS30_IV_SRCID_SRBM_CTX_SWITCH 0x00000061 /* 97 */ + +#define VISLANDS30_IV_SRBM_REG_ACCESS_ERROR 0x00000062 /* 98 */ + + +#define VISLANDS30_IV_SRCID_UVD_ENC_GEN_PURP 0x00000077 /* 119 */ +#define VISLANDS30_IV_SRCID_UVD_SYSTEM_MESSAGE 0x0000007c /* 124 */ + +#define VISLANDS30_IV_SRCID_BIF_PF_VF_MSGBUF_VALID 0x00000087 /* 135 */ + +#define VISLANDS30_IV_SRCID_BIF_VF_PF_MSGBUF_ACK 0x0000008a /* 138 */ + +#define VISLANDS30_IV_SRCID_SYS_PAGE_INV_FAULT 0x0000008c /* 140 */ +#define VISLANDS30_IV_SRCID_SYS_MEM_PROT_FAULT 0x0000008d /* 141 */ + +#define VISLANDS30_IV_SRCID_SEM_PAGE_INV_FAULT 0x00000090 /* 144 */ +#define VISLANDS30_IV_SRCID_SEM_MEM_PROT_FAULT 0x00000091 /* 145 */ + +#define VISLANDS30_IV_SRCID_GFX_PAGE_INV_FAULT 0x00000092 /* 146 */ +#define VISLANDS30_IV_SRCID_GFX_MEM_PROT_FAULT 0x00000093 /* 147 */ + +#define VISLANDS30_IV_SRCID_ACP 0x000000a2 /* 162 */ + +#define VISLANDS30_IV_SRCID_VCE_TRAP 0x000000a7 /* 167 */ +#define VISLANDS30_IV_EXTID_VCE_TRAP_GENERAL_PURPOSE 0 +#define VISLANDS30_IV_EXTID_VCE_TRAP_LOW_LATENCY 1 +#define VISLANDS30_IV_EXTID_VCE_TRAP_REAL_TIME 2 + +#define VISLANDS30_IV_SRCID_CP_INT_RB 0x000000b0 /* 176 */ +#define VISLANDS30_IV_SRCID_CP_INT_IB1 0x000000b1 /* 177 */ +#define VISLANDS30_IV_SRCID_CP_INT_IB2 0x000000b2 /* 178 */ +#define VISLANDS30_IV_SRCID_CP_PM4_RES_BITS_ERR 0x000000b4 /* 180 */ +#define VISLANDS30_IV_SRCID_CP_END_OF_PIPE 0x000000b5 /* 181 */ +#define VISLANDS30_IV_SRCID_CP_BAD_OPCODE 0x000000b7 /* 183 */ +#define VISLANDS30_IV_SRCID_CP_PRIV_REG_FAULT 0x000000b8 /* 184 */ +#define VISLANDS30_IV_SRCID_CP_PRIV_INSTR_FAULT 0x000000b9 /* 185 */ +#define VISLANDS30_IV_SRCID_CP_WAIT_MEM_SEM_FAULT 0x000000ba /* 186 */ +#define VISLANDS30_IV_SRCID_CP_GUI_IDLE 0x000000bb /* 187 */ +#define VISLANDS30_IV_SRCID_CP_GUI_BUSY 0x000000bc /* 188 */ + +#define VISLANDS30_IV_SRCID_CP_COMPUTE_QUERY_STATUS 0x000000bf /* 191 */ +#define VISLANDS30_IV_SRCID_CP_ECC_ERROR 0x000000c5 /* 197 */ + +#define CARRIZO_IV_SRCID_CP_COMPUTE_QUERY_STATUS 0x000000c7 /* 199 */ + +#define VISLANDS30_IV_SRCID_CP_WAIT_REG_MEM_POLL_TIMEOUT 0x000000c0 /* 192 */ +#define VISLANDS30_IV_SRCID_CP_SEM_SIG_INCOMPL 0x000000c1 /* 193 */ +#define VISLANDS30_IV_SRCID_CP_PREEMPT_ACK 0x000000c2 /* 194 */ +#define VISLANDS30_IV_SRCID_CP_GENERAL_PROT_FAULT 0x000000c3 /* 195 */ +#define VISLANDS30_IV_SRCID_CP_GDS_ALLOC_ERROR 0x000000c4 /* 196 */ +#define VISLANDS30_IV_SRCID_CP_ECC_ERROR 0x000000c5 /* 197 */ + +#define VISLANDS30_IV_SRCID_RLC_STRM_PERF_MONITOR 0x000000ca /* 202 */ + +#define VISLANDS30_IV_SDMA_ATOMIC_SRC_ID 0x000000da /* 218 */ + +#define VISLANDS30_IV_SRCID_SDMA_ECC_ERROR 0x000000dc /* 220 */ + +#define VISLANDS30_IV_SRCID_SDMA_TRAP 0x000000e0 /* 224 */ +#define VISLANDS30_IV_SRCID_SDMA_SEM_INCOMPLETE 0x000000e1 /* 225 */ +#define VISLANDS30_IV_SRCID_SDMA_SEM_WAIT 0x000000e2 /* 226 */ + + +#define VISLANDS30_IV_SRCID_SMU_DISP_TIMER2_TRIGGER 0x000000e5 /* 229 */ + +#define VISLANDS30_IV_SRCID_CG_TSS_THERMAL_LOW_TO_HIGH 0x000000e6 /* 230 */ +#define VISLANDS30_IV_SRCID_CG_TSS_THERMAL_HIGH_TO_LOW 0x000000e7 /* 231 */ + +#define VISLANDS30_IV_SRCID_GRBM_READ_TIMEOUT_ERR 0x000000e8 /* 232 */ +#define VISLANDS30_IV_SRCID_GRBM_REG_GUI_IDLE 0x000000e9 /* 233 */ + +#define VISLANDS30_IV_SRCID_SQ_INTERRUPT_MSG 0x000000ef /* 239 */ + +#define VISLANDS30_IV_SRCID_SDMA_PREEMPT 0x000000f0 /* 240 */ +#define VISLANDS30_IV_SRCID_SDMA_VM_HOLE 0x000000f2 /* 242 */ +#define VISLANDS30_IV_SRCID_SDMA_CTXEMPTY 0x000000f3 /* 243 */ +#define VISLANDS30_IV_SRCID_SDMA_DOORBELL_INVALID 0x000000f4 /* 244 */ +#define VISLANDS30_IV_SRCID_SDMA_FROZEN 0x000000f5 /* 245 */ +#define VISLANDS30_IV_SRCID_SDMA_POLL_TIMEOUT 0x000000f6 /* 246 */ +#define VISLANDS30_IV_SRCID_SDMA_SRBM_WRITE 0x000000f7 /* 247 */ + +#define VISLANDS30_IV_SRCID_CG_THERMAL_TRIG 0x000000f8 /* 248 */ + +#define VISLANDS30_IV_SRCID_SMU_DISP_TIMER_TRIGGER 0x000000fd /* 253 */ + +/* These are not "real" source ids defined by HW */ +#define VISLANDS30_IV_SRCID_VM_CONTEXT_ALL 0x00000100 /* 256 */ +#define VISLANDS30_IV_EXTID_VM_CONTEXT0_ALL 0 +#define VISLANDS30_IV_EXTID_VM_CONTEXT1_ALL 1 + + +/* IV Extended IDs */ +#define VISLANDS30_IV_EXTID_NONE 0x00000000 +#define VISLANDS30_IV_EXTID_INVALID 0xffffffff + #endif // _IVSRCID_VISLANDS30_H_ -- GitLab From 091aec0b4e26c8d31b6c211b57a2ea2c5b985ca9 Mon Sep 17 00:00:00 2001 From: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Date: Fri, 25 May 2018 10:06:52 -0400 Subject: [PATCH 1093/1506] drm/amd: Use newly added interrupt source defs for VI v3. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v2: Rebase v3: Use defines for CP_SQ and CP_ECC_ERROR interrupts. Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/dce_v10_0.c | 6 ++++-- drivers/gpu/drm/amd/amdgpu/dce_v11_0.c | 6 ++++-- drivers/gpu/drm/amd/amdgpu/dce_virtual.c | 3 ++- drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 14 ++++++++------ drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c | 6 ++++-- drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c | 6 ++++-- drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c | 6 ++++-- drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c | 6 ++++-- drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c | 3 ++- drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c | 5 +++-- drivers/gpu/drm/amd/amdgpu/vce_v3_0.c | 3 ++- drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c | 8 +++++--- 12 files changed, 46 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c index ab043228d8da0..308f9f238bc11 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c @@ -41,6 +41,8 @@ #include "gmc/gmc_8_1_d.h" #include "gmc/gmc_8_1_sh_mask.h" +#include "ivsrcid/ivsrcid_vislands30.h" + static void dce_v10_0_set_display_funcs(struct amdgpu_device *adev); static void dce_v10_0_set_irq_funcs(struct amdgpu_device *adev); @@ -2737,14 +2739,14 @@ static int dce_v10_0_sw_init(void *handle) return r; } - for (i = 8; i < 20; i += 2) { + for (i = VISLANDS30_IV_SRCID_D1_GRPH_PFLIP; i < 20; i += 2) { r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, i, &adev->pageflip_irq); if (r) return r; } /* HPD hotplug */ - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 42, &adev->hpd_irq); + r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, VISLANDS30_IV_SRCID_HOTPLUG_DETECT_A, &adev->hpd_irq); if (r) return r; diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c index 1778512647547..76dfb76f7900c 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c @@ -41,6 +41,8 @@ #include "gmc/gmc_8_1_d.h" #include "gmc/gmc_8_1_sh_mask.h" +#include "ivsrcid/ivsrcid_vislands30.h" + static void dce_v11_0_set_display_funcs(struct amdgpu_device *adev); static void dce_v11_0_set_irq_funcs(struct amdgpu_device *adev); @@ -2858,14 +2860,14 @@ static int dce_v11_0_sw_init(void *handle) return r; } - for (i = 8; i < 20; i += 2) { + for (i = VISLANDS30_IV_SRCID_D1_GRPH_PFLIP; i < 20; i += 2) { r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, i, &adev->pageflip_irq); if (r) return r; } /* HPD hotplug */ - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 42, &adev->hpd_irq); + r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, VISLANDS30_IV_SRCID_HOTPLUG_DETECT_A, &adev->hpd_irq); if (r) return r; diff --git a/drivers/gpu/drm/amd/amdgpu/dce_virtual.c b/drivers/gpu/drm/amd/amdgpu/dce_virtual.c index dbf2ccd0c7447..aea8b89765c61 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_virtual.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_virtual.c @@ -36,6 +36,7 @@ #include "dce_v10_0.h" #include "dce_v11_0.h" #include "dce_virtual.h" +#include "ivsrcid/ivsrcid_vislands30.h" #define DCE_VIRTUAL_VBLANK_PERIOD 16666666 @@ -378,7 +379,7 @@ static int dce_virtual_sw_init(void *handle) int r, i; struct amdgpu_device *adev = (struct amdgpu_device *)handle; - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 229, &adev->crtc_irq); + r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, VISLANDS30_IV_SRCID_SMU_DISP_TIMER2_TRIGGER, &adev->crtc_irq); if (r) return r; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index 551f21bad6d38..5cd45210113f6 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -51,6 +51,8 @@ #include "smu/smu_7_1_3_d.h" +#include "ivsrcid/ivsrcid_vislands30.h" + #define GFX8_NUM_GFX_RINGS 1 #define GFX8_MEC_HPD_SIZE 2048 @@ -2047,35 +2049,35 @@ static int gfx_v8_0_sw_init(void *handle) adev->gfx.mec.num_queue_per_pipe = 8; /* KIQ event */ - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 178, &adev->gfx.kiq.irq); + r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, VISLANDS30_IV_SRCID_CP_INT_IB2, &adev->gfx.kiq.irq); if (r) return r; /* EOP Event */ - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 181, &adev->gfx.eop_irq); + r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, VISLANDS30_IV_SRCID_CP_END_OF_PIPE, &adev->gfx.eop_irq); if (r) return r; /* Privileged reg */ - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 184, + r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, VISLANDS30_IV_SRCID_CP_PRIV_REG_FAULT, &adev->gfx.priv_reg_irq); if (r) return r; /* Privileged inst */ - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 185, + r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, VISLANDS30_IV_SRCID_CP_PRIV_INSTR_FAULT, &adev->gfx.priv_inst_irq); if (r) return r; /* Add CP EDC/ECC irq */ - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 197, + r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, VISLANDS30_IV_SRCID_CP_ECC_ERROR, &adev->gfx.cp_ecc_error_irq); if (r) return r; /* SQ interrupts. */ - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 239, + r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, VISLANDS30_IV_SRCID_SQ_INTERRUPT_MSG, &adev->gfx.sq_irq); if (r) { DRM_ERROR("amdgpu_irq_add() for SQ failed: %d\n", r); diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c index 78339309a00c6..10920f0bd85ff 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c @@ -43,6 +43,8 @@ #include "amdgpu_atombios.h" +#include "ivsrcid/ivsrcid_vislands30.h" + static void gmc_v7_0_set_gmc_funcs(struct amdgpu_device *adev); static void gmc_v7_0_set_irq_funcs(struct amdgpu_device *adev); static int gmc_v7_0_wait_for_idle(void *handle); @@ -996,11 +998,11 @@ static int gmc_v7_0_sw_init(void *handle) adev->gmc.vram_type = gmc_v7_0_convert_vram_type(tmp); } - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 146, &adev->gmc.vm_fault); + r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, VISLANDS30_IV_SRCID_GFX_PAGE_INV_FAULT, &adev->gmc.vm_fault); if (r) return r; - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 147, &adev->gmc.vm_fault); + r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, VISLANDS30_IV_SRCID_GFX_MEM_PROT_FAULT, &adev->gmc.vm_fault); if (r) return r; diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c index a86332f36c3e0..75f3ffb2891e9 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c @@ -44,6 +44,8 @@ #include "amdgpu_atombios.h" +#include "ivsrcid/ivsrcid_vislands30.h" + static void gmc_v8_0_set_gmc_funcs(struct amdgpu_device *adev); static void gmc_v8_0_set_irq_funcs(struct amdgpu_device *adev); static int gmc_v8_0_wait_for_idle(void *handle); @@ -1100,11 +1102,11 @@ static int gmc_v8_0_sw_init(void *handle) adev->gmc.vram_type = gmc_v8_0_convert_vram_type(tmp); } - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 146, &adev->gmc.vm_fault); + r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, VISLANDS30_IV_SRCID_GFX_PAGE_INV_FAULT, &adev->gmc.vm_fault); if (r) return r; - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 147, &adev->gmc.vm_fault); + r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, VISLANDS30_IV_SRCID_GFX_MEM_PROT_FAULT, &adev->gmc.vm_fault); if (r) return r; diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c index cee4fae76d200..15ae4bc9c0727 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c @@ -44,6 +44,8 @@ #include "iceland_sdma_pkt_open.h" +#include "ivsrcid/ivsrcid_vislands30.h" + static void sdma_v2_4_set_ring_funcs(struct amdgpu_device *adev); static void sdma_v2_4_set_buffer_funcs(struct amdgpu_device *adev); static void sdma_v2_4_set_vm_pte_funcs(struct amdgpu_device *adev); @@ -896,7 +898,7 @@ static int sdma_v2_4_sw_init(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; /* SDMA trap event */ - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 224, + r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, VISLANDS30_IV_SRCID_SDMA_TRAP, &adev->sdma.trap_irq); if (r) return r; @@ -908,7 +910,7 @@ static int sdma_v2_4_sw_init(void *handle) return r; /* SDMA Privileged inst */ - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 247, + r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, VISLANDS30_IV_SRCID_SDMA_SRBM_WRITE, &adev->sdma.illegal_inst_irq); if (r) return r; diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c index 99616dd9594f2..1e07ff274d734 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c @@ -44,6 +44,8 @@ #include "tonga_sdma_pkt_open.h" +#include "ivsrcid/ivsrcid_vislands30.h" + static void sdma_v3_0_set_ring_funcs(struct amdgpu_device *adev); static void sdma_v3_0_set_buffer_funcs(struct amdgpu_device *adev); static void sdma_v3_0_set_vm_pte_funcs(struct amdgpu_device *adev); @@ -1175,7 +1177,7 @@ static int sdma_v3_0_sw_init(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; /* SDMA trap event */ - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 224, + r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, VISLANDS30_IV_SRCID_SDMA_TRAP, &adev->sdma.trap_irq); if (r) return r; @@ -1187,7 +1189,7 @@ static int sdma_v3_0_sw_init(void *handle) return r; /* SDMA Privileged inst */ - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 247, + r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, VISLANDS30_IV_SRCID_SDMA_SRBM_WRITE, &adev->sdma.illegal_inst_irq); if (r) return r; diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c index 341ee6d55ce89..aeaa1ca46a99d 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c @@ -35,6 +35,7 @@ #include "vi.h" #include "smu/smu_7_1_2_d.h" #include "smu/smu_7_1_2_sh_mask.h" +#include "ivsrcid/ivsrcid_vislands30.h" static void uvd_v5_0_set_ring_funcs(struct amdgpu_device *adev); static void uvd_v5_0_set_irq_funcs(struct amdgpu_device *adev); @@ -104,7 +105,7 @@ static int uvd_v5_0_sw_init(void *handle) int r; /* UVD TRAP */ - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 124, &adev->uvd.inst->irq); + r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, VISLANDS30_IV_SRCID_UVD_SYSTEM_MESSAGE, &adev->uvd.inst->irq); if (r) return r; diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c index 8ee1c2eaaa14e..2623f249cb7a8 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c @@ -36,6 +36,7 @@ #include "bif/bif_5_1_d.h" #include "gmc/gmc_8_1_d.h" #include "vi.h" +#include "ivsrcid/ivsrcid_vislands30.h" /* Polaris10/11/12 firmware version */ #define FW_1_130_16 ((1 << 24) | (130 << 16) | (16 << 8)) @@ -400,14 +401,14 @@ static int uvd_v6_0_sw_init(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; /* UVD TRAP */ - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 124, &adev->uvd.inst->irq); + r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, VISLANDS30_IV_SRCID_UVD_SYSTEM_MESSAGE, &adev->uvd.inst->irq); if (r) return r; /* UVD ENC TRAP */ if (uvd_v6_0_enc_support(adev)) { for (i = 0; i < adev->uvd.num_enc_rings; ++i) { - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, i + 119, &adev->uvd.inst->irq); + r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, i + VISLANDS30_IV_SRCID_UVD_ENC_GEN_PURP, &adev->uvd.inst->irq); if (r) return r; } diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c index 99604d0262ada..cc6ce6cc03f47 100644 --- a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c @@ -39,6 +39,7 @@ #include "smu/smu_7_1_2_sh_mask.h" #include "gca/gfx_8_0_d.h" #include "gca/gfx_8_0_sh_mask.h" +#include "ivsrcid/ivsrcid_vislands30.h" #define GRBM_GFX_INDEX__VCE_INSTANCE__SHIFT 0x04 @@ -422,7 +423,7 @@ static int vce_v3_0_sw_init(void *handle) int r, i; /* VCE */ - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 167, &adev->vce.irq); + r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, VISLANDS30_IV_SRCID_VCE_TRAP, &adev->vce.irq); if (r) return r; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c index 2f7e70730e3cc..052e60dfaf9fd 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c @@ -48,6 +48,8 @@ #include "processpptables.h" #include "pp_thermal.h" +#include "ivsrcid/ivsrcid_vislands30.h" + #define MC_CG_ARB_FREQ_F0 0x0a #define MC_CG_ARB_FREQ_F1 0x0b #define MC_CG_ARB_FREQ_F2 0x0c @@ -4105,17 +4107,17 @@ static int smu7_register_irq_handlers(struct pp_hwmgr *hwmgr) amdgpu_irq_add_id((struct amdgpu_device *)(hwmgr->adev), AMDGPU_IH_CLIENTID_LEGACY, - 230, + VISLANDS30_IV_SRCID_CG_TSS_THERMAL_LOW_TO_HIGH, source); amdgpu_irq_add_id((struct amdgpu_device *)(hwmgr->adev), AMDGPU_IH_CLIENTID_LEGACY, - 231, + VISLANDS30_IV_SRCID_CG_TSS_THERMAL_HIGH_TO_LOW, source); /* Register CTF(GPIO_19) interrupt */ amdgpu_irq_add_id((struct amdgpu_device *)(hwmgr->adev), AMDGPU_IH_CLIENTID_LEGACY, - 83, + VISLANDS30_IV_SRCID_GPIO_19, source); return 0; -- GitLab From ba61bb17496d1664bf7c5c2fd650d5fd78bd0a92 Mon Sep 17 00:00:00 2001 From: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Date: Fri, 25 May 2018 10:44:12 -0400 Subject: [PATCH 1094/1506] drm/amd: Add interrupt source definitions for SOC15 v3. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stop using 'magic numbers' when registering interrupt sources. v2: Switch to kernel style comments. v3: Rebase. Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Acked-by: Christian König <christian.koenig@amd.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../amd/include/ivsrcid/gfx/irqsrcs_gfx_9_0.h | 55 +++++++++++++++++++ .../include/ivsrcid/sdma0/irqsrcs_sdma0_4_0.h | 50 +++++++++++++++++ .../include/ivsrcid/sdma1/irqsrcs_sdma1_4_0.h | 50 +++++++++++++++++ .../include/ivsrcid/smuio/irqsrcs_smuio_9_0.h | 32 +++++++++++ .../amd/include/ivsrcid/thm/irqsrcs_thm_9_0.h | 33 +++++++++++ .../amd/include/ivsrcid/uvd/irqsrcs_uvd_7_0.h | 34 ++++++++++++ .../amd/include/ivsrcid/vce/irqsrcs_vce_4_0.h | 34 ++++++++++++ .../amd/include/ivsrcid/vcn/irqsrcs_vcn_1_0.h | 34 ++++++++++++ .../amd/include/ivsrcid/vmc/irqsrcs_vmc_1_0.h | 37 +++++++++++++ 9 files changed, 359 insertions(+) create mode 100644 drivers/gpu/drm/amd/include/ivsrcid/gfx/irqsrcs_gfx_9_0.h create mode 100644 drivers/gpu/drm/amd/include/ivsrcid/sdma0/irqsrcs_sdma0_4_0.h create mode 100644 drivers/gpu/drm/amd/include/ivsrcid/sdma1/irqsrcs_sdma1_4_0.h create mode 100644 drivers/gpu/drm/amd/include/ivsrcid/smuio/irqsrcs_smuio_9_0.h create mode 100644 drivers/gpu/drm/amd/include/ivsrcid/thm/irqsrcs_thm_9_0.h create mode 100644 drivers/gpu/drm/amd/include/ivsrcid/uvd/irqsrcs_uvd_7_0.h create mode 100644 drivers/gpu/drm/amd/include/ivsrcid/vce/irqsrcs_vce_4_0.h create mode 100644 drivers/gpu/drm/amd/include/ivsrcid/vcn/irqsrcs_vcn_1_0.h create mode 100644 drivers/gpu/drm/amd/include/ivsrcid/vmc/irqsrcs_vmc_1_0.h diff --git a/drivers/gpu/drm/amd/include/ivsrcid/gfx/irqsrcs_gfx_9_0.h b/drivers/gpu/drm/amd/include/ivsrcid/gfx/irqsrcs_gfx_9_0.h new file mode 100644 index 0000000000000..36306c57a2b41 --- /dev/null +++ b/drivers/gpu/drm/amd/include/ivsrcid/gfx/irqsrcs_gfx_9_0.h @@ -0,0 +1,55 @@ +/* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __IRQSRCS_GFX_9_0_H__ +#define __IRQSRCS_GFX_9_0_H__ + + +#define GFX_9_0__SRCID__CP_RB_INTERRUPT_PKT 176 /* B0 CP_INTERRUPT pkt in RB */ +#define GFX_9_0__SRCID__CP_IB1_INTERRUPT_PKT 177 /* B1 CP_INTERRUPT pkt in IB1 */ +#define GFX_9_0__SRCID__CP_IB2_INTERRUPT_PKT 178 /* B2 CP_INTERRUPT pkt in IB2 */ +#define GFX_9_0__SRCID__CP_PM4_PKT_RSVD_BIT_ERROR 180 /* B4 PM4 Pkt Rsvd Bits Error */ +#define GFX_9_0__SRCID__CP_EOP_INTERRUPT 181 /* B5 End-of-Pipe Interrupt */ +#define GFX_9_0__SRCID__CP_BAD_OPCODE_ERROR 183 /* B7 Bad Opcode Error */ +#define GFX_9_0__SRCID__CP_PRIV_REG_FAULT 184 /* B8 Privileged Register Fault */ +#define GFX_9_0__SRCID__CP_PRIV_INSTR_FAULT 185 /* B9 Privileged Instr Fault */ +#define GFX_9_0__SRCID__CP_WAIT_MEM_SEM_FAULT 186 /* BA Wait Memory Semaphore Fault (Synchronization Object Fault) */ +#define GFX_9_0__SRCID__CP_CTX_EMPTY_INTERRUPT 187 /* BB Context Empty Interrupt */ +#define GFX_9_0__SRCID__CP_CTX_BUSY_INTERRUPT 188 /* BC Context Busy Interrupt */ +#define GFX_9_0__SRCID__CP_ME_WAIT_REG_MEM_POLL_TIMEOUT 192 /* C0 CP.ME Wait_Reg_Mem Poll Timeout */ +#define GFX_9_0__SRCID__CP_SIG_INCOMPLETE 193 /* C1 "Surface Probe Fault Signal Incomplete" */ +#define GFX_9_0__SRCID__CP_PREEMPT_ACK 194 /* C2 Preemption Ack-wledge */ +#define GFX_9_0__SRCID__CP_GPF 195 /* C3 General Protection Fault (GPF) */ +#define GFX_9_0__SRCID__CP_GDS_ALLOC_ERROR 196 /* C4 GDS Alloc Error */ +#define GFX_9_0__SRCID__CP_ECC_ERROR 197 /* C5 ECC Error */ +#define GFX_9_0__SRCID__CP_COMPUTE_QUERY_STATUS 199 /* C7 Compute query status */ +#define GFX_9_0__SRCID__CP_VM_DOORBELL 200 /* C8 Unattached VM Doorbell Received */ +#define GFX_9_0__SRCID__CP_FUE_ERROR 201 /* C9 ECC FUE Error */ +#define GFX_9_0__SRCID__RLC_STRM_PERF_MONITOR_INTERRUPT 202 /* CA Streaming Perf Monitor Interrupt */ +#define GFX_9_0__SRCID__GRBM_RD_TIMEOUT_ERROR 232 /* E8 CRead timeout error */ +#define GFX_9_0__SRCID__GRBM_REG_GUI_IDLE 233 /* E9 Register GUI Idle */ +#define GFX_9_0__SRCID__SQ_INTERRUPT_ID 239 /* EF SQ Interrupt (ttrace wrap, errors) */ + +#endif /* __IRQSRCS_GFX_9_0_H__ */ diff --git a/drivers/gpu/drm/amd/include/ivsrcid/sdma0/irqsrcs_sdma0_4_0.h b/drivers/gpu/drm/amd/include/ivsrcid/sdma0/irqsrcs_sdma0_4_0.h new file mode 100644 index 0000000000000..802413832fe80 --- /dev/null +++ b/drivers/gpu/drm/amd/include/ivsrcid/sdma0/irqsrcs_sdma0_4_0.h @@ -0,0 +1,50 @@ +/* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __IRQSRCS_SDMA0_4_0_H__ +#define __IRQSRCS_SDMA0_4_0_H__ + +#define SDMA0_4_0__SRCID__SDMA_ATOMIC_RTN_DONE 217 /* 0xD9 SDMA atomic*_rtn ops complete */ +#define SDMA0_4_0__SRCID__SDMA_ATOMIC_TIMEOUT 218 /* 0xDA SDMA atomic CMPSWAP loop timeout */ +#define SDMA0_4_0__SRCID__SDMA_IB_PREEMPT 219 /* 0xDB sdma mid-command buffer preempt interrupt */ +#define SDMA0_4_0__SRCID__SDMA_ECC 220 /* 0xDC ECC Error */ +#define SDMA0_4_0__SRCID__SDMA_PAGE_FAULT 221 /* 0xDD Page Fault Error from UTCL2 when nack=3 */ +#define SDMA0_4_0__SRCID__SDMA_PAGE_NULL 222 /* 0xDE Page Null from UTCL2 when nack=2 */ +#define SDMA0_4_0__SRCID__SDMA_XNACK 223 /* 0xDF Page retry timeout after UTCL2 return nack=1 */ +#define SDMA0_4_0__SRCID__SDMA_TRAP 224 /* 0xE0 Trap */ +#define SDMA0_4_0__SRCID__SDMA_SEM_INCOMPLETE_TIMEOUT 225 /* 0xE1 0xDAGPF (Sem incomplete timeout) */ +#define SDMA0_4_0__SRCID__SDMA_SEM_WAIT_FAIL_TIMEOUT 226 /* 0xE2 Semaphore wait fail timeout */ +#define SDMA0_4_0__SRCID__SDMA_SRAM_ECC 228 /* 0xE4 SRAM ECC Error */ +#define SDMA0_4_0__SRCID__SDMA_PREEMPT 240 /* 0xF0 SDMA New Run List */ +#define SDMA0_4_0__SRCID__SDMA_VM_HOLE 242 /* 0xF2 MC or SEM address in VM hole */ +#define SDMA0_4_0__SRCID__SDMA_CTXEMPTY 243 /* 0xF3 Context Empty */ +#define SDMA0_4_0__SRCID__SDMA_DOORBELL_INVALID 244 /* 0xF4 Doorbell BE invalid */ +#define SDMA0_4_0__SRCID__SDMA_FROZEN 245 /* 0xF5 SDMA Frozen */ +#define SDMA0_4_0__SRCID__SDMA_POLL_TIMEOUT 246 /* 0xF6 SRBM read poll timeout */ +#define SDMA0_4_0__SRCID__SDMA_SRBMWRITE 247 /* 0xF7 SRBM write Protection */ + +#endif /* __IRQSRCS_SDMA_4_0_H__ */ + + diff --git a/drivers/gpu/drm/amd/include/ivsrcid/sdma1/irqsrcs_sdma1_4_0.h b/drivers/gpu/drm/amd/include/ivsrcid/sdma1/irqsrcs_sdma1_4_0.h new file mode 100644 index 0000000000000..d12a35619f9aa --- /dev/null +++ b/drivers/gpu/drm/amd/include/ivsrcid/sdma1/irqsrcs_sdma1_4_0.h @@ -0,0 +1,50 @@ +/* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __IRQSRCS_SDMA1_4_0_H__ +#define __IRQSRCS_SDMA1_4_0_H__ + +#define SDMA1_4_0__SRCID__SDMA_ATOMIC_RTN_DONE 217 /* 0xD9 SDMA atomic*_rtn ops complete */ +#define SDMA1_4_0__SRCID__SDMA_ATOMIC_TIMEOUT 218 /* 0xDA SDMA atomic CMPSWAP loop timeout */ +#define SDMA1_4_0__SRCID__SDMA_IB_PREEMPT 219 /* 0xDB sdma mid-command buffer preempt interrupt */ +#define SDMA1_4_0__SRCID__SDMA_ECC 220 /* 0xDC ECC Error */ +#define SDMA1_4_0__SRCID__SDMA_PAGE_FAULT 221 /* 0xDD Page Fault Error from UTCL2 when nack=3 */ +#define SDMA1_4_0__SRCID__SDMA_PAGE_NULL 222 /* 0xDE Page Null from UTCL2 when nack=2 */ +#define SDMA1_4_0__SRCID__SDMA_XNACK 223 /* 0xDF Page retry timeout after UTCL2 return nack=1 */ +#define SDMA1_4_0__SRCID__SDMA_TRAP 224 /* 0xE0 Trap */ +#define SDMA1_4_0__SRCID__SDMA_SEM_INCOMPLETE_TIMEOUT 225 /* 0xE1 0xDAGPF (Sem incomplete timeout) */ +#define SDMA1_4_0__SRCID__SDMA_SEM_WAIT_FAIL_TIMEOUT 226 /* 0xE2 Semaphore wait fail timeout */ +#define SDMA1_4_0__SRCID__SDMA_SRAM_ECC 228 /* 0xE4 SRAM ECC Error */ +#define SDMA1_4_0__SRCID__SDMA_PREEMPT 240 /* 0xF0 SDMA New Run List */ +#define SDMA1_4_0__SRCID__SDMA_VM_HOLE 242 /* 0xF2 MC or SEM address in VM hole */ +#define SDMA1_4_0__SRCID__SDMA_CTXEMPTY 243 /* 0xF3 Context Empty */ +#define SDMA1_4_0__SRCID__SDMA_DOORBELL_INVALID 244 /* 0xF4 Doorbell BE invalid */ +#define SDMA1_4_0__SRCID__SDMA_FROZEN 245 /* 0xF5 SDMA Frozen */ +#define SDMA1_4_0__SRCID__SDMA_POLL_TIMEOUT 246 /* 0xF6 SRBM read poll timeout */ +#define SDMA1_4_0__SRCID__SDMA_SRBMWRITE 247 /* 0xF7 SRBM write Protection */ + +#endif /* __IRQSRCS_SDMA1_4_0_H__ */ + + diff --git a/drivers/gpu/drm/amd/include/ivsrcid/smuio/irqsrcs_smuio_9_0.h b/drivers/gpu/drm/amd/include/ivsrcid/smuio/irqsrcs_smuio_9_0.h new file mode 100644 index 0000000000000..02bab4673cd4e --- /dev/null +++ b/drivers/gpu/drm/amd/include/ivsrcid/smuio/irqsrcs_smuio_9_0.h @@ -0,0 +1,32 @@ +/* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __IRQSRCS_SMUIO_9_0_H__ +#define __IRQSRCS_SMUIO_9_0_H__ + +#define SMUIO_9_0__SRCID__SMUIO_GPIO19 83 /* GPIO19 interrupt */ + +#endif /* __IRQSRCS_SMUIO_9_0_H__ */ + diff --git a/drivers/gpu/drm/amd/include/ivsrcid/thm/irqsrcs_thm_9_0.h b/drivers/gpu/drm/amd/include/ivsrcid/thm/irqsrcs_thm_9_0.h new file mode 100644 index 0000000000000..5218bc53fb2db --- /dev/null +++ b/drivers/gpu/drm/amd/include/ivsrcid/thm/irqsrcs_thm_9_0.h @@ -0,0 +1,33 @@ +/* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __IRQSRCS_THM_9_0_H__ +#define __IRQSRCS_THM_9_0_H__ + +#define THM_9_0__SRCID__THM_DIG_THERM_L2H 0 /* ASIC_TEMP > CG_THERMAL_INT.DIG_THERM_INTH */ +#define THM_9_0__SRCID__THM_DIG_THERM_H2L 1 /* ASIC_TEMP < CG_THERMAL_INT.DIG_THERM_INTL */ + +#endif /* __IRQSRCS_THM_9_0_H__ */ + diff --git a/drivers/gpu/drm/amd/include/ivsrcid/uvd/irqsrcs_uvd_7_0.h b/drivers/gpu/drm/amd/include/ivsrcid/uvd/irqsrcs_uvd_7_0.h new file mode 100644 index 0000000000000..fb041aee6c66a --- /dev/null +++ b/drivers/gpu/drm/amd/include/ivsrcid/uvd/irqsrcs_uvd_7_0.h @@ -0,0 +1,34 @@ +/* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __IRQSRCS_UVD_7_0_H__ +#define __IRQSRCS_UVD_7_0_H__ + +#define UVD_7_0__SRCID__UVD_ENC_GEN_PURP 119 +#define UVD_7_0__SRCID__UVD_ENC_LOW_LATENCY 120 +#define UVD_7_0__SRCID__UVD_SYSTEM_MESSAGE_INTERRUPT 124 /* UVD system message interrupt */ + +#endif /* __IRQSRCS_UVD_7_0_H__ */ + diff --git a/drivers/gpu/drm/amd/include/ivsrcid/vce/irqsrcs_vce_4_0.h b/drivers/gpu/drm/amd/include/ivsrcid/vce/irqsrcs_vce_4_0.h new file mode 100644 index 0000000000000..3440bab565af5 --- /dev/null +++ b/drivers/gpu/drm/amd/include/ivsrcid/vce/irqsrcs_vce_4_0.h @@ -0,0 +1,34 @@ +/* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __IRQSRCS_VCE_4_0_H__ +#define __IRQSRCS_VCE_4_0_H__ + +#define VCE_4_0__CTXID__VCE_TRAP_GENERAL_PURPOSE 0 +#define VCE_4_0__CTXID__VCE_TRAP_LOW_LATENCY 1 +#define VCE_4_0__CTXID__VCE_TRAP_REAL_TIME 2 + +#endif /* __IRQSRCS_VCE_4_0_H__ */ + diff --git a/drivers/gpu/drm/amd/include/ivsrcid/vcn/irqsrcs_vcn_1_0.h b/drivers/gpu/drm/amd/include/ivsrcid/vcn/irqsrcs_vcn_1_0.h new file mode 100644 index 0000000000000..e5951709bfc36 --- /dev/null +++ b/drivers/gpu/drm/amd/include/ivsrcid/vcn/irqsrcs_vcn_1_0.h @@ -0,0 +1,34 @@ +/* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __IRQSRCS_VCN_1_0_H__ +#define __IRQSRCS_VCN_1_0_H__ + +#define VCN_1_0__SRCID__UVD_ENC_GENERAL_PURPOSE 119 /* 0x77 Encoder General Purpose */ +#define VCN_1_0__SRCID__UVD_ENC_LOW_LATENCY 120 /* 0x78 Encoder Low Latency */ +#define VCN_1_0__SRCID__UVD_SYSTEM_MESSAGE_INTERRUPT 124 /* 0x7c UVD system message interrupt */ + +#endif /* __IRQSRCS_VCN_1_0_H__ */ + diff --git a/drivers/gpu/drm/amd/include/ivsrcid/vmc/irqsrcs_vmc_1_0.h b/drivers/gpu/drm/amd/include/ivsrcid/vmc/irqsrcs_vmc_1_0.h new file mode 100644 index 0000000000000..d130936c99890 --- /dev/null +++ b/drivers/gpu/drm/amd/include/ivsrcid/vmc/irqsrcs_vmc_1_0.h @@ -0,0 +1,37 @@ +/* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __IRQSRCS_VMC_1_0_H__ +#define __IRQSRCS_VMC_1_0_H__ + + +#define VMC_1_0__SRCID__VM_FAULT 0 +#define VMC_1_0__SRCID__VM_CONTEXT0_ALL 256 +#define VMC_1_0__SRCID__VM_CONTEXT1_ALL 257 + +#define UTCL2_1_0__SRCID__FAULT 0 /* UTC L2 has encountered a fault or retry scenario */ + + +#endif /* __IRQSRCS_VMC_1_0_H__ */ -- GitLab From 44a99b65fc27474b66f7173b971bfbd67ca6ba74 Mon Sep 17 00:00:00 2001 From: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Date: Fri, 25 May 2018 10:45:34 -0400 Subject: [PATCH 1095/1506] drm/amd: Use newly added interrupt source defs for SOC15. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 10 ++++++---- drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c | 6 ++++-- drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c | 7 +++++-- drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c | 5 +++-- drivers/gpu/drm/amd/amdgpu/vce_v4_0.c | 2 ++ drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c | 6 ++++-- drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.c | 8 +++++--- 7 files changed, 29 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index e6d19e7fbfbda..a12da4a66b01c 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -38,6 +38,8 @@ #include "clearstate_gfx9.h" #include "v9_structs.h" +#include "ivsrcid/gfx/irqsrcs_gfx_9_0.h" + #define GFX9_NUM_GFX_RINGS 1 #define GFX9_MEC_HPD_SIZE 2048 #define RLCG_UCODE_LOADING_START_ADDRESS 0x00002000L @@ -1488,23 +1490,23 @@ static int gfx_v9_0_sw_init(void *handle) adev->gfx.mec.num_queue_per_pipe = 8; /* KIQ event */ - r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_GRBM_CP, 178, &adev->gfx.kiq.irq); + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_GRBM_CP, GFX_9_0__SRCID__CP_IB2_INTERRUPT_PKT, &adev->gfx.kiq.irq); if (r) return r; /* EOP Event */ - r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_GRBM_CP, 181, &adev->gfx.eop_irq); + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_GRBM_CP, GFX_9_0__SRCID__CP_EOP_INTERRUPT, &adev->gfx.eop_irq); if (r) return r; /* Privileged reg */ - r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_GRBM_CP, 184, + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_GRBM_CP, GFX_9_0__SRCID__CP_PRIV_REG_FAULT, &adev->gfx.priv_reg_irq); if (r) return r; /* Privileged inst */ - r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_GRBM_CP, 185, + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_GRBM_CP, GFX_9_0__SRCID__CP_PRIV_INSTR_FAULT, &adev->gfx.priv_inst_irq); if (r) return r; diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c index 7f238149ba54a..9df94b45d17de 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c @@ -43,6 +43,8 @@ #include "gfxhub_v1_0.h" #include "mmhub_v1_0.h" +#include "ivsrcid/vmc/irqsrcs_vmc_1_0.h" + /* add these here since we already include dce12 headers and these are for DCN */ #define mmHUBP0_DCSURF_PRI_VIEWPORT_DIMENSION 0x055d #define mmHUBP0_DCSURF_PRI_VIEWPORT_DIMENSION_BASE_IDX 2 @@ -877,9 +879,9 @@ static int gmc_v9_0_sw_init(void *handle) } /* This interrupt is VMC page fault.*/ - r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_VMC, 0, + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_VMC, VMC_1_0__SRCID__VM_FAULT, &adev->gmc.vm_fault); - r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_UTCL2, 0, + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_UTCL2, UTCL2_1_0__SRCID__FAULT, &adev->gmc.vm_fault); if (r) diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c index 572ca63cf676b..e7ca4623cfb94 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c @@ -38,6 +38,9 @@ #include "soc15.h" #include "vega10_sdma_pkt_open.h" +#include "ivsrcid/sdma0/irqsrcs_sdma0_4_0.h" +#include "ivsrcid/sdma1/irqsrcs_sdma1_4_0.h" + MODULE_FIRMWARE("amdgpu/vega10_sdma.bin"); MODULE_FIRMWARE("amdgpu/vega10_sdma1.bin"); MODULE_FIRMWARE("amdgpu/vega12_sdma.bin"); @@ -1225,13 +1228,13 @@ static int sdma_v4_0_sw_init(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; /* SDMA trap event */ - r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_SDMA0, 224, + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_SDMA0, SDMA0_4_0__SRCID__SDMA_TRAP, &adev->sdma.trap_irq); if (r) return r; /* SDMA trap event */ - r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_SDMA1, 224, + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_SDMA1, SDMA1_4_0__SRCID__SDMA_TRAP, &adev->sdma.trap_irq); if (r) return r; diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c index ba244d3b74dbb..ce360ad16856f 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c @@ -39,6 +39,7 @@ #include "hdp/hdp_4_0_offset.h" #include "mmhub/mmhub_1_0_offset.h" #include "mmhub/mmhub_1_0_sh_mask.h" +#include "ivsrcid/uvd/irqsrcs_uvd_7_0.h" #define UVD7_MAX_HW_INSTANCES_VEGA20 2 @@ -402,13 +403,13 @@ static int uvd_v7_0_sw_init(void *handle) for (j = 0; j < adev->uvd.num_uvd_inst; j++) { /* UVD TRAP */ - r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_uvds[j], 124, &adev->uvd.inst[j].irq); + r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_uvds[j], UVD_7_0__SRCID__UVD_SYSTEM_MESSAGE_INTERRUPT, &adev->uvd.inst[j].irq); if (r) return r; /* UVD ENC TRAP */ for (i = 0; i < adev->uvd.num_enc_rings; ++i) { - r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_uvds[j], i + 119, &adev->uvd.inst[j].irq); + r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_uvds[j], i + UVD_7_0__SRCID__UVD_ENC_GEN_PURP, &adev->uvd.inst[j].irq); if (r) return r; } diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c index 575bf9709389a..65f8860169e95 100644 --- a/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c @@ -39,6 +39,8 @@ #include "mmhub/mmhub_1_0_offset.h" #include "mmhub/mmhub_1_0_sh_mask.h" +#include "ivsrcid/vce/irqsrcs_vce_4_0.h" + #define VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK 0x02 #define VCE_V4_0_FW_SIZE (384 * 1024) diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c index ca4265bc10b99..2ce91a748c402 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c @@ -35,6 +35,8 @@ #include "mmhub/mmhub_9_1_offset.h" #include "mmhub/mmhub_9_1_sh_mask.h" +#include "ivsrcid/vcn/irqsrcs_vcn_1_0.h" + static int vcn_v1_0_stop(struct amdgpu_device *adev); static void vcn_v1_0_set_dec_ring_funcs(struct amdgpu_device *adev); static void vcn_v1_0_set_enc_ring_funcs(struct amdgpu_device *adev); @@ -77,13 +79,13 @@ static int vcn_v1_0_sw_init(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; /* VCN DEC TRAP */ - r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_VCN, 124, &adev->vcn.irq); + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_VCN, VCN_1_0__SRCID__UVD_SYSTEM_MESSAGE_INTERRUPT, &adev->vcn.irq); if (r) return r; /* VCN ENC TRAP */ for (i = 0; i < adev->vcn.num_enc_rings; ++i) { - r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_VCN, i + 119, + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_VCN, i + VCN_1_0__SRCID__UVD_ENC_GENERAL_PURPOSE, &adev->vcn.irq); if (r) return r; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.c index 3effb5583d1f1..8eea49e4c74de 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.c @@ -25,6 +25,8 @@ #include "ppatomctrl.h" #include "ppsmc.h" #include "atom.h" +#include "ivsrcid/thm/irqsrcs_thm_9_0.h" +#include "ivsrcid/smuio/irqsrcs_smuio_9_0.h" uint8_t convert_to_vid(uint16_t vddc) { @@ -594,17 +596,17 @@ int smu9_register_irq_handlers(struct pp_hwmgr *hwmgr) amdgpu_irq_add_id((struct amdgpu_device *)(hwmgr->adev), SOC15_IH_CLIENTID_THM, - 0, + THM_9_0__SRCID__THM_DIG_THERM_L2H, source); amdgpu_irq_add_id((struct amdgpu_device *)(hwmgr->adev), SOC15_IH_CLIENTID_THM, - 1, + THM_9_0__SRCID__THM_DIG_THERM_H2L, source); /* Register CTF(GPIO_19) interrupt */ amdgpu_irq_add_id((struct amdgpu_device *)(hwmgr->adev), SOC15_IH_CLIENTID_ROM_SMUIO, - 83, + SMUIO_9_0__SRCID__SMUIO_GPIO19, source); return 0; -- GitLab From b7d85e1db32ea85b09f58f416da48f44285ff41f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Thu, 12 Jul 2018 14:31:25 +0200 Subject: [PATCH 1096/1506] drm/amdgpu: fix TTM move entity init order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are initializing the entity before the scheduler is actually initialized. This can lead to all kind of problem, but especially NULL pointer deref because of Nayan's scheduler work. Signed-off-by: Christian König <christian.koenig@amd.com> Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 37 ++++++++++++++----------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 0e47f15b0f977..6a3fead5c1f0d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -104,8 +104,6 @@ static void amdgpu_ttm_mem_global_release(struct drm_global_reference *ref) static int amdgpu_ttm_global_init(struct amdgpu_device *adev) { struct drm_global_reference *global_ref; - struct amdgpu_ring *ring; - struct drm_sched_rq *rq; int r; /* ensure reference is false in case init fails */ @@ -138,21 +136,10 @@ static int amdgpu_ttm_global_init(struct amdgpu_device *adev) mutex_init(&adev->mman.gtt_window_lock); - ring = adev->mman.buffer_funcs_ring; - rq = &ring->sched.sched_rq[DRM_SCHED_PRIORITY_KERNEL]; - r = drm_sched_entity_init(&ring->sched, &adev->mman.entity, - rq, NULL); - if (r) { - DRM_ERROR("Failed setting up TTM BO move run queue.\n"); - goto error_entity; - } - adev->mman.mem_global_referenced = true; return 0; -error_entity: - drm_global_item_unref(&adev->mman.bo_global_ref.ref); error_bo: drm_global_item_unref(&adev->mman.mem_global_ref); error_mem: @@ -162,8 +149,6 @@ static int amdgpu_ttm_global_init(struct amdgpu_device *adev) static void amdgpu_ttm_global_fini(struct amdgpu_device *adev) { if (adev->mman.mem_global_referenced) { - drm_sched_entity_destroy(adev->mman.entity.sched, - &adev->mman.entity); mutex_destroy(&adev->mman.gtt_window_lock); drm_global_item_unref(&adev->mman.bo_global_ref.ref); drm_global_item_unref(&adev->mman.mem_global_ref); @@ -1921,10 +1906,30 @@ void amdgpu_ttm_set_buffer_funcs_status(struct amdgpu_device *adev, bool enable) { struct ttm_mem_type_manager *man = &adev->mman.bdev.man[TTM_PL_VRAM]; uint64_t size; + int r; - if (!adev->mman.initialized || adev->in_gpu_reset) + if (!adev->mman.initialized || adev->in_gpu_reset || + adev->mman.buffer_funcs_enabled == enable) return; + if (enable) { + struct amdgpu_ring *ring; + struct drm_sched_rq *rq; + + ring = adev->mman.buffer_funcs_ring; + rq = &ring->sched.sched_rq[DRM_SCHED_PRIORITY_KERNEL]; + r = drm_sched_entity_init(&ring->sched, &adev->mman.entity, + rq, NULL); + if (r) { + DRM_ERROR("Failed setting up TTM BO move entity (%d)\n", + r); + return; + } + } else { + drm_sched_entity_destroy(adev->mman.entity.sched, + &adev->mman.entity); + } + /* this just adjusts TTM size idea, which sets lpfn to the correct value */ if (enable) size = adev->gmc.real_vram_size; -- GitLab From 8dc9fbbf274b7b2a647e06141aee70ffabf6dbc0 Mon Sep 17 00:00:00 2001 From: Nayan Deshmukh <nayan26deshmukh@gmail.com> Date: Fri, 13 Jul 2018 15:21:13 +0530 Subject: [PATCH 1097/1506] drm/scheduler: add a pointer to scheduler in the rq MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch is in preparation for a better load balancing in scheduler. It allows us to associate entities with the run queues instead of binding them to a scheduler. Signed-off-by: Nayan Deshmukh <nayan26deshmukh@gmail.com> Reviewed-by: Christian König <christian.koenig@amd.com> Acked-by: Eric Anholt <eric@anholt.net> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/scheduler/gpu_scheduler.c | 6 ++++-- include/drm/gpu_scheduler.h | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/scheduler/gpu_scheduler.c b/drivers/gpu/drm/scheduler/gpu_scheduler.c index 7d2560699b84e..429b1328653a0 100644 --- a/drivers/gpu/drm/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/scheduler/gpu_scheduler.c @@ -69,11 +69,13 @@ static void drm_sched_process_job(struct dma_fence *f, struct dma_fence_cb *cb); * * Initializes a scheduler runqueue. */ -static void drm_sched_rq_init(struct drm_sched_rq *rq) +static void drm_sched_rq_init(struct drm_gpu_scheduler *sched, + struct drm_sched_rq *rq) { spin_lock_init(&rq->lock); INIT_LIST_HEAD(&rq->entities); rq->current_entity = NULL; + rq->sched = sched; } /** @@ -926,7 +928,7 @@ int drm_sched_init(struct drm_gpu_scheduler *sched, sched->timeout = timeout; sched->hang_limit = hang_limit; for (i = DRM_SCHED_PRIORITY_MIN; i < DRM_SCHED_PRIORITY_MAX; i++) - drm_sched_rq_init(&sched->sched_rq[i]); + drm_sched_rq_init(sched, &sched->sched_rq[i]); init_waitqueue_head(&sched->wake_up_worker); init_waitqueue_head(&sched->job_scheduled); diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h index 4214ceb71c054..43e93d6077cf3 100644 --- a/include/drm/gpu_scheduler.h +++ b/include/drm/gpu_scheduler.h @@ -93,6 +93,7 @@ struct drm_sched_entity { * struct drm_sched_rq - queue of entities to be scheduled. * * @lock: to modify the entities list. + * @sched: the scheduler to which this rq belongs to. * @entities: list of the entities to be scheduled. * @current_entity: the entity which is to be scheduled. * @@ -102,6 +103,7 @@ struct drm_sched_entity { */ struct drm_sched_rq { spinlock_t lock; + struct drm_gpu_scheduler *sched; struct list_head entities; struct drm_sched_entity *current_entity; }; -- GitLab From aa16b6c6b4d979234f830a48add47d02c12bb569 Mon Sep 17 00:00:00 2001 From: Nayan Deshmukh <nayan26deshmukh@gmail.com> Date: Fri, 13 Jul 2018 15:21:14 +0530 Subject: [PATCH 1098/1506] drm/scheduler: modify args of drm_sched_entity_init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit replace run queue by a list of run queues and remove the sched arg as that is part of run queue itself Signed-off-by: Nayan Deshmukh <nayan26deshmukh@gmail.com> Reviewed-by: Christian König <christian.koenig@amd.com> Acked-by: Eric Anholt <eric@anholt.net> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c | 4 ++-- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 3 +-- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 4 ++-- drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c | 3 +-- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 3 +-- drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c | 4 ++-- drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c | 4 ++-- drivers/gpu/drm/etnaviv/etnaviv_drv.c | 8 ++++---- drivers/gpu/drm/scheduler/gpu_scheduler.c | 20 ++++++++++++-------- drivers/gpu/drm/v3d/v3d_drv.c | 7 +++---- include/drm/gpu_scheduler.h | 6 +++--- 11 files changed, 33 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c index 0120b24fae1b9..83e3b320a7938 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c @@ -90,8 +90,8 @@ static int amdgpu_ctx_init(struct amdgpu_device *adev, if (ring == &adev->gfx.kiq.ring) continue; - r = drm_sched_entity_init(&ring->sched, &ctx->rings[i].entity, - rq, &ctx->guilty); + r = drm_sched_entity_init(&ctx->rings[i].entity, + &rq, 1, &ctx->guilty); if (r) goto failed; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 6a3fead5c1f0d..11a12483c9950 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -1918,8 +1918,7 @@ void amdgpu_ttm_set_buffer_funcs_status(struct amdgpu_device *adev, bool enable) ring = adev->mman.buffer_funcs_ring; rq = &ring->sched.sched_rq[DRM_SCHED_PRIORITY_KERNEL]; - r = drm_sched_entity_init(&ring->sched, &adev->mman.entity, - rq, NULL); + r = drm_sched_entity_init(&adev->mman.entity, &rq, 1, NULL); if (r) { DRM_ERROR("Failed setting up TTM BO move entity (%d)\n", r); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c index 3e70eb61a9609..a6c2cace4b9dc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c @@ -266,8 +266,8 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev) ring = &adev->uvd.inst[j].ring; rq = &ring->sched.sched_rq[DRM_SCHED_PRIORITY_NORMAL]; - r = drm_sched_entity_init(&ring->sched, &adev->uvd.inst[j].entity, - rq, NULL); + r = drm_sched_entity_init(&adev->uvd.inst[j].entity, &rq, + 1, NULL); if (r != 0) { DRM_ERROR("Failed setting up UVD(%d) run queue.\n", j); return r; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c index 6ae1ad7e83b3c..ffb0fcc9707ec 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c @@ -190,8 +190,7 @@ int amdgpu_vce_sw_init(struct amdgpu_device *adev, unsigned long size) ring = &adev->vce.ring[0]; rq = &ring->sched.sched_rq[DRM_SCHED_PRIORITY_NORMAL]; - r = drm_sched_entity_init(&ring->sched, &adev->vce.entity, - rq, NULL); + r = drm_sched_entity_init(&adev->vce.entity, &rq, 1, NULL); if (r != 0) { DRM_ERROR("Failed setting up VCE run queue.\n"); return r; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 0fd0a718763b6..484e2c19c0278 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -2564,8 +2564,7 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm, ring_instance %= adev->vm_manager.vm_pte_num_rings; ring = adev->vm_manager.vm_pte_rings[ring_instance]; rq = &ring->sched.sched_rq[DRM_SCHED_PRIORITY_KERNEL]; - r = drm_sched_entity_init(&ring->sched, &vm->entity, - rq, NULL); + r = drm_sched_entity_init(&vm->entity, &rq, 1, NULL); if (r) return r; diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c index 2623f249cb7a8..1c118c02e8cb0 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c @@ -430,8 +430,8 @@ static int uvd_v6_0_sw_init(void *handle) struct drm_sched_rq *rq; ring = &adev->uvd.inst->ring_enc[0]; rq = &ring->sched.sched_rq[DRM_SCHED_PRIORITY_NORMAL]; - r = drm_sched_entity_init(&ring->sched, &adev->uvd.inst->entity_enc, - rq, NULL); + r = drm_sched_entity_init(&adev->uvd.inst->entity_enc, + &rq, 1, NULL); if (r) { DRM_ERROR("Failed setting up UVD ENC run queue.\n"); return r; diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c index ce360ad16856f..d48bc33935452 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c @@ -432,8 +432,8 @@ static int uvd_v7_0_sw_init(void *handle) for (j = 0; j < adev->uvd.num_uvd_inst; j++) { ring = &adev->uvd.inst[j].ring_enc[0]; rq = &ring->sched.sched_rq[DRM_SCHED_PRIORITY_NORMAL]; - r = drm_sched_entity_init(&ring->sched, &adev->uvd.inst[j].entity_enc, - rq, NULL); + r = drm_sched_entity_init(&adev->uvd.inst[j].entity_enc, + &rq, 1, NULL); if (r) { DRM_ERROR("(%d)Failed setting up UVD ENC run queue.\n", j); return r; diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c index 45bfdf4cc1078..36414ba56b226 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c @@ -49,12 +49,12 @@ static int etnaviv_open(struct drm_device *dev, struct drm_file *file) for (i = 0; i < ETNA_MAX_PIPES; i++) { struct etnaviv_gpu *gpu = priv->gpu[i]; + struct drm_sched_rq *rq; if (gpu) { - drm_sched_entity_init(&gpu->sched, - &ctx->sched_entity[i], - &gpu->sched.sched_rq[DRM_SCHED_PRIORITY_NORMAL], - NULL); + rq = &gpu->sched.sched_rq[DRM_SCHED_PRIORITY_NORMAL]; + drm_sched_entity_init(&ctx->sched_entity[i], + &rq, 1, NULL); } } diff --git a/drivers/gpu/drm/scheduler/gpu_scheduler.c b/drivers/gpu/drm/scheduler/gpu_scheduler.c index 429b1328653a0..16bf446aa6b38 100644 --- a/drivers/gpu/drm/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/scheduler/gpu_scheduler.c @@ -162,26 +162,30 @@ drm_sched_rq_select_entity(struct drm_sched_rq *rq) * drm_sched_entity_init - Init a context entity used by scheduler when * submit to HW ring. * - * @sched: scheduler instance * @entity: scheduler entity to init - * @rq: the run queue this entity belongs + * @rq_list: the list of run queue on which jobs from this + * entity can be submitted + * @num_rq_list: number of run queue in rq_list * @guilty: atomic_t set to 1 when a job on this queue * is found to be guilty causing a timeout * + * Note: the rq_list should have atleast one element to schedule + * the entity + * * Returns 0 on success or a negative error code on failure. */ -int drm_sched_entity_init(struct drm_gpu_scheduler *sched, - struct drm_sched_entity *entity, - struct drm_sched_rq *rq, +int drm_sched_entity_init(struct drm_sched_entity *entity, + struct drm_sched_rq **rq_list, + unsigned int num_rq_list, atomic_t *guilty) { - if (!(sched && entity && rq)) + if (!(entity && rq_list && num_rq_list > 0 && rq_list[0])) return -EINVAL; memset(entity, 0, sizeof(struct drm_sched_entity)); INIT_LIST_HEAD(&entity->list); - entity->rq = rq; - entity->sched = sched; + entity->rq = rq_list[0]; + entity->sched = rq_list[0]->sched; entity->guilty = guilty; entity->last_scheduled = NULL; diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c index 567f7d46d912d..1dceba2b42fd6 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.c +++ b/drivers/gpu/drm/v3d/v3d_drv.c @@ -123,6 +123,7 @@ v3d_open(struct drm_device *dev, struct drm_file *file) { struct v3d_dev *v3d = to_v3d_dev(dev); struct v3d_file_priv *v3d_priv; + struct drm_sched_rq *rq; int i; v3d_priv = kzalloc(sizeof(*v3d_priv), GFP_KERNEL); @@ -132,10 +133,8 @@ v3d_open(struct drm_device *dev, struct drm_file *file) v3d_priv->v3d = v3d; for (i = 0; i < V3D_MAX_QUEUES; i++) { - drm_sched_entity_init(&v3d->queue[i].sched, - &v3d_priv->sched_entity[i], - &v3d->queue[i].sched.sched_rq[DRM_SCHED_PRIORITY_NORMAL], - NULL); + rq = &v3d->queue[i].sched.sched_rq[DRM_SCHED_PRIORITY_NORMAL]; + drm_sched_entity_init(&v3d_priv->sched_entity[i], &rq, 1, NULL); } file->driver_priv = v3d_priv; diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h index 43e93d6077cf3..2205e89722f6b 100644 --- a/include/drm/gpu_scheduler.h +++ b/include/drm/gpu_scheduler.h @@ -282,9 +282,9 @@ int drm_sched_init(struct drm_gpu_scheduler *sched, const char *name); void drm_sched_fini(struct drm_gpu_scheduler *sched); -int drm_sched_entity_init(struct drm_gpu_scheduler *sched, - struct drm_sched_entity *entity, - struct drm_sched_rq *rq, +int drm_sched_entity_init(struct drm_sched_entity *entity, + struct drm_sched_rq **rq_list, + unsigned int num_rq_list, atomic_t *guilty); long drm_sched_entity_flush(struct drm_gpu_scheduler *sched, struct drm_sched_entity *entity, long timeout); -- GitLab From ddc21af4d0f37f42b33c54cb69b215997fe5b082 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= <michel.daenzer@amd.com> Date: Wed, 11 Jul 2018 12:06:31 +0200 Subject: [PATCH 1099/1506] drm/amdgpu: Keep track of amount of pinned CPU visible VRAM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of CPU invisible VRAM. Preparation for the following, no functional change intended. v2: * Also change amdgpu_vram_mgr_bo_invisible_size to amdgpu_vram_mgr_bo_visible_size, allowing further simplification (Christian König) Cc: stable@vger.kernel.org Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Michel Dänzer <michel.daenzer@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 5 ++--- drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 4 ++-- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c | 20 ++++++++------------ 5 files changed, 14 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index b38c170fb95c6..51b16de008bbc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1590,7 +1590,7 @@ struct amdgpu_device { /* tracking pinned memory */ u64 vram_pin_size; - u64 invisible_pin_size; + u64 visible_pin_size; u64 gart_pin_size; /* amdkfd interface */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index 2060f208e60b7..c00bd9591dada 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -504,7 +504,7 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file vram_gtt.vram_size = adev->gmc.real_vram_size; vram_gtt.vram_size -= adev->vram_pin_size; vram_gtt.vram_cpu_accessible_size = adev->gmc.visible_vram_size; - vram_gtt.vram_cpu_accessible_size -= (adev->vram_pin_size - adev->invisible_pin_size); + vram_gtt.vram_cpu_accessible_size -= adev->visible_pin_size; vram_gtt.gtt_size = adev->mman.bdev.man[TTM_PL_TT].size; vram_gtt.gtt_size *= PAGE_SIZE; vram_gtt.gtt_size -= adev->gart_pin_size; @@ -525,8 +525,7 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file mem.cpu_accessible_vram.total_heap_size = adev->gmc.visible_vram_size; mem.cpu_accessible_vram.usable_heap_size = - adev->gmc.visible_vram_size - - (adev->vram_pin_size - adev->invisible_pin_size); + adev->gmc.visible_vram_size - adev->visible_pin_size; mem.cpu_accessible_vram.heap_usage = amdgpu_vram_mgr_vis_usage(&adev->mman.bdev.man[TTM_PL_VRAM]); mem.cpu_accessible_vram.max_allocation = diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 9ee678d638906..f0239feceab4b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -917,7 +917,7 @@ int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain, domain = amdgpu_mem_type_to_domain(bo->tbo.mem.mem_type); if (domain == AMDGPU_GEM_DOMAIN_VRAM) { adev->vram_pin_size += amdgpu_bo_size(bo); - adev->invisible_pin_size += amdgpu_vram_mgr_bo_invisible_size(bo); + adev->visible_pin_size += amdgpu_vram_mgr_bo_visible_size(bo); } else if (domain == AMDGPU_GEM_DOMAIN_GTT) { adev->gart_pin_size += amdgpu_bo_size(bo); } @@ -969,7 +969,7 @@ int amdgpu_bo_unpin(struct amdgpu_bo *bo) if (bo->tbo.mem.mem_type == TTM_PL_VRAM) { adev->vram_pin_size -= amdgpu_bo_size(bo); - adev->invisible_pin_size -= amdgpu_vram_mgr_bo_invisible_size(bo); + adev->visible_pin_size -= amdgpu_vram_mgr_bo_visible_size(bo); } else if (bo->tbo.mem.mem_type == TTM_PL_TT) { adev->gart_pin_size -= amdgpu_bo_size(bo); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h index e5da4654b630d..8b3cc6687769e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h @@ -73,7 +73,7 @@ bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_mem_reg *mem); uint64_t amdgpu_gtt_mgr_usage(struct ttm_mem_type_manager *man); int amdgpu_gtt_mgr_recover(struct ttm_mem_type_manager *man); -u64 amdgpu_vram_mgr_bo_invisible_size(struct amdgpu_bo *bo); +u64 amdgpu_vram_mgr_bo_visible_size(struct amdgpu_bo *bo); uint64_t amdgpu_vram_mgr_usage(struct ttm_mem_type_manager *man); uint64_t amdgpu_vram_mgr_vis_usage(struct ttm_mem_type_manager *man); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c index f7a4bd5885a39..9cfa8a9ada921 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c @@ -97,33 +97,29 @@ static u64 amdgpu_vram_mgr_vis_size(struct amdgpu_device *adev, } /** - * amdgpu_vram_mgr_bo_invisible_size - CPU invisible BO size + * amdgpu_vram_mgr_bo_visible_size - CPU visible BO size * * @bo: &amdgpu_bo buffer object (must be in VRAM) * * Returns: - * How much of the given &amdgpu_bo buffer object lies in CPU invisible VRAM. + * How much of the given &amdgpu_bo buffer object lies in CPU visible VRAM. */ -u64 amdgpu_vram_mgr_bo_invisible_size(struct amdgpu_bo *bo) +u64 amdgpu_vram_mgr_bo_visible_size(struct amdgpu_bo *bo) { struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); struct ttm_mem_reg *mem = &bo->tbo.mem; struct drm_mm_node *nodes = mem->mm_node; unsigned pages = mem->num_pages; - u64 usage = 0; + u64 usage; if (amdgpu_gmc_vram_full_visible(&adev->gmc)) - return 0; + return amdgpu_bo_size(bo); if (mem->start >= adev->gmc.visible_vram_size >> PAGE_SHIFT) - return amdgpu_bo_size(bo); + return 0; - while (nodes && pages) { - usage += nodes->size << PAGE_SHIFT; - usage -= amdgpu_vram_mgr_vis_size(adev, nodes); - pages -= nodes->size; - ++nodes; - } + for (usage = 0; nodes && pages; pages -= nodes->size, nodes++) + usage += amdgpu_vram_mgr_vis_size(adev, nodes); return usage; } -- GitLab From a5ccfe5c20740f2fbf00291490cdf8d2373ec255 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= <michel.daenzer@amd.com> Date: Wed, 11 Jul 2018 12:00:40 +0200 Subject: [PATCH 1100/1506] drm/amdgpu: Make pin_size values atomic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Concurrent execution of the non-atomic arithmetic could result in completely bogus values. v2: * Rebased on v2 of the previous patch Cc: stable@vger.kernel.org Bugzilla: https://bugs.freedesktop.org/106872 Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Michel Dänzer <michel.daenzer@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 6 +++--- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 22 +++++++++++----------- drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 14 ++++++++------ 4 files changed, 23 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 51b16de008bbc..53435da158c22 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1589,9 +1589,9 @@ struct amdgpu_device { DECLARE_HASHTABLE(mn_hash, 7); /* tracking pinned memory */ - u64 vram_pin_size; - u64 visible_pin_size; - u64 gart_pin_size; + atomic64_t vram_pin_size; + atomic64_t visible_pin_size; + atomic64_t gart_pin_size; /* amdkfd interface */ struct kfd_dev *kfd; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 9881a1e55df3e..5a2a5ba29f9a1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -262,7 +262,7 @@ static void amdgpu_cs_get_threshold_for_moves(struct amdgpu_device *adev, return; } - total_vram = adev->gmc.real_vram_size - adev->vram_pin_size; + total_vram = adev->gmc.real_vram_size - atomic64_read(&adev->vram_pin_size); used_vram = amdgpu_vram_mgr_usage(&adev->mman.bdev.man[TTM_PL_VRAM]); free_vram = used_vram >= total_vram ? 0 : total_vram - used_vram; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index c00bd9591dada..207f238649b47 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -501,13 +501,13 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file case AMDGPU_INFO_VRAM_GTT: { struct drm_amdgpu_info_vram_gtt vram_gtt; - vram_gtt.vram_size = adev->gmc.real_vram_size; - vram_gtt.vram_size -= adev->vram_pin_size; - vram_gtt.vram_cpu_accessible_size = adev->gmc.visible_vram_size; - vram_gtt.vram_cpu_accessible_size -= adev->visible_pin_size; + vram_gtt.vram_size = adev->gmc.real_vram_size - + atomic64_read(&adev->vram_pin_size); + vram_gtt.vram_cpu_accessible_size = adev->gmc.visible_vram_size - + atomic64_read(&adev->visible_pin_size); vram_gtt.gtt_size = adev->mman.bdev.man[TTM_PL_TT].size; vram_gtt.gtt_size *= PAGE_SIZE; - vram_gtt.gtt_size -= adev->gart_pin_size; + vram_gtt.gtt_size -= atomic64_read(&adev->gart_pin_size); return copy_to_user(out, &vram_gtt, min((size_t)size, sizeof(vram_gtt))) ? -EFAULT : 0; } @@ -516,16 +516,16 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file memset(&mem, 0, sizeof(mem)); mem.vram.total_heap_size = adev->gmc.real_vram_size; - mem.vram.usable_heap_size = - adev->gmc.real_vram_size - adev->vram_pin_size; + mem.vram.usable_heap_size = adev->gmc.real_vram_size - + atomic64_read(&adev->vram_pin_size); mem.vram.heap_usage = amdgpu_vram_mgr_usage(&adev->mman.bdev.man[TTM_PL_VRAM]); mem.vram.max_allocation = mem.vram.usable_heap_size * 3 / 4; mem.cpu_accessible_vram.total_heap_size = adev->gmc.visible_vram_size; - mem.cpu_accessible_vram.usable_heap_size = - adev->gmc.visible_vram_size - adev->visible_pin_size; + mem.cpu_accessible_vram.usable_heap_size = adev->gmc.visible_vram_size - + atomic64_read(&adev->visible_pin_size); mem.cpu_accessible_vram.heap_usage = amdgpu_vram_mgr_vis_usage(&adev->mman.bdev.man[TTM_PL_VRAM]); mem.cpu_accessible_vram.max_allocation = @@ -533,8 +533,8 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file mem.gtt.total_heap_size = adev->mman.bdev.man[TTM_PL_TT].size; mem.gtt.total_heap_size *= PAGE_SIZE; - mem.gtt.usable_heap_size = mem.gtt.total_heap_size - - adev->gart_pin_size; + mem.gtt.usable_heap_size = mem.gtt.total_heap_size - + atomic64_read(&adev->gart_pin_size); mem.gtt.heap_usage = amdgpu_gtt_mgr_usage(&adev->mman.bdev.man[TTM_PL_TT]); mem.gtt.max_allocation = mem.gtt.usable_heap_size * 3 / 4; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index f0239feceab4b..1fd83ed175fa2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -916,10 +916,11 @@ int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain, domain = amdgpu_mem_type_to_domain(bo->tbo.mem.mem_type); if (domain == AMDGPU_GEM_DOMAIN_VRAM) { - adev->vram_pin_size += amdgpu_bo_size(bo); - adev->visible_pin_size += amdgpu_vram_mgr_bo_visible_size(bo); + atomic64_add(amdgpu_bo_size(bo), &adev->vram_pin_size); + atomic64_add(amdgpu_vram_mgr_bo_visible_size(bo), + &adev->visible_pin_size); } else if (domain == AMDGPU_GEM_DOMAIN_GTT) { - adev->gart_pin_size += amdgpu_bo_size(bo); + atomic64_add(amdgpu_bo_size(bo), &adev->gart_pin_size); } error: @@ -968,10 +969,11 @@ int amdgpu_bo_unpin(struct amdgpu_bo *bo) return 0; if (bo->tbo.mem.mem_type == TTM_PL_VRAM) { - adev->vram_pin_size -= amdgpu_bo_size(bo); - adev->visible_pin_size -= amdgpu_vram_mgr_bo_visible_size(bo); + atomic64_sub(amdgpu_bo_size(bo), &adev->vram_pin_size); + atomic64_sub(amdgpu_vram_mgr_bo_visible_size(bo), + &adev->visible_pin_size); } else if (bo->tbo.mem.mem_type == TTM_PL_TT) { - adev->gart_pin_size -= amdgpu_bo_size(bo); + atomic64_sub(amdgpu_bo_size(bo), &adev->gart_pin_size); } for (i = 0; i < bo->placement.num_placement; i++) { -- GitLab From 15e6b76880e65be24250e30986084b5569b7a06f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= <michel.daenzer@amd.com> Date: Wed, 11 Jul 2018 12:42:55 +0200 Subject: [PATCH 1101/1506] drm/amdgpu: Warn and update pin_size values when destroying a pinned BO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This shouldn't happen, but if it does, we'll get a backtrace of the caller, and update the pin_size values as needed. v2: * Check bo->pin_count instead of placement flags (Christian König) Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Michel Dänzer <michel.daenzer@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 32 +++++++++++++++++----- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 1fd83ed175fa2..b12526ce1a9d3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -63,11 +63,35 @@ static bool amdgpu_need_backup(struct amdgpu_device *adev) return true; } +/** + * amdgpu_bo_subtract_pin_size - Remove BO from pin_size accounting + * + * @bo: &amdgpu_bo buffer object + * + * This function is called when a BO stops being pinned, and updates the + * &amdgpu_device pin_size values accordingly. + */ +static void amdgpu_bo_subtract_pin_size(struct amdgpu_bo *bo) +{ + struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); + + if (bo->tbo.mem.mem_type == TTM_PL_VRAM) { + atomic64_sub(amdgpu_bo_size(bo), &adev->vram_pin_size); + atomic64_sub(amdgpu_vram_mgr_bo_visible_size(bo), + &adev->visible_pin_size); + } else if (bo->tbo.mem.mem_type == TTM_PL_TT) { + atomic64_sub(amdgpu_bo_size(bo), &adev->gart_pin_size); + } +} + static void amdgpu_ttm_bo_destroy(struct ttm_buffer_object *tbo) { struct amdgpu_device *adev = amdgpu_ttm_adev(tbo->bdev); struct amdgpu_bo *bo = ttm_to_amdgpu_bo(tbo); + if (WARN_ON_ONCE(bo->pin_count > 0)) + amdgpu_bo_subtract_pin_size(bo); + if (bo->kfd_bo) amdgpu_amdkfd_unreserve_system_memory_limit(bo); @@ -968,13 +992,7 @@ int amdgpu_bo_unpin(struct amdgpu_bo *bo) if (bo->pin_count) return 0; - if (bo->tbo.mem.mem_type == TTM_PL_VRAM) { - atomic64_sub(amdgpu_bo_size(bo), &adev->vram_pin_size); - atomic64_sub(amdgpu_vram_mgr_bo_visible_size(bo), - &adev->visible_pin_size); - } else if (bo->tbo.mem.mem_type == TTM_PL_TT) { - atomic64_sub(amdgpu_bo_size(bo), &adev->gart_pin_size); - } + amdgpu_bo_subtract_pin_size(bo); for (i = 0; i < bo->placement.num_placement; i++) { bo->placements[i].lpfn = 0; -- GitLab From 37b5fcfde879652bac7fc4b18c5f242f2544e9ea Mon Sep 17 00:00:00 2001 From: Harry Wentland <harry.wentland@amd.com> Date: Fri, 6 Jul 2018 10:54:18 -0400 Subject: [PATCH 1102/1506] Revert "drm/amd/display: Don't return ddc result and read_bytes in same return value" This reverts commit 8a61bc085ffab3071c59efcbeff4044c034e7490. Need to revert "make dm_dp_aux_transfer return payload bytes instead of size", which this commit is based on. That commit was problematic on other OSes. The real solution is to leave all the error checking to DRM and don't do it in DC, which is addressed by "Return aux replies directly to DRM" later in this patchset. v2: Add reason for revert. Signed-off-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../display/amdgpu_dm/amdgpu_dm_mst_types.c | 20 ++++++++----------- .../gpu/drm/amd/display/dc/core/dc_link_ddc.c | 10 +++------- .../gpu/drm/amd/display/dc/inc/dc_link_ddc.h | 5 ++--- 3 files changed, 13 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index 4304d9e408b88..ace9ad578ca08 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -83,22 +83,21 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, enum i2c_mot_mode mot = (msg->request & DP_AUX_I2C_MOT) ? I2C_MOT_TRUE : I2C_MOT_FALSE; enum ddc_result res; - uint32_t read_bytes = msg->size; + ssize_t read_bytes; if (WARN_ON(msg->size > 16)) return -E2BIG; switch (msg->request & ~DP_AUX_I2C_MOT) { case DP_AUX_NATIVE_READ: - res = dal_ddc_service_read_dpcd_data( + read_bytes = dal_ddc_service_read_dpcd_data( TO_DM_AUX(aux)->ddc_service, false, I2C_MOT_UNDEF, msg->address, msg->buffer, - msg->size, - &read_bytes); - break; + msg->size); + return read_bytes; case DP_AUX_NATIVE_WRITE: res = dal_ddc_service_write_dpcd_data( TO_DM_AUX(aux)->ddc_service, @@ -109,15 +108,14 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, msg->size); break; case DP_AUX_I2C_READ: - res = dal_ddc_service_read_dpcd_data( + read_bytes = dal_ddc_service_read_dpcd_data( TO_DM_AUX(aux)->ddc_service, true, mot, msg->address, msg->buffer, - msg->size, - &read_bytes); - break; + msg->size); + return read_bytes; case DP_AUX_I2C_WRITE: res = dal_ddc_service_write_dpcd_data( TO_DM_AUX(aux)->ddc_service, @@ -139,9 +137,7 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, r == DDC_RESULT_SUCESSFULL); #endif - if (res != DDC_RESULT_SUCESSFULL) - return -EIO; - return read_bytes; + return msg->size; } static enum drm_connector_status diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c index ae48d603ebd6c..49c2face1e7a8 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c @@ -629,14 +629,13 @@ bool dal_ddc_service_query_ddc_data( return ret; } -enum ddc_result dal_ddc_service_read_dpcd_data( +ssize_t dal_ddc_service_read_dpcd_data( struct ddc_service *ddc, bool i2c, enum i2c_mot_mode mot, uint32_t address, uint8_t *data, - uint32_t len, - uint32_t *read) + uint32_t len) { struct aux_payload read_payload = { .i2c_over_aux = i2c, @@ -653,8 +652,6 @@ enum ddc_result dal_ddc_service_read_dpcd_data( .mot = mot }; - *read = 0; - if (len > DEFAULT_AUX_MAX_DATA_SIZE) { BREAK_TO_DEBUGGER(); return DDC_RESULT_FAILED_INVALID_OPERATION; @@ -664,8 +661,7 @@ enum ddc_result dal_ddc_service_read_dpcd_data( ddc->ctx->i2caux, ddc->ddc_pin, &command)) { - *read = command.payloads->length; - return DDC_RESULT_SUCESSFULL; + return (ssize_t)command.payloads->length; } return DDC_RESULT_FAILED_OPERATION; diff --git a/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h b/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h index 30b3a08b91be2..090b7a8dd67bd 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h +++ b/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h @@ -102,14 +102,13 @@ bool dal_ddc_service_query_ddc_data( uint8_t *read_buf, uint32_t read_size); -enum ddc_result dal_ddc_service_read_dpcd_data( +ssize_t dal_ddc_service_read_dpcd_data( struct ddc_service *ddc, bool i2c, enum i2c_mot_mode mot, uint32_t address, uint8_t *data, - uint32_t len, - uint32_t *read); + uint32_t len); enum ddc_result dal_ddc_service_write_dpcd_data( struct ddc_service *ddc, -- GitLab From 013fc06ea4260574755541773ece1a76a8017de6 Mon Sep 17 00:00:00 2001 From: Harry Wentland <harry.wentland@amd.com> Date: Fri, 6 Jul 2018 10:54:33 -0400 Subject: [PATCH 1103/1506] Revert "drm/amd/display: make dm_dp_aux_transfer return payload bytes instead of size" This reverts commit cc195141133ac3e767d930bedd8294ceebf1f10b. This commit was problematic on other OSes. The real solution is to leave all the error checking to DRM and don't do it in DC, which is addressed by "Return aux replies directly to DRM" later in this patchset. v2: Add reason for revert. Signed-off-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../amd/display/amdgpu_dm/amdgpu_dm_mst_types.c | 9 ++++----- drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c | 7 +++---- .../gpu/drm/amd/display/dc/i2caux/aux_engine.c | 15 +++++++++++++-- drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c | 1 - drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h | 2 +- 5 files changed, 21 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index ace9ad578ca08..c74105758815d 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -83,21 +83,20 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, enum i2c_mot_mode mot = (msg->request & DP_AUX_I2C_MOT) ? I2C_MOT_TRUE : I2C_MOT_FALSE; enum ddc_result res; - ssize_t read_bytes; if (WARN_ON(msg->size > 16)) return -E2BIG; switch (msg->request & ~DP_AUX_I2C_MOT) { case DP_AUX_NATIVE_READ: - read_bytes = dal_ddc_service_read_dpcd_data( + res = dal_ddc_service_read_dpcd_data( TO_DM_AUX(aux)->ddc_service, false, I2C_MOT_UNDEF, msg->address, msg->buffer, msg->size); - return read_bytes; + break; case DP_AUX_NATIVE_WRITE: res = dal_ddc_service_write_dpcd_data( TO_DM_AUX(aux)->ddc_service, @@ -108,14 +107,14 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, msg->size); break; case DP_AUX_I2C_READ: - read_bytes = dal_ddc_service_read_dpcd_data( + res = dal_ddc_service_read_dpcd_data( TO_DM_AUX(aux)->ddc_service, true, mot, msg->address, msg->buffer, msg->size); - return read_bytes; + break; case DP_AUX_I2C_WRITE: res = dal_ddc_service_write_dpcd_data( TO_DM_AUX(aux)->ddc_service, diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c index 49c2face1e7a8..d5294798b0a54 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c @@ -629,7 +629,7 @@ bool dal_ddc_service_query_ddc_data( return ret; } -ssize_t dal_ddc_service_read_dpcd_data( +enum ddc_result dal_ddc_service_read_dpcd_data( struct ddc_service *ddc, bool i2c, enum i2c_mot_mode mot, @@ -660,9 +660,8 @@ ssize_t dal_ddc_service_read_dpcd_data( if (dal_i2caux_submit_aux_command( ddc->ctx->i2caux, ddc->ddc_pin, - &command)) { - return (ssize_t)command.payloads->length; - } + &command)) + return DDC_RESULT_SUCESSFULL; return DDC_RESULT_FAILED_OPERATION; } diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.c b/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.c index 1d7309611978e..0afd2fa57bbe5 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.c +++ b/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.c @@ -128,8 +128,20 @@ static void process_read_reply( ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR; ctx->operation_succeeded = false; + } else if (ctx->returned_byte < ctx->current_read_length) { + ctx->current_read_length -= ctx->returned_byte; + + ctx->offset += ctx->returned_byte; + + ++ctx->invalid_reply_retry_aux_on_ack; + + if (ctx->invalid_reply_retry_aux_on_ack > + AUX_INVALID_REPLY_RETRY_COUNTER) { + ctx->status = + I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR; + ctx->operation_succeeded = false; + } } else { - ctx->current_read_length = ctx->returned_byte; ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED; ctx->transaction_complete = true; ctx->operation_succeeded = true; @@ -290,7 +302,6 @@ static bool read_command( ctx.operation_succeeded); } - request->payload.length = ctx.reply.length; return ctx.operation_succeeded; } diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c b/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c index 14dc8c94d862b..9b0bcc6b769b5 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c +++ b/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c @@ -254,7 +254,6 @@ bool dal_i2caux_submit_aux_command( break; } - cmd->payloads->length = request.payload.length; ++index_of_payload; } diff --git a/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h b/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h index 090b7a8dd67bd..0bf73b742f1f7 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h +++ b/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h @@ -102,7 +102,7 @@ bool dal_ddc_service_query_ddc_data( uint8_t *read_buf, uint32_t read_size); -ssize_t dal_ddc_service_read_dpcd_data( +enum ddc_result dal_ddc_service_read_dpcd_data( struct ddc_service *ddc, bool i2c, enum i2c_mot_mode mot, -- GitLab From a9962fb8e53aad86bc5c4147ecc209a214345f56 Mon Sep 17 00:00:00 2001 From: Eric Bernstein <eric.bernstein@amd.com> Date: Fri, 8 Jun 2018 15:01:59 -0400 Subject: [PATCH 1104/1506] drm/amd/display: Separate HUBP surface size and rotation/mirror programming Separate HUBP surface size and rotation/mirror programming so that HUBP revision without mirror/rotation do not access those register fields. Signed-off-by: Eric Bernstein <eric.bernstein@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c | 23 ++++++++++++------- .../gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h | 13 +++++++---- 2 files changed, 23 insertions(+), 13 deletions(-) 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 a281bed9b413a..ec8e833a07bd9 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c @@ -152,16 +152,14 @@ void hubp1_program_tiling( PIPE_ALIGNED, info->gfx9.pipe_aligned); } -void hubp1_program_size_and_rotation( +void hubp1_program_size( struct hubp *hubp, - enum dc_rotation_angle rotation, enum surface_pixel_format format, const union plane_size *plane_size, - struct dc_plane_dcc_param *dcc, - bool horizontal_mirror) + struct dc_plane_dcc_param *dcc) { struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); - uint32_t pitch, meta_pitch, pitch_c, meta_pitch_c, mirror; + uint32_t pitch, meta_pitch, pitch_c, meta_pitch_c; /* Program data and meta surface pitch (calculation from addrlib) * 444 or 420 luma @@ -192,13 +190,22 @@ void hubp1_program_size_and_rotation( if (format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) REG_UPDATE_2(DCSURF_SURFACE_PITCH_C, PITCH_C, pitch_c, META_PITCH_C, meta_pitch_c); +} + +void hubp1_program_rotation( + struct hubp *hubp, + enum dc_rotation_angle rotation, + bool horizontal_mirror) +{ + struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); + uint32_t mirror; + if (horizontal_mirror) mirror = 1; else mirror = 0; - /* Program rotation angle and horz mirror - no mirror */ if (rotation == ROTATION_ANGLE_0) REG_UPDATE_2(DCSURF_SURFACE_CONFIG, @@ -481,8 +488,8 @@ void hubp1_program_surface_config( { hubp1_dcc_control(hubp, dcc->enable, dcc->grph.independent_64b_blks); hubp1_program_tiling(hubp, tiling_info, format); - hubp1_program_size_and_rotation( - hubp, rotation, format, plane_size, dcc, horizontal_mirror); + hubp1_program_size(hubp, format, plane_size, dcc); + hubp1_program_rotation(hubp, rotation, horizontal_mirror); hubp1_program_pixel_format(hubp, format); } 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 d901d5092969d..f689feace82d1 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h @@ -268,8 +268,6 @@ HUBP_SF(HUBPREQ0_DCSURF_SURFACE_PITCH, META_PITCH, mask_sh),\ HUBP_SF(HUBPREQ0_DCSURF_SURFACE_PITCH_C, PITCH_C, mask_sh),\ HUBP_SF(HUBPREQ0_DCSURF_SURFACE_PITCH_C, META_PITCH_C, mask_sh),\ - HUBP_SF(HUBP0_DCSURF_SURFACE_CONFIG, ROTATION_ANGLE, mask_sh),\ - HUBP_SF(HUBP0_DCSURF_SURFACE_CONFIG, H_MIRROR_EN, mask_sh),\ HUBP_SF(HUBP0_DCSURF_SURFACE_CONFIG, SURFACE_PIXEL_FORMAT, mask_sh),\ HUBP_SF(HUBPREQ0_DCSURF_FLIP_CONTROL, SURFACE_FLIP_TYPE, mask_sh),\ HUBP_SF(HUBPREQ0_DCSURF_FLIP_CONTROL, SURFACE_FLIP_PENDING, mask_sh),\ @@ -388,6 +386,8 @@ #define HUBP_MASK_SH_LIST_DCN10(mask_sh)\ HUBP_MASK_SH_LIST_DCN(mask_sh),\ HUBP_MASK_SH_LIST_DCN_VM(mask_sh),\ + HUBP_SF(HUBP0_DCSURF_SURFACE_CONFIG, ROTATION_ANGLE, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_SURFACE_CONFIG, H_MIRROR_EN, mask_sh),\ HUBP_SF(HUBPREQ0_PREFETCH_SETTINS, DST_Y_PREFETCH, mask_sh),\ HUBP_SF(HUBPREQ0_PREFETCH_SETTINS, VRATIO_PREFETCH, mask_sh),\ HUBP_SF(HUBPREQ0_PREFETCH_SETTINS_C, VRATIO_PREFETCH_C, mask_sh),\ @@ -679,12 +679,15 @@ void hubp1_program_pixel_format( struct hubp *hubp, enum surface_pixel_format format); -void hubp1_program_size_and_rotation( +void hubp1_program_size( struct hubp *hubp, - enum dc_rotation_angle rotation, enum surface_pixel_format format, const union plane_size *plane_size, - struct dc_plane_dcc_param *dcc, + struct dc_plane_dcc_param *dcc); + +void hubp1_program_rotation( + struct hubp *hubp, + enum dc_rotation_angle rotation, bool horizontal_mirror); void hubp1_program_tiling( -- GitLab From 91f191c74e8da29360109acb97a20240bedbc355 Mon Sep 17 00:00:00 2001 From: Tony Cheng <tony.cheng@amd.com> Date: Thu, 14 Jun 2018 16:06:10 -0400 Subject: [PATCH 1105/1506] drm/amd/display: Add avoid_vbios_exec_table debug bit Signed-off-by: Tony Cheng <tony.cheng@amd.com> Reviewed-by: Yongqiang Sun <yongqiang.sun@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dc.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 0cb7e10d2505b..59985baac11e4 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -249,6 +249,7 @@ struct dc_debug { bool always_use_regamma; bool p010_mpo_support; bool recovery_enabled; + bool avoid_vbios_exec_table; }; struct dc_state; -- GitLab From 0a14544661fad1606cc96aece30b2950fd9c4c81 Mon Sep 17 00:00:00 2001 From: Eric Yang <Eric.Yang2@amd.com> Date: Tue, 12 Jun 2018 18:37:12 -0400 Subject: [PATCH 1106/1506] drm/amd/display: support access ddc for mst branch [Why] Megachip dockings accesses ddc line through display driver when installing FW. Previously, we would fail every transaction because link attached to mst branch did not have their ddc transaction type set. [How] Set ddc transaction type when mst branch is connected. Signed-off-by: Eric Yang <Eric.Yang2@amd.com> Reviewed-by: Charlene Liu <Charlene.Liu@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 4 ++++ 1 file changed, 4 insertions(+) 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 fa56c0fc02bf5..a4180ba63d824 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -498,6 +498,10 @@ static bool detect_dp( sink_caps->signal = SIGNAL_TYPE_DISPLAY_PORT_MST; link->type = dc_connection_mst_branch; + dal_ddc_service_set_transaction_type( + link->ddc, + sink_caps->transaction_type); + /* * This call will initiate MST topology discovery. Which * will detect MST ports and add new DRM connector DRM -- GitLab From 1811a51f6a04adbaa4dba1e7bfe13201c04b9f94 Mon Sep 17 00:00:00 2001 From: Krunoslav Kovac <Krunoslav.Kovac@amd.com> Date: Thu, 14 Jun 2018 15:08:58 -0400 Subject: [PATCH 1107/1506] drm/amd/display: Implement cursor multiplier DCN allows cursor multiplier when blending FP16 surface. Signed-off-by: Krunoslav Kovac <Krunoslav.Kovac@amd.com> Reviewed-by: Aric Cyr <Aric.Cyr@amd.com> Reviewed-by: Anthony Koo <Anthony.Koo@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dc_hw_types.h | 1 + drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c | 15 +++++++++++++++ drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h | 12 ++++++++---- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h index 14afbc5c0a621..00afd07a852ed 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h @@ -490,6 +490,7 @@ struct dc_cursor_attributes { uint32_t height; enum dc_cursor_color_format color_format; + uint32_t sdr_white_level; // for boosting (SDR) cursor in HDR mode /* In case we support HW Cursor rotation in the future */ enum dc_rotation_angle rotation_angle; 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 ec8e833a07bd9..9eb60a013f4c1 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c @@ -27,6 +27,7 @@ #include "reg_helper.h" #include "basics/conversion.h" #include "dcn10_hubp.h" +#include "custom_float.h" #define REG(reg)\ hubp1->hubp_regs->reg @@ -1038,6 +1039,18 @@ void hubp1_cursor_set_attributes( enum cursor_pitch hw_pitch = hubp1_get_cursor_pitch(attr->pitch); enum cursor_lines_per_chunk lpc = hubp1_get_lines_per_chunk( attr->width, attr->color_format); + struct fixed31_32 multiplier; + uint32_t hw_mult = 0x3c00; // 1.0 default multiplier + struct custom_float_format fmt; + + fmt.exponenta_bits = 5; + fmt.mantissa_bits = 10; + fmt.sign = true; + + if (attr->sdr_white_level > 80) { + multiplier = dc_fixpt_from_fraction(attr->sdr_white_level, 80); + convert_to_custom_float_format(multiplier, &fmt, &hw_mult); + } hubp->curs_attr = *attr; @@ -1060,6 +1073,8 @@ void hubp1_cursor_set_attributes( CURSOR0_DST_Y_OFFSET, 0, /* used to shift the cursor chunk request deadline */ CURSOR0_CHUNK_HDL_ADJUST, 3); + + REG_UPDATE(CURSOR0_FP_SCALE_BIAS, CUR0_FP_SCALE, hw_mult); } void hubp1_cursor_set_position( 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 f689feace82d1..9991da50bf29b 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h @@ -133,7 +133,8 @@ SRI(CURSOR_CONTROL, CURSOR, id), \ SRI(CURSOR_POSITION, CURSOR, id), \ SRI(CURSOR_HOT_SPOT, CURSOR, id), \ - SRI(CURSOR_DST_OFFSET, CURSOR, id) + SRI(CURSOR_DST_OFFSET, CURSOR, id), \ + SRI(CURSOR0_FP_SCALE_BIAS, CNVC_CUR, id) #define HUBP_COMMON_REG_VARIABLE_LIST \ uint32_t DCHUBP_CNTL; \ @@ -241,7 +242,8 @@ uint32_t CURSOR_POSITION; \ uint32_t CURSOR_HOT_SPOT; \ uint32_t CURSOR_DST_OFFSET; \ - uint32_t HUBP_CLK_CNTL + uint32_t HUBP_CLK_CNTL; \ + uint32_t CURSOR0_FP_SCALE_BIAS #define HUBP_SF(reg_name, field_name, post_fix)\ .field_name = reg_name ## __ ## field_name ## post_fix @@ -424,7 +426,8 @@ HUBP_SF(CURSOR0_CURSOR_POSITION, CURSOR_Y_POSITION, mask_sh), \ HUBP_SF(CURSOR0_CURSOR_HOT_SPOT, CURSOR_HOT_SPOT_X, mask_sh), \ HUBP_SF(CURSOR0_CURSOR_HOT_SPOT, CURSOR_HOT_SPOT_Y, mask_sh), \ - HUBP_SF(CURSOR0_CURSOR_DST_OFFSET, CURSOR_DST_X_OFFSET, mask_sh) + HUBP_SF(CURSOR0_CURSOR_DST_OFFSET, CURSOR_DST_X_OFFSET, mask_sh), \ + HUBP_SF(CNVC_CUR0_CURSOR0_FP_SCALE_BIAS, CUR0_FP_SCALE, mask_sh) #define DCN_HUBP_REG_FIELD_LIST(type) \ type HUBP_BLANK_EN;\ @@ -615,7 +618,8 @@ type CURSOR_HOT_SPOT_X; \ type CURSOR_HOT_SPOT_Y; \ type CURSOR_DST_X_OFFSET; \ - type OUTPUT_FP + type OUTPUT_FP; \ + type CUR0_FP_SCALE struct dcn_mi_registers { HUBP_COMMON_REG_VARIABLE_LIST; -- GitLab From 40dd6bd376a4b8617d7cfb1402bafd84bbd79bbd Mon Sep 17 00:00:00 2001 From: Hersen Wu <hersenxs.wu@amd.com> Date: Fri, 15 Jun 2018 09:28:34 -0400 Subject: [PATCH 1108/1506] drm/amd/display: Linux Set/Read link rate and lane count through debugfs expose dc function to be called by linux dm Signed-off-by: Hersen Wu <hersenxs.wu@amd.com> Reviewed-by: Sun peng Li <Sunpeng.Li@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/core/dc.c | 65 ++++++++++++++++++++++++ drivers/gpu/drm/amd/display/dc/dc_link.h | 17 +++++++ 2 files changed, 82 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 2a785bbf2b8f1..815656a5b6bdd 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -384,6 +384,71 @@ void dc_stream_set_static_screen_events(struct dc *dc, dc->hwss.set_static_screen_control(pipes_affected, num_pipes_affected, events); } +void dc_link_set_drive_settings(struct dc *dc, + struct link_training_settings *lt_settings, + const struct dc_link *link) +{ + + int i; + + for (i = 0; i < dc->link_count; i++) { + if (dc->links[i] == link) + break; + } + + if (i >= dc->link_count) + ASSERT_CRITICAL(false); + + dc_link_dp_set_drive_settings(dc->links[i], lt_settings); +} + +void dc_link_perform_link_training(struct dc *dc, + struct dc_link_settings *link_setting, + bool skip_video_pattern) +{ + int i; + + for (i = 0; i < dc->link_count; i++) + dc_link_dp_perform_link_training( + dc->links[i], + link_setting, + skip_video_pattern); +} + +void dc_link_set_preferred_link_settings(struct dc *dc, + struct dc_link_settings *link_setting, + struct dc_link *link) +{ + link->preferred_link_setting = *link_setting; + dp_retrain_link_dp_test(link, link_setting, false); +} + +void dc_link_enable_hpd(const struct dc_link *link) +{ + dc_link_dp_enable_hpd(link); +} + +void dc_link_disable_hpd(const struct dc_link *link) +{ + dc_link_dp_disable_hpd(link); +} + + +void dc_link_set_test_pattern(struct dc_link *link, + enum dp_test_pattern test_pattern, + const struct link_training_settings *p_link_settings, + const unsigned char *p_custom_pattern, + unsigned int cust_pattern_size) +{ + if (link != NULL) + dc_link_dp_set_test_pattern( + link, + test_pattern, + p_link_settings, + p_custom_pattern, + cust_pattern_size); +} + static void destruct(struct dc *dc) { dc_release_state(dc->current_state); diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h index 8a716baa1203b..83eea42452b51 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_link.h +++ b/drivers/gpu/drm/amd/display/dc/dc_link.h @@ -214,6 +214,23 @@ void dc_link_enable_hpd_filter(struct dc_link *link, bool enable); * DPCD access interfaces */ +void dc_link_set_drive_settings(struct dc *dc, + struct link_training_settings *lt_settings, + const struct dc_link *link); +void dc_link_perform_link_training(struct dc *dc, + struct dc_link_settings *link_setting, + bool skip_video_pattern); +void dc_link_set_preferred_link_settings(struct dc *dc, + struct dc_link_settings *link_setting, + struct dc_link *link); +void dc_link_enable_hpd(const struct dc_link *link); +void dc_link_disable_hpd(const struct dc_link *link); +void dc_link_set_test_pattern(struct dc_link *link, + enum dp_test_pattern test_pattern, + const struct link_training_settings *p_link_settings, + const unsigned char *p_custom_pattern, + unsigned int cust_pattern_size); + bool dc_submit_i2c( struct dc *dc, uint32_t link_index, -- GitLab From b81e5aa39f66fa159beb449c47220cfb483f0d5f Mon Sep 17 00:00:00 2001 From: Charlene Liu <charlene.liu@amd.com> Date: Fri, 15 Jun 2018 12:19:00 -0400 Subject: [PATCH 1109/1506] drm/amd/display: Move common GPIO registers into a common define Signed-off-by: Charlene Liu <charlene.liu@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/gpio/ddc_regs.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/gpio/ddc_regs.h b/drivers/gpu/drm/amd/display/dc/gpio/ddc_regs.h index 9c4a56c738c01..bf40725f982ff 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/ddc_regs.h +++ b/drivers/gpu/drm/amd/display/dc/gpio/ddc_regs.h @@ -82,13 +82,16 @@ DDC_GPIO_I2C_REG_LIST(cd),\ .ddc_setup = 0 -#define DDC_MASK_SH_LIST(mask_sh) \ +#define DDC_MASK_SH_LIST_COMMON(mask_sh) \ SF_DDC(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_ENABLE, mask_sh),\ SF_DDC(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_EDID_DETECT_ENABLE, mask_sh),\ SF_DDC(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_EDID_DETECT_MODE, mask_sh),\ SF_DDC(DC_GPIO_DDC1_MASK, DC_GPIO_DDC1DATA_PD_EN, mask_sh),\ SF_DDC(DC_GPIO_DDC1_MASK, DC_GPIO_DDC1CLK_PD_EN, mask_sh),\ - SF_DDC(DC_GPIO_DDC1_MASK, AUX_PAD1_MODE, mask_sh),\ + SF_DDC(DC_GPIO_DDC1_MASK, AUX_PAD1_MODE, mask_sh) + +#define DDC_MASK_SH_LIST(mask_sh) \ + DDC_MASK_SH_LIST_COMMON(mask_sh),\ SF_DDC(DC_GPIO_I2CPAD_MASK, DC_GPIO_SDA_PD_DIS, mask_sh),\ SF_DDC(DC_GPIO_I2CPAD_MASK, DC_GPIO_SCL_PD_DIS, mask_sh) -- GitLab From 4981a66144fa1e05c54164ea2ef4255451b62d78 Mon Sep 17 00:00:00 2001 From: Tony Cheng <tony.cheng@amd.com> Date: Fri, 15 Jun 2018 17:53:35 -0400 Subject: [PATCH 1110/1506] drm/amd/display: fix bug where we are creating bogus i2c aux [WHY] we were using 6 instances based on i2caux_dce110.c [HOW] pass in how many instances to ctor Signed-off-by: Tony Cheng <tony.cheng@amd.com> Reviewed-by: Yongqiang Sun <yongqiang.sun@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/display/dc/i2caux/dce100/i2caux_dce100.c | 1 + .../gpu/drm/amd/display/dc/i2caux/dce110/i2caux_dce110.c | 6 ++++-- .../gpu/drm/amd/display/dc/i2caux/dce110/i2caux_dce110.h | 1 + .../gpu/drm/amd/display/dc/i2caux/dce112/i2caux_dce112.c | 1 + .../gpu/drm/amd/display/dc/i2caux/dce120/i2caux_dce120.c | 1 + drivers/gpu/drm/amd/display/dc/i2caux/dcn10/i2caux_dcn10.c | 1 + 6 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce100/i2caux_dce100.c b/drivers/gpu/drm/amd/display/dc/i2caux/dce100/i2caux_dce100.c index e8d3781deaed0..8b704ab0471cd 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dce100/i2caux_dce100.c +++ b/drivers/gpu/drm/amd/display/dc/i2caux/dce100/i2caux_dce100.c @@ -97,6 +97,7 @@ struct i2caux *dal_i2caux_dce100_create( dal_i2caux_dce110_construct(i2caux_dce110, ctx, + ARRAY_SIZE(dce100_aux_regs), dce100_aux_regs, dce100_hw_engine_regs, &i2c_shift, diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2caux_dce110.c b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2caux_dce110.c index 2a047f8ca0e9a..e0557d3538188 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2caux_dce110.c +++ b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2caux_dce110.c @@ -199,6 +199,7 @@ static const struct dce110_i2c_hw_engine_mask i2c_mask = { void dal_i2caux_dce110_construct( struct i2caux_dce110 *i2caux_dce110, struct dc_context *ctx, + unsigned int num_i2caux_inst, const struct dce110_aux_registers aux_regs[], const struct dce110_i2c_hw_engine_registers i2c_hw_engine_regs[], const struct dce110_i2c_hw_engine_shift *i2c_shift, @@ -251,7 +252,7 @@ void dal_i2caux_dce110_construct( dal_i2c_hw_engine_dce110_create(&hw_arg_dce110); ++i; - } while (i < ARRAY_SIZE(hw_ddc_lines)); + } while (i < num_i2caux_inst); /* Create AUX engines for all lines which has assisted HW AUX * 'i' (loop counter) used as DDC/AUX engine_id */ @@ -272,7 +273,7 @@ void dal_i2caux_dce110_construct( dal_aux_engine_dce110_create(&aux_init_data); ++i; - } while (i < ARRAY_SIZE(hw_aux_lines)); + } while (i < num_i2caux_inst); /*TODO Generic I2C SW and HW*/ } @@ -303,6 +304,7 @@ struct i2caux *dal_i2caux_dce110_create( dal_i2caux_dce110_construct(i2caux_dce110, ctx, + ARRAY_SIZE(dce110_aux_regs), dce110_aux_regs, i2c_hw_engine_regs, &i2c_shift, diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2caux_dce110.h b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2caux_dce110.h index 1b1f71c60ac93..d3d8cc58666ac 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2caux_dce110.h +++ b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2caux_dce110.h @@ -45,6 +45,7 @@ struct i2caux *dal_i2caux_dce110_create( void dal_i2caux_dce110_construct( struct i2caux_dce110 *i2caux_dce110, struct dc_context *ctx, + unsigned int num_i2caux_inst, const struct dce110_aux_registers *aux_regs, const struct dce110_i2c_hw_engine_registers *i2c_hw_engine_regs, const struct dce110_i2c_hw_engine_shift *i2c_shift, diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce112/i2caux_dce112.c b/drivers/gpu/drm/amd/display/dc/i2caux/dce112/i2caux_dce112.c index dafc1a727f7f9..a9db047387245 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dce112/i2caux_dce112.c +++ b/drivers/gpu/drm/amd/display/dc/i2caux/dce112/i2caux_dce112.c @@ -93,6 +93,7 @@ static void construct( { dal_i2caux_dce110_construct(i2caux_dce110, ctx, + ARRAY_SIZE(dce112_aux_regs), dce112_aux_regs, dce112_hw_engine_regs, &i2c_shift, diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce120/i2caux_dce120.c b/drivers/gpu/drm/amd/display/dc/i2caux/dce120/i2caux_dce120.c index 0e7b182600279..6a4f344c1db49 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dce120/i2caux_dce120.c +++ b/drivers/gpu/drm/amd/display/dc/i2caux/dce120/i2caux_dce120.c @@ -111,6 +111,7 @@ struct i2caux *dal_i2caux_dce120_create( dal_i2caux_dce110_construct(i2caux_dce110, ctx, + ARRAY_SIZE(dce120_aux_regs), dce120_aux_regs, dce120_hw_engine_regs, &i2c_shift, diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dcn10/i2caux_dcn10.c b/drivers/gpu/drm/amd/display/dc/i2caux/dcn10/i2caux_dcn10.c index e44a8901f38bc..a59c1f50c1e8e 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dcn10/i2caux_dcn10.c +++ b/drivers/gpu/drm/amd/display/dc/i2caux/dcn10/i2caux_dcn10.c @@ -111,6 +111,7 @@ struct i2caux *dal_i2caux_dcn10_create( dal_i2caux_dce110_construct(i2caux_dce110, ctx, + ARRAY_SIZE(dcn10_aux_regs), dcn10_aux_regs, dcn10_hw_engine_regs, &i2c_shift, -- GitLab From 16aecfd4bf546907a6d7d06b4edfdbeea75b1839 Mon Sep 17 00:00:00 2001 From: Tony Cheng <tony.cheng@amd.com> Date: Sat, 16 Jun 2018 19:43:41 -0400 Subject: [PATCH 1111/1506] drm/amd/display: generic indirect register access add generic indirect register access following our register access pattern this will make it easier to review code and programming sequence, with all the complexity hidden in macro Signed-off-by: Tony Cheng <tony.cheng@amd.com> Reviewed-by: Yongqiang Sun <yongqiang.sun@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dc_helper.c | 51 +++++++++++++++++++ .../gpu/drm/amd/display/dc/inc/reg_helper.h | 46 +++++++++++++++++ 2 files changed, 97 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dc_helper.c b/drivers/gpu/drm/amd/display/dc/dc_helper.c index bd0fda0ceb919..e68077e655658 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_helper.c +++ b/drivers/gpu/drm/amd/display/dc/dc_helper.c @@ -255,3 +255,54 @@ uint32_t generic_reg_wait(const struct dc_context *ctx, return reg_val; } + +void generic_write_indirect_reg(const struct dc_context *ctx, + uint32_t addr_index, uint32_t addr_data, + uint32_t index, uint32_t data) +{ + dm_write_reg(ctx, addr_index, index); + dm_write_reg(ctx, addr_data, data); +} + +uint32_t generic_read_indirect_reg(const struct dc_context *ctx, + uint32_t addr_index, uint32_t addr_data, + uint32_t index) +{ + uint32_t value = 0; + + dm_write_reg(ctx, addr_index, index); + value = dm_read_reg(ctx, addr_data); + + return value; +} + + +uint32_t generic_indirect_reg_update_ex(const struct dc_context *ctx, + uint32_t addr_index, uint32_t addr_data, + uint32_t index, uint32_t reg_val, int n, + uint8_t shift1, uint32_t mask1, uint32_t field_value1, + ...) +{ + uint32_t shift, mask, field_value; + int i = 1; + + va_list ap; + + va_start(ap, field_value1); + + reg_val = set_reg_field_value_ex(reg_val, field_value1, mask1, shift1); + + while (i < n) { + shift = va_arg(ap, uint32_t); + mask = va_arg(ap, uint32_t); + field_value = va_arg(ap, uint32_t); + + reg_val = set_reg_field_value_ex(reg_val, field_value, mask, shift); + i++; + } + + generic_write_indirect_reg(ctx, addr_index, addr_data, index, reg_val); + va_end(ap); + + return reg_val; +} diff --git a/drivers/gpu/drm/amd/display/dc/inc/reg_helper.h b/drivers/gpu/drm/amd/display/dc/inc/reg_helper.h index 3306e7b0b3e34..cf5a84b9e27c4 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/reg_helper.h +++ b/drivers/gpu/drm/amd/display/dc/inc/reg_helper.h @@ -445,4 +445,50 @@ uint32_t generic_reg_get8(const struct dc_context *ctx, uint32_t addr, uint8_t shift6, uint32_t mask6, uint32_t *field_value6, uint8_t shift7, uint32_t mask7, uint32_t *field_value7, uint8_t shift8, uint32_t mask8, uint32_t *field_value8); + + +/* indirect register access */ + +#define IX_REG_SET_N(index_reg_name, data_reg_name, index, n, initial_val, ...) \ + generic_indirect_reg_update_ex(CTX, \ + REG(index_reg_name), REG(data_reg_name), IND_REG(index), \ + initial_val, \ + n, __VA_ARGS__) + +#define IX_REG_SET_2(index_reg_name, data_reg_name, index, init_value, f1, v1, f2, v2) \ + IX_REG_SET_N(index_reg_name, data_reg_name, index, 2, init_value, \ + FN(reg, f1), v1,\ + FN(reg, f2), v2) + + +#define IX_REG_READ(index_reg_name, data_reg_name, index) \ + generic_read_indirect_reg(CTX, REG(index_reg_name), REG(data_reg_name), IND_REG(index)) + + + +#define IX_REG_UPDATE_N(index_reg_name, data_reg_name, index, n, ...) \ + generic_indirect_reg_update_ex(CTX, \ + REG(index_reg_name), REG(data_reg_name), IND_REG(index), \ + IX_REG_READ(index_reg_name, data_reg_name, index), \ + n, __VA_ARGS__) + +#define IX_REG_UPDATE_2(index_reg_name, data_reg_name, index, f1, v1, f2, v2) \ + IX_REG_UPDATE_N(index_reg_name, data_reg_name, index, 2,\ + FN(reg, f1), v1,\ + FN(reg, f2), v2) + +void generic_write_indirect_reg(const struct dc_context *ctx, + uint32_t addr_index, uint32_t addr_data, + uint32_t index, uint32_t data); + +uint32_t generic_read_indirect_reg(const struct dc_context *ctx, + uint32_t addr_index, uint32_t addr_data, + uint32_t index); + +uint32_t generic_indirect_reg_update_ex(const struct dc_context *ctx, + uint32_t addr_index, uint32_t addr_data, + uint32_t index, uint32_t reg_val, int n, + uint8_t shift1, uint32_t mask1, uint32_t field_value1, + ...); + #endif /* DRIVERS_GPU_DRM_AMD_DC_DEV_DC_INC_REG_HELPER_H_ */ -- GitLab From 7a34057cb5ceb20756e30abc36c58c34be62eff9 Mon Sep 17 00:00:00 2001 From: Tony Cheng <tony.cheng@amd.com> Date: Sun, 17 Jun 2018 13:26:27 -0400 Subject: [PATCH 1112/1506] drm/amd/display: fix incorrect check for atom table size in case we have very few pins in the table, check fails and we can't boot Signed-off-by: Tony Cheng <tony.cheng@amd.com> Reviewed-by: Yongqiang Sun <yongqiang.sun@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c index aeb56e402cccf..eab007e1793c2 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c @@ -678,7 +678,7 @@ static enum bp_result bios_parser_get_gpio_pin_info( return BP_RESULT_BADBIOSTABLE; if (sizeof(struct atom_common_table_header) + - sizeof(struct atom_gpio_pin_lut_v2_1) + sizeof(struct atom_gpio_pin_assignment) > le16_to_cpu(header->table_header.structuresize)) return BP_RESULT_BADBIOSTABLE; -- GitLab From 41db5f1931ec73f2d909752e09ffb691fecdaaa1 Mon Sep 17 00:00:00 2001 From: Hersen Wu <hersenxs.wu@amd.com> Date: Fri, 15 Jun 2018 14:25:48 -0400 Subject: [PATCH 1113/1506] drm/amd/display: set-read link rate and lane count through debugfs function description get/ set DP configuration: lane_count, link_rate, spread_spectrum valid lane count value: 1, 2, 4 valid link rate value: 06h = 1.62Gbps per lane 0Ah = 2.7Gbps per lane 0Ch = 3.24Gbps per lane 14h = 5.4Gbps per lane 1Eh = 8.1Gbps per lane debugfs is located at /sys/kernel/debug/dri/0/DP-x/link_settings --- to get dp configuration xxd -l 300 phy_settings It will list current, verified, reported, preferred dp configuration. current -- for current video mode verified --- maximum configuration which pass link training reported --- DP rx report caps (DPCD register offset 0, 1 2) preferred --- user force settings --- set (or force) dp configuration echo <lane_count> <link_rate> for example, to force to 2 lane, 2.7GHz, echo 4 0xa > link_settings spread_spectrum could not be changed dynamically. in case invalid lane count, link rate are force, no hw programming will be done. please check link settings after force operation to see if HW get programming. xxd -l 300 link_settings check current and preferred settings. Signed-off-by: Hersen Wu <hersenxs.wu@amd.com> Reviewed-by: Hersen Wu <hersenxs.wu@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 227 +++++++++++++++--- 1 file changed, 196 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c index cf5ea69e46ad3..9ff8833b52c48 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -26,38 +26,211 @@ #include <linux/debugfs.h> #include "dc.h" -#include "dc_link.h" #include "amdgpu.h" #include "amdgpu_dm.h" #include "amdgpu_dm_debugfs.h" -static ssize_t dp_link_rate_debugfs_read(struct file *f, char __user *buf, +/* function description + * get/ set DP configuration: lane_count, link_rate, spread_spectrum + * + * valid lane count value: 1, 2, 4 + * valid link rate value: + * 06h = 1.62Gbps per lane + * 0Ah = 2.7Gbps per lane + * 0Ch = 3.24Gbps per lane + * 14h = 5.4Gbps per lane + * 1Eh = 8.1Gbps per lane + * + * debugfs is located at /sys/kernel/debug/dri/0/DP-x/link_settings + * + * --- to get dp configuration + * + * xxd -l 300 phy_settings + * + * It will list current, verified, reported, preferred dp configuration. + * current -- for current video mode + * verified --- maximum configuration which pass link training + * reported --- DP rx report caps (DPCD register offset 0, 1 2) + * preferred --- user force settings + * + * --- set (or force) dp configuration + * + * echo <lane_count> <link_rate> + * + * for example, to force to 2 lane, 2.7GHz, + * echo 4 0xa > link_settings + * + * spread_spectrum could not be changed dynamically. + * + * in case invalid lane count, link rate are force, no hw programming will be + * done. please check link settings after force operation to see if HW get + * programming. + * + * xxd -l 300 link_settings + * + * check current and preferred settings. + * + */ +static ssize_t dp_link_settings_read(struct file *f, char __user *buf, size_t size, loff_t *pos) { - /* TODO: create method to read link rate */ - return 1; -} + struct amdgpu_dm_connector *connector = file_inode(f)->i_private; + struct dc_link *link = connector->dc_link; + char *rd_buf = NULL; + char *rd_buf_ptr = NULL; + uint32_t rd_buf_size = 320; + int bytes_to_user; + uint8_t str_len = 0; + int r; -static ssize_t dp_link_rate_debugfs_write(struct file *f, const char __user *buf, - size_t size, loff_t *pos) -{ - /* TODO: create method to write link rate */ - return 1; -} + if (size == 0) + return 0; -static ssize_t dp_lane_count_debugfs_read(struct file *f, char __user *buf, - size_t size, loff_t *pos) -{ - /* TODO: create method to read lane count */ - return 1; + rd_buf = kcalloc(rd_buf_size, sizeof(char), GFP_KERNEL); + if (!rd_buf) + return 0; + + rd_buf_ptr = rd_buf; + + str_len = strlen("Current: %d %d %d "); + snprintf(rd_buf_ptr, str_len, "Current: %d %d %d ", + link->cur_link_settings.lane_count, + link->cur_link_settings.link_rate, + link->cur_link_settings.link_spread); + rd_buf_ptr = rd_buf_ptr + str_len; + + str_len = strlen("Verified: %d %d %d "); + snprintf(rd_buf_ptr, str_len, "Verified: %d %d %d ", + link->verified_link_cap.lane_count, + link->verified_link_cap.link_rate, + link->verified_link_cap.link_spread); + rd_buf_ptr = rd_buf_ptr + str_len; + + str_len = strlen("Reported: %d %d %d "); + snprintf(rd_buf_ptr, str_len, "Reported: %d %d %d ", + link->reported_link_cap.lane_count, + link->reported_link_cap.link_rate, + link->reported_link_cap.link_spread); + rd_buf_ptr = rd_buf_ptr + str_len; + + str_len = strlen("Preferred: %d %d %d "); + snprintf(rd_buf_ptr, str_len, "Preferred: %d %d %d ", + link->preferred_link_setting.lane_count, + link->preferred_link_setting.link_rate, + link->preferred_link_setting.link_spread); + + r = copy_to_user(buf, rd_buf, rd_buf_size); + + bytes_to_user = rd_buf_size - r; + + if (r > rd_buf_size) { + bytes_to_user = 0; + DRM_DEBUG_DRIVER("data not copy to user"); + } + + kfree(rd_buf); + return bytes_to_user; } -static ssize_t dp_lane_count_debugfs_write(struct file *f, const char __user *buf, +static ssize_t dp_link_settings_write(struct file *f, const char __user *buf, size_t size, loff_t *pos) { - /* TODO: create method to write lane count */ - return 1; + struct amdgpu_dm_connector *connector = file_inode(f)->i_private; + struct dc_link *link = connector->dc_link; + struct dc *dc = (struct dc *)link->dc; + struct dc_link_settings prefer_link_settings; + char *wr_buf = NULL; + char *wr_buf_ptr = NULL; + uint32_t wr_buf_size = 40; + int r; + int bytes_from_user; + char *sub_str; + /* 0: lane_count; 1: link_rate */ + uint8_t param_index = 0; + long param[2]; + const char delimiter[3] = {' ', '\n', '\0'}; + bool valid_input = false; + + if (size == 0) + return 0; + + wr_buf = kcalloc(wr_buf_size, sizeof(char), GFP_KERNEL); + if (!wr_buf) + return 0; + wr_buf_ptr = wr_buf; + + r = copy_from_user(wr_buf_ptr, buf, wr_buf_size); + + /* r is bytes not be copied */ + if (r >= wr_buf_size) { + kfree(wr_buf); + DRM_DEBUG_DRIVER("user data not read\n"); + return 0; + } + + bytes_from_user = wr_buf_size - r; + + while (isspace(*wr_buf_ptr)) + wr_buf_ptr++; + + while ((*wr_buf_ptr != '\0') && (param_index < 2)) { + + sub_str = strsep(&wr_buf_ptr, delimiter); + + r = kstrtol(sub_str, 16, ¶m[param_index]); + + if (r) + DRM_DEBUG_DRIVER(" -EINVAL convert error happens!\n"); + + param_index++; + while (isspace(*wr_buf_ptr)) + wr_buf_ptr++; + } + + DRM_DEBUG_DRIVER("Lane_count: %lx\n", param[0]); + DRM_DEBUG_DRIVER("link_rate: %lx\n", param[1]); + + switch (param[0]) { + case LANE_COUNT_ONE: + case LANE_COUNT_TWO: + case LANE_COUNT_FOUR: + valid_input = true; + break; + default: + break; + } + + switch (param[1]) { + case LINK_RATE_LOW: + case LINK_RATE_HIGH: + case LINK_RATE_RBR2: + case LINK_RATE_HIGH2: + case LINK_RATE_HIGH3: + valid_input = true; + break; + default: + break; + } + + if (!valid_input) { + kfree(wr_buf); + DRM_DEBUG_DRIVER("Invalid Input value exceed No HW will be programmed\n"); + return bytes_from_user; + } + + /* save user force lane_count, link_rate to preferred settings + * spread spectrum will not be changed + */ + prefer_link_settings.link_spread = link->cur_link_settings.link_spread; + prefer_link_settings.lane_count = param[0]; + prefer_link_settings.link_rate = param[1]; + + dc_link_set_preferred_link_settings(dc, &prefer_link_settings, link); + + kfree(wr_buf); + + return bytes_from_user; } static ssize_t dp_voltage_swing_debugfs_read(struct file *f, char __user *buf, @@ -102,17 +275,10 @@ static ssize_t dp_phy_test_pattern_debugfs_write(struct file *f, const char __us return 1; } -static const struct file_operations dp_link_rate_fops = { - .owner = THIS_MODULE, - .read = dp_link_rate_debugfs_read, - .write = dp_link_rate_debugfs_write, - .llseek = default_llseek -}; - -static const struct file_operations dp_lane_count_fops = { +static const struct file_operations dp_link_settings_debugfs_fops = { .owner = THIS_MODULE, - .read = dp_lane_count_debugfs_read, - .write = dp_lane_count_debugfs_write, + .read = dp_link_settings_read, + .write = dp_link_settings_write, .llseek = default_llseek }; @@ -141,8 +307,7 @@ static const struct { char *name; const struct file_operations *fops; } dp_debugfs_entries[] = { - {"link_rate", &dp_link_rate_fops}, - {"lane_count", &dp_lane_count_fops}, + {"link_settings", &dp_link_settings_debugfs_fops}, {"voltage_swing", &dp_voltage_swing_fops}, {"pre_emphasis", &dp_pre_emphasis_fops}, {"phy_test_pattern", &dp_phy_test_pattern_fops} -- GitLab From c9ff778b291b95f6f7c0aa764c714ca88cc49f7b Mon Sep 17 00:00:00 2001 From: Tony Cheng <tony.cheng@amd.com> Date: Tue, 5 Jun 2018 09:14:56 -0400 Subject: [PATCH 1114/1506] drm/amd/display: dal 3.1.53 Signed-off-by: Tony Cheng <tony.cheng@amd.com> Reviewed-by: Aric Cyr <Aric.Cyr@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 59985baac11e4..85533619440a3 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.1.52" +#define DC_VER "3.1.53" #define MAX_SURFACES 3 #define MAX_STREAMS 6 -- GitLab From 93ed1814c668fb13f3b23b629528e90a2b0d5ea3 Mon Sep 17 00:00:00 2001 From: Hugo Hu <hugo.hu@amd.com> Date: Mon, 18 Jun 2018 15:27:58 -0400 Subject: [PATCH 1115/1506] drm/amd/display: Correct calculation of duration time. Signed-off-by: Hugo Hu <hugo.hu@amd.com> Reviewed-by: Charlene Liu <Charlene.Liu@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 9cbd5036db079..bf4df34bc1df0 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 @@ -864,10 +864,10 @@ void hwss_edp_power_control( if (power_up) { unsigned long long current_ts = dm_get_timestamp(ctx); unsigned long long duration_in_ms = - dm_get_elapse_time_in_ns( + div64_u64(dm_get_elapse_time_in_ns( ctx, current_ts, - div64_u64(link->link_trace.time_stamp.edp_poweroff, 1000000)); + link->link_trace.time_stamp.edp_poweroff), 1000000); unsigned long long wait_time_ms = 0; /* max 500ms from LCDVDD off to on */ -- GitLab From 0252c9425f20ade8bfcb5ad4f1e150940acbe39c Mon Sep 17 00:00:00 2001 From: Eric Bernstein <eric.bernstein@amd.com> Date: Mon, 18 Jun 2018 15:45:07 -0400 Subject: [PATCH 1116/1506] drm/amd/display: Add Azalia registers to HW sequencer Signed-off-by: Eric Bernstein <eric.bernstein@amd.com> Reviewed-by: Charlene Liu <Charlene.Liu@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h index 0574078926184..f091d87f8f8bc 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h @@ -275,6 +275,8 @@ struct dce_hwseq_registers { uint32_t MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB; uint32_t MC_VM_SYSTEM_APERTURE_LOW_ADDR; uint32_t MC_VM_SYSTEM_APERTURE_HIGH_ADDR; + uint32_t AZALIA_AUDIO_DTO; + uint32_t AZALIA_CONTROLLER_CLOCK_GATING; }; /* set field name */ #define HWS_SF(blk_name, reg_name, field_name, post_fix)\ @@ -500,7 +502,8 @@ struct dce_hwseq_registers { type D1VGA_MODE_ENABLE; \ type D2VGA_MODE_ENABLE; \ type D3VGA_MODE_ENABLE; \ - type D4VGA_MODE_ENABLE; + type D4VGA_MODE_ENABLE; \ + type AZALIA_AUDIO_DTO_MODULE; struct dce_hwseq_shift { HWSEQ_REG_FIELD_LIST(uint8_t) -- GitLab From 8e8539c2fcdf65b6a2e6ceb93e56034896e47dd0 Mon Sep 17 00:00:00 2001 From: Charlene Liu <charlene.liu@amd.com> Date: Mon, 18 Jun 2018 19:50:07 -0400 Subject: [PATCH 1117/1506] drm/amd/display: Define couple extra DCN registers Signed-off-by: Charlene Liu <charlene.liu@amd.com> Reviewed-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h | 1 + .../gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h index f091d87f8f8bc..df3203a1d2783 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h @@ -147,6 +147,7 @@ SR(DCCG_GATE_DISABLE_CNTL2), \ SR(DCFCLK_CNTL),\ SR(DCFCLK_CNTL), \ + SR(DC_MEM_GLOBAL_PWR_REQ_CNTL), \ /* todo: get these from GVM instead of reading registers ourselves */\ MMHUB_SR(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32),\ MMHUB_SR(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32),\ diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h index 2a97cdb2cfbb3..d8ef30bed9ff6 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h @@ -42,6 +42,7 @@ #define LE_DCN_COMMON_REG_LIST(id) \ SRI(DIG_BE_CNTL, DIG, id), \ SRI(DIG_BE_EN_CNTL, DIG, id), \ + SRI(TMDS_CTL_BITS, DIG, id), \ SRI(DP_CONFIG, DP, id), \ SRI(DP_DPHY_CNTL, DP, id), \ SRI(DP_DPHY_PRBS_CNTL, DP, id), \ @@ -64,6 +65,7 @@ SRI(DP_DPHY_INTERNAL_CTRL, DP, id), \ SRI(DP_DPHY_HBR2_PATTERN_CONTROL, DP, id) + #define LE_DCN10_REG_LIST(id)\ LE_DCN_COMMON_REG_LIST(id) @@ -100,6 +102,7 @@ struct dcn10_link_enc_registers { uint32_t DP_DPHY_BS_SR_SWAP_CNTL; uint32_t DP_DPHY_HBR2_PATTERN_CONTROL; uint32_t DP_SEC_CNTL1; + uint32_t TMDS_CTL_BITS; }; #define LE_SF(reg_name, field_name, post_fix)\ @@ -110,6 +113,7 @@ struct dcn10_link_enc_registers { LE_SF(DIG0_DIG_BE_CNTL, DIG_HPD_SELECT, mask_sh),\ LE_SF(DIG0_DIG_BE_CNTL, DIG_MODE, mask_sh),\ LE_SF(DIG0_DIG_BE_CNTL, DIG_FE_SOURCE_SELECT, mask_sh),\ + LE_SF(DIG0_TMDS_CTL_BITS, TMDS_CTL0, mask_sh), \ LE_SF(DP0_DP_DPHY_CNTL, DPHY_BYPASS, mask_sh),\ LE_SF(DP0_DP_DPHY_CNTL, DPHY_ATEST_SEL_LANE0, mask_sh),\ LE_SF(DP0_DP_DPHY_CNTL, DPHY_ATEST_SEL_LANE1, mask_sh),\ @@ -198,10 +202,11 @@ struct dcn10_link_enc_registers { type DP_MSE_SAT_SLOT_COUNT3;\ type DP_MSE_SAT_UPDATE;\ type DP_MSE_16_MTP_KEEPOUT;\ + type DC_HPD_EN;\ + type TMDS_CTL0;\ type AUX_HPD_SEL;\ type AUX_LS_READ_EN;\ - type AUX_RX_RECEIVE_WINDOW;\ - type DC_HPD_EN + type AUX_RX_RECEIVE_WINDOW struct dcn10_link_enc_shift { DCN_LINK_ENCODER_REG_FIELD_LIST(uint8_t); -- GitLab From 1bd493e37807c4bf7ee8c4809d2d83545379c04d Mon Sep 17 00:00:00 2001 From: Tony Cheng <tony.cheng@amd.com> Date: Mon, 18 Jun 2018 18:32:43 -0400 Subject: [PATCH 1118/1506] drm/amd/display: Expose configure_encoder for link_encoder Signed-off-by: Tony Cheng <tony.cheng@amd.com> Reviewed-by: Charlene Liu <Charlene.Liu@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c | 3 +-- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h | 4 ++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c index fd9dc70190a88..18a7cac4f6e31 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c @@ -445,12 +445,11 @@ static uint8_t get_frontend_source( } } -static void configure_encoder( +void configure_encoder( struct dcn10_link_encoder *enc10, const struct dc_link_settings *link_settings) { /* set number of lanes */ - REG_SET(DP_CONFIG, 0, DP_UDI_LANES, link_settings->lane_count - LANE_COUNT_ONE); diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h index d8ef30bed9ff6..cd3bb5d40579c 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h @@ -271,6 +271,10 @@ void dcn10_link_encoder_setup( struct link_encoder *enc, enum signal_type signal); +void configure_encoder( + struct dcn10_link_encoder *enc10, + const struct dc_link_settings *link_settings); + /* enables TMDS PHY output */ /* TODO: still need depth or just pass in adjusted pixel clock? */ void dcn10_link_encoder_enable_tmds_output( -- GitLab From aac5db824d6f5997344101ae0e71fbb003b9692b Mon Sep 17 00:00:00 2001 From: Harry Wentland <harry.wentland@amd.com> Date: Tue, 29 May 2018 13:11:55 -0400 Subject: [PATCH 1119/1506] drm/amd/display: Serialize is_dp_sink_present Access to GPIO needs to be serialized. Aux transactions are already serialized in DRM but we also need to serialize access to the GPIO pin for purposes of DP dongle detection. Call is_dp_sink_present through DM so we can lock correctly. This follows the same pattern used for DPCD transactions. Signed-off-by: Harry Wentland <harry.wentland@amd.com> Reviewed-by: Jun Lei <Jun.Lei@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 16 ++++++++++++++++ drivers/gpu/drm/amd/display/dc/core/dc_link.c | 4 ++-- drivers/gpu/drm/amd/display/dc/dc_link.h | 2 ++ drivers/gpu/drm/amd/display/dc/dm_helpers.h | 3 +++ 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c index b19dc4cfc0301..7b51b8fde3fe3 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c @@ -454,6 +454,22 @@ bool dm_helpers_submit_i2c( return result; } +bool dm_helpers_is_dp_sink_present(struct dc_link *link) +{ + bool dp_sink_present; + struct amdgpu_dm_connector *aconnector = link->priv; + + if (!aconnector) { + BUG_ON("Failed to found connector for link!"); + return true; + } + + mutex_lock(&aconnector->dm_dp_aux.aux.hw_mutex); + dp_sink_present = dc_link_is_dp_sink_present(link); + mutex_unlock(&aconnector->dm_dp_aux.aux.hw_mutex); + return dp_sink_present; +} + enum dc_edid_status dm_helpers_read_local_edid( struct dc_context *ctx, struct dc_link *link, 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 a4180ba63d824..fe29a398b7039 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -313,7 +313,7 @@ static enum signal_type get_basic_signal_type( * @brief * Check whether there is a dongle on DP connector */ -static bool is_dp_sink_present(struct dc_link *link) +bool dc_link_is_dp_sink_present(struct dc_link *link) { enum gpio_result gpio_result; uint32_t clock_pin = 0; @@ -406,7 +406,7 @@ static enum signal_type link_detect_sink( * we assume signal is DVI; it could be corrected * to HDMI after dongle detection */ - if (!is_dp_sink_present(link)) + if (!dm_helpers_is_dp_sink_present(link)) result = SIGNAL_TYPE_DVI_SINGLE_LINK; } } diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h index 83eea42452b51..eda4a5d3ff1c7 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_link.h +++ b/drivers/gpu/drm/amd/display/dc/dc_link.h @@ -210,6 +210,8 @@ bool dc_link_dp_set_test_pattern( void dc_link_enable_hpd_filter(struct dc_link *link, bool enable); +bool dc_link_is_dp_sink_present(struct dc_link *link); + /* * DPCD access interfaces */ diff --git a/drivers/gpu/drm/amd/display/dc/dm_helpers.h b/drivers/gpu/drm/amd/display/dc/dm_helpers.h index 034369fbb9e2c..7e6b9f5b89061 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_helpers.h +++ b/drivers/gpu/drm/amd/display/dc/dm_helpers.h @@ -103,6 +103,9 @@ bool dm_helpers_submit_i2c( const struct dc_link *link, struct i2c_command *cmd); +bool dm_helpers_is_dp_sink_present( + struct dc_link *link); + enum dc_edid_status dm_helpers_read_local_edid( struct dc_context *ctx, struct dc_link *link, -- GitLab From 899e2aaddbfa0ff96fbaf31f0d9e91427e87dd88 Mon Sep 17 00:00:00 2001 From: Harry Wentland <harry.wentland@amd.com> Date: Tue, 8 May 2018 16:28:31 -0400 Subject: [PATCH 1120/1506] drm/amd/display: Break out function to simply read aux reply DRM's DP helpers take care of dealing with the error code for us. In order not to step on each other's toes we'll need to be able to simply read auch channel replies without further logic based on return values. Signed-off-by: Harry Wentland <harry.wentland@amd.com> Reviewed-by: Sun peng Li <Sunpeng.Li@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../drm/amd/display/dc/i2caux/aux_engine.h | 6 + .../dc/i2caux/dce110/aux_engine_dce110.c | 119 ++++++++++-------- 2 files changed, 76 insertions(+), 49 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.h b/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.h index b01488f710d51..c33a2898d9671 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.h +++ b/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.h @@ -44,6 +44,12 @@ struct aux_engine_funcs { void (*process_channel_reply)( struct aux_engine *engine, struct aux_reply_transaction_data *reply); + int (*read_channel_reply)( + struct aux_engine *engine, + uint32_t size, + uint8_t *buffer, + uint8_t *reply_result, + uint32_t *sw_status); enum aux_channel_operation_result (*get_channel_status)( struct aux_engine *engine, uint8_t *returned_bytes); diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.c b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.c index 2b927f25937b4..1f3940644a5b0 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.c +++ b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.c @@ -275,61 +275,92 @@ static void submit_channel_request( REG_UPDATE(AUX_SW_CONTROL, AUX_SW_GO, 1); } -static void process_channel_reply( - struct aux_engine *engine, - struct aux_reply_transaction_data *reply) +static int read_channel_reply(struct aux_engine *engine, uint32_t size, + uint8_t *buffer, uint8_t *reply_result, + uint32_t *sw_status) { struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine); + uint32_t bytes_replied; + uint32_t reply_result_32; - /* Need to do a read to get the number of bytes to process - * Alternatively, this information can be passed - - * but that causes coupling which isn't good either. */ + *sw_status = REG_GET(AUX_SW_STATUS, AUX_SW_REPLY_BYTE_COUNT, + &bytes_replied); - uint32_t bytes_replied; - uint32_t value; + /* In case HPD is LOW, exit AUX transaction */ + if ((*sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) + return -1; - value = REG_GET(AUX_SW_STATUS, - AUX_SW_REPLY_BYTE_COUNT, &bytes_replied); + /* Need at least the status byte */ + if (!bytes_replied) + return -1; - /* in case HPD is LOW, exit AUX transaction */ - if ((value & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) { - reply->status = AUX_TRANSACTION_REPLY_HPD_DISCON; - return; - } + REG_UPDATE_1BY1_3(AUX_SW_DATA, + AUX_SW_INDEX, 0, + AUX_SW_AUTOINCREMENT_DISABLE, 1, + AUX_SW_DATA_RW, 1); + + REG_GET(AUX_SW_DATA, AUX_SW_DATA, &reply_result_32); + *reply_result = (uint8_t)reply_result_32; - if (bytes_replied) { - uint32_t reply_result; + if (reply_result_32 >> 4 == 0) { /* ACK */ + uint32_t i = 0; - REG_UPDATE_1BY1_3(AUX_SW_DATA, - AUX_SW_INDEX, 0, - AUX_SW_AUTOINCREMENT_DISABLE, 1, - AUX_SW_DATA_RW, 1); + /* First byte was already used to get the command status */ + --bytes_replied; - REG_GET(AUX_SW_DATA, - AUX_SW_DATA, &reply_result); + /* Do not overflow buffer */ + if (bytes_replied > size) + return -1; - reply_result = reply_result >> 4; + while (i < bytes_replied) { + uint32_t aux_sw_data_val; - switch (reply_result) { - case 0: /* ACK */ { - uint32_t i = 0; + REG_GET(AUX_SW_DATA, AUX_SW_DATA, &aux_sw_data_val); + buffer[i] = aux_sw_data_val; + ++i; + } - /* first byte was already used - * to get the command status */ - --bytes_replied; + return i; + } + + return 0; +} + +static void process_channel_reply( + struct aux_engine *engine, + struct aux_reply_transaction_data *reply) +{ + int bytes_replied; + uint8_t reply_result; + uint32_t sw_status; - while (i < bytes_replied) { - uint32_t aux_sw_data_val; + bytes_replied = read_channel_reply(engine, reply->length, reply->data, + &reply_result, &sw_status); - REG_GET(AUX_SW_DATA, - AUX_SW_DATA, &aux_sw_data_val); + /* in case HPD is LOW, exit AUX transaction */ + if ((sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) { + reply->status = AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON; + return; + } - reply->data[i] = aux_sw_data_val; - ++i; - } + if (bytes_replied < 0) { + /* Need to handle an error case... + * Hopefully, upper layer function won't call this function if + * the number of bytes in the reply was 0, because there was + * surely an error that was asserted that should have been + * handled for hot plug case, this could happens + */ + if (!(sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) { + reply->status = AUX_TRANSACTION_REPLY_INVALID; + ASSERT_CRITICAL(false); + return; + } + } else { + reply_result = reply_result >> 4; + switch (reply_result) { + case 0: /* ACK */ reply->status = AUX_TRANSACTION_REPLY_AUX_ACK; - } break; case 1: /* NACK */ reply->status = AUX_TRANSACTION_REPLY_AUX_NACK; @@ -346,17 +377,6 @@ static void process_channel_reply( default: reply->status = AUX_TRANSACTION_REPLY_INVALID; } - } else { - /* Need to handle an error case... - * hopefully, upper layer function won't call this function - * if the number of bytes in the reply was 0 - * because there was surely an error that was asserted - * that should have been handled - * for hot plug case, this could happens*/ - if (!(value & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) { - reply->status = AUX_TRANSACTION_REPLY_INVALID; - ASSERT_CRITICAL(false); - } } } @@ -427,6 +447,7 @@ static const struct aux_engine_funcs aux_engine_funcs = { .acquire_engine = acquire_engine, .submit_channel_request = submit_channel_request, .process_channel_reply = process_channel_reply, + .read_channel_reply = read_channel_reply, .get_channel_status = get_channel_status, .is_engine_available = is_engine_available, }; -- GitLab From 084b3765ec4baf8b7de57e7dc1e1ba1b6905e9d9 Mon Sep 17 00:00:00 2001 From: Harry Wentland <harry.wentland@amd.com> Date: Wed, 9 May 2018 16:26:17 -0400 Subject: [PATCH 1121/1506] drm/amd/display: Return aux replies directly to DRM Currently we still go through DC code that does error checking, retries, etc. There's no need for that since DRM already does that for us. This simplifies the code a bit and makes it easier to debug. This also ensures we correctly tell DRM how many bytes have actually been read, as we should. This allows DRM to correctly read the EDID on the Chamelium DP port. Signed-off-by: Harry Wentland <harry.wentland@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../display/amdgpu_dm/amdgpu_dm_mst_types.c | 89 ++++++++----- .../gpu/drm/amd/display/dc/core/dc_link_ddc.c | 120 ++++++++---------- .../gpu/drm/amd/display/dc/inc/dc_link_ddc.h | 22 +--- 3 files changed, 117 insertions(+), 114 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index c74105758815d..8348d4d46b301 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -80,52 +80,72 @@ static void log_dpcd(uint8_t type, static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) { - enum i2c_mot_mode mot = (msg->request & DP_AUX_I2C_MOT) ? - I2C_MOT_TRUE : I2C_MOT_FALSE; - enum ddc_result res; + ssize_t result = 0; + enum i2caux_transaction_action action; + enum aux_transaction_type type; if (WARN_ON(msg->size > 16)) return -E2BIG; switch (msg->request & ~DP_AUX_I2C_MOT) { case DP_AUX_NATIVE_READ: - res = dal_ddc_service_read_dpcd_data( - TO_DM_AUX(aux)->ddc_service, - false, - I2C_MOT_UNDEF, - msg->address, - msg->buffer, - msg->size); + type = AUX_TRANSACTION_TYPE_DP; + action = I2CAUX_TRANSACTION_ACTION_DP_READ; + + result = dc_link_aux_transfer(TO_DM_AUX(aux)->ddc_service, + msg->address, + &msg->reply, + msg->buffer, + msg->size, + type, + action); break; case DP_AUX_NATIVE_WRITE: - res = dal_ddc_service_write_dpcd_data( - TO_DM_AUX(aux)->ddc_service, - false, - I2C_MOT_UNDEF, - msg->address, - msg->buffer, - msg->size); + type = AUX_TRANSACTION_TYPE_DP; + action = I2CAUX_TRANSACTION_ACTION_DP_WRITE; + + dc_link_aux_transfer(TO_DM_AUX(aux)->ddc_service, + msg->address, + &msg->reply, + msg->buffer, + msg->size, + type, + action); + result = msg->size; break; case DP_AUX_I2C_READ: - res = dal_ddc_service_read_dpcd_data( - TO_DM_AUX(aux)->ddc_service, - true, - mot, - msg->address, - msg->buffer, - msg->size); + type = AUX_TRANSACTION_TYPE_I2C; + if (msg->request & DP_AUX_I2C_MOT) + action = I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT; + else + action = I2CAUX_TRANSACTION_ACTION_I2C_READ; + + result = dc_link_aux_transfer(TO_DM_AUX(aux)->ddc_service, + msg->address, + &msg->reply, + msg->buffer, + msg->size, + type, + action); break; case DP_AUX_I2C_WRITE: - res = dal_ddc_service_write_dpcd_data( - TO_DM_AUX(aux)->ddc_service, - true, - mot, - msg->address, - msg->buffer, - msg->size); + type = AUX_TRANSACTION_TYPE_I2C; + if (msg->request & DP_AUX_I2C_MOT) + action = I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT; + else + action = I2CAUX_TRANSACTION_ACTION_I2C_WRITE; + + dc_link_aux_transfer(TO_DM_AUX(aux)->ddc_service, + msg->address, + &msg->reply, + msg->buffer, + msg->size, + type, + action); + result = msg->size; break; default: - return 0; + return -EINVAL; } #ifdef TRACE_DPCD @@ -136,7 +156,10 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, r == DDC_RESULT_SUCESSFULL); #endif - return msg->size; + if (result < 0) /* DC doesn't know about kernel error codes */ + result = -EIO; + + return result; } static enum drm_connector_status diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c index d5294798b0a54..d108ccfc5cf9f 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c @@ -33,6 +33,10 @@ #include "include/vector.h" #include "core_types.h" #include "dc_link_ddc.h" +#include "i2caux/engine.h" +#include "i2caux/i2c_engine.h" +#include "i2caux/aux_engine.h" +#include "i2caux/i2caux.h" #define AUX_POWER_UP_WA_DELAY 500 #define I2C_OVER_AUX_DEFER_WA_DELAY 70 @@ -629,78 +633,62 @@ bool dal_ddc_service_query_ddc_data( return ret; } -enum ddc_result dal_ddc_service_read_dpcd_data( - struct ddc_service *ddc, - bool i2c, - enum i2c_mot_mode mot, - uint32_t address, - uint8_t *data, - uint32_t len) +int dc_link_aux_transfer(struct ddc_service *ddc, + unsigned int address, + uint8_t *reply, + void *buffer, + unsigned int size, + enum aux_transaction_type type, + enum i2caux_transaction_action action) { - struct aux_payload read_payload = { - .i2c_over_aux = i2c, - .write = false, - .address = address, - .length = len, - .data = data, - }; - struct aux_command command = { - .payloads = &read_payload, - .number_of_payloads = 1, - .defer_delay = 0, - .max_defer_write_retry = 0, - .mot = mot - }; - - if (len > DEFAULT_AUX_MAX_DATA_SIZE) { - BREAK_TO_DEBUGGER(); - return DDC_RESULT_FAILED_INVALID_OPERATION; - } + struct i2caux *i2caux = ddc->ctx->i2caux; + struct ddc *ddc_pin = ddc->ddc_pin; + struct aux_engine *engine; + enum aux_channel_operation_result operation_result; + struct aux_request_transaction_data aux_req; + struct aux_reply_transaction_data aux_rep; + uint8_t returned_bytes = 0; + int res = -1; + uint32_t status; - if (dal_i2caux_submit_aux_command( - ddc->ctx->i2caux, - ddc->ddc_pin, - &command)) - return DDC_RESULT_SUCESSFULL; + memset(&aux_req, 0, sizeof(aux_req)); + memset(&aux_rep, 0, sizeof(aux_rep)); - return DDC_RESULT_FAILED_OPERATION; -} + engine = i2caux->funcs->acquire_aux_engine(i2caux, ddc_pin); -enum ddc_result dal_ddc_service_write_dpcd_data( - struct ddc_service *ddc, - bool i2c, - enum i2c_mot_mode mot, - uint32_t address, - const uint8_t *data, - uint32_t len) -{ - struct aux_payload write_payload = { - .i2c_over_aux = i2c, - .write = true, - .address = address, - .length = len, - .data = (uint8_t *)data, - }; - struct aux_command command = { - .payloads = &write_payload, - .number_of_payloads = 1, - .defer_delay = 0, - .max_defer_write_retry = 0, - .mot = mot - }; - - if (len > DEFAULT_AUX_MAX_DATA_SIZE) { - BREAK_TO_DEBUGGER(); - return DDC_RESULT_FAILED_INVALID_OPERATION; - } + aux_req.type = type; + aux_req.action = action; + + aux_req.address = address; + aux_req.delay = 0; + aux_req.length = size; + aux_req.data = buffer; + + engine->funcs->submit_channel_request(engine, &aux_req); + operation_result = engine->funcs->get_channel_status(engine, &returned_bytes); - if (dal_i2caux_submit_aux_command( - ddc->ctx->i2caux, - ddc->ddc_pin, - &command)) - return DDC_RESULT_SUCESSFULL; + switch (operation_result) { + case AUX_CHANNEL_OPERATION_SUCCEEDED: + res = returned_bytes; + + if (res <= size && res > 0) + res = engine->funcs->read_channel_reply(engine, size, + buffer, reply, + &status); + + break; + case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON: + res = 0; + break; + case AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN: + case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY: + case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT: + res = -1; + break; + } - return DDC_RESULT_FAILED_OPERATION; + i2caux->funcs->release_engine(i2caux, &engine->base); + return res; } /*test only function*/ diff --git a/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h b/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h index 0bf73b742f1f7..538b83303b866 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h +++ b/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h @@ -102,21 +102,13 @@ bool dal_ddc_service_query_ddc_data( uint8_t *read_buf, uint32_t read_size); -enum ddc_result dal_ddc_service_read_dpcd_data( - struct ddc_service *ddc, - bool i2c, - enum i2c_mot_mode mot, - uint32_t address, - uint8_t *data, - uint32_t len); - -enum ddc_result dal_ddc_service_write_dpcd_data( - struct ddc_service *ddc, - bool i2c, - enum i2c_mot_mode mot, - uint32_t address, - const uint8_t *data, - uint32_t len); +int dc_link_aux_transfer(struct ddc_service *ddc, + unsigned int address, + uint8_t *reply, + void *buffer, + unsigned int size, + enum aux_transaction_type type, + enum i2caux_transaction_action action); void dal_ddc_service_write_scdc_data( struct ddc_service *ddc_service, -- GitLab From e1cb3e4801e6896ba93d63222b1052199d2a8c9b Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com> Date: Tue, 19 Jun 2018 09:58:24 -0400 Subject: [PATCH 1122/1506] drm/amd/display: Convert remaining loggers off dc_logger - Removed dal/dm/dc loggers from linux, switched to kernel prints - Modified functions that used these directly to use macros - dc_logger support is completely dropped from Linux Signed-off-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com> Reviewed-by: Harry Wentland <Harry.Wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/TODO | 8 +- .../gpu/drm/amd/display/dc/basics/Makefile | 2 +- .../drm/amd/display/dc/basics/log_helpers.c | 71 +-- .../gpu/drm/amd/display/dc/basics/logger.c | 406 ------------------ .../drm/amd/display/dc/calcs/calcs_logger.h | 9 +- .../gpu/drm/amd/display/dc/calcs/dce_calcs.c | 6 +- drivers/gpu/drm/amd/display/dc/core/dc.c | 15 +- .../gpu/drm/amd/display/dc/core/dc_stream.c | 23 +- drivers/gpu/drm/amd/display/dc/dc_stream.h | 5 +- drivers/gpu/drm/amd/display/dc/dc_types.h | 2 - .../amd/display/dc/dce110/dce110_resource.c | 34 +- .../amd/display/dc/dce112/dce112_resource.c | 34 +- .../amd/display/include/logger_interface.h | 138 ++---- .../drm/amd/display/include/logger_types.h | 59 --- 14 files changed, 99 insertions(+), 713 deletions(-) delete mode 100644 drivers/gpu/drm/amd/display/dc/basics/logger.c diff --git a/drivers/gpu/drm/amd/display/TODO b/drivers/gpu/drm/amd/display/TODO index 357d596484016..a8a6c106e8c74 100644 --- a/drivers/gpu/drm/amd/display/TODO +++ b/drivers/gpu/drm/amd/display/TODO @@ -97,10 +97,10 @@ share it with drivers. But that's a very long term goal, and by far not just an issue with DC - other drivers, especially around DP sink handling, are equally guilty. -19. The DC logger is still a rather sore thing, but I know that the DRM_DEBUG -stuff just isn't up to the challenges either. We need to figure out something -that integrates better with DRM and linux debug printing, while not being -useless with filtering output. dynamic debug printing might be an option. +19. DONE - The DC logger is still a rather sore thing, but I know that the +DRM_DEBUG stuff just isn't up to the challenges either. We need to figure out +something that integrates better with DRM and linux debug printing, while not +being useless with filtering output. dynamic debug printing might be an option. 20. Use kernel i2c device to program HDMI retimer. Some boards have an HDMI retimer that we need to program to pass PHY compliance. Currently that's diff --git a/drivers/gpu/drm/amd/display/dc/basics/Makefile b/drivers/gpu/drm/amd/display/dc/basics/Makefile index b49ea96b5daee..a50a76471107e 100644 --- a/drivers/gpu/drm/amd/display/dc/basics/Makefile +++ b/drivers/gpu/drm/amd/display/dc/basics/Makefile @@ -25,7 +25,7 @@ # subcomponents. BASICS = conversion.o fixpt31_32.o \ - logger.o log_helpers.o vector.o + log_helpers.o vector.o AMD_DAL_BASICS = $(addprefix $(AMDDALPATH)/dc/basics/,$(BASICS)) diff --git a/drivers/gpu/drm/amd/display/dc/basics/log_helpers.c b/drivers/gpu/drm/amd/display/dc/basics/log_helpers.c index f6c00a51d51a3..26583f346c395 100644 --- a/drivers/gpu/drm/amd/display/dc/basics/log_helpers.c +++ b/drivers/gpu/drm/amd/display/dc/basics/log_helpers.c @@ -28,77 +28,12 @@ #include "include/logger_interface.h" #include "dm_helpers.h" -#define NUM_ELEMENTS(a) (sizeof(a) / sizeof((a)[0])) - -struct dc_signal_type_info { - enum signal_type type; - char name[MAX_NAME_LEN]; -}; - -static const struct dc_signal_type_info signal_type_info_tbl[] = { - {SIGNAL_TYPE_NONE, "NC"}, - {SIGNAL_TYPE_DVI_SINGLE_LINK, "DVI"}, - {SIGNAL_TYPE_DVI_DUAL_LINK, "DDVI"}, - {SIGNAL_TYPE_HDMI_TYPE_A, "HDMIA"}, - {SIGNAL_TYPE_LVDS, "LVDS"}, - {SIGNAL_TYPE_RGB, "VGA"}, - {SIGNAL_TYPE_DISPLAY_PORT, "DP"}, - {SIGNAL_TYPE_DISPLAY_PORT_MST, "MST"}, - {SIGNAL_TYPE_EDP, "eDP"}, - {SIGNAL_TYPE_VIRTUAL, "Virtual"} -}; - -void dc_conn_log(struct dc_context *ctx, - const struct dc_link *link, - uint8_t *hex_data, - int hex_data_count, - enum dc_log_type event, - const char *msg, - ...) +void dc_conn_log_hex_linux(const uint8_t *hex_data, int hex_data_count) { int i; - va_list args; - struct log_entry entry = { 0 }; - enum signal_type signal; - - if (link->local_sink) - signal = link->local_sink->sink_signal; - else - signal = link->connector_signal; - - if (link->type == dc_connection_mst_branch) - signal = SIGNAL_TYPE_DISPLAY_PORT_MST; - - dm_logger_open(ctx->logger, &entry, event); - - for (i = 0; i < NUM_ELEMENTS(signal_type_info_tbl); i++) - if (signal == signal_type_info_tbl[i].type) - break; - - if (i == NUM_ELEMENTS(signal_type_info_tbl)) - goto fail; - - dm_logger_append_heading(&entry); - - dm_logger_append(&entry, "[%s][ConnIdx:%d] ", - signal_type_info_tbl[i].name, - link->link_index); - - va_start(args, msg); - dm_logger_append_va(&entry, msg, args); - - if (entry.buf_offset > 0 && - entry.buf[entry.buf_offset - 1] == '\n') - entry.buf_offset--; if (hex_data) for (i = 0; i < hex_data_count; i++) - dm_logger_append(&entry, "%2.2X ", hex_data[i]); - - dm_logger_append(&entry, "^\n"); - -fail: - dm_logger_close(&entry); - - va_end(args); + DC_LOG_DEBUG("%2.2X ", hex_data[i]); } + diff --git a/drivers/gpu/drm/amd/display/dc/basics/logger.c b/drivers/gpu/drm/amd/display/dc/basics/logger.c deleted file mode 100644 index a3c56cd8b3965..0000000000000 --- a/drivers/gpu/drm/amd/display/dc/basics/logger.c +++ /dev/null @@ -1,406 +0,0 @@ -/* - * Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ -#include "dm_services.h" -#include "include/logger_interface.h" -#include "logger.h" - - -#define NUM_ELEMENTS(a) (sizeof(a) / sizeof((a)[0])) - -static const struct dc_log_type_info log_type_info_tbl[] = { - {LOG_ERROR, "Error"}, - {LOG_WARNING, "Warning"}, - {LOG_DEBUG, "Debug"}, - {LOG_DC, "DC_Interface"}, - {LOG_DTN, "DTN"}, - {LOG_SURFACE, "Surface"}, - {LOG_HW_HOTPLUG, "HW_Hotplug"}, - {LOG_HW_LINK_TRAINING, "HW_LKTN"}, - {LOG_HW_SET_MODE, "HW_Mode"}, - {LOG_HW_RESUME_S3, "HW_Resume"}, - {LOG_HW_AUDIO, "HW_Audio"}, - {LOG_HW_HPD_IRQ, "HW_HPDIRQ"}, - {LOG_MST, "MST"}, - {LOG_SCALER, "Scaler"}, - {LOG_BIOS, "BIOS"}, - {LOG_BANDWIDTH_CALCS, "BWCalcs"}, - {LOG_BANDWIDTH_VALIDATION, "BWValidation"}, - {LOG_I2C_AUX, "I2C_AUX"}, - {LOG_SYNC, "Sync"}, - {LOG_BACKLIGHT, "Backlight"}, - {LOG_FEATURE_OVERRIDE, "Override"}, - {LOG_DETECTION_EDID_PARSER, "Edid"}, - {LOG_DETECTION_DP_CAPS, "DP_Caps"}, - {LOG_RESOURCE, "Resource"}, - {LOG_DML, "DML"}, - {LOG_EVENT_MODE_SET, "Mode"}, - {LOG_EVENT_DETECTION, "Detect"}, - {LOG_EVENT_LINK_TRAINING, "LKTN"}, - {LOG_EVENT_LINK_LOSS, "LinkLoss"}, - {LOG_EVENT_UNDERFLOW, "Underflow"}, - {LOG_IF_TRACE, "InterfaceTrace"}, - {LOG_PERF_TRACE, "PerfTrace"}, - {LOG_DISPLAYSTATS, "DisplayStats"} -}; - - -/* ----------- Object init and destruction ----------- */ -static bool construct(struct dc_context *ctx, struct dal_logger *logger, - uint32_t log_mask) -{ - /* malloc buffer and init offsets */ - logger->log_buffer_size = DAL_LOGGER_BUFFER_MAX_SIZE; - logger->log_buffer = kcalloc(logger->log_buffer_size, sizeof(char), - GFP_KERNEL); - if (!logger->log_buffer) - return false; - - /* Initialize both offsets to start of buffer (empty) */ - logger->buffer_read_offset = 0; - logger->buffer_write_offset = 0; - - logger->open_count = 0; - - logger->flags.bits.ENABLE_CONSOLE = 1; - logger->flags.bits.ENABLE_BUFFER = 0; - - logger->ctx = ctx; - - logger->mask = log_mask; - - return true; -} - -static void destruct(struct dal_logger *logger) -{ - if (logger->log_buffer) { - kfree(logger->log_buffer); - logger->log_buffer = NULL; - } -} - -struct dal_logger *dal_logger_create(struct dc_context *ctx, uint32_t log_mask) -{ - /* malloc struct */ - struct dal_logger *logger = kzalloc(sizeof(struct dal_logger), - GFP_KERNEL); - - if (!logger) - return NULL; - if (!construct(ctx, logger, log_mask)) { - kfree(logger); - return NULL; - } - - return logger; -} - -uint32_t dal_logger_destroy(struct dal_logger **logger) -{ - if (logger == NULL || *logger == NULL) - return 1; - destruct(*logger); - kfree(*logger); - *logger = NULL; - - return 0; -} - -/* ------------------------------------------------------------------------ */ -void dm_logger_append_heading(struct log_entry *entry) -{ - int j; - - for (j = 0; j < NUM_ELEMENTS(log_type_info_tbl); j++) { - - const struct dc_log_type_info *info = &log_type_info_tbl[j]; - - if (info->type == entry->type) - dm_logger_append(entry, "[%s]\t", info->name); - } -} - - -/* Print everything unread existing in log_buffer to debug console*/ -void dm_logger_flush_buffer(struct dal_logger *logger, bool should_warn) -{ - char *string_start = &logger->log_buffer[logger->buffer_read_offset]; - - if (should_warn) - dm_output_to_console( - "---------------- FLUSHING LOG BUFFER ----------------\n"); - while (logger->buffer_read_offset < logger->buffer_write_offset) { - - if (logger->log_buffer[logger->buffer_read_offset] == '\0') { - dm_output_to_console("%s", string_start); - string_start = logger->log_buffer + logger->buffer_read_offset + 1; - } - logger->buffer_read_offset++; - } - if (should_warn) - dm_output_to_console( - "-------------- END FLUSHING LOG BUFFER --------------\n\n"); -} -/* ------------------------------------------------------------------------ */ - -/* Warning: Be careful that 'msg' is null terminated and the total size is - * less than DAL_LOGGER_BUFFER_MAX_LOG_LINE_SIZE (256) including '\0' - */ -static bool dal_logger_should_log( - struct dal_logger *logger, - enum dc_log_type log_type) -{ - if (logger->mask & (1 << log_type)) - return true; - - return false; -} - -static void log_to_debug_console(struct log_entry *entry) -{ - struct dal_logger *logger = entry->logger; - - if (logger->flags.bits.ENABLE_CONSOLE == 0) - return; - - if (entry->buf_offset) { - switch (entry->type) { - case LOG_ERROR: - dm_error("%s", entry->buf); - break; - default: - dm_output_to_console("%s", entry->buf); - break; - } - } -} - - -static void log_to_internal_buffer(struct log_entry *entry) -{ - - uint32_t size = entry->buf_offset; - struct dal_logger *logger = entry->logger; - - if (logger->flags.bits.ENABLE_BUFFER == 0) - return; - - if (logger->log_buffer == NULL) - return; - - if (size > 0 && size < logger->log_buffer_size) { - - int buffer_space = logger->log_buffer_size - - logger->buffer_write_offset; - - if (logger->buffer_write_offset == logger->buffer_read_offset) { - /* Buffer is empty, start writing at beginning */ - buffer_space = logger->log_buffer_size; - logger->buffer_write_offset = 0; - logger->buffer_read_offset = 0; - } - - if (buffer_space > size) { - /* No wrap around, copy 'size' bytes - * from 'entry->buf' to 'log_buffer' - */ - memmove(logger->log_buffer + - logger->buffer_write_offset, - entry->buf, size); - logger->buffer_write_offset += size; - - } else { - /* Not enough room remaining, we should flush - * existing logs */ - - /* Flush existing unread logs to console */ - dm_logger_flush_buffer(logger, true); - - /* Start writing to beginning of buffer */ - memmove(logger->log_buffer, entry->buf, size); - logger->buffer_write_offset = size; - logger->buffer_read_offset = 0; - } - - } -} - -static void append_entry( - struct log_entry *entry, - char *buffer, - uint32_t buf_size) -{ - if (!entry->buf || - entry->buf_offset + buf_size > entry->max_buf_bytes - ) { - BREAK_TO_DEBUGGER(); - return; - } - - /* Todo: check if off by 1 byte due to \0 anywhere */ - memmove(entry->buf + entry->buf_offset, buffer, buf_size); - entry->buf_offset += buf_size; -} - - -void dm_logger_write( - struct dal_logger *logger, - enum dc_log_type log_type, - const char *msg, - ...) -{ - if (logger && dal_logger_should_log(logger, log_type)) { - uint32_t size; - va_list args; - char buffer[LOG_MAX_LINE_SIZE]; - struct log_entry entry; - - va_start(args, msg); - - entry.logger = logger; - - entry.buf = buffer; - - entry.buf_offset = 0; - entry.max_buf_bytes = DAL_LOGGER_BUFFER_MAX_SIZE * sizeof(char); - - entry.type = log_type; - - dm_logger_append_heading(&entry); - - size = dm_log_to_buffer( - buffer, LOG_MAX_LINE_SIZE - 1, msg, args); - - buffer[entry.buf_offset + size] = '\0'; - entry.buf_offset += size + 1; - - /* --Flush log_entry buffer-- */ - /* print to kernel console */ - log_to_debug_console(&entry); - /* log internally for dsat */ - log_to_internal_buffer(&entry); - - va_end(args); - } -} - -/* Same as dm_logger_write, except without open() and close(), which must - * be done separately. - */ -void dm_logger_append( - struct log_entry *entry, - const char *msg, - ...) -{ - va_list args; - - va_start(args, msg); - dm_logger_append_va(entry, msg, args); - va_end(args); -} - -void dm_logger_append_va( - struct log_entry *entry, - const char *msg, - va_list args) -{ - struct dal_logger *logger; - - if (!entry) { - BREAK_TO_DEBUGGER(); - return; - } - - logger = entry->logger; - - if (logger && logger->open_count > 0 && - dal_logger_should_log(logger, entry->type)) { - - uint32_t size; - char buffer[LOG_MAX_LINE_SIZE]; - - size = dm_log_to_buffer( - buffer, LOG_MAX_LINE_SIZE, msg, args); - - if (size < LOG_MAX_LINE_SIZE - 1) { - append_entry(entry, buffer, size); - } else { - append_entry(entry, "LOG_ERROR, line too long\n", 27); - } - } -} - -void dm_logger_open( - struct dal_logger *logger, - struct log_entry *entry, /* out */ - enum dc_log_type log_type) -{ - if (!entry) { - BREAK_TO_DEBUGGER(); - return; - } - - entry->type = log_type; - entry->logger = logger; - - entry->buf = kzalloc(DAL_LOGGER_BUFFER_MAX_SIZE, - GFP_KERNEL); - - entry->buf_offset = 0; - entry->max_buf_bytes = DAL_LOGGER_BUFFER_MAX_SIZE * sizeof(char); - - logger->open_count++; - - dm_logger_append_heading(entry); -} - -void dm_logger_close(struct log_entry *entry) -{ - struct dal_logger *logger = entry->logger; - - if (logger && logger->open_count > 0) { - logger->open_count--; - } else { - BREAK_TO_DEBUGGER(); - goto cleanup; - } - - /* --Flush log_entry buffer-- */ - /* print to kernel console */ - log_to_debug_console(entry); - /* log internally for dsat */ - log_to_internal_buffer(entry); - - /* TODO: Write end heading */ - -cleanup: - if (entry->buf) { - kfree(entry->buf); - entry->buf = NULL; - entry->buf_offset = 0; - entry->max_buf_bytes = 0; - } -} - diff --git a/drivers/gpu/drm/amd/display/dc/calcs/calcs_logger.h b/drivers/gpu/drm/amd/display/dc/calcs/calcs_logger.h index fc3f98fb09ead..62435bfc274da 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/calcs_logger.h +++ b/drivers/gpu/drm/amd/display/dc/calcs/calcs_logger.h @@ -25,10 +25,9 @@ #ifndef _CALCS_CALCS_LOGGER_H_ #define _CALCS_CALCS_LOGGER_H_ -#define DC_LOGGER \ - logger +#define DC_LOGGER ctx->logger -static void print_bw_calcs_dceip(struct dal_logger *logger, const struct bw_calcs_dceip *dceip) +static void print_bw_calcs_dceip(struct dc_context *ctx, const struct bw_calcs_dceip *dceip) { DC_LOG_BANDWIDTH_CALCS("#####################################################################"); @@ -122,7 +121,7 @@ static void print_bw_calcs_dceip(struct dal_logger *logger, const struct bw_calc } -static void print_bw_calcs_vbios(struct dal_logger *logger, const struct bw_calcs_vbios *vbios) +static void print_bw_calcs_vbios(struct dc_context *ctx, const struct bw_calcs_vbios *vbios) { DC_LOG_BANDWIDTH_CALCS("#####################################################################"); @@ -181,7 +180,7 @@ static void print_bw_calcs_vbios(struct dal_logger *logger, const struct bw_calc } -static void print_bw_calcs_data(struct dal_logger *logger, struct bw_calcs_data *data) +static void print_bw_calcs_data(struct dc_context *ctx, struct bw_calcs_data *data) { int i, j, k; diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c b/drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c index 2c4e8f0cb2dcd..160d11a15eac7 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c @@ -3010,9 +3010,9 @@ bool bw_calcs(struct dc_context *ctx, struct bw_fixed low_yclk = vbios->low_yclk; if (ctx->dc->debug.bandwidth_calcs_trace) { - print_bw_calcs_dceip(ctx->logger, dceip); - print_bw_calcs_vbios(ctx->logger, vbios); - print_bw_calcs_data(ctx->logger, data); + print_bw_calcs_dceip(ctx, dceip); + print_bw_calcs_vbios(ctx, vbios); + print_bw_calcs_data(ctx, data); } calculate_bandwidth(dceip, vbios, data); diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 815656a5b6bdd..cb0be7f6994ca 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -467,9 +467,6 @@ static void destruct(struct dc *dc) if (dc->ctx->created_bios) dal_bios_parser_destroy(&dc->ctx->dc_bios); - if (dc->ctx->logger) - dal_logger_destroy(&dc->ctx->logger); - kfree(dc->ctx); dc->ctx = NULL; @@ -492,7 +489,6 @@ static void destruct(struct dc *dc) static bool construct(struct dc *dc, const struct dc_init_data *init_params) { - struct dal_logger *logger; struct dc_context *dc_ctx; struct bw_calcs_dceip *dc_dceip; struct bw_calcs_vbios *dc_vbios; @@ -557,14 +553,7 @@ static bool construct(struct dc *dc, } /* Create logger */ - logger = dal_logger_create(dc_ctx, init_params->log_mask); - if (!logger) { - /* can *not* call logger. call base driver 'print error' */ - dm_error("%s: failed to create Logger!\n", __func__); - goto fail; - } - dc_ctx->logger = logger; dc_ctx->dce_environment = init_params->dce_environment; dc_version = resource_parse_asic_id(init_params->asic_id); @@ -983,9 +972,7 @@ bool dc_commit_state(struct dc *dc, struct dc_state *context) for (i = 0; i < context->stream_count; i++) { struct dc_stream_state *stream = context->streams[i]; - dc_stream_log(stream, - dc->ctx->logger, - LOG_DC); + dc_stream_log(dc, stream); } result = dc_commit_state_no_check(dc, context); 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 3732a1de9d6c2..0223f4867e8d0 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c @@ -30,6 +30,8 @@ #include "ipp.h" #include "timing_generator.h" +#define DC_LOGGER dc->ctx->logger + /******************************************************************************* * Private functions ******************************************************************************/ @@ -317,16 +319,10 @@ bool dc_stream_get_scanoutpos(const struct dc_stream_state *stream, return ret; } - -void dc_stream_log( - const struct dc_stream_state *stream, - struct dal_logger *dm_logger, - enum dc_log_type log_type) +void dc_stream_log(const struct dc *dc, const struct dc_stream_state *stream) { - - dm_logger_write(dm_logger, - log_type, - "core_stream 0x%x: src: %d, %d, %d, %d; dst: %d, %d, %d, %d, colorSpace:%d\n", + DC_LOG_DC( + "core_stream 0x%p: src: %d, %d, %d, %d; dst: %d, %d, %d, %d, colorSpace:%d\n", stream, stream->src.x, stream->src.y, @@ -337,21 +333,18 @@ void dc_stream_log( stream->dst.width, stream->dst.height, stream->output_color_space); - dm_logger_write(dm_logger, - log_type, + DC_LOG_DC( "\tpix_clk_khz: %d, h_total: %d, v_total: %d, pixelencoder:%d, displaycolorDepth:%d\n", stream->timing.pix_clk_khz, stream->timing.h_total, stream->timing.v_total, stream->timing.pixel_encoding, stream->timing.display_color_depth); - dm_logger_write(dm_logger, - log_type, + DC_LOG_DC( "\tsink name: %s, serial: %d\n", stream->sink->edid_caps.display_name, stream->sink->edid_caps.serial_number); - dm_logger_write(dm_logger, - log_type, + DC_LOG_DC( "\tlink: %d\n", stream->sink->link->link_index); } diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index af503e0286a75..64eeb440e3d31 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -147,10 +147,7 @@ void dc_commit_updates_for_stream(struct dc *dc, /* * Log the current stream state. */ -void dc_stream_log( - const struct dc_stream_state *stream, - struct dal_logger *dc_logger, - enum dc_log_type log_type); +void dc_stream_log(const struct dc *dc, const struct dc_stream_state *stream); uint8_t dc_get_current_stream_count(struct dc *dc); struct dc_stream_state *dc_get_stream_at_index(struct dc *dc, uint8_t i); diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index c96e526d07bb6..03bf9eee9a045 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -77,8 +77,6 @@ struct dc_context { struct dc *dc; void *driver_context; /* e.g. amdgpu_device */ - - struct dal_logger *logger; void *cgs_device; enum dce_environment dce_environment; diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c index 3edaa006bd576..1c902e49a7124 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c @@ -794,43 +794,38 @@ static bool dce110_validate_bandwidth( if (memcmp(&dc->current_state->bw.dce, &context->bw.dce, sizeof(context->bw.dce))) { - struct log_entry log_entry; - dm_logger_open( - dc->ctx->logger, - &log_entry, - LOG_BANDWIDTH_CALCS); - dm_logger_append(&log_entry, "%s: finish,\n" + + DC_LOG_BANDWIDTH_CALCS( + "%s: finish,\n" + "nbpMark_b: %d nbpMark_a: %d urgentMark_b: %d urgentMark_a: %d\n" + "stutMark_b: %d stutMark_a: %d\n" "nbpMark_b: %d nbpMark_a: %d urgentMark_b: %d urgentMark_a: %d\n" - "stutMark_b: %d stutMark_a: %d\n", + "stutMark_b: %d stutMark_a: %d\n" + "nbpMark_b: %d nbpMark_a: %d urgentMark_b: %d urgentMark_a: %d\n" + "stutMark_b: %d stutMark_a: %d stutter_mode_enable: %d\n" + "cstate: %d pstate: %d nbpstate: %d sync: %d dispclk: %d\n" + "sclk: %d sclk_sleep: %d yclk: %d blackout_recovery_time_us: %d\n" + , __func__, context->bw.dce.nbp_state_change_wm_ns[0].b_mark, context->bw.dce.nbp_state_change_wm_ns[0].a_mark, context->bw.dce.urgent_wm_ns[0].b_mark, context->bw.dce.urgent_wm_ns[0].a_mark, context->bw.dce.stutter_exit_wm_ns[0].b_mark, - context->bw.dce.stutter_exit_wm_ns[0].a_mark); - dm_logger_append(&log_entry, - "nbpMark_b: %d nbpMark_a: %d urgentMark_b: %d urgentMark_a: %d\n" - "stutMark_b: %d stutMark_a: %d\n", + context->bw.dce.stutter_exit_wm_ns[0].a_mark, context->bw.dce.nbp_state_change_wm_ns[1].b_mark, context->bw.dce.nbp_state_change_wm_ns[1].a_mark, context->bw.dce.urgent_wm_ns[1].b_mark, context->bw.dce.urgent_wm_ns[1].a_mark, context->bw.dce.stutter_exit_wm_ns[1].b_mark, - context->bw.dce.stutter_exit_wm_ns[1].a_mark); - dm_logger_append(&log_entry, - "nbpMark_b: %d nbpMark_a: %d urgentMark_b: %d urgentMark_a: %d\n" - "stutMark_b: %d stutMark_a: %d stutter_mode_enable: %d\n", + context->bw.dce.stutter_exit_wm_ns[1].a_mark, context->bw.dce.nbp_state_change_wm_ns[2].b_mark, context->bw.dce.nbp_state_change_wm_ns[2].a_mark, context->bw.dce.urgent_wm_ns[2].b_mark, context->bw.dce.urgent_wm_ns[2].a_mark, context->bw.dce.stutter_exit_wm_ns[2].b_mark, context->bw.dce.stutter_exit_wm_ns[2].a_mark, - context->bw.dce.stutter_mode_enable); - dm_logger_append(&log_entry, - "cstate: %d pstate: %d nbpstate: %d sync: %d dispclk: %d\n" - "sclk: %d sclk_sleep: %d yclk: %d blackout_recovery_time_us: %d\n", + context->bw.dce.stutter_mode_enable, context->bw.dce.cpuc_state_change_enable, context->bw.dce.cpup_state_change_enable, context->bw.dce.nbp_state_change_enable, @@ -840,7 +835,6 @@ static bool dce110_validate_bandwidth( context->bw.dce.sclk_deep_sleep_khz, context->bw.dce.yclk_khz, context->bw.dce.blackout_recovery_time_us); - dm_logger_close(&log_entry); } return result; } diff --git a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c index 9e1afb11e6ad0..30d5b32892d69 100644 --- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c @@ -744,43 +744,38 @@ bool dce112_validate_bandwidth( if (memcmp(&dc->current_state->bw.dce, &context->bw.dce, sizeof(context->bw.dce))) { - struct log_entry log_entry; - dm_logger_open( - dc->ctx->logger, - &log_entry, - LOG_BANDWIDTH_CALCS); - dm_logger_append(&log_entry, "%s: finish,\n" + + DC_LOG_BANDWIDTH_CALCS( + "%s: finish,\n" + "nbpMark_b: %d nbpMark_a: %d urgentMark_b: %d urgentMark_a: %d\n" + "stutMark_b: %d stutMark_a: %d\n" "nbpMark_b: %d nbpMark_a: %d urgentMark_b: %d urgentMark_a: %d\n" - "stutMark_b: %d stutMark_a: %d\n", + "stutMark_b: %d stutMark_a: %d\n" + "nbpMark_b: %d nbpMark_a: %d urgentMark_b: %d urgentMark_a: %d\n" + "stutMark_b: %d stutMark_a: %d stutter_mode_enable: %d\n" + "cstate: %d pstate: %d nbpstate: %d sync: %d dispclk: %d\n" + "sclk: %d sclk_sleep: %d yclk: %d blackout_recovery_time_us: %d\n" + , __func__, context->bw.dce.nbp_state_change_wm_ns[0].b_mark, context->bw.dce.nbp_state_change_wm_ns[0].a_mark, context->bw.dce.urgent_wm_ns[0].b_mark, context->bw.dce.urgent_wm_ns[0].a_mark, context->bw.dce.stutter_exit_wm_ns[0].b_mark, - context->bw.dce.stutter_exit_wm_ns[0].a_mark); - dm_logger_append(&log_entry, - "nbpMark_b: %d nbpMark_a: %d urgentMark_b: %d urgentMark_a: %d\n" - "stutMark_b: %d stutMark_a: %d\n", + context->bw.dce.stutter_exit_wm_ns[0].a_mark, context->bw.dce.nbp_state_change_wm_ns[1].b_mark, context->bw.dce.nbp_state_change_wm_ns[1].a_mark, context->bw.dce.urgent_wm_ns[1].b_mark, context->bw.dce.urgent_wm_ns[1].a_mark, context->bw.dce.stutter_exit_wm_ns[1].b_mark, - context->bw.dce.stutter_exit_wm_ns[1].a_mark); - dm_logger_append(&log_entry, - "nbpMark_b: %d nbpMark_a: %d urgentMark_b: %d urgentMark_a: %d\n" - "stutMark_b: %d stutMark_a: %d stutter_mode_enable: %d\n", + context->bw.dce.stutter_exit_wm_ns[1].a_mark, context->bw.dce.nbp_state_change_wm_ns[2].b_mark, context->bw.dce.nbp_state_change_wm_ns[2].a_mark, context->bw.dce.urgent_wm_ns[2].b_mark, context->bw.dce.urgent_wm_ns[2].a_mark, context->bw.dce.stutter_exit_wm_ns[2].b_mark, context->bw.dce.stutter_exit_wm_ns[2].a_mark, - context->bw.dce.stutter_mode_enable); - dm_logger_append(&log_entry, - "cstate: %d pstate: %d nbpstate: %d sync: %d dispclk: %d\n" - "sclk: %d sclk_sleep: %d yclk: %d blackout_recovery_time_us: %d\n", + context->bw.dce.stutter_mode_enable, context->bw.dce.cpuc_state_change_enable, context->bw.dce.cpup_state_change_enable, context->bw.dce.nbp_state_change_enable, @@ -790,7 +785,6 @@ bool dce112_validate_bandwidth( context->bw.dce.sclk_deep_sleep_khz, context->bw.dce.yclk_khz, context->bw.dce.blackout_recovery_time_us); - dm_logger_close(&log_entry); } return result; } diff --git a/drivers/gpu/drm/amd/display/include/logger_interface.h b/drivers/gpu/drm/amd/display/include/logger_interface.h index 0f10ed710e0d0..e3c79616682dc 100644 --- a/drivers/gpu/drm/amd/display/include/logger_interface.h +++ b/drivers/gpu/drm/amd/display/include/logger_interface.h @@ -40,49 +40,7 @@ struct dc_state; * */ -struct dal_logger *dal_logger_create(struct dc_context *ctx, uint32_t log_mask); - -uint32_t dal_logger_destroy(struct dal_logger **logger); - -void dm_logger_flush_buffer(struct dal_logger *logger, bool should_warn); - -void dm_logger_write( - struct dal_logger *logger, - enum dc_log_type log_type, - const char *msg, - ...); - -void dm_logger_append( - struct log_entry *entry, - const char *msg, - ...); - -void dm_logger_append_va( - struct log_entry *entry, - const char *msg, - va_list args); - -void dm_logger_append_heading(struct log_entry *entry); - -void dm_logger_open( - struct dal_logger *logger, - struct log_entry *entry, - enum dc_log_type log_type); - -void dm_logger_close(struct log_entry *entry); - -void dc_conn_log(struct dc_context *ctx, - const struct dc_link *link, - uint8_t *hex_data, - int hex_data_count, - enum dc_log_type event, - const char *msg, - ...); - -void logger_write(struct dal_logger *logger, - enum dc_log_type log_type, - const char *msg, - void *paralist); +void dc_conn_log_hex_linux(const uint8_t *hex_data, int hex_data_count); void pre_surface_trace( struct dc *dc, @@ -108,28 +66,31 @@ void context_clock_trace( * marked by this macro. * Note that the message will be printed exactly once for every function * it is used in order to avoid repeating of the same message. */ + #define DAL_LOGGER_NOT_IMPL(fmt, ...) \ -{ \ - static bool print_not_impl = true; \ -\ - if (print_not_impl == true) { \ - print_not_impl = false; \ - dm_logger_write(ctx->logger, LOG_WARNING, \ - "DAL_NOT_IMPL: " fmt, ##__VA_ARGS__); \ - } \ -} + do { \ + static bool print_not_impl = true; \ + if (print_not_impl == true) { \ + print_not_impl = false; \ + DRM_WARN("DAL_NOT_IMPL: " fmt, ##__VA_ARGS__); \ + } \ + } while (0) /****************************************************************************** * Convenience macros to save on typing. *****************************************************************************/ #define DC_ERROR(...) \ - dm_logger_write(dc_ctx->logger, LOG_ERROR, \ - __VA_ARGS__) + do { \ + (void)(dc_ctx); \ + DC_LOG_ERROR(__VA_ARGS__); \ + } while (0) #define DC_SYNC_INFO(...) \ - dm_logger_write(dc_ctx->logger, LOG_SYNC, \ - __VA_ARGS__) + do { \ + (void)(dc_ctx); \ + DC_LOG_SYNC(__VA_ARGS__); \ + } while (0) /* Connectivity log format: * [time stamp] [drm] [Major_minor] [connector name] message..... @@ -139,20 +100,30 @@ void context_clock_trace( */ #define CONN_DATA_DETECT(link, hex_data, hex_len, ...) \ - dc_conn_log(link->ctx, link, hex_data, hex_len, \ - LOG_EVENT_DETECTION, ##__VA_ARGS__) + do { \ + (void)(link); \ + dc_conn_log_hex_linux(hex_data, hex_len); \ + DC_LOG_EVENT_DETECTION(__VA_ARGS__); \ + } while (0) #define CONN_DATA_LINK_LOSS(link, hex_data, hex_len, ...) \ - dc_conn_log(link->ctx, link, hex_data, hex_len, \ - LOG_EVENT_LINK_LOSS, ##__VA_ARGS__) + do { \ + (void)(link); \ + dc_conn_log_hex_linux(hex_data, hex_len); \ + DC_LOG_EVENT_LINK_LOSS(__VA_ARGS__); \ + } while (0) #define CONN_MSG_LT(link, ...) \ - dc_conn_log(link->ctx, link, NULL, 0, \ - LOG_EVENT_LINK_TRAINING, ##__VA_ARGS__) + do { \ + (void)(link); \ + DC_LOG_EVENT_LINK_TRAINING(__VA_ARGS__); \ + } while (0) #define CONN_MSG_MODE(link, ...) \ - dc_conn_log(link->ctx, link, NULL, 0, \ - LOG_EVENT_MODE_SET, ##__VA_ARGS__) + do { \ + (void)(link); \ + DC_LOG_EVENT_MODE_SET(__VA_ARGS__); \ + } while (0) /* * Display Test Next logging @@ -167,38 +138,21 @@ void context_clock_trace( dm_dtn_log_end(dc_ctx) #define PERFORMANCE_TRACE_START() \ - unsigned long long perf_trc_start_stmp = dm_get_timestamp(dc->ctx); \ - unsigned long long perf_trc_start_log_msk = dc->ctx->logger->mask; \ - unsigned int perf_trc_start_log_flags = dc->ctx->logger->flags.value; \ - if (dc->debug.performance_trace) {\ - dm_logger_flush_buffer(dc->ctx->logger, false);\ - dc->ctx->logger->mask = 1<<LOG_PERF_TRACE;\ - dc->ctx->logger->flags.bits.ENABLE_CONSOLE = 0;\ - dc->ctx->logger->flags.bits.ENABLE_BUFFER = 1;\ - } - -#define PERFORMANCE_TRACE_END() do {\ - unsigned long long perf_trc_end_stmp = dm_get_timestamp(dc->ctx);\ - if (dc->debug.performance_trace) {\ - dm_logger_write(dc->ctx->logger, \ - LOG_PERF_TRACE, \ - "%s duration: %d ticks\n", __func__,\ + unsigned long long perf_trc_start_stmp = dm_get_timestamp(dc->ctx) + +#define PERFORMANCE_TRACE_END() \ + do { \ + unsigned long long perf_trc_end_stmp = dm_get_timestamp(dc->ctx); \ + if (dc->debug.performance_trace) { \ + DC_LOG_PERF_TRACE("%s duration: %lld ticks\n", __func__, \ perf_trc_end_stmp - perf_trc_start_stmp); \ - if (perf_trc_start_log_msk != 1<<LOG_PERF_TRACE) {\ - dc->ctx->logger->mask = perf_trc_start_log_msk;\ - dc->ctx->logger->flags.value = perf_trc_start_log_flags;\ - dm_logger_flush_buffer(dc->ctx->logger, false);\ } \ - } \ -} while (0) + } while (0) -#define DISPLAY_STATS_BEGIN(entry) \ - dm_logger_open(dc->ctx->logger, &entry, LOG_DISPLAYSTATS) +#define DISPLAY_STATS_BEGIN(entry) (void)(entry) -#define DISPLAY_STATS(msg, ...) \ - dm_logger_append(&log_entry, msg, ##__VA_ARGS__) +#define DISPLAY_STATS(msg, ...) DC_LOG_PERF_TRACE(msg, __VA_ARGS__) -#define DISPLAY_STATS_END(entry) \ - dm_logger_close(&entry) +#define DISPLAY_STATS_END(entry) (void)(entry) #endif /* __DAL_LOGGER_INTERFACE_H__ */ diff --git a/drivers/gpu/drm/amd/display/include/logger_types.h b/drivers/gpu/drm/amd/display/include/logger_types.h index 0a540b9897a67..ad3695e67b76f 100644 --- a/drivers/gpu/drm/amd/display/include/logger_types.h +++ b/drivers/gpu/drm/amd/display/include/logger_types.h @@ -138,63 +138,4 @@ enum dc_log_type { (1 << LOG_HW_AUDIO)| \ (1 << LOG_BANDWIDTH_CALCS)*/ -union logger_flags { - struct { - uint32_t ENABLE_CONSOLE:1; /* Print to console */ - uint32_t ENABLE_BUFFER:1; /* Print to buffer */ - uint32_t RESERVED:30; - } bits; - uint32_t value; -}; - -struct log_entry { - struct dal_logger *logger; - enum dc_log_type type; - - char *buf; - uint32_t buf_offset; - uint32_t max_buf_bytes; -}; - -/** -* Structure for enumerating log types -*/ -struct dc_log_type_info { - enum dc_log_type type; - char name[MAX_NAME_LEN]; -}; - -/* Structure for keeping track of offsets, buffer, etc */ - -#define DAL_LOGGER_BUFFER_MAX_SIZE 2048 - -/*Connectivity log needs to output EDID, which needs at lease 256x3 bytes, - * change log line size to 896 to meet the request. - */ -#define LOG_MAX_LINE_SIZE 896 - -struct dal_logger { - - /* How far into the circular buffer has been read by dsat - * Read offset should never cross write offset. Write \0's to - * read data just to be sure? - */ - uint32_t buffer_read_offset; - - /* How far into the circular buffer we have written - * Write offset should never cross read offset - */ - uint32_t buffer_write_offset; - - uint32_t open_count; - - char *log_buffer; /* Pointer to malloc'ed buffer */ - uint32_t log_buffer_size; /* Size of circular buffer */ - - uint32_t mask; /*array of masks for major elements*/ - - union logger_flags flags; - struct dc_context *ctx; -}; - #endif /* __DAL_LOGGER_TYPES_H__ */ -- GitLab From 4b99affbb30027c8414a9d583777ad5c6439ae12 Mon Sep 17 00:00:00 2001 From: Alvin lee <alvin.lee3@amd.com> Date: Tue, 19 Jun 2018 15:40:09 -0400 Subject: [PATCH 1123/1506] drm/amd/display: read DP sink and DP branch hardware and firmware revision from DPCD - define new dpcd address in drm - implement new members in dpcd_caps to store values read from new dpcd address Signed-off-by: Alvin lee <alvin.lee3@amd.com> Reviewed-by: Harry Wentland <Harry.Wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/display/dc/core/dc_link_dp.c | 25 +++++++++++++++++++ drivers/gpu/drm/amd/display/dc/dc.h | 5 ++++ .../gpu/drm/amd/display/include/dpcd_defs.h | 3 +++ 3 files changed, 33 insertions(+) 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 84586b679d73e..6d4642bf395da 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 @@ -2262,6 +2262,11 @@ static void get_active_converter_info( link->dpcd_caps.branch_hw_revision = dp_hw_fw_revision.ieee_hw_rev; + + memmove( + link->dpcd_caps.branch_fw_revision, + dp_hw_fw_revision.ieee_fw_rev, + sizeof(dp_hw_fw_revision.ieee_fw_rev)); } } @@ -2317,6 +2322,7 @@ static bool retrieve_link_cap(struct dc_link *link) enum dc_status status = DC_ERROR_UNEXPECTED; uint32_t read_dpcd_retry_cnt = 3; int i; + struct dp_sink_hw_fw_revision dp_hw_fw_revision; memset(dpcd_data, '\0', sizeof(dpcd_data)); memset(&down_strm_port_count, @@ -2408,6 +2414,25 @@ static bool retrieve_link_cap(struct dc_link *link) (sink_id.ieee_oui[1] << 8) + (sink_id.ieee_oui[2]); + memmove( + link->dpcd_caps.sink_dev_id_str, + sink_id.ieee_device_id, + sizeof(sink_id.ieee_device_id)); + + core_link_read_dpcd( + link, + DP_SINK_HW_REVISION_START, + (uint8_t *)&dp_hw_fw_revision, + sizeof(dp_hw_fw_revision)); + + link->dpcd_caps.sink_hw_revision = + dp_hw_fw_revision.ieee_hw_rev; + + memmove( + link->dpcd_caps.sink_fw_revision, + dp_hw_fw_revision.ieee_fw_rev, + sizeof(dp_hw_fw_revision.ieee_fw_rev)); + /* Connectivity log: detection */ CONN_DATA_DETECT(link, dpcd_data, sizeof(dpcd_data), "Rx Caps: "); diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 85533619440a3..1b36e763f3b08 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -628,9 +628,14 @@ struct dpcd_caps { struct dc_dongle_caps dongle_caps; uint32_t sink_dev_id; + int8_t sink_dev_id_str[6]; + int8_t sink_hw_revision; + int8_t sink_fw_revision[2]; + uint32_t branch_dev_id; int8_t branch_dev_name[6]; int8_t branch_hw_revision; + int8_t branch_fw_revision[2]; bool allow_invalid_MSA_timing_param; bool panel_mode_edp; diff --git a/drivers/gpu/drm/amd/display/include/dpcd_defs.h b/drivers/gpu/drm/amd/display/include/dpcd_defs.h index d8e52e3b8e3c7..1c66166d0a949 100644 --- a/drivers/gpu/drm/amd/display/include/dpcd_defs.h +++ b/drivers/gpu/drm/amd/display/include/dpcd_defs.h @@ -27,6 +27,9 @@ #define __DAL_DPCD_DEFS_H__ #include <drm/drm_dp_helper.h> +#ifndef DP_SINK_HW_REVISION_START // can remove this once the define gets into linux drm_dp_helper.h +#define DP_SINK_HW_REVISION_START 0x409 +#endif enum dpcd_revision { DPCD_REV_10 = 0x10, -- GitLab From 30cdbfaa6aa469347db7fcda5949f1ccf7559ecf Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Date: Wed, 13 Jun 2018 13:58:14 -0400 Subject: [PATCH 1124/1506] drm/amd/display: dcc always on for bw calculations on raven Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Reviewed-by: Charlene Liu <Charlene.Liu@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/display/dc/calcs/dcn_calcs.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c index e44b8d3d68910..080f777d705e7 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c @@ -250,7 +250,24 @@ static void pipe_ctx_to_e2e_pipe_params ( else if (pipe->bottom_pipe != NULL && pipe->bottom_pipe->plane_state == pipe->plane_state) input->src.is_hsplit = true; - input->src.dcc = pipe->plane_state->dcc.enable; + if (pipe->plane_res.dpp->ctx->dc->debug.optimized_watermark) { + /* + * this method requires us to always re-calculate watermark when dcc change + * between flip. + */ + input->src.dcc = pipe->plane_state->dcc.enable ? 1 : 0; + } else { + /* + * allow us to disable dcc on the fly without re-calculating WM + * + * extra overhead for DCC is quite small. for 1080p WM without + * DCC is only 0.417us lower (urgent goes from 6.979us to 6.562us) + */ + unsigned int bpe; + + input->src.dcc = pipe->plane_res.dpp->ctx->dc->res_pool->hubbub->funcs-> + dcc_support_pixel_format(pipe->plane_state->format, &bpe) ? 1 : 0; + } input->src.dcc_rate = 1; input->src.meta_pitch = pipe->plane_state->dcc.grph.meta_pitch; input->src.source_scan = dm_horz; -- GitLab From 0a1d56599b9bb58464a8bf1243191eb32b36b694 Mon Sep 17 00:00:00 2001 From: Hersen Wu <hersenxs.wu@amd.com> Date: Tue, 19 Jun 2018 12:14:29 -0400 Subject: [PATCH 1125/1506] drm/amd/display: hook dp test pattern through debugfs set PHY layer or Link layer test pattern PHY test pattern is used for PHY SI check. Link layer test will not affect PHY SI. - normal video mode 0 = DP_TEST_PATTERN_VIDEO_MODE - PHY test pattern supported 1 = DP_TEST_PATTERN_D102 2 = DP_TEST_PATTERN_SYMBOL_ERROR 3 = DP_TEST_PATTERN_PRBS7 4 = DP_TEST_PATTERN_80BIT_CUSTOM 5 = DP_TEST_PATTERN_CP2520_1 6 = DP_TEST_PATTERN_CP2520_2 = DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE 7 = DP_TEST_PATTERN_CP2520_3 - DP PHY Link Training Patterns 8 = DP_TEST_PATTERN_TRAINING_PATTERN1 9 = DP_TEST_PATTERN_TRAINING_PATTERN2 0xa = DP_TEST_PATTERN_TRAINING_PATTERN3 0xb = DP_TEST_PATTERN_TRAINING_PATTERN4 - DP Link Layer Test pattern 0xc = DP_TEST_PATTERN_COLOR_SQUARES 0xd = DP_TEST_PATTERN_COLOR_SQUARES_CEA 0xe = DP_TEST_PATTERN_VERTICAL_BARS 0xf = DP_TEST_PATTERN_HORIZONTAL_BARS 0x10= DP_TEST_PATTERN_COLOR_RAMP debugfs phy_test_pattern is located at /syskernel/debug/dri/0/DP-x --- set test pattern echo <test pattern #> > test_pattern - custom test pattern If test pattern # is not supported, NO HW programming will be done for DP_TEST_PATTERN_80BIT_CUSTOM, it needs extra 10 bytes of data for the user pattern. input 10 bytes data are separated by space echo 0x4 0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88 0x99 0xaa > test_pattern --- reset test pattern echo 0 > test_pattern --- HPD detection is disabled when set PHY test pattern when PHY test pattern (pattern # within [1,7]) is set, HPD pin of HW ASIC is disable. User could unplug DP display from DP connected and plug scope to check test pattern PHY SI. If there is need unplug scope and plug DP display back, do steps below: echo 0 > phy_test_pattern unplug scope plug DP display. "echo 0 > phy_test_pattern" will re-enable HPD pin again so that video sw driver could detect "unplug scope" and "plug DP display" Signed-off-by: Hersen Wu <hersenxs.wu@amd.com> Reviewed-by: Harry Wentland <Harry.Wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 222 +++++++++++++++++- 1 file changed, 211 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c index 9ff8833b52c48..8ddbf219dd230 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -261,18 +261,219 @@ static ssize_t dp_pre_emphasis_debugfs_write(struct file *f, const char __user * return 1; } -static ssize_t dp_phy_test_pattern_debugfs_read(struct file *f, char __user *buf, - size_t size, loff_t *pos) -{ - /* TODO: create method to read PHY test pattern */ - return 1; -} - +/* function description + * + * set PHY layer or Link layer test pattern + * PHY test pattern is used for PHY SI check. + * Link layer test will not affect PHY SI. + * + * Reset Test Pattern: + * 0 = DP_TEST_PATTERN_VIDEO_MODE + * + * PHY test pattern supported: + * 1 = DP_TEST_PATTERN_D102 + * 2 = DP_TEST_PATTERN_SYMBOL_ERROR + * 3 = DP_TEST_PATTERN_PRBS7 + * 4 = DP_TEST_PATTERN_80BIT_CUSTOM + * 5 = DP_TEST_PATTERN_CP2520_1 + * 6 = DP_TEST_PATTERN_CP2520_2 = DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE + * 7 = DP_TEST_PATTERN_CP2520_3 + * + * DP PHY Link Training Patterns + * 8 = DP_TEST_PATTERN_TRAINING_PATTERN1 + * 9 = DP_TEST_PATTERN_TRAINING_PATTERN2 + * a = DP_TEST_PATTERN_TRAINING_PATTERN3 + * b = DP_TEST_PATTERN_TRAINING_PATTERN4 + * + * DP Link Layer Test pattern + * c = DP_TEST_PATTERN_COLOR_SQUARES + * d = DP_TEST_PATTERN_COLOR_SQUARES_CEA + * e = DP_TEST_PATTERN_VERTICAL_BARS + * f = DP_TEST_PATTERN_HORIZONTAL_BARS + * 10= DP_TEST_PATTERN_COLOR_RAMP + * + * debugfs phy_test_pattern is located at /syskernel/debug/dri/0/DP-x + * + * --- set test pattern + * echo <test pattern #> > test_pattern + * + * If test pattern # is not supported, NO HW programming will be done. + * for DP_TEST_PATTERN_80BIT_CUSTOM, it needs extra 10 bytes of data + * for the user pattern. input 10 bytes data are separated by space + * + * echo 0x4 0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88 0x99 0xaa > test_pattern + * + * --- reset test pattern + * echo 0 > test_pattern + * + * --- HPD detection is disabled when set PHY test pattern + * + * when PHY test pattern (pattern # within [1,7]) is set, HPD pin of HW ASIC + * is disable. User could unplug DP display from DP connected and plug scope to + * check test pattern PHY SI. + * If there is need unplug scope and plug DP display back, do steps below: + * echo 0 > phy_test_pattern + * unplug scope + * plug DP display. + * + * "echo 0 > phy_test_pattern" will re-enable HPD pin again so that video sw + * driver could detect "unplug scope" and "plug DP display" + */ static ssize_t dp_phy_test_pattern_debugfs_write(struct file *f, const char __user *buf, size_t size, loff_t *pos) { - /* TODO: create method to write PHY test pattern */ - return 1; + struct amdgpu_dm_connector *connector = file_inode(f)->i_private; + struct dc_link *link = connector->dc_link; + char *wr_buf = NULL; + char *wr_buf_ptr = NULL; + uint32_t wr_buf_size = 100; + int r; + int bytes_from_user; + char *sub_str; + uint8_t param_index = 0; + long param[11]; + const char delimiter[3] = {' ', '\n', '\0'}; + enum dp_test_pattern test_pattern = DP_TEST_PATTERN_UNSUPPORTED; + bool disable_hpd = false; + bool valid_test_pattern = false; + uint8_t custom_pattern[10] = {0}; + struct dc_link_settings prefer_link_settings = {LANE_COUNT_UNKNOWN, + LINK_RATE_UNKNOWN, LINK_SPREAD_DISABLED}; + struct dc_link_settings cur_link_settings = {LANE_COUNT_UNKNOWN, + LINK_RATE_UNKNOWN, LINK_SPREAD_DISABLED}; + struct link_training_settings link_training_settings; + int i; + + if (size == 0) + return 0; + + wr_buf = kcalloc(wr_buf_size, sizeof(char), GFP_KERNEL); + if (!wr_buf) + return 0; + wr_buf_ptr = wr_buf; + + r = copy_from_user(wr_buf_ptr, buf, wr_buf_size); + + /* r is bytes not be copied */ + if (r >= wr_buf_size) { + kfree(wr_buf); + DRM_DEBUG_DRIVER("user data not be read\n"); + return 0; + } + + bytes_from_user = wr_buf_size - r; + + while (isspace(*wr_buf_ptr)) + wr_buf_ptr++; + + while ((*wr_buf_ptr != '\0') && (param_index < 1)) { + sub_str = strsep(&wr_buf_ptr, delimiter); + r = kstrtol(sub_str, 16, ¶m[param_index]); + + if (r) + DRM_DEBUG_DRIVER("string to int convert error code: %d\n", r); + + param_index++; + while (isspace(*wr_buf_ptr)) + wr_buf_ptr++; + + /* DP_TEST_PATTERN_80BIT_CUSTOM need extra 80 bits + * whci are 10 bytes separte by space + */ + if (param[0] != 0x4) + break; + } + + test_pattern = param[0]; + + switch (test_pattern) { + case DP_TEST_PATTERN_VIDEO_MODE: + case DP_TEST_PATTERN_COLOR_SQUARES: + case DP_TEST_PATTERN_COLOR_SQUARES_CEA: + case DP_TEST_PATTERN_VERTICAL_BARS: + case DP_TEST_PATTERN_HORIZONTAL_BARS: + case DP_TEST_PATTERN_COLOR_RAMP: + valid_test_pattern = true; + break; + + case DP_TEST_PATTERN_D102: + case DP_TEST_PATTERN_SYMBOL_ERROR: + case DP_TEST_PATTERN_PRBS7: + case DP_TEST_PATTERN_80BIT_CUSTOM: + case DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE: + case DP_TEST_PATTERN_TRAINING_PATTERN4: + disable_hpd = true; + valid_test_pattern = true; + break; + + default: + valid_test_pattern = false; + test_pattern = DP_TEST_PATTERN_UNSUPPORTED; + break; + } + + if (!valid_test_pattern) { + kfree(wr_buf); + DRM_DEBUG_DRIVER("Invalid Test Pattern Parameters\n"); + return bytes_from_user; + } + + if (test_pattern == DP_TEST_PATTERN_80BIT_CUSTOM) { + for (i = 0; i < 10; i++) + custom_pattern[i] = (uint8_t) param[i + 1]; + } + + /* Usage: set DP physical test pattern using debugfs with normal DP + * panel. Then plug out DP panel and connect a scope to measure + * For normal video mode and test pattern generated from CRCT, + * they are visibile to user. So do not disable HPD. + * Video Mode is also set to clear the test pattern, so enable HPD + * because it might have been disabled after a test pattern was set. + * AUX depends on HPD * sequence dependent, do not move! + */ + if (!disable_hpd) + dc_link_enable_hpd(link); + + prefer_link_settings.lane_count = link->verified_link_cap.lane_count; + prefer_link_settings.link_rate = link->verified_link_cap.link_rate; + prefer_link_settings.link_spread = link->verified_link_cap.link_spread; + + cur_link_settings.lane_count = link->cur_link_settings.lane_count; + cur_link_settings.link_rate = link->cur_link_settings.link_rate; + cur_link_settings.link_spread = link->cur_link_settings.link_spread; + + link_training_settings.link_settings = cur_link_settings; + + + if (test_pattern != DP_TEST_PATTERN_VIDEO_MODE) { + if (prefer_link_settings.lane_count != LANE_COUNT_UNKNOWN && + prefer_link_settings.link_rate != LINK_RATE_UNKNOWN && + (prefer_link_settings.lane_count != cur_link_settings.lane_count || + prefer_link_settings.link_rate != cur_link_settings.link_rate)) + link_training_settings.link_settings = prefer_link_settings; + } + + for (i = 0; i < (unsigned int)(link_training_settings.link_settings.lane_count); i++) + link_training_settings.lane_settings[i] = link->cur_lane_setting; + + dc_link_set_test_pattern( + link, + test_pattern, + &link_training_settings, + custom_pattern, + 10); + + /* Usage: Set DP physical test pattern using AMDDP with normal DP panel + * Then plug out DP panel and connect a scope to measure DP PHY signal. + * Need disable interrupt to avoid SW driver disable DP output. This is + * done after the test pattern is set. + */ + if (valid_test_pattern && disable_hpd) + dc_link_disable_hpd(link); + + kfree(wr_buf); + + return bytes_from_user; } static const struct file_operations dp_link_settings_debugfs_fops = { @@ -298,7 +499,6 @@ static const struct file_operations dp_pre_emphasis_fops = { static const struct file_operations dp_phy_test_pattern_fops = { .owner = THIS_MODULE, - .read = dp_phy_test_pattern_debugfs_read, .write = dp_phy_test_pattern_debugfs_write, .llseek = default_llseek }; @@ -310,7 +510,7 @@ static const struct { {"link_settings", &dp_link_settings_debugfs_fops}, {"voltage_swing", &dp_voltage_swing_fops}, {"pre_emphasis", &dp_pre_emphasis_fops}, - {"phy_test_pattern", &dp_phy_test_pattern_fops} + {"test_pattern", &dp_phy_test_pattern_fops} }; int connector_debugfs_init(struct amdgpu_dm_connector *connector) -- GitLab From 05541913a97053e58669ea5817fa5000b836f834 Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Date: Wed, 13 Jun 2018 13:52:53 -0400 Subject: [PATCH 1126/1506] drm/amd/display: remove dentist_vco_freq from resource_pool Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Reviewed-by: Charlene Liu <Charlene.Liu@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/inc/core_types.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h index 00d728e629fa6..1db26bc0bec3a 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h @@ -148,7 +148,6 @@ struct resource_pool { unsigned int underlay_pipe_index; unsigned int stream_enc_count; unsigned int ref_clock_inKhz; - unsigned int dentist_vco_freq_khz; unsigned int timing_generator_count; /* -- GitLab From 793d4d087f9ff365031a62b30d6578686ae1765b Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Date: Wed, 20 Jun 2018 11:40:15 -0400 Subject: [PATCH 1127/1506] drm/amd/display: drop unused register defines Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Reviewed-by: Harry Wentland <Harry.Wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h index 7ce0a54e548f4..8a6b2d328467c 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h @@ -44,18 +44,14 @@ CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DPREFCLK_WDIVIDER, mask_sh) #define CLK_COMMON_MASK_SH_LIST_DCN_COMMON_BASE(mask_sh) \ - CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DPPCLK_WDIVIDER, mask_sh),\ CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_WDIVIDER, mask_sh),\ - CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_CHG_DONE, mask_sh),\ - CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DPPCLK_CHG_DONE, mask_sh) + CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_CHG_DONE, mask_sh) #define CLK_REG_FIELD_LIST(type) \ type DPREFCLK_SRC_SEL; \ type DENTIST_DPREFCLK_WDIVIDER; \ type DENTIST_DISPCLK_WDIVIDER; \ - type DENTIST_DPPCLK_WDIVIDER; \ - type DENTIST_DISPCLK_CHG_DONE; \ - type DENTIST_DPPCLK_CHG_DONE; + type DENTIST_DISPCLK_CHG_DONE; struct dccg_shift { CLK_REG_FIELD_LIST(uint8_t) -- GitLab From 39a9f4d89e123b62c8a5cc26696ea8afa98e0e88 Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Date: Tue, 19 Jun 2018 15:49:02 -0400 Subject: [PATCH 1128/1506] drm/amd/display: add additional info for cursor position programming Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Reviewed-by: Charlene Liu <Charlene.Liu@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dc_hw_types.h | 5 +++-- .../gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c | 7 ++++--- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c | 4 ++-- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c | 4 ++-- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c | 7 ++++--- 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h index 00afd07a852ed..5e80bc1a88c43 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h @@ -404,9 +404,10 @@ struct dc_cursor_position { struct dc_cursor_mi_param { unsigned int pixel_clk_khz; unsigned int ref_clk_khz; - unsigned int viewport_x_start; - unsigned int viewport_width; + struct rect viewport; struct fixed31_32 h_scale_ratio; + struct fixed31_32 v_scale_ratio; + enum dc_rotation_angle rotation; }; /* IPP related types */ 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 bf4df34bc1df0..5b41cbe06f597 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 @@ -2801,9 +2801,10 @@ void dce110_set_cursor_position(struct pipe_ctx *pipe_ctx) struct dc_cursor_mi_param param = { .pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_khz, .ref_clk_khz = pipe_ctx->stream->ctx->dc->res_pool->ref_clock_inKhz, - .viewport_x_start = pipe_ctx->plane_res.scl_data.viewport.x, - .viewport_width = pipe_ctx->plane_res.scl_data.viewport.width, - .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz + .viewport = pipe_ctx->plane_res.scl_data.viewport, + .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz, + .v_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.vert, + .rotation = pipe_ctx->plane_state->rotation }; if (pipe_ctx->plane_state->address.type diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c index 742fd497ed006..a558efa9b34a4 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c @@ -445,10 +445,10 @@ void dpp1_set_cursor_position( uint32_t width) { struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); - int src_x_offset = pos->x - pos->x_hotspot - param->viewport_x_start; + int src_x_offset = pos->x - pos->x_hotspot - param->viewport.x; uint32_t cur_en = pos->enable ? 1 : 0; - if (src_x_offset >= (int)param->viewport_width) + if (src_x_offset >= (int)param->viewport.width) cur_en = 0; /* not visible beyond right edge*/ if (src_x_offset + (int)width <= 0) 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 9eb60a013f4c1..617fd30b11613 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c @@ -1083,7 +1083,7 @@ void hubp1_cursor_set_position( const struct dc_cursor_mi_param *param) { struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); - int src_x_offset = pos->x - pos->x_hotspot - param->viewport_x_start; + int src_x_offset = pos->x - pos->x_hotspot - param->viewport.x; uint32_t cur_en = pos->enable ? 1 : 0; uint32_t dst_x_offset = (src_x_offset >= 0) ? src_x_offset : 0; @@ -1107,7 +1107,7 @@ void hubp1_cursor_set_position( dc_fixpt_from_int(dst_x_offset), param->h_scale_ratio)); - if (src_x_offset >= (int)param->viewport_width) + if (src_x_offset >= (int)param->viewport.width) cur_en = 0; /* not visible beyond right edge*/ if (src_x_offset + (int)hubp->curs_attr.width <= 0) 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 3b2cb2d3b8a61..2938364fd2f0d 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 @@ -2520,9 +2520,10 @@ static void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) struct dc_cursor_mi_param param = { .pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_khz, .ref_clk_khz = pipe_ctx->stream->ctx->dc->res_pool->ref_clock_inKhz, - .viewport_x_start = pipe_ctx->plane_res.scl_data.viewport.x, - .viewport_width = pipe_ctx->plane_res.scl_data.viewport.width, - .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz + .viewport = pipe_ctx->plane_res.scl_data.viewport, + .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz, + .v_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.vert, + .rotation = pipe_ctx->plane_state->rotation }; if (pipe_ctx->plane_state->address.type -- GitLab From ff58798725ba9c747cd934e2623f7a0610b3f0dd Mon Sep 17 00:00:00 2001 From: Hugo Hu <hugo.hu@amd.com> Date: Fri, 15 Jun 2018 15:49:55 -0400 Subject: [PATCH 1129/1506] drm/amd/display: Patch for extend time to panel poweron. [WHY] In eDP spec, the min duration in LCDVDD on-off-on sequence should be 500ms, some BOE panels need 700ms to pass. [HOW] Add patch to wait more time when eDP power on. Signed-off-by: Hugo Hu <hugo.hu@amd.com> Reviewed-by: Charlene Liu <Charlene.Liu@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dc_types.h | 1 + .../gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index 03bf9eee9a045..8c6eb78b0c3bd 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -192,6 +192,7 @@ union display_content_support { struct dc_panel_patch { unsigned int dppowerup_delay; + unsigned int extra_t12_ms; }; struct dc_edid_caps { 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 5b41cbe06f597..7227cfddb3521 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 @@ -871,10 +871,13 @@ void hwss_edp_power_control( unsigned long long wait_time_ms = 0; /* max 500ms from LCDVDD off to on */ + unsigned long long edp_poweroff_time_ms = + 500 + link->local_sink->edid_caps.panel_patch.extra_t12_ms; + if (link->link_trace.time_stamp.edp_poweroff == 0) - wait_time_ms = 500; - else if (duration_in_ms < 500) - wait_time_ms = 500 - duration_in_ms; + wait_time_ms = edp_poweroff_time_ms; + else if (duration_in_ms < edp_poweroff_time_ms) + wait_time_ms = edp_poweroff_time_ms - duration_in_ms; if (wait_time_ms) { msleep(wait_time_ms); -- GitLab From f8ac2cf78f276b4d9fc0bc6b90f5e3560caa11de Mon Sep 17 00:00:00 2001 From: Hersen Wu <hersenxs.wu@amd.com> Date: Fri, 15 Jun 2018 10:32:50 -0400 Subject: [PATCH 1130/1506] drm/amd/display: Linux set/read lane settings through debugfs function: get current DP PHY settings: voltage swing, pre-emphasis, post-cursor2 (defined by VESA DP specification) valid values: voltage swing: 0,1,2,3 pre-emphasis : 0,1,2,3 post cursor2 : 0,1,2,3 debugfs file phy_setings is located at /sys/kernel/debug/dri/0/DP-x there will be directories, like DP-1, DP-2,DP-3, etc. for DP display --- to figure out which DP-x is the display for DP to be check, cd DP-x ls -ll There should be debugfs file, like link_settings, phy_settings. cat link_settings from lane_count, link_rate to figure which DP-x is for display to be worked on --- to get current DP PHY settings, cat phy_settings --- to change DP PHY settings, echo <voltage_swing> <pre-emphasis> <post_cursor2> > phy_settings for examle, to change voltage swing to 2, pre-emphasis to 3, post_cursor2 to 0, echo 2 3 0 > phy_settings --- to check if change be applied, get current phy settings by cat phy_settings --- in case invalid values are set by user, like echo 1 4 0 > phy_settings HW will NOT be programmed by these settings. cat phy_settings will show the previous valid settings. Signed-off-by: Hersen Wu <hersenxs.wu@amd.com> Reviewed-by: Harry Wentland <Harry.Wentland@amd.com> Reviewed-by: Hersen Wu <hersenxs.wu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 266 ++++++++++++++---- 1 file changed, 207 insertions(+), 59 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c index 8ddbf219dd230..f20ba9d1c9e25 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -26,7 +26,6 @@ #include <linux/debugfs.h> #include "dc.h" - #include "amdgpu.h" #include "amdgpu_dm.h" #include "amdgpu_dm_debugfs.h" @@ -46,7 +45,7 @@ * * --- to get dp configuration * - * xxd -l 300 phy_settings + * cat link_settings * * It will list current, verified, reported, preferred dp configuration. * current -- for current video mode @@ -56,7 +55,7 @@ * * --- set (or force) dp configuration * - * echo <lane_count> <link_rate> + * echo <lane_count> <link_rate> > link_settings * * for example, to force to 2 lane, 2.7GHz, * echo 4 0xa > link_settings @@ -67,7 +66,7 @@ * done. please check link settings after force operation to see if HW get * programming. * - * xxd -l 300 link_settings + * cat link_settings * * check current and preferred settings. * @@ -79,13 +78,13 @@ static ssize_t dp_link_settings_read(struct file *f, char __user *buf, struct dc_link *link = connector->dc_link; char *rd_buf = NULL; char *rd_buf_ptr = NULL; - uint32_t rd_buf_size = 320; - int bytes_to_user; + const uint32_t rd_buf_size = 100; + uint32_t result = 0; uint8_t str_len = 0; int r; - if (size == 0) - return 0; + if (*pos & 3 || size & 3) + return -EINVAL; rd_buf = kcalloc(rd_buf_size, sizeof(char), GFP_KERNEL); if (!rd_buf) @@ -98,39 +97,44 @@ static ssize_t dp_link_settings_read(struct file *f, char __user *buf, link->cur_link_settings.lane_count, link->cur_link_settings.link_rate, link->cur_link_settings.link_spread); - rd_buf_ptr = rd_buf_ptr + str_len; + rd_buf_ptr += str_len; str_len = strlen("Verified: %d %d %d "); snprintf(rd_buf_ptr, str_len, "Verified: %d %d %d ", link->verified_link_cap.lane_count, link->verified_link_cap.link_rate, link->verified_link_cap.link_spread); - rd_buf_ptr = rd_buf_ptr + str_len; + rd_buf_ptr += str_len; str_len = strlen("Reported: %d %d %d "); snprintf(rd_buf_ptr, str_len, "Reported: %d %d %d ", link->reported_link_cap.lane_count, link->reported_link_cap.link_rate, link->reported_link_cap.link_spread); - rd_buf_ptr = rd_buf_ptr + str_len; + rd_buf_ptr += str_len; str_len = strlen("Preferred: %d %d %d "); - snprintf(rd_buf_ptr, str_len, "Preferred: %d %d %d ", + snprintf(rd_buf_ptr, str_len, "Preferred: %d %d %d\n", link->preferred_link_setting.lane_count, link->preferred_link_setting.link_rate, link->preferred_link_setting.link_spread); - r = copy_to_user(buf, rd_buf, rd_buf_size); + while (size) { + if (*pos >= rd_buf_size) + break; - bytes_to_user = rd_buf_size - r; + r = put_user(*(rd_buf + result), buf); + if (r) + return r; /* r = -EFAULT */ - if (r > rd_buf_size) { - bytes_to_user = 0; - DRM_DEBUG_DRIVER("data not copy to user"); + buf += 1; + size -= 1; + *pos += 1; + result += 1; } kfree(rd_buf); - return bytes_to_user; + return result; } static ssize_t dp_link_settings_write(struct file *f, const char __user *buf, @@ -142,7 +146,7 @@ static ssize_t dp_link_settings_write(struct file *f, const char __user *buf, struct dc_link_settings prefer_link_settings; char *wr_buf = NULL; char *wr_buf_ptr = NULL; - uint32_t wr_buf_size = 40; + const uint32_t wr_buf_size = 40; int r; int bytes_from_user; char *sub_str; @@ -153,11 +157,11 @@ static ssize_t dp_link_settings_write(struct file *f, const char __user *buf, bool valid_input = false; if (size == 0) - return 0; + return -EINVAL; wr_buf = kcalloc(wr_buf_size, sizeof(char), GFP_KERNEL); if (!wr_buf) - return 0; + return -EINVAL; wr_buf_ptr = wr_buf; r = copy_from_user(wr_buf_ptr, buf, wr_buf_size); @@ -166,7 +170,7 @@ static ssize_t dp_link_settings_write(struct file *f, const char __user *buf, if (r >= wr_buf_size) { kfree(wr_buf); DRM_DEBUG_DRIVER("user data not read\n"); - return 0; + return -EINVAL; } bytes_from_user = wr_buf_size - r; @@ -181,16 +185,13 @@ static ssize_t dp_link_settings_write(struct file *f, const char __user *buf, r = kstrtol(sub_str, 16, ¶m[param_index]); if (r) - DRM_DEBUG_DRIVER(" -EINVAL convert error happens!\n"); + DRM_DEBUG_DRIVER("string to int convert error code: %d\n", r); param_index++; while (isspace(*wr_buf_ptr)) wr_buf_ptr++; } - DRM_DEBUG_DRIVER("Lane_count: %lx\n", param[0]); - DRM_DEBUG_DRIVER("link_rate: %lx\n", param[1]); - switch (param[0]) { case LANE_COUNT_ONE: case LANE_COUNT_TWO: @@ -213,9 +214,10 @@ static ssize_t dp_link_settings_write(struct file *f, const char __user *buf, break; } - if (!valid_input) { + if (!valid_input || (param[0] > link->reported_link_cap.lane_count) || + (param[1] > link->reported_link_cap.link_rate)) { kfree(wr_buf); - DRM_DEBUG_DRIVER("Invalid Input value exceed No HW will be programmed\n"); + DRM_DEBUG_DRIVER("Invalid Input value No HW will be programmed\n"); return bytes_from_user; } @@ -229,36 +231,190 @@ static ssize_t dp_link_settings_write(struct file *f, const char __user *buf, dc_link_set_preferred_link_settings(dc, &prefer_link_settings, link); kfree(wr_buf); - return bytes_from_user; } -static ssize_t dp_voltage_swing_debugfs_read(struct file *f, char __user *buf, +/* function: get current DP PHY settings: voltage swing, pre-emphasis, + * post-cursor2 (defined by VESA DP specification) + * + * valid values + * voltage swing: 0,1,2,3 + * pre-emphasis : 0,1,2,3 + * post cursor2 : 0,1,2,3 + * + * + * how to use this debugfs + * + * debugfs is located at /sys/kernel/debug/dri/0/DP-x + * + * there will be directories, like DP-1, DP-2,DP-3, etc. for DP display + * + * To figure out which DP-x is the display for DP to be check, + * cd DP-x + * ls -ll + * There should be debugfs file, like link_settings, phy_settings. + * cat link_settings + * from lane_count, link_rate to figure which DP-x is for display to be worked + * on + * + * To get current DP PHY settings, + * cat phy_settings + * + * To change DP PHY settings, + * echo <voltage_swing> <pre-emphasis> <post_cursor2> > phy_settings + * for examle, to change voltage swing to 2, pre-emphasis to 3, post_cursor2 to + * 0, + * echo 2 3 0 > phy_settings + * + * To check if change be applied, get current phy settings by + * cat phy_settings + * + * In case invalid values are set by user, like + * echo 1 4 0 > phy_settings + * + * HW will NOT be programmed by these settings. + * cat phy_settings will show the previous valid settings. + */ +static ssize_t dp_phy_settings_read(struct file *f, char __user *buf, size_t size, loff_t *pos) { - /* TODO: create method to read voltage swing */ - return 1; -} + struct amdgpu_dm_connector *connector = file_inode(f)->i_private; + struct dc_link *link = connector->dc_link; + char *rd_buf = NULL; + const uint32_t rd_buf_size = 20; + uint32_t result = 0; + int r; -static ssize_t dp_voltage_swing_debugfs_write(struct file *f, const char __user *buf, - size_t size, loff_t *pos) -{ - /* TODO: create method to write voltage swing */ - return 1; -} + if (*pos & 3 || size & 3) + return -EINVAL; -static ssize_t dp_pre_emphasis_debugfs_read(struct file *f, char __user *buf, - size_t size, loff_t *pos) -{ - /* TODO: create method to read pre-emphasis */ - return 1; + rd_buf = kcalloc(rd_buf_size, sizeof(char), GFP_KERNEL); + if (!rd_buf) + return -EINVAL; + + snprintf(rd_buf, rd_buf_size, " %d %d %d ", + link->cur_lane_setting.VOLTAGE_SWING, + link->cur_lane_setting.PRE_EMPHASIS, + link->cur_lane_setting.POST_CURSOR2); + + while (size) { + if (*pos >= rd_buf_size) + break; + + r = put_user((*(rd_buf + result)), buf); + if (r) + return r; /* r = -EFAULT */ + + buf += 1; + size -= 1; + *pos += 1; + result += 1; + } + + kfree(rd_buf); + return result; } -static ssize_t dp_pre_emphasis_debugfs_write(struct file *f, const char __user *buf, +static ssize_t dp_phy_settings_write(struct file *f, const char __user *buf, size_t size, loff_t *pos) { - /* TODO: create method to write pre-emphasis */ - return 1; + struct amdgpu_dm_connector *connector = file_inode(f)->i_private; + struct dc_link *link = connector->dc_link; + struct dc *dc = (struct dc *)link->dc; + char *wr_buf = NULL; + char *wr_buf_ptr = NULL; + uint32_t wr_buf_size = 40; + int r; + int bytes_from_user; + char *sub_str; + uint8_t param_index = 0; + long param[3]; + const char delimiter[3] = {' ', '\n', '\0'}; + bool use_prefer_link_setting; + struct link_training_settings link_lane_settings; + + if (size == 0) + return 0; + + wr_buf = kcalloc(wr_buf_size, sizeof(char), GFP_KERNEL); + if (!wr_buf) + return 0; + wr_buf_ptr = wr_buf; + + r = copy_from_user(wr_buf_ptr, buf, wr_buf_size); + + /* r is bytes not be copied */ + if (r >= wr_buf_size) { + kfree(wr_buf); + DRM_DEBUG_DRIVER("user data not be read\n"); + return 0; + } + + bytes_from_user = wr_buf_size - r; + + while (isspace(*wr_buf_ptr)) + wr_buf_ptr++; + + while ((*wr_buf_ptr != '\0') && (param_index < 3)) { + + sub_str = strsep(&wr_buf_ptr, delimiter); + + r = kstrtol(sub_str, 16, ¶m[param_index]); + + if (r) + DRM_DEBUG_DRIVER("string to int convert error code: %d\n", r); + + param_index++; + while (isspace(*wr_buf_ptr)) + wr_buf_ptr++; + } + + if ((param[0] > VOLTAGE_SWING_MAX_LEVEL) || + (param[1] > PRE_EMPHASIS_MAX_LEVEL) || + (param[2] > POST_CURSOR2_MAX_LEVEL)) { + kfree(wr_buf); + DRM_DEBUG_DRIVER("Invalid Input No HW will be programmed\n"); + return bytes_from_user; + } + + /* get link settings: lane count, link rate */ + use_prefer_link_setting = + ((link->preferred_link_setting.link_rate != LINK_RATE_UNKNOWN) && + (link->test_pattern_enabled)); + + memset(&link_lane_settings, 0, sizeof(link_lane_settings)); + + if (use_prefer_link_setting) { + link_lane_settings.link_settings.lane_count = + link->preferred_link_setting.lane_count; + link_lane_settings.link_settings.link_rate = + link->preferred_link_setting.link_rate; + link_lane_settings.link_settings.link_spread = + link->preferred_link_setting.link_spread; + } else { + link_lane_settings.link_settings.lane_count = + link->cur_link_settings.lane_count; + link_lane_settings.link_settings.link_rate = + link->cur_link_settings.link_rate; + link_lane_settings.link_settings.link_spread = + link->cur_link_settings.link_spread; + } + + /* apply phy settings from user */ + for (r = 0; r < link_lane_settings.link_settings.lane_count; r++) { + link_lane_settings.lane_settings[r].VOLTAGE_SWING = + (enum dc_voltage_swing) (param[0]); + link_lane_settings.lane_settings[r].PRE_EMPHASIS = + (enum dc_pre_emphasis) (param[1]); + link_lane_settings.lane_settings[r].POST_CURSOR2 = + (enum dc_post_cursor2) (param[2]); + } + + /* program ASIC registers and DPCD registers */ + dc_link_set_drive_settings(dc, &link_lane_settings, link); + + kfree(wr_buf); + return bytes_from_user; } /* function description @@ -483,17 +639,10 @@ static const struct file_operations dp_link_settings_debugfs_fops = { .llseek = default_llseek }; -static const struct file_operations dp_voltage_swing_fops = { - .owner = THIS_MODULE, - .read = dp_voltage_swing_debugfs_read, - .write = dp_voltage_swing_debugfs_write, - .llseek = default_llseek -}; - -static const struct file_operations dp_pre_emphasis_fops = { +static const struct file_operations dp_phy_settings_debugfs_fop = { .owner = THIS_MODULE, - .read = dp_pre_emphasis_debugfs_read, - .write = dp_pre_emphasis_debugfs_write, + .read = dp_phy_settings_read, + .write = dp_phy_settings_write, .llseek = default_llseek }; @@ -508,8 +657,7 @@ static const struct { const struct file_operations *fops; } dp_debugfs_entries[] = { {"link_settings", &dp_link_settings_debugfs_fops}, - {"voltage_swing", &dp_voltage_swing_fops}, - {"pre_emphasis", &dp_pre_emphasis_fops}, + {"phy_settings", &dp_phy_settings_debugfs_fop}, {"test_pattern", &dp_phy_test_pattern_fops} }; -- GitLab From 1a2eaed80a0bd19f69da880d87f037f5829fb664 Mon Sep 17 00:00:00 2001 From: "Leo (Sunpeng) Li" <sunpeng.li@amd.com> Date: Mon, 18 Jun 2018 12:23:03 -0400 Subject: [PATCH 1131/1506] drm/amd/display: Fix compile error on older GCC versions GCC 4.9 reports a 'missing braces around initializer' error. This is a bug, documented here: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119 Fix it by adding another brace. Signed-off-by: Leo (Sunpeng) Li <sunpeng.li@amd.com> Reviewed-by: Mikita Lipski <Mikita.Lipski@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c index 7b51b8fde3fe3..59b113d11f66f 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c @@ -514,8 +514,8 @@ enum dc_edid_status dm_helpers_read_local_edid( edid_status, aconnector->base.name); if (link->aux_mode) { - union test_request test_request = {0}; - union test_response test_response = {0}; + union test_request test_request = { {0} }; + union test_response test_response = { {0} }; dm_helpers_dp_read_dpcd(ctx, link, -- GitLab From abfa99f4d2f1d1a0018f8f39fc1958eda6a48dde Mon Sep 17 00:00:00 2001 From: Charlene Liu <charlene.liu@amd.com> Date: Thu, 21 Jun 2018 17:57:51 -0400 Subject: [PATCH 1132/1506] drm/amd/display: add missing mask for dcn Signed-off-by: Charlene Liu <charlene.liu@amd.com> Reviewed-by: Wesley Chalmers <Wesley.Chalmers@amd.com> Reviewed-by: Duke Du <Duke.Du@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h index df3203a1d2783..64dc753785415 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h @@ -364,7 +364,8 @@ struct dce_hwseq_registers { HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, OTG0_),\ HWS_SF1(OTG0_, PHYPLL_PIXEL_RATE_CNTL, PHYPLL_PIXEL_RATE_SOURCE, mask_sh), \ HWS_SF(, DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, mask_sh), \ - HWS_SF(, DCFCLK_CNTL, DCFCLK_GATE_DIS, mask_sh) + HWS_SF(, DCFCLK_CNTL, DCFCLK_GATE_DIS, mask_sh), \ + HWS_SF(, DC_MEM_GLOBAL_PWR_REQ_CNTL, DC_MEM_GLOBAL_PWR_REQ_DIS, mask_sh) #define HWSEQ_DCN1_MASK_SH_LIST(mask_sh)\ HWSEQ_DCN_MASK_SH_LIST(mask_sh), \ -- GitLab From 613cb725dc6cb6039b37d2b71c90a70d49780ce5 Mon Sep 17 00:00:00 2001 From: Charlene Liu <charlene.liu@amd.com> Date: Thu, 21 Jun 2018 21:32:36 -0400 Subject: [PATCH 1133/1506] drm/amd/display: set default GPIO_ID_HPD Signed-off-by: Charlene Liu <charlene.liu@amd.com> Reviewed-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c index ab5483c0c502c..f20161c5706d7 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c @@ -375,6 +375,7 @@ struct gpio *dal_gpio_create_irq( case GPIO_ID_GPIO_PAD: break; default: + id = GPIO_ID_HPD; ASSERT_CRITICAL(false); return NULL; } -- GitLab From 08ed681c8453c2934136bcc3b30bca4dee8a5fca Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Date: Thu, 21 Jun 2018 13:33:41 -0400 Subject: [PATCH 1134/1506] drm/amd/display: add dcn cursor hotsport rotation and mirror support Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dc_hw_types.h | 1 + .../display/dc/dce110/dce110_hw_sequencer.c | 3 ++- .../gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c | 20 ++++++++++++++++--- .../amd/display/dc/dcn10/dcn10_hw_sequencer.c | 3 ++- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h index 5e80bc1a88c43..da787e2793190 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h @@ -408,6 +408,7 @@ struct dc_cursor_mi_param { struct fixed31_32 h_scale_ratio; struct fixed31_32 v_scale_ratio; enum dc_rotation_angle rotation; + bool mirror; }; /* IPP related types */ 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 7227cfddb3521..109d4103d10d6 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 @@ -2807,7 +2807,8 @@ void dce110_set_cursor_position(struct pipe_ctx *pipe_ctx) .viewport = pipe_ctx->plane_res.scl_data.viewport, .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz, .v_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.vert, - .rotation = pipe_ctx->plane_state->rotation + .rotation = pipe_ctx->plane_state->rotation, + .mirror = pipe_ctx->plane_state->horizontal_mirror }; if (pipe_ctx->plane_state->address.type 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 617fd30b11613..5c4ad8a67e62a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c @@ -1084,8 +1084,10 @@ void hubp1_cursor_set_position( { struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); int src_x_offset = pos->x - pos->x_hotspot - param->viewport.x; + int x_hotspot = pos->x_hotspot; + int y_hotspot = pos->y_hotspot; + uint32_t dst_x_offset; uint32_t cur_en = pos->enable ? 1 : 0; - uint32_t dst_x_offset = (src_x_offset >= 0) ? src_x_offset : 0; /* * Guard aganst cursor_set_position() from being called with invalid @@ -1097,6 +1099,18 @@ void hubp1_cursor_set_position( if (hubp->curs_attr.address.quad_part == 0) return; + if (param->rotation == ROTATION_ANGLE_90 || param->rotation == ROTATION_ANGLE_270) { + src_x_offset = pos->y - pos->y_hotspot - param->viewport.x; + y_hotspot = pos->x_hotspot; + x_hotspot = pos->y_hotspot; + } + + if (param->mirror) { + x_hotspot = param->viewport.width - x_hotspot; + src_x_offset = param->viewport.x + param->viewport.width - src_x_offset; + } + + dst_x_offset = (src_x_offset >= 0) ? src_x_offset : 0; dst_x_offset *= param->ref_clk_khz; dst_x_offset /= param->pixel_clk_khz; @@ -1124,8 +1138,8 @@ void hubp1_cursor_set_position( CURSOR_Y_POSITION, pos->y); REG_SET_2(CURSOR_HOT_SPOT, 0, - CURSOR_HOT_SPOT_X, pos->x_hotspot, - CURSOR_HOT_SPOT_Y, pos->y_hotspot); + CURSOR_HOT_SPOT_X, x_hotspot, + CURSOR_HOT_SPOT_Y, y_hotspot); REG_SET(CURSOR_DST_OFFSET, 0, CURSOR_DST_X_OFFSET, dst_x_offset); 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 2938364fd2f0d..944275a50c0a6 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 @@ -2523,7 +2523,8 @@ static void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) .viewport = pipe_ctx->plane_res.scl_data.viewport, .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz, .v_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.vert, - .rotation = pipe_ctx->plane_state->rotation + .rotation = pipe_ctx->plane_state->rotation, + .mirror = pipe_ctx->plane_state->horizontal_mirror }; if (pipe_ctx->plane_state->address.type -- GitLab From ac99243c8db70c9b5497a9c75c53f6bfd19b572a Mon Sep 17 00:00:00 2001 From: Yongqiang Sun <yongqiang.sun@amd.com> Date: Mon, 25 Jun 2018 00:18:54 +0800 Subject: [PATCH 1135/1506] drm/amd/display: expose dcn10_aux_initialize in header Signed-off-by: Yongqiang Sun <yongqiang.sun@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c | 10 ++-------- .../gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h | 2 ++ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c index 18a7cac4f6e31..be78ccb439e95 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c @@ -65,11 +65,6 @@ enum { DP_MST_UPDATE_MAX_RETRY = 50 }; - - -static void aux_initialize(struct dcn10_link_encoder *enc10); - - static const struct link_encoder_funcs dcn10_lnk_enc_funcs = { .validate_output_with_stream = dcn10_link_encoder_validate_output_with_stream, @@ -811,7 +806,7 @@ void dcn10_link_encoder_hw_init( ASSERT(result == BP_RESULT_OK); } - aux_initialize(enc10); + dcn10_aux_initialize(enc10); /* reinitialize HPD. * hpd_initialize() will pass DIG_FE id to HW context. @@ -1348,8 +1343,7 @@ void dcn10_link_encoder_disable_hpd(struct link_encoder *enc) FN(reg, f1), v1,\ FN(reg, f2), v2) -static void aux_initialize( - struct dcn10_link_encoder *enc10) +void dcn10_aux_initialize(struct dcn10_link_encoder *enc10) { enum hpd_source_id hpd_source = enc10->base.hpd_source; diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h index cd3bb5d40579c..49ead12b25329 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h @@ -336,4 +336,6 @@ void dcn10_psr_program_secondary_packet(struct link_encoder *enc, bool dcn10_is_dig_enabled(struct link_encoder *enc); +void dcn10_aux_initialize(struct dcn10_link_encoder *enc10); + #endif /* __DC_LINK_ENCODER__DCN10_H__ */ -- GitLab From 53a599de5560b95bf76bc12d17b93406c33e9f75 Mon Sep 17 00:00:00 2001 From: Hersen Wu <hersenxs.wu@amd.com> Date: Fri, 22 Jun 2018 13:06:01 -0400 Subject: [PATCH 1136/1506] drm/amd/display: Linux hook test pattern through debufs bug fix: phy test PLTAT is special 80bit test pattern. The 80bit data should be hard coded within driver so that user does not need input the deata. previous driver does not have hard coded 80 bits pattern data for PLTPAT. Other than this PLTPAT, user has to input 80 bits pattern data. In case user input less than 10 bytes data, un-input data byte will be filled by 0x00. Signed-off-by: Hersen Wu <hersenxs.wu@amd.com> Reviewed-by: Harry Wentland <Harry.Wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 70 +++++++++++++++---- 1 file changed, 55 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c index f20ba9d1c9e25..0276e09d0b82e 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -483,16 +483,22 @@ static ssize_t dp_phy_test_pattern_debugfs_write(struct file *f, const char __us char *wr_buf = NULL; char *wr_buf_ptr = NULL; uint32_t wr_buf_size = 100; + uint32_t wr_buf_count = 0; int r; int bytes_from_user; - char *sub_str; + char *sub_str = NULL; uint8_t param_index = 0; - long param[11]; + uint8_t param_nums = 0; + long param[11] = {0x0}; const char delimiter[3] = {' ', '\n', '\0'}; enum dp_test_pattern test_pattern = DP_TEST_PATTERN_UNSUPPORTED; bool disable_hpd = false; bool valid_test_pattern = false; - uint8_t custom_pattern[10] = {0}; + /* init with defalut 80bit custom pattern */ + uint8_t custom_pattern[10] = { + 0x1f, 0x7c, 0xf0, 0xc1, 0x07, + 0x1f, 0x7c, 0xf0, 0xc1, 0x07 + }; struct dc_link_settings prefer_link_settings = {LANE_COUNT_UNKNOWN, LINK_RATE_UNKNOWN, LINK_SPREAD_DISABLED}; struct dc_link_settings cur_link_settings = {LANE_COUNT_UNKNOWN, @@ -519,25 +525,51 @@ static ssize_t dp_phy_test_pattern_debugfs_write(struct file *f, const char __us bytes_from_user = wr_buf_size - r; - while (isspace(*wr_buf_ptr)) + /* check number of parameters. isspace could not differ space and \n */ + while ((*wr_buf_ptr != 0xa) && (wr_buf_count < wr_buf_size)) { + /* skip space*/ + while (isspace(*wr_buf_ptr) && (wr_buf_count < wr_buf_size)) { + wr_buf_ptr++; + wr_buf_count++; + } + + if (wr_buf_count == wr_buf_size) + break; + + /* skip non-space*/ + while ((!isspace(*wr_buf_ptr)) && (wr_buf_count < wr_buf_size)) { + wr_buf_ptr++; + wr_buf_count++; + } + + param_nums++; + + if (wr_buf_count == wr_buf_size) + break; + } + + /* max 11 parameters */ + if (param_nums > 11) + param_nums = 11; + + wr_buf_ptr = wr_buf; /* reset buf pinter */ + wr_buf_count = 0; /* number of char already checked */ + + while (isspace(*wr_buf_ptr) && (wr_buf_count < wr_buf_size)) { wr_buf_ptr++; + wr_buf_count++; + } - while ((*wr_buf_ptr != '\0') && (param_index < 1)) { + while (param_index < param_nums) { + /* after strsep, wr_buf_ptr will be moved to after space */ sub_str = strsep(&wr_buf_ptr, delimiter); + r = kstrtol(sub_str, 16, ¶m[param_index]); if (r) DRM_DEBUG_DRIVER("string to int convert error code: %d\n", r); param_index++; - while (isspace(*wr_buf_ptr)) - wr_buf_ptr++; - - /* DP_TEST_PATTERN_80BIT_CUSTOM need extra 80 bits - * whci are 10 bytes separte by space - */ - if (param[0] != 0x4) - break; } test_pattern = param[0]; @@ -575,8 +607,16 @@ static ssize_t dp_phy_test_pattern_debugfs_write(struct file *f, const char __us } if (test_pattern == DP_TEST_PATTERN_80BIT_CUSTOM) { - for (i = 0; i < 10; i++) - custom_pattern[i] = (uint8_t) param[i + 1]; + for (i = 0; i < 10; i++) { + if ((uint8_t) param[i + 1] != 0x0) + break; + } + + if (i < 10) { + /* not use default value */ + for (i = 0; i < 10; i++) + custom_pattern[i] = (uint8_t) param[i + 1]; + } } /* Usage: set DP physical test pattern using debugfs with normal DP -- GitLab From 76fbdc63daaa216bdbd294e4d7ac6a35e1470126 Mon Sep 17 00:00:00 2001 From: Tony Cheng <tony.cheng@amd.com> Date: Tue, 5 Jun 2018 09:15:15 -0400 Subject: [PATCH 1137/1506] drm/amd/display: dal 3.1.54 Signed-off-by: Tony Cheng <tony.cheng@amd.com> Reviewed-by: Aric Cyr <Aric.Cyr@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 1b36e763f3b08..6074680ecee1a 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.1.53" +#define DC_VER "3.1.54" #define MAX_SURFACES 3 #define MAX_STREAMS 6 -- GitLab From e7baae1cfb7fd1a31fa8c968403cbc761cf999ff Mon Sep 17 00:00:00 2001 From: "Jerry (Fangzhi) Zuo" <Jerry.Zuo@amd.com> Date: Fri, 22 Jun 2018 17:12:47 -0400 Subject: [PATCH 1138/1506] drm/amd/display: Add YCbCr420 only support for HDMI 4K@60 [Why] Some monitors mark 4K@60 capable HDMI port only have 300MHz TMDS maximum, but the edid includes 4K@60 mode in cea extension block. [How] To enable 4K@60, need to limit BW by allowing YCbCr420 ONLY mode. Add YCbCr420 only support for monitors that do not fully support HDMI2.0, e.g., ASUS PA328. The YCbCr420 only support applies to DCN, DCE112 or higher. Signed-off-by: Jerry (Fangzhi) Zuo <Jerry.Zuo@amd.com> Reviewed-by: Charlene Liu <Charlene.Liu@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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 d2cc32add5f76..88854982171c0 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -3509,7 +3509,6 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm, aconnector->base.stereo_allowed = false; aconnector->base.dpms = DRM_MODE_DPMS_OFF; aconnector->hpd.hpd = AMDGPU_HPD_NONE; /* not used */ - mutex_init(&aconnector->hpd_lock); /* configure support HPD hot plug connector_>polled default value is 0 @@ -3518,9 +3517,13 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm, switch (connector_type) { case DRM_MODE_CONNECTOR_HDMIA: aconnector->base.polled = DRM_CONNECTOR_POLL_HPD; + aconnector->base.ycbcr_420_allowed = + link->link_enc->features.ycbcr420_supported ? true : false; break; case DRM_MODE_CONNECTOR_DisplayPort: aconnector->base.polled = DRM_CONNECTOR_POLL_HPD; + aconnector->base.ycbcr_420_allowed = + link->link_enc->features.ycbcr420_supported ? true : false; break; case DRM_MODE_CONNECTOR_DVID: aconnector->base.polled = DRM_CONNECTOR_POLL_HPD; -- GitLab From c2437b1f16d9b136c88b2c7c0254919a0e1311f6 Mon Sep 17 00:00:00 2001 From: Eric Bernstein <eric.bernstein@amd.com> Date: Wed, 16 May 2018 16:19:50 -0400 Subject: [PATCH 1139/1506] drm/amd/display: Expose bunch of functions from dcn10_hw_sequencer v2: Remove spurious newline changes Signed-off-by: Eric Bernstein <eric.bernstein@amd.com> Reviewed-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../amd/display/dc/dcn10/dcn10_hw_sequencer.c | 59 +++++++++++-------- .../amd/display/dc/dcn10/dcn10_hw_sequencer.h | 7 +++ .../gpu/drm/amd/display/dc/inc/hw_sequencer.h | 8 +++ 3 files changed, 49 insertions(+), 25 deletions(-) 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 944275a50c0a6..a9942fd5f34e6 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 @@ -834,7 +834,7 @@ static bool dcn10_hw_wa_force_recovery(struct dc *dc) } -static void dcn10_verify_allow_pstate_change_high(struct dc *dc) +void dcn10_verify_allow_pstate_change_high(struct dc *dc) { static bool should_log_hw_state; /* prevent hw state log by default */ @@ -1848,8 +1848,7 @@ static void update_dpp(struct dpp *dpp, struct dc_plane_state *plane_state) dpp->funcs->dpp_program_bias_and_scale(dpp, &bns_params); } - -static void update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) +static void dcn10_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) { struct hubp *hubp = pipe_ctx->plane_res.hubp; struct mpcc_blnd_cfg blnd_cfg; @@ -1994,7 +1993,7 @@ static void update_dchubp_dpp( if (plane_state->update_flags.bits.full_update || plane_state->update_flags.bits.per_pixel_alpha_change) - update_mpcc(dc, pipe_ctx); + dc->hwss.update_mpcc(dc, pipe_ctx); if (plane_state->update_flags.bits.full_update || plane_state->update_flags.bits.per_pixel_alpha_change || @@ -2104,6 +2103,33 @@ static void set_hdr_multiplier(struct pipe_ctx *pipe_ctx) pipe_ctx->plane_res.dpp, hw_mult); } +void dcn10_program_pipe( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + struct dc_state *context) +{ + if (pipe_ctx->plane_state->update_flags.bits.full_update) + dcn10_enable_plane(dc, pipe_ctx, context); + + update_dchubp_dpp(dc, pipe_ctx, context); + + set_hdr_multiplier(pipe_ctx); + + if (pipe_ctx->plane_state->update_flags.bits.full_update || + pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change || + pipe_ctx->plane_state->update_flags.bits.gamma_change) + dc->hwss.set_input_transfer_func(pipe_ctx, pipe_ctx->plane_state); + + /* dcn10_translate_regamma_to_hw_format takes 750us to finish + * only do gamma programming for full update. + * TODO: This can be further optimized/cleaned up + * Always call this for now since it does memcmp inside before + * doing heavy calculation and programming + */ + if (pipe_ctx->plane_state->update_flags.bits.full_update) + dc->hwss.set_output_transfer_func(pipe_ctx, pipe_ctx->stream); +} + static void program_all_pipe_in_tree( struct dc *dc, struct pipe_ctx *pipe_ctx, @@ -2125,26 +2151,7 @@ static void program_all_pipe_in_tree( } if (pipe_ctx->plane_state != NULL) { - if (pipe_ctx->plane_state->update_flags.bits.full_update) - dcn10_enable_plane(dc, pipe_ctx, context); - - update_dchubp_dpp(dc, pipe_ctx, context); - - set_hdr_multiplier(pipe_ctx); - - if (pipe_ctx->plane_state->update_flags.bits.full_update || - pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change || - pipe_ctx->plane_state->update_flags.bits.gamma_change) - dc->hwss.set_input_transfer_func(pipe_ctx, pipe_ctx->plane_state); - - /* dcn10_translate_regamma_to_hw_format takes 750us to finish - * only do gamma programming for full update. - * TODO: This can be further optimized/cleaned up - * Always call this for now since it does memcmp inside before - * doing heavy calculation and programming - */ - if (pipe_ctx->plane_state->update_flags.bits.full_update) - dc->hwss.set_output_transfer_func(pipe_ctx, pipe_ctx->stream); + dcn10_program_pipe(dc, pipe_ctx, context); } if (pipe_ctx->bottom_pipe != NULL && pipe_ctx->bottom_pipe != pipe_ctx) { @@ -2269,7 +2276,7 @@ static void dcn10_apply_ctx_for_surface( old_pipe_ctx->plane_state && old_pipe_ctx->stream_res.tg == tg) { - hwss1_plane_atomic_disconnect(dc, old_pipe_ctx); + dc->hwss.plane_atomic_disconnect(dc, old_pipe_ctx); removed_pipe[i] = true; DC_LOG_DC("Reset mpcc for pipe %d\n", @@ -2555,7 +2562,9 @@ static const struct hw_sequencer_funcs dcn10_funcs = { .apply_ctx_to_hw = dce110_apply_ctx_to_hw, .apply_ctx_for_surface = dcn10_apply_ctx_for_surface, .update_plane_addr = dcn10_update_plane_addr, + .plane_atomic_disconnect = hwss1_plane_atomic_disconnect, .update_dchub = dcn10_update_dchub, + .update_mpcc = dcn10_update_mpcc, .update_pending_status = dcn10_update_pending_status, .set_input_transfer_func = dcn10_set_input_transfer_func, .set_output_transfer_func = dcn10_set_output_transfer_func, 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 44f734b73f9ea..7139fb73e966e 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 @@ -39,4 +39,11 @@ bool is_rgb_cspace(enum dc_color_space output_color_space); void hwss1_plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx); +void dcn10_verify_allow_pstate_change_high(struct dc *dc); + +void dcn10_program_pipe( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + struct dc_state *context); + #endif /* __DC_HWSS_DCN10_H__ */ 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 2506601120afa..c2277d1e195b4 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h @@ -102,10 +102,18 @@ struct hw_sequencer_funcs { const struct dc *dc, struct pipe_ctx *pipe_ctx); + void (*plane_atomic_disconnect)( + struct dc *dc, + struct pipe_ctx *pipe_ctx); + void (*update_dchub)( struct dce_hwseq *hws, struct dchub_init_data *dh_data); + void (*update_mpcc)( + struct dc *dc, + struct pipe_ctx *pipe_ctx); + void (*update_pending_status)( struct pipe_ctx *pipe_ctx); -- GitLab From 3092108904461dd50b1502f3a2977a4259d91044 Mon Sep 17 00:00:00 2001 From: "Leo (Sunpeng) Li" <sunpeng.li@amd.com> Date: Tue, 26 Jun 2018 10:44:05 -0400 Subject: [PATCH 1140/1506] drm/amd/display: Right shift AUX reply value sooner than later [Why] There is no point in keeping the AUX reply value in the raw format as returned from reading the AUX_SW_DATA register. [How] Shift it within read_channel_reply(), where the register is read, before returning it. Signed-off-by: Leo (Sunpeng) Li <sunpeng.li@amd.com> Reviewed-by: Harry Wentland <Harry.Wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.c b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.c index 1f3940644a5b0..ae5caa97cacaf 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.c +++ b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.c @@ -300,9 +300,10 @@ static int read_channel_reply(struct aux_engine *engine, uint32_t size, AUX_SW_DATA_RW, 1); REG_GET(AUX_SW_DATA, AUX_SW_DATA, &reply_result_32); + reply_result_32 = reply_result_32 >> 4; *reply_result = (uint8_t)reply_result_32; - if (reply_result_32 >> 4 == 0) { /* ACK */ + if (reply_result_32 == 0) { /* ACK */ uint32_t i = 0; /* First byte was already used to get the command status */ @@ -356,7 +357,6 @@ static void process_channel_reply( return; } } else { - reply_result = reply_result >> 4; switch (reply_result) { case 0: /* ACK */ -- GitLab From edf6ffe4f47e6749cfd45c1489feea2dbb0041c7 Mon Sep 17 00:00:00 2001 From: "Leo (Sunpeng) Li" <sunpeng.li@amd.com> Date: Tue, 26 Jun 2018 10:50:16 -0400 Subject: [PATCH 1141/1506] drm/amd/display: Read AUX channel even if only status byte is returned [Why] get_channel_status() can return 0 in returned_bytes, and report a successful operation result. This is because it prunes the first status byte out. This was preventing read_channel_reply() from being called (due to the faulty condition), and consequently preventing the AUX reply status from being set. [How] Fix the conditional so that it accounts for when get_channel_status() returns 0 bytes read. [Fixes] Fixes possible edid read failures during S3 resume, where we are now relying on DRM's DP AUX handling. This was an regression introduced by: Author: Harry Wentland <harry.wentland@amd.com> drm/amd/display: Return aux replies directly to DRM Signed-off-by: Leo (Sunpeng) Li <sunpeng.li@amd.com> Reviewed-by: Harry Wentland <Harry.Wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c index d108ccfc5cf9f..08c9d73b9ab72 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c @@ -671,7 +671,7 @@ int dc_link_aux_transfer(struct ddc_service *ddc, case AUX_CHANNEL_OPERATION_SUCCEEDED: res = returned_bytes; - if (res <= size && res > 0) + if (res <= size && res >= 0) res = engine->funcs->read_channel_reply(engine, size, buffer, reply, &status); -- GitLab From e0d85b20c74fc078862262da64b36e8e7b6663e7 Mon Sep 17 00:00:00 2001 From: Charlene Liu <charlene.liu@amd.com> Date: Mon, 25 Jun 2018 19:28:54 -0400 Subject: [PATCH 1142/1506] drm/amd/display: introduce concept of send_reset_length for i2c engines Signed-off-by: Charlene Liu <charlene.liu@amd.com> Reviewed-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dc.h | 1 + .../dc/i2caux/dce110/i2c_hw_engine_dce110.c | 26 +++++++++++-------- .../dc/i2caux/dce110/i2c_hw_engine_dce110.h | 8 ++++++ .../display/dc/i2caux/dce110/i2caux_dce110.c | 18 ++++++++++++- .../drm/amd/display/dc/i2caux/i2c_engine.h | 2 ++ 5 files changed, 43 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 6074680ecee1a..ede3489b4f37d 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -250,6 +250,7 @@ struct dc_debug { bool p010_mpo_support; bool recovery_enabled; bool avoid_vbios_exec_table; + bool scl_reset_length10; }; struct dc_state; diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_hw_engine_dce110.c b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_hw_engine_dce110.c index b7256f595052b..9cbe1a7a6bcb2 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_hw_engine_dce110.c +++ b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_hw_engine_dce110.c @@ -62,12 +62,7 @@ enum dc_i2c_arbitration { DC_I2C_ARBITRATION__DC_I2C_SW_PRIORITY_HIGH }; -enum { - /* No timeout in HW - * (timeout implemented in SW by querying status) */ - I2C_SETUP_TIME_LIMIT = 255, - I2C_HW_BUFFER_SIZE = 538 -}; + /* * @brief @@ -152,6 +147,11 @@ static bool setup_engine( struct i2c_engine *i2c_engine) { struct i2c_hw_engine_dce110 *hw_engine = FROM_I2C_ENGINE(i2c_engine); + uint32_t i2c_setup_limit = I2C_SETUP_TIME_LIMIT_DCE; + uint32_t reset_length = 0; + + if (hw_engine->base.base.setup_limit != 0) + i2c_setup_limit = hw_engine->base.base.setup_limit; /* Program pin select */ REG_UPDATE_6( @@ -164,11 +164,15 @@ static bool setup_engine( DC_I2C_DDC_SELECT, hw_engine->engine_id); /* Program time limit */ - REG_UPDATE_N( - SETUP, 2, - FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_TIME_LIMIT), I2C_SETUP_TIME_LIMIT, - FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_ENABLE), 1); - + if (hw_engine->base.base.send_reset_length == 0) { + /*pre-dcn*/ + REG_UPDATE_N( + SETUP, 2, + FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_TIME_LIMIT), i2c_setup_limit, + FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_ENABLE), 1); + } else { + reset_length = hw_engine->base.base.send_reset_length; + } /* Program HW priority * set to High - interrupt software I2C at any time * Enable restart of SW I2C that was interrupted by HW diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_hw_engine_dce110.h b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_hw_engine_dce110.h index 5bb04085f6706..fea2946906ed6 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_hw_engine_dce110.h +++ b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_hw_engine_dce110.h @@ -192,6 +192,7 @@ struct i2c_hw_engine_dce110 { /* number of pending transactions (before GO) */ uint32_t transaction_count; uint32_t engine_keep_power_up_count; + uint32_t i2_setup_time_limit; }; struct i2c_hw_engine_dce110_create_arg { @@ -207,4 +208,11 @@ struct i2c_hw_engine_dce110_create_arg { struct i2c_engine *dal_i2c_hw_engine_dce110_create( const struct i2c_hw_engine_dce110_create_arg *arg); +enum { + I2C_SETUP_TIME_LIMIT_DCE = 255, + I2C_SETUP_TIME_LIMIT_DCN = 3, + I2C_HW_BUFFER_SIZE = 538, + I2C_SEND_RESET_LENGTH_9 = 9, + I2C_SEND_RESET_LENGTH_10 = 10, +}; #endif diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2caux_dce110.c b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2caux_dce110.c index e0557d3538188..1d748ac1d6d65 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2caux_dce110.c +++ b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2caux_dce110.c @@ -43,6 +43,9 @@ #include "i2c_sw_engine_dce110.h" #include "i2c_hw_engine_dce110.h" #include "aux_engine_dce110.h" +#include "../../dc.h" +#include "dc_types.h" + /* * Post-requisites: headers required by this unit @@ -250,7 +253,20 @@ void dal_i2caux_dce110_construct( base->i2c_hw_engines[line_id] = dal_i2c_hw_engine_dce110_create(&hw_arg_dce110); - + if (base->i2c_hw_engines[line_id] != NULL) { + switch (ctx->dce_version) { + case DCN_VERSION_1_0: + base->i2c_hw_engines[line_id]->setup_limit = + I2C_SETUP_TIME_LIMIT_DCN; + base->i2c_hw_engines[line_id]->send_reset_length = 0; + break; + default: + base->i2c_hw_engines[line_id]->setup_limit = + I2C_SETUP_TIME_LIMIT_DCE; + base->i2c_hw_engines[line_id]->send_reset_length = 0; + break; + } + } ++i; } while (i < num_i2caux_inst); diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/i2c_engine.h b/drivers/gpu/drm/amd/display/dc/i2caux/i2c_engine.h index 58fc0f25ecebb..ded6ea34b714c 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/i2c_engine.h +++ b/drivers/gpu/drm/amd/display/dc/i2caux/i2c_engine.h @@ -86,6 +86,8 @@ struct i2c_engine { struct engine base; const struct i2c_engine_funcs *funcs; uint32_t timeout_delay; + uint32_t setup_limit; + uint32_t send_reset_length; }; void dal_i2c_engine_construct( -- GitLab From 8fc0a0d4a0a49ed148db2e484539516ad67b6321 Mon Sep 17 00:00:00 2001 From: Charlene Liu <charlene.liu@amd.com> Date: Tue, 26 Jun 2018 18:49:32 -0400 Subject: [PATCH 1143/1506] drm/amd/display: add DalEnableHDMI20 key support [why] "DalEnableHDMI20" set to 0, disallow HDMI YCbCr420 and pixel clock > 340Mhz Default is enabled. Signed-off-by: Charlene Liu <charlene.liu@amd.com> Reviewed-by: Jun Lei <Jun.Lei@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dc.h | 1 + drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c | 6 ++++++ drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c | 6 ++++++ 3 files changed, 13 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index ede3489b4f37d..721c5cdff38fe 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -251,6 +251,7 @@ struct dc_debug { bool recovery_enabled; bool avoid_vbios_exec_table; bool scl_reset_length10; + bool hdmi20_disable; }; struct dc_state; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c index dbe3b26b6d9eb..60e3c6a73d370 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c @@ -646,6 +646,9 @@ static bool dce110_link_encoder_validate_hdmi_output( if (!enc110->base.features.flags.bits.HDMI_6GB_EN && adjusted_pix_clk_khz >= 300000) return false; + if (enc110->base.ctx->dc->debug.hdmi20_disable && + crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) + return false; return true; } @@ -773,6 +776,9 @@ void dce110_link_encoder_construct( __func__, result); } + if (enc110->base.ctx->dc->debug.hdmi20_disable) { + enc110->base.features.flags.bits.HDMI_6GB_EN = 0; + } } bool dce110_link_encoder_validate_output_with_stream( diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c index be78ccb439e95..6f675206a136a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c @@ -596,6 +596,9 @@ static bool dcn10_link_encoder_validate_hdmi_output( if (!enc10->base.features.flags.bits.HDMI_6GB_EN && adjusted_pix_clk_khz >= 300000) return false; + if (enc10->base.ctx->dc->debug.hdmi20_disable && + crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) + return false; return true; } @@ -728,6 +731,9 @@ void dcn10_link_encoder_construct( __func__, result); } + if (enc10->base.ctx->dc->debug.hdmi20_disable) { + enc10->base.features.flags.bits.HDMI_6GB_EN = 0; + } } bool dcn10_link_encoder_validate_output_with_stream( -- GitLab From c2c09ed5cd1b7423b2d2bf372e4c62394264324d Mon Sep 17 00:00:00 2001 From: Mikita Lipski <mikita.lipski@amd.com> Date: Tue, 26 Jun 2018 09:52:29 -0400 Subject: [PATCH 1144/1506] drm/amd/display: add pp to dc powerlevel enum translator [why] Add a switch statement to translate pp's powerlevel enum to dc powerlevel statement enum [how] Add a translator function Signed-off-by: Mikita Lipski <mikita.lipski@amd.com> Reviewed-by: Sun peng Li <Sunpeng.Li@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c index 50e863024f585..c69ae78d82b24 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c @@ -192,6 +192,33 @@ static enum amd_pp_clock_type dc_to_pp_clock_type( return amd_pp_clk_type; } +static enum dm_pp_clocks_state pp_to_dc_powerlevel_state( + enum PP_DAL_POWERLEVEL max_clocks_state) +{ + switch (max_clocks_state) { + case PP_DAL_POWERLEVEL_0: + return DM_PP_CLOCKS_DPM_STATE_LEVEL_0; + case PP_DAL_POWERLEVEL_1: + return DM_PP_CLOCKS_DPM_STATE_LEVEL_1; + case PP_DAL_POWERLEVEL_2: + return DM_PP_CLOCKS_DPM_STATE_LEVEL_2; + case PP_DAL_POWERLEVEL_3: + return DM_PP_CLOCKS_DPM_STATE_LEVEL_3; + case PP_DAL_POWERLEVEL_4: + return DM_PP_CLOCKS_DPM_STATE_LEVEL_4; + case PP_DAL_POWERLEVEL_5: + return DM_PP_CLOCKS_DPM_STATE_LEVEL_5; + case PP_DAL_POWERLEVEL_6: + return DM_PP_CLOCKS_DPM_STATE_LEVEL_6; + case PP_DAL_POWERLEVEL_7: + return DM_PP_CLOCKS_DPM_STATE_LEVEL_7; + default: + DRM_ERROR("DM_PPLIB: invalid powerlevel state: %d!\n", + max_clocks_state); + return DM_PP_CLOCKS_STATE_INVALID; + } +} + static void pp_to_dc_clock_levels( const struct amd_pp_clocks *pp_clks, struct dm_pp_clock_levels *dc_clks, @@ -441,7 +468,7 @@ bool dm_pp_get_static_clocks( if (ret) return false; - static_clk_info->max_clocks_state = pp_clk_info.max_clocks_state; + static_clk_info->max_clocks_state = pp_to_dc_powerlevel_state(pp_clk_info.max_clocks_state); static_clk_info->max_mclk_khz = pp_clk_info.max_memory_clock; static_clk_info->max_sclk_khz = pp_clk_info.max_engine_clock; -- GitLab From 6c4fff068f7940993b3ec74a9996f4b514089d1a Mon Sep 17 00:00:00 2001 From: Yue Hin Lau <Yuehin.Lau@amd.com> Date: Wed, 27 Jun 2018 13:49:20 -0400 Subject: [PATCH 1145/1506] drm/amd/display: Add NULL check for local sink in edp_power_control [WHY] PNP cause bsod regression fix [HOW] Add NULL check Signed-off-by: Yue Hin Lau <Yuehin.Lau@amd.com> Reviewed-by: Hugo Hu <Hugo.Hu@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 109d4103d10d6..e48eb3056af5e 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 @@ -871,9 +871,11 @@ void hwss_edp_power_control( unsigned long long wait_time_ms = 0; /* max 500ms from LCDVDD off to on */ - unsigned long long edp_poweroff_time_ms = - 500 + link->local_sink->edid_caps.panel_patch.extra_t12_ms; + unsigned long long edp_poweroff_time_ms = 500; + if (link->local_sink != NULL) + edp_poweroff_time_ms = + 500 + link->local_sink->edid_caps.panel_patch.extra_t12_ms; if (link->link_trace.time_stamp.edp_poweroff == 0) wait_time_ms = edp_poweroff_time_ms; else if (duration_in_ms < edp_poweroff_time_ms) -- GitLab From 4e18814eeec946fa864723423c9a607815ede5cb Mon Sep 17 00:00:00 2001 From: Fatemeh Darbehani <fatemeh.darbehani@amd.com> Date: Tue, 26 Jun 2018 16:40:55 -0400 Subject: [PATCH 1146/1506] drm/amd/display: Return out_link_loss from interrupt handler Signed-off-by: Fatemeh Darbehani <fatemeh.darbehani@amd.com> Reviewed-by: Aric Cyr <Aric.Cyr@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 +- drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c | 8 +++++++- drivers/gpu/drm/amd/display/dc/dc_link.h | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) 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 88854982171c0..e0cf54ccc9f46 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -1041,7 +1041,7 @@ static void handle_hpd_rx_irq(void *param) if (dc_link->type != dc_connection_mst_branch) mutex_lock(&aconnector->hpd_lock); - if (dc_link_handle_hpd_rx_irq(dc_link, NULL) && + if (dc_link_handle_hpd_rx_irq(dc_link, NULL, NULL) && !is_mst_root_connector) { /* Downstream Port status changed. */ if (dc_link_detect(dc_link, DETECT_REASON_HPDRX)) { 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 6d4642bf395da..54e3964523457 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 @@ -1996,12 +1996,16 @@ static void handle_automated_test(struct dc_link *link) sizeof(test_response)); } -bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd_irq_dpcd_data) +bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd_irq_dpcd_data, bool *out_link_loss) { union hpd_irq_data hpd_irq_dpcd_data = {{{{0}}}}; union device_service_irq device_service_clear = { { 0 } }; enum dc_status result; + bool status = false; + + if (out_link_loss) + *out_link_loss = false; /* For use cases related to down stream connection status change, * PSR and device auto test, refer to function handle_sst_hpd_irq * in DAL2.1*/ @@ -2076,6 +2080,8 @@ bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd true, LINK_TRAINING_ATTEMPTS); status = false; + if (out_link_loss) + *out_link_loss = true; } if (link->type == dc_connection_active_dongle && diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h index eda4a5d3ff1c7..070a56926308a 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_link.h +++ b/drivers/gpu/drm/amd/display/dc/dc_link.h @@ -172,7 +172,7 @@ bool dc_link_detect(struct dc_link *dc_link, enum dc_detect_reason reason); * false - no change in Downstream port status. No further action required * from DM. */ bool dc_link_handle_hpd_rx_irq(struct dc_link *dc_link, - union hpd_irq_data *hpd_irq_dpcd_data); + union hpd_irq_data *hpd_irq_dpcd_data, bool *out_link_loss); struct dc_sink_init_data; -- GitLab From 99a100ae327c2d9c89740bd556cc128f666ba71b Mon Sep 17 00:00:00 2001 From: David Francis <David.Francis@amd.com> Date: Tue, 26 Jun 2018 14:58:15 -0400 Subject: [PATCH 1147/1506] drm/amd/display: Add CRC support for DCN [Why] Regamma/CTM tests require CRC support [How] The CRC registers that were used in DCE exist under different names in DCN. The code was copied from DCE (in dc/dce110/dce110_timing_generator.c) into DCN, and changed to use the DCN register access helper functions. Signed-off-by: David Francis <David.Francis@amd.com> Reviewed-by: Charlene Liu <Charlene.Liu@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/display/dc/dcn10/dcn10_optc.c | 68 +++++++++++++++++++ .../gpu/drm/amd/display/dc/dcn10/dcn10_optc.h | 49 ++++++++++++- 2 files changed, 114 insertions(+), 3 deletions(-) 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 e6a3ade154b92..411f89218e019 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c @@ -1324,6 +1324,72 @@ bool optc1_is_optc_underflow_occurred(struct timing_generator *optc) return (underflow_occurred == 1); } +bool optc1_configure_crc(struct timing_generator *optc, + const struct crc_params *params) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + /* Cannot configure crc on a CRTC that is disabled */ + if (!optc1_is_tg_enabled(optc)) + return false; + + REG_WRITE(OTG_CRC_CNTL, 0); + + if (!params->enable) + return true; + + /* Program frame boundaries */ + /* Window A x axis start and end. */ + REG_UPDATE_2(OTG_CRC0_WINDOWA_X_CONTROL, + OTG_CRC0_WINDOWA_X_START, params->windowa_x_start, + OTG_CRC0_WINDOWA_X_END, params->windowa_x_end); + + /* Window A y axis start and end. */ + REG_UPDATE_2(OTG_CRC0_WINDOWA_Y_CONTROL, + OTG_CRC0_WINDOWA_Y_START, params->windowa_y_start, + OTG_CRC0_WINDOWA_Y_END, params->windowa_y_end); + + /* Window B x axis start and end. */ + REG_UPDATE_2(OTG_CRC0_WINDOWB_X_CONTROL, + OTG_CRC0_WINDOWB_X_START, params->windowb_x_start, + OTG_CRC0_WINDOWB_X_END, params->windowb_x_end); + + /* Window B y axis start and end. */ + REG_UPDATE_2(OTG_CRC0_WINDOWB_Y_CONTROL, + OTG_CRC0_WINDOWB_Y_START, params->windowb_y_start, + OTG_CRC0_WINDOWB_Y_END, params->windowb_y_end); + + /* Set crc mode and selection, and enable. Only using CRC0*/ + REG_UPDATE_3(OTG_CRC_CNTL, + OTG_CRC_CONT_EN, params->continuous_mode ? 1 : 0, + OTG_CRC0_SELECT, params->selection, + OTG_CRC_EN, 1); + + return true; +} + +bool optc1_get_crc(struct timing_generator *optc, + uint32_t *r_cr, uint32_t *g_y, uint32_t *b_cb) +{ + uint32_t field = 0; + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_GET(OTG_CRC_CNTL, OTG_CRC_EN, &field); + + /* Early return if CRC is not enabled for this CRTC */ + if (!field) + return false; + + REG_GET_2(OTG_CRC0_DATA_RG, + CRC0_R_CR, r_cr, + CRC0_G_Y, g_y); + + REG_GET(OTG_CRC0_DATA_B, + CRC0_B_CB, b_cb); + + return true; +} + static const struct timing_generator_funcs dcn10_tg_funcs = { .validate_timing = optc1_validate_timing, .program_timing = optc1_program_timing, @@ -1360,6 +1426,8 @@ static const struct timing_generator_funcs dcn10_tg_funcs = { .is_tg_enabled = optc1_is_tg_enabled, .is_optc_underflow_occurred = optc1_is_optc_underflow_occurred, .clear_optc_underflow = optc1_clear_optc_underflow, + .get_crc = optc1_get_crc, + .configure_crc = optc1_configure_crc, }; void dcn10_timing_generator_init(struct optc *optc1) 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 59ed272e0c493..1df510f57377d 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h @@ -75,7 +75,14 @@ SRI(CONTROL, VTG, inst),\ SRI(OTG_VERT_SYNC_CONTROL, OTG, inst),\ SRI(OTG_MASTER_UPDATE_MODE, OTG, inst),\ - SRI(OTG_GSL_CONTROL, OTG, inst) + SRI(OTG_GSL_CONTROL, OTG, inst),\ + SRI(OTG_CRC_CNTL, OTG, inst),\ + SRI(OTG_CRC0_DATA_RG, OTG, inst),\ + SRI(OTG_CRC0_DATA_B, OTG, inst),\ + SRI(OTG_CRC0_WINDOWA_X_CONTROL, OTG, inst),\ + SRI(OTG_CRC0_WINDOWA_Y_CONTROL, OTG, inst),\ + SRI(OTG_CRC0_WINDOWB_X_CONTROL, OTG, inst),\ + SRI(OTG_CRC0_WINDOWB_Y_CONTROL, OTG, inst) #define TG_COMMON_REG_LIST_DCN1_0(inst) \ TG_COMMON_REG_LIST_DCN(inst),\ @@ -138,6 +145,13 @@ struct dcn_optc_registers { uint32_t OTG_GSL_WINDOW_X; uint32_t OTG_GSL_WINDOW_Y; uint32_t OTG_VUPDATE_KEEPOUT; + uint32_t OTG_CRC_CNTL; + uint32_t OTG_CRC0_DATA_RG; + uint32_t OTG_CRC0_DATA_B; + uint32_t OTG_CRC0_WINDOWA_X_CONTROL; + uint32_t OTG_CRC0_WINDOWA_Y_CONTROL; + uint32_t OTG_CRC0_WINDOWB_X_CONTROL; + uint32_t OTG_CRC0_WINDOWB_Y_CONTROL; }; #define TG_COMMON_MASK_SH_LIST_DCN(mask_sh)\ @@ -232,7 +246,21 @@ struct dcn_optc_registers { SF(OTG0_OTG_GSL_CONTROL, OTG_GSL2_EN, mask_sh),\ SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_MASTER_EN, mask_sh),\ SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_FORCE_DELAY, mask_sh),\ - SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_CHECK_ALL_FIELDS, mask_sh) + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_CHECK_ALL_FIELDS, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL, OTG_CRC_CONT_EN, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL, OTG_CRC0_SELECT, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL, OTG_CRC_EN, mask_sh),\ + SF(OTG0_OTG_CRC0_DATA_RG, CRC0_R_CR, mask_sh),\ + SF(OTG0_OTG_CRC0_DATA_RG, CRC0_G_Y, mask_sh),\ + SF(OTG0_OTG_CRC0_DATA_B, CRC0_B_CB, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWA_X_CONTROL, OTG_CRC0_WINDOWA_X_START, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWA_X_CONTROL, OTG_CRC0_WINDOWA_X_END, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWA_Y_CONTROL, OTG_CRC0_WINDOWA_Y_START, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWA_Y_CONTROL, OTG_CRC0_WINDOWA_Y_END, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWB_X_CONTROL, OTG_CRC0_WINDOWB_X_START, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWB_X_CONTROL, OTG_CRC0_WINDOWB_X_END, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWB_Y_CONTROL, OTG_CRC0_WINDOWB_Y_START, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWB_Y_CONTROL, OTG_CRC0_WINDOWB_Y_END, mask_sh) #define TG_COMMON_MASK_SH_LIST_DCN1_0(mask_sh)\ @@ -363,7 +391,22 @@ struct dcn_optc_registers { type OTG_MASTER_UPDATE_LOCK_GSL_EN;\ type MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_START_OFFSET;\ type MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_END_OFFSET;\ - type OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN; + type OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN;\ + type OTG_CRC_CONT_EN;\ + type OTG_CRC0_SELECT;\ + type OTG_CRC_EN;\ + type CRC0_R_CR;\ + type CRC0_G_Y;\ + type CRC0_B_CB;\ + type OTG_CRC0_WINDOWA_X_START;\ + type OTG_CRC0_WINDOWA_X_END;\ + type OTG_CRC0_WINDOWA_Y_START;\ + type OTG_CRC0_WINDOWA_Y_END;\ + type OTG_CRC0_WINDOWB_X_START;\ + type OTG_CRC0_WINDOWB_X_END;\ + type OTG_CRC0_WINDOWB_Y_START;\ + type OTG_CRC0_WINDOWB_Y_END; + #define TG_REG_FIELD_LIST(type) \ TG_REG_FIELD_LIST_DCN1_0(type) -- GitLab From aca3e9a49b200d56e4dd0a21bbb443e96a482fd9 Mon Sep 17 00:00:00 2001 From: David Francis <David.Francis@amd.com> Date: Wed, 27 Jun 2018 15:55:57 -0400 Subject: [PATCH 1148/1506] drm/amd/display: Expose couple OPTC functions through header Signed-off-by: David Francis <David.Francis@amd.com> Reviewed-by: Charlene Liu <Charlene.Liu@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h | 11 +++++++++++ 1 file changed, 11 insertions(+) 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 1df510f57377d..c1b114209fe8d 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h @@ -554,4 +554,15 @@ bool optc1_get_otg_active_size(struct timing_generator *optc, uint32_t *otg_active_width, uint32_t *otg_active_height); +void optc1_enable_crtc_reset( + struct timing_generator *optc, + int source_tg_inst, + struct crtc_trigger_info *crtc_tp); + +bool optc1_configure_crc(struct timing_generator *optc, + const struct crc_params *params); + +bool optc1_get_crc(struct timing_generator *optc, + uint32_t *r_cr, uint32_t *g_y, uint32_t *b_cb); + #endif /* __DC_TIMING_GENERATOR_DCN10_H__ */ -- GitLab From 245524d9b827e184de1a23aff24c7872fed04cdb Mon Sep 17 00:00:00 2001 From: Hersen Wu <hersenxs.wu@amd.com> Date: Wed, 27 Jun 2018 13:03:04 -0400 Subject: [PATCH 1149/1506] drm/amd/display: dp debugfs allow link rate lane count greater than dp rx reported caps [Why] when hw team does phy parameters tuning, there is need to force dp link rate or lane count grater than the values from dp receiver to check dp tx. current debufs limit link rate, lane count no more than rx caps. [How] remove force settings less than rx caps check v2: Fix typo in title Signed-off-by: Hersen Wu <hersenxs.wu@amd.com> Reviewed-by: Charlene Liu <Charlene.Liu@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c index 0276e09d0b82e..0d9e410ca01e2 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -214,8 +214,7 @@ static ssize_t dp_link_settings_write(struct file *f, const char __user *buf, break; } - if (!valid_input || (param[0] > link->reported_link_cap.lane_count) || - (param[1] > link->reported_link_cap.link_rate)) { + if (!valid_input) { kfree(wr_buf); DRM_DEBUG_DRIVER("Invalid Input value No HW will be programmed\n"); return bytes_from_user; -- GitLab From ece4147fea152fe0761d67b825fb4b4b9f94349b Mon Sep 17 00:00:00 2001 From: Ken Chalmers <ken.chalmers@amd.com> Date: Wed, 27 Jun 2018 12:48:21 -0400 Subject: [PATCH 1150/1506] drm/amd/display: Fix new stream count check in dc_add_stream_to_ctx [Why] The previous code could allow through attempts to enable more streams than there are timing generators, in designs where the number of pipes is greater than the number of timing generators. [How] Compare the new stream count to the resource pool's timing generator count, instead of its pipe count. Also correct a typo in the error message. Signed-off-by: Ken Chalmers <ken.chalmers@amd.com> Reviewed-by: Charlene Liu <Charlene.Liu@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 c5fc5250e2bfc..9abe5481e40c8 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -1705,8 +1705,8 @@ enum dc_status dc_add_stream_to_ctx( struct dc_context *dc_ctx = dc->ctx; enum dc_status res; - if (new_ctx->stream_count >= dc->res_pool->pipe_count) { - DC_ERROR("Max streams reached, can add stream %p !\n", stream); + if (new_ctx->stream_count >= dc->res_pool->timing_generator_count) { + DC_ERROR("Max streams reached, can't add stream %p !\n", stream); return DC_ERROR_UNEXPECTED; } -- GitLab From dbcac9c8abb117b11728da44fcaffcdc0d2fcc81 Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Date: Thu, 28 Jun 2018 12:28:00 -0400 Subject: [PATCH 1151/1506] drm/amd/display: add max scl ratio to soc bounding box Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Reviewed-by: Charlene Liu <Charlene.Liu@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h index 6943801c5fd3f..c43d68bc9d5cd 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h @@ -111,6 +111,8 @@ struct _vcs_dpi_soc_bounding_box_st { double xfc_bus_transport_time_us; double xfc_xbuf_latency_tolerance_us; int use_urgent_burst_bw; + double max_hscl_ratio; + double max_vscl_ratio; struct _vcs_dpi_voltage_scaling_st clock_limits[7]; }; -- GitLab From 5fbac0a5ff99071919976a5434b19e9cc792a2ca Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Date: Thu, 28 Jun 2018 11:31:13 -0400 Subject: [PATCH 1152/1506] drm/amd/display: update dml to match DV dml DV updated their dml with an option to use max vstartup, this updates dc dml with the same option Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h index c43d68bc9d5cd..cbafce649e333 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h @@ -305,6 +305,7 @@ struct _vcs_dpi_display_pipe_dest_params_st { unsigned char otg_inst; unsigned char odm_split_cnt; unsigned char odm_combine; + unsigned char use_maximum_vstartup; }; struct _vcs_dpi_display_pipe_params_st { -- GitLab From cc034fed70d2d41ac7726d1c9872a80f035f8692 Mon Sep 17 00:00:00 2001 From: Tony Cheng <tony.cheng@amd.com> Date: Tue, 5 Jun 2018 09:15:41 -0400 Subject: [PATCH 1153/1506] drm/amd/display: dal 3.1.55 Signed-off-by: Tony Cheng <tony.cheng@amd.com> Reviewed-by: Anthony Koo <Anthony.Koo@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 721c5cdff38fe..208578301d593 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.1.54" +#define DC_VER "3.1.55" #define MAX_SURFACES 3 #define MAX_STREAMS 6 -- GitLab From 522e6b434a61f8be910560969386a2b3ce113c1b Mon Sep 17 00:00:00 2001 From: Hugo Hu <hugo.hu@amd.com> Date: Tue, 3 Jul 2018 15:59:15 -0400 Subject: [PATCH 1154/1506] drm/amd/display: Initialize data structure for DalMpVisualConfirm. [Why] Prevent unexpected color shows if DalMpVisualConfirm enable. [How] Zero out color configuration data for DalMpVisualConfirm when initiating. Signed-off-by: Hugo Hu <hugo.hu@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 a9942fd5f34e6..2e145aa663a4a 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 @@ -1851,7 +1851,7 @@ static void update_dpp(struct dpp *dpp, struct dc_plane_state *plane_state) static void dcn10_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) { struct hubp *hubp = pipe_ctx->plane_res.hubp; - struct mpcc_blnd_cfg blnd_cfg; + struct mpcc_blnd_cfg blnd_cfg = {0}; bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe; int mpcc_id; struct mpcc *new_mpcc; -- GitLab From ec95213112dca6111eb7561ae6384f77017dfd1f Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Date: Wed, 4 Jul 2018 11:31:40 -0400 Subject: [PATCH 1155/1506] drm/amd/display: properly turn autocal off [why] Currently we do not turn off autocal when scaling is in bypass. In case vbios enalbes auto scale and our first mode set is a non-scaled mode we have autocal on causing screen corruption. [how] moves turning autocal off to be first thing done during scaler setup Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c index f862fd148ccaf..f0cc97518c499 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c @@ -655,6 +655,12 @@ void dpp1_dscl_set_scaler_manual_scale( dpp->scl_data = *scl_data; + /* Autocal off */ + REG_SET_3(DSCL_AUTOCAL, 0, + AUTOCAL_MODE, AUTOCAL_MODE_OFF, + AUTOCAL_NUM_PIPE, 0, + AUTOCAL_PIPE_ID, 0); + /* Recout */ dpp1_dscl_set_recout(dpp, &scl_data->recout); @@ -678,12 +684,6 @@ void dpp1_dscl_set_scaler_manual_scale( if (dscl_mode == DSCL_MODE_SCALING_444_BYPASS) return; - /* Autocal off */ - REG_SET_3(DSCL_AUTOCAL, 0, - AUTOCAL_MODE, AUTOCAL_MODE_OFF, - AUTOCAL_NUM_PIPE, 0, - AUTOCAL_PIPE_ID, 0); - /* Black offsets */ if (ycbcr) REG_SET_2(SCL_BLACK_OFFSET, 0, -- GitLab From 3f2ddfa8875ce71a8c12723d1841647af8cbb0ba Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexander.deucher@amd.com> Date: Tue, 10 Jul 2018 16:51:22 -0500 Subject: [PATCH 1156/1506] drm/amdgpu/vi: fix mixed up state in smu clockgating setup Use the PP_STATE_SUPPORT_* rather than AMD_CG_SUPPORT_* when communicating with the SMU. Reviewed-by: Huang Rui <ray.huang@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/vi.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/vi.c b/drivers/gpu/drm/amd/amdgpu/vi.c index 4ac1288ab7dff..42c8ad105b050 100644 --- a/drivers/gpu/drm/amd/amdgpu/vi.c +++ b/drivers/gpu/drm/amd/amdgpu/vi.c @@ -1363,11 +1363,11 @@ static int vi_common_set_clockgating_state_by_smu(void *handle, if (adev->cg_flags & (AMD_CG_SUPPORT_MC_LS | AMD_CG_SUPPORT_MC_MGCG)) { if (adev->cg_flags & AMD_CG_SUPPORT_MC_LS) { - pp_support_state = AMD_CG_SUPPORT_MC_LS; + pp_support_state = PP_STATE_SUPPORT_LS; pp_state = PP_STATE_LS; } if (adev->cg_flags & AMD_CG_SUPPORT_MC_MGCG) { - pp_support_state |= AMD_CG_SUPPORT_MC_MGCG; + pp_support_state |= PP_STATE_SUPPORT_CG; pp_state |= PP_STATE_CG; } if (state == AMD_CG_STATE_UNGATE) @@ -1382,11 +1382,11 @@ static int vi_common_set_clockgating_state_by_smu(void *handle, if (adev->cg_flags & (AMD_CG_SUPPORT_SDMA_LS | AMD_CG_SUPPORT_SDMA_MGCG)) { if (adev->cg_flags & AMD_CG_SUPPORT_SDMA_LS) { - pp_support_state = AMD_CG_SUPPORT_SDMA_LS; + pp_support_state = PP_STATE_SUPPORT_LS; pp_state = PP_STATE_LS; } if (adev->cg_flags & AMD_CG_SUPPORT_SDMA_MGCG) { - pp_support_state |= AMD_CG_SUPPORT_SDMA_MGCG; + pp_support_state |= PP_STATE_SUPPORT_CG; pp_state |= PP_STATE_CG; } if (state == AMD_CG_STATE_UNGATE) @@ -1401,11 +1401,11 @@ static int vi_common_set_clockgating_state_by_smu(void *handle, if (adev->cg_flags & (AMD_CG_SUPPORT_HDP_LS | AMD_CG_SUPPORT_HDP_MGCG)) { if (adev->cg_flags & AMD_CG_SUPPORT_HDP_LS) { - pp_support_state = AMD_CG_SUPPORT_HDP_LS; + pp_support_state = PP_STATE_SUPPORT_LS; pp_state = PP_STATE_LS; } if (adev->cg_flags & AMD_CG_SUPPORT_HDP_MGCG) { - pp_support_state |= AMD_CG_SUPPORT_HDP_MGCG; + pp_support_state |= PP_STATE_SUPPORT_CG; pp_state |= PP_STATE_CG; } if (state == AMD_CG_STATE_UNGATE) -- GitLab From 3d75a8b689af2824dabe79d250b1ec535341109d Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexander.deucher@amd.com> Date: Thu, 12 Jul 2018 08:38:09 -0500 Subject: [PATCH 1157/1506] drm/amdgpu/pp/smu7: use a local variable for toc indexing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather than using the index variable stored in vram. If the device fails to come back online after a resume cycle, reads from vram will return all 1s which will cause a segfault. Based on a patch from Thomas Martitz <kugel@rockbox.org>. This avoids the segfault, but we still need to sort out why the GPU does not come back online after a resume. Bug: https://bugs.freedesktop.org/show_bug.cgi?id=105760 Acked-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../drm/amd/powerplay/smumgr/smu7_smumgr.c | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.c index d644a9bb9078d..9f407c48d4f0d 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.c @@ -381,6 +381,7 @@ int smu7_request_smu_load_fw(struct pp_hwmgr *hwmgr) uint32_t fw_to_load; int result = 0; struct SMU_DRAMData_TOC *toc; + uint32_t num_entries = 0; if (!hwmgr->reload_fw) { pr_info("skip reloading...\n"); @@ -422,41 +423,41 @@ int smu7_request_smu_load_fw(struct pp_hwmgr *hwmgr) } toc = (struct SMU_DRAMData_TOC *)smu_data->header; - toc->num_entries = 0; toc->structure_version = 1; PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, - UCODE_ID_RLC_G, &toc->entry[toc->num_entries++]), + UCODE_ID_RLC_G, &toc->entry[num_entries++]), "Failed to Get Firmware Entry.", return -EINVAL); PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, - UCODE_ID_CP_CE, &toc->entry[toc->num_entries++]), + UCODE_ID_CP_CE, &toc->entry[num_entries++]), "Failed to Get Firmware Entry.", return -EINVAL); PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, - UCODE_ID_CP_PFP, &toc->entry[toc->num_entries++]), + UCODE_ID_CP_PFP, &toc->entry[num_entries++]), "Failed to Get Firmware Entry.", return -EINVAL); PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, - UCODE_ID_CP_ME, &toc->entry[toc->num_entries++]), + UCODE_ID_CP_ME, &toc->entry[num_entries++]), "Failed to Get Firmware Entry.", return -EINVAL); PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, - UCODE_ID_CP_MEC, &toc->entry[toc->num_entries++]), + UCODE_ID_CP_MEC, &toc->entry[num_entries++]), "Failed to Get Firmware Entry.", return -EINVAL); PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, - UCODE_ID_CP_MEC_JT1, &toc->entry[toc->num_entries++]), + UCODE_ID_CP_MEC_JT1, &toc->entry[num_entries++]), "Failed to Get Firmware Entry.", return -EINVAL); PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, - UCODE_ID_CP_MEC_JT2, &toc->entry[toc->num_entries++]), + UCODE_ID_CP_MEC_JT2, &toc->entry[num_entries++]), "Failed to Get Firmware Entry.", return -EINVAL); PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, - UCODE_ID_SDMA0, &toc->entry[toc->num_entries++]), + UCODE_ID_SDMA0, &toc->entry[num_entries++]), "Failed to Get Firmware Entry.", return -EINVAL); PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, - UCODE_ID_SDMA1, &toc->entry[toc->num_entries++]), + UCODE_ID_SDMA1, &toc->entry[num_entries++]), "Failed to Get Firmware Entry.", return -EINVAL); if (!hwmgr->not_vf) PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, - UCODE_ID_MEC_STORAGE, &toc->entry[toc->num_entries++]), + UCODE_ID_MEC_STORAGE, &toc->entry[num_entries++]), "Failed to Get Firmware Entry.", return -EINVAL); + toc->num_entries = num_entries; smu7_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_DRV_DRAM_ADDR_HI, upper_32_bits(smu_data->header_buffer.mc_addr)); smu7_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_DRV_DRAM_ADDR_LO, lower_32_bits(smu_data->header_buffer.mc_addr)); -- GitLab From 2bce4be03738bc679c61f74fd42dd9e45c9a9959 Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexander.deucher@amd.com> Date: Wed, 11 Jul 2018 13:24:53 -0500 Subject: [PATCH 1158/1506] drm/amdgpu/pp/smu7: drop unused values in smu data structure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit use kaddr directly rather than secondary variable. Acked-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.c | 3 +-- drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.h | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.c index 9f407c48d4f0d..0f11c5341c495 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.c @@ -422,7 +422,7 @@ int smu7_request_smu_load_fw(struct pp_hwmgr *hwmgr) + UCODE_ID_CP_MEC_JT2_MASK; } - toc = (struct SMU_DRAMData_TOC *)smu_data->header; + toc = (struct SMU_DRAMData_TOC *)smu_data->header_buffer.kaddr; toc->structure_version = 1; PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, @@ -591,7 +591,6 @@ int smu7_init(struct pp_hwmgr *hwmgr) if (r) return -EINVAL; - smu_data->header = smu_data->header_buffer.kaddr; smu_data->header_buffer.mc_addr = mc_addr; if (!hwmgr->not_vf) diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.h b/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.h index 39c9bfda0ab41..e6def283b7311 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.h +++ b/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.h @@ -37,8 +37,6 @@ struct smu7_buffer_entry { }; struct smu7_smumgr { - uint8_t *header; - uint8_t *mec_image; struct smu7_buffer_entry smu_buffer; struct smu7_buffer_entry header_buffer; -- GitLab From 82088d5d7de1ef3575206cc3284dc219d0bd8fab Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexander.deucher@amd.com> Date: Wed, 11 Jul 2018 13:43:40 -0500 Subject: [PATCH 1159/1506] drm/amdgpu/pp/smu7: remove local mc_addr variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit use the structure member directly. Acked-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.c index 0f11c5341c495..cb5da61f214b3 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.c @@ -571,7 +571,6 @@ int smu7_setup_pwr_virus(struct pp_hwmgr *hwmgr) int smu7_init(struct pp_hwmgr *hwmgr) { struct smu7_smumgr *smu_data; - uint64_t mc_addr = 0; int r; /* Allocate memory for backend private data */ smu_data = (struct smu7_smumgr *)(hwmgr->smu_backend); @@ -585,14 +584,12 @@ int smu7_init(struct pp_hwmgr *hwmgr) PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM, &smu_data->header_buffer.handle, - &mc_addr, + &smu_data->header_buffer.mc_addr, &smu_data->header_buffer.kaddr); if (r) return -EINVAL; - smu_data->header_buffer.mc_addr = mc_addr; - if (!hwmgr->not_vf) return 0; @@ -602,7 +599,7 @@ int smu7_init(struct pp_hwmgr *hwmgr) PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM, &smu_data->smu_buffer.handle, - &mc_addr, + &smu_data->smu_buffer.mc_addr, &smu_data->smu_buffer.kaddr); if (r) { @@ -611,7 +608,6 @@ int smu7_init(struct pp_hwmgr *hwmgr) &smu_data->header_buffer.kaddr); return -EINVAL; } - smu_data->smu_buffer.mc_addr = mc_addr; if (smum_is_hw_avfs_present(hwmgr)) hwmgr->avfs_supported = true; -- GitLab From d92867122cd952485a4d209829bfa935689b14fe Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexander.deucher@amd.com> Date: Thu, 12 Jul 2018 00:38:23 -0500 Subject: [PATCH 1160/1506] drm/amdgpu/pp/smu7: cache smu firmware toc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather than calculating it everytime we rebuild the toc buffer, calculate it once initially and then just copy the cached results to the vram buffer. Acked-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../drm/amd/powerplay/smumgr/smu7_smumgr.c | 92 +++++++++++-------- .../drm/amd/powerplay/smumgr/smu7_smumgr.h | 1 + 2 files changed, 54 insertions(+), 39 deletions(-) diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.c index cb5da61f214b3..a029e47c2319c 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.c @@ -379,9 +379,7 @@ int smu7_request_smu_load_fw(struct pp_hwmgr *hwmgr) { struct smu7_smumgr *smu_data = (struct smu7_smumgr *)(hwmgr->smu_backend); uint32_t fw_to_load; - int result = 0; - struct SMU_DRAMData_TOC *toc; - uint32_t num_entries = 0; + int r = 0; if (!hwmgr->reload_fw) { pr_info("skip reloading...\n"); @@ -422,49 +420,62 @@ int smu7_request_smu_load_fw(struct pp_hwmgr *hwmgr) + UCODE_ID_CP_MEC_JT2_MASK; } - toc = (struct SMU_DRAMData_TOC *)smu_data->header_buffer.kaddr; - toc->structure_version = 1; - - PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, - UCODE_ID_RLC_G, &toc->entry[num_entries++]), - "Failed to Get Firmware Entry.", return -EINVAL); - PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, - UCODE_ID_CP_CE, &toc->entry[num_entries++]), - "Failed to Get Firmware Entry.", return -EINVAL); - PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, - UCODE_ID_CP_PFP, &toc->entry[num_entries++]), - "Failed to Get Firmware Entry.", return -EINVAL); - PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, - UCODE_ID_CP_ME, &toc->entry[num_entries++]), - "Failed to Get Firmware Entry.", return -EINVAL); - PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, - UCODE_ID_CP_MEC, &toc->entry[num_entries++]), - "Failed to Get Firmware Entry.", return -EINVAL); - PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, - UCODE_ID_CP_MEC_JT1, &toc->entry[num_entries++]), - "Failed to Get Firmware Entry.", return -EINVAL); - PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, - UCODE_ID_CP_MEC_JT2, &toc->entry[num_entries++]), - "Failed to Get Firmware Entry.", return -EINVAL); - PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, - UCODE_ID_SDMA0, &toc->entry[num_entries++]), - "Failed to Get Firmware Entry.", return -EINVAL); - PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, - UCODE_ID_SDMA1, &toc->entry[num_entries++]), - "Failed to Get Firmware Entry.", return -EINVAL); - if (!hwmgr->not_vf) - PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, - UCODE_ID_MEC_STORAGE, &toc->entry[num_entries++]), - "Failed to Get Firmware Entry.", return -EINVAL); + if (!smu_data->toc) { + struct SMU_DRAMData_TOC *toc; - toc->num_entries = num_entries; + smu_data->toc = kzalloc(sizeof(struct SMU_DRAMData_TOC), GFP_KERNEL); + if (!smu_data->toc) + return -ENOMEM; + toc = smu_data->toc; + toc->num_entries = 0; + toc->structure_version = 1; + + PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, + UCODE_ID_RLC_G, &toc->entry[toc->num_entries++]), + "Failed to Get Firmware Entry.", r = -EINVAL; goto failed); + PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, + UCODE_ID_CP_CE, &toc->entry[toc->num_entries++]), + "Failed to Get Firmware Entry.", r = -EINVAL; goto failed); + PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, + UCODE_ID_CP_PFP, &toc->entry[toc->num_entries++]), + "Failed to Get Firmware Entry.", r = -EINVAL; goto failed); + PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, + UCODE_ID_CP_ME, &toc->entry[toc->num_entries++]), + "Failed to Get Firmware Entry.", r = -EINVAL; goto failed); + PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, + UCODE_ID_CP_MEC, &toc->entry[toc->num_entries++]), + "Failed to Get Firmware Entry.", r = -EINVAL; goto failed); + PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, + UCODE_ID_CP_MEC_JT1, &toc->entry[toc->num_entries++]), + "Failed to Get Firmware Entry.", r = -EINVAL; goto failed); + PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, + UCODE_ID_CP_MEC_JT2, &toc->entry[toc->num_entries++]), + "Failed to Get Firmware Entry.", r = -EINVAL; goto failed); + PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, + UCODE_ID_SDMA0, &toc->entry[toc->num_entries++]), + "Failed to Get Firmware Entry.", r = -EINVAL; goto failed); + PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, + UCODE_ID_SDMA1, &toc->entry[toc->num_entries++]), + "Failed to Get Firmware Entry.", r = -EINVAL; goto failed); + if (!hwmgr->not_vf) + PP_ASSERT_WITH_CODE(0 == smu7_populate_single_firmware_entry(hwmgr, + UCODE_ID_MEC_STORAGE, &toc->entry[toc->num_entries++]), + "Failed to Get Firmware Entry.", r = -EINVAL; goto failed); + } + memcpy_toio(smu_data->header_buffer.kaddr, smu_data->toc, + sizeof(struct SMU_DRAMData_TOC)); smu7_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_DRV_DRAM_ADDR_HI, upper_32_bits(smu_data->header_buffer.mc_addr)); smu7_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_DRV_DRAM_ADDR_LO, lower_32_bits(smu_data->header_buffer.mc_addr)); if (smu7_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_LoadUcodes, fw_to_load)) pr_err("Fail to Request SMU Load uCode"); - return result; + return r; + +failed: + kfree(smu_data->toc); + smu_data->toc = NULL; + return r; } /* Check if the FW has been loaded, SMU will not return if loading has not finished. */ @@ -629,6 +640,9 @@ int smu7_smu_fini(struct pp_hwmgr *hwmgr) &smu_data->smu_buffer.mc_addr, &smu_data->smu_buffer.kaddr); + + kfree(smu_data->toc); + smu_data->toc = NULL; kfree(hwmgr->smu_backend); hwmgr->smu_backend = NULL; return 0; diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.h b/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.h index e6def283b7311..01f0538fba6b9 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.h +++ b/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.h @@ -39,6 +39,7 @@ struct smu7_buffer_entry { struct smu7_smumgr { struct smu7_buffer_entry smu_buffer; struct smu7_buffer_entry header_buffer; + struct SMU_DRAMData_TOC *toc; uint32_t soft_regs_start; uint32_t dpm_table_start; -- GitLab From f3ed5df84c268235fb1d489ab8979af423da02de Mon Sep 17 00:00:00 2001 From: Yong Zhao <yong.zhao@amd.com> Date: Fri, 13 Jul 2018 16:17:43 -0400 Subject: [PATCH 1161/1506] drm/amdkfd: Consolidate duplicate memory banks info in topology If there are several memory banks that has the same properties in CRAT, we aggregate them into one memory bank. This cleans up memory banks on APUs (e.g. Raven) where the CRAT reports each memory channel as a separate bank. This only confuses user mode, which only deals with virtual memory. Signed-off-by: Yong Zhao <yong.zhao@amd.com> Reviewed-by: Felix Kuehling <Felix.Kuehling@amd.com> Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com> Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com> --- drivers/gpu/drm/amd/amdkfd/kfd_crat.c | 57 +++++++++++++++++++++------ 1 file changed, 46 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c index 296b3f230280b..ee4996029a868 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c @@ -189,6 +189,21 @@ static int kfd_parse_subtype_cu(struct crat_subtype_computeunit *cu, return 0; } +static struct kfd_mem_properties * +find_subtype_mem(uint32_t heap_type, uint32_t flags, uint32_t width, + struct kfd_topology_device *dev) +{ + struct kfd_mem_properties *props; + + list_for_each_entry(props, &dev->mem_props, list) { + if (props->heap_type == heap_type + && props->flags == flags + && props->width == width) + return props; + } + + return NULL; +} /* kfd_parse_subtype_mem - parse memory subtypes and attach it to correct * topology device present in the device_list */ @@ -197,36 +212,56 @@ static int kfd_parse_subtype_mem(struct crat_subtype_memory *mem, { struct kfd_mem_properties *props; struct kfd_topology_device *dev; + uint32_t heap_type; + uint64_t size_in_bytes; + uint32_t flags = 0; + uint32_t width; pr_debug("Found memory entry in CRAT table with proximity_domain=%d\n", mem->proximity_domain); list_for_each_entry(dev, device_list, list) { if (mem->proximity_domain == dev->proximity_domain) { - props = kfd_alloc_struct(props); - if (!props) - return -ENOMEM; - /* We're on GPU node */ if (dev->node_props.cpu_cores_count == 0) { /* APU */ if (mem->visibility_type == 0) - props->heap_type = + heap_type = HSA_MEM_HEAP_TYPE_FB_PRIVATE; /* dGPU */ else - props->heap_type = mem->visibility_type; + heap_type = mem->visibility_type; } else - props->heap_type = HSA_MEM_HEAP_TYPE_SYSTEM; + heap_type = HSA_MEM_HEAP_TYPE_SYSTEM; if (mem->flags & CRAT_MEM_FLAGS_HOT_PLUGGABLE) - props->flags |= HSA_MEM_FLAGS_HOT_PLUGGABLE; + flags |= HSA_MEM_FLAGS_HOT_PLUGGABLE; if (mem->flags & CRAT_MEM_FLAGS_NON_VOLATILE) - props->flags |= HSA_MEM_FLAGS_NON_VOLATILE; + flags |= HSA_MEM_FLAGS_NON_VOLATILE; - props->size_in_bytes = + size_in_bytes = ((uint64_t)mem->length_high << 32) + mem->length_low; - props->width = mem->width; + width = mem->width; + + /* Multiple banks of the same type are aggregated into + * one. User mode doesn't care about multiple physical + * memory segments. It's managed as a single virtual + * heap for user mode. + */ + props = find_subtype_mem(heap_type, flags, width, dev); + if (props) { + props->size_in_bytes += size_in_bytes; + break; + } + + props = kfd_alloc_struct(props); + if (!props) + return -ENOMEM; + + props->heap_type = heap_type; + props->flags = flags; + props->size_in_bytes = size_in_bytes; + props->width = width; dev->node_props.mem_banks_count++; list_add_tail(&props->list, &dev->mem_props); -- GitLab From 98bb92222eef6ac022f352aa4224f4c94a119199 Mon Sep 17 00:00:00 2001 From: Yong Zhao <yong.zhao@amd.com> Date: Fri, 13 Jul 2018 16:17:44 -0400 Subject: [PATCH 1162/1506] drm/amdkfd: Make SDMA engine number an ASIC-dependent variable On Raven there is only one SDMA engine instead of previously assumed two, so we need to adapt our code to this new scenario. Signed-off-by: Yong Zhao <yong.zhao@amd.com> Reviewed-by: Felix Kuehling <Felix.Kuehling@amd.com> Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com> Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com> --- drivers/gpu/drm/amd/amdkfd/kfd_device.c | 12 ++++++++ .../drm/amd/amdkfd/kfd_device_queue_manager.c | 29 +++++++++++++------ .../drm/amd/amdkfd/kfd_device_queue_manager.h | 6 ++-- drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 1 + .../amd/amdkfd/kfd_process_queue_manager.c | 3 +- 5 files changed, 36 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index 8faa8db3eba52..572235cdd061b 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -52,6 +52,7 @@ static const struct kfd_device_info kaveri_device_info = { .supports_cwsr = false, .needs_iommu_device = true, .needs_pci_atomics = false, + .num_sdma_engines = 2, }; static const struct kfd_device_info carrizo_device_info = { @@ -67,6 +68,7 @@ static const struct kfd_device_info carrizo_device_info = { .supports_cwsr = true, .needs_iommu_device = true, .needs_pci_atomics = false, + .num_sdma_engines = 2, }; #endif @@ -83,6 +85,7 @@ static const struct kfd_device_info hawaii_device_info = { .supports_cwsr = false, .needs_iommu_device = false, .needs_pci_atomics = false, + .num_sdma_engines = 2, }; static const struct kfd_device_info tonga_device_info = { @@ -97,6 +100,7 @@ static const struct kfd_device_info tonga_device_info = { .supports_cwsr = false, .needs_iommu_device = false, .needs_pci_atomics = true, + .num_sdma_engines = 2, }; static const struct kfd_device_info tonga_vf_device_info = { @@ -111,6 +115,7 @@ static const struct kfd_device_info tonga_vf_device_info = { .supports_cwsr = false, .needs_iommu_device = false, .needs_pci_atomics = false, + .num_sdma_engines = 2, }; static const struct kfd_device_info fiji_device_info = { @@ -125,6 +130,7 @@ static const struct kfd_device_info fiji_device_info = { .supports_cwsr = true, .needs_iommu_device = false, .needs_pci_atomics = true, + .num_sdma_engines = 2, }; static const struct kfd_device_info fiji_vf_device_info = { @@ -139,6 +145,7 @@ static const struct kfd_device_info fiji_vf_device_info = { .supports_cwsr = true, .needs_iommu_device = false, .needs_pci_atomics = false, + .num_sdma_engines = 2, }; @@ -154,6 +161,7 @@ static const struct kfd_device_info polaris10_device_info = { .supports_cwsr = true, .needs_iommu_device = false, .needs_pci_atomics = true, + .num_sdma_engines = 2, }; static const struct kfd_device_info polaris10_vf_device_info = { @@ -168,6 +176,7 @@ static const struct kfd_device_info polaris10_vf_device_info = { .supports_cwsr = true, .needs_iommu_device = false, .needs_pci_atomics = false, + .num_sdma_engines = 2, }; static const struct kfd_device_info polaris11_device_info = { @@ -182,6 +191,7 @@ static const struct kfd_device_info polaris11_device_info = { .supports_cwsr = true, .needs_iommu_device = false, .needs_pci_atomics = true, + .num_sdma_engines = 2, }; static const struct kfd_device_info vega10_device_info = { @@ -196,6 +206,7 @@ static const struct kfd_device_info vega10_device_info = { .supports_cwsr = true, .needs_iommu_device = false, .needs_pci_atomics = false, + .num_sdma_engines = 2, }; static const struct kfd_device_info vega10_vf_device_info = { @@ -210,6 +221,7 @@ static const struct kfd_device_info vega10_vf_device_info = { .supports_cwsr = true, .needs_iommu_device = false, .needs_pci_atomics = false, + .num_sdma_engines = 2, }; 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 97c9f10ff473a..ace94d6e54cf2 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -101,6 +101,17 @@ unsigned int get_pipes_per_mec(struct device_queue_manager *dqm) return dqm->dev->shared_resources.num_pipe_per_mec; } +static unsigned int get_num_sdma_engines(struct device_queue_manager *dqm) +{ + return dqm->dev->device_info->num_sdma_engines; +} + +unsigned int get_num_sdma_queues(struct device_queue_manager *dqm) +{ + return dqm->dev->device_info->num_sdma_engines + * KFD_SDMA_QUEUES_PER_ENGINE; +} + void program_sh_mem_settings(struct device_queue_manager *dqm, struct qcm_process_device *qpd) { @@ -855,7 +866,7 @@ static int initialize_nocpsch(struct device_queue_manager *dqm) } dqm->vmid_bitmap = (1 << dqm->dev->vm_info.vmid_num_kfd) - 1; - dqm->sdma_bitmap = (1 << CIK_SDMA_QUEUES) - 1; + dqm->sdma_bitmap = (1 << get_num_sdma_queues(dqm)) - 1; return 0; } @@ -903,7 +914,7 @@ static int allocate_sdma_queue(struct device_queue_manager *dqm, static void deallocate_sdma_queue(struct device_queue_manager *dqm, unsigned int sdma_queue_id) { - if (sdma_queue_id >= CIK_SDMA_QUEUES) + if (sdma_queue_id >= get_num_sdma_queues(dqm)) return; dqm->sdma_bitmap |= (1 << sdma_queue_id); } @@ -923,8 +934,8 @@ static int create_sdma_queue_nocpsch(struct device_queue_manager *dqm, if (retval) return retval; - q->properties.sdma_queue_id = q->sdma_id / CIK_SDMA_QUEUES_PER_ENGINE; - q->properties.sdma_engine_id = q->sdma_id % CIK_SDMA_QUEUES_PER_ENGINE; + q->properties.sdma_queue_id = q->sdma_id / get_num_sdma_engines(dqm); + q->properties.sdma_engine_id = q->sdma_id % get_num_sdma_engines(dqm); retval = allocate_doorbell(qpd, q); if (retval) @@ -1011,7 +1022,7 @@ static int initialize_cpsch(struct device_queue_manager *dqm) dqm->queue_count = dqm->processes_count = 0; dqm->sdma_queue_count = 0; dqm->active_runlist = false; - dqm->sdma_bitmap = (1 << CIK_SDMA_QUEUES) - 1; + dqm->sdma_bitmap = (1 << get_num_sdma_queues(dqm)) - 1; INIT_WORK(&dqm->hw_exception_work, kfd_process_hw_exception); @@ -1142,9 +1153,9 @@ static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q, if (retval) goto out_unlock; q->properties.sdma_queue_id = - q->sdma_id / CIK_SDMA_QUEUES_PER_ENGINE; + q->sdma_id / get_num_sdma_engines(dqm); q->properties.sdma_engine_id = - q->sdma_id % CIK_SDMA_QUEUES_PER_ENGINE; + q->sdma_id % get_num_sdma_engines(dqm); } retval = allocate_doorbell(qpd, q); @@ -1791,8 +1802,8 @@ int dqm_debugfs_hqds(struct seq_file *m, void *data) } } - for (pipe = 0; pipe < CIK_SDMA_ENGINE_NUM; pipe++) { - for (queue = 0; queue < CIK_SDMA_QUEUES_PER_ENGINE; queue++) { + for (pipe = 0; pipe < get_num_sdma_engines(dqm); pipe++) { + for (queue = 0; queue < KFD_SDMA_QUEUES_PER_ENGINE; queue++) { r = dqm->dev->kfd2kgd->hqd_sdma_dump( dqm->dev->kgd, pipe, queue, &dump, &n_regs); if (r) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h index 52e708c4f9a53..00da3169a0044 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h @@ -33,10 +33,7 @@ #define KFD_UNMAP_LATENCY_MS (4000) #define QUEUE_PREEMPT_DEFAULT_TIMEOUT_MS (2 * KFD_UNMAP_LATENCY_MS + 1000) - -#define CIK_SDMA_QUEUES (4) -#define CIK_SDMA_QUEUES_PER_ENGINE (2) -#define CIK_SDMA_ENGINE_NUM (2) +#define KFD_SDMA_QUEUES_PER_ENGINE (2) struct device_process_node { struct qcm_process_device *qpd; @@ -214,6 +211,7 @@ void program_sh_mem_settings(struct device_queue_manager *dqm, unsigned int get_queues_num(struct device_queue_manager *dqm); unsigned int get_queues_per_pipe(struct device_queue_manager *dqm); unsigned int get_pipes_per_mec(struct device_queue_manager *dqm); +unsigned int get_num_sdma_queues(struct device_queue_manager *dqm); static inline unsigned int get_sh_mem_bases_32(struct kfd_process_device *pdd) { diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index 37d179ed51dc1..ca83254719fca 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -203,6 +203,7 @@ struct kfd_device_info { bool supports_cwsr; bool needs_iommu_device; bool needs_pci_atomics; + unsigned int num_sdma_engines; }; struct kfd_mem_obj { diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c index 1303b1457950c..eb4e5fb4f2f24 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c @@ -186,8 +186,7 @@ int pqm_create_queue(struct process_queue_manager *pqm, switch (type) { case KFD_QUEUE_TYPE_SDMA: - if (dev->dqm->queue_count >= - CIK_SDMA_QUEUES_PER_ENGINE * CIK_SDMA_ENGINE_NUM) { + if (dev->dqm->queue_count >= get_num_sdma_queues(dev->dqm)) { pr_err("Over-subscription is not allowed for SDMA.\n"); retval = -EPERM; goto err_create_queue; -- GitLab From eab69801cf4388aeba2c730ce4db746ae164eada Mon Sep 17 00:00:00 2001 From: Yong Zhao <yong.zhao@amd.com> Date: Fri, 13 Jul 2018 16:17:45 -0400 Subject: [PATCH 1163/1506] drm/amdkfd: Avoid flooding dmesg on Raven due to IOMMU issues On Raven Invalid PPRs (peripheral page requests) can be reported because multiple PPRs can be still queued when memory is freed. Apply a rate limit to avoid flooding the log in this case. Signed-off-by: Yong Zhao <yong.zhao@amd.com> Reviewed-by: Felix Kuehling <Felix.Kuehling@amd.com> Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com> Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com> --- drivers/gpu/drm/amd/amdkfd/kfd_iommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_iommu.c b/drivers/gpu/drm/amd/amdkfd/kfd_iommu.c index c71817963eea6..7a61f38c09e65 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_iommu.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_iommu.c @@ -190,7 +190,7 @@ static int iommu_invalid_ppr_cb(struct pci_dev *pdev, int pasid, { struct kfd_dev *dev; - dev_warn(kfd_device, + dev_warn_ratelimited(kfd_device, "Invalid PPR device %x:%x.%x pasid %d address 0x%lX flags 0x%X", PCI_BUS_NUM(pdev->devfn), PCI_SLOT(pdev->devfn), -- GitLab From 8725aecac331954e0827d6bed7be02eb7b8f1e9e Mon Sep 17 00:00:00 2001 From: Yong Zhao <yong.zhao@amd.com> Date: Fri, 13 Jul 2018 16:17:46 -0400 Subject: [PATCH 1164/1506] drm/amdkfd: Workaround to accommodate Raven too many PPR issue On Raven multiple PPRs can be queued up by the hardware. When the first of those requests is handled by the IOMMU driver, the memory access succeeds. After that the application may be done with the memory and unmap it. At that point the page table entries are invalidated, but there are still outstanding duplicate PPRs for those addresses. When the IOMMU driver processes those duplicate requests, it finds invalid page table entries and triggers an invalid PPR fault. As a workaround, don't signal invalid PPR faults on Raven to avoid segfaulting applications that haven't done anything wrong. As a side effect, real GPU memory access faults may go unnoticed by the application. Signed-off-by: Yong Zhao <yong.zhao@amd.com> Reviewed-by: Felix Kuehling <Felix.Kuehling@amd.com> Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com> Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com> --- drivers/gpu/drm/amd/amdkfd/kfd_events.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_events.c index 820133cdef83e..4dcacce2db869 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_events.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_events.c @@ -932,13 +932,24 @@ void kfd_signal_iommu_event(struct kfd_dev *dev, unsigned int pasid, up_read(&mm->mmap_sem); mmput(mm); - mutex_lock(&p->event_mutex); + pr_debug("notpresent %d, noexecute %d, readonly %d\n", + memory_exception_data.failure.NotPresent, + memory_exception_data.failure.NoExecute, + memory_exception_data.failure.ReadOnly); - /* Lookup events by type and signal them */ - lookup_events_by_type_and_signal(p, KFD_EVENT_TYPE_MEMORY, - &memory_exception_data); + /* Workaround on Raven to not kill the process when memory is freed + * before IOMMU is able to finish processing all the excessive PPRs + */ + if (dev->device_info->asic_family != CHIP_RAVEN) { + mutex_lock(&p->event_mutex); + + /* Lookup events by type and signal them */ + lookup_events_by_type_and_signal(p, KFD_EVENT_TYPE_MEMORY, + &memory_exception_data); + + mutex_unlock(&p->event_mutex); + } - mutex_unlock(&p->event_mutex); kfd_unref_process(p); } #endif /* KFD_SUPPORT_IOMMU_V2 */ -- GitLab From 359cecdd499783abcf4ba6589066db8d8cb58e88 Mon Sep 17 00:00:00 2001 From: Yong Zhao <yong.zhao@amd.com> Date: Fri, 13 Jul 2018 16:17:47 -0400 Subject: [PATCH 1165/1506] drm/amdkfd: Optimize out some duplicated code in kfd_signal_iommu_event() memory_exception_data is already initialized for not-present faults. It only needs to be overridden for permission faults. Signed-off-by: Yong Zhao <yong.zhao@amd.com> Reviewed-by: Felix Kuehling <Felix.Kuehling@amd.com> Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com> Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com> --- drivers/gpu/drm/amd/amdkfd/kfd_events.c | 26 +++++++++++-------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_events.c index 4dcacce2db869..e9f0e0a1b41c0 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_events.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_events.c @@ -911,22 +911,18 @@ void kfd_signal_iommu_event(struct kfd_dev *dev, unsigned int pasid, memory_exception_data.failure.NotPresent = 1; memory_exception_data.failure.NoExecute = 0; memory_exception_data.failure.ReadOnly = 0; - if (vma) { - if (vma->vm_start > address) { - memory_exception_data.failure.NotPresent = 1; - memory_exception_data.failure.NoExecute = 0; + if (vma && address >= vma->vm_start) { + memory_exception_data.failure.NotPresent = 0; + + if (is_write_requested && !(vma->vm_flags & VM_WRITE)) + memory_exception_data.failure.ReadOnly = 1; + else memory_exception_data.failure.ReadOnly = 0; - } else { - memory_exception_data.failure.NotPresent = 0; - if (is_write_requested && !(vma->vm_flags & VM_WRITE)) - memory_exception_data.failure.ReadOnly = 1; - else - memory_exception_data.failure.ReadOnly = 0; - if (is_execute_requested && !(vma->vm_flags & VM_EXEC)) - memory_exception_data.failure.NoExecute = 1; - else - memory_exception_data.failure.NoExecute = 0; - } + + if (is_execute_requested && !(vma->vm_flags & VM_EXEC)) + memory_exception_data.failure.NoExecute = 1; + else + memory_exception_data.failure.NoExecute = 0; } up_read(&mm->mmap_sem); -- GitLab From 4d663df6588709e8763b976310117aa0f9825bc6 Mon Sep 17 00:00:00 2001 From: Yong Zhao <Yong.Zhao@amd.com> Date: Fri, 13 Jul 2018 16:17:48 -0400 Subject: [PATCH 1166/1506] drm/amdkfd: Enable Raven for KFD Add DID and kfd_device_info for Raven. Signed-off-by: Yong Zhao <Yong.Zhao@amd.com> Reviewed-by: Felix Kuehling <Felix.Kuehling@amd.com> Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com> Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com> --- drivers/gpu/drm/amd/amdkfd/kfd_device.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index 572235cdd061b..1b048715ab8a1 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -70,6 +70,21 @@ static const struct kfd_device_info carrizo_device_info = { .needs_pci_atomics = false, .num_sdma_engines = 2, }; + +static const struct kfd_device_info raven_device_info = { + .asic_family = CHIP_RAVEN, + .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 = true, + .needs_pci_atomics = true, + .num_sdma_engines = 1, +}; #endif static const struct kfd_device_info hawaii_device_info = { @@ -259,6 +274,7 @@ static const struct kfd_deviceid supported_devices[] = { { 0x9875, &carrizo_device_info }, /* Carrizo */ { 0x9876, &carrizo_device_info }, /* Carrizo */ { 0x9877, &carrizo_device_info }, /* Carrizo */ + { 0x15DD, &raven_device_info }, /* Raven */ #endif { 0x67A0, &hawaii_device_info }, /* Hawaii */ { 0x67A1, &hawaii_device_info }, /* Hawaii */ -- GitLab From 9dd1a981a22a6c5416e9a179912fb1215225235f Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 13 Jul 2018 21:35:27 +0100 Subject: [PATCH 1167/1506] drm/i915/selftests: Include the start of each subtest in the GEM trace Knowing the boundary of each subtest can be instrumental in digesting the voluminous trace output and finding the critical piece of information. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Michel Thierry <michel.thierry@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180713203529.1973-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/selftests/i915_selftest.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/selftests/i915_selftest.c b/drivers/gpu/drm/i915/selftests/i915_selftest.c index addc5a599c4ad..86c54ea37f488 100644 --- a/drivers/gpu/drm/i915/selftests/i915_selftest.c +++ b/drivers/gpu/drm/i915/selftests/i915_selftest.c @@ -210,6 +210,8 @@ int __i915_subtests(const char *caller, return -EINTR; pr_debug(DRIVER_NAME ": Running %s/%s\n", caller, st->name); + GEM_TRACE("Running %s/%s\n", caller, st->name); + err = st->func(data); if (err && err != -EINTR) { pr_err(DRIVER_NAME "/%s: %s failed with error %d\n", -- GitLab From 9701975e851082d179faaab9c6306a7800d86c0f Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 13 Jul 2018 21:35:28 +0100 Subject: [PATCH 1168/1506] drm/i915: Do not short-circuit tasklets during reset Inside intel_engine_is_idle(), we flush the tasklet to ensure that is being run in a timely fashion (ksoftirqd has taught us to expect the worst). However, if we are in the middle of reset, the HW may not yet be ready to execute the submission tasklet and so we must respect the disable flag. Fixes: dd0cf235d81f ("drm/i915: Speed up idle detection by kicking the tasklets") Testcase: igt/drv_selftest/live_hangcheck Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Reviewed-by: Michel Thierry <michel.thierry@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180713203529.1973-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_engine_cs.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index 220050107c486..2d1952849d69f 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -989,16 +989,18 @@ bool intel_engine_is_idle(struct intel_engine_cs *engine) /* Waiting to drain ELSP? */ if (READ_ONCE(engine->execlists.active)) { - struct intel_engine_execlists *execlists = &engine->execlists; + struct tasklet_struct *t = &engine->execlists.tasklet; local_bh_disable(); - if (tasklet_trylock(&execlists->tasklet)) { - execlists->tasklet.func(execlists->tasklet.data); - tasklet_unlock(&execlists->tasklet); + if (tasklet_trylock(t)) { + /* Must wait for any GPU reset in progress. */ + if (__tasklet_is_enabled(t)) + t->func(t->data); + tasklet_unlock(t); } local_bh_enable(); - if (READ_ONCE(execlists->active)) + if (READ_ONCE(engine->execlists.active)) return false; } -- GitLab From 60a94324541361542f1ffb12844f4cb737695ba5 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Fri, 13 Jul 2018 21:35:29 +0100 Subject: [PATCH 1169/1506] drm/i915/execlists: Drop clear_gtiir() on GPU reset With the new CSB processing code, we are not vulnerable to delayed delivery of a pre-reset interrupt as we use the CSB status pointers in the HWSP to decide if we need to parse any CSB events and no longer need to wait for the first post-reset interrupt to be assured that the CSB mmio registers are valid. The new icl code to clear registers has a nasty lock inversion: [ 57.409776] ====================================================== [ 57.409779] WARNING: possible circular locking dependency detected [ 57.409783] 4.18.0-rc4-CI-CI_DII_1137+ #1 Tainted: G U W [ 57.409785] ------------------------------------------------------ [ 57.409788] swapper/6/0 is trying to acquire lock: [ 57.409790] 000000004f304ee5 (&engine->timeline.lock/1){-.-.}, at: execlists_submit_request+0x2b/0x1a0 [i915] [ 57.409841] but task is already holding lock: [ 57.409844] 00000000aad89594 (&(&rq->lock)->rlock#2){-.-.}, at: notify_ring+0x2b2/0x480 [i915] [ 57.409869] which lock already depends on the new lock. [ 57.409872] the existing dependency chain (in reverse order) is: [ 57.409876] -> #2 (&(&rq->lock)->rlock#2){-.-.}: [ 57.409900] notify_ring+0x2b2/0x480 [i915] [ 57.409922] gen8_cs_irq_handler+0x39/0xa0 [i915] [ 57.409943] gen11_irq_handler+0x2f0/0x420 [i915] [ 57.409949] __handle_irq_event_percpu+0x42/0x370 [ 57.409952] handle_irq_event_percpu+0x2b/0x70 [ 57.409956] handle_irq_event+0x2f/0x50 [ 57.409959] handle_edge_irq+0xe7/0x190 [ 57.409964] handle_irq+0x67/0x160 [ 57.409967] do_IRQ+0x5e/0x120 [ 57.409971] ret_from_intr+0x0/0x1d [ 57.409974] _raw_spin_unlock_irqrestore+0x4e/0x60 [ 57.409979] tasklet_action_common.isra.5+0x47/0xb0 [ 57.409982] __do_softirq+0xd9/0x505 [ 57.409985] irq_exit+0xa9/0xc0 [ 57.409988] do_IRQ+0x9a/0x120 [ 57.409991] ret_from_intr+0x0/0x1d [ 57.409995] cpuidle_enter_state+0xac/0x360 [ 57.409999] do_idle+0x1f3/0x250 [ 57.410004] cpu_startup_entry+0x6a/0x70 [ 57.410010] start_secondary+0x19d/0x1f0 [ 57.410015] secondary_startup_64+0xa5/0xb0 [ 57.410018] -> #1 (&(&dev_priv->irq_lock)->rlock){-.-.}: [ 57.410081] clear_gtiir+0x30/0x200 [i915] [ 57.410116] execlists_reset+0x6e/0x2b0 [i915] [ 57.410140] i915_reset_engine+0x111/0x190 [i915] [ 57.410165] i915_handle_error+0x11a/0x4a0 [i915] [ 57.410198] i915_hangcheck_elapsed+0x378/0x530 [i915] [ 57.410204] process_one_work+0x248/0x6c0 [ 57.410207] worker_thread+0x37/0x380 [ 57.410211] kthread+0x119/0x130 [ 57.410215] ret_from_fork+0x3a/0x50 [ 57.410217] -> #0 (&engine->timeline.lock/1){-.-.}: [ 57.410224] _raw_spin_lock_irqsave+0x33/0x50 [ 57.410256] execlists_submit_request+0x2b/0x1a0 [i915] [ 57.410289] submit_notify+0x8d/0x124 [i915] [ 57.410314] __i915_sw_fence_complete+0x81/0x250 [i915] [ 57.410339] dma_i915_sw_fence_wake+0xd/0x20 [i915] [ 57.410344] dma_fence_signal_locked+0x79/0x200 [ 57.410368] notify_ring+0x2ba/0x480 [i915] [ 57.410392] gen8_cs_irq_handler+0x39/0xa0 [i915] [ 57.410416] gen11_irq_handler+0x2f0/0x420 [i915] [ 57.410421] __handle_irq_event_percpu+0x42/0x370 [ 57.410425] handle_irq_event_percpu+0x2b/0x70 [ 57.410428] handle_irq_event+0x2f/0x50 [ 57.410432] handle_edge_irq+0xe7/0x190 [ 57.410436] handle_irq+0x67/0x160 [ 57.410439] do_IRQ+0x5e/0x120 [ 57.410445] ret_from_intr+0x0/0x1d [ 57.410449] cpuidle_enter_state+0xac/0x360 [ 57.410453] do_idle+0x1f3/0x250 [ 57.410456] cpu_startup_entry+0x6a/0x70 [ 57.410460] start_secondary+0x19d/0x1f0 [ 57.410464] secondary_startup_64+0xa5/0xb0 [ 57.410466] other info that might help us debug this: [ 57.410471] Chain exists of: &engine->timeline.lock/1 --> &(&dev_priv->irq_lock)->rlock --> &(&rq->lock)->rlock#2 [ 57.410481] Possible unsafe locking scenario: [ 57.410485] CPU0 CPU1 [ 57.410487] ---- ---- [ 57.410490] lock(&(&rq->lock)->rlock#2); [ 57.410494] lock(&(&dev_priv->irq_lock)->rlock); [ 57.410498] lock(&(&rq->lock)->rlock#2); [ 57.410503] lock(&engine->timeline.lock/1); [ 57.410506] *** DEADLOCK *** [ 57.410511] 4 locks held by swapper/6/0: [ 57.410514] #0: 0000000074575789 (&(&dev_priv->irq_lock)->rlock){-.-.}, at: gen11_irq_handler+0x8a/0x420 [i915] [ 57.410542] #1: 000000009b29b30e (rcu_read_lock){....}, at: notify_ring+0x1a/0x480 [i915] [ 57.410573] #2: 00000000aad89594 (&(&rq->lock)->rlock#2){-.-.}, at: notify_ring+0x2b2/0x480 [i915] [ 57.410601] #3: 000000009b29b30e (rcu_read_lock){....}, at: submit_notify+0x35/0x124 [i915] [ 57.410635] stack backtrace: [ 57.410640] CPU: 6 PID: 0 Comm: swapper/6 Tainted: G U W 4.18.0-rc4-CI-CI_DII_1137+ #1 [ 57.410644] Hardware name: Intel Corporation Ice Lake Client Platform/IceLake U DDR4 SODIMM PD RVP, BIOS ICLSFWR1.R00.2222.A01.1805300339 05/30/2018 [ 57.410650] Call Trace: [ 57.410652] <IRQ> [ 57.410657] dump_stack+0x67/0x9b [ 57.410662] print_circular_bug.isra.16+0x1c8/0x2b0 [ 57.410666] __lock_acquire+0x1897/0x1b50 [ 57.410671] ? lock_acquire+0xa6/0x210 [ 57.410674] lock_acquire+0xa6/0x210 [ 57.410706] ? execlists_submit_request+0x2b/0x1a0 [i915] [ 57.410711] _raw_spin_lock_irqsave+0x33/0x50 [ 57.410741] ? execlists_submit_request+0x2b/0x1a0 [i915] [ 57.410769] execlists_submit_request+0x2b/0x1a0 [i915] [ 57.410774] ? _raw_spin_unlock_irqrestore+0x39/0x60 [ 57.410804] submit_notify+0x8d/0x124 [i915] [ 57.410828] __i915_sw_fence_complete+0x81/0x250 [i915] [ 57.410854] dma_i915_sw_fence_wake+0xd/0x20 [i915] [ 57.410858] dma_fence_signal_locked+0x79/0x200 [ 57.410882] notify_ring+0x2ba/0x480 [i915] [ 57.410907] gen8_cs_irq_handler+0x39/0xa0 [i915] [ 57.410933] gen11_irq_handler+0x2f0/0x420 [i915] [ 57.410938] __handle_irq_event_percpu+0x42/0x370 [ 57.410943] handle_irq_event_percpu+0x2b/0x70 [ 57.410947] handle_irq_event+0x2f/0x50 [ 57.410951] handle_edge_irq+0xe7/0x190 [ 57.410955] handle_irq+0x67/0x160 [ 57.410958] do_IRQ+0x5e/0x120 [ 57.410962] common_interrupt+0xf/0xf [ 57.410965] </IRQ> [ 57.410969] RIP: 0010:cpuidle_enter_state+0xac/0x360 [ 57.410972] Code: 44 00 00 31 ff e8 84 93 91 ff 45 84 f6 74 12 9c 58 f6 c4 02 0f 85 31 02 00 00 31 ff e8 7d 30 98 ff e8 e8 0e 94 ff fb 4c 29 fb <48> ba cf f7 53 e3 a5 9b c4 20 48 89 d8 48 c1 fb 3f 48 f7 ea b8 ff [ 57.411015] RSP: 0018:ffffc90000133e90 EFLAGS: 00000216 ORIG_RAX: ffffffffffffffdd [ 57.411023] RAX: ffff8804ae748040 RBX: 000000000002a97d RCX: 0000000000000000 [ 57.411029] RDX: 0000000000000046 RSI: ffffffff82141263 RDI: ffffffff820f05a7 [ 57.411035] RBP: 0000000000000001 R08: 0000000000000001 R09: 0000000000000000 [ 57.411041] R10: 0000000000000000 R11: 0000000000000000 R12: ffffffff8229f078 [ 57.411045] R13: ffff8804ab2adfa8 R14: 0000000000000000 R15: 0000000d5de092e3 [ 57.411052] do_idle+0x1f3/0x250 [ 57.411055] cpu_startup_entry+0x6a/0x70 [ 57.411059] start_secondary+0x19d/0x1f0 [ 57.411064] secondary_startup_64+0xa5/0xb0 The easiest remedy is to remove the defunct code. Fixes: ff047a87cfac ("drm/i915/icl: Correctly clear lost ctx-switch interrupts across reset for Gen11") References: fd8526e50902 ("drm/i915/execlists: Trust the CSB") Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Michel Thierry <michel.thierry@intel.com> Cc: Oscar Mateo <oscar.mateo@intel.com> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Cc: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com> Reviewed-by: Michel Thierry <michel.thierry@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180713203529.1973-3-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_irq.c | 6 +-- drivers/gpu/drm/i915/intel_drv.h | 3 -- drivers/gpu/drm/i915/intel_lrc.c | 68 -------------------------------- 3 files changed, 3 insertions(+), 74 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 6975a169c4e4a..5dadefca2ad22 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -263,9 +263,9 @@ static u32 gen11_gt_engine_identity(struct drm_i915_private * const i915, const unsigned int bank, const unsigned int bit); -bool gen11_reset_one_iir(struct drm_i915_private * const i915, - const unsigned int bank, - const unsigned int bit) +static bool gen11_reset_one_iir(struct drm_i915_private * const i915, + const unsigned int bank, + const unsigned int bit) { void __iomem * const regs = i915->regs; u32 dw; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index a45f6324dd9b5..f8d5fafe1f1a7 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1353,9 +1353,6 @@ void intel_check_cpu_fifo_underruns(struct drm_i915_private *dev_priv); void intel_check_pch_fifo_underruns(struct drm_i915_private *dev_priv); /* i915_irq.c */ -bool gen11_reset_one_iir(struct drm_i915_private * const i915, - const unsigned int bank, - const unsigned int bit); void gen5_enable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask); void gen5_disable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask); void gen6_mask_pm_irq(struct drm_i915_private *dev_priv, u32 mask); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index ad436d200758c..05567e30efe06 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -796,72 +796,6 @@ execlists_cancel_port_requests(struct intel_engine_execlists * const execlists) execlists_user_end(execlists); } -static void clear_gtiir(struct intel_engine_cs *engine) -{ - struct drm_i915_private *dev_priv = engine->i915; - int i; - - /* - * Clear any pending interrupt state. - * - * We do it twice out of paranoia that some of the IIR are - * double buffered, and so if we only reset it once there may - * still be an interrupt pending. - */ - if (INTEL_GEN(dev_priv) >= 11) { - static const struct { - u8 bank; - u8 bit; - } gen11_gtiir[] = { - [RCS] = {0, GEN11_RCS0}, - [BCS] = {0, GEN11_BCS}, - [_VCS(0)] = {1, GEN11_VCS(0)}, - [_VCS(1)] = {1, GEN11_VCS(1)}, - [_VCS(2)] = {1, GEN11_VCS(2)}, - [_VCS(3)] = {1, GEN11_VCS(3)}, - [_VECS(0)] = {1, GEN11_VECS(0)}, - [_VECS(1)] = {1, GEN11_VECS(1)}, - }; - unsigned long irqflags; - - GEM_BUG_ON(engine->id >= ARRAY_SIZE(gen11_gtiir)); - - spin_lock_irqsave(&dev_priv->irq_lock, irqflags); - for (i = 0; i < 2; i++) { - gen11_reset_one_iir(dev_priv, - gen11_gtiir[engine->id].bank, - gen11_gtiir[engine->id].bit); - } - spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); - } else { - static const u8 gtiir[] = { - [RCS] = 0, - [BCS] = 0, - [VCS] = 1, - [VCS2] = 1, - [VECS] = 3, - }; - - GEM_BUG_ON(engine->id >= ARRAY_SIZE(gtiir)); - - for (i = 0; i < 2; i++) { - I915_WRITE(GEN8_GT_IIR(gtiir[engine->id]), - engine->irq_keep_mask); - POSTING_READ(GEN8_GT_IIR(gtiir[engine->id])); - } - GEM_BUG_ON(I915_READ(GEN8_GT_IIR(gtiir[engine->id])) & - engine->irq_keep_mask); - } -} - -static void reset_irq(struct intel_engine_cs *engine) -{ - /* Mark all CS interrupts as complete */ - smp_store_mb(engine->execlists.active, 0); - - clear_gtiir(engine); -} - static void reset_csb_pointers(struct intel_engine_execlists *execlists) { /* @@ -905,7 +839,6 @@ static void execlists_cancel_requests(struct intel_engine_cs *engine) /* Cancel the requests on the HW and clear the ELSP tracker. */ execlists_cancel_port_requests(execlists); - reset_irq(engine); /* Mark all executing requests as skipped. */ list_for_each_entry(rq, &engine->timeline.requests, link) { @@ -1976,7 +1909,6 @@ static void execlists_reset(struct intel_engine_cs *engine, * requests were completed. */ execlists_cancel_port_requests(execlists); - reset_irq(engine); /* Push back any incomplete requests for replay after the reset. */ __unwind_incomplete_requests(engine); -- GitLab From e5cae659597811f8bacc4abc70135dffb48711d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Winiarski?= <michal.winiarski@intel.com> Date: Sat, 14 Jul 2018 18:37:03 +0100 Subject: [PATCH 1170/1506] drm/i915/guc: Disable rpm wakeref asserts in GuC irq handler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We're seeing "RPM wakelock ref not held during HW access" warning otherwise. Since IRQs are synced for runtime suspend we can just disable the wakeref asserts. Reported-by: Marta Löfstedt <marta.lofstedt@intel.com> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=105710 Signed-off-by: MichaÅ‚ Winiarski <michal.winiarski@intel.com> Cc: Chris Wilson <chris@chris-wilson.co.uk> Cc: Michal Wajdeczko <michal.wajdeczko@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180714173703.7894-1-chris@chris-wilson.co.uk Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> --- drivers/gpu/drm/i915/intel_guc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c index e12bd259df172..560c7406ae406 100644 --- a/drivers/gpu/drm/i915/intel_guc.c +++ b/drivers/gpu/drm/i915/intel_guc.c @@ -466,11 +466,13 @@ void intel_guc_to_host_event_handler_mmio(struct intel_guc *guc) * could happen that GuC sets the bit for 2nd interrupt but Host * clears out the bit on handling the 1st interrupt. */ + disable_rpm_wakeref_asserts(dev_priv); spin_lock(&guc->irq_lock); val = I915_READ(SOFT_SCRATCH(15)); msg = val & guc->msg_enabled_mask; I915_WRITE(SOFT_SCRATCH(15), val & ~msg); spin_unlock(&guc->irq_lock); + enable_rpm_wakeref_asserts(dev_priv); intel_guc_to_host_process_recv_msg(guc, msg); } -- GitLab From a7fe68a1e8e4bce007505f729bc33e427c540386 Mon Sep 17 00:00:00 2001 From: Felix Kuehling <Felix.Kuehling@amd.com> Date: Sat, 14 Jul 2018 19:05:58 -0400 Subject: [PATCH 1171/1506] drm/amd: Add CU-masking ioctl definition to kfd_ioctl.h Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com> Acked-by: Oded Gabbay <oded.gabbay@gmail.com> Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com> --- include/uapi/linux/kfd_ioctl.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/kfd_ioctl.h b/include/uapi/linux/kfd_ioctl.h index 88d17c39dbf9a..01674b56e14f2 100644 --- a/include/uapi/linux/kfd_ioctl.h +++ b/include/uapi/linux/kfd_ioctl.h @@ -76,6 +76,12 @@ struct kfd_ioctl_update_queue_args { __u32 queue_priority; /* to KFD */ }; +struct kfd_ioctl_set_cu_mask_args { + __u32 queue_id; /* to KFD */ + __u32 num_cu_mask; /* to KFD */ + __u64 cu_mask_ptr; /* to KFD */ +}; + /* For kfd_ioctl_set_memory_policy_args.default_policy and alternate_policy */ #define KFD_IOC_CACHE_POLICY_COHERENT 0 #define KFD_IOC_CACHE_POLICY_NONCOHERENT 1 @@ -466,7 +472,10 @@ struct kfd_ioctl_unmap_memory_from_gpu_args { #define AMDKFD_IOC_UNMAP_MEMORY_FROM_GPU \ AMDKFD_IOWR(0x19, struct kfd_ioctl_unmap_memory_from_gpu_args) +#define AMDKFD_IOC_SET_CU_MASK \ + AMDKFD_IOW(0x1A, struct kfd_ioctl_set_cu_mask_args) + #define AMDKFD_COMMAND_START 0x01 -#define AMDKFD_COMMAND_END 0x1A +#define AMDKFD_COMMAND_END 0x1B #endif -- GitLab From 39e7f331864d2b9e30d5f3fd2121e182b2c9c8a9 Mon Sep 17 00:00:00 2001 From: Felix Kuehling <Felix.Kuehling@amd.com> Date: Sat, 14 Jul 2018 19:05:59 -0400 Subject: [PATCH 1172/1506] drm/amdkfd: Add CU-masking ioctl to KFD CU-masking allows a KFD client to control the set of CUs used by a user mode queue for executing compute dispatches. This can be used for optimizing the partitioning of the GPU and minimize conflicts between concurrent tasks. Signed-off-by: Flora Cui <flora.cui@amd.com> Signed-off-by: Kent Russell <kent.russell@amd.com> Signed-off-by: Eric Huang <JinHuiEric.Huang@amd.com> Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com> Acked-by: Oded Gabbay <oded.gabbay@gmail.com> Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com> --- drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 58 +++++++++++++++++++ drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c | 1 + drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c | 41 ++++++++++++- drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h | 4 ++ .../gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c | 27 +++++++++ .../gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c | 27 +++++++++ .../gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c | 27 +++++++++ drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 5 ++ .../amd/amdkfd/kfd_process_queue_manager.c | 30 ++++++++++ 9 files changed, 219 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index b5338bff8cef4..297b36c26a05c 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -392,6 +392,61 @@ static int kfd_ioctl_update_queue(struct file *filp, struct kfd_process *p, return retval; } +static int kfd_ioctl_set_cu_mask(struct file *filp, struct kfd_process *p, + void *data) +{ + int retval; + const int max_num_cus = 1024; + struct kfd_ioctl_set_cu_mask_args *args = data; + struct queue_properties properties; + uint32_t __user *cu_mask_ptr = (uint32_t __user *)args->cu_mask_ptr; + size_t cu_mask_size = sizeof(uint32_t) * (args->num_cu_mask / 32); + + if ((args->num_cu_mask % 32) != 0) { + pr_debug("num_cu_mask 0x%x must be a multiple of 32", + args->num_cu_mask); + return -EINVAL; + } + + properties.cu_mask_count = args->num_cu_mask; + if (properties.cu_mask_count == 0) { + pr_debug("CU mask cannot be 0"); + return -EINVAL; + } + + /* To prevent an unreasonably large CU mask size, set an arbitrary + * limit of max_num_cus bits. We can then just drop any CU mask bits + * past max_num_cus bits and just use the first max_num_cus bits. + */ + if (properties.cu_mask_count > max_num_cus) { + pr_debug("CU mask cannot be greater than 1024 bits"); + properties.cu_mask_count = max_num_cus; + cu_mask_size = sizeof(uint32_t) * (max_num_cus/32); + } + + properties.cu_mask = kzalloc(cu_mask_size, GFP_KERNEL); + if (!properties.cu_mask) + return -ENOMEM; + + retval = copy_from_user(properties.cu_mask, cu_mask_ptr, cu_mask_size); + if (retval) { + pr_debug("Could not copy CU mask from userspace"); + kfree(properties.cu_mask); + return -EFAULT; + } + + mutex_lock(&p->mutex); + + retval = pqm_set_cu_mask(&p->pqm, args->queue_id, &properties); + + mutex_unlock(&p->mutex); + + if (retval) + kfree(properties.cu_mask); + + return retval; +} + static int kfd_ioctl_set_memory_policy(struct file *filep, struct kfd_process *p, void *data) { @@ -1557,6 +1612,9 @@ static const struct amdkfd_ioctl_desc amdkfd_ioctls[] = { AMDKFD_IOCTL_DEF(AMDKFD_IOC_UNMAP_MEMORY_FROM_GPU, kfd_ioctl_unmap_memory_from_gpu, 0), + AMDKFD_IOCTL_DEF(AMDKFD_IOC_SET_CU_MASK, + kfd_ioctl_set_cu_mask, 0), + }; #define AMDKFD_CORE_IOCTL_COUNT ARRAY_SIZE(amdkfd_ioctls) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c index 2c8897e9073d3..9f84b4d9fb884 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c @@ -123,6 +123,7 @@ static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev, prop.write_ptr = (uint32_t *) kq->wptr_gpu_addr; prop.eop_ring_buffer_address = kq->eop_gpu_addr; prop.eop_ring_buffer_size = PAGE_SIZE; + prop.cu_mask = NULL; if (init_queue(&kq->queue, &prop) != 0) goto err_init_queue; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c index 4b8eb506642b8..3bc25ab84f340 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c @@ -21,7 +21,7 @@ * */ -#include "kfd_priv.h" +#include "kfd_mqd_manager.h" struct mqd_manager *mqd_manager_init(enum KFD_MQD_TYPE type, struct kfd_dev *dev) @@ -48,3 +48,42 @@ struct mqd_manager *mqd_manager_init(enum KFD_MQD_TYPE type, return NULL; } + +void mqd_symmetrically_map_cu_mask(struct mqd_manager *mm, + const uint32_t *cu_mask, uint32_t cu_mask_count, + uint32_t *se_mask) +{ + struct kfd_cu_info cu_info; + uint32_t cu_per_sh[4] = {0}; + int i, se, cu = 0; + + mm->dev->kfd2kgd->get_cu_info(mm->dev->kgd, &cu_info); + + if (cu_mask_count > cu_info.cu_active_number) + cu_mask_count = cu_info.cu_active_number; + + for (se = 0; se < cu_info.num_shader_engines; se++) + for (i = 0; i < 4; i++) + cu_per_sh[se] += hweight32(cu_info.cu_bitmap[se][i]); + + /* Symmetrically map cu_mask to all SEs: + * cu_mask[0] bit0 -> se_mask[0] bit0; + * cu_mask[0] bit1 -> se_mask[1] bit0; + * ... (if # SE is 4) + * cu_mask[0] bit4 -> se_mask[0] bit1; + * ... + */ + se = 0; + for (i = 0; i < cu_mask_count; i++) { + if (cu_mask[i / 32] & (1 << (i % 32))) + se_mask[se] |= 1 << cu; + + do { + se++; + if (se == cu_info.num_shader_engines) { + se = 0; + cu++; + } + } while (cu >= cu_per_sh[se] && cu < 32); + } +} diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h index 8972bcfbf701c..4e84052d4e210 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h @@ -93,4 +93,8 @@ struct mqd_manager { struct kfd_dev *dev; }; +void mqd_symmetrically_map_cu_mask(struct mqd_manager *mm, + const uint32_t *cu_mask, uint32_t cu_mask_count, + uint32_t *se_mask); + #endif /* KFD_MQD_MANAGER_H_ */ diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c index 4872574f7a046..47243165a082a 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c @@ -41,6 +41,31 @@ static inline struct cik_sdma_rlc_registers *get_sdma_mqd(void *mqd) return (struct cik_sdma_rlc_registers *)mqd; } +static void update_cu_mask(struct mqd_manager *mm, void *mqd, + struct queue_properties *q) +{ + struct cik_mqd *m; + uint32_t se_mask[4] = {0}; /* 4 is the max # of SEs */ + + if (q->cu_mask_count == 0) + return; + + mqd_symmetrically_map_cu_mask(mm, + q->cu_mask, q->cu_mask_count, se_mask); + + m = get_mqd(mqd); + m->compute_static_thread_mgmt_se0 = se_mask[0]; + m->compute_static_thread_mgmt_se1 = se_mask[1]; + m->compute_static_thread_mgmt_se2 = se_mask[2]; + m->compute_static_thread_mgmt_se3 = se_mask[3]; + + pr_debug("Update cu mask to %#x %#x %#x %#x\n", + m->compute_static_thread_mgmt_se0, + m->compute_static_thread_mgmt_se1, + m->compute_static_thread_mgmt_se2, + m->compute_static_thread_mgmt_se3); +} + static int init_mqd(struct mqd_manager *mm, void **mqd, struct kfd_mem_obj **mqd_mem_obj, uint64_t *gart_addr, struct queue_properties *q) @@ -196,6 +221,8 @@ static int __update_mqd(struct mqd_manager *mm, void *mqd, if (q->format == KFD_QUEUE_FORMAT_AQL) m->cp_hqd_pq_control |= NO_UPDATE_RPTR; + update_cu_mask(mm, mqd, q); + q->is_active = (q->queue_size > 0 && q->queue_address != 0 && q->queue_percent > 0 && diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c index ad5c9f80cccd5..f5fc3675f21ed 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c @@ -41,6 +41,31 @@ static inline struct v9_sdma_mqd *get_sdma_mqd(void *mqd) return (struct v9_sdma_mqd *)mqd; } +static void update_cu_mask(struct mqd_manager *mm, void *mqd, + struct queue_properties *q) +{ + struct v9_mqd *m; + uint32_t se_mask[4] = {0}; /* 4 is the max # of SEs */ + + if (q->cu_mask_count == 0) + return; + + mqd_symmetrically_map_cu_mask(mm, + q->cu_mask, q->cu_mask_count, se_mask); + + m = get_mqd(mqd); + m->compute_static_thread_mgmt_se0 = se_mask[0]; + m->compute_static_thread_mgmt_se1 = se_mask[1]; + m->compute_static_thread_mgmt_se2 = se_mask[2]; + m->compute_static_thread_mgmt_se3 = se_mask[3]; + + pr_debug("update cu mask to %#x %#x %#x %#x\n", + m->compute_static_thread_mgmt_se0, + m->compute_static_thread_mgmt_se1, + m->compute_static_thread_mgmt_se2, + m->compute_static_thread_mgmt_se3); +} + static int init_mqd(struct mqd_manager *mm, void **mqd, struct kfd_mem_obj **mqd_mem_obj, uint64_t *gart_addr, struct queue_properties *q) @@ -198,6 +223,8 @@ static int update_mqd(struct mqd_manager *mm, void *mqd, if (mm->dev->cwsr_enabled && q->ctx_save_restore_area_address) m->cp_hqd_ctx_save_control = 0; + update_cu_mask(mm, mqd, q); + q->is_active = (q->queue_size > 0 && q->queue_address != 0 && q->queue_percent > 0 && diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c index 89e4242e43e71..b81fda3754dac 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c @@ -43,6 +43,31 @@ static inline struct vi_sdma_mqd *get_sdma_mqd(void *mqd) return (struct vi_sdma_mqd *)mqd; } +static void update_cu_mask(struct mqd_manager *mm, void *mqd, + struct queue_properties *q) +{ + struct vi_mqd *m; + uint32_t se_mask[4] = {0}; /* 4 is the max # of SEs */ + + if (q->cu_mask_count == 0) + return; + + mqd_symmetrically_map_cu_mask(mm, + q->cu_mask, q->cu_mask_count, se_mask); + + m = get_mqd(mqd); + m->compute_static_thread_mgmt_se0 = se_mask[0]; + m->compute_static_thread_mgmt_se1 = se_mask[1]; + m->compute_static_thread_mgmt_se2 = se_mask[2]; + m->compute_static_thread_mgmt_se3 = se_mask[3]; + + pr_debug("Update cu mask to %#x %#x %#x %#x\n", + m->compute_static_thread_mgmt_se0, + m->compute_static_thread_mgmt_se1, + m->compute_static_thread_mgmt_se2, + m->compute_static_thread_mgmt_se3); +} + static int init_mqd(struct mqd_manager *mm, void **mqd, struct kfd_mem_obj **mqd_mem_obj, uint64_t *gart_addr, struct queue_properties *q) @@ -196,6 +221,8 @@ static int __update_mqd(struct mqd_manager *mm, void *mqd, atc_bit << CP_HQD_CTX_SAVE_CONTROL__ATC__SHIFT | mtype << CP_HQD_CTX_SAVE_CONTROL__MTYPE__SHIFT; + update_cu_mask(mm, mqd, q); + q->is_active = (q->queue_size > 0 && q->queue_address != 0 && q->queue_percent > 0 && diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index ca83254719fca..f971710f1c91b 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -422,6 +422,9 @@ struct queue_properties { uint32_t ctl_stack_size; uint64_t tba_addr; uint64_t tma_addr; + /* Relevant for CU */ + uint32_t cu_mask_count; /* Must be a multiple of 32 */ + uint32_t *cu_mask; }; /** @@ -872,6 +875,8 @@ int pqm_create_queue(struct process_queue_manager *pqm, int pqm_destroy_queue(struct process_queue_manager *pqm, unsigned int qid); int pqm_update_queue(struct process_queue_manager *pqm, unsigned int qid, struct queue_properties *p); +int pqm_set_cu_mask(struct process_queue_manager *pqm, unsigned int qid, + struct queue_properties *p); struct kernel_queue *pqm_get_kernel_queue(struct process_queue_manager *pqm, unsigned int qid); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c index eb4e5fb4f2f24..c8cad9c078ae3 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c @@ -325,6 +325,8 @@ int pqm_destroy_queue(struct process_queue_manager *pqm, unsigned int qid) if (retval != -ETIME) goto err_destroy_queue; } + kfree(pqn->q->properties.cu_mask); + pqn->q->properties.cu_mask = NULL; uninit_queue(pqn->q); } @@ -365,6 +367,34 @@ int pqm_update_queue(struct process_queue_manager *pqm, unsigned int qid, return 0; } +int pqm_set_cu_mask(struct process_queue_manager *pqm, unsigned int qid, + struct queue_properties *p) +{ + int retval; + struct process_queue_node *pqn; + + pqn = get_queue_by_qid(pqm, qid); + if (!pqn) { + pr_debug("No queue %d exists for update operation\n", qid); + return -EFAULT; + } + + /* Free the old CU mask memory if it is already allocated, then + * allocate memory for the new CU mask. + */ + kfree(pqn->q->properties.cu_mask); + + pqn->q->properties.cu_mask_count = p->cu_mask_count; + pqn->q->properties.cu_mask = p->cu_mask; + + retval = pqn->q->device->dqm->ops.update_queue(pqn->q->device->dqm, + pqn->q); + if (retval != 0) + return retval; + + return 0; +} + struct kernel_queue *pqm_get_kernel_queue( struct process_queue_manager *pqm, unsigned int qid) -- GitLab From bdf4424dc3b180e40718034a30eced5c1eac8588 Mon Sep 17 00:00:00 2001 From: Ben Skeggs <bskeggs@redhat.com> Date: Wed, 30 May 2018 15:36:42 +1000 Subject: [PATCH 1173/1506] drm/nouveau/gr/gv100: handle multiple SM-per-TPC for shader exceptions Signed-off-by: Ben Skeggs <bskeggs@redhat.com> --- .../gpu/drm/nouveau/nvkm/engine/gr/gv100.c | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gv100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gv100.c index 19173ea190962..3b3327789ae78 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gv100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gv100.c @@ -25,24 +25,31 @@ #include <nvif/class.h> static void -gv100_gr_trap_mp(struct gf100_gr *gr, int gpc, int tpc) +gv100_gr_trap_sm(struct gf100_gr *gr, int gpc, int tpc, int sm) { struct nvkm_subdev *subdev = &gr->base.engine.subdev; struct nvkm_device *device = subdev->device; - u32 werr = nvkm_rd32(device, TPC_UNIT(gpc, tpc, 0x730)); - u32 gerr = nvkm_rd32(device, TPC_UNIT(gpc, tpc, 0x734)); + u32 werr = nvkm_rd32(device, TPC_UNIT(gpc, tpc, 0x730 + (sm * 0x80))); + u32 gerr = nvkm_rd32(device, TPC_UNIT(gpc, tpc, 0x734 + (sm * 0x80))); const struct nvkm_enum *warp; char glob[128]; nvkm_snprintbf(glob, sizeof(glob), gf100_mp_global_error, gerr); warp = nvkm_enum_find(gf100_mp_warp_error, werr & 0xffff); - nvkm_error(subdev, "GPC%i/TPC%i/MP trap: " + nvkm_error(subdev, "GPC%i/TPC%i/SM%d trap: " "global %08x [%s] warp %04x [%s]\n", - gpc, tpc, gerr, glob, werr, warp ? warp->name : ""); + gpc, tpc, sm, gerr, glob, werr, warp ? warp->name : ""); + + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x730 + sm * 0x80), 0x00000000); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x734 + sm * 0x80), gerr); +} - nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x730), 0x00000000); - nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x734), gerr); +static void +gv100_gr_trap_mp(struct gf100_gr *gr, int gpc, int tpc) +{ + gv100_gr_trap_sm(gr, gpc, tpc, 0); + gv100_gr_trap_sm(gr, gpc, tpc, 1); } static void -- GitLab From 60cda665724a33af1486d0a84190b384f180bb0e Mon Sep 17 00:00:00 2001 From: Ben Skeggs <bskeggs@redhat.com> Date: Wed, 13 Jun 2018 15:33:16 +1000 Subject: [PATCH 1174/1506] drm/nouveau/fault/gv100: fix fault buffer initialisation Not sure how this happened, it worked last time I tested it! Signed-off-by: Ben Skeggs <bskeggs@redhat.com> --- .../gpu/drm/nouveau/nvkm/subdev/fault/base.c | 10 +++++++-- .../gpu/drm/nouveau/nvkm/subdev/fault/gv100.c | 21 +++++++++---------- .../gpu/drm/nouveau/nvkm/subdev/fault/priv.h | 1 + 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/base.c index 007bf4af33b99..16ad91c91a7be 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/base.c @@ -133,8 +133,14 @@ nvkm_fault_oneinit(struct nvkm_subdev *subdev) } } - return nvkm_event_init(&nvkm_fault_ntfy, 1, fault->buffer_nr, - &fault->event); + ret = nvkm_event_init(&nvkm_fault_ntfy, 1, fault->buffer_nr, + &fault->event); + if (ret) + return ret; + + if (fault->func->oneinit) + ret = fault->func->oneinit(fault); + return ret; } static void * diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/gv100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/gv100.c index 73c7728b59696..3cd610d7deb52 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/gv100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/gv100.c @@ -176,8 +176,17 @@ gv100_fault_init(struct nvkm_fault *fault) nvkm_notify_get(&fault->nrpfb); } +static int +gv100_fault_oneinit(struct nvkm_fault *fault) +{ + return nvkm_notify_init(&fault->buffer[0]->object, &fault->event, + gv100_fault_ntfy_nrpfb, false, NULL, 0, 0, + &fault->nrpfb); +} + static const struct nvkm_fault_func gv100_fault = { + .oneinit = gv100_fault_oneinit, .init = gv100_fault_init, .fini = gv100_fault_fini, .intr = gv100_fault_intr, @@ -192,15 +201,5 @@ int gv100_fault_new(struct nvkm_device *device, int index, struct nvkm_fault **pfault) { - struct nvkm_fault *fault; - int ret; - - ret = nvkm_fault_new_(&gv100_fault, device, index, &fault); - *pfault = fault; - if (ret) - return ret; - - return nvkm_notify_init(&fault->buffer[0]->object, &fault->event, - gv100_fault_ntfy_nrpfb, false, NULL, 0, 0, - &fault->nrpfb); + return nvkm_fault_new_(&gv100_fault, device, index, pfault); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/priv.h index 44843ecf12b07..e4d2f5234fd19 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fault/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fault/priv.h @@ -20,6 +20,7 @@ int nvkm_fault_new_(const struct nvkm_fault_func *, struct nvkm_device *, int index, struct nvkm_fault **); struct nvkm_fault_func { + int (*oneinit)(struct nvkm_fault *); void (*init)(struct nvkm_fault *); void (*fini)(struct nvkm_fault *); void (*intr)(struct nvkm_fault *); -- GitLab From 3c9f27eeedb76fb65fc572adbb58d7f4ca154536 Mon Sep 17 00:00:00 2001 From: Nicolas Chauvet <kwizart@gmail.com> Date: Sun, 10 Jun 2018 13:01:31 +0200 Subject: [PATCH 1175/1506] drm/nouveau/secboot/tegra: Enable gp20b/gp10b firmware tag when relevant This allows to have the related MODULE_FIRMWARE tag only on relevant arch (arm64). This will saves about 400k on initramfs when not relevant Signed-off-by: Nicolas Chauvet <kwizart@gmail.com> Acked-by: Thierry Reding <treding@nvidia.com> Signed-off-by: Ben Skeggs <bskeggs@redhat.com> --- drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm20b.c | 2 ++ drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gp10b.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm20b.c index 30491d132d59c..df8b919dcf09b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm20b.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm20b.c @@ -129,6 +129,7 @@ gm20b_secboot_new(struct nvkm_device *device, int index, return 0; } +#if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC) MODULE_FIRMWARE("nvidia/gm20b/acr/bl.bin"); MODULE_FIRMWARE("nvidia/gm20b/acr/ucode_load.bin"); MODULE_FIRMWARE("nvidia/gm20b/gr/fecs_bl.bin"); @@ -144,3 +145,4 @@ MODULE_FIRMWARE("nvidia/gm20b/gr/sw_method_init.bin"); MODULE_FIRMWARE("nvidia/gm20b/pmu/desc.bin"); MODULE_FIRMWARE("nvidia/gm20b/pmu/image.bin"); MODULE_FIRMWARE("nvidia/gm20b/pmu/sig.bin"); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gp10b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gp10b.c index 632e9545e2923..28ca29d0eeeeb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gp10b.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gp10b.c @@ -74,6 +74,7 @@ gp10b_secboot_new(struct nvkm_device *device, int index, return 0; } +#if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC) MODULE_FIRMWARE("nvidia/gp10b/acr/bl.bin"); MODULE_FIRMWARE("nvidia/gp10b/acr/ucode_load.bin"); MODULE_FIRMWARE("nvidia/gp10b/gr/fecs_bl.bin"); @@ -91,3 +92,4 @@ MODULE_FIRMWARE("nvidia/gp10b/gr/sw_method_init.bin"); MODULE_FIRMWARE("nvidia/gp10b/pmu/desc.bin"); MODULE_FIRMWARE("nvidia/gp10b/pmu/image.bin"); MODULE_FIRMWARE("nvidia/gp10b/pmu/sig.bin"); +#endif -- GitLab From f0fffeeb149e6d1fe05f2c8d6e385c5e82814cff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Glisse?= <jglisse@redhat.com> Date: Thu, 7 Jun 2018 14:18:24 -0400 Subject: [PATCH 1176/1506] drm/nouveau/mmu/gp10b: remove ghost file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This ghost file have been haunting us. Signed-off-by: Jérôme Glisse <jglisse@redhat.com> Signed-off-by: Ben Skeggs <bskeggs@redhat.com> --- drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gp10b. | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gp10b. diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gp10b. b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gp10b. deleted file mode 100644 index e69de29bb2d1d..0000000000000 -- GitLab From f7fbbf2ccaa0f557c4615a5cf3e1e5704585628a Mon Sep 17 00:00:00 2001 From: Ben Skeggs <bskeggs@redhat.com> Date: Fri, 15 Jun 2018 07:59:28 +1000 Subject: [PATCH 1177/1506] drm/nouveau/core: ERR_PTR vs NULL bug in nvkm_engine_info() Reported-by: Dan Carpenter <dan.carpenter@oracle.com> Signed-off-by: Ben Skeggs <bskeggs@redhat.com> --- drivers/gpu/drm/nouveau/nvkm/core/engine.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/core/engine.c b/drivers/gpu/drm/nouveau/nvkm/core/engine.c index d0322ce85172a..1a47c40e171b3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/engine.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/engine.c @@ -87,11 +87,12 @@ nvkm_engine_info(struct nvkm_subdev *subdev, u64 mthd, u64 *data) { struct nvkm_engine *engine = nvkm_engine(subdev); if (engine->func->info) { - if ((engine = nvkm_engine_ref(engine))) { + if (!IS_ERR((engine = nvkm_engine_ref(engine)))) { int ret = engine->func->info(engine, mthd, data); nvkm_engine_unref(&engine); return ret; } + return PTR_ERR(engine); } return -ENOSYS; } -- GitLab From 7a26c92367a7195277bf663eca69c55b863b4d7b Mon Sep 17 00:00:00 2001 From: Ben Skeggs <bskeggs@redhat.com> Date: Fri, 15 Jun 2018 08:02:33 +1000 Subject: [PATCH 1178/1506] drm/nouveau/disp/nv50-gp10x: fix coverity warning Change values to u32, there's no need for them to be 64-bit. Reported-by: Colin Ian King <colin.king@canonical.com> Suggested-by: Ilia Mirkin <imirkin@alum.mit.edu> Signed-off-by: Ben Skeggs <bskeggs@redhat.com> --- drivers/gpu/drm/nouveau/nvkm/engine/disp/changf119.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/changf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/changf119.c index 29e6dd58ac48c..525f95d064290 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/changf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/changf119.c @@ -52,7 +52,7 @@ void gf119_disp_chan_intr(struct nv50_disp_chan *chan, bool en) { struct nvkm_device *device = chan->disp->base.engine.subdev.device; - const u64 mask = 0x00000001 << chan->chid.user; + const u32 mask = 0x00000001 << chan->chid.user; if (!en) { nvkm_mask(device, 0x610090, mask, 0x00000000); nvkm_mask(device, 0x6100a0, mask, 0x00000000); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c index 57719f675eec9..bcf32d92ee5a9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c @@ -166,8 +166,8 @@ void nv50_disp_chan_intr(struct nv50_disp_chan *chan, bool en) { struct nvkm_device *device = chan->disp->base.engine.subdev.device; - const u64 mask = 0x00010001 << chan->chid.user; - const u64 data = en ? 0x00010000 : 0x00000000; + const u32 mask = 0x00010001 << chan->chid.user; + const u32 data = en ? 0x00010000 << chan->chid.user : 0x00000000; nvkm_mask(device, 0x610028, mask, data); } -- GitLab From 01981aeb4745e31e0842b6f9f98be9b99615db3c Mon Sep 17 00:00:00 2001 From: kbuild test robot <fengguang.wu@intel.com> Date: Fri, 18 May 2018 18:51:32 +0200 Subject: [PATCH 1179/1506] drm/nouveau/kms/nv50-: fix drm-get-put.cocci warnings Use drm_*_get() and drm_*_put() helpers instead of drm_*_reference() and drm_*_unreference() helpers. Generated by: scripts/coccinelle/api/drm-get-put.cocci Fixes: 30ed49b55b6e ("drm/nouveau/kms/nv50-: move code underneath dispnv50/") Signed-off-by: kbuild test robot <fengguang.wu@intel.com> Signed-off-by: Julia Lawall <julia.lawall@lip6.fr> Signed-off-by: Ben Skeggs <bskeggs@redhat.com> --- drivers/gpu/drm/nouveau/dispnv50/disp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index b83465ae7c1bc..1f8bba8f65281 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -1007,7 +1007,7 @@ nv50_mstm_destroy_connector(struct drm_dp_mst_topology_mgr *mgr, mstc->port = NULL; drm_modeset_unlock(&drm->dev->mode_config.connection_mutex); - drm_connector_unreference(&mstc->connector); + drm_connector_put(&mstc->connector); } static void -- GitLab From 6ec7aecf1f1080d058943d4c44edff470c67679b Mon Sep 17 00:00:00 2001 From: Ben Skeggs <bskeggs@redhat.com> Date: Mon, 18 Jun 2018 17:53:12 +1000 Subject: [PATCH 1180/1506] drm/nouveau/kms/nv50-: remove duplicate assignment Signed-off-by: Ben Skeggs <bskeggs@redhat.com> --- drivers/gpu/drm/nouveau/dispnv50/wndw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndw.c b/drivers/gpu/drm/nouveau/dispnv50/wndw.c index c5a9bc1af5af7..2187922e8dc28 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/wndw.c +++ b/drivers/gpu/drm/nouveau/dispnv50/wndw.c @@ -586,7 +586,6 @@ nv50_wndw_new_(const struct nv50_wndw_func *func, struct drm_device *dev, wndw->id = index; wndw->interlock.type = interlock_type; wndw->interlock.data = interlock_data; - wndw->ctxdma.parent = &wndw->wndw.base.user; wndw->ctxdma.parent = &wndw->wndw.base.user; INIT_LIST_HEAD(&wndw->ctxdma.list); -- GitLab From 2ae4c5f6ff7310e4dcaca4378ddadd881d176693 Mon Sep 17 00:00:00 2001 From: Mario Kleiner <mario.kleiner.de@gmail.com> Date: Mon, 16 Jul 2018 16:47:50 +1000 Subject: [PATCH 1181/1506] drm/nouveau/kms/nv50-: Allow vblank_disable_immediate With instantaneous high precision vblank timestamping that updates at leading edge of vblank, the emulated "hw vblank counter" from vblank timestamping, which increments at leading edge of vblank, and reliable page flip execution and completion at leading edge of vblank, we should meet the requirements for fast/ immediate vblank irq disable/enable. This is only allowed on nv50+ gpu's, ie. the ones with atomic modesetting. One requirement for immediate vblank disable is that high precision vblank timestamping works reliably all the time on all connectors. This is not the case on all pre-nv50 parts for analog VGA outputs, where we currently don't always have support for scanout position queries and therefore fall back to vblank interrupt timestamping. The implementation in nv04_head_state() does not return valid values for vblanks, vtotal, hblanks, htotal for VGA outputs on all cards, but those are needed for scanout position queries. Testing on Linux-4.12-rc5 + drm-next on a GeForce 9500 GT (NV G96) with timing measurement equipment indicates this works fine, so allow immediate vblank disable for power saving. For debugging in case of unexpected trouble, booting with kernel cmdline option drm.vblankoffdelay=0 (or echo 0 > /sys/module/drm/parameters/vblankoffdelay) would keep vblank irqs permanently on to approximate old behavior. Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com> Signed-off-by: Ben Skeggs <bskeggs@redhat.com> --- drivers/gpu/drm/nouveau/dispnv50/disp.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 1f8bba8f65281..7d00d833bbe5a 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -2231,6 +2231,9 @@ nv50_display_create(struct drm_device *dev) connector->funcs->destroy(connector); } + /* Disable vblank irqs aggressively for power-saving, safe on nv50+ */ + dev->vblank_disable_immediate = true; + out: if (ret) nv50_display_destroy(dev); -- GitLab From f706037c4e135d322160e201872ee3567435035a Mon Sep 17 00:00:00 2001 From: Karol Herbst <karolherbst@gmail.com> Date: Sat, 14 Jul 2018 12:52:08 +0200 Subject: [PATCH 1182/1506] drm/nouveau/bios/vpstate: There are some fermi vbios with no boost or tdp entry If the entry size is too small, default to invalid values for both boost_id and tdp_id, so as to default to the base clock in both cases. Signed-off-by: Karol Herbst <karolherbst@gmail.com> Signed-off-by: Martin Peres <martin.peres@free.fr> Signed-off-by: Ben Skeggs <bskeggs@redhat.com> --- drivers/gpu/drm/nouveau/nvkm/subdev/bios/vpstate.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/vpstate.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/vpstate.c index 20b6fc8243e0a..71524548de32c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/vpstate.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/vpstate.c @@ -58,8 +58,14 @@ nvbios_vpstate_parse(struct nvkm_bios *b, struct nvbios_vpstate_header *h) h->ecount = nvbios_rd08(b, h->offset + 0x5); h->base_id = nvbios_rd08(b, h->offset + 0x0f); - h->boost_id = nvbios_rd08(b, h->offset + 0x10); - h->tdp_id = nvbios_rd08(b, h->offset + 0x11); + if (h->hlen > 0x10) + h->boost_id = nvbios_rd08(b, h->offset + 0x10); + else + h->boost_id = 0xff; + if (h->hlen > 0x11) + h->tdp_id = nvbios_rd08(b, h->offset + 0x11); + else + h->tdp_id = 0xff; return 0; default: return -EINVAL; -- GitLab From eaeb9010bb4bcdc20e58254fa42f3fe730a7f908 Mon Sep 17 00:00:00 2001 From: Karol Herbst <karolherbst@gmail.com> Date: Sat, 14 Jul 2018 12:52:09 +0200 Subject: [PATCH 1183/1506] drm/nouveau/debugfs: Wake up GPU before doing any reclocking Fixes various reclocking related issues on prime systems. Signed-off-by: Karol Herbst <karolherbst@gmail.com> Signed-off-by: Martin Peres <martin.peres@free.fr> Signed-off-by: Ben Skeggs <bskeggs@redhat.com> --- drivers/gpu/drm/nouveau/nouveau_debugfs.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nouveau_debugfs.c b/drivers/gpu/drm/nouveau/nouveau_debugfs.c index 963a4dba8213e..9109b69cd0529 100644 --- a/drivers/gpu/drm/nouveau/nouveau_debugfs.c +++ b/drivers/gpu/drm/nouveau/nouveau_debugfs.c @@ -160,7 +160,11 @@ nouveau_debugfs_pstate_set(struct file *file, const char __user *ubuf, args.ustate = value; } + ret = pm_runtime_get_sync(drm->dev); + if (IS_ERR_VALUE(ret) && ret != -EACCES) + return ret; ret = nvif_mthd(ctrl, NVIF_CONTROL_PSTATE_USER, &args, sizeof(args)); + pm_runtime_put_autosuspend(drm->dev); if (ret < 0) return ret; -- GitLab From 922a8c82fafdec99688bbaea6c5889f562a42cdc Mon Sep 17 00:00:00 2001 From: Lyude Paul <lyude@redhat.com> Date: Thu, 12 Jul 2018 13:02:52 -0400 Subject: [PATCH 1184/1506] drm/nouveau: Fix runtime PM leak in drm_open() Noticed this as I was skimming through, if we fail to allocate memory for cli we'll end up returning without dropping the runtime PM ref we got. Additionally, we'll even return the wrong return code! (ret most likely will == 0 here, we want -ENOMEM). Signed-off-by: Lyude Paul <lyude@redhat.com> Reviewed-by: Lukas Wunner <lukas@wunner.de> Signed-off-by: Ben Skeggs <bskeggs@redhat.com> --- drivers/gpu/drm/nouveau/nouveau_drm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 775443c9af943..c779ee3c665b0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -912,8 +912,10 @@ nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv) get_task_comm(tmpname, current); snprintf(name, sizeof(name), "%s[%d]", tmpname, pid_nr(fpriv->pid)); - if (!(cli = kzalloc(sizeof(*cli), GFP_KERNEL))) - return ret; + if (!(cli = kzalloc(sizeof(*cli), GFP_KERNEL))) { + ret = -ENOMEM; + goto done; + } ret = nouveau_cli_init(drm, name, cli); if (ret) -- GitLab From da71f0efe714ecf71d450f882b94e2acd8e0c3c0 Mon Sep 17 00:00:00 2001 From: Dan Carpenter <dan.carpenter@oracle.com> Date: Wed, 11 Jul 2018 11:02:28 +0300 Subject: [PATCH 1185/1506] drm/nouveau/hwmon: potential uninitialized variables Smatch complains that "value" can be uninitialized when kstrtol() returns -ERANGE. Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com> Signed-off-by: Ben Skeggs <bskeggs@redhat.com> --- drivers/gpu/drm/nouveau/nouveau_hwmon.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_hwmon.c b/drivers/gpu/drm/nouveau/nouveau_hwmon.c index 44178b4c35998..08a1ab6b150d0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_hwmon.c +++ b/drivers/gpu/drm/nouveau/nouveau_hwmon.c @@ -69,8 +69,8 @@ nouveau_hwmon_set_temp1_auto_point1_temp(struct device *d, struct nvkm_therm *therm = nvxx_therm(&drm->client.device); long value; - if (kstrtol(buf, 10, &value) == -EINVAL) - return count; + if (kstrtol(buf, 10, &value)) + return -EINVAL; therm->attr_set(therm, NVKM_THERM_ATTR_THRS_FAN_BOOST, value / 1000); @@ -102,8 +102,8 @@ nouveau_hwmon_set_temp1_auto_point1_temp_hyst(struct device *d, struct nvkm_therm *therm = nvxx_therm(&drm->client.device); long value; - if (kstrtol(buf, 10, &value) == -EINVAL) - return count; + if (kstrtol(buf, 10, &value)) + return -EINVAL; therm->attr_set(therm, NVKM_THERM_ATTR_THRS_FAN_BOOST_HYST, value / 1000); @@ -156,7 +156,7 @@ nouveau_hwmon_set_pwm1_min(struct device *d, struct device_attribute *a, long value; int ret; - if (kstrtol(buf, 10, &value) == -EINVAL) + if (kstrtol(buf, 10, &value)) return -EINVAL; ret = therm->attr_set(therm, NVKM_THERM_ATTR_FAN_MIN_DUTY, value); @@ -179,7 +179,7 @@ nouveau_hwmon_set_pwm1_max(struct device *d, struct device_attribute *a, long value; int ret; - if (kstrtol(buf, 10, &value) == -EINVAL) + if (kstrtol(buf, 10, &value)) return -EINVAL; ret = therm->attr_set(therm, NVKM_THERM_ATTR_FAN_MAX_DUTY, value); -- GitLab From c9fb2cc84c31910e710cdd8d67a01473170ea67d Mon Sep 17 00:00:00 2001 From: Nick Desaulniers <ndesaulniers@google.com> Date: Fri, 15 Jun 2018 16:00:42 -0700 Subject: [PATCH 1186/1506] drm/nouveau/nvif: remove const attribute from nvif_mclass Similar to commit 0bf8bf50eddc ("module: Remove const attribute from alias for MODULE_DEVICE_TABLE") Fixes many -Wduplicate-decl-specifier warnings due to the combination of const typeof() of already const variables. Signed-off-by: Nick Desaulniers <ndesaulniers@google.com> Reviewed-by: Matthias Kaehlcke <mka@chromium.org> Signed-off-by: Ben Skeggs <bskeggs@redhat.com> --- drivers/gpu/drm/nouveau/include/nvif/object.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/object.h b/drivers/gpu/drm/nouveau/include/nvif/object.h index 20754d9e68838..8407651f6ac6e 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/object.h +++ b/drivers/gpu/drm/nouveau/include/nvif/object.h @@ -78,7 +78,7 @@ struct nvif_mclass { #define nvif_mclass(o,m) ({ \ struct nvif_object *object = (o); \ struct nvif_sclass *sclass; \ - const typeof(m[0]) *mclass = (m); \ + typeof(m[0]) *mclass = (m); \ int ret = -ENODEV; \ int cnt, i, j; \ \ -- GitLab From f066f7950708d889f59545c6c9f426885dcf3dcb Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann <tdz@users.sourceforge.net> Date: Mon, 18 Jun 2018 14:53:10 +0200 Subject: [PATCH 1187/1506] drm/nouveau: Replace drm_framebuffer_{un/reference} with put, get functions This patch unifies the naming of DRM functions for reference counting of struct drm_framebuffer. The resulting code is more aligned with the rest of the Linux kernel interfaces. Signed-off-by: Thomas Zimmermann <tdz@users.sourceforge.net> Signed-off-by: Ben Skeggs <bskeggs@redhat.com> --- drivers/gpu/drm/nouveau/nouveau_fbcon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 85c1f10bc2b67..844498c4267cb 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -429,7 +429,7 @@ nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *fbcon) nouveau_vma_del(&nouveau_fb->vma); nouveau_bo_unmap(nouveau_fb->nvbo); nouveau_bo_unpin(nouveau_fb->nvbo); - drm_framebuffer_unreference(&nouveau_fb->base); + drm_framebuffer_put(&nouveau_fb->base); } return 0; -- GitLab From 743e0f079a38182cb22e663b34e6a45ad3274b9e Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann <tdz@users.sourceforge.net> Date: Mon, 18 Jun 2018 14:53:11 +0200 Subject: [PATCH 1188/1506] drm/nouveau: Replace drm_gem_object_unreference_unlocked with put function This patch unifies the naming of DRM functions for reference counting of struct drm_gem_object. The resulting code is more aligned with the rest of the Linux kernel interfaces. Signed-off-by: Thomas Zimmermann <tdz@users.sourceforge.net> Signed-off-by: Ben Skeggs <bskeggs@redhat.com> --- drivers/gpu/drm/nouveau/dispnv04/crtc.c | 2 +- drivers/gpu/drm/nouveau/nouveau_abi16.c | 2 +- drivers/gpu/drm/nouveau/nouveau_display.c | 8 ++++---- drivers/gpu/drm/nouveau/nouveau_gem.c | 14 +++++++------- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c index 6aa6ee16dcbdc..2c569e264df37 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c +++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c @@ -1017,7 +1017,7 @@ nv04_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, nv_crtc->cursor.set_offset(nv_crtc, nv_crtc->cursor.offset); nv_crtc->cursor.show(nv_crtc, true); out: - drm_gem_object_unreference_unlocked(gem); + drm_gem_object_put_unlocked(gem); return ret; } diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index e2211bb2cf79e..e67a471331b51 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -139,7 +139,7 @@ nouveau_abi16_chan_fini(struct nouveau_abi16 *abi16, if (chan->ntfy) { nouveau_vma_del(&chan->ntfy_vma); nouveau_bo_unpin(chan->ntfy); - drm_gem_object_unreference_unlocked(&chan->ntfy->gem); + drm_gem_object_put_unlocked(&chan->ntfy->gem); } if (chan->heap.block_size) diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 774b429142bc8..dfa2363707269 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -205,7 +205,7 @@ nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb) struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb); if (fb->nvbo) - drm_gem_object_unreference_unlocked(&fb->nvbo->gem); + drm_gem_object_put_unlocked(&fb->nvbo->gem); drm_framebuffer_cleanup(drm_fb); kfree(fb); @@ -287,7 +287,7 @@ nouveau_user_framebuffer_create(struct drm_device *dev, if (ret == 0) return &fb->base; - drm_gem_object_unreference_unlocked(gem); + drm_gem_object_put_unlocked(gem); return ERR_PTR(ret); } @@ -939,7 +939,7 @@ nouveau_display_dumb_create(struct drm_file *file_priv, struct drm_device *dev, return ret; ret = drm_gem_handle_create(file_priv, &bo->gem, &args->handle); - drm_gem_object_unreference_unlocked(&bo->gem); + drm_gem_object_put_unlocked(&bo->gem); return ret; } @@ -954,7 +954,7 @@ nouveau_display_dumb_map_offset(struct drm_file *file_priv, if (gem) { struct nouveau_bo *bo = nouveau_gem_object(gem); *poffset = drm_vma_node_offset_addr(&bo->bo.vma_node); - drm_gem_object_unreference_unlocked(gem); + drm_gem_object_put_unlocked(gem); return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 300daee74209a..df73bec354e8d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -274,7 +274,7 @@ nouveau_gem_ioctl_new(struct drm_device *dev, void *data, } /* drop reference from allocate - handle holds it now */ - drm_gem_object_unreference_unlocked(&nvbo->gem); + drm_gem_object_put_unlocked(&nvbo->gem); return ret; } @@ -354,7 +354,7 @@ validate_fini_no_ticket(struct validate_op *op, struct nouveau_fence *fence, list_del(&nvbo->entry); nvbo->reserved_by = NULL; ttm_bo_unreserve(&nvbo->bo); - drm_gem_object_unreference_unlocked(&nvbo->gem); + drm_gem_object_put_unlocked(&nvbo->gem); } } @@ -400,14 +400,14 @@ validate_init(struct nouveau_channel *chan, struct drm_file *file_priv, nvbo = nouveau_gem_object(gem); if (nvbo == res_bo) { res_bo = NULL; - drm_gem_object_unreference_unlocked(gem); + drm_gem_object_put_unlocked(gem); continue; } if (nvbo->reserved_by && nvbo->reserved_by == file_priv) { NV_PRINTK(err, cli, "multiple instances of buffer %d on " "validation list\n", b->handle); - drm_gem_object_unreference_unlocked(gem); + drm_gem_object_put_unlocked(gem); ret = -EINVAL; break; } @@ -894,7 +894,7 @@ nouveau_gem_ioctl_cpu_prep(struct drm_device *dev, void *data, ret = lret; nouveau_bo_sync_for_cpu(nvbo); - drm_gem_object_unreference_unlocked(gem); + drm_gem_object_put_unlocked(gem); return ret; } @@ -913,7 +913,7 @@ nouveau_gem_ioctl_cpu_fini(struct drm_device *dev, void *data, nvbo = nouveau_gem_object(gem); nouveau_bo_sync_for_device(nvbo); - drm_gem_object_unreference_unlocked(gem); + drm_gem_object_put_unlocked(gem); return 0; } @@ -930,7 +930,7 @@ nouveau_gem_ioctl_info(struct drm_device *dev, void *data, return -ENOENT; ret = nouveau_gem_info(file_priv, gem, req); - drm_gem_object_unreference_unlocked(gem); + drm_gem_object_put_unlocked(gem); return ret; } -- GitLab From 94a0b8634f4ccb0a512702f96df67914b615d556 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann <tdz@users.sourceforge.net> Date: Mon, 18 Jun 2018 14:53:12 +0200 Subject: [PATCH 1189/1506] drm/nouveau: 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 <tdz@users.sourceforge.net> Signed-off-by: Ben Skeggs <bskeggs@redhat.com> --- drivers/gpu/drm/nouveau/nouveau_platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_platform.c b/drivers/gpu/drm/nouveau/nouveau_platform.c index 1ada186fab770..039e23548e08f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_platform.c +++ b/drivers/gpu/drm/nouveau/nouveau_platform.c @@ -36,7 +36,7 @@ static int nouveau_platform_probe(struct platform_device *pdev) ret = drm_dev_register(drm, 0); if (ret < 0) { - drm_dev_unref(drm); + drm_dev_put(drm); return ret; } -- GitLab From 0d466901552a8b4e80cb3c0968e344751c2c9ac3 Mon Sep 17 00:00:00 2001 From: Kees Cook <keescook@chromium.org> Date: Thu, 24 May 2018 10:24:36 -0700 Subject: [PATCH 1190/1506] drm/nouveau/secboot/acr: Remove VLA usage In the quest to remove all stack VLA usage from the kernel[1], this allocates the working buffers before starting the writing so it won't abort in the middle. This needs an initial walk of the lists to figure out how large the buffer should be. [1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com Signed-off-by: Kees Cook <keescook@chromium.org> Signed-off-by: Ben Skeggs <bskeggs@redhat.com> --- .../nouveau/nvkm/subdev/secboot/acr_r352.c | 25 ++++++++++++++++--- .../nouveau/nvkm/subdev/secboot/acr_r367.c | 16 +++++++++++- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r352.c b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r352.c index a721354249ce6..d02e183717dc4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r352.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r352.c @@ -414,6 +414,20 @@ acr_r352_ls_write_wpr(struct acr_r352 *acr, struct list_head *imgs, { struct ls_ucode_img *_img; u32 pos = 0; + u32 max_desc_size = 0; + u8 *gdesc; + + /* Figure out how large we need gdesc to be. */ + list_for_each_entry(_img, imgs, node) { + const struct acr_r352_ls_func *ls_func = + acr->func->ls_func[_img->falcon_id]; + + max_desc_size = max(max_desc_size, ls_func->bl_desc_size); + } + + gdesc = kmalloc(max_desc_size, GFP_KERNEL); + if (!gdesc) + return -ENOMEM; nvkm_kmap(wpr_blob); @@ -421,7 +435,6 @@ acr_r352_ls_write_wpr(struct acr_r352 *acr, struct list_head *imgs, struct ls_ucode_img_r352 *img = ls_ucode_img_r352(_img); const struct acr_r352_ls_func *ls_func = acr->func->ls_func[_img->falcon_id]; - u8 gdesc[ls_func->bl_desc_size]; nvkm_gpuobj_memcpy_to(wpr_blob, pos, &img->wpr_header, sizeof(img->wpr_header)); @@ -447,6 +460,8 @@ acr_r352_ls_write_wpr(struct acr_r352 *acr, struct list_head *imgs, nvkm_done(wpr_blob); + kfree(gdesc); + return 0; } @@ -771,7 +786,11 @@ acr_r352_load(struct nvkm_acr *_acr, struct nvkm_falcon *falcon, struct fw_bl_desc *hsbl_desc; void *bl, *blob_data, *hsbl_code, *hsbl_data; u32 code_size; - u8 bl_desc[bl_desc_size]; + u8 *bl_desc; + + bl_desc = kzalloc(bl_desc_size, GFP_KERNEL); + if (!bl_desc) + return -ENOMEM; /* Find the bootloader descriptor for our blob and copy it */ if (blob == acr->load_blob) { @@ -802,7 +821,6 @@ acr_r352_load(struct nvkm_acr *_acr, struct nvkm_falcon *falcon, code_size, hsbl_desc->start_tag, 0, false); /* Generate the BL header */ - memset(bl_desc, 0, bl_desc_size); acr->func->generate_hs_bl_desc(load_hdr, bl_desc, offset); /* @@ -811,6 +829,7 @@ acr_r352_load(struct nvkm_acr *_acr, struct nvkm_falcon *falcon, nvkm_falcon_load_dmem(falcon, bl_desc, hsbl_desc->dmem_load_off, bl_desc_size, 0); + kfree(bl_desc); return hsbl_desc->start_tag << 8; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r367.c b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r367.c index 866877b88797b..978ad07903670 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r367.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r367.c @@ -265,6 +265,19 @@ acr_r367_ls_write_wpr(struct acr_r352 *acr, struct list_head *imgs, { struct ls_ucode_img *_img; u32 pos = 0; + u32 max_desc_size = 0; + u8 *gdesc; + + list_for_each_entry(_img, imgs, node) { + const struct acr_r352_ls_func *ls_func = + acr->func->ls_func[_img->falcon_id]; + + max_desc_size = max(max_desc_size, ls_func->bl_desc_size); + } + + gdesc = kmalloc(max_desc_size, GFP_KERNEL); + if (!gdesc) + return -ENOMEM; nvkm_kmap(wpr_blob); @@ -272,7 +285,6 @@ acr_r367_ls_write_wpr(struct acr_r352 *acr, struct list_head *imgs, struct ls_ucode_img_r367 *img = ls_ucode_img_r367(_img); const struct acr_r352_ls_func *ls_func = acr->func->ls_func[_img->falcon_id]; - u8 gdesc[ls_func->bl_desc_size]; nvkm_gpuobj_memcpy_to(wpr_blob, pos, &img->wpr_header, sizeof(img->wpr_header)); @@ -298,6 +310,8 @@ acr_r367_ls_write_wpr(struct acr_r352 *acr, struct list_head *imgs, nvkm_done(wpr_blob); + kfree(gdesc); + return 0; } -- GitLab From 1874619a7df4b14b23b14877e705ae15325773e3 Mon Sep 17 00:00:00 2001 From: Thierry Reding <treding@nvidia.com> Date: Wed, 30 May 2018 16:06:24 +0200 Subject: [PATCH 1191/1506] ARM: dma-mapping: Set proper DMA ops in arm_iommu_detach_device() Instead of setting the DMA ops pointer to NULL, set the correct, non-IOMMU ops depending on the device's coherency setting. Signed-off-by: Thierry Reding <treding@nvidia.com> Reviewed-by: Robin Murphy <robin.murphy@arm.com> Acked-by: Russell King <rmk+kernel@armlinux.org.uk> Acked-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Ben Skeggs <bskeggs@redhat.com> --- arch/arm/mm/dma-mapping.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index be0fa7e39c262..ba0e786c952e7 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -1151,6 +1151,11 @@ int arm_dma_supported(struct device *dev, u64 mask) return __dma_supported(dev, mask, false); } +static const struct dma_map_ops *arm_get_dma_map_ops(bool coherent) +{ + return coherent ? &arm_coherent_dma_ops : &arm_dma_ops; +} + #ifdef CONFIG_ARM_DMA_USE_IOMMU static int __dma_info_to_prot(enum dma_data_direction dir, unsigned long attrs) @@ -2296,7 +2301,7 @@ void arm_iommu_detach_device(struct device *dev) iommu_detach_device(mapping->domain, dev); kref_put(&mapping->kref, release_iommu_mapping); to_dma_iommu_mapping(dev) = NULL; - set_dma_ops(dev, NULL); + set_dma_ops(dev, arm_get_dma_map_ops(dev->archdata.dma_coherent)); pr_debug("Detached IOMMU controller from %s device.\n", dev_name(dev)); } @@ -2357,11 +2362,6 @@ static void arm_teardown_iommu_dma_ops(struct device *dev) { } #endif /* CONFIG_ARM_DMA_USE_IOMMU */ -static const struct dma_map_ops *arm_get_dma_map_ops(bool coherent) -{ - return coherent ? &arm_coherent_dma_ops : &arm_dma_ops; -} - void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, const struct iommu_ops *iommu, bool coherent) { -- GitLab From b59fb482b52269977ee5de205308e5b236a03917 Mon Sep 17 00:00:00 2001 From: Thierry Reding <treding@nvidia.com> Date: Wed, 30 May 2018 16:06:25 +0200 Subject: [PATCH 1192/1506] drm/nouveau: tegra: Detach from ARM DMA/IOMMU mapping Depending on the kernel configuration, early ARM architecture setup code may have attached the GPU to a DMA/IOMMU mapping that transparently uses the IOMMU to back the DMA API. Tegra requires special handling for IOMMU backed buffers (a special bit in the GPU's MMU page tables indicates the memory path to take: via the SMMU or directly to the memory controller). Transparently backing DMA memory with an IOMMU prevents Nouveau from properly handling such memory accesses and causes memory access faults. As a side-note: buffers other than those allocated in instance memory don't need to be physically contiguous from the GPU's perspective since the GPU can map them into contiguous buffers using its own MMU. Mapping these buffers through the IOMMU is unnecessary and will even lead to performance degradation because of the additional translation. One exception to this are compressible buffers which need large pages. In order to enable these large pages, multiple small pages will have to be combined into one large (I/O virtually contiguous) mapping via the IOMMU. However, that is a topic outside the scope of this fix and isn't currently supported. An implementation will want to explicitly create these large pages in the Nouveau driver, so detaching from a DMA/IOMMU mapping would still be required. Signed-off-by: Thierry Reding <treding@nvidia.com> Acked-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Robin Murphy <robin.murphy@arm.com> Tested-by: Nicolas Chauvet <kwizart@gmail.com> Signed-off-by: Ben Skeggs <bskeggs@redhat.com> --- drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c index 78597da6313ad..0e372a190d3f1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c @@ -23,6 +23,10 @@ #ifdef CONFIG_NOUVEAU_PLATFORM_DRIVER #include "priv.h" +#if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU) +#include <asm/dma-iommu.h> +#endif + static int nvkm_device_tegra_power_up(struct nvkm_device_tegra *tdev) { @@ -105,6 +109,15 @@ nvkm_device_tegra_probe_iommu(struct nvkm_device_tegra *tdev) unsigned long pgsize_bitmap; int ret; +#if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU) + if (dev->archdata.mapping) { + struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev); + + arm_iommu_detach_device(dev); + arm_iommu_release_mapping(mapping); + } +#endif + if (!tdev->func->iommu_bit) return; -- GitLab From 3273fc63e1ed4866fe10a582f4203f2aa142b216 Mon Sep 17 00:00:00 2001 From: Neil Armstrong <narmstrong@baylibre.com> Date: Mon, 16 Jul 2018 09:40:14 +0200 Subject: [PATCH 1193/1506] drm/meson: Make DMT timings parameters and pixel clock generic Remove the modes timings tables for DMT modes and calculate the HW paremeters from the modes timings. Switch the DMT modes pixel clock calculation out of the static frequency list to a generic calculation from a range of possible PLL dividers. This patch is an intermediate step towards usage of the Common Clock Framwework for PLL setup, by reworking the code to have common sel_pll() function called by the CEA (HDMI) freq setup and the generic DMT frequencies setup, we should be able to simply call clk_set_rate() on the PLL clock handle in a near future. The CEA (HDMI) and CVBS modes needs very specific clock paths that CCF will never be able to determine by itself, so there is still some work to do for a full handoff to CCF handling the clocks. This setup permits setting non-CEA modes like : - 1600x900-60Hz - 1280x1024-75Hz - 1280x1024-60Hz - 1440x900-60Hz - 1366x768-60Hz - 1280x800-60Hz - 1152x864-75Hz - 1024x768-75Hz - 1024x768-70Hz - 1024x768-60Hz - 832x624-75Hz - 800x600-75Hz - 800x600-72Hz - 800x600-60Hz - 640x480-75Hz - 640x480-73Hz - 640x480-67Hz Signed-off-by: Neil Armstrong <narmstrong@baylibre.com> Acked-by: Jerome Brunet <jbrunet@baylibre.com> [narmstrong: fixed trivial checkpatch issues] Link: https://patchwork.freedesktop.org/patch/msgid/1531726814-14638-1-git-send-email-narmstrong@baylibre.com --- drivers/gpu/drm/meson/meson_dw_hdmi.c | 22 +- drivers/gpu/drm/meson/meson_vclk.c | 656 +++++++++++--------------- drivers/gpu/drm/meson/meson_vclk.h | 4 + drivers/gpu/drm/meson/meson_venc.c | 378 ++------------- drivers/gpu/drm/meson/meson_venc.h | 3 +- 5 files changed, 350 insertions(+), 713 deletions(-) diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c index c9ad45686e7ae..df7247cd93f98 100644 --- a/drivers/gpu/drm/meson/meson_dw_hdmi.c +++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c @@ -329,6 +329,12 @@ static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi, vclk_freq = mode->clock; + if (!vic) { + meson_vclk_setup(priv, MESON_VCLK_TARGET_DMT, vclk_freq, + vclk_freq, vclk_freq, false); + return; + } + if (mode->flags & DRM_MODE_FLAG_DBLCLK) vclk_freq *= 2; @@ -542,10 +548,12 @@ static enum drm_mode_status dw_hdmi_mode_valid(struct drm_connector *connector, const struct drm_display_mode *mode) { + struct meson_drm *priv = connector->dev->dev_private; unsigned int vclk_freq; unsigned int venc_freq; unsigned int hdmi_freq; int vic = drm_match_cea_mode(mode); + enum drm_mode_status status; DRM_DEBUG_DRIVER("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n", mode->base.id, mode->name, mode->vrefresh, mode->clock, @@ -556,8 +564,11 @@ dw_hdmi_mode_valid(struct drm_connector *connector, /* Check against non-VIC supported modes */ if (!vic) { - if (!meson_venc_hdmi_supported_mode(mode)) - return MODE_BAD; + status = meson_venc_hdmi_supported_mode(mode); + if (status != MODE_OK) + return status; + + return meson_vclk_dmt_supported_freq(priv, mode->clock); /* Check against supported VIC modes */ } else if (!meson_venc_hdmi_supported_vic(vic)) return MODE_BAD; @@ -583,16 +594,11 @@ dw_hdmi_mode_valid(struct drm_connector *connector, dev_dbg(connector->dev->dev, "%s: vclk:%d venc=%d hdmi=%d\n", __func__, vclk_freq, venc_freq, hdmi_freq); - /* Finally filter by configurable vclk frequencies */ + /* Finally filter by configurable vclk frequencies for VIC modes */ switch (vclk_freq) { - case 25175: - case 40000: case 54000: - case 65000: case 74250: - case 108000: case 148500: - case 162000: case 297000: case 594000: return MODE_OK; diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c index f0511220317f9..ae5473257f727 100644 --- a/drivers/gpu/drm/meson/meson_vclk.c +++ b/drivers/gpu/drm/meson/meson_vclk.c @@ -320,32 +320,23 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv) CTS_VDAC_EN, CTS_VDAC_EN); } - +enum { /* PLL O1 O2 O3 VP DV EN TX */ /* 4320 /4 /4 /1 /5 /1 => /2 /2 */ -#define MESON_VCLK_HDMI_ENCI_54000 1 + MESON_VCLK_HDMI_ENCI_54000 = 1, /* 4320 /4 /4 /1 /5 /1 => /1 /2 */ -#define MESON_VCLK_HDMI_DDR_54000 2 + MESON_VCLK_HDMI_DDR_54000, /* 2970 /4 /1 /1 /5 /1 => /1 /2 */ -#define MESON_VCLK_HDMI_DDR_148500 3 -/* 4028 /4 /4 /1 /5 /2 => /1 /1 */ -#define MESON_VCLK_HDMI_25175 4 -/* 3200 /4 /2 /1 /5 /2 => /1 /1 */ -#define MESON_VCLK_HDMI_40000 5 -/* 5200 /4 /2 /1 /5 /2 => /1 /1 */ -#define MESON_VCLK_HDMI_65000 6 + MESON_VCLK_HDMI_DDR_148500, /* 2970 /2 /2 /2 /5 /1 => /1 /1 */ -#define MESON_VCLK_HDMI_74250 7 -/* 4320 /4 /1 /1 /5 /2 => /1 /1 */ -#define MESON_VCLK_HDMI_108000 8 + MESON_VCLK_HDMI_74250, /* 2970 /1 /2 /2 /5 /1 => /1 /1 */ -#define MESON_VCLK_HDMI_148500 9 -/* 3240 /2 /1 /1 /5 /2 => /1 /1 */ -#define MESON_VCLK_HDMI_162000 10 + MESON_VCLK_HDMI_148500, /* 2970 /1 /1 /1 /5 /2 => /1 /1 */ -#define MESON_VCLK_HDMI_297000 11 + MESON_VCLK_HDMI_297000, /* 5940 /1 /1 /2 /5 /1 => /1 /1 */ -#define MESON_VCLK_HDMI_594000 12 + MESON_VCLK_HDMI_594000 +}; struct meson_vclk_params { unsigned int pll_base_freq; @@ -411,46 +402,6 @@ struct meson_vclk_params { .vid_pll_div = VID_PLL_DIV_5, .vclk_div = 1, }, - [MESON_VCLK_HDMI_25175] = { - .pll_base_freq = 4028000, - .pll_od1 = 4, - .pll_od2 = 4, - .pll_od3 = 1, - .vid_pll_div = VID_PLL_DIV_5, - .vclk_div = 2, - }, - [MESON_VCLK_HDMI_40000] = { - .pll_base_freq = 3200000, - .pll_od1 = 4, - .pll_od2 = 2, - .pll_od3 = 1, - .vid_pll_div = VID_PLL_DIV_5, - .vclk_div = 2, - }, - [MESON_VCLK_HDMI_65000] = { - .pll_base_freq = 5200000, - .pll_od1 = 4, - .pll_od2 = 2, - .pll_od3 = 1, - .vid_pll_div = VID_PLL_DIV_5, - .vclk_div = 2, - }, - [MESON_VCLK_HDMI_108000] = { - .pll_base_freq = 4320000, - .pll_od1 = 4, - .pll_od2 = 1, - .pll_od3 = 1, - .vid_pll_div = VID_PLL_DIV_5, - .vclk_div = 2, - }, - [MESON_VCLK_HDMI_162000] = { - .pll_base_freq = 3240000, - .pll_od1 = 2, - .pll_od2 = 1, - .pll_od3 = 1, - .vid_pll_div = VID_PLL_DIV_5, - .vclk_div = 2, - }, }; static inline unsigned int pll_od_to_reg(unsigned int od) @@ -470,358 +421,217 @@ static inline unsigned int pll_od_to_reg(unsigned int od) return 0; } -void meson_hdmi_pll_set(struct meson_drm *priv, - unsigned int base, - unsigned int od1, - unsigned int od2, - unsigned int od3) +void meson_hdmi_pll_set_params(struct meson_drm *priv, unsigned int m, + unsigned int frac, unsigned int od1, + unsigned int od2, unsigned int od3) { unsigned int val; if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) { - switch (base) { - case 2970000: - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800023d); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); - - /* Enable and unreset */ - regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, - 0x7 << 28, 0x4 << 28); - - /* Poll for lock bit */ - regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, - val, (val & HDMI_PLL_LOCK), 10, 0); - - /* div_frac */ - regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, - 0xFFFF, 0x4e00); - break; - - case 3200000: - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000242); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); - - /* unreset */ - regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, - BIT(28), 0); - - /* Poll for lock bit */ - regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, - val, (val & HDMI_PLL_LOCK), 10, 0); - - /* div_frac */ - regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, - 0xFFFF, 0x4aab); - break; - - case 3240000: - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000243); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); - - /* unreset */ - regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, - BIT(28), 0); - - /* Poll for lock bit */ - regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, - val, (val & HDMI_PLL_LOCK), 10, 0); - - /* div_frac */ - regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, - 0xFFFF, 0x4800); - break; - - case 3865000: - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000250); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); - - /* unreset */ - regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, - BIT(28), 0); - - /* Poll for lock bit */ - regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, - val, (val & HDMI_PLL_LOCK), 10, 0); - - /* div_frac */ - regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, - 0xFFFF, 0x4855); - break; - - case 4028000: - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000253); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); - - /* unreset */ - regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, - BIT(28), 0); - - /* Poll for lock bit */ - regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, - val, (val & HDMI_PLL_LOCK), 10, 0); - - /* div_frac */ - regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, - 0xFFFF, 0x4eab); - break; - - case 4320000: - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800025a); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); - - /* unreset */ - regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, - BIT(28), 0); - - /* Poll for lock bit */ - regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, - val, (val & HDMI_PLL_LOCK), 10, 0); - break; + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000200 | m); + if (frac) + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, + 0x00004000 | frac); + else + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, + 0x00000000); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); - case 5940000: - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800027b); - regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, - 0xFFFF, 0x4c00); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x135c5091); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); - - /* unreset */ - regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, - BIT(28), 0); - - /* Poll for lock bit */ - regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, - val, (val & HDMI_PLL_LOCK), 10, 0); - break; + /* Enable and unreset */ + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, + 0x7 << 28, 0x4 << 28); - case 5200000: - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800026c); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x135c5091); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); - - /* unreset */ - regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, - BIT(28), 0); - - /* Poll for lock bit */ - regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, - val, (val & HDMI_PLL_LOCK), 10, 0); - break; - }; + /* Poll for lock bit */ + regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, + val, (val & HDMI_PLL_LOCK), 10, 0); } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) { - switch (base) { - case 2970000: - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x4000027b); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb300); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); - break; - - case 3200000: - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x40000285); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb155); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); - break; - - case 3240000: - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x40000287); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb000); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); - break; - - case 3865000: - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002a1); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb02b); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); - break; - - case 4028000: - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002a7); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb355); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); - break; - - case 4320000: - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002b4); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb000); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); - break; - - case 5940000: - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002f7); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb200); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); - break; - - case 5200000: - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002d8); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb2ab); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); - break; - - }; + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x40000200 | m); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb000 | frac); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); /* Reset PLL */ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, - HDMI_PLL_RESET, HDMI_PLL_RESET); + HDMI_PLL_RESET, HDMI_PLL_RESET); regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, - HDMI_PLL_RESET, 0); + HDMI_PLL_RESET, 0); /* Poll for lock bit */ regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val, (val & HDMI_PLL_LOCK), 10, 0); - }; + } if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, - 3 << 16, pll_od_to_reg(od1) << 16); + 3 << 16, pll_od_to_reg(od1) << 16); else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || - meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) + meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3, - 3 << 21, pll_od_to_reg(od1) << 21); + 3 << 21, pll_od_to_reg(od1) << 21); if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, - 3 << 22, pll_od_to_reg(od2) << 22); + 3 << 22, pll_od_to_reg(od2) << 22); else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || - meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) + meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3, - 3 << 23, pll_od_to_reg(od2) << 23); + 3 << 23, pll_od_to_reg(od2) << 23); if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, - 3 << 18, pll_od_to_reg(od3) << 18); + 3 << 18, pll_od_to_reg(od3) << 18); else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || - meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) + meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3, - 3 << 19, pll_od_to_reg(od3) << 19); + 3 << 19, pll_od_to_reg(od3) << 19); + } -void meson_vclk_setup(struct meson_drm *priv, unsigned int target, - unsigned int vclk_freq, unsigned int venc_freq, - unsigned int dac_freq, bool hdmi_use_enci) +#define XTAL_FREQ 24000 + +static unsigned int meson_hdmi_pll_get_m(struct meson_drm *priv, + unsigned int pll_freq) { - unsigned int freq; - unsigned int hdmi_tx_div; - unsigned int venc_div; + /* The GXBB PLL has a /2 pre-multiplier */ + if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) + pll_freq /= 2; - if (target == MESON_VCLK_TARGET_CVBS) { - meson_venci_cvbs_clock_config(priv); - return; + return pll_freq / XTAL_FREQ; +} + +#define HDMI_FRAC_MAX_GXBB 4096 +#define HDMI_FRAC_MAX_GXL 1024 + +static unsigned int meson_hdmi_pll_get_frac(struct meson_drm *priv, + unsigned int m, + unsigned int pll_freq) +{ + unsigned int parent_freq = XTAL_FREQ; + unsigned int frac_max = HDMI_FRAC_MAX_GXL; + unsigned int frac_m; + unsigned int frac; + + /* The GXBB PLL has a /2 pre-multiplier and a larger FRAC width */ + if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) { + frac_max = HDMI_FRAC_MAX_GXBB; + parent_freq *= 2; } - hdmi_tx_div = vclk_freq / dac_freq; + /* We can have a perfect match !*/ + if (pll_freq / m == parent_freq && + pll_freq % m == 0) + return 0; - if (hdmi_tx_div == 0) { - pr_err("Fatal Error, invalid HDMI-TX freq %d\n", - dac_freq); - return; + frac = div_u64((u64)pll_freq * (u64)frac_max, parent_freq); + frac_m = m * frac_max; + if (frac_m > frac) + return frac_max; + frac -= frac_m; + + return min((u16)frac, (u16)(frac_max - 1)); +} + +static bool meson_hdmi_pll_validate_params(struct meson_drm *priv, + unsigned int m, + unsigned int frac) +{ + if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) { + /* Empiric supported min/max dividers */ + if (m < 53 || m > 123) + return false; + if (frac >= HDMI_FRAC_MAX_GXBB) + return false; + } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || + meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) { + /* Empiric supported min/max dividers */ + if (m < 106 || m > 247) + return false; + if (frac >= HDMI_FRAC_MAX_GXL) + return false; } - venc_div = vclk_freq / venc_freq; + return true; +} - if (venc_div == 0) { - pr_err("Fatal Error, invalid HDMI venc freq %d\n", - venc_freq); - return; +static bool meson_hdmi_pll_find_params(struct meson_drm *priv, + unsigned int freq, + unsigned int *m, + unsigned int *frac, + unsigned int *od) +{ + /* Cycle from /16 to /2 */ + for (*od = 16 ; *od > 1 ; *od >>= 1) { + *m = meson_hdmi_pll_get_m(priv, freq * *od); + if (!*m) + continue; + *frac = meson_hdmi_pll_get_frac(priv, *m, freq * *od); + + DRM_DEBUG_DRIVER("PLL params for %dkHz: m=%x frac=%x od=%d\n", + freq, *m, *frac, *od); + + if (meson_hdmi_pll_validate_params(priv, *m, *frac)) + return true; } - switch (vclk_freq) { - case 54000: - if (hdmi_use_enci) - freq = MESON_VCLK_HDMI_ENCI_54000; - else - freq = MESON_VCLK_HDMI_DDR_54000; - break; - case 25175: - freq = MESON_VCLK_HDMI_25175; - break; - case 40000: - freq = MESON_VCLK_HDMI_40000; - break; - case 65000: - freq = MESON_VCLK_HDMI_65000; - break; - case 74250: - freq = MESON_VCLK_HDMI_74250; - break; - case 108000: - freq = MESON_VCLK_HDMI_108000; - break; - case 148500: - if (dac_freq != 148500) - freq = MESON_VCLK_HDMI_DDR_148500; - else - freq = MESON_VCLK_HDMI_148500; - break; - case 162000: - freq = MESON_VCLK_HDMI_162000; - break; - case 297000: - freq = MESON_VCLK_HDMI_297000; - break; - case 594000: - freq = MESON_VCLK_HDMI_594000; - break; - default: - pr_err("Fatal Error, invalid HDMI vclk freq %d\n", - vclk_freq); + return false; +} + +/* pll_freq is the frequency after the OD dividers */ +enum drm_mode_status +meson_vclk_dmt_supported_freq(struct meson_drm *priv, unsigned int freq) +{ + unsigned int od, m, frac; + + /* In DMT mode, path after PLL is always /10 */ + freq *= 10; + + if (meson_hdmi_pll_find_params(priv, freq, &m, &frac, &od)) + return MODE_OK; + + return MODE_CLOCK_RANGE; +} +EXPORT_SYMBOL_GPL(meson_vclk_dmt_supported_freq); + +/* pll_freq is the frequency after the OD dividers */ +static void meson_hdmi_pll_generic_set(struct meson_drm *priv, + unsigned int pll_freq) +{ + unsigned int od, m, frac, od1, od2, od3; + + if (meson_hdmi_pll_find_params(priv, pll_freq, &m, &frac, &od)) { + od3 = 1; + if (od < 4) { + od1 = 2; + od2 = 1; + } else { + od2 = od / 4; + od1 = od / od2; + } + + DRM_DEBUG_DRIVER("PLL params for %dkHz: m=%x frac=%x od=%d/%d/%d\n", + pll_freq, m, frac, od1, od2, od3); + + meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3); + return; } + DRM_ERROR("Fatal, unable to find parameters for PLL freq %d\n", + pll_freq); +} + +static void meson_vclk_set(struct meson_drm *priv, unsigned int pll_base_freq, + unsigned int od1, unsigned int od2, unsigned int od3, + unsigned int vid_pll_div, unsigned int vclk_div, + unsigned int hdmi_tx_div, unsigned int venc_div, + bool hdmi_use_enci) +{ /* Set HDMI-TX sys clock */ regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, CTS_HDMI_SYS_SEL_MASK, 0); @@ -831,19 +641,49 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target, CTS_HDMI_SYS_EN, CTS_HDMI_SYS_EN); /* Set HDMI PLL rate */ - meson_hdmi_pll_set(priv, params[freq].pll_base_freq, - params[freq].pll_od1, - params[freq].pll_od2, - params[freq].pll_od3); + if (!od1 && !od2 && !od3) { + meson_hdmi_pll_generic_set(priv, pll_base_freq); + } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) { + switch (pll_base_freq) { + case 2970000: + meson_hdmi_pll_set_params(priv, 0x3d, 0xe00, + od1, od2, od3); + break; + case 4320000: + meson_hdmi_pll_set_params(priv, 0x5a, 0, + od1, od2, od3); + break; + case 5940000: + meson_hdmi_pll_set_params(priv, 0x7b, 0xc00, + od1, od2, od3); + break; + } + } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || + meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) { + switch (pll_base_freq) { + case 2970000: + meson_hdmi_pll_set_params(priv, 0x7b, 0x300, + od1, od2, od3); + break; + case 4320000: + meson_hdmi_pll_set_params(priv, 0xb4, 0, + od1, od2, od3); + break; + case 5940000: + meson_hdmi_pll_set_params(priv, 0xf7, 0x200, + od1, od2, od3); + break; + } + } /* Setup vid_pll divider */ - meson_vid_pll_set(priv, params[freq].vid_pll_div); + meson_vid_pll_set(priv, vid_pll_div); /* Set VCLK div */ regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL, VCLK_SEL_MASK, 0); regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV, - VCLK_DIV_MASK, params[freq].vclk_div - 1); + VCLK_DIV_MASK, vclk_div - 1); /* Set HDMI-TX source */ switch (hdmi_tx_div) { @@ -981,4 +821,80 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target, regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL, VCLK_EN, VCLK_EN); } + +void meson_vclk_setup(struct meson_drm *priv, unsigned int target, + unsigned int vclk_freq, unsigned int venc_freq, + unsigned int dac_freq, bool hdmi_use_enci) +{ + unsigned int freq; + unsigned int hdmi_tx_div; + unsigned int venc_div; + + if (target == MESON_VCLK_TARGET_CVBS) { + meson_venci_cvbs_clock_config(priv); + return; + } else if (target == MESON_VCLK_TARGET_DMT) { + /* The DMT clock path is fixed after the PLL: + * - automatic PLL freq + OD management + * - vid_pll_div = VID_PLL_DIV_5 + * - vclk_div = 2 + * - hdmi_tx_div = 1 + * - venc_div = 1 + * - encp encoder + */ + meson_vclk_set(priv, vclk_freq * 10, 0, 0, 0, + VID_PLL_DIV_5, 2, 1, 1, false); + return; + } + + hdmi_tx_div = vclk_freq / dac_freq; + + if (hdmi_tx_div == 0) { + pr_err("Fatal Error, invalid HDMI-TX freq %d\n", + dac_freq); + return; + } + + venc_div = vclk_freq / venc_freq; + + if (venc_div == 0) { + pr_err("Fatal Error, invalid HDMI venc freq %d\n", + venc_freq); + return; + } + + switch (vclk_freq) { + case 54000: + if (hdmi_use_enci) + freq = MESON_VCLK_HDMI_ENCI_54000; + else + freq = MESON_VCLK_HDMI_DDR_54000; + break; + case 74250: + freq = MESON_VCLK_HDMI_74250; + break; + case 148500: + if (dac_freq != 148500) + freq = MESON_VCLK_HDMI_DDR_148500; + else + freq = MESON_VCLK_HDMI_148500; + break; + case 297000: + freq = MESON_VCLK_HDMI_297000; + break; + case 594000: + freq = MESON_VCLK_HDMI_594000; + break; + default: + pr_err("Fatal Error, invalid HDMI vclk freq %d\n", + vclk_freq); + return; + } + + meson_vclk_set(priv, params[freq].pll_base_freq, + params[freq].pll_od1, params[freq].pll_od2, + params[freq].pll_od3, params[freq].vid_pll_div, + params[freq].vclk_div, hdmi_tx_div, venc_div, + hdmi_use_enci); +} EXPORT_SYMBOL_GPL(meson_vclk_setup); diff --git a/drivers/gpu/drm/meson/meson_vclk.h b/drivers/gpu/drm/meson/meson_vclk.h index 0401b52134713..869fa3a3073e9 100644 --- a/drivers/gpu/drm/meson/meson_vclk.h +++ b/drivers/gpu/drm/meson/meson_vclk.h @@ -24,11 +24,15 @@ enum { MESON_VCLK_TARGET_CVBS = 0, MESON_VCLK_TARGET_HDMI = 1, + MESON_VCLK_TARGET_DMT = 2, }; /* 27MHz is the CVBS Pixel Clock */ #define MESON_VCLK_CVBS 27000 +enum drm_mode_status +meson_vclk_dmt_supported_freq(struct meson_drm *priv, unsigned int freq); + void meson_vclk_setup(struct meson_drm *priv, unsigned int target, unsigned int vclk_freq, unsigned int venc_freq, unsigned int dac_freq, bool hdmi_use_enci); diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c index 6e27013898013..514245e69b384 100644 --- a/drivers/gpu/drm/meson/meson_venc.c +++ b/drivers/gpu/drm/meson/meson_venc.c @@ -697,314 +697,6 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p60 = { }, }; -union meson_hdmi_venc_mode meson_hdmi_encp_mode_640x480_60 = { - .encp = { - .dvi_settings = 0x21, - .video_mode = 0x4040, - .video_mode_adv = 0x18, - /* video_prog_mode */ - /* video_sync_mode */ - /* video_yc_dly */ - /* video_rgb_ctrl */ - /* video_filt_ctrl */ - /* video_ofld_voav_ofst */ - /* yfp1_htime */ - /* yfp2_htime */ - .max_pxcnt = 0x31f, - /* hspuls_begin */ - /* hspuls_end */ - /* hspuls_switch */ - /* vspuls_begin */ - /* vspuls_end */ - /* vspuls_bline */ - /* vspuls_eline */ - .havon_begin = 0x90, - .havon_end = 0x30f, - .vavon_bline = 0x23, - .vavon_eline = 0x202, - /* eqpuls_begin */ - /* eqpuls_end */ - /* eqpuls_bline */ - /* eqpuls_eline */ - .hso_begin = 0, - .hso_end = 0x60, - .vso_begin = 0x1e, - .vso_end = 0x32, - .vso_bline = 0, - .vso_eline = 2, - .vso_eline_present = true, - /* sy_val */ - /* sy2_val */ - .max_lncnt = 0x20c, - }, -}; - -union meson_hdmi_venc_mode meson_hdmi_encp_mode_800x600_60 = { - .encp = { - .dvi_settings = 0x21, - .video_mode = 0x4040, - .video_mode_adv = 0x18, - /* video_prog_mode */ - /* video_sync_mode */ - /* video_yc_dly */ - /* video_rgb_ctrl */ - /* video_filt_ctrl */ - /* video_ofld_voav_ofst */ - /* yfp1_htime */ - /* yfp2_htime */ - .max_pxcnt = 0x41f, - /* hspuls_begin */ - /* hspuls_end */ - /* hspuls_switch */ - /* vspuls_begin */ - /* vspuls_end */ - /* vspuls_bline */ - /* vspuls_eline */ - .havon_begin = 0xD8, - .havon_end = 0x3f7, - .vavon_bline = 0x1b, - .vavon_eline = 0x272, - /* eqpuls_begin */ - /* eqpuls_end */ - /* eqpuls_bline */ - /* eqpuls_eline */ - .hso_begin = 0, - .hso_end = 0x80, - .vso_begin = 0x1e, - .vso_end = 0x32, - .vso_bline = 0, - .vso_eline = 4, - .vso_eline_present = true, - /* sy_val */ - /* sy2_val */ - .max_lncnt = 0x273, - }, -}; - -union meson_hdmi_venc_mode meson_hdmi_encp_mode_1024x768_60 = { - .encp = { - .dvi_settings = 0x21, - .video_mode = 0x4040, - .video_mode_adv = 0x18, - /* video_prog_mode */ - /* video_sync_mode */ - /* video_yc_dly */ - /* video_rgb_ctrl */ - /* video_filt_ctrl */ - /* video_ofld_voav_ofst */ - /* yfp1_htime */ - /* yfp2_htime */ - .max_pxcnt = 1343, - /* hspuls_begin */ - /* hspuls_end */ - /* hspuls_switch */ - /* vspuls_begin */ - /* vspuls_end */ - /* vspuls_bline */ - /* vspuls_eline */ - .havon_begin = 296, - .havon_end = 1319, - .vavon_bline = 35, - .vavon_eline = 802, - /* eqpuls_begin */ - /* eqpuls_end */ - /* eqpuls_bline */ - /* eqpuls_eline */ - .hso_begin = 0, - .hso_end = 136, - .vso_begin = 30, - .vso_end = 50, - .vso_bline = 0, - .vso_eline = 6, - .vso_eline_present = true, - /* sy_val */ - /* sy2_val */ - .max_lncnt = 805, - }, -}; - -union meson_hdmi_venc_mode meson_hdmi_encp_mode_1152x864_75 = { - .encp = { - .dvi_settings = 0x21, - .video_mode = 0x4040, - .video_mode_adv = 0x18, - /* video_prog_mode */ - /* video_sync_mode */ - /* video_yc_dly */ - /* video_rgb_ctrl */ - /* video_filt_ctrl */ - /* video_ofld_voav_ofst */ - /* yfp1_htime */ - /* yfp2_htime */ - .max_pxcnt = 0x63f, - /* hspuls_begin */ - /* hspuls_end */ - /* hspuls_switch */ - /* vspuls_begin */ - /* vspuls_end */ - /* vspuls_bline */ - /* vspuls_eline */ - .havon_begin = 0x180, - .havon_end = 0x5ff, - .vavon_bline = 0x23, - .vavon_eline = 0x382, - /* eqpuls_begin */ - /* eqpuls_end */ - /* eqpuls_bline */ - /* eqpuls_eline */ - .hso_begin = 0, - .hso_end = 0x80, - .vso_begin = 0x1e, - .vso_end = 0x32, - .vso_bline = 0, - .vso_eline = 3, - .vso_eline_present = true, - /* sy_val */ - /* sy2_val */ - .max_lncnt = 0x383, - }, -}; - -union meson_hdmi_venc_mode meson_hdmi_encp_mode_1280x1024_60 = { - .encp = { - .dvi_settings = 0x21, - .video_mode = 0x4040, - .video_mode_adv = 0x18, - /* video_prog_mode */ - /* video_sync_mode */ - /* video_yc_dly */ - /* video_rgb_ctrl */ - /* video_filt_ctrl */ - /* video_ofld_voav_ofst */ - /* yfp1_htime */ - /* yfp2_htime */ - .max_pxcnt = 0x697, - /* hspuls_begin */ - /* hspuls_end */ - /* hspuls_switch */ - /* vspuls_begin */ - /* vspuls_end */ - /* vspuls_bline */ - /* vspuls_eline */ - .havon_begin = 0x168, - .havon_end = 0x667, - .vavon_bline = 0x29, - .vavon_eline = 0x428, - /* eqpuls_begin */ - /* eqpuls_end */ - /* eqpuls_bline */ - /* eqpuls_eline */ - .hso_begin = 0, - .hso_end = 0x70, - .vso_begin = 0x1e, - .vso_end = 0x32, - .vso_bline = 0, - .vso_eline = 3, - .vso_eline_present = true, - /* sy_val */ - /* sy2_val */ - .max_lncnt = 0x429, - }, -}; - -union meson_hdmi_venc_mode meson_hdmi_encp_mode_1600x1200_60 = { - .encp = { - .dvi_settings = 0x21, - .video_mode = 0x4040, - .video_mode_adv = 0x18, - /* video_prog_mode */ - /* video_sync_mode */ - /* video_yc_dly */ - /* video_rgb_ctrl */ - /* video_filt_ctrl */ - /* video_ofld_voav_ofst */ - /* yfp1_htime */ - /* yfp2_htime */ - .max_pxcnt = 0x86f, - /* hspuls_begin */ - /* hspuls_end */ - /* hspuls_switch */ - /* vspuls_begin */ - /* vspuls_end */ - /* vspuls_bline */ - /* vspuls_eline */ - .havon_begin = 0x1f0, - .havon_end = 0x82f, - .vavon_bline = 0x31, - .vavon_eline = 0x4e0, - /* eqpuls_begin */ - /* eqpuls_end */ - /* eqpuls_bline */ - /* eqpuls_eline */ - .hso_begin = 0, - .hso_end = 0xc0, - .vso_begin = 0x1e, - .vso_end = 0x32, - .vso_bline = 0, - .vso_eline = 3, - .vso_eline_present = true, - /* sy_val */ - /* sy2_val */ - .max_lncnt = 0x4e1, - }, -}; - -struct meson_hdmi_venc_dmt_mode { - struct drm_display_mode drm_mode; - union meson_hdmi_venc_mode *mode; -} meson_hdmi_venc_dmt_modes[] = { - /* 640x480@60Hz */ - { - { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656, - 752, 800, 0, 480, 490, 492, 525, 0, - DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, - &meson_hdmi_encp_mode_640x480_60, - }, - /* 800x600@60Hz */ - { - { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840, - 968, 1056, 0, 600, 601, 605, 628, 0, - DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, - &meson_hdmi_encp_mode_800x600_60, - }, - /* 1024x768@60Hz */ - { - { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, - 1048, 1184, 1344, 0, 768, 771, 777, 806, 0, - DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, - &meson_hdmi_encp_mode_1024x768_60, - }, - /* 1152x864@75Hz */ - { - { DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, - 1216, 1344, 1600, 0, 864, 865, 868, 900, 0, - DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, - &meson_hdmi_encp_mode_1152x864_75, - }, - /* 1280x1024@60Hz */ - { - { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 108000, 1280, - 1328, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, - DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, - &meson_hdmi_encp_mode_1280x1024_60, - }, - /* 1600x1200@60Hz */ - { - { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 162000, 1600, - 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, - DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, - &meson_hdmi_encp_mode_1600x1200_60, - }, - /* 1920x1080@60Hz */ - { - { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, - 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, - DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, - &meson_hdmi_encp_mode_1080p60 - }, - { }, /* sentinel */ -}; - struct meson_hdmi_venc_vic_mode { unsigned int vic; union meson_hdmi_venc_mode *mode; @@ -1044,17 +736,20 @@ static unsigned long modulo(unsigned long a, unsigned long b) return a; } -bool meson_venc_hdmi_supported_mode(const struct drm_display_mode *mode) +enum drm_mode_status +meson_venc_hdmi_supported_mode(const struct drm_display_mode *mode) { - struct meson_hdmi_venc_dmt_mode *vmode = meson_hdmi_venc_dmt_modes; + if (mode->flags & ~(DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NHSYNC | + DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_NVSYNC)) + return MODE_BAD; - while (vmode->mode) { - if (drm_mode_equal(&vmode->drm_mode, mode)) - return true; - vmode++; - } + if (mode->hdisplay < 640 || mode->hdisplay > 1920) + return MODE_BAD_HVALUE; - return false; + if (mode->vdisplay < 480 || mode->vdisplay > 1200) + return MODE_BAD_VVALUE; + + return MODE_OK; } EXPORT_SYMBOL_GPL(meson_venc_hdmi_supported_mode); @@ -1072,18 +767,29 @@ bool meson_venc_hdmi_supported_vic(int vic) } EXPORT_SYMBOL_GPL(meson_venc_hdmi_supported_vic); -static union meson_hdmi_venc_mode -*meson_venc_hdmi_get_dmt_vmode(const struct drm_display_mode *mode) +void meson_venc_hdmi_get_dmt_vmode(const struct drm_display_mode *mode, + union meson_hdmi_venc_mode *dmt_mode) { - struct meson_hdmi_venc_dmt_mode *vmode = meson_hdmi_venc_dmt_modes; - - while (vmode->mode) { - if (drm_mode_equal(&vmode->drm_mode, mode)) - return vmode->mode; - vmode++; - } - - return NULL; + memset(dmt_mode, 0, sizeof(*dmt_mode)); + + dmt_mode->encp.dvi_settings = 0x21; + dmt_mode->encp.video_mode = 0x4040; + dmt_mode->encp.video_mode_adv = 0x18; + dmt_mode->encp.max_pxcnt = mode->htotal - 1; + dmt_mode->encp.havon_begin = mode->htotal - mode->hsync_start; + dmt_mode->encp.havon_end = dmt_mode->encp.havon_begin + + mode->hdisplay - 1; + dmt_mode->encp.vavon_bline = mode->vtotal - mode->vsync_start; + dmt_mode->encp.vavon_eline = dmt_mode->encp.vavon_bline + + mode->vdisplay - 1; + dmt_mode->encp.hso_begin = 0; + dmt_mode->encp.hso_end = mode->hsync_end - mode->hsync_start; + dmt_mode->encp.vso_begin = 30; + dmt_mode->encp.vso_end = 50; + dmt_mode->encp.vso_bline = 0; + dmt_mode->encp.vso_eline = mode->vsync_end - mode->vsync_start; + dmt_mode->encp.vso_eline_present = true; + dmt_mode->encp.max_lncnt = mode->vtotal - 1; } static union meson_hdmi_venc_mode *meson_venc_hdmi_get_vic_vmode(int vic) @@ -1120,6 +826,7 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, struct drm_display_mode *mode) { union meson_hdmi_venc_mode *vmode = NULL; + union meson_hdmi_venc_mode vmode_dmt; bool use_enci = false; bool venc_repeat = false; bool hdmi_repeat = false; @@ -1147,14 +854,17 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, unsigned int sof_lines; unsigned int vsync_lines; - if (meson_venc_hdmi_supported_vic(vic)) + if (meson_venc_hdmi_supported_vic(vic)) { vmode = meson_venc_hdmi_get_vic_vmode(vic); - else - vmode = meson_venc_hdmi_get_dmt_vmode(mode); - if (!vmode) { - dev_err(priv->dev, "%s: Fatal Error, unsupported mode " - DRM_MODE_FMT "\n", __func__, DRM_MODE_ARG(mode)); - return; + if (!vmode) { + dev_err(priv->dev, "%s: Fatal Error, unsupported mode " + DRM_MODE_FMT "\n", __func__, + DRM_MODE_ARG(mode)); + return; + } + } else { + meson_venc_hdmi_get_dmt_vmode(mode, &vmode_dmt); + vmode = &vmode_dmt; } /* Use VENCI for 480i and 576i and double HDMI pixels */ diff --git a/drivers/gpu/drm/meson/meson_venc.h b/drivers/gpu/drm/meson/meson_venc.h index 7c18a36a0dd0c..97eaebbfa0c4a 100644 --- a/drivers/gpu/drm/meson/meson_venc.h +++ b/drivers/gpu/drm/meson/meson_venc.h @@ -58,7 +58,8 @@ struct meson_cvbs_enci_mode { }; /* HDMI Clock parameters */ -bool meson_venc_hdmi_supported_mode(const struct drm_display_mode *mode); +enum drm_mode_status +meson_venc_hdmi_supported_mode(const struct drm_display_mode *mode); bool meson_venc_hdmi_supported_vic(int vic); bool meson_venc_hdmi_venc_repeat(int vic); -- GitLab From 55e4b859a2e1952d3feb2e2ec1c520952cc8b660 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Mon, 16 Jul 2018 09:03:32 +0100 Subject: [PATCH 1194/1506] drm/i915/selftests: Downgrade igt_timeout message Give in, since CI continues to incorrectly insist that KERN_NOTICE is a warning and flags the timeout message as unwanted spam. At first, the intention was to use the message to indicate which tests might warrant an extended run, but virtually all tests require a timeout so it is simply not as interesting as first thought. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=103667 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180716080332.32283-6-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_selftest.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_selftest.h b/drivers/gpu/drm/i915/i915_selftest.h index 9766e806dce63..a73472dd12fd9 100644 --- a/drivers/gpu/drm/i915/i915_selftest.h +++ b/drivers/gpu/drm/i915/i915_selftest.h @@ -99,6 +99,6 @@ __printf(2, 3) bool __igt_timeout(unsigned long timeout, const char *fmt, ...); #define igt_timeout(t, fmt, ...) \ - __igt_timeout((t), KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__) + __igt_timeout((t), KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__) #endif /* !__I915_SELFTEST_H__ */ -- GitLab From 159b69bc0dcdb88ea5126a8f98e4caa31789326b Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Mon, 16 Jul 2018 09:03:31 +0100 Subject: [PATCH 1195/1506] drm/i915: Remove pci private pointer after destroying the device private On an aborted module load, we unwind and free our device private - but we left a dangling pointer to our privates inside the pci_device. After the attempted aborted unload, we may still get a call to i915_pci_remove() when the module is removed, potentially chasing stale data. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180716080332.32283-5-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_drv.c | 1 + drivers/gpu/drm/i915/i915_pci.c | 13 ++++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index cfa7583cf4088..337b1aad5212b 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1424,6 +1424,7 @@ int i915_driver_load(struct pci_dev *pdev, const struct pci_device_id *ent) drm_dev_fini(&dev_priv->drm); out_free: kfree(dev_priv); + pci_set_drvdata(pdev, NULL); return ret; } diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c index 55543f1b0236a..6a4d1388ad2d3 100644 --- a/drivers/gpu/drm/i915/i915_pci.c +++ b/drivers/gpu/drm/i915/i915_pci.c @@ -674,10 +674,16 @@ MODULE_DEVICE_TABLE(pci, pciidlist); static void i915_pci_remove(struct pci_dev *pdev) { - struct drm_device *dev = pci_get_drvdata(pdev); + struct drm_device *dev; + + dev = pci_get_drvdata(pdev); + if (!dev) /* driver load aborted, nothing to cleanup */ + return; i915_driver_unload(dev); drm_dev_put(dev); + + pci_set_drvdata(pdev, NULL); } static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -712,6 +718,11 @@ static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (err) return err; + if (i915_inject_load_failure()) { + i915_pci_remove(pdev); + return -ENODEV; + } + err = i915_live_selftests(pdev); if (err) { i915_pci_remove(pdev); -- GitLab From f1a498fa549e8e86895cda37e3fca867aae955b7 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Mon, 16 Jul 2018 09:03:30 +0100 Subject: [PATCH 1196/1506] drm/i915/execlists: Disable submission tasklet upon wedging If we declare the driver wedged before the GPU truly is, then we may see the GPU complete some CS events following our cancellation. This leaves us quite confused as we deleted all the bookkeeping and thus complain about the inconsistent state. We can just ignore the remaining events and let the GPU idle by not feeding it, and so avoid trying to racily overwrite shared state. We rely on there being a full GPU reset before unwedging, giving us the opportunity to reset the shared state. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=107188 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180716080332.32283-4-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_lrc.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 05567e30efe06..629127e035770 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -811,6 +811,11 @@ static void reset_csb_pointers(struct intel_engine_execlists *execlists) WRITE_ONCE(*execlists->csb_write, execlists->csb_write_reset); } +static void nop_submission_tasklet(unsigned long data) +{ + /* The driver is wedged; don't process any more events. */ +} + static void execlists_cancel_requests(struct intel_engine_cs *engine) { struct intel_engine_execlists * const execlists = &engine->execlists; @@ -870,6 +875,9 @@ static void execlists_cancel_requests(struct intel_engine_cs *engine) execlists->queue = RB_ROOT_CACHED; GEM_BUG_ON(port_isset(execlists->port)); + GEM_BUG_ON(__tasklet_is_enabled(&execlists->tasklet)); + execlists->tasklet.func = nop_submission_tasklet; + spin_unlock_irqrestore(&engine->timeline.lock, flags); } -- GitLab From 7f43ef9f0d98abbc0eb5e697628ec06756bf60a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= <michel.daenzer@amd.com> Date: Wed, 4 Jul 2018 17:14:05 +0200 Subject: [PATCH 1197/1506] dma-buf: Move BUG_ON from _add_shared_fence to _add_shared_inplace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the BUG_ON spuriously triggering under the following circumstances: * reservation_object_reserve_shared is called with shared_count == shared_max - 1, so obj->staged is freed in preparation of an in-place update. * reservation_object_add_shared_fence is called with the first fence, after which shared_count == shared_max. * reservation_object_add_shared_fence is called with a follow-up fence from the same context. In the second reservation_object_add_shared_fence call, the BUG_ON triggers. However, nothing bad would happen in reservation_object_add_shared_inplace, since both fences are from the same context, so they only occupy a single slot. Prevent this by moving the BUG_ON to where an overflow would actually happen (e.g. if a buggy caller didn't call reservation_object_reserve_shared before). v2: * Fix description of breaking scenario (Christian König) * Add bugzilla reference Cc: stable@vger.kernel.org Bugzilla: https://bugs.freedesktop.org/106418 Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> # v1 Reviewed-by: Christian König <christian.koenig@amd.com> # v1 Signed-off-by: Michel Dänzer <michel.daenzer@amd.com> Signed-off-by: Sumit Semwal <sumit.semwal@linaro.org> Link: https://patchwork.freedesktop.org/patch/msgid/20180704151405.10357-1-michel@daenzer.net --- drivers/dma-buf/reservation.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/dma-buf/reservation.c b/drivers/dma-buf/reservation.c index 20bf90f4ee632..6c95f61a32e73 100644 --- a/drivers/dma-buf/reservation.c +++ b/drivers/dma-buf/reservation.c @@ -141,6 +141,7 @@ reservation_object_add_shared_inplace(struct reservation_object *obj, if (signaled) { RCU_INIT_POINTER(fobj->shared[signaled_idx], fence); } else { + BUG_ON(fobj->shared_count >= fobj->shared_max); RCU_INIT_POINTER(fobj->shared[fobj->shared_count], fence); fobj->shared_count++; } @@ -230,10 +231,9 @@ void reservation_object_add_shared_fence(struct reservation_object *obj, old = reservation_object_get_list(obj); obj->staged = NULL; - if (!fobj) { - BUG_ON(old->shared_count >= old->shared_max); + if (!fobj) reservation_object_add_shared_inplace(obj, old, fence); - } else + else reservation_object_add_shared_replace(obj, old, fobj, fence); } EXPORT_SYMBOL(reservation_object_add_shared_fence); -- GitLab From 3cdba8018fd54a418480ded9c14df5436a5b743d Mon Sep 17 00:00:00 2001 From: Leonard Crestez <leonard.crestez@nxp.com> Date: Wed, 28 Mar 2018 00:39:47 +0300 Subject: [PATCH 1198/1506] drm/imx: Remove last traces of struct imx_drm_crtc When the definition of this struct was removed a forward declaration and an unused struct member were still left around. Remove them because they serve no purpose. Fixes 44b460cfe554 ("drm: imx: remove struct imx_drm_crtc and imx_drm_crtc_helper_funcs") Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com> Reviewed-by: Fabio Estevam <fabio.estevam@nxp.com> Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de> --- drivers/gpu/drm/imx/imx-drm.h | 1 - drivers/gpu/drm/imx/ipuv3-crtc.c | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/gpu/drm/imx/imx-drm.h b/drivers/gpu/drm/imx/imx-drm.h index 15c2bec47a04c..ab9c6f706eb3d 100644 --- a/drivers/gpu/drm/imx/imx-drm.h +++ b/drivers/gpu/drm/imx/imx-drm.h @@ -10,7 +10,6 @@ struct drm_display_mode; struct drm_encoder; struct drm_framebuffer; struct drm_plane; -struct imx_drm_crtc; struct platform_device; struct imx_crtc_state { diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c index e83af0f2be869..50d9f2bbe3487 100644 --- a/drivers/gpu/drm/imx/ipuv3-crtc.c +++ b/drivers/gpu/drm/imx/ipuv3-crtc.c @@ -35,7 +35,6 @@ struct ipu_crtc { struct device *dev; struct drm_crtc base; - struct imx_drm_crtc *imx_crtc; /* plane[0] is the full plane, plane[1] is the partial plane */ struct ipu_plane *plane[2]; -- GitLab From 7cc3bf3f08b5645d1d08439fea36e4148dc6d7d3 Mon Sep 17 00:00:00 2001 From: Michael Grzeschik <m.grzeschik@pengutronix.de> Date: Wed, 2 May 2018 14:52:26 +0200 Subject: [PATCH 1199/1506] gpu: ipu-csi: add rgb/bgr888 24bit support to mbus_code_to_bus_cfg The 24bit RGB format configuration is currently missing, we add it now. Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de> Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de> --- drivers/gpu/ipu-v3/ipu-csi.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/ipu-v3/ipu-csi.c b/drivers/gpu/ipu-v3/ipu-csi.c index 5450a2db12192..813a3199aa844 100644 --- a/drivers/gpu/ipu-v3/ipu-csi.c +++ b/drivers/gpu/ipu-v3/ipu-csi.c @@ -247,6 +247,12 @@ static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code) cfg->mipi_dt = MIPI_DT_RGB555; cfg->data_width = IPU_CSI_DATA_WIDTH_8; break; + case MEDIA_BUS_FMT_RGB888_1X24: + case MEDIA_BUS_FMT_BGR888_1X24: + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB_YUV444; + cfg->mipi_dt = MIPI_DT_RGB888; + cfg->data_width = IPU_CSI_DATA_WIDTH_8; + break; case MEDIA_BUS_FMT_UYVY8_2X8: cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY; cfg->mipi_dt = MIPI_DT_YUV422; -- GitLab From d36d0e6309dd8137cf438cbb680e72eb63c81425 Mon Sep 17 00:00:00 2001 From: Enrico Scholz <enrico.scholz@sigma-chemnitz.de> Date: Thu, 3 May 2018 18:29:36 +0200 Subject: [PATCH 1200/1506] gpu: ipu-v3: csi: pass back mbus_code_to_bus_cfg error codes mbus_code_to_bus_cfg() can fail on unknown mbus codes; pass back the error to the caller. Signed-off-by: Enrico Scholz <enrico.scholz@sigma-chemnitz.de> Signed-off-by: Jan Luebbe <jlu@pengutronix.de> [p.zabel@pengutronix.de - renamed rc to ret for consistency] Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de> --- drivers/gpu/ipu-v3/ipu-csi.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/ipu-v3/ipu-csi.c b/drivers/gpu/ipu-v3/ipu-csi.c index 813a3199aa844..27262748a549d 100644 --- a/drivers/gpu/ipu-v3/ipu-csi.c +++ b/drivers/gpu/ipu-v3/ipu-csi.c @@ -324,13 +324,17 @@ static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code) /* * Fill a CSI bus config struct from mbus_config and mbus_framefmt. */ -static void fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg, +static int fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg, struct v4l2_mbus_config *mbus_cfg, struct v4l2_mbus_framefmt *mbus_fmt) { + int ret; + memset(csicfg, 0, sizeof(*csicfg)); - mbus_code_to_bus_cfg(csicfg, mbus_fmt->code); + ret = mbus_code_to_bus_cfg(csicfg, mbus_fmt->code); + if (ret < 0) + return ret; switch (mbus_cfg->type) { case V4L2_MBUS_PARALLEL: @@ -362,6 +366,8 @@ static void fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg, /* will never get here, keep compiler quiet */ break; } + + return 0; } int ipu_csi_init_interface(struct ipu_csi *csi, @@ -371,8 +377,11 @@ int ipu_csi_init_interface(struct ipu_csi *csi, struct ipu_csi_bus_config cfg; unsigned long flags; u32 width, height, data = 0; + int ret; - fill_csi_bus_cfg(&cfg, mbus_cfg, mbus_fmt); + ret = fill_csi_bus_cfg(&cfg, mbus_cfg, mbus_fmt); + if (ret < 0) + return ret; /* set default sensor frame width and height */ width = mbus_fmt->width; @@ -593,11 +602,14 @@ int ipu_csi_set_mipi_datatype(struct ipu_csi *csi, u32 vc, struct ipu_csi_bus_config cfg; unsigned long flags; u32 temp; + int ret; if (vc > 3) return -EINVAL; - mbus_code_to_bus_cfg(&cfg, mbus_fmt->code); + ret = mbus_code_to_bus_cfg(&cfg, mbus_fmt->code); + if (ret < 0) + return ret; spin_lock_irqsave(&csi->lock, flags); -- GitLab From 1e6a1495c66947b289de9ba92b569b62ce68a979 Mon Sep 17 00:00:00 2001 From: Jan Luebbe <jlu@pengutronix.de> Date: Thu, 3 May 2018 18:29:37 +0200 Subject: [PATCH 1201/1506] gpu: ipu-v3: csi: support RGB565 on parallel bus The CSI_SENS_CONF_DATA_FMT_RGB565 configuration only works for MIPI CSI-2 sources. On the parallel bus, we need to use bayer (generic) mode instead. To handle this difference, we pass the mbus_type to mbus_code_to_bus_cfg(). Signed-off-by: Jan Luebbe <jlu@pengutronix.de> [p.zabel@pengutronix.de - renamed rc to ret for consistency] Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de> --- drivers/gpu/ipu-v3/ipu-csi.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/ipu-v3/ipu-csi.c b/drivers/gpu/ipu-v3/ipu-csi.c index 27262748a549d..954eefe144e2d 100644 --- a/drivers/gpu/ipu-v3/ipu-csi.c +++ b/drivers/gpu/ipu-v3/ipu-csi.c @@ -224,14 +224,18 @@ static int ipu_csi_set_testgen_mclk(struct ipu_csi *csi, u32 pixel_clk, * Find the CSI data format and data width for the given V4L2 media * bus pixel format code. */ -static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code) +static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code, + enum v4l2_mbus_type mbus_type) { switch (mbus_code) { case MEDIA_BUS_FMT_BGR565_2X8_BE: case MEDIA_BUS_FMT_BGR565_2X8_LE: case MEDIA_BUS_FMT_RGB565_2X8_BE: case MEDIA_BUS_FMT_RGB565_2X8_LE: - cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB565; + if (mbus_type == V4L2_MBUS_CSI2) + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB565; + else + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER; cfg->mipi_dt = MIPI_DT_RGB565; cfg->data_width = IPU_CSI_DATA_WIDTH_8; break; @@ -332,7 +336,7 @@ static int fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg, memset(csicfg, 0, sizeof(*csicfg)); - ret = mbus_code_to_bus_cfg(csicfg, mbus_fmt->code); + ret = mbus_code_to_bus_cfg(csicfg, mbus_fmt->code, mbus_cfg->type); if (ret < 0) return ret; @@ -607,7 +611,7 @@ int ipu_csi_set_mipi_datatype(struct ipu_csi *csi, u32 vc, if (vc > 3) return -EINVAL; - ret = mbus_code_to_bus_cfg(&cfg, mbus_fmt->code); + ret = mbus_code_to_bus_cfg(&cfg, mbus_fmt->code, V4L2_MBUS_CSI2); if (ret < 0) return ret; -- GitLab From 4e3c5d7e05be6c9c6de4f4da9116511428924997 Mon Sep 17 00:00:00 2001 From: Philipp Zabel <p.zabel@pengutronix.de> Date: Fri, 1 Jun 2018 15:13:16 +0200 Subject: [PATCH 1202/1506] gpu: ipu-v3: Allow negative offsets for interlaced scanning The IPU also supports interlaced buffers that start with the bottom field. To achieve this, the the base address EBA has to be increased by a stride length and the interlace offset ILO has to be set to the negative stride. Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de> Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com> --- drivers/gpu/ipu-v3/ipu-cpmem.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/ipu-v3/ipu-cpmem.c b/drivers/gpu/ipu-v3/ipu-cpmem.c index 9f2d9ec42add6..125721a7f8b6d 100644 --- a/drivers/gpu/ipu-v3/ipu-cpmem.c +++ b/drivers/gpu/ipu-v3/ipu-cpmem.c @@ -269,9 +269,20 @@ EXPORT_SYMBOL_GPL(ipu_cpmem_set_uv_offset); void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride) { + u32 ilo, sly; + + if (stride < 0) { + stride = -stride; + ilo = 0x100000 - (stride / 8); + } else { + ilo = stride / 8; + } + + sly = (stride * 2) - 1; + ipu_ch_param_write_field(ch, IPU_FIELD_SO, 1); - ipu_ch_param_write_field(ch, IPU_FIELD_ILO, stride / 8); - ipu_ch_param_write_field(ch, IPU_FIELD_SLY, (stride * 2) - 1); + ipu_ch_param_write_field(ch, IPU_FIELD_ILO, ilo); + ipu_ch_param_write_field(ch, IPU_FIELD_SLY, sly); }; EXPORT_SYMBOL_GPL(ipu_cpmem_interlaced_scan); -- GitLab From 71a5cb3eb758b5b3735709c7fca577522eda43d4 Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe <alexandru-cosmin.gheorghe@arm.com> Date: Fri, 13 Jul 2018 16:10:58 +0100 Subject: [PATCH 1203/1506] drm: writeback: Fix doc that says connector should be disconnected During iteration process one of the proposed mechanism for not breaking existing userspace was to report writeback connectors as disconnected, however the final version used DRM_CLIENT_CAP_WRITEBACK_CONNECTORS for that purpose. Change-Id: I2319d099f7669094c8530f1521abdbca08e76486 Signed-off-by: Alexandru Gheorghe <alexandru-cosmin.gheorghe@arm.com> Reviewed-by: Sean Paul <seanpaul@chromium.org> Acked-by: Liviu Dudau <liviu.dudau@arm.com> Link: https://patchwork.freedesktop.org/patch/238399/ --- drivers/gpu/drm/drm_writeback.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_writeback.c b/drivers/gpu/drm/drm_writeback.c index 169746f6b5677..c20e6fe00cb38 100644 --- a/drivers/gpu/drm/drm_writeback.c +++ b/drivers/gpu/drm/drm_writeback.c @@ -25,8 +25,8 @@ * * * Writeback connectors don't provide a way to output visually to the user. * - * * Writeback connectors should always report as "disconnected" (so that - * clients which don't understand them will ignore them). + * * Writeback connectors are visible to userspace only when the client sets + * DRM_CLIENT_CAP_WRITEBACK_CONNECTORS. * * * Writeback connectors don't have EDID. * -- GitLab From a18b21929453af70390e14f8dee40acf00d428cb Mon Sep 17 00:00:00 2001 From: Lyude Paul <lyude@redhat.com> Date: Mon, 16 Jul 2018 11:44:32 -0400 Subject: [PATCH 1204/1506] drm/dp_helper: Add DP aux channel tracing This is something we've needed for a very long time now, as it makes debugging issues with faulty MST hubs along with debugging issues regarding us interfacing with hubs correctly vastly easier to debug. Currently this can actually be done if you trace the i2c devices for DP using ftrace but that's significantly less useful for a couple of reasons: - Tracing the i2c devices through ftrace means all of the traces are going to contain a lot of "garbage" output that we're sending over the i2c line. Most of this garbage comes from retrying transactions, DRM's helper library adding extra transactions to work around bad hubs, etc. - Having a user set up ftrace so that they can provide debugging information is a lot more difficult then being able to say "just boot with drm.debug=0x100" - We can potentially expand upon this tracing in the future to print debugging information in regards to other DP transactions like MST sideband transactions This is inspired by a patch Rob Clark sent to do this a long time back. Neither of us could find the patch however, so we both assumed it would probably just be easier to rewrite it anyway. Cc: Rob Clark <robdclark@gmail.com> Signed-off-by: Lyude Paul <lyude@redhat.com> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20180716154432.13433-1-lyude@redhat.com --- drivers/gpu/drm/drm_dp_helper.c | 32 +++++++++++++++++++++++++++----- drivers/gpu/drm/drm_drv.c | 15 ++++++++------- include/drm/drm_print.h | 6 ++++++ 3 files changed, 41 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index f4a06b54aa7df..0cccbcb2d03ea 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -185,6 +185,20 @@ EXPORT_SYMBOL(drm_dp_bw_code_to_link_rate); #define AUX_RETRY_INTERVAL 500 /* us */ +static inline void +drm_dp_dump_access(const struct drm_dp_aux *aux, + u8 request, uint offset, void *buffer, int ret) +{ + const char *arrow = request == DP_AUX_NATIVE_READ ? "->" : "<-"; + + if (ret > 0) + drm_dbg(DRM_UT_DP, "%s: 0x%05x AUX %s (ret=%3d) %*ph\n", + aux->name, offset, arrow, ret, min(ret, 20), buffer); + else + drm_dbg(DRM_UT_DP, "%s: 0x%05x AUX %s (ret=%3d)\n", + aux->name, offset, arrow, ret); +} + /** * DOC: dp helpers * @@ -288,10 +302,14 @@ ssize_t drm_dp_dpcd_read(struct drm_dp_aux *aux, unsigned int offset, ret = drm_dp_dpcd_access(aux, DP_AUX_NATIVE_READ, DP_DPCD_REV, buffer, 1); if (ret != 1) - return ret; + goto out; - return drm_dp_dpcd_access(aux, DP_AUX_NATIVE_READ, offset, buffer, - size); + ret = drm_dp_dpcd_access(aux, DP_AUX_NATIVE_READ, offset, buffer, + size); + +out: + drm_dp_dump_access(aux, DP_AUX_NATIVE_READ, offset, buffer, ret); + return ret; } EXPORT_SYMBOL(drm_dp_dpcd_read); @@ -312,8 +330,12 @@ EXPORT_SYMBOL(drm_dp_dpcd_read); ssize_t drm_dp_dpcd_write(struct drm_dp_aux *aux, unsigned int offset, void *buffer, size_t size) { - return drm_dp_dpcd_access(aux, DP_AUX_NATIVE_WRITE, offset, buffer, - size); + int ret; + + ret = drm_dp_dpcd_access(aux, DP_AUX_NATIVE_WRITE, offset, buffer, + size); + drm_dp_dump_access(aux, DP_AUX_NATIVE_WRITE, offset, buffer, ret); + return ret; } EXPORT_SYMBOL(drm_dp_dpcd_write); diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 6eb935bb2f92f..ea4941da9b273 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -54,13 +54,14 @@ MODULE_AUTHOR("Gareth Hughes, Leif Delgass, José Fonseca, Jon Smirl"); MODULE_DESCRIPTION("DRM shared core routines"); MODULE_LICENSE("GPL and additional rights"); MODULE_PARM_DESC(debug, "Enable debug output, where each bit enables a debug category.\n" -"\t\tBit 0 (0x01) will enable CORE messages (drm core code)\n" -"\t\tBit 1 (0x02) will enable DRIVER messages (drm controller code)\n" -"\t\tBit 2 (0x04) will enable KMS messages (modesetting code)\n" -"\t\tBit 3 (0x08) will enable PRIME messages (prime code)\n" -"\t\tBit 4 (0x10) will enable ATOMIC messages (atomic code)\n" -"\t\tBit 5 (0x20) will enable VBL messages (vblank code)\n" -"\t\tBit 7 (0x80) will enable LEASE messages (leasing code)"); +"\t\tBit 0 (0x01) will enable CORE messages (drm core code)\n" +"\t\tBit 1 (0x02) will enable DRIVER messages (drm controller code)\n" +"\t\tBit 2 (0x04) will enable KMS messages (modesetting code)\n" +"\t\tBit 3 (0x08) will enable PRIME messages (prime code)\n" +"\t\tBit 4 (0x10) will enable ATOMIC messages (atomic code)\n" +"\t\tBit 5 (0x20) will enable VBL messages (vblank code)\n" +"\t\tBit 7 (0x80) will enable LEASE messages (leasing code)\n" +"\t\tBit 8 (0x100) will enable DP messages (displayport code)"); module_param_named(debug, drm_debug, int, 0600); static DEFINE_SPINLOCK(drm_minor_lock); diff --git a/include/drm/drm_print.h b/include/drm/drm_print.h index e1a46e9991cca..767c90b654c53 100644 --- a/include/drm/drm_print.h +++ b/include/drm/drm_print.h @@ -195,6 +195,7 @@ static inline struct drm_printer drm_debug_printer(const char *prefix) #define DRM_UT_VBL 0x20 #define DRM_UT_STATE 0x40 #define DRM_UT_LEASE 0x80 +#define DRM_UT_DP 0x100 __printf(3, 4) void drm_dev_printk(const struct device *dev, const char *level, @@ -307,6 +308,11 @@ void drm_err(const char *format, ...); #define DRM_DEBUG_LEASE(fmt, ...) \ drm_dbg(DRM_UT_LEASE, fmt, ##__VA_ARGS__) +#define DRM_DEV_DEBUG_DP(dev, fmt, ...) \ + drm_dev_dbg(dev, DRM_UT_DP, fmt, ## __VA_ARGS__) +#define DRM_DEBUG_DP(dev, fmt, ...) \ + drm_dbg(DRM_UT_DP, fmt, ## __VA_ARGS__) + #define _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, category, fmt, ...) \ ({ \ static DEFINE_RATELIMIT_STATE(_rs, \ -- GitLab From 0051163ab3d8090a08ea2ea5edbb738c0920000a Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Mon, 16 Jul 2018 13:54:24 +0100 Subject: [PATCH 1205/1506] drm/i915/execlists: Always clear preempt status on cancelling all On reset/wedging, we cancel all pending replies from the HW and we also want to cancel an outstanding preemption event. Since we use the same function to cancel the pending replies for reset and for a preemption event, we can simply clear the active tracking for all. v2: Keep execlists_user_end() markup for wedging v3: Move assignment to inline to hide the bare assignment. Fixes: 60a943245413 ("drm/i915/execlists: Drop clear_gtiir() on GPU reset") Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180716125424.5715-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_guc_submission.c | 2 -- drivers/gpu/drm/i915/intel_lrc.c | 6 ++---- drivers/gpu/drm/i915/intel_ringbuffer.h | 6 ++++++ 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_guc_submission.c b/drivers/gpu/drm/i915/intel_guc_submission.c index cc444dc5f3adb..94d0674ea3c6a 100644 --- a/drivers/gpu/drm/i915/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/intel_guc_submission.c @@ -633,8 +633,6 @@ static void complete_preempt_context(struct intel_engine_cs *engine) wait_for_guc_preempt_report(engine); intel_write_status_page(engine, I915_GEM_HWS_PREEMPT_INDEX, 0); - - execlists_clear_active(execlists, EXECLISTS_ACTIVE_PREEMPT); } /** diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 629127e035770..c0ee14f867549 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -563,8 +563,6 @@ static void complete_preempt_context(struct intel_engine_execlists *execlists) __unwind_incomplete_requests(container_of(execlists, struct intel_engine_cs, execlists)); - - execlists_clear_active(execlists, EXECLISTS_ACTIVE_PREEMPT); } static void execlists_dequeue(struct intel_engine_cs *engine) @@ -792,8 +790,7 @@ execlists_cancel_port_requests(struct intel_engine_execlists * const execlists) port++; } - execlists_clear_active(execlists, EXECLISTS_ACTIVE_USER); - execlists_user_end(execlists); + execlists_clear_all_active(execlists); } static void reset_csb_pointers(struct intel_engine_execlists *execlists) @@ -844,6 +841,7 @@ static void execlists_cancel_requests(struct intel_engine_cs *engine) /* Cancel the requests on the HW and clear the ELSP tracker. */ execlists_cancel_port_requests(execlists); + execlists_user_end(execlists); /* Mark all executing requests as skipped. */ list_for_each_entry(rq, &engine->timeline.requests, link) { diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index d1eee08e5f6bb..665b59ba1f45d 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -683,6 +683,12 @@ execlists_clear_active(struct intel_engine_execlists *execlists, __clear_bit(bit, (unsigned long *)&execlists->active); } +static inline void +execlists_clear_all_active(struct intel_engine_execlists *execlists) +{ + execlists->active = 0; +} + static inline bool execlists_is_active(const struct intel_engine_execlists *execlists, unsigned int bit) -- GitLab From 0f6b79fa138d781b978bcff22680662fd351cd2d Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Mon, 16 Jul 2018 14:21:54 +0100 Subject: [PATCH 1206/1506] drm/i915/selftests: Force a preemption hang Inject a failure into preemption completion to pretend as if the HW didn't successfully handle preemption and we are forced to do a reset in the middle. v2: Wait for preemption, to force testing with the missed preemption. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180716132154.12539-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_guc_submission.c | 3 + drivers/gpu/drm/i915/intel_lrc.c | 3 + drivers/gpu/drm/i915/intel_ringbuffer.h | 27 +++++ drivers/gpu/drm/i915/selftests/intel_lrc.c | 115 ++++++++++++++++++++ 4 files changed, 148 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_guc_submission.c b/drivers/gpu/drm/i915/intel_guc_submission.c index 94d0674ea3c6a..0fa1eb0bfff54 100644 --- a/drivers/gpu/drm/i915/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/intel_guc_submission.c @@ -628,6 +628,9 @@ static void complete_preempt_context(struct intel_engine_cs *engine) GEM_BUG_ON(!execlists_is_active(execlists, EXECLISTS_ACTIVE_PREEMPT)); + if (inject_preempt_hang(execlists)) + return; + execlists_cancel_port_requests(execlists); execlists_unwind_incomplete_requests(execlists); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index c0ee14f867549..db5351e6a3a53 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -559,6 +559,9 @@ static void complete_preempt_context(struct intel_engine_execlists *execlists) { GEM_BUG_ON(!execlists_is_active(execlists, EXECLISTS_ACTIVE_PREEMPT)); + if (inject_preempt_hang(execlists)) + return; + execlists_cancel_port_requests(execlists); __unwind_incomplete_requests(container_of(execlists, struct intel_engine_cs, diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 665b59ba1f45d..f5ffa6d31e82c 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -193,6 +193,11 @@ struct i915_priolist { int priority; }; +struct st_preempt_hang { + struct completion completion; + bool inject_hang; +}; + /** * struct intel_engine_execlists - execlist submission queue and port state * @@ -333,6 +338,8 @@ struct intel_engine_execlists { * @csb_head: context status buffer head */ u8 csb_head; + + I915_SELFTEST_DECLARE(struct st_preempt_hang preempt_hang;) }; #define INTEL_ENGINE_CS_MAX_NAME 8 @@ -1155,4 +1162,24 @@ void intel_disable_engine_stats(struct intel_engine_cs *engine); ktime_t intel_engine_get_busy_time(struct intel_engine_cs *engine); +#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) + +static inline bool inject_preempt_hang(struct intel_engine_execlists *execlists) +{ + if (!execlists->preempt_hang.inject_hang) + return false; + + complete(&execlists->preempt_hang.completion); + return true; +} + +#else + +static inline bool inject_preempt_hang(struct intel_engine_execlists *execlists) +{ + return false; +} + +#endif + #endif /* _INTEL_RINGBUFFER_H_ */ diff --git a/drivers/gpu/drm/i915/selftests/intel_lrc.c b/drivers/gpu/drm/i915/selftests/intel_lrc.c index 636cb68191e3b..582566faef090 100644 --- a/drivers/gpu/drm/i915/selftests/intel_lrc.c +++ b/drivers/gpu/drm/i915/selftests/intel_lrc.c @@ -451,12 +451,127 @@ static int live_late_preempt(void *arg) goto err_ctx_lo; } +static int live_preempt_hang(void *arg) +{ + struct drm_i915_private *i915 = arg; + struct i915_gem_context *ctx_hi, *ctx_lo; + struct spinner spin_hi, spin_lo; + struct intel_engine_cs *engine; + enum intel_engine_id id; + int err = -ENOMEM; + + if (!HAS_LOGICAL_RING_PREEMPTION(i915)) + return 0; + + if (!intel_has_reset_engine(i915)) + return 0; + + mutex_lock(&i915->drm.struct_mutex); + + if (spinner_init(&spin_hi, i915)) + goto err_unlock; + + if (spinner_init(&spin_lo, i915)) + goto err_spin_hi; + + ctx_hi = kernel_context(i915); + if (!ctx_hi) + goto err_spin_lo; + ctx_hi->sched.priority = I915_CONTEXT_MAX_USER_PRIORITY; + + ctx_lo = kernel_context(i915); + if (!ctx_lo) + goto err_ctx_hi; + ctx_lo->sched.priority = I915_CONTEXT_MIN_USER_PRIORITY; + + for_each_engine(engine, i915, id) { + struct i915_request *rq; + + if (!intel_engine_has_preemption(engine)) + continue; + + rq = spinner_create_request(&spin_lo, ctx_lo, engine, + MI_ARB_CHECK); + if (IS_ERR(rq)) { + err = PTR_ERR(rq); + goto err_ctx_lo; + } + + i915_request_add(rq); + if (!wait_for_spinner(&spin_lo, rq)) { + GEM_TRACE("lo spinner failed to start\n"); + GEM_TRACE_DUMP(); + i915_gem_set_wedged(i915); + err = -EIO; + goto err_ctx_lo; + } + + rq = spinner_create_request(&spin_hi, ctx_hi, engine, + MI_ARB_CHECK); + if (IS_ERR(rq)) { + spinner_end(&spin_lo); + err = PTR_ERR(rq); + goto err_ctx_lo; + } + + init_completion(&engine->execlists.preempt_hang.completion); + engine->execlists.preempt_hang.inject_hang = true; + + i915_request_add(rq); + + if (!wait_for_completion_timeout(&engine->execlists.preempt_hang.completion, + HZ / 10)) { + pr_err("Preemption did not occur within timeout!"); + GEM_TRACE_DUMP(); + i915_gem_set_wedged(i915); + err = -EIO; + goto err_ctx_lo; + } + + set_bit(I915_RESET_ENGINE + id, &i915->gpu_error.flags); + i915_reset_engine(engine, NULL); + clear_bit(I915_RESET_ENGINE + id, &i915->gpu_error.flags); + + engine->execlists.preempt_hang.inject_hang = false; + + if (!wait_for_spinner(&spin_hi, rq)) { + GEM_TRACE("hi spinner failed to start\n"); + GEM_TRACE_DUMP(); + i915_gem_set_wedged(i915); + err = -EIO; + goto err_ctx_lo; + } + + spinner_end(&spin_hi); + spinner_end(&spin_lo); + if (igt_flush_test(i915, I915_WAIT_LOCKED)) { + err = -EIO; + goto err_ctx_lo; + } + } + + err = 0; +err_ctx_lo: + kernel_context_close(ctx_lo); +err_ctx_hi: + kernel_context_close(ctx_hi); +err_spin_lo: + spinner_fini(&spin_lo); +err_spin_hi: + spinner_fini(&spin_hi); +err_unlock: + igt_flush_test(i915, I915_WAIT_LOCKED); + mutex_unlock(&i915->drm.struct_mutex); + return err; +} + int intel_execlists_live_selftests(struct drm_i915_private *i915) { static const struct i915_subtest tests[] = { SUBTEST(live_sanitycheck), SUBTEST(live_preempt), SUBTEST(live_late_preempt), + SUBTEST(live_preempt_hang), }; if (!HAS_EXECLISTS(i915)) -- GitLab From 26094c02934e9aceee8f7386a8e28190262a69d3 Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexander.deucher@amd.com> Date: Wed, 11 Jul 2018 17:30:25 -0500 Subject: [PATCH 1207/1506] drm/amdgpu/pp: remove dead vega12 code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commented out. Reviewed-by: Rex Zhu <rezhu@amd.com> Acked-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../drm/amd/powerplay/smumgr/vega12_smumgr.c | 29 ------------------- 1 file changed, 29 deletions(-) diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/vega12_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/vega12_smumgr.c index 7d9b40e8b1bf0..508a262fb328c 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/vega12_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/vega12_smumgr.c @@ -343,29 +343,6 @@ static int vega12_set_tools_address(struct pp_hwmgr *hwmgr) return 0; } -#if 0 /* tentatively remove */ -static int vega12_verify_smc_interface(struct pp_hwmgr *hwmgr) -{ - uint32_t smc_driver_if_version; - - PP_ASSERT_WITH_CODE(!vega12_send_msg_to_smc(hwmgr, - PPSMC_MSG_GetDriverIfVersion), - "Attempt to get SMC IF Version Number Failed!", - return -EINVAL); - vega12_read_arg_from_smc(hwmgr, &smc_driver_if_version); - - if (smc_driver_if_version != SMU9_DRIVER_IF_VERSION) { - pr_err("Your firmware(0x%x) doesn't match \ - SMU9_DRIVER_IF_VERSION(0x%x). \ - Please update your firmware!\n", - smc_driver_if_version, SMU9_DRIVER_IF_VERSION); - return -EINVAL; - } - - return 0; -} -#endif - static int vega12_smu_init(struct pp_hwmgr *hwmgr) { struct vega12_smumgr *priv; @@ -517,12 +494,6 @@ static int vega12_start_smu(struct pp_hwmgr *hwmgr) "SMC is not running!", return -EINVAL); -#if 0 /* tentatively remove */ - PP_ASSERT_WITH_CODE(!vega12_verify_smc_interface(hwmgr), - "Failed to verify SMC interface!", - return -EINVAL); -#endif - vega12_set_tools_address(hwmgr); return 0; -- GitLab From ce7577a2194b58bf7faf303612a24b7cd5210afc Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexander.deucher@amd.com> Date: Thu, 12 Jul 2018 14:47:30 -0500 Subject: [PATCH 1208/1506] drm/amdgpu/pp: split out common smumgr smu9 code Split out the shared smumgr code for vega10 and 12 so we don't have duplicate code for both. Reviewed-by: Rex Zhu <rezhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../drm/amd/powerplay/hwmgr/vega12_hwmgr.c | 44 ++-- .../drm/amd/powerplay/hwmgr/vega12_thermal.c | 8 +- drivers/gpu/drm/amd/powerplay/smumgr/Makefile | 2 +- .../drm/amd/powerplay/smumgr/smu9_smumgr.c | 150 ++++++++++++++ .../drm/amd/powerplay/smumgr/smu9_smumgr.h | 32 +++ .../drm/amd/powerplay/smumgr/vega10_smumgr.c | 168 ++------------- .../drm/amd/powerplay/smumgr/vega12_smumgr.c | 191 ++---------------- .../drm/amd/powerplay/smumgr/vega12_smumgr.h | 1 - 8 files changed, 242 insertions(+), 354 deletions(-) create mode 100644 drivers/gpu/drm/amd/powerplay/smumgr/smu9_smumgr.c create mode 100644 drivers/gpu/drm/amd/powerplay/smumgr/smu9_smumgr.h diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c index c0ceb69a23b0d..912d0d6cf4765 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c @@ -477,7 +477,7 @@ static int vega12_get_number_of_dpm_level(struct pp_hwmgr *hwmgr, "[GetNumOfDpmLevel] failed to get dpm levels!", return ret); - vega12_read_arg_from_smc(hwmgr, num_of_levels); + *num_of_levels = smum_get_argument(hwmgr); PP_ASSERT_WITH_CODE(*num_of_levels > 0, "[GetNumOfDpmLevel] number of clk levels is invalid!", return -EINVAL); @@ -499,11 +499,7 @@ static int vega12_get_dpm_frequency_by_index(struct pp_hwmgr *hwmgr, "[GetDpmFrequencyByIndex] Failed to get dpm frequency from SMU!", return -EINVAL); - result = vega12_read_arg_from_smc(hwmgr, clock); - - PP_ASSERT_WITH_CODE(*clock != 0, - "[GetDPMFrequencyByIndex] Failed to get dpm frequency by index.!", - return -EINVAL); + *clock = smum_get_argument(hwmgr); return result; } @@ -884,21 +880,21 @@ static int vega12_get_all_clock_ranges_helper(struct pp_hwmgr *hwmgr, smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_GetMaxDpmFreq, (clkid << 16)) == 0, "[GetClockRanges] Failed to get max ac clock from SMC!", return -EINVAL); - vega12_read_arg_from_smc(hwmgr, &(clock->ACMax)); + clock->ACMax = smum_get_argument(hwmgr); /* AC Min */ PP_ASSERT_WITH_CODE( smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_GetMinDpmFreq, (clkid << 16)) == 0, "[GetClockRanges] Failed to get min ac clock from SMC!", return -EINVAL); - vega12_read_arg_from_smc(hwmgr, &(clock->ACMin)); + clock->ACMin = smum_get_argument(hwmgr); /* DC Max */ PP_ASSERT_WITH_CODE( smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_GetDcModeMaxDpmFreq, (clkid << 16)) == 0, "[GetClockRanges] Failed to get max dc clock from SMC!", return -EINVAL); - vega12_read_arg_from_smc(hwmgr, &(clock->DCMax)); + clock->DCMax = smum_get_argument(hwmgr); return 0; } @@ -1219,7 +1215,7 @@ static int vega12_get_gpu_power(struct pp_hwmgr *hwmgr, uint32_t *query) "Failed to get current package power!", return -EINVAL); - vega12_read_arg_from_smc(hwmgr, &value); + value = smum_get_argument(hwmgr); /* power value is an integer */ *query = value << 8; #endif @@ -1235,11 +1231,8 @@ static int vega12_get_current_gfx_clk_freq(struct pp_hwmgr *hwmgr, uint32_t *gfx PP_ASSERT_WITH_CODE(smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_GetDpmClockFreq, (PPCLK_GFXCLK << 16)) == 0, "[GetCurrentGfxClkFreq] Attempt to get Current GFXCLK Frequency Failed!", - return -1); - PP_ASSERT_WITH_CODE( - vega12_read_arg_from_smc(hwmgr, &gfx_clk) == 0, - "[GetCurrentGfxClkFreq] Attempt to read arg from SMC Failed", - return -1); + return -EINVAL); + gfx_clk = smum_get_argument(hwmgr); *gfx_freq = gfx_clk * 100; @@ -1255,11 +1248,8 @@ static int vega12_get_current_mclk_freq(struct pp_hwmgr *hwmgr, uint32_t *mclk_f PP_ASSERT_WITH_CODE( smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_GetDpmClockFreq, (PPCLK_UCLK << 16)) == 0, "[GetCurrentMClkFreq] Attempt to get Current MCLK Frequency Failed!", - return -1); - PP_ASSERT_WITH_CODE( - vega12_read_arg_from_smc(hwmgr, &mem_clk) == 0, - "[GetCurrentMClkFreq] Attempt to read arg from SMC Failed", - return -1); + return -EINVAL); + mem_clk = smum_get_argument(hwmgr); *mclk_freq = mem_clk * 100; @@ -1276,16 +1266,12 @@ static int vega12_get_current_activity_percent( #if 0 ret = smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_GetAverageGfxActivity, 0); if (!ret) { - ret = vega12_read_arg_from_smc(hwmgr, ¤t_activity); - if (!ret) { - if (current_activity > 100) { - PP_ASSERT(false, - "[GetCurrentActivityPercent] Activity Percentage Exceeds 100!"); - current_activity = 100; - } - } else + current_activity = smum_get_argument(hwmgr); + if (current_activity > 100) { PP_ASSERT(false, - "[GetCurrentActivityPercent] Attempt To Read Average Graphics Activity from SMU Failed!"); + "[GetCurrentActivityPercent] Activity Percentage Exceeds 100!"); + current_activity = 100; + } } else PP_ASSERT(false, "[GetCurrentActivityPercent] Attempt To Send Get Average Graphics Activity to SMU Failed!"); diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_thermal.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_thermal.c index cfd9e6ccb7901..904eb2c9155b4 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_thermal.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_thermal.c @@ -34,11 +34,9 @@ static int vega12_get_current_rpm(struct pp_hwmgr *hwmgr, uint32_t *current_rpm) PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetCurrentRpm), "Attempt to get current RPM from SMC Failed!", - return -1); - PP_ASSERT_WITH_CODE(!vega12_read_arg_from_smc(hwmgr, - current_rpm), - "Attempt to read current RPM from SMC Failed!", - return -1); + return -EINVAL); + *current_rpm = smum_get_argument(hwmgr); + return 0; } diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/Makefile b/drivers/gpu/drm/amd/powerplay/smumgr/Makefile index 0a200406a1ec2..8d557accaef2a 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/Makefile +++ b/drivers/gpu/drm/amd/powerplay/smumgr/Makefile @@ -26,7 +26,7 @@ SMU_MGR = smumgr.o smu8_smumgr.o tonga_smumgr.o fiji_smumgr.o \ polaris10_smumgr.o iceland_smumgr.o \ smu7_smumgr.o vega10_smumgr.o smu10_smumgr.o ci_smumgr.o \ - vega12_smumgr.o vegam_smumgr.o + vega12_smumgr.o vegam_smumgr.o smu9_smumgr.o AMD_PP_SMUMGR = $(addprefix $(AMD_PP_PATH)/smumgr/,$(SMU_MGR)) diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu9_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/smu9_smumgr.c new file mode 100644 index 0000000000000..aad8f077f33cf --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/smumgr/smu9_smumgr.c @@ -0,0 +1,150 @@ +/* + * Copyright 2018 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "smumgr.h" +#include "vega10_inc.h" +#include "soc15_common.h" +#include "pp_debug.h" + + +/* MP Apertures */ +#define MP0_Public 0x03800000 +#define MP0_SRAM 0x03900000 +#define MP1_Public 0x03b00000 +#define MP1_SRAM 0x03c00004 + +#define smnMP1_FIRMWARE_FLAGS 0x3010028 + +bool smu9_is_smc_ram_running(struct pp_hwmgr *hwmgr) +{ + struct amdgpu_device *adev = hwmgr->adev; + uint32_t mp1_fw_flags; + + WREG32_SOC15(NBIF, 0, mmPCIE_INDEX2, + (MP1_Public | (smnMP1_FIRMWARE_FLAGS & 0xffffffff))); + + mp1_fw_flags = RREG32_SOC15(NBIF, 0, mmPCIE_DATA2); + + if (mp1_fw_flags & MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED_MASK) + return true; + + return false; +} + +/* + * Check if SMC has responded to previous message. + * + * @param smumgr the address of the powerplay hardware manager. + * @return TRUE SMC has responded, FALSE otherwise. + */ +static uint32_t smu9_wait_for_response(struct pp_hwmgr *hwmgr) +{ + struct amdgpu_device *adev = hwmgr->adev; + uint32_t reg; + uint32_t ret; + + reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); + + ret = phm_wait_for_register_unequal(hwmgr, reg, + 0, MP1_C2PMSG_90__CONTENT_MASK); + + if (ret) + pr_err("No response from smu\n"); + + return RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90); +} + +/* + * Send a message to the SMC, and do not wait for its response. + * @param smumgr the address of the powerplay hardware manager. + * @param msg the message to send. + * @return Always return 0. + */ +static int smu9_send_msg_to_smc_without_waiting(struct pp_hwmgr *hwmgr, + uint16_t msg) +{ + struct amdgpu_device *adev = hwmgr->adev; + + WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_66, msg); + + return 0; +} + +/* + * Send a message to the SMC, and wait for its response. + * @param hwmgr the address of the powerplay hardware manager. + * @param msg the message to send. + * @return Always return 0. + */ +int smu9_send_msg_to_smc(struct pp_hwmgr *hwmgr, uint16_t msg) +{ + struct amdgpu_device *adev = hwmgr->adev; + uint32_t ret; + + smu9_wait_for_response(hwmgr); + + WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90, 0); + + smu9_send_msg_to_smc_without_waiting(hwmgr, msg); + + ret = smu9_wait_for_response(hwmgr); + if (ret != 1) + pr_err("Failed to send message: 0x%x, ret value: 0x%x\n", msg, ret); + + return 0; +} + +/* + * Send a message to the SMC with parameter + * @param hwmgr: the address of the powerplay hardware manager. + * @param msg: the message to send. + * @param parameter: the parameter to send + * @return Always return 0. + */ +int smu9_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr, + uint16_t msg, uint32_t parameter) +{ + struct amdgpu_device *adev = hwmgr->adev; + uint32_t ret; + + smu9_wait_for_response(hwmgr); + + WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90, 0); + + WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_82, parameter); + + smu9_send_msg_to_smc_without_waiting(hwmgr, msg); + + ret = smu9_wait_for_response(hwmgr); + if (ret != 1) + pr_err("Failed message: 0x%x, input parameter: 0x%x, error code: 0x%x\n", msg, parameter, ret); + + return 0; +} + +int smu9_get_argument(struct pp_hwmgr *hwmgr) +{ + struct amdgpu_device *adev = hwmgr->adev; + + return RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_82); +} diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu9_smumgr.h b/drivers/gpu/drm/amd/powerplay/smumgr/smu9_smumgr.h new file mode 100644 index 0000000000000..a8da2815bd892 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/smumgr/smu9_smumgr.h @@ -0,0 +1,32 @@ +/* + * Copyright 2018 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ +#ifndef _SMU9_SMUMANAGER_H_ +#define _SMU9_SMUMANAGER_H_ + +bool smu9_is_smc_ram_running(struct pp_hwmgr *hwmgr); +int smu9_send_msg_to_smc(struct pp_hwmgr *hwmgr, uint16_t msg); +int smu9_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr, + uint16_t msg, uint32_t parameter); +int smu9_get_argument(struct pp_hwmgr *hwmgr); + +#endif diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c index e84669c448a30..5d19115f410c9 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c @@ -28,142 +28,11 @@ #include "vega10_hwmgr.h" #include "vega10_ppsmc.h" #include "smu9_driver_if.h" +#include "smu9_smumgr.h" #include "ppatomctrl.h" #include "pp_debug.h" -#define AVFS_EN_MSB 1568 -#define AVFS_EN_LSB 1568 - -/* Microcode file is stored in this buffer */ -#define BUFFER_SIZE 80000 -#define MAX_STRING_SIZE 15 -#define BUFFER_SIZETWO 131072 /* 128 *1024 */ - -/* MP Apertures */ -#define MP0_Public 0x03800000 -#define MP0_SRAM 0x03900000 -#define MP1_Public 0x03b00000 -#define MP1_SRAM 0x03c00004 - -#define smnMP1_FIRMWARE_FLAGS 0x3010028 -#define smnMP0_FW_INTF 0x3010104 -#define smnMP1_PUB_CTRL 0x3010b14 - -static bool vega10_is_smc_ram_running(struct pp_hwmgr *hwmgr) -{ - struct amdgpu_device *adev = hwmgr->adev; - uint32_t mp1_fw_flags; - - WREG32_SOC15(NBIF, 0, mmPCIE_INDEX2, - (MP1_Public | (smnMP1_FIRMWARE_FLAGS & 0xffffffff))); - - mp1_fw_flags = RREG32_SOC15(NBIF, 0, mmPCIE_DATA2); - - if (mp1_fw_flags & MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED_MASK) - return true; - - return false; -} - -/* - * Check if SMC has responded to previous message. - * - * @param smumgr the address of the powerplay hardware manager. - * @return TRUE SMC has responded, FALSE otherwise. - */ -static uint32_t vega10_wait_for_response(struct pp_hwmgr *hwmgr) -{ - struct amdgpu_device *adev = hwmgr->adev; - uint32_t reg; - uint32_t ret; - - reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); - - ret = phm_wait_for_register_unequal(hwmgr, reg, - 0, MP1_C2PMSG_90__CONTENT_MASK); - - if (ret) - pr_err("No response from smu\n"); - - return RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90); -} - -/* - * Send a message to the SMC, and do not wait for its response. - * @param smumgr the address of the powerplay hardware manager. - * @param msg the message to send. - * @return Always return 0. - */ -static int vega10_send_msg_to_smc_without_waiting(struct pp_hwmgr *hwmgr, - uint16_t msg) -{ - struct amdgpu_device *adev = hwmgr->adev; - - WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_66, msg); - - return 0; -} - -/* - * Send a message to the SMC, and wait for its response. - * @param hwmgr the address of the powerplay hardware manager. - * @param msg the message to send. - * @return Always return 0. - */ -static int vega10_send_msg_to_smc(struct pp_hwmgr *hwmgr, uint16_t msg) -{ - struct amdgpu_device *adev = hwmgr->adev; - uint32_t ret; - - vega10_wait_for_response(hwmgr); - - WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90, 0); - - vega10_send_msg_to_smc_without_waiting(hwmgr, msg); - - ret = vega10_wait_for_response(hwmgr); - if (ret != 1) - pr_err("Failed to send message: 0x%x, ret value: 0x%x\n", msg, ret); - - return 0; -} - -/* - * Send a message to the SMC with parameter - * @param hwmgr: the address of the powerplay hardware manager. - * @param msg: the message to send. - * @param parameter: the parameter to send - * @return Always return 0. - */ -static int vega10_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr, - uint16_t msg, uint32_t parameter) -{ - struct amdgpu_device *adev = hwmgr->adev; - uint32_t ret; - - vega10_wait_for_response(hwmgr); - - WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90, 0); - - WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_82, parameter); - - vega10_send_msg_to_smc_without_waiting(hwmgr, msg); - - ret = vega10_wait_for_response(hwmgr); - if (ret != 1) - pr_err("Failed message: 0x%x, input parameter: 0x%x, error code: 0x%x\n", msg, parameter, ret); - - return 0; -} - -static int vega10_get_argument(struct pp_hwmgr *hwmgr) -{ - struct amdgpu_device *adev = hwmgr->adev; - - return RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_82); -} - static int vega10_copy_table_from_smc(struct pp_hwmgr *hwmgr, uint8_t *table, int16_t table_id) { @@ -175,13 +44,13 @@ static int vega10_copy_table_from_smc(struct pp_hwmgr *hwmgr, "Invalid SMU Table version!", return -EINVAL); PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].size != 0, "Invalid SMU Table Length!", return -EINVAL); - vega10_send_msg_to_smc_with_parameter(hwmgr, + smu9_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetDriverDramAddrHigh, upper_32_bits(priv->smu_tables.entry[table_id].mc_addr)); - vega10_send_msg_to_smc_with_parameter(hwmgr, + smu9_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetDriverDramAddrLow, lower_32_bits(priv->smu_tables.entry[table_id].mc_addr)); - vega10_send_msg_to_smc_with_parameter(hwmgr, + smu9_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_TransferTableSmu2Dram, priv->smu_tables.entry[table_id].table_id); @@ -206,13 +75,13 @@ static int vega10_copy_table_to_smc(struct pp_hwmgr *hwmgr, memcpy(priv->smu_tables.entry[table_id].table, table, priv->smu_tables.entry[table_id].size); - vega10_send_msg_to_smc_with_parameter(hwmgr, + smu9_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetDriverDramAddrHigh, upper_32_bits(priv->smu_tables.entry[table_id].mc_addr)); - vega10_send_msg_to_smc_with_parameter(hwmgr, + smu9_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetDriverDramAddrLow, lower_32_bits(priv->smu_tables.entry[table_id].mc_addr)); - vega10_send_msg_to_smc_with_parameter(hwmgr, + smu9_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_TransferTableDram2Smu, priv->smu_tables.entry[table_id].table_id); @@ -225,8 +94,8 @@ static int vega10_get_smc_features(struct pp_hwmgr *hwmgr, if (features_enabled == NULL) return -EINVAL; - vega10_send_msg_to_smc(hwmgr, PPSMC_MSG_GetEnabledSmuFeatures); - *features_enabled = vega10_get_argument(hwmgr); + smu9_send_msg_to_smc(hwmgr, PPSMC_MSG_GetEnabledSmuFeatures); + *features_enabled = smu9_get_argument(hwmgr); return 0; } @@ -248,10 +117,10 @@ static int vega10_set_tools_address(struct pp_hwmgr *hwmgr) struct vega10_smumgr *priv = hwmgr->smu_backend; if (priv->smu_tables.entry[TOOLSTABLE].mc_addr) { - vega10_send_msg_to_smc_with_parameter(hwmgr, + smu9_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetToolsDramAddrHigh, upper_32_bits(priv->smu_tables.entry[TOOLSTABLE].mc_addr)); - vega10_send_msg_to_smc_with_parameter(hwmgr, + smu9_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetToolsDramAddrLow, lower_32_bits(priv->smu_tables.entry[TOOLSTABLE].mc_addr)); } @@ -265,11 +134,11 @@ static int vega10_verify_smc_interface(struct pp_hwmgr *hwmgr) uint32_t dev_id; uint32_t rev_id; - PP_ASSERT_WITH_CODE(!vega10_send_msg_to_smc(hwmgr, + PP_ASSERT_WITH_CODE(!smu9_send_msg_to_smc(hwmgr, PPSMC_MSG_GetDriverIfVersion), "Attempt to get SMC IF Version Number Failed!", return -EINVAL); - smc_driver_if_version = vega10_get_argument(hwmgr); + smc_driver_if_version = smu9_get_argument(hwmgr); dev_id = adev->pdev->device; rev_id = adev->pdev->revision; @@ -441,7 +310,7 @@ static int vega10_smu_fini(struct pp_hwmgr *hwmgr) static int vega10_start_smu(struct pp_hwmgr *hwmgr) { - if (!vega10_is_smc_ram_running(hwmgr)) + if (!smu9_is_smc_ram_running(hwmgr)) return -EINVAL; PP_ASSERT_WITH_CODE(!vega10_verify_smc_interface(hwmgr), @@ -453,7 +322,8 @@ static int vega10_start_smu(struct pp_hwmgr *hwmgr) return 0; } -static int vega10_smc_table_manager(struct pp_hwmgr *hwmgr, uint8_t *table, uint16_t table_id, bool rw) +static int vega10_smc_table_manager(struct pp_hwmgr *hwmgr, uint8_t *table, + uint16_t table_id, bool rw) { int ret; @@ -470,11 +340,11 @@ const struct pp_smumgr_func vega10_smu_funcs = { .smu_fini = &vega10_smu_fini, .start_smu = &vega10_start_smu, .request_smu_load_specific_fw = NULL, - .send_msg_to_smc = &vega10_send_msg_to_smc, - .send_msg_to_smc_with_parameter = &vega10_send_msg_to_smc_with_parameter, + .send_msg_to_smc = &smu9_send_msg_to_smc, + .send_msg_to_smc_with_parameter = &smu9_send_msg_to_smc_with_parameter, .download_pptable_settings = NULL, .upload_pptable_settings = NULL, .is_dpm_running = vega10_is_dpm_running, - .get_argument = vega10_get_argument, + .get_argument = smu9_get_argument, .smc_table_manager = vega10_smc_table_manager, }; diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/vega12_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/vega12_smumgr.c index 508a262fb328c..7f0e2109f40d7 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/vega12_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/vega12_smumgr.c @@ -24,157 +24,14 @@ #include "smumgr.h" #include "vega12_inc.h" #include "soc15_common.h" +#include "smu9_smumgr.h" #include "vega12_smumgr.h" #include "vega12_ppsmc.h" #include "vega12/smu9_driver_if.h" - #include "ppatomctrl.h" #include "pp_debug.h" -/* MP Apertures */ -#define MP0_Public 0x03800000 -#define MP0_SRAM 0x03900000 -#define MP1_Public 0x03b00000 -#define MP1_SRAM 0x03c00004 - -#define smnMP1_FIRMWARE_FLAGS 0x3010028 -#define smnMP0_FW_INTF 0x3010104 -#define smnMP1_PUB_CTRL 0x3010b14 - -static bool vega12_is_smc_ram_running(struct pp_hwmgr *hwmgr) -{ - struct amdgpu_device *adev = hwmgr->adev; - uint32_t mp1_fw_flags; - - WREG32_SOC15(NBIF, 0, mmPCIE_INDEX2, - (MP1_Public | (smnMP1_FIRMWARE_FLAGS & 0xffffffff))); - - mp1_fw_flags = RREG32_SOC15(NBIF, 0, mmPCIE_DATA2); - - if ((mp1_fw_flags & MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED_MASK) >> - MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED__SHIFT) - return true; - - return false; -} - -/* - * Check if SMC has responded to previous message. - * - * @param smumgr the address of the powerplay hardware manager. - * @return TRUE SMC has responded, FALSE otherwise. - */ -static uint32_t vega12_wait_for_response(struct pp_hwmgr *hwmgr) -{ - struct amdgpu_device *adev = hwmgr->adev; - uint32_t reg; - - reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); - - phm_wait_for_register_unequal(hwmgr, reg, - 0, MP1_C2PMSG_90__CONTENT_MASK); - - return RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90); -} - -/* - * Send a message to the SMC, and do not wait for its response. - * @param smumgr the address of the powerplay hardware manager. - * @param msg the message to send. - * @return Always return 0. - */ -int vega12_send_msg_to_smc_without_waiting(struct pp_hwmgr *hwmgr, - uint16_t msg) -{ - struct amdgpu_device *adev = hwmgr->adev; - - WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_66, msg); - - return 0; -} - -/* - * Send a message to the SMC, and wait for its response. - * @param hwmgr the address of the powerplay hardware manager. - * @param msg the message to send. - * @return Always return 0. - */ -int vega12_send_msg_to_smc(struct pp_hwmgr *hwmgr, uint16_t msg) -{ - struct amdgpu_device *adev = hwmgr->adev; - - vega12_wait_for_response(hwmgr); - - WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90, 0); - - vega12_send_msg_to_smc_without_waiting(hwmgr, msg); - - if (vega12_wait_for_response(hwmgr) != 1) - pr_err("Failed to send message: 0x%x\n", msg); - - return 0; -} - -/* - * Send a message to the SMC with parameter - * @param hwmgr: the address of the powerplay hardware manager. - * @param msg: the message to send. - * @param parameter: the parameter to send - * @return Always return 0. - */ -int vega12_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr, - uint16_t msg, uint32_t parameter) -{ - struct amdgpu_device *adev = hwmgr->adev; - - vega12_wait_for_response(hwmgr); - - WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90, 0); - - WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_82, parameter); - - vega12_send_msg_to_smc_without_waiting(hwmgr, msg); - - if (vega12_wait_for_response(hwmgr) != 1) - pr_err("Failed to send message: 0x%x\n", msg); - - return 0; -} - - -/* - * Send a message to the SMC with parameter, do not wait for response - * @param hwmgr: the address of the powerplay hardware manager. - * @param msg: the message to send. - * @param parameter: the parameter to send - * @return The response that came from the SMC. - */ -int vega12_send_msg_to_smc_with_parameter_without_waiting( - struct pp_hwmgr *hwmgr, uint16_t msg, uint32_t parameter) -{ - struct amdgpu_device *adev = hwmgr->adev; - - WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_66, parameter); - - return vega12_send_msg_to_smc_without_waiting(hwmgr, msg); -} - -/* - * Retrieve an argument from SMC. - * @param hwmgr the address of the powerplay hardware manager. - * @param arg pointer to store the argument from SMC. - * @return Always return 0. - */ -int vega12_read_arg_from_smc(struct pp_hwmgr *hwmgr, uint32_t *arg) -{ - struct amdgpu_device *adev = hwmgr->adev; - - *arg = RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_82); - - return 0; -} - /* * Copy table from SMC into driver FB * @param hwmgr the address of the HW manager @@ -192,16 +49,16 @@ int vega12_copy_table_from_smc(struct pp_hwmgr *hwmgr, "Invalid SMU Table version!", return -EINVAL); PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].size != 0, "Invalid SMU Table Length!", return -EINVAL); - PP_ASSERT_WITH_CODE(vega12_send_msg_to_smc_with_parameter(hwmgr, + PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetDriverDramAddrHigh, upper_32_bits(priv->smu_tables.entry[table_id].mc_addr)) == 0, "[CopyTableFromSMC] Attempt to Set Dram Addr High Failed!", return -EINVAL); - PP_ASSERT_WITH_CODE(vega12_send_msg_to_smc_with_parameter(hwmgr, + PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetDriverDramAddrLow, lower_32_bits(priv->smu_tables.entry[table_id].mc_addr)) == 0, "[CopyTableFromSMC] Attempt to Set Dram Addr Low Failed!", return -EINVAL); - PP_ASSERT_WITH_CODE(vega12_send_msg_to_smc_with_parameter(hwmgr, + PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_TransferTableSmu2Dram, table_id) == 0, "[CopyTableFromSMC] Attempt to Transfer Table From SMU Failed!", @@ -234,17 +91,17 @@ int vega12_copy_table_to_smc(struct pp_hwmgr *hwmgr, memcpy(priv->smu_tables.entry[table_id].table, table, priv->smu_tables.entry[table_id].size); - PP_ASSERT_WITH_CODE(vega12_send_msg_to_smc_with_parameter(hwmgr, + PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetDriverDramAddrHigh, upper_32_bits(priv->smu_tables.entry[table_id].mc_addr)) == 0, "[CopyTableToSMC] Attempt to Set Dram Addr High Failed!", return -EINVAL;); - PP_ASSERT_WITH_CODE(vega12_send_msg_to_smc_with_parameter(hwmgr, + PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetDriverDramAddrLow, lower_32_bits(priv->smu_tables.entry[table_id].mc_addr)) == 0, "[CopyTableToSMC] Attempt to Set Dram Addr Low Failed!", return -EINVAL); - PP_ASSERT_WITH_CODE(vega12_send_msg_to_smc_with_parameter(hwmgr, + PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_TransferTableDram2Smu, table_id) == 0, "[CopyTableToSMC] Attempt to Transfer Table To SMU Failed!", @@ -262,20 +119,20 @@ int vega12_enable_smc_features(struct pp_hwmgr *hwmgr, smu_features_high = (uint32_t)((feature_mask & SMU_FEATURES_HIGH_MASK) >> SMU_FEATURES_HIGH_SHIFT); if (enable) { - PP_ASSERT_WITH_CODE(vega12_send_msg_to_smc_with_parameter(hwmgr, + PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_EnableSmuFeaturesLow, smu_features_low) == 0, "[EnableDisableSMCFeatures] Attemp to enable SMU features Low failed!", return -EINVAL); - PP_ASSERT_WITH_CODE(vega12_send_msg_to_smc_with_parameter(hwmgr, + PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_EnableSmuFeaturesHigh, smu_features_high) == 0, "[EnableDisableSMCFeatures] Attemp to enable SMU features High failed!", return -EINVAL); } else { - PP_ASSERT_WITH_CODE(vega12_send_msg_to_smc_with_parameter(hwmgr, + PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_DisableSmuFeaturesLow, smu_features_low) == 0, "[EnableDisableSMCFeatures] Attemp to disable SMU features Low failed!", return -EINVAL); - PP_ASSERT_WITH_CODE(vega12_send_msg_to_smc_with_parameter(hwmgr, + PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_DisableSmuFeaturesHigh, smu_features_high) == 0, "[EnableDisableSMCFeatures] Attemp to disable SMU features High failed!", return -EINVAL); @@ -292,22 +149,17 @@ int vega12_get_enabled_smc_features(struct pp_hwmgr *hwmgr, if (features_enabled == NULL) return -EINVAL; - PP_ASSERT_WITH_CODE(vega12_send_msg_to_smc(hwmgr, + PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc(hwmgr, PPSMC_MSG_GetEnabledSmuFeaturesLow) == 0, "[GetEnabledSMCFeatures] Attemp to get SMU features Low failed!", return -EINVAL); - PP_ASSERT_WITH_CODE(vega12_read_arg_from_smc(hwmgr, - &smc_features_low) == 0, - "[GetEnabledSMCFeatures] Attemp to read SMU features Low argument failed!", - return -EINVAL); - PP_ASSERT_WITH_CODE(vega12_send_msg_to_smc(hwmgr, + smc_features_low = smu9_get_argument(hwmgr); + + PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc(hwmgr, PPSMC_MSG_GetEnabledSmuFeaturesHigh) == 0, "[GetEnabledSMCFeatures] Attemp to get SMU features High failed!", return -EINVAL); - PP_ASSERT_WITH_CODE(vega12_read_arg_from_smc(hwmgr, - &smc_features_high) == 0, - "[GetEnabledSMCFeatures] Attemp to read SMU features High argument failed!", - return -EINVAL); + smc_features_high = smu9_get_argument(hwmgr); *features_enabled = ((((uint64_t)smc_features_low << SMU_FEATURES_LOW_SHIFT) & SMU_FEATURES_LOW_MASK) | (((uint64_t)smc_features_high << SMU_FEATURES_HIGH_SHIFT) & SMU_FEATURES_HIGH_MASK)); @@ -333,10 +185,10 @@ static int vega12_set_tools_address(struct pp_hwmgr *hwmgr) (struct vega12_smumgr *)(hwmgr->smu_backend); if (priv->smu_tables.entry[TABLE_PMSTATUSLOG].mc_addr) { - if (!vega12_send_msg_to_smc_with_parameter(hwmgr, + if (!smu9_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetToolsDramAddrHigh, upper_32_bits(priv->smu_tables.entry[TABLE_PMSTATUSLOG].mc_addr))) - vega12_send_msg_to_smc_with_parameter(hwmgr, + smu9_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetToolsDramAddrLow, lower_32_bits(priv->smu_tables.entry[TABLE_PMSTATUSLOG].mc_addr)); } @@ -490,7 +342,7 @@ static int vega12_smu_fini(struct pp_hwmgr *hwmgr) static int vega12_start_smu(struct pp_hwmgr *hwmgr) { - PP_ASSERT_WITH_CODE(vega12_is_smc_ram_running(hwmgr), + PP_ASSERT_WITH_CODE(smu9_is_smc_ram_running(hwmgr), "SMC is not running!", return -EINVAL); @@ -504,9 +356,10 @@ const struct pp_smumgr_func vega12_smu_funcs = { .smu_fini = &vega12_smu_fini, .start_smu = &vega12_start_smu, .request_smu_load_specific_fw = NULL, - .send_msg_to_smc = &vega12_send_msg_to_smc, - .send_msg_to_smc_with_parameter = &vega12_send_msg_to_smc_with_parameter, + .send_msg_to_smc = &smu9_send_msg_to_smc, + .send_msg_to_smc_with_parameter = &smu9_send_msg_to_smc_with_parameter, .download_pptable_settings = NULL, .upload_pptable_settings = NULL, .is_dpm_running = vega12_is_dpm_running, + .get_argument = smu9_get_argument, }; diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/vega12_smumgr.h b/drivers/gpu/drm/amd/powerplay/smumgr/vega12_smumgr.h index 2810d387b611c..b285cbc04019c 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/vega12_smumgr.h +++ b/drivers/gpu/drm/amd/powerplay/smumgr/vega12_smumgr.h @@ -48,7 +48,6 @@ struct vega12_smumgr { #define SMU_FEATURES_HIGH_MASK 0xFFFFFFFF00000000 #define SMU_FEATURES_HIGH_SHIFT 32 -int vega12_read_arg_from_smc(struct pp_hwmgr *hwmgr, uint32_t *arg); int vega12_copy_table_from_smc(struct pp_hwmgr *hwmgr, uint8_t *table, int16_t table_id); int vega12_copy_table_to_smc(struct pp_hwmgr *hwmgr, -- GitLab From 59f20f5a0c9767a8b66688b84e72a345b4dc1bc1 Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexander.deucher@amd.com> Date: Thu, 12 Jul 2018 14:59:22 -0500 Subject: [PATCH 1209/1506] drm/amdgpu/pp: switch smu callback type for get_argument() return a uint32_t rather than an int to properly reflect what the function does. Reviewed-by: Rex Zhu <rezhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/powerplay/inc/hwmgr.h | 2 +- drivers/gpu/drm/amd/powerplay/inc/smumgr.h | 2 +- drivers/gpu/drm/amd/powerplay/smumgr/smu10_smumgr.c | 2 +- drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c | 4 ++-- drivers/gpu/drm/amd/powerplay/smumgr/smu9_smumgr.c | 2 +- drivers/gpu/drm/amd/powerplay/smumgr/smu9_smumgr.h | 2 +- drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h index b3363f26039a7..d3d96260f4406 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h @@ -194,7 +194,7 @@ struct pp_smumgr_func { int (*request_smu_load_fw)(struct pp_hwmgr *hwmgr); int (*request_smu_load_specific_fw)(struct pp_hwmgr *hwmgr, uint32_t firmware); - int (*get_argument)(struct pp_hwmgr *hwmgr); + uint32_t (*get_argument)(struct pp_hwmgr *hwmgr); int (*send_msg_to_smc)(struct pp_hwmgr *hwmgr, uint16_t msg); int (*send_msg_to_smc_with_parameter)(struct pp_hwmgr *hwmgr, uint16_t msg, uint32_t parameter); diff --git a/drivers/gpu/drm/amd/powerplay/inc/smumgr.h b/drivers/gpu/drm/amd/powerplay/inc/smumgr.h index 89dfbf53c7e6a..82550a8a3a3fc 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smumgr.h +++ b/drivers/gpu/drm/amd/powerplay/inc/smumgr.h @@ -80,7 +80,7 @@ enum SMU10_TABLE_ID { SMU10_CLOCKTABLE, }; -extern int smum_get_argument(struct pp_hwmgr *hwmgr); +extern uint32_t smum_get_argument(struct pp_hwmgr *hwmgr); extern int smum_download_powerplay_table(struct pp_hwmgr *hwmgr, void **table); diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu10_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/smu10_smumgr.c index 0a563f6fe9ea6..bb07d43f38744 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/smu10_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/smu10_smumgr.c @@ -68,7 +68,7 @@ static int smu10_send_msg_to_smc_without_waiting(struct pp_hwmgr *hwmgr, return 0; } -static int smu10_read_arg_from_smc(struct pp_hwmgr *hwmgr) +static uint32_t smu10_read_arg_from_smc(struct pp_hwmgr *hwmgr) { struct amdgpu_device *adev = hwmgr->adev; diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c index c861d3023474c..f7e3bc22bb93f 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c @@ -52,10 +52,10 @@ static const enum smu8_scratch_entry firmware_list[] = { SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_G, }; -static int smu8_get_argument(struct pp_hwmgr *hwmgr) +static uint32_t smu8_get_argument(struct pp_hwmgr *hwmgr) { if (hwmgr == NULL || hwmgr->device == NULL) - return -EINVAL; + return 0; return cgs_read_register(hwmgr->device, mmSMU_MP1_SRBM2P_ARG_0); diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu9_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/smu9_smumgr.c index aad8f077f33cf..079fc8e8f709f 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/smu9_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/smu9_smumgr.c @@ -142,7 +142,7 @@ int smu9_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr, return 0; } -int smu9_get_argument(struct pp_hwmgr *hwmgr) +uint32_t smu9_get_argument(struct pp_hwmgr *hwmgr) { struct amdgpu_device *adev = hwmgr->adev; diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu9_smumgr.h b/drivers/gpu/drm/amd/powerplay/smumgr/smu9_smumgr.h index a8da2815bd892..1462279ca1285 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/smu9_smumgr.h +++ b/drivers/gpu/drm/amd/powerplay/smumgr/smu9_smumgr.h @@ -27,6 +27,6 @@ bool smu9_is_smc_ram_running(struct pp_hwmgr *hwmgr); int smu9_send_msg_to_smc(struct pp_hwmgr *hwmgr, uint16_t msg); int smu9_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr, uint16_t msg, uint32_t parameter); -int smu9_get_argument(struct pp_hwmgr *hwmgr); +uint32_t smu9_get_argument(struct pp_hwmgr *hwmgr); #endif diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c index c9837935f0f5e..99d5e4f98f49c 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c @@ -96,7 +96,7 @@ int smum_process_firmware_header(struct pp_hwmgr *hwmgr) return 0; } -int smum_get_argument(struct pp_hwmgr *hwmgr) +uint32_t smum_get_argument(struct pp_hwmgr *hwmgr) { if (NULL != hwmgr->smumgr_funcs->get_argument) return hwmgr->smumgr_funcs->get_argument(hwmgr); -- GitLab From 4f45c778352eff878757a21566d87fbbedd104fc Mon Sep 17 00:00:00 2001 From: Lyude Paul <lyude@redhat.com> Date: Mon, 16 Jul 2018 13:17:11 -0400 Subject: [PATCH 1210/1506] drm/connector: Fix typo in drm_connector_list_iter_next() Signed-off-by: Lyude Paul <lyude@redhat.com> Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180716171711.413-1-lyude@redhat.com --- drivers/gpu/drm/drm_connector.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index 8f3f672a47b04..6011d769d50bb 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -606,7 +606,7 @@ __drm_connector_put_safe(struct drm_connector *conn) /** * drm_connector_list_iter_next - return next connector - * @iter: connectr_list iterator + * @iter: connector_list iterator * * Returns the next connector for @iter, or NULL when the list walk has * completed. -- GitLab From eb5f43d45b3b3c239b9ca0fde6eee11244a57346 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Mon, 16 Jul 2018 14:40:09 +0100 Subject: [PATCH 1211/1506] drm/i915/selftests: Exercise reset to break stuck GTT eviction We must be able to reset the GPU while we are waiting on it to perform an eviction (unbinding an active vma). So attach a spinning request to a target vma and try and it evict it from a thread to see if that blocks indefinitely. v2: Add a wait for the thread to start just in case that takes more than 10ms... v3: complete() not completion_done() to signal the completion. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180716134009.13143-1-chris@chris-wilson.co.uk --- .../gpu/drm/i915/selftests/intel_hangcheck.c | 171 +++++++++++++++++- 1 file changed, 169 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c index 73462a65a3303..65d66cdedd26c 100644 --- a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c +++ b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c @@ -27,6 +27,7 @@ #include "../i915_selftest.h" #include "i915_random.h" #include "igt_flush_test.h" +#include "igt_wedge_me.h" #include "mock_context.h" #include "mock_drm.h" @@ -921,7 +922,7 @@ static u32 fake_hangcheck(struct i915_request *rq, u32 mask) return reset_count; } -static int igt_wait_reset(void *arg) +static int igt_reset_wait(void *arg) { struct drm_i915_private *i915 = arg; struct i915_request *rq; @@ -995,6 +996,170 @@ static int igt_wait_reset(void *arg) return err; } +struct evict_vma { + struct completion completion; + struct i915_vma *vma; +}; + +static int evict_vma(void *data) +{ + struct evict_vma *arg = data; + struct i915_address_space *vm = arg->vma->vm; + struct drm_i915_private *i915 = vm->i915; + struct drm_mm_node evict = arg->vma->node; + int err; + + complete(&arg->completion); + + mutex_lock(&i915->drm.struct_mutex); + err = i915_gem_evict_for_node(vm, &evict, 0); + mutex_unlock(&i915->drm.struct_mutex); + + return err; +} + +static int __igt_reset_evict_vma(struct drm_i915_private *i915, + struct i915_address_space *vm) +{ + struct drm_i915_gem_object *obj; + struct task_struct *tsk = NULL; + struct i915_request *rq; + struct evict_vma arg; + struct hang h; + int err; + + if (!intel_engine_can_store_dword(i915->engine[RCS])) + return 0; + + /* Check that we can recover an unbind stuck on a hanging request */ + + global_reset_lock(i915); + + mutex_lock(&i915->drm.struct_mutex); + err = hang_init(&h, i915); + if (err) + goto unlock; + + obj = i915_gem_object_create_internal(i915, PAGE_SIZE); + if (IS_ERR(obj)) { + err = PTR_ERR(obj); + goto fini; + } + + arg.vma = i915_vma_instance(obj, vm, NULL); + if (IS_ERR(arg.vma)) { + err = PTR_ERR(arg.vma); + goto out_obj; + } + + rq = hang_create_request(&h, i915->engine[RCS]); + if (IS_ERR(rq)) { + err = PTR_ERR(rq); + goto out_obj; + } + + err = i915_vma_pin(arg.vma, 0, 0, + i915_vma_is_ggtt(arg.vma) ? PIN_GLOBAL : PIN_USER); + if (err) + goto out_obj; + + err = i915_vma_move_to_active(arg.vma, rq, EXEC_OBJECT_WRITE); + i915_vma_unpin(arg.vma); + + i915_request_get(rq); + i915_request_add(rq); + if (err) + goto out_rq; + + mutex_unlock(&i915->drm.struct_mutex); + + if (!wait_until_running(&h, rq)) { + struct drm_printer p = drm_info_printer(i915->drm.dev); + + pr_err("%s: Failed to start request %x, at %x\n", + __func__, rq->fence.seqno, hws_seqno(&h, rq)); + intel_engine_dump(rq->engine, &p, "%s\n", rq->engine->name); + + i915_gem_set_wedged(i915); + goto out_reset; + } + + init_completion(&arg.completion); + + tsk = kthread_run(evict_vma, &arg, "igt/evict_vma"); + if (IS_ERR(tsk)) { + err = PTR_ERR(tsk); + tsk = NULL; + goto out_reset; + } + + wait_for_completion(&arg.completion); + + if (wait_for(waitqueue_active(&rq->execute), 10)) { + struct drm_printer p = drm_info_printer(i915->drm.dev); + + pr_err("igt/evict_vma kthread did not wait\n"); + intel_engine_dump(rq->engine, &p, "%s\n", rq->engine->name); + + i915_gem_set_wedged(i915); + goto out_reset; + } + +out_reset: + fake_hangcheck(rq, intel_engine_flag(rq->engine)); + + if (tsk) { + struct igt_wedge_me w; + + /* The reset, even indirectly, should take less than 10ms. */ + igt_wedge_on_timeout(&w, i915, HZ / 10 /* 100ms timeout*/) + err = kthread_stop(tsk); + } + + mutex_lock(&i915->drm.struct_mutex); +out_rq: + i915_request_put(rq); +out_obj: + i915_gem_object_put(obj); +fini: + hang_fini(&h); +unlock: + mutex_unlock(&i915->drm.struct_mutex); + global_reset_unlock(i915); + + if (i915_terminally_wedged(&i915->gpu_error)) + return -EIO; + + return err; +} + +static int igt_reset_evict_ggtt(void *arg) +{ + struct drm_i915_private *i915 = arg; + + return __igt_reset_evict_vma(i915, &i915->ggtt.vm); +} + +static int igt_reset_evict_ppgtt(void *arg) +{ + struct drm_i915_private *i915 = arg; + struct i915_gem_context *ctx; + int err; + + mutex_lock(&i915->drm.struct_mutex); + ctx = kernel_context(i915); + mutex_unlock(&i915->drm.struct_mutex); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + err = 0; + if (ctx->ppgtt) /* aliasing == global gtt locking, covered above */ + err = __igt_reset_evict_vma(i915, &ctx->ppgtt->vm); + + kernel_context_close(ctx); + return err; +} + static int wait_for_others(struct drm_i915_private *i915, struct intel_engine_cs *exclude) { @@ -1240,8 +1405,10 @@ int intel_hangcheck_live_selftests(struct drm_i915_private *i915) SUBTEST(igt_reset_idle_engine), SUBTEST(igt_reset_active_engine), SUBTEST(igt_reset_engines), - SUBTEST(igt_wait_reset), SUBTEST(igt_reset_queue), + SUBTEST(igt_reset_wait), + SUBTEST(igt_reset_evict_ggtt), + SUBTEST(igt_reset_evict_ppgtt), SUBTEST(igt_handle_error), }; bool saved_hangcheck; -- GitLab From 8415afbd86ddd8a268a8450286bc58b2bb3b83d1 Mon Sep 17 00:00:00 2001 From: Eric Huang <JinhuiEric.Huang@amd.com> Date: Fri, 13 Jul 2018 15:05:10 -0400 Subject: [PATCH 1212/1506] Revert "drm/amd/powerplay: fix performance drop on Vega10" This reverts commit b87079ec7b4d38efee015367315958ce5495ba93. SMU FW team ask to remove this version specific code. Signed-off-by: Eric Huang <JinHuiEric.Huang@amd.com> Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c index eb37316cfbf73..1a0dccb3fac1f 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c @@ -2896,11 +2896,6 @@ static int vega10_enable_dpm_tasks(struct pp_hwmgr *hwmgr) vega10_enable_disable_PCC_limit_feature(hwmgr, true); - if ((hwmgr->smu_version == 0x001c2c00) || - (hwmgr->smu_version == 0x001c2d00)) - smum_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_UpdatePkgPwrPidAlpha, 1); - smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_ConfigureTelemetry, data->config_telemetry); -- GitLab From 964d0fbf6301d3dc8dfad19ffab5a06d002d27f1 Mon Sep 17 00:00:00 2001 From: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Date: Fri, 6 Jul 2018 14:16:54 -0400 Subject: [PATCH 1213/1506] drm/amdgpu: Allow to create BO lists in CS ioctl v3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change is to support MESA performace optimization. Modify CS IOCTL to allow its input as command buffer and an array of buffer handles to create a temporay bo list and then destroy it when IOCTL completes. This saves on calling for BO_LIST create and destry IOCTLs in MESA and by this improves performance. v2: Avoid inserting the temp list into idr struct. v3: Remove idr alloation from amdgpu_bo_list_create. Remove useless argument from amdgpu_cs_parser_fini Minor cosmetic stuff. v4: Revert amdgpu_bo_list_destroy back to static Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Reviewed-by: Chunming Zhou <david1.zhou@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 8 ++ drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c | 88 ++++++++++++--------- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 48 ++++++++++- drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 3 +- include/uapi/drm/amdgpu_drm.h | 1 + 5 files changed, 108 insertions(+), 40 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 53435da158c22..c6c1e8dc919f5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -732,6 +732,14 @@ void amdgpu_bo_list_get_list(struct amdgpu_bo_list *list, struct list_head *validated); void amdgpu_bo_list_put(struct amdgpu_bo_list *list); void amdgpu_bo_list_free(struct amdgpu_bo_list *list); +int amdgpu_bo_create_list_entry_array(struct drm_amdgpu_bo_list_in *in, + struct drm_amdgpu_bo_list_entry **info_param); + +int amdgpu_bo_list_create(struct amdgpu_device *adev, + struct drm_file *filp, + struct drm_amdgpu_bo_list_entry *info, + unsigned num_entries, + struct amdgpu_bo_list **list); /* * GFX stuff diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c index 92be7f6de1973..7679c068c89a8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c @@ -55,15 +55,15 @@ static void amdgpu_bo_list_release_rcu(struct kref *ref) kfree_rcu(list, rhead); } -static int amdgpu_bo_list_create(struct amdgpu_device *adev, +int amdgpu_bo_list_create(struct amdgpu_device *adev, struct drm_file *filp, struct drm_amdgpu_bo_list_entry *info, unsigned num_entries, - int *id) + struct amdgpu_bo_list **list_out) { - int r; - struct amdgpu_fpriv *fpriv = filp->driver_priv; struct amdgpu_bo_list *list; + int r; + list = kzalloc(sizeof(struct amdgpu_bo_list), GFP_KERNEL); if (!list) @@ -78,16 +78,7 @@ static int amdgpu_bo_list_create(struct amdgpu_device *adev, return r; } - /* idr alloc should be called only after initialization of bo list. */ - mutex_lock(&fpriv->bo_list_lock); - r = idr_alloc(&fpriv->bo_list_handles, list, 1, 0, GFP_KERNEL); - mutex_unlock(&fpriv->bo_list_lock); - if (r < 0) { - amdgpu_bo_list_free(list); - return r; - } - *id = r; - + *list_out = list; return 0; } @@ -263,55 +254,79 @@ void amdgpu_bo_list_free(struct amdgpu_bo_list *list) kfree(list); } -int amdgpu_bo_list_ioctl(struct drm_device *dev, void *data, - struct drm_file *filp) +int amdgpu_bo_create_list_entry_array(struct drm_amdgpu_bo_list_in *in, + struct drm_amdgpu_bo_list_entry **info_param) { + const void __user *uptr = u64_to_user_ptr(in->bo_info_ptr); const uint32_t info_size = sizeof(struct drm_amdgpu_bo_list_entry); - - struct amdgpu_device *adev = dev->dev_private; - struct amdgpu_fpriv *fpriv = filp->driver_priv; - union drm_amdgpu_bo_list *args = data; - uint32_t handle = args->in.list_handle; - const void __user *uptr = u64_to_user_ptr(args->in.bo_info_ptr); - struct drm_amdgpu_bo_list_entry *info; - struct amdgpu_bo_list *list; - int r; - info = kvmalloc_array(args->in.bo_number, - sizeof(struct drm_amdgpu_bo_list_entry), GFP_KERNEL); + info = kvmalloc_array(in->bo_number, info_size, GFP_KERNEL); if (!info) return -ENOMEM; /* copy the handle array from userspace to a kernel buffer */ r = -EFAULT; - if (likely(info_size == args->in.bo_info_size)) { - unsigned long bytes = args->in.bo_number * - args->in.bo_info_size; + if (likely(info_size == in->bo_info_size)) { + unsigned long bytes = in->bo_number * + in->bo_info_size; if (copy_from_user(info, uptr, bytes)) goto error_free; } else { - unsigned long bytes = min(args->in.bo_info_size, info_size); + unsigned long bytes = min(in->bo_info_size, info_size); unsigned i; - memset(info, 0, args->in.bo_number * info_size); - for (i = 0; i < args->in.bo_number; ++i) { + memset(info, 0, in->bo_number * info_size); + for (i = 0; i < in->bo_number; ++i) { if (copy_from_user(&info[i], uptr, bytes)) goto error_free; - uptr += args->in.bo_info_size; + uptr += in->bo_info_size; } } + *info_param = info; + return 0; + +error_free: + kvfree(info); + return r; +} + +int amdgpu_bo_list_ioctl(struct drm_device *dev, void *data, + struct drm_file *filp) +{ + struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_fpriv *fpriv = filp->driver_priv; + union drm_amdgpu_bo_list *args = data; + uint32_t handle = args->in.list_handle; + struct drm_amdgpu_bo_list_entry *info = NULL; + struct amdgpu_bo_list *list; + int r; + + r = amdgpu_bo_create_list_entry_array(&args->in, &info); + if (r) + goto error_free; + switch (args->in.operation) { case AMDGPU_BO_LIST_OP_CREATE: r = amdgpu_bo_list_create(adev, filp, info, args->in.bo_number, - &handle); + &list); if (r) goto error_free; + + mutex_lock(&fpriv->bo_list_lock); + r = idr_alloc(&fpriv->bo_list_handles, list, 1, 0, GFP_KERNEL); + mutex_unlock(&fpriv->bo_list_lock); + if (r < 0) { + amdgpu_bo_list_free(list); + return r; + } + + handle = r; break; case AMDGPU_BO_LIST_OP_DESTROY: @@ -345,6 +360,7 @@ int amdgpu_bo_list_ioctl(struct drm_device *dev, void *data, return 0; error_free: - kvfree(info); + if (info) + kvfree(info); return r; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 5a2a5ba29f9a1..6d8df76b5a5d5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -66,11 +66,35 @@ static int amdgpu_cs_user_fence_chunk(struct amdgpu_cs_parser *p, return 0; } -static int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data) +static int amdgpu_cs_bo_handles_chunk(struct amdgpu_cs_parser *p, + struct drm_amdgpu_bo_list_in *data) +{ + int r; + struct drm_amdgpu_bo_list_entry *info = NULL; + + r = amdgpu_bo_create_list_entry_array(data, &info); + if (r) + return r; + + r = amdgpu_bo_list_create(p->adev, p->filp, info, data->bo_number, + &p->bo_list); + if (r) + goto error_free; + + kvfree(info); + return 0; + +error_free: + if (info) + kvfree(info); + + return r; +} + +static int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, union drm_amdgpu_cs *cs) { struct amdgpu_fpriv *fpriv = p->filp->driver_priv; struct amdgpu_vm *vm = &fpriv->vm; - union drm_amdgpu_cs *cs = data; uint64_t *chunk_array_user; uint64_t *chunk_array; unsigned size, num_ibs = 0; @@ -164,6 +188,19 @@ static int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data) break; + case AMDGPU_CHUNK_ID_BO_HANDLES: + size = sizeof(struct drm_amdgpu_bo_list_in); + if (p->chunks[i].length_dw * sizeof(uint32_t) < size) { + ret = -EINVAL; + goto free_partial_kdata; + } + + ret = amdgpu_cs_bo_handles_chunk(p, p->chunks[i].kdata); + if (ret) + goto free_partial_kdata; + + break; + case AMDGPU_CHUNK_ID_DEPENDENCIES: case AMDGPU_CHUNK_ID_SYNCOBJ_IN: case AMDGPU_CHUNK_ID_SYNCOBJ_OUT: @@ -534,7 +571,12 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, INIT_LIST_HEAD(&p->validated); - p->bo_list = amdgpu_bo_list_get(fpriv, cs->in.bo_list_handle); + /* p->bo_list could already be assigned if AMDGPU_CHUNK_ID_BO_HANDLES is present */ + if (!p->bo_list) + p->bo_list = amdgpu_bo_list_get(fpriv, cs->in.bo_list_handle); + else + mutex_lock(&p->bo_list->lock); + if (p->bo_list) { amdgpu_bo_list_get_list(p->bo_list, &p->validated); if (p->bo_list->first_userptr != p->bo_list->num_entries) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 06aede194bf85..529500c94675c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -69,9 +69,10 @@ * - 3.24.0 - Add high priority compute support for gfx9 * - 3.25.0 - Add support for sensor query info (stable pstate sclk/mclk). * - 3.26.0 - GFX9: Process AMDGPU_IB_FLAG_TC_WB_NOT_INVALIDATE. + * - 3.27.0 - Add new chunk to to AMDGPU_CS to enable BO_LIST creation. */ #define KMS_DRIVER_MAJOR 3 -#define KMS_DRIVER_MINOR 26 +#define KMS_DRIVER_MINOR 27 #define KMS_DRIVER_PATCHLEVEL 0 int amdgpu_vram_limit = 0; diff --git a/include/uapi/drm/amdgpu_drm.h b/include/uapi/drm/amdgpu_drm.h index 784b0fe470eea..1ceec56de0157 100644 --- a/include/uapi/drm/amdgpu_drm.h +++ b/include/uapi/drm/amdgpu_drm.h @@ -516,6 +516,7 @@ struct drm_amdgpu_gem_va { #define AMDGPU_CHUNK_ID_DEPENDENCIES 0x03 #define AMDGPU_CHUNK_ID_SYNCOBJ_IN 0x04 #define AMDGPU_CHUNK_ID_SYNCOBJ_OUT 0x05 +#define AMDGPU_CHUNK_ID_BO_HANDLES 0x06 struct drm_amdgpu_cs_chunk { __u32 chunk_id; -- GitLab From a6da48caf92b4b6119cae146259528bec0e48545 Mon Sep 17 00:00:00 2001 From: Junwei Zhang <Jerry.Zhang@amd.com> Date: Mon, 16 Jul 2018 10:53:43 +0800 Subject: [PATCH 1214/1506] drm/scheduler: add NULL pointer check for run queue (v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To check rq pointer before adding entity into it. That avoids NULL pointer access in some case. v2: move the check to caller Suggested-by: Christian König <christian.koenig@amd.com> Signed-off-by: Junwei Zhang <Jerry.Zhang@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/scheduler/gpu_scheduler.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/scheduler/gpu_scheduler.c b/drivers/gpu/drm/scheduler/gpu_scheduler.c index 16bf446aa6b38..dac71e3b4514c 100644 --- a/drivers/gpu/drm/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/scheduler/gpu_scheduler.c @@ -547,6 +547,11 @@ void drm_sched_entity_push_job(struct drm_sched_job *sched_job, if (first) { /* Add the entity to the run queue */ spin_lock(&entity->rq_lock); + if (!entity->rq) { + DRM_ERROR("Trying to push to a killed entity\n"); + spin_unlock(&entity->rq_lock); + return; + } drm_sched_rq_add_entity(entity->rq, entity); spin_unlock(&entity->rq_lock); drm_sched_wakeup(sched); -- GitLab From 8d2bbe54d18906e456c1ba0e1b0aa9fd175cae97 Mon Sep 17 00:00:00 2001 From: Vitaly Prosyak <vitaly.prosyak@amd.com> Date: Fri, 15 Jun 2018 08:34:10 -0500 Subject: [PATCH 1215/1506] drm/amd/display: Add headers for hardcoded 1d luts. Hard-coded luts are needed since complex algorithms are used for color and tone mapping. Add the headers for future use. Signed-off-by: Vitaly Prosyak <vitaly.prosyak@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Leo Li <sunpeng.li@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../drm/amd/display/modules/color/luts_1d.h | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 drivers/gpu/drm/amd/display/modules/color/luts_1d.h diff --git a/drivers/gpu/drm/amd/display/modules/color/luts_1d.h b/drivers/gpu/drm/amd/display/modules/color/luts_1d.h new file mode 100644 index 0000000000000..66b1fad572ace --- /dev/null +++ b/drivers/gpu/drm/amd/display/modules/color/luts_1d.h @@ -0,0 +1,51 @@ +/* + * Copyright 2016 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ +#ifndef LUTS_1D_H +#define LUTS_1D_H + +#include "hw_shared.h" + +struct point_config { + uint32_t custom_float_x; + uint32_t custom_float_y; + uint32_t custom_float_slope; +}; + +struct lut_point { + uint32_t red; + uint32_t green; + uint32_t blue; + uint32_t delta_red; + uint32_t delta_green; + uint32_t delta_blue; +}; + +struct pwl_1dlut_parameter { + struct gamma_curve arr_curve_points[34]; + struct point_config arr_points[2]; + struct lut_point rgb_resulted[256]; + uint32_t hw_points_num; +}; +#endif // LUTS_1D_H -- GitLab From 6d92b5c2d5bea1b1d0859bd8f3080344e5e3960e Mon Sep 17 00:00:00 2001 From: Krunoslav Kovac <Krunoslav.Kovac@amd.com> Date: Wed, 27 Jun 2018 18:23:37 -0400 Subject: [PATCH 1216/1506] drm/amd/display: Refactor SDR cursor boosting in HDR mode [Why] Cursor boosting is done via CNVC_CUR register which is DPP, not HUBP Previous commit was implementing it in HUBP functions, and also breaking diags tests. [How] 1. Undo original commit as well as Eric's diags test fix, almost completely 2. Move programming to DPP and call via new dc_stream function 3. Also removing cur_rom_en from dpp_cursor_attributes and programming as part of normal cursor attributes as it depends on cursor color format Signed-off-by: Krunoslav Kovac <Krunoslav.Kovac@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Leo Li <sunpeng.li@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/display/dc/core/dc_stream.c | 1 + drivers/gpu/drm/amd/display/dc/dc_hw_types.h | 5 ++++ drivers/gpu/drm/amd/display/dc/dc_stream.h | 2 ++ .../gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c | 13 ++++++++ .../gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h | 14 +++++++-- .../gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c | 15 ---------- .../gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h | 12 +++----- .../amd/display/dc/dcn10/dcn10_hw_sequencer.c | 30 ++++++++++++++++++- drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h | 3 ++ .../gpu/drm/amd/display/dc/inc/hw_sequencer.h | 1 + 10 files changed, 70 insertions(+), 26 deletions(-) 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 0223f4867e8d0..4717330a42f49 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c @@ -214,6 +214,7 @@ bool dc_stream_set_cursor_attributes( } core_dc->hwss.set_cursor_attribute(pipe_ctx); + core_dc->hwss.set_cursor_sdr_white_level(pipe_ctx); } if (pipe_to_program) diff --git a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h index da787e2793190..9cfd7ea845e3f 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h @@ -500,6 +500,11 @@ struct dc_cursor_attributes { union dc_cursor_attribute_flags attribute_flags; }; +struct dpp_cursor_attributes { + int bias; + int scale; +}; + /* OPP */ enum dc_color_space { diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index 64eeb440e3d31..cbfe418006cba 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -100,6 +100,7 @@ struct dc_stream_state { struct dc_cursor_attributes cursor_attributes; struct dc_cursor_position cursor_position; + uint32_t sdr_white_level; // for boosting (SDR) cursor in HDR mode /* from stream struct */ struct kref refcount; @@ -255,6 +256,7 @@ bool dc_stream_set_cursor_position( struct dc_stream_state *stream, const struct dc_cursor_position *position); + bool dc_stream_adjust_vmin_vmax(struct dc *dc, struct dc_stream_state **stream, int num_streams, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c index a558efa9b34a4..bf8b68f8db4f7 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c @@ -459,6 +459,18 @@ void dpp1_set_cursor_position( } +void dpp1_cnv_set_optional_cursor_attributes( + struct dpp *dpp_base, + struct dpp_cursor_attributes *attr) +{ + struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); + + if (attr) { + REG_UPDATE(CURSOR0_FP_SCALE_BIAS, CUR0_FP_BIAS, attr->bias); + REG_UPDATE(CURSOR0_FP_SCALE_BIAS, CUR0_FP_SCALE, attr->scale); + } +} + void dpp1_dppclk_control( struct dpp *dpp_base, bool dppclk_div, @@ -499,6 +511,7 @@ static const struct dpp_funcs dcn10_dpp_funcs = { .dpp_full_bypass = dpp1_full_bypass, .set_cursor_attributes = dpp1_set_cursor_attributes, .set_cursor_position = dpp1_set_cursor_position, + .set_optional_cursor_attributes = dpp1_cnv_set_optional_cursor_attributes, .dpp_dppclk_control = dpp1_dppclk_control, .dpp_set_hdr_multiplier = dpp1_set_hdr_multiplier, }; diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h index e862cafa6501b..e2889e61b18c6 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h @@ -119,6 +119,7 @@ SRI(CURSOR0_CONTROL, CNVC_CUR, id), \ SRI(CURSOR0_COLOR0, CNVC_CUR, id), \ SRI(CURSOR0_COLOR1, CNVC_CUR, id), \ + SRI(CURSOR0_FP_SCALE_BIAS, CNVC_CUR, id), \ SRI(DPP_CONTROL, DPP_TOP, id), \ SRI(CM_HDR_MULT_COEF, CM, id) @@ -324,6 +325,8 @@ TF_SF(CNVC_CUR0_CURSOR0_CONTROL, CUR0_ENABLE, mask_sh), \ TF_SF(CNVC_CUR0_CURSOR0_COLOR0, CUR0_COLOR0, mask_sh), \ TF_SF(CNVC_CUR0_CURSOR0_COLOR1, CUR0_COLOR1, mask_sh), \ + TF_SF(CNVC_CUR0_CURSOR0_FP_SCALE_BIAS, CUR0_FP_BIAS, mask_sh), \ + TF_SF(CNVC_CUR0_CURSOR0_FP_SCALE_BIAS, CUR0_FP_SCALE, mask_sh), \ TF_SF(DPP_TOP0_DPP_CONTROL, DPP_CLOCK_ENABLE, mask_sh), \ TF_SF(CM0_CM_HDR_MULT_COEF, CM_HDR_MULT_COEF, mask_sh) @@ -1076,7 +1079,9 @@ type CUR0_COLOR1; \ type DPPCLK_RATE_CONTROL; \ type DPP_CLOCK_ENABLE; \ - type CM_HDR_MULT_COEF; + type CM_HDR_MULT_COEF; \ + type CUR0_FP_BIAS; \ + type CUR0_FP_SCALE; struct dcn_dpp_shift { TF_REG_FIELD_LIST(uint8_t) @@ -1329,7 +1334,8 @@ struct dcn_dpp_mask { uint32_t CURSOR0_COLOR0; \ uint32_t CURSOR0_COLOR1; \ uint32_t DPP_CONTROL; \ - uint32_t CM_HDR_MULT_COEF; + uint32_t CM_HDR_MULT_COEF; \ + uint32_t CURSOR0_FP_SCALE_BIAS; struct dcn_dpp_registers { DPP_COMMON_REG_VARIABLE_LIST @@ -1370,6 +1376,10 @@ void dpp1_set_cursor_position( const struct dc_cursor_mi_param *param, uint32_t width); +void dpp1_cnv_set_optional_cursor_attributes( + struct dpp *dpp_base, + struct dpp_cursor_attributes *attr); + bool dpp1_dscl_is_lb_conf_valid( int ceil_vratio, int num_partitions, 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 5c4ad8a67e62a..d6dc61ecf4a15 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c @@ -27,7 +27,6 @@ #include "reg_helper.h" #include "basics/conversion.h" #include "dcn10_hubp.h" -#include "custom_float.h" #define REG(reg)\ hubp1->hubp_regs->reg @@ -1039,18 +1038,6 @@ void hubp1_cursor_set_attributes( enum cursor_pitch hw_pitch = hubp1_get_cursor_pitch(attr->pitch); enum cursor_lines_per_chunk lpc = hubp1_get_lines_per_chunk( attr->width, attr->color_format); - struct fixed31_32 multiplier; - uint32_t hw_mult = 0x3c00; // 1.0 default multiplier - struct custom_float_format fmt; - - fmt.exponenta_bits = 5; - fmt.mantissa_bits = 10; - fmt.sign = true; - - if (attr->sdr_white_level > 80) { - multiplier = dc_fixpt_from_fraction(attr->sdr_white_level, 80); - convert_to_custom_float_format(multiplier, &fmt, &hw_mult); - } hubp->curs_attr = *attr; @@ -1073,8 +1060,6 @@ void hubp1_cursor_set_attributes( CURSOR0_DST_Y_OFFSET, 0, /* used to shift the cursor chunk request deadline */ CURSOR0_CHUNK_HDL_ADJUST, 3); - - REG_UPDATE(CURSOR0_FP_SCALE_BIAS, CUR0_FP_SCALE, hw_mult); } void hubp1_cursor_set_position( 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 9991da50bf29b..f689feace82d1 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h @@ -133,8 +133,7 @@ SRI(CURSOR_CONTROL, CURSOR, id), \ SRI(CURSOR_POSITION, CURSOR, id), \ SRI(CURSOR_HOT_SPOT, CURSOR, id), \ - SRI(CURSOR_DST_OFFSET, CURSOR, id), \ - SRI(CURSOR0_FP_SCALE_BIAS, CNVC_CUR, id) + SRI(CURSOR_DST_OFFSET, CURSOR, id) #define HUBP_COMMON_REG_VARIABLE_LIST \ uint32_t DCHUBP_CNTL; \ @@ -242,8 +241,7 @@ uint32_t CURSOR_POSITION; \ uint32_t CURSOR_HOT_SPOT; \ uint32_t CURSOR_DST_OFFSET; \ - uint32_t HUBP_CLK_CNTL; \ - uint32_t CURSOR0_FP_SCALE_BIAS + uint32_t HUBP_CLK_CNTL #define HUBP_SF(reg_name, field_name, post_fix)\ .field_name = reg_name ## __ ## field_name ## post_fix @@ -426,8 +424,7 @@ HUBP_SF(CURSOR0_CURSOR_POSITION, CURSOR_Y_POSITION, mask_sh), \ HUBP_SF(CURSOR0_CURSOR_HOT_SPOT, CURSOR_HOT_SPOT_X, mask_sh), \ HUBP_SF(CURSOR0_CURSOR_HOT_SPOT, CURSOR_HOT_SPOT_Y, mask_sh), \ - HUBP_SF(CURSOR0_CURSOR_DST_OFFSET, CURSOR_DST_X_OFFSET, mask_sh), \ - HUBP_SF(CNVC_CUR0_CURSOR0_FP_SCALE_BIAS, CUR0_FP_SCALE, mask_sh) + HUBP_SF(CURSOR0_CURSOR_DST_OFFSET, CURSOR_DST_X_OFFSET, mask_sh) #define DCN_HUBP_REG_FIELD_LIST(type) \ type HUBP_BLANK_EN;\ @@ -618,8 +615,7 @@ type CURSOR_HOT_SPOT_X; \ type CURSOR_HOT_SPOT_Y; \ type CURSOR_DST_X_OFFSET; \ - type OUTPUT_FP; \ - type CUR0_FP_SCALE + type OUTPUT_FP struct dcn_mi_registers { HUBP_COMMON_REG_VARIABLE_LIST; 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 2e145aa663a4a..6e8127cb2e565 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 @@ -2555,6 +2555,33 @@ static void dcn10_set_cursor_attribute(struct pipe_ctx *pipe_ctx) pipe_ctx->plane_res.dpp, attributes->color_format); } +static void dcn10_set_cursor_sdr_white_level(struct pipe_ctx *pipe_ctx) +{ + uint32_t sdr_white_level = pipe_ctx->stream->cursor_attributes.sdr_white_level; + struct fixed31_32 multiplier; + struct dpp_cursor_attributes opt_attr = { 0 }; + uint32_t hw_scale = 0x3c00; // 1.0 default multiplier + struct custom_float_format fmt; + + if (!pipe_ctx->plane_res.dpp->funcs->set_optional_cursor_attributes) + return; + + fmt.exponenta_bits = 5; + fmt.mantissa_bits = 10; + fmt.sign = true; + + if (sdr_white_level > 80) { + multiplier = dc_fixpt_from_fraction(sdr_white_level, 80); + convert_to_custom_float_format(multiplier, &fmt, &hw_scale); + } + + opt_attr.scale = hw_scale; + opt_attr.bias = 0; + + pipe_ctx->plane_res.dpp->funcs->set_optional_cursor_attributes( + pipe_ctx->plane_res.dpp, &opt_attr); +} + static const struct hw_sequencer_funcs dcn10_funcs = { .program_gamut_remap = program_gamut_remap, .program_csc_matrix = program_csc_matrix, @@ -2602,7 +2629,8 @@ static const struct hw_sequencer_funcs dcn10_funcs = { .edp_power_control = hwss_edp_power_control, .edp_wait_for_hpd_ready = hwss_edp_wait_for_hpd_ready, .set_cursor_position = dcn10_set_cursor_position, - .set_cursor_attribute = dcn10_set_cursor_attribute + .set_cursor_attribute = dcn10_set_cursor_attribute, + .set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level }; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h index 582458f028f84..74ad94b0e4f08 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h @@ -151,6 +151,9 @@ struct dpp_funcs { void (*dpp_set_hdr_multiplier)( struct dpp *dpp_base, uint32_t multiplier); + void (*set_optional_cursor_attributes)( + struct dpp *dpp_base, + struct dpp_cursor_attributes *attr); void (*dpp_dppclk_control)( struct dpp *dpp_base, 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 c2277d1e195b4..a14ce4de80b26 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h @@ -223,6 +223,7 @@ struct hw_sequencer_funcs { void (*set_cursor_position)(struct pipe_ctx *pipe); void (*set_cursor_attribute)(struct pipe_ctx *pipe); + void (*set_cursor_sdr_white_level)(struct pipe_ctx *pipe); }; -- GitLab From bf53769d9fc95c89d2f1588463c268c3af987748 Mon Sep 17 00:00:00 2001 From: Gloria Li <geling.li@amd.com> Date: Tue, 3 Jul 2018 14:39:22 -0400 Subject: [PATCH 1217/1506] drm/amd/display: add HDR visual confirm [Why] Testing team wants a way to tell if HDR is on or not [How] Program the overscan color to visually indicate the HDR state of the top-most plane Signed-off-by: Gloria Li <geling.li@amd.com> Reviewed-by: Aric Cyr <Aric.Cyr@amd.com> Acked-by: Leo Li <sunpeng.li@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dc.h | 11 +++- .../drm/amd/display/dc/dce/dce_transform.c | 2 +- .../display/dc/dce110/dce110_hw_sequencer.c | 2 +- .../display/dc/dce110/dce110_transform_v.c | 2 +- .../drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c | 7 ++- .../amd/display/dc/dcn10/dcn10_hw_sequencer.c | 50 +++++++++++++++++-- 6 files changed, 63 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 208578301d593..85f5ddded4188 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -169,6 +169,12 @@ struct dc_config { bool disable_disp_pll_sharing; }; +enum visual_confirm { + VISUAL_CONFIRM_DISABLE = 0, + VISUAL_CONFIRM_SURFACE = 1, + VISUAL_CONFIRM_HDR = 2, +}; + enum dcc_option { DCC_ENABLE = 0, DCC_DISABLE = 1, @@ -202,7 +208,7 @@ struct dc_clocks { }; struct dc_debug { - bool surface_visual_confirm; + enum visual_confirm visual_confirm; bool sanity_checks; bool max_disp_clk; bool surface_trace; @@ -387,7 +393,8 @@ enum dc_transfer_func_predefined { TRANSFER_FUNCTION_LINEAR, TRANSFER_FUNCTION_UNITY, TRANSFER_FUNCTION_HLG, - TRANSFER_FUNCTION_HLG12 + TRANSFER_FUNCTION_HLG12, + TRANSFER_FUNCTION_GAMMA22 }; struct dc_transfer_func { diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c b/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c index a02e719d77944..ab63d0d0304cb 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c @@ -155,7 +155,7 @@ static void program_overscan( int overscan_bottom = data->v_active - data->recout.y - data->recout.height; - if (xfm_dce->base.ctx->dc->debug.surface_visual_confirm) { + if (xfm_dce->base.ctx->dc->debug.visual_confirm != VISUAL_CONFIRM_DISABLE) { overscan_bottom += 2; overscan_right += 2; } 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 e48eb3056af5e..45388bff2c7dc 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 @@ -1256,7 +1256,7 @@ static void program_scaler(const struct dc *dc, return; #endif - if (dc->debug.surface_visual_confirm) + if (dc->debug.visual_confirm == VISUAL_CONFIRM_SURFACE) get_surface_visual_confirm_color(pipe_ctx, &color); else color_space_to_black_color(dc, diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_transform_v.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_transform_v.c index a7dce060204fc..aa8d6b10d2c3f 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_transform_v.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_transform_v.c @@ -235,7 +235,7 @@ static void program_overscan( int overscan_right = data->h_active - data->recout.x - data->recout.width; int overscan_bottom = data->v_active - data->recout.y - data->recout.height; - if (xfm_dce->base.ctx->dc->debug.surface_visual_confirm) { + if (xfm_dce->base.ctx->dc->debug.visual_confirm != VISUAL_CONFIRM_DISABLE) { overscan_bottom += 2; overscan_right += 2; } diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c index f0cc97518c499..4a863a5dab417 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c @@ -621,6 +621,10 @@ static void dpp1_dscl_set_manual_ratio_init( static void dpp1_dscl_set_recout( struct dcn10_dpp *dpp, const struct rect *recout) { + int visual_confirm_on = 0; + if (dpp->base.ctx->dc->debug.visual_confirm != VISUAL_CONFIRM_DISABLE) + visual_confirm_on = 1; + REG_SET_2(RECOUT_START, 0, /* First pixel of RECOUT */ RECOUT_START_X, recout->x, @@ -632,8 +636,7 @@ static void dpp1_dscl_set_recout( RECOUT_WIDTH, recout->width, /* Number of RECOUT vertical lines */ RECOUT_HEIGHT, recout->height - - dpp->base.ctx->dc->debug.surface_visual_confirm * 4 * - (dpp->base.inst + 1)); + - visual_confirm_on * 4 * (dpp->base.inst + 1)); } /* Main function to program scaler and line buffer in manual scaling mode */ 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 6e8127cb2e565..ade74c8218311 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 @@ -1768,6 +1768,43 @@ static void dcn10_get_surface_visual_confirm_color( } } +static void dcn10_get_hdr_visual_confirm_color( + struct pipe_ctx *pipe_ctx, + struct tg_color *color) +{ + uint32_t color_value = MAX_TG_COLOR_VALUE; + + // Determine the overscan color based on the top-most (desktop) plane's context + struct pipe_ctx *top_pipe_ctx = pipe_ctx; + + while (top_pipe_ctx->top_pipe != NULL) + top_pipe_ctx = top_pipe_ctx->top_pipe; + + switch (top_pipe_ctx->plane_res.scl_data.format) { + case PIXEL_FORMAT_ARGB2101010: + if (top_pipe_ctx->stream->out_transfer_func->tf == TRANSFER_FUNCTION_UNITY) { + /* HDR10, ARGB2101010 - set boarder color to red */ + color->color_r_cr = color_value; + } + break; + case PIXEL_FORMAT_FP16: + if (top_pipe_ctx->stream->out_transfer_func->tf == TRANSFER_FUNCTION_PQ) { + /* HDR10, FP16 - set boarder color to blue */ + color->color_b_cb = color_value; + } else if (top_pipe_ctx->stream->out_transfer_func->tf == TRANSFER_FUNCTION_GAMMA22) { + /* FreeSync 2 HDR - set boarder color to green */ + color->color_g_y = color_value; + } + break; + default: + /* SDR - set boarder color to Gray */ + color->color_r_cr = color_value/2; + color->color_b_cb = color_value/2; + color->color_g_y = color_value/2; + break; + } +} + static uint16_t fixed_point_to_int_frac( struct fixed31_32 arg, uint8_t integer_bits, @@ -1862,13 +1899,17 @@ static void dcn10_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) /* TODO: proper fix once fpga works */ - if (dc->debug.surface_visual_confirm) + if (dc->debug.visual_confirm == VISUAL_CONFIRM_HDR) { + dcn10_get_hdr_visual_confirm_color( + pipe_ctx, &blnd_cfg.black_color); + } else if (dc->debug.visual_confirm == VISUAL_CONFIRM_SURFACE) { dcn10_get_surface_visual_confirm_color( pipe_ctx, &blnd_cfg.black_color); - else + } else { color_space_to_black_color( - dc, pipe_ctx->stream->output_color_space, - &blnd_cfg.black_color); + dc, pipe_ctx->stream->output_color_space, + &blnd_cfg.black_color); + } if (per_pixel_alpha) blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA; @@ -2148,6 +2189,7 @@ static void program_all_pipe_in_tree( pipe_ctx->stream_res.tg); dc->hwss.blank_pixel_data(dc, pipe_ctx, blank); + } if (pipe_ctx->plane_state != NULL) { -- GitLab From 2068afe649ae36f422ced4ecf0efee79e2ff5154 Mon Sep 17 00:00:00 2001 From: Nikola Cornij <nikola.cornij@amd.com> Date: Wed, 4 Jul 2018 19:05:16 -0400 Subject: [PATCH 1218/1506] drm/amd/display: Add hook for MST root branch info This allows DM to do any necessary updates before MST discovery starts. Signed-off-by: Nikola Cornij <nikola.cornij@amd.com> Reviewed-by: Nikola Cornij <Nikola.Cornij@amd.com> Acked-by: Leo Li <sunpeng.li@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 5 +++++ drivers/gpu/drm/amd/display/dc/core/dc_link.c | 4 ++++ drivers/gpu/drm/amd/display/dc/dm_helpers.h | 8 ++++++++ 3 files changed, 17 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c index 59b113d11f66f..8403b6a9a77bd 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c @@ -169,6 +169,11 @@ static void get_payload_table( mutex_unlock(&mst_mgr->payload_lock); } +void dm_helpers_dp_update_branch_info( + struct dc_context *ctx, + const struct dc_link *link) +{} + /* * Writes payload allocation table in immediate downstream device. */ 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 fe29a398b7039..a4429c90c60c4 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -529,6 +529,10 @@ static bool detect_dp( if (reason == DETECT_REASON_BOOT) boot = true; + dm_helpers_dp_update_branch_info( + link->ctx, + link); + if (!dm_helpers_dp_mst_start_top_mgr( link->ctx, link, boot)) { diff --git a/drivers/gpu/drm/amd/display/dc/dm_helpers.h b/drivers/gpu/drm/amd/display/dc/dm_helpers.h index 7e6b9f5b89061..5d4527d03045e 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_helpers.h +++ b/drivers/gpu/drm/amd/display/dc/dm_helpers.h @@ -40,6 +40,14 @@ enum dc_edid_status dm_helpers_parse_edid_caps( const struct dc_edid *edid, struct dc_edid_caps *edid_caps); + +/* + * Update DP branch info + */ +void dm_helpers_dp_update_branch_info( + struct dc_context *ctx, + const struct dc_link *link); + /* * Writes payload allocation table in immediate downstream device. */ -- GitLab From 68199bd16cb56d121ade83918d5858933d07ae8a Mon Sep 17 00:00:00 2001 From: Tony Cheng <tony.cheng@amd.com> Date: Sat, 7 Jul 2018 15:43:07 -0400 Subject: [PATCH 1219/1506] drm/amd/display: Move address tracking out of HUBP [Why] We sometime require remapping of FB address space to UMA [How] Move address tracking up a layer before we apply address translation Signed-off-by: Tony Cheng <tony.cheng@amd.com> Reviewed-by: Charlene Liu <Charlene.Liu@amd.com> Acked-by: Leo Li <sunpeng.li@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c | 4 ---- .../amd/display/dc/dcn10/dcn10_hw_sequencer.c | 19 +++++++++++++++---- drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h | 1 - 3 files changed, 15 insertions(+), 9 deletions(-) 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 d6dc61ecf4a15..332354ca6529e 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c @@ -457,9 +457,6 @@ bool hubp1_program_surface_flip_and_addr( hubp->request_address = *address; - if (flip_immediate) - hubp->current_address = *address; - return true; } @@ -695,7 +692,6 @@ bool hubp1_is_flip_pending(struct hubp *hubp) if (earliest_inuse_address.grph.addr.quad_part != hubp->request_address.grph.addr.quad_part) return true; - hubp->current_address = hubp->request_address; return false; } 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 ade74c8218311..c87f6e603055a 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 @@ -1157,12 +1157,19 @@ static void dcn10_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_c if (plane_state == NULL) return; + addr_patched = patch_address_for_sbs_tb_stereo(pipe_ctx, &addr); + pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr( pipe_ctx->plane_res.hubp, &plane_state->address, plane_state->flip_immediate); + plane_state->status.requested_address = plane_state->address; + + if (plane_state->flip_immediate) + plane_state->status.current_address = plane_state->address; + if (addr_patched) pipe_ctx->plane_state->address.grph_stereo.left_addr = addr; } @@ -2533,16 +2540,20 @@ static void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx) { struct dc_plane_state *plane_state = pipe_ctx->plane_state; struct timing_generator *tg = pipe_ctx->stream_res.tg; + bool flip_pending; if (plane_state == NULL) return; - plane_state->status.is_flip_pending = - pipe_ctx->plane_res.hubp->funcs->hubp_is_flip_pending( + flip_pending = pipe_ctx->plane_res.hubp->funcs->hubp_is_flip_pending( pipe_ctx->plane_res.hubp); - plane_state->status.current_address = pipe_ctx->plane_res.hubp->current_address; - if (pipe_ctx->plane_res.hubp->current_address.type == PLN_ADDR_TYPE_GRPH_STEREO && + plane_state->status.is_flip_pending = flip_pending; + + if (!flip_pending) + plane_state->status.current_address = plane_state->status.requested_address; + + if (plane_state->status.current_address.type == PLN_ADDR_TYPE_GRPH_STEREO && tg->funcs->is_stereo_left_eye) { plane_state->status.is_right_eye = !tg->funcs->is_stereo_left_eye(pipe_ctx->stream_res.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 5b7976f6861ab..4f3f9e68ccfa4 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h @@ -46,7 +46,6 @@ struct hubp { const struct hubp_funcs *funcs; struct dc_context *ctx; struct dc_plane_address request_address; - struct dc_plane_address current_address; int inst; /* run time states */ -- GitLab From d6e75df4e5e10362a140c5c6ce8ced3612296ae3 Mon Sep 17 00:00:00 2001 From: Jun Lei <Jun.Lei@amd.com> Date: Fri, 22 Jun 2018 16:51:47 -0400 Subject: [PATCH 1220/1506] drm/amd/display: add new dc debug structure to track debug data [why] Some DTN tests still failing @ 2% Need to reduce. [how] add instrumentation code to driver so we can get more information from failed runs. Signed-off-by: Jun Lei <Jun.Lei@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Leo Li <sunpeng.li@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c | 3 +++ drivers/gpu/drm/amd/display/dc/dc.h | 5 +++++ 2 files changed, 8 insertions(+) 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 54e3964523457..701a882505e98 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 @@ -1028,6 +1028,9 @@ enum link_training_result dc_link_dp_perform_link_training( lt_settings.lane_settings[0].VOLTAGE_SWING, lt_settings.lane_settings[0].PRE_EMPHASIS); + if (status != LINK_TRAINING_SUCCESS) + link->ctx->dc->debug.debug_data.ltFailCount++; + return status; } diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 85f5ddded4188..f74ad8e3fd4e4 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -259,6 +259,11 @@ struct dc_debug { bool scl_reset_length10; bool hdmi20_disable; + struct { + uint32_t ltFailCount; + uint32_t i2cErrorCount; + uint32_t auxErrorCount; + } debug_data; }; struct dc_state; struct resource_pool; -- GitLab From 4a7d1d123ddb8c0b57e9beacee03ffcc9b55555a Mon Sep 17 00:00:00 2001 From: Harry Wentland <harry.wentland@amd.com> Date: Mon, 9 Jul 2018 17:25:15 -0400 Subject: [PATCH 1221/1506] drm/amd/display: dal 3.1.56 Signed-off-by: Harry Wentland <harry.wentland@amd.com> Reviewed-by: Steven Chiu <Steven.Chiu@amd.com> Acked-by: Leo Li <sunpeng.li@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index f74ad8e3fd4e4..b10dc177ad61c 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.1.55" +#define DC_VER "3.1.56" #define MAX_SURFACES 3 #define MAX_STREAMS 6 -- GitLab From ddb85fcd839cab0ac46a44d47c4f345dad4c2cb1 Mon Sep 17 00:00:00 2001 From: Krunoslav Kovac <Krunoslav.Kovac@amd.com> Date: Tue, 10 Jul 2018 16:04:05 -0400 Subject: [PATCH 1222/1506] drm/amd/display: Null ptr check for set_sdr_white_level [Why&How] Cursor boosting can only be done on DCN+ Check for nullptr since DCE doesn't implement it. Signed-off-by: Krunoslav Kovac <Krunoslav.Kovac@amd.com> Reviewed-by: Sivapiriyan Kumarasamy <Sivapiriyan.Kumarasamy@amd.com> Acked-by: Leo Li <sunpeng.li@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/core/dc_stream.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 4717330a42f49..fdcc8ab19bf3f 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c @@ -214,7 +214,8 @@ bool dc_stream_set_cursor_attributes( } core_dc->hwss.set_cursor_attribute(pipe_ctx); - core_dc->hwss.set_cursor_sdr_white_level(pipe_ctx); + if (core_dc->hwss.set_cursor_sdr_white_level) + core_dc->hwss.set_cursor_sdr_white_level(pipe_ctx); } if (pipe_to_program) -- GitLab From 9a6a8075bd439115b41468eaccdcb5e463196fb5 Mon Sep 17 00:00:00 2001 From: Harry Wentland <harry.wentland@amd.com> Date: Fri, 6 Jul 2018 13:40:33 -0400 Subject: [PATCH 1223/1506] drm/amd/display: Fix some checkpatch.pl errors and warnings in dc_link_dp.c [Why] Any Linux kernel code should pass checkpatch.pl with no errors and little, if any, warning. [How] Fixing some spacing errors and warnings. Signed-off-by: Harry Wentland <harry.wentland@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Leo Li <sunpeng.li@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/display/dc/core/dc_link_dp.c | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) 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 701a882505e98..474cd3e017521 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 @@ -39,7 +39,7 @@ static bool decide_fallback_link_setting( struct dc_link_settings initial_link_settings, struct dc_link_settings *current_link_setting, enum link_training_result training_result); -static struct dc_link_settings get_common_supported_link_settings ( +static struct dc_link_settings get_common_supported_link_settings( struct dc_link_settings link_setting_a, struct dc_link_settings link_setting_b); @@ -94,8 +94,8 @@ static void dpcd_set_link_settings( uint8_t rate = (uint8_t) (lt_settings->link_settings.link_rate); - union down_spread_ctrl downspread = {{0}}; - union lane_count_set lane_count_set = {{0}}; + union down_spread_ctrl downspread = { {0} }; + union lane_count_set lane_count_set = { {0} }; uint8_t link_set_buffer[2]; downspread.raw = (uint8_t) @@ -165,11 +165,11 @@ static void dpcd_set_lt_pattern_and_lane_settings( const struct link_training_settings *lt_settings, enum hw_dp_training_pattern pattern) { - union dpcd_training_lane dpcd_lane[LANE_COUNT_DP_MAX] = {{{0}}}; + union dpcd_training_lane dpcd_lane[LANE_COUNT_DP_MAX] = { { {0} } }; const uint32_t dpcd_base_lt_offset = DP_TRAINING_PATTERN_SET; uint8_t dpcd_lt_buffer[5] = {0}; - union dpcd_training_pattern dpcd_pattern = {{0}}; + union dpcd_training_pattern dpcd_pattern = { {0} }; uint32_t lane; uint32_t size_in_bytes; bool edp_workaround = false; /* TODO link_prop.INTERNAL */ @@ -233,7 +233,7 @@ static void dpcd_set_lt_pattern_and_lane_settings( link, DP_TRAINING_PATTERN_SET, &dpcd_pattern.raw, - sizeof(dpcd_pattern.raw) ); + sizeof(dpcd_pattern.raw)); core_link_write_dpcd( link, @@ -247,7 +247,7 @@ static void dpcd_set_lt_pattern_and_lane_settings( link, dpcd_base_lt_offset, dpcd_lt_buffer, - size_in_bytes + sizeof(dpcd_pattern.raw) ); + size_in_bytes + sizeof(dpcd_pattern.raw)); link->cur_lane_setting = lt_settings->lane_settings[0]; } @@ -429,8 +429,8 @@ static void get_lane_status_and_drive_settings( struct link_training_settings *req_settings) { uint8_t dpcd_buf[6] = {0}; - union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {{{0}}}; - struct link_training_settings request_settings = {{0}}; + union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = { { {0} } }; + struct link_training_settings request_settings = { {0} }; uint32_t lane; memset(req_settings, '\0', sizeof(struct link_training_settings)); @@ -652,7 +652,7 @@ static bool perform_post_lt_adj_req_sequence( if (req_drv_setting_changed) { update_drive_settings( - lt_settings,req_settings); + lt_settings, req_settings); dc_link_dp_set_drive_settings(link, lt_settings); @@ -725,8 +725,8 @@ static enum link_training_result perform_channel_equalization_sequence( enum hw_dp_training_pattern hw_tr_pattern; uint32_t retries_ch_eq; enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; - union lane_align_status_updated dpcd_lane_status_updated = {{0}}; - union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {{{0}}}; + union lane_align_status_updated dpcd_lane_status_updated = { {0} }; + union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = { { {0} } }; hw_tr_pattern = get_supported_tp(link); @@ -1186,7 +1186,7 @@ bool dp_hbr_verify_link_cap( return success; } -static struct dc_link_settings get_common_supported_link_settings ( +static struct dc_link_settings get_common_supported_link_settings( struct dc_link_settings link_setting_a, struct dc_link_settings link_setting_b) { @@ -1432,6 +1432,7 @@ static uint32_t bandwidth_in_kbps_from_link_settings( uint32_t lane_count = link_setting->lane_count; uint32_t kbps = link_rate_in_kbps; + kbps *= lane_count; kbps *= 8; /* 8 bits per byte*/ @@ -1449,9 +1450,9 @@ bool dp_validate_mode_timing( const struct dc_link_settings *link_setting; /*always DP fail safe mode*/ - if (timing->pix_clk_khz == (uint32_t)25175 && - timing->h_addressable == (uint32_t)640 && - timing->v_addressable == (uint32_t)480) + if (timing->pix_clk_khz == (uint32_t) 25175 && + timing->h_addressable == (uint32_t) 640 && + timing->v_addressable == (uint32_t) 480) return true; /* We always use verified link settings */ @@ -2001,7 +2002,7 @@ static void handle_automated_test(struct dc_link *link) bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd_irq_dpcd_data, bool *out_link_loss) { - union hpd_irq_data hpd_irq_dpcd_data = {{{{0}}}}; + union hpd_irq_data hpd_irq_dpcd_data = { { { {0} } } }; union device_service_irq device_service_clear = { { 0 } }; enum dc_status result; -- GitLab From 050d9d43a7d3847fd9726a675bf644b124518425 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Fri, 13 Jul 2018 09:50:08 +0200 Subject: [PATCH 1224/1506] drm/amdgpu: cleanup job header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move job related defines, structure and function declarations to amdgpu_job.h Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Junwei Zhang <Jerry.Zhang@amd.com> Acked-by: Chunming Zhou <david1.zhou@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 46 +-------------- drivers/gpu/drm/amd/amdgpu/amdgpu_job.h | 74 +++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 45 deletions(-) create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_job.h diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index c6c1e8dc919f5..e0cc9f878e803 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -73,6 +73,7 @@ #include "amdgpu_virt.h" #include "amdgpu_gart.h" #include "amdgpu_debugfs.h" +#include "amdgpu_job.h" /* * Modules parameters. @@ -600,17 +601,6 @@ struct amdgpu_ib { extern const struct drm_sched_backend_ops amdgpu_sched_ops; -int amdgpu_job_alloc(struct amdgpu_device *adev, unsigned num_ibs, - struct amdgpu_job **job, struct amdgpu_vm *vm); -int amdgpu_job_alloc_with_ib(struct amdgpu_device *adev, unsigned size, - struct amdgpu_job **job); - -void amdgpu_job_free_resources(struct amdgpu_job *job); -void amdgpu_job_free(struct amdgpu_job *job); -int amdgpu_job_submit(struct amdgpu_job *job, struct amdgpu_ring *ring, - struct drm_sched_entity *entity, void *owner, - struct dma_fence **f); - /* * Queue manager */ @@ -1058,40 +1048,6 @@ struct amdgpu_cs_parser { struct drm_syncobj **post_dep_syncobjs; }; -#define AMDGPU_PREAMBLE_IB_PRESENT (1 << 0) /* bit set means command submit involves a preamble IB */ -#define AMDGPU_PREAMBLE_IB_PRESENT_FIRST (1 << 1) /* bit set means preamble IB is first presented in belonging context */ -#define AMDGPU_HAVE_CTX_SWITCH (1 << 2) /* bit set means context switch occured */ - -struct amdgpu_job { - struct drm_sched_job base; - struct amdgpu_device *adev; - struct amdgpu_vm *vm; - struct amdgpu_ring *ring; - struct amdgpu_sync sync; - struct amdgpu_sync sched_sync; - struct amdgpu_ib *ibs; - struct dma_fence *fence; /* the hw fence */ - uint32_t preamble_status; - uint32_t num_ibs; - void *owner; - uint64_t fence_ctx; /* the fence_context this job uses */ - bool vm_needs_flush; - uint64_t vm_pd_addr; - unsigned vmid; - unsigned pasid; - uint32_t gds_base, gds_size; - uint32_t gws_base, gws_size; - uint32_t oa_base, oa_size; - uint32_t vram_lost_counter; - - /* user fence handling */ - uint64_t uf_addr; - uint64_t uf_sequence; - -}; -#define to_amdgpu_job(sched_job) \ - container_of((sched_job), struct amdgpu_job, base) - static inline u32 amdgpu_get_ib_value(struct amdgpu_cs_parser *p, uint32_t ib_idx, int idx) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h new file mode 100644 index 0000000000000..35bb93254eb26 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h @@ -0,0 +1,74 @@ +/* + * Copyright 2018 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ +#ifndef __AMDGPU_JOB_H__ +#define __AMDGPU_JOB_H__ + +/* bit set means command submit involves a preamble IB */ +#define AMDGPU_PREAMBLE_IB_PRESENT (1 << 0) +/* bit set means preamble IB is first presented in belonging context */ +#define AMDGPU_PREAMBLE_IB_PRESENT_FIRST (1 << 1) +/* bit set means context switch occured */ +#define AMDGPU_HAVE_CTX_SWITCH (1 << 2) + +#define to_amdgpu_job(sched_job) \ + container_of((sched_job), struct amdgpu_job, base) + +struct amdgpu_job { + struct drm_sched_job base; + struct amdgpu_device *adev; + struct amdgpu_vm *vm; + struct amdgpu_ring *ring; + struct amdgpu_sync sync; + struct amdgpu_sync sched_sync; + struct amdgpu_ib *ibs; + struct dma_fence *fence; /* the hw fence */ + uint32_t preamble_status; + uint32_t num_ibs; + void *owner; + uint64_t fence_ctx; /* the fence_context this job uses */ + bool vm_needs_flush; + uint64_t vm_pd_addr; + unsigned vmid; + unsigned pasid; + uint32_t gds_base, gds_size; + uint32_t gws_base, gws_size; + uint32_t oa_base, oa_size; + uint32_t vram_lost_counter; + + /* user fence handling */ + uint64_t uf_addr; + uint64_t uf_sequence; + +}; + +int amdgpu_job_alloc(struct amdgpu_device *adev, unsigned num_ibs, + struct amdgpu_job **job, struct amdgpu_vm *vm); +int amdgpu_job_alloc_with_ib(struct amdgpu_device *adev, unsigned size, + struct amdgpu_job **job); + +void amdgpu_job_free_resources(struct amdgpu_job *job); +void amdgpu_job_free(struct amdgpu_job *job); +int amdgpu_job_submit(struct amdgpu_job *job, struct amdgpu_ring *ring, + struct drm_sched_entity *entity, void *owner, + struct dma_fence **f); +#endif -- GitLab From eb3961a57424a5c3dae44576d1c88e64a818d871 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Fri, 13 Jul 2018 09:58:49 +0200 Subject: [PATCH 1225/1506] drm/amdgpu: remove fence context from the job MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Can be obtained directly from the fence as well. Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Junwei Zhang <Jerry.Zhang@amd.com> Acked-by: Chunming Zhou <david1.zhou@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 1 - drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_job.c | 1 - drivers/gpu/drm/amd/amdgpu/amdgpu_job.h | 1 - 4 files changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 6d8df76b5a5d5..6eb7ee859ffd1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -1239,7 +1239,6 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, } job->owner = p->filp; - job->fence_ctx = entity->fence_context; p->fence = dma_fence_get(&job->base.s_fence->finished); r = amdgpu_ctx_add_fence(p->ctx, ring, p->fence, &seq); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c index ce7739832d292..5518e623fed21 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c @@ -139,7 +139,7 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs, /* ring tests don't use a job */ if (job) { vm = job->vm; - fence_ctx = job->fence_ctx; + fence_ctx = job->base.s_fence->scheduled.context; } else { vm = NULL; fence_ctx = 0; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c index 2bd56760c7441..10e0a97c7c03e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c @@ -132,7 +132,6 @@ int amdgpu_job_submit(struct amdgpu_job *job, struct amdgpu_ring *ring, return r; job->owner = owner; - job->fence_ctx = entity->fence_context; *f = dma_fence_get(&job->base.s_fence->finished); amdgpu_job_free_resources(job); amdgpu_ring_priority_get(job->ring, job->base.s_priority); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h index 35bb93254eb26..3151692312bdf 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h @@ -45,7 +45,6 @@ struct amdgpu_job { uint32_t preamble_status; uint32_t num_ibs; void *owner; - uint64_t fence_ctx; /* the fence_context this job uses */ bool vm_needs_flush; uint64_t vm_pd_addr; unsigned vmid; -- GitLab From 0e28b10ff1b8e65788040b51c30c9cc984060dcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Fri, 13 Jul 2018 13:54:56 +0200 Subject: [PATCH 1226/1506] drm/amdgpu: remove ring parameter from amdgpu_job_submit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We know the ring through the entity anyway. Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Junwei Zhang <Jerry.Zhang@amd.com> Acked-by: Chunming Zhou <david1.zhou@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_job.c | 9 ++++----- drivers/gpu/drm/amd/amdgpu/amdgpu_job.h | 5 ++--- drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h | 2 ++ drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 6 +++--- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 11 +++++------ drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c | 2 +- drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c | 2 +- 9 files changed, 20 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c index 10e0a97c7c03e..51ff751e093b9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c @@ -117,21 +117,20 @@ void amdgpu_job_free(struct amdgpu_job *job) kfree(job); } -int amdgpu_job_submit(struct amdgpu_job *job, struct amdgpu_ring *ring, - struct drm_sched_entity *entity, void *owner, - struct dma_fence **f) +int amdgpu_job_submit(struct amdgpu_job *job, struct drm_sched_entity *entity, + void *owner, struct dma_fence **f) { int r; - job->ring = ring; if (!f) return -EINVAL; - r = drm_sched_job_init(&job->base, &ring->sched, entity, owner); + r = drm_sched_job_init(&job->base, entity->sched, entity, owner); if (r) return r; job->owner = owner; + job->ring = to_amdgpu_ring(entity->sched); *f = dma_fence_get(&job->base.s_fence->finished); amdgpu_job_free_resources(job); amdgpu_ring_priority_get(job->ring, job->base.s_priority); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h index 3151692312bdf..39f4230e1d37f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h @@ -67,7 +67,6 @@ int amdgpu_job_alloc_with_ib(struct amdgpu_device *adev, unsigned size, void amdgpu_job_free_resources(struct amdgpu_job *job); void amdgpu_job_free(struct amdgpu_job *job); -int amdgpu_job_submit(struct amdgpu_job *job, struct amdgpu_ring *ring, - struct drm_sched_entity *entity, void *owner, - struct dma_fence **f); +int amdgpu_job_submit(struct amdgpu_job *job, struct drm_sched_entity *entity, + void *owner, struct dma_fence **f); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h index a293f4e6760db..5018c0b6bf1a4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h @@ -44,6 +44,8 @@ #define AMDGPU_FENCE_FLAG_INT (1 << 1) #define AMDGPU_FENCE_FLAG_TC_WB_ONLY (1 << 2) +#define to_amdgpu_ring(s) container_of((s), struct amdgpu_ring, sched) + enum amdgpu_ring_type { AMDGPU_RING_TYPE_GFX, AMDGPU_RING_TYPE_COMPUTE, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 11a12483c9950..9958e76d1c784 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -2006,7 +2006,7 @@ static int amdgpu_map_buffer(struct ttm_buffer_object *bo, if (r) goto error_free; - r = amdgpu_job_submit(job, ring, &adev->mman.entity, + r = amdgpu_job_submit(job, &adev->mman.entity, AMDGPU_FENCE_OWNER_UNDEFINED, &fence); if (r) goto error_free; @@ -2083,7 +2083,7 @@ int amdgpu_copy_buffer(struct amdgpu_ring *ring, uint64_t src_offset, DRM_ERROR("Error scheduling IBs (%d)\n", r); amdgpu_job_free(job); } else { - r = amdgpu_job_submit(job, ring, &adev->mman.entity, + r = amdgpu_job_submit(job, &adev->mman.entity, AMDGPU_FENCE_OWNER_UNDEFINED, fence); if (r) goto error_free; @@ -2175,7 +2175,7 @@ int amdgpu_fill_buffer(struct amdgpu_bo *bo, amdgpu_ring_pad_ib(ring, &job->ibs[0]); WARN_ON(job->ibs[0].length_dw > num_dw); - r = amdgpu_job_submit(job, ring, &adev->mman.entity, + r = amdgpu_job_submit(job, &adev->mman.entity, AMDGPU_FENCE_OWNER_UNDEFINED, fence); if (r) goto error_free; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c index a6c2cace4b9dc..848b2e8988185 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c @@ -1074,7 +1074,7 @@ static int amdgpu_uvd_send_msg(struct amdgpu_ring *ring, struct amdgpu_bo *bo, if (r) goto err_free; - r = amdgpu_job_submit(job, ring, &adev->uvd.inst[ring->me].entity, + r = amdgpu_job_submit(job, &adev->uvd.inst[ring->me].entity, AMDGPU_FENCE_OWNER_UNDEFINED, &f); if (r) goto err_free; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c index ffb0fcc9707ec..7dfb4c4b19c5f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c @@ -539,7 +539,7 @@ int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle, amdgpu_job_free(job); } else { - r = amdgpu_job_submit(job, ring, &ring->adev->vce.entity, + r = amdgpu_job_submit(job, &ring->adev->vce.entity, AMDGPU_FENCE_OWNER_UNDEFINED, &f); if (r) goto err; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 484e2c19c0278..5d3d783f2d727 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -425,8 +425,8 @@ static int amdgpu_vm_clear_bo(struct amdgpu_device *adev, if (r) goto error_free; - r = amdgpu_job_submit(job, ring, &vm->entity, - AMDGPU_FENCE_OWNER_UNDEFINED, &fence); + r = amdgpu_job_submit(job, &vm->entity, AMDGPU_FENCE_OWNER_UNDEFINED, + &fence); if (r) goto error_free; @@ -1120,8 +1120,8 @@ int amdgpu_vm_update_directories(struct amdgpu_device *adev, amdgpu_sync_resv(adev, &job->sync, root->tbo.resv, AMDGPU_FENCE_OWNER_VM, false); WARN_ON(params.ib->length_dw > ndw); - r = amdgpu_job_submit(job, ring, &vm->entity, - AMDGPU_FENCE_OWNER_VM, &fence); + r = amdgpu_job_submit(job, &vm->entity, AMDGPU_FENCE_OWNER_VM, + &fence); if (r) goto error; @@ -1485,8 +1485,7 @@ static int amdgpu_vm_bo_update_mapping(struct amdgpu_device *adev, amdgpu_ring_pad_ib(ring, params.ib); WARN_ON(params.ib->length_dw > ndw); - r = amdgpu_job_submit(job, ring, &vm->entity, - AMDGPU_FENCE_OWNER_VM, &f); + r = amdgpu_job_submit(job, &vm->entity, AMDGPU_FENCE_OWNER_VM, &f); if (r) goto error_free; diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c index 1c118c02e8cb0..591d1f2118239 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c @@ -320,7 +320,7 @@ static int uvd_v6_0_enc_get_destroy_msg(struct amdgpu_ring *ring, amdgpu_job_free(job); } else { - r = amdgpu_job_submit(job, ring, &ring->adev->vce.entity, + r = amdgpu_job_submit(job, &ring->adev->vce.entity, AMDGPU_FENCE_OWNER_UNDEFINED, &f); if (r) goto err; diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c index d48bc33935452..ceb0a7037897e 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c @@ -321,7 +321,7 @@ int uvd_v7_0_enc_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle, amdgpu_job_free(job); } else { - r = amdgpu_job_submit(job, ring, &ring->adev->vce.entity, + r = amdgpu_job_submit(job, &ring->adev->vce.entity, AMDGPU_FENCE_OWNER_UNDEFINED, &f); if (r) goto err; -- GitLab From 3320b8d2acd3d480d0dd4835d970067354eac915 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Fri, 13 Jul 2018 15:08:44 +0200 Subject: [PATCH 1227/1506] drm/amdgpu: remove job->ring MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can easily get that from the scheduler. Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Junwei Zhang <Jerry.Zhang@amd.com> Acked-by: Chunming Zhou <david1.zhou@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 1 + drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 18 ++++++++--------- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 4 ++-- drivers/gpu/drm/amd/amdgpu/amdgpu_job.c | 23 +++++++++++----------- drivers/gpu/drm/amd/amdgpu/amdgpu_job.h | 1 - drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h | 8 ++++---- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 2 +- 7 files changed, 29 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index e0cc9f878e803..90780b0f0ce57 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1027,6 +1027,7 @@ struct amdgpu_cs_parser { /* scheduler job object */ struct amdgpu_job *job; + struct amdgpu_ring *ring; /* buffer objects */ struct ww_acquire_ctx ticket; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 6eb7ee859ffd1..72dc9b36b937f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -912,11 +912,11 @@ static int amdgpu_cs_ib_vm_chunk(struct amdgpu_device *adev, { struct amdgpu_fpriv *fpriv = p->filp->driver_priv; struct amdgpu_vm *vm = &fpriv->vm; - struct amdgpu_ring *ring = p->job->ring; + struct amdgpu_ring *ring = p->ring; int r; /* Only for UVD/VCE VM emulation */ - if (p->job->ring->funcs->parse_cs) { + if (p->ring->funcs->parse_cs) { unsigned i, j; for (i = 0, j = 0; i < p->nchunks && j < p->job->num_ibs; i++) { @@ -1030,10 +1030,10 @@ static int amdgpu_cs_ib_fill(struct amdgpu_device *adev, } } - if (parser->job->ring && parser->job->ring != ring) + if (parser->ring && parser->ring != ring) return -EINVAL; - parser->job->ring = ring; + parser->ring = ring; r = amdgpu_ib_get(adev, vm, ring->funcs->parse_cs ? chunk_ib->ib_bytes : 0, @@ -1052,11 +1052,11 @@ static int amdgpu_cs_ib_fill(struct amdgpu_device *adev, /* UVD & VCE fw doesn't support user fences */ if (parser->job->uf_addr && ( - parser->job->ring->funcs->type == AMDGPU_RING_TYPE_UVD || - parser->job->ring->funcs->type == AMDGPU_RING_TYPE_VCE)) + parser->ring->funcs->type == AMDGPU_RING_TYPE_UVD || + parser->ring->funcs->type == AMDGPU_RING_TYPE_VCE)) return -EINVAL; - return amdgpu_ctx_wait_prev_fence(parser->ctx, parser->job->ring->idx); + return amdgpu_ctx_wait_prev_fence(parser->ctx, parser->ring->idx); } static int amdgpu_cs_process_fence_dep(struct amdgpu_cs_parser *p, @@ -1207,7 +1207,7 @@ static void amdgpu_cs_post_dependencies(struct amdgpu_cs_parser *p) static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, union drm_amdgpu_cs *cs) { - struct amdgpu_ring *ring = p->job->ring; + struct amdgpu_ring *ring = p->ring; struct drm_sched_entity *entity = &p->ctx->rings[ring->idx].entity; struct amdgpu_job *job; unsigned i; @@ -1256,7 +1256,7 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, job->uf_sequence = seq; amdgpu_job_free_resources(job); - amdgpu_ring_priority_get(job->ring, job->base.s_priority); + amdgpu_ring_priority_get(p->ring, job->base.s_priority); trace_amdgpu_cs_ioctl(job); drm_sched_entity_push_job(&job->base, entity); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 2720444ff23a0..2b2de5f3e6e35 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -3253,7 +3253,7 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, kthread_park(ring->sched.thread); - if (job && job->ring->idx != i) + if (job && job->base.sched == &ring->sched) continue; drm_sched_hw_job_reset(&ring->sched, &job->base); @@ -3277,7 +3277,7 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, * or all rings (in the case @job is NULL) * after above amdgpu_reset accomplished */ - if ((!job || job->ring->idx == i) && !r) + if ((!job || job->base.sched == &ring->sched) && !r) drm_sched_job_recovery(&ring->sched); kthread_unpark(ring->sched.thread); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c index 51ff751e093b9..2496f2269bcb9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c @@ -30,12 +30,12 @@ static void amdgpu_job_timedout(struct drm_sched_job *s_job) { - struct amdgpu_job *job = container_of(s_job, struct amdgpu_job, base); + struct amdgpu_ring *ring = to_amdgpu_ring(s_job->sched); + struct amdgpu_job *job = to_amdgpu_job(s_job); DRM_ERROR("ring %s timeout, last signaled seq=%u, last emitted seq=%u\n", - job->base.sched->name, - atomic_read(&job->ring->fence_drv.last_seq), - job->ring->fence_drv.sync_seq); + job->base.sched->name, atomic_read(&ring->fence_drv.last_seq), + ring->fence_drv.sync_seq); amdgpu_device_gpu_recover(job->adev, job, false); } @@ -98,9 +98,10 @@ void amdgpu_job_free_resources(struct amdgpu_job *job) static void amdgpu_job_free_cb(struct drm_sched_job *s_job) { - struct amdgpu_job *job = container_of(s_job, struct amdgpu_job, base); + struct amdgpu_ring *ring = to_amdgpu_ring(s_job->sched); + struct amdgpu_job *job = to_amdgpu_job(s_job); - amdgpu_ring_priority_put(job->ring, s_job->s_priority); + amdgpu_ring_priority_put(ring, s_job->s_priority); dma_fence_put(job->fence); amdgpu_sync_free(&job->sync); amdgpu_sync_free(&job->sched_sync); @@ -120,6 +121,7 @@ void amdgpu_job_free(struct amdgpu_job *job) int amdgpu_job_submit(struct amdgpu_job *job, struct drm_sched_entity *entity, void *owner, struct dma_fence **f) { + struct amdgpu_ring *ring = to_amdgpu_ring(entity->sched); int r; if (!f) @@ -130,10 +132,9 @@ int amdgpu_job_submit(struct amdgpu_job *job, struct drm_sched_entity *entity, return r; job->owner = owner; - job->ring = to_amdgpu_ring(entity->sched); *f = dma_fence_get(&job->base.s_fence->finished); amdgpu_job_free_resources(job); - amdgpu_ring_priority_get(job->ring, job->base.s_priority); + amdgpu_ring_priority_get(ring, job->base.s_priority); drm_sched_entity_push_job(&job->base, entity); return 0; @@ -142,6 +143,7 @@ int amdgpu_job_submit(struct amdgpu_job *job, struct drm_sched_entity *entity, static struct dma_fence *amdgpu_job_dependency(struct drm_sched_job *sched_job, struct drm_sched_entity *s_entity) { + struct amdgpu_ring *ring = to_amdgpu_ring(s_entity->sched); struct amdgpu_job *job = to_amdgpu_job(sched_job); struct amdgpu_vm *vm = job->vm; bool explicit = false; @@ -157,8 +159,6 @@ static struct dma_fence *amdgpu_job_dependency(struct drm_sched_job *sched_job, } while (fence == NULL && vm && !job->vmid) { - struct amdgpu_ring *ring = job->ring; - r = amdgpu_vmid_grab(vm, ring, &job->sync, &job->base.s_fence->finished, job); @@ -173,6 +173,7 @@ static struct dma_fence *amdgpu_job_dependency(struct drm_sched_job *sched_job, static struct dma_fence *amdgpu_job_run(struct drm_sched_job *sched_job) { + struct amdgpu_ring *ring = to_amdgpu_ring(sched_job->sched); struct dma_fence *fence = NULL, *finished; struct amdgpu_device *adev; struct amdgpu_job *job; @@ -196,7 +197,7 @@ static struct dma_fence *amdgpu_job_run(struct drm_sched_job *sched_job) if (finished->error < 0) { DRM_INFO("Skip scheduling IBs!\n"); } else { - r = amdgpu_ib_schedule(job->ring, job->num_ibs, job->ibs, job, + r = amdgpu_ib_schedule(ring, job->num_ibs, job->ibs, job, &fence); if (r) DRM_ERROR("Error scheduling IBs (%d)\n", r); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h index 39f4230e1d37f..c663c1925f91f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h @@ -37,7 +37,6 @@ struct amdgpu_job { struct drm_sched_job base; struct amdgpu_device *adev; struct amdgpu_vm *vm; - struct amdgpu_ring *ring; struct amdgpu_sync sync; struct amdgpu_sync sched_sync; struct amdgpu_ib *ibs; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h index e96e26d3f3b08..76920035eb22d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h @@ -150,10 +150,10 @@ TRACE_EVENT(amdgpu_cs, TP_fast_assign( __entry->bo_list = p->bo_list; - __entry->ring = p->job->ring->idx; + __entry->ring = p->ring->idx; __entry->dw = p->job->ibs[i].length_dw; __entry->fences = amdgpu_fence_count_emitted( - p->job->ring); + p->ring); ), TP_printk("bo_list=%p, ring=%u, dw=%u, fences=%u", __entry->bo_list, __entry->ring, __entry->dw, @@ -178,7 +178,7 @@ TRACE_EVENT(amdgpu_cs_ioctl, __assign_str(timeline, AMDGPU_JOB_GET_TIMELINE_NAME(job)) __entry->context = job->base.s_fence->finished.context; __entry->seqno = job->base.s_fence->finished.seqno; - __entry->ring_name = job->ring->name; + __entry->ring_name = to_amdgpu_ring(job->base.sched)->name; __entry->num_ibs = job->num_ibs; ), TP_printk("sched_job=%llu, timeline=%s, context=%u, seqno=%u, ring_name=%s, num_ibs=%u", @@ -203,7 +203,7 @@ TRACE_EVENT(amdgpu_sched_run_job, __assign_str(timeline, AMDGPU_JOB_GET_TIMELINE_NAME(job)) __entry->context = job->base.s_fence->finished.context; __entry->seqno = job->base.s_fence->finished.seqno; - __entry->ring_name = job->ring->name; + __entry->ring_name = to_amdgpu_ring(job->base.sched)->name; __entry->num_ibs = job->num_ibs; ), TP_printk("sched_job=%llu, timeline=%s, context=%u, seqno=%u, ring_name=%s, num_ibs=%u", diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c index 848b2e8988185..7738d2b90dae3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c @@ -692,11 +692,11 @@ static int amdgpu_uvd_cs_msg(struct amdgpu_uvd_cs_ctx *ctx, struct amdgpu_bo *bo, unsigned offset) { struct amdgpu_device *adev = ctx->parser->adev; + uint32_t ip_instance = ctx->parser->ring->me; int32_t *msg, msg_type, handle; void *ptr; long r; int i; - uint32_t ip_instance = ctx->parser->job->ring->me; if (offset & 0x3F) { DRM_ERROR("UVD(%d) messages must be 64 byte aligned!\n", ip_instance); -- GitLab From ee913fd9e166384aacc0aa70ffd4e93ca41d54b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Fri, 13 Jul 2018 16:29:10 +0200 Subject: [PATCH 1228/1506] drm/amdgpu: add amdgpu_job_submit_direct helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make sure that we properly initialize at least the sched member. Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Junwei Zhang <Jerry.Zhang@amd.com> Acked-by: Chunming Zhou <david1.zhou@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_job.c | 15 +++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_job.h | 4 ++++ drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 17 ++++++----------- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 5 +---- drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c | 20 ++++++-------------- drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c | 17 ++++------------- drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c | 20 ++++++-------------- drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c | 20 ++++++-------------- 8 files changed, 48 insertions(+), 70 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c index 2496f2269bcb9..0e2b18ccdf2e3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c @@ -140,6 +140,21 @@ int amdgpu_job_submit(struct amdgpu_job *job, struct drm_sched_entity *entity, return 0; } +int amdgpu_job_submit_direct(struct amdgpu_job *job, struct amdgpu_ring *ring, + struct dma_fence **fence) +{ + int r; + + job->base.sched = &ring->sched; + r = amdgpu_ib_schedule(ring, job->num_ibs, job->ibs, NULL, fence); + job->fence = dma_fence_get(*fence); + if (r) + return r; + + amdgpu_job_free(job); + return 0; +} + static struct dma_fence *amdgpu_job_dependency(struct drm_sched_job *sched_job, struct drm_sched_entity *s_entity) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h index c663c1925f91f..d77fd232f7ce3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h @@ -33,6 +33,8 @@ #define to_amdgpu_job(sched_job) \ container_of((sched_job), struct amdgpu_job, base) +struct amdgpu_fence; + struct amdgpu_job { struct drm_sched_job base; struct amdgpu_device *adev; @@ -68,4 +70,6 @@ void amdgpu_job_free_resources(struct amdgpu_job *job); void amdgpu_job_free(struct amdgpu_job *job); int amdgpu_job_submit(struct amdgpu_job *job, struct drm_sched_entity *entity, void *owner, struct dma_fence **f); +int amdgpu_job_submit_direct(struct amdgpu_job *job, struct amdgpu_ring *ring, + struct dma_fence **fence); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 9958e76d1c784..13977ea6a0978 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -2075,24 +2075,19 @@ int amdgpu_copy_buffer(struct amdgpu_ring *ring, uint64_t src_offset, amdgpu_ring_pad_ib(ring, &job->ibs[0]); WARN_ON(job->ibs[0].length_dw > num_dw); - if (direct_submit) { - r = amdgpu_ib_schedule(ring, job->num_ibs, job->ibs, - NULL, fence); - job->fence = dma_fence_get(*fence); - if (r) - DRM_ERROR("Error scheduling IBs (%d)\n", r); - amdgpu_job_free(job); - } else { + if (direct_submit) + r = amdgpu_job_submit_direct(job, ring, fence); + else r = amdgpu_job_submit(job, &adev->mman.entity, AMDGPU_FENCE_OWNER_UNDEFINED, fence); - if (r) - goto error_free; - } + if (r) + goto error_free; return r; error_free: amdgpu_job_free(job); + DRM_ERROR("Error scheduling IBs (%d)\n", r); return r; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c index 7738d2b90dae3..d708970244eb7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c @@ -1062,12 +1062,9 @@ static int amdgpu_uvd_send_msg(struct amdgpu_ring *ring, struct amdgpu_bo *bo, if (r < 0) goto err_free; - r = amdgpu_ib_schedule(ring, 1, ib, NULL, &f); - job->fence = dma_fence_get(f); + r = amdgpu_job_submit_direct(job, ring, &f); if (r) goto err_free; - - amdgpu_job_free(job); } else { r = amdgpu_sync_resv(adev, &job->sync, bo->tbo.resv, AMDGPU_FENCE_OWNER_UNDEFINED, false); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c index 7dfb4c4b19c5f..86182c966ed6f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c @@ -469,12 +469,10 @@ int amdgpu_vce_get_create_msg(struct amdgpu_ring *ring, uint32_t handle, for (i = ib->length_dw; i < ib_size_dw; ++i) ib->ptr[i] = 0x0; - r = amdgpu_ib_schedule(ring, 1, ib, NULL, &f); - job->fence = dma_fence_get(f); + r = amdgpu_job_submit_direct(job, ring, &f); if (r) goto err; - amdgpu_job_free(job); if (fence) *fence = dma_fence_get(f); dma_fence_put(f); @@ -531,19 +529,13 @@ int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle, for (i = ib->length_dw; i < ib_size_dw; ++i) ib->ptr[i] = 0x0; - if (direct) { - r = amdgpu_ib_schedule(ring, 1, ib, NULL, &f); - job->fence = dma_fence_get(f); - if (r) - goto err; - - amdgpu_job_free(job); - } else { + if (direct) + r = amdgpu_job_submit_direct(job, ring, &f); + else r = amdgpu_job_submit(job, &ring->adev->vce.entity, AMDGPU_FENCE_OWNER_UNDEFINED, &f); - if (r) - goto err; - } + if (r) + goto err; if (fence) *fence = dma_fence_get(f); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c index 769c6723c9caf..798648a197108 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c @@ -308,13 +308,10 @@ static int amdgpu_vcn_dec_send_msg(struct amdgpu_ring *ring, } ib->length_dw = 16; - r = amdgpu_ib_schedule(ring, 1, ib, NULL, &f); - job->fence = dma_fence_get(f); + r = amdgpu_job_submit_direct(job, ring, &f); if (r) goto err_free; - amdgpu_job_free(job); - amdgpu_bo_fence(bo, f, false); amdgpu_bo_unreserve(bo); amdgpu_bo_unref(&bo); @@ -499,12 +496,10 @@ static int amdgpu_vcn_enc_get_create_msg(struct amdgpu_ring *ring, uint32_t hand for (i = ib->length_dw; i < ib_size_dw; ++i) ib->ptr[i] = 0x0; - r = amdgpu_ib_schedule(ring, 1, ib, NULL, &f); - job->fence = dma_fence_get(f); + r = amdgpu_job_submit_direct(job, ring, &f); if (r) goto err; - amdgpu_job_free(job); if (fence) *fence = dma_fence_get(f); dma_fence_put(f); @@ -553,12 +548,10 @@ static int amdgpu_vcn_enc_get_destroy_msg(struct amdgpu_ring *ring, uint32_t han for (i = ib->length_dw; i < ib_size_dw; ++i) ib->ptr[i] = 0x0; - r = amdgpu_ib_schedule(ring, 1, ib, NULL, &f); - job->fence = dma_fence_get(f); + r = amdgpu_job_submit_direct(job, ring, &f); if (r) goto err; - amdgpu_job_free(job); if (fence) *fence = dma_fence_get(f); dma_fence_put(f); @@ -666,12 +659,10 @@ static int amdgpu_vcn_jpeg_set_reg(struct amdgpu_ring *ring, uint32_t handle, } ib->length_dw = 16; - r = amdgpu_ib_schedule(ring, 1, ib, NULL, &f); - job->fence = dma_fence_get(f); + r = amdgpu_job_submit_direct(job, ring, &f); if (r) goto err; - amdgpu_job_free(job); if (fence) *fence = dma_fence_get(f); dma_fence_put(f); diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c index 591d1f2118239..b796dc8375cd1 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c @@ -248,12 +248,10 @@ static int uvd_v6_0_enc_get_create_msg(struct amdgpu_ring *ring, uint32_t handle for (i = ib->length_dw; i < ib_size_dw; ++i) ib->ptr[i] = 0x0; - r = amdgpu_ib_schedule(ring, 1, ib, NULL, &f); - job->fence = dma_fence_get(f); + r = amdgpu_job_submit_direct(job, ring, &f); if (r) goto err; - amdgpu_job_free(job); if (fence) *fence = dma_fence_get(f); dma_fence_put(f); @@ -312,19 +310,13 @@ static int uvd_v6_0_enc_get_destroy_msg(struct amdgpu_ring *ring, for (i = ib->length_dw; i < ib_size_dw; ++i) ib->ptr[i] = 0x0; - if (direct) { - r = amdgpu_ib_schedule(ring, 1, ib, NULL, &f); - job->fence = dma_fence_get(f); - if (r) - goto err; - - amdgpu_job_free(job); - } else { + if (direct) + r = amdgpu_job_submit_direct(job, ring, &f); + else r = amdgpu_job_submit(job, &ring->adev->vce.entity, AMDGPU_FENCE_OWNER_UNDEFINED, &f); - if (r) - goto err; - } + if (r) + goto err; if (fence) *fence = dma_fence_get(f); diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c index ceb0a7037897e..831bb995b0ed9 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c @@ -250,12 +250,10 @@ static int uvd_v7_0_enc_get_create_msg(struct amdgpu_ring *ring, uint32_t handle for (i = ib->length_dw; i < ib_size_dw; ++i) ib->ptr[i] = 0x0; - r = amdgpu_ib_schedule(ring, 1, ib, NULL, &f); - job->fence = dma_fence_get(f); + r = amdgpu_job_submit_direct(job, ring, &f); if (r) goto err; - amdgpu_job_free(job); if (fence) *fence = dma_fence_get(f); dma_fence_put(f); @@ -313,19 +311,13 @@ int uvd_v7_0_enc_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle, for (i = ib->length_dw; i < ib_size_dw; ++i) ib->ptr[i] = 0x0; - if (direct) { - r = amdgpu_ib_schedule(ring, 1, ib, NULL, &f); - job->fence = dma_fence_get(f); - if (r) - goto err; - - amdgpu_job_free(job); - } else { + if (direct) + r = amdgpu_job_submit_direct(job, ring, &f); + else r = amdgpu_job_submit(job, &ring->adev->vce.entity, AMDGPU_FENCE_OWNER_UNDEFINED, &f); - if (r) - goto err; - } + if (r) + goto err; if (fence) *fence = dma_fence_get(f); -- GitLab From 01c097dbfc03ac1357b9c8a1f52fd43d636bc7f7 Mon Sep 17 00:00:00 2001 From: Felix Kuehling <Felix.Kuehling@amd.com> Date: Mon, 16 Jul 2018 19:10:36 -0400 Subject: [PATCH 1229/1506] drm/amdgpu: Add kfd2kgd.set_compute_idle interface This allows automatic switching to the compute power profile depending on compute activity. Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com> Reviewed-by: Eric Huang <JinHuiEric.Huang@amd.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 8 ++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h | 1 + drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c | 3 ++- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c | 3 ++- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c | 3 ++- drivers/gpu/drm/amd/include/kgd_kfd_interface.h | 5 +++++ 6 files changed, 20 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index 454c22c722c24..f8bbbb3a95043 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -488,6 +488,14 @@ int amdgpu_amdkfd_submit_ib(struct kgd_dev *kgd, enum kgd_engine_type engine, return ret; } +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); +} + bool amdgpu_amdkfd_is_kfd_vmid(struct amdgpu_device *adev, u32 vmid) { if (adev->kfd) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h index 60207ea48bf5d..2f379c183ed20 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h @@ -119,6 +119,7 @@ int amdgpu_amdkfd_evict_userptr(struct kgd_mem *mem, struct mm_struct *mm); int amdgpu_amdkfd_submit_ib(struct kgd_dev *kgd, enum kgd_engine_type engine, uint32_t vmid, uint64_t gpu_addr, uint32_t *ib_cmd, uint32_t ib_len); +void amdgpu_amdkfd_set_compute_idle(struct kgd_dev *kgd, bool idle); struct kfd2kgd_calls *amdgpu_amdkfd_gfx_7_get_functions(void); struct kfd2kgd_calls *amdgpu_amdkfd_gfx_8_0_get_functions(void); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c index 98eac00e5d325..ea3f698aef5ea 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c @@ -219,7 +219,8 @@ static const struct kfd2kgd_calls kfd2kgd = { .submit_ib = amdgpu_amdkfd_submit_ib, .get_vm_fault_info = amdgpu_amdkfd_gpuvm_get_vm_fault_info, .read_vmid_from_vmfault_reg = read_vmid_from_vmfault_reg, - .gpu_recover = amdgpu_amdkfd_gpu_reset + .gpu_recover = amdgpu_amdkfd_gpu_reset, + .set_compute_idle = amdgpu_amdkfd_set_compute_idle }; struct kfd2kgd_calls *amdgpu_amdkfd_gfx_7_get_functions(void) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c index ad563b1ee5474..f6e53e9352bd8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c @@ -177,7 +177,8 @@ static const struct kfd2kgd_calls kfd2kgd = { .invalidate_tlbs_vmid = invalidate_tlbs_vmid, .submit_ib = amdgpu_amdkfd_submit_ib, .get_vm_fault_info = amdgpu_amdkfd_gpuvm_get_vm_fault_info, - .gpu_recover = amdgpu_amdkfd_gpu_reset + .gpu_recover = amdgpu_amdkfd_gpu_reset, + .set_compute_idle = amdgpu_amdkfd_set_compute_idle }; struct kfd2kgd_calls *amdgpu_amdkfd_gfx_8_0_get_functions(void) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c index 3b07d37b6fd45..8efedfcb9dfca 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c @@ -213,7 +213,8 @@ static const struct kfd2kgd_calls kfd2kgd = { .invalidate_tlbs = invalidate_tlbs, .invalidate_tlbs_vmid = invalidate_tlbs_vmid, .submit_ib = amdgpu_amdkfd_submit_ib, - .gpu_recover = amdgpu_amdkfd_gpu_reset + .gpu_recover = amdgpu_amdkfd_gpu_reset, + .set_compute_idle = amdgpu_amdkfd_set_compute_idle }; struct kfd2kgd_calls *amdgpu_amdkfd_gfx_9_0_get_functions(void) diff --git a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h index 7df5e4ab839f5..14391b06080ce 100644 --- a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h @@ -282,6 +282,9 @@ struct tile_config { * * @gpu_recover: let kgd reset gpu after kfd detect CPC hang * + * @set_compute_idle: Indicates that compute is idle on a device. This + * can be used to change power profiles depending on compute activity. + * * This structure contains function pointers to services that the kgd driver * provides to amdkfd driver. * @@ -403,6 +406,8 @@ struct kfd2kgd_calls { uint32_t (*read_vmid_from_vmfault_reg)(struct kgd_dev *kgd); void (*gpu_recover)(struct kgd_dev *kgd); + + void (*set_compute_idle)(struct kgd_dev *kgd, bool idle); }; /** -- GitLab From b5aa3f4aef724e9c0f626dcf69948b22efcc5176 Mon Sep 17 00:00:00 2001 From: Felix Kuehling <Felix.Kuehling@amd.com> Date: Mon, 16 Jul 2018 19:10:37 -0400 Subject: [PATCH 1230/1506] drm/amdkfd: Call kfd2kgd.set_compute_idle User mode queue submissions don't go through KFD. Therefore we don't know exactly when compute is idle or not idle. We use the existence of user mode queues on a device as an approximation. register_process is called when the first queue of a process is created. Conversely unregister_process is called when the last queue is destroyed. The first process that is registered takes compute out of idle. The last process that is unregisters sets compute back to idle. Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com> Reviewed-by: Eric Huang <JinHuiEric.Huang@amd.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com> --- drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) 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 ace94d6e54cf2..ec0d62a16e538 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -782,7 +782,8 @@ static int register_process(struct device_queue_manager *dqm, retval = dqm->asic_ops.update_qpd(dqm, qpd); - dqm->processes_count++; + if (dqm->processes_count++ == 0) + dqm->dev->kfd2kgd->set_compute_idle(dqm->dev->kgd, false); dqm_unlock(dqm); @@ -805,7 +806,9 @@ static int unregister_process(struct device_queue_manager *dqm, if (qpd == cur->qpd) { list_del(&cur->list); kfree(cur); - dqm->processes_count--; + if (--dqm->processes_count == 0) + dqm->dev->kfd2kgd->set_compute_idle( + dqm->dev->kgd, true); goto out; } } -- GitLab From d778847208c016f66a44d4c40baa74ca3bf724fd Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Tue, 17 Jul 2018 09:23:34 +0100 Subject: [PATCH 1231/1506] drm/i915/selftests: Free the backing store between iterations In the huge pages tests, we may have lots of objects being trapped on the freelist as we hold the struct_mutex allowing the free worker no opportunity to recover the backing store. We also have stricter requirements and the desire for large contiguous pages, further increasing the allocation pressure. To reduce the chance of running out of memory, we could either drop the mutex and flush the free worker, or we could release the backing store directly. We do the latter in this patch for simplicity. References: https://bugs.freedesktop.org/show_bug.cgi?id=107254 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Matthew Auld <matthew.william.auld@gmail.com> Reviewed-by: Matthew Auld <matthew.william.auld@gmail.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180717082334.18774-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/selftests/huge_pages.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/i915/selftests/huge_pages.c b/drivers/gpu/drm/i915/selftests/huge_pages.c index d9f439f6219f6..7efb326badcd6 100644 --- a/drivers/gpu/drm/i915/selftests/huge_pages.c +++ b/drivers/gpu/drm/i915/selftests/huge_pages.c @@ -570,6 +570,7 @@ static int igt_mock_ppgtt_misaligned_dma(void *arg) i915_vma_close(vma); i915_gem_object_unpin_pages(obj); + __i915_gem_object_put_pages(obj, I915_MM_NORMAL); i915_gem_object_put(obj); } @@ -597,6 +598,7 @@ static void close_object_list(struct list_head *objects, list_del(&obj->st_link); i915_gem_object_unpin_pages(obj); + __i915_gem_object_put_pages(obj, I915_MM_NORMAL); i915_gem_object_put(obj); } } @@ -866,6 +868,7 @@ static int igt_mock_ppgtt_64K(void *arg) i915_vma_close(vma); i915_gem_object_unpin_pages(obj); + __i915_gem_object_put_pages(obj, I915_MM_NORMAL); i915_gem_object_put(obj); } } @@ -1265,6 +1268,7 @@ static int igt_ppgtt_exhaust_huge(void *arg) } i915_gem_object_unpin_pages(obj); + __i915_gem_object_put_pages(obj, I915_MM_NORMAL); i915_gem_object_put(obj); } } @@ -1326,6 +1330,7 @@ static int igt_ppgtt_internal_huge(void *arg) } i915_gem_object_unpin_pages(obj); + __i915_gem_object_put_pages(obj, I915_MM_NORMAL); i915_gem_object_put(obj); } @@ -1394,6 +1399,7 @@ static int igt_ppgtt_gemfs_huge(void *arg) } i915_gem_object_unpin_pages(obj); + __i915_gem_object_put_pages(obj, I915_MM_NORMAL); i915_gem_object_put(obj); } -- GitLab From 1ef2917d1d9e6cce41c8794b2e3e81552b1668e4 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann <tzimmermann@suse.de> Date: Tue, 17 Jul 2018 10:33:49 +0200 Subject: [PATCH 1232/1506] drm/imx: 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 <tzimmermann@suse.de> Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de> --- drivers/gpu/drm/imx/imx-drm-core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c index 1d053bbefc02c..c895fe78fb48c 100644 --- a/drivers/gpu/drm/imx/imx-drm-core.c +++ b/drivers/gpu/drm/imx/imx-drm-core.c @@ -229,7 +229,7 @@ static int imx_drm_bind(struct device *dev) imxdrm = devm_kzalloc(dev, sizeof(*imxdrm), GFP_KERNEL); if (!imxdrm) { ret = -ENOMEM; - goto err_unref; + goto err_put; } imxdrm->drm = drm; @@ -306,8 +306,8 @@ static int imx_drm_bind(struct device *dev) component_unbind_all(drm->dev, drm); err_kms: drm_mode_config_cleanup(drm); -err_unref: - drm_dev_unref(drm); +err_put: + drm_dev_put(drm); return ret; } @@ -327,7 +327,7 @@ static void imx_drm_unbind(struct device *dev) component_unbind_all(drm->dev, drm); dev_set_drvdata(dev, NULL); - drm_dev_unref(drm); + drm_dev_put(drm); } static const struct component_master_ops imx_drm_ops = { -- GitLab From 4c2ae34f64c80991501ebd830b13dce5c7dc3621 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann <tzimmermann@suse.de> Date: Tue, 17 Jul 2018 10:48:14 +0200 Subject: [PATCH 1233/1506] drm/sun4i: 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 <tzimmermann@suse.de> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180717084814.18091-1-tzimmermann@suse.de --- drivers/gpu/drm/sun4i/sun4i_drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c index 03ffbcc98dd07..dd19d674055c6 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.c +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c @@ -144,7 +144,7 @@ static int sun4i_drv_bind(struct device *dev) drm_mode_config_cleanup(drm); of_reserved_mem_device_release(dev); free_drm: - drm_dev_unref(drm); + drm_dev_put(drm); return ret; } @@ -157,7 +157,7 @@ static void sun4i_drv_unbind(struct device *dev) sun4i_framebuffer_free(drm); drm_mode_config_cleanup(drm); of_reserved_mem_device_release(dev); - drm_dev_unref(drm); + drm_dev_put(drm); } static const struct component_master_ops sun4i_drv_master_ops = { -- GitLab From 81f2b25adddeff2fc7fdd1f23f889d018ba65466 Mon Sep 17 00:00:00 2001 From: Leonard Crestez <leonard.crestez@nxp.com> Date: Tue, 17 Jul 2018 15:11:28 +0300 Subject: [PATCH 1234/1506] drm/imx: Remove unused field imx_drm_device.pipes This has been unused since commit 44b460cfe554 ("drm: imx: remove struct imx_drm_crtc and imx_drm_crtc_helper_funcs") Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com> Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de> --- drivers/gpu/drm/imx/imx-drm-core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c index c895fe78fb48c..f0122afcf2a88 100644 --- a/drivers/gpu/drm/imx/imx-drm-core.c +++ b/drivers/gpu/drm/imx/imx-drm-core.c @@ -37,7 +37,6 @@ struct imx_drm_device { struct drm_device *drm; - unsigned int pipes; struct drm_atomic_state *state; }; -- GitLab From d8b3f454dab48bc40528aa5f19f7f27f2a6dc825 Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski <paul.kocialkowski@bootlin.com> Date: Tue, 17 Jul 2018 14:25:22 +0200 Subject: [PATCH 1235/1506] drm/sun4i: sun8i: Avoid clearing blending order at each atomic commit Blending order is set based on the z position of each DRM plane. The blending order register is currently cleared at each atomic DRM commit, with the intent that each committed plane will set the appropriate bits (based on its z-pos) when enabling the plane. However, it sometimes happens that a particular plane is left unchanged by an atomic commit and thus will not be configured again. In that scenario, blending order is cleared and only the bits relevant for the planes affected by the commit are set. This leaves the planes that did not change without their blending order set in the register, leading to that plane not being displayed. Instead of clearing the blending order register at every atomic commit, this change moves the register's initial clear at bind time and only clears the bits for a specific plane when disabling it or changing its zpos. This way, planes that are left untouched by a DRM atomic commit are no longer disabled. Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180717122522.11327-1-paul.kocialkowski@bootlin.com --- drivers/gpu/drm/sun4i/sun8i_mixer.c | 15 +++------------ drivers/gpu/drm/sun4i/sun8i_ui_layer.c | 24 ++++++++++++++++++++---- drivers/gpu/drm/sun4i/sun8i_vi_layer.c | 24 ++++++++++++++++++++---- 3 files changed, 43 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c index f76a5576c0e62..fc3713608f78d 100644 --- a/drivers/gpu/drm/sun4i/sun8i_mixer.c +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c @@ -261,17 +261,6 @@ const struct de2_fmt_info *sun8i_mixer_format_info(u32 format) return NULL; } -static void sun8i_mixer_atomic_begin(struct sunxi_engine *engine, - struct drm_crtc_state *old_state) -{ - /* - * Disable all pipes at the beginning. They will be enabled - * again if needed in plane update callback. - */ - regmap_update_bits(engine->regs, SUN8I_MIXER_BLEND_PIPE_CTL, - SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK, 0); -} - static void sun8i_mixer_commit(struct sunxi_engine *engine) { DRM_DEBUG_DRIVER("Committing changes\n"); @@ -323,7 +312,6 @@ static struct drm_plane **sun8i_layers_init(struct drm_device *drm, } static const struct sunxi_engine_ops sun8i_engine_ops = { - .atomic_begin = sun8i_mixer_atomic_begin, .commit = sun8i_mixer_commit, .layers_init = sun8i_layers_init, }; @@ -494,6 +482,9 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master, regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_MODE(i), SUN8I_MIXER_BLEND_MODE_DEF); + regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL, + SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK, 0); + return 0; err_disable_bus_clk: diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c index 518e1921f47e6..28c15c6ef1efb 100644 --- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c +++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c @@ -27,7 +27,8 @@ #include "sun8i_ui_scaler.h" static void sun8i_ui_layer_enable(struct sun8i_mixer *mixer, int channel, - int overlay, bool enable, unsigned int zpos) + int overlay, bool enable, unsigned int zpos, + unsigned int old_zpos) { u32 val; @@ -43,6 +44,18 @@ static void sun8i_ui_layer_enable(struct sun8i_mixer *mixer, int channel, SUN8I_MIXER_CHAN_UI_LAYER_ATTR(channel, overlay), SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN, val); + if (!enable || zpos != old_zpos) { + regmap_update_bits(mixer->engine.regs, + SUN8I_MIXER_BLEND_PIPE_CTL, + SUN8I_MIXER_BLEND_PIPE_CTL_EN(old_zpos), + 0); + + regmap_update_bits(mixer->engine.regs, + SUN8I_MIXER_BLEND_ROUTE, + SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(old_zpos), + 0); + } + if (enable) { val = SUN8I_MIXER_BLEND_PIPE_CTL_EN(zpos); @@ -242,9 +255,11 @@ static void sun8i_ui_layer_atomic_disable(struct drm_plane *plane, struct drm_plane_state *old_state) { struct sun8i_ui_layer *layer = plane_to_sun8i_ui_layer(plane); + unsigned int old_zpos = old_state->normalized_zpos; struct sun8i_mixer *mixer = layer->mixer; - sun8i_ui_layer_enable(mixer, layer->channel, layer->overlay, false, 0); + sun8i_ui_layer_enable(mixer, layer->channel, layer->overlay, false, 0, + old_zpos); } static void sun8i_ui_layer_atomic_update(struct drm_plane *plane, @@ -252,11 +267,12 @@ static void sun8i_ui_layer_atomic_update(struct drm_plane *plane, { struct sun8i_ui_layer *layer = plane_to_sun8i_ui_layer(plane); unsigned int zpos = plane->state->normalized_zpos; + unsigned int old_zpos = old_state->normalized_zpos; struct sun8i_mixer *mixer = layer->mixer; if (!plane->state->visible) { sun8i_ui_layer_enable(mixer, layer->channel, - layer->overlay, false, 0); + layer->overlay, false, 0, old_zpos); return; } @@ -267,7 +283,7 @@ static void sun8i_ui_layer_atomic_update(struct drm_plane *plane, sun8i_ui_layer_update_buffer(mixer, layer->channel, layer->overlay, plane); sun8i_ui_layer_enable(mixer, layer->channel, layer->overlay, - true, zpos); + true, zpos, old_zpos); } static struct drm_plane_helper_funcs sun8i_ui_layer_helper_funcs = { diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c index 17e0d00cfd8a4..f4fe97813f943 100644 --- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c +++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c @@ -21,7 +21,8 @@ #include "sun8i_vi_scaler.h" static void sun8i_vi_layer_enable(struct sun8i_mixer *mixer, int channel, - int overlay, bool enable, unsigned int zpos) + int overlay, bool enable, unsigned int zpos, + unsigned int old_zpos) { u32 val; @@ -37,6 +38,18 @@ static void sun8i_vi_layer_enable(struct sun8i_mixer *mixer, int channel, SUN8I_MIXER_CHAN_VI_LAYER_ATTR(channel, overlay), SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN, val); + if (!enable || zpos != old_zpos) { + regmap_update_bits(mixer->engine.regs, + SUN8I_MIXER_BLEND_PIPE_CTL, + SUN8I_MIXER_BLEND_PIPE_CTL_EN(old_zpos), + 0); + + regmap_update_bits(mixer->engine.regs, + SUN8I_MIXER_BLEND_ROUTE, + SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(old_zpos), + 0); + } + if (enable) { val = SUN8I_MIXER_BLEND_PIPE_CTL_EN(zpos); @@ -270,9 +283,11 @@ static void sun8i_vi_layer_atomic_disable(struct drm_plane *plane, struct drm_plane_state *old_state) { struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane); + unsigned int old_zpos = old_state->normalized_zpos; struct sun8i_mixer *mixer = layer->mixer; - sun8i_vi_layer_enable(mixer, layer->channel, layer->overlay, false, 0); + sun8i_vi_layer_enable(mixer, layer->channel, layer->overlay, false, 0, + old_zpos); } static void sun8i_vi_layer_atomic_update(struct drm_plane *plane, @@ -280,11 +295,12 @@ static void sun8i_vi_layer_atomic_update(struct drm_plane *plane, { struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane); unsigned int zpos = plane->state->normalized_zpos; + unsigned int old_zpos = old_state->normalized_zpos; struct sun8i_mixer *mixer = layer->mixer; if (!plane->state->visible) { sun8i_vi_layer_enable(mixer, layer->channel, - layer->overlay, false, 0); + layer->overlay, false, 0, old_zpos); return; } @@ -295,7 +311,7 @@ static void sun8i_vi_layer_atomic_update(struct drm_plane *plane, sun8i_vi_layer_update_buffer(mixer, layer->channel, layer->overlay, plane); sun8i_vi_layer_enable(mixer, layer->channel, layer->overlay, - true, zpos); + true, zpos, old_zpos); } static struct drm_plane_helper_funcs sun8i_vi_layer_helper_funcs = { -- GitLab From a8bd3b884dd79dcc9a89dedd0e24b7554de4fe79 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Tue, 17 Jul 2018 10:26:55 +0100 Subject: [PATCH 1236/1506] drm/i915: Flush chipset caches after GGTT writes Our I915g (early gen3, the oldest machine we have in the farm) is still reporting occasional incoherency performing the following operations: 1) write through GGTT (indirect write into memory) 2) write through either CPU or WC (direct write into memory) 3) read from GGTT (indirect read) Instead of reporting the value from (2), the read from GGTT reports the earlier value written via the GGTT. We have made sure that the writes are flushed from the CPU (commit 3a32497f0dbe ("drm/i915/selftests: Provide full mb() around clflush") and commit add00e6d896f ("drm/i915: Flush the WCB following a WC write")), but still see the error, just less frequently. The only remaining cache that might be affected here is a chipset cache, so flush that as well. Testcase: igt/drv_selftest/live_coherency #gdg Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180717092655.28417-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 42d24410a98c6..08266791801e0 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -802,7 +802,7 @@ void i915_gem_flush_ggtt_writes(struct drm_i915_private *dev_priv) * that was!). */ - wmb(); + i915_gem_chipset_flush(dev_priv); intel_runtime_pm_get(dev_priv); spin_lock_irq(&dev_priv->uncore.lock); -- GitLab From a708edf13fb0b55d29a003b00251bccbfec74b20 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann <tzimmermann@suse.de> Date: Tue, 17 Jul 2018 10:54:28 +0200 Subject: [PATCH 1237/1506] drm/vc4: 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 <tzimmermann@suse.de> Signed-off-by: Eric Anholt <eric@anholt.net> Link: https://patchwork.freedesktop.org/patch/msgid/20180717085428.18500-1-tzimmermann@suse.de --- drivers/gpu/drm/vc4/vc4_drv.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c index e42fd5ec41cc9..04270a14fcaaf 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.c +++ b/drivers/gpu/drm/vc4/vc4_drv.c @@ -288,7 +288,7 @@ static int vc4_drm_bind(struct device *dev) ret = vc4_bo_cache_init(drm); if (ret) - goto dev_unref; + goto dev_put; drm_mode_config_init(drm); @@ -313,8 +313,8 @@ static int vc4_drm_bind(struct device *dev) gem_destroy: vc4_gem_destroy(drm); vc4_bo_cache_destroy(drm); -dev_unref: - drm_dev_unref(drm); +dev_put: + drm_dev_put(drm); return ret; } @@ -331,7 +331,7 @@ static void vc4_drm_unbind(struct device *dev) drm_atomic_private_obj_fini(&vc4->ctm_manager); - drm_dev_unref(drm); + drm_dev_put(drm); } static const struct component_master_ops vc4_drm_ops = { -- GitLab From f9760772d26560ec137fb1c768487c601b93dbc3 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann <tzimmermann@suse.de> Date: Tue, 17 Jul 2018 10:36:57 +0200 Subject: [PATCH 1238/1506] drm/pl111: 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 <tzimmermann@suse.de> Signed-off-by: Eric Anholt <eric@anholt.net> Link: https://patchwork.freedesktop.org/patch/msgid/20180717083657.16262-1-tzimmermann@suse.de --- drivers/gpu/drm/pl111/pl111_drv.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/pl111/pl111_drv.c b/drivers/gpu/drm/pl111/pl111_drv.c index 17a38e85ba7dd..47fe302234442 100644 --- a/drivers/gpu/drm/pl111/pl111_drv.c +++ b/drivers/gpu/drm/pl111/pl111_drv.c @@ -304,13 +304,14 @@ static int pl111_amba_probe(struct amba_device *amba_dev, if (IS_ERR(priv->regs)) { dev_err(dev, "%s failed mmio\n", __func__); ret = PTR_ERR(priv->regs); - goto dev_unref; + goto dev_put; } /* This may override some variant settings */ ret = pl111_versatile_init(dev, priv); if (ret) - goto dev_unref; + goto dev_put; + pl111_nomadik_init(dev); /* turn off interrupts before requesting the irq */ @@ -325,16 +326,16 @@ static int pl111_amba_probe(struct amba_device *amba_dev, ret = pl111_modeset_init(drm); if (ret != 0) - goto dev_unref; + goto dev_put; ret = drm_dev_register(drm, 0); if (ret < 0) - goto dev_unref; + goto dev_put; return 0; -dev_unref: - drm_dev_unref(drm); +dev_put: + drm_dev_put(drm); of_reserved_mem_device_release(dev); return ret; @@ -351,7 +352,7 @@ static int pl111_amba_remove(struct amba_device *amba_dev) if (priv->panel) drm_panel_bridge_remove(priv->bridge); drm_mode_config_cleanup(drm); - drm_dev_unref(drm); + drm_dev_put(drm); of_reserved_mem_device_release(dev); return 0; -- GitLab From 108019a7e6a34df91246365066bea7cf6faf6b02 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" <gustavo@embeddedor.com> Date: Wed, 4 Jul 2018 09:22:55 -0500 Subject: [PATCH 1239/1506] drm/pl111: Use 64-bit arithmetic instead of 32-bit Add suffix ULL to constant 1000 in order to give the compiler complete information about the proper arithmetic to use. Notice that such constant is used in a context that expects an expression of type u64 (64 bits, unsigned) and the following expression is currently being evaluated using 32-bit arithmetic: mode->clock * 1000 Addresses-Coverity-ID: 1466139 ("Unintentional integer overflow") Signed-off-by: Gustavo A. R. Silva <gustavo@embeddedor.com> Signed-off-by: Eric Anholt <eric@anholt.net> Link: https://patchwork.freedesktop.org/patch/msgid/20180704142255.GA8614@embeddedor.com --- drivers/gpu/drm/pl111/pl111_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/pl111/pl111_display.c b/drivers/gpu/drm/pl111/pl111_display.c index a432eb7ad4454..754f6b25f2652 100644 --- a/drivers/gpu/drm/pl111/pl111_display.c +++ b/drivers/gpu/drm/pl111/pl111_display.c @@ -63,7 +63,7 @@ pl111_mode_valid(struct drm_crtc *crtc, * We use the pixelclock to also account for interlaced modes, the * resulting bandwidth is in bytes per second. */ - bw = mode->clock * 1000; /* In Hz */ + bw = mode->clock * 1000ULL; /* In Hz */ bw = bw * mode->hdisplay * mode->vdisplay * cpp; bw = div_u64(bw, mode->htotal * mode->vtotal); -- GitLab From a1917b73d89e88a6ecdd076b9d6618682f1b0d08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Fri, 13 Jul 2018 17:15:54 +0200 Subject: [PATCH 1240/1506] drm/amdgpu: remove job->adev (v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can get that from the ring. v2: squash in "drm/amdgpu: always initialize job->base.sched" (Alex) Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Junwei Zhang <Jerry.Zhang@amd.com> Acked-by: Chunming Zhou <david1.zhou@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_job.c | 18 +++++++++++------- drivers/gpu/drm/amd/amdgpu/amdgpu_job.h | 1 - 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c index 0e2b18ccdf2e3..9b1c54ace5834 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c @@ -37,7 +37,7 @@ static void amdgpu_job_timedout(struct drm_sched_job *s_job) job->base.sched->name, atomic_read(&ring->fence_drv.last_seq), ring->fence_drv.sync_seq); - amdgpu_device_gpu_recover(job->adev, job, false); + amdgpu_device_gpu_recover(ring->adev, job, false); } int amdgpu_job_alloc(struct amdgpu_device *adev, unsigned num_ibs, @@ -54,7 +54,11 @@ int amdgpu_job_alloc(struct amdgpu_device *adev, unsigned num_ibs, if (!*job) return -ENOMEM; - (*job)->adev = adev; + /* + * Initialize the scheduler to at least some ring so that we always + * have a pointer to adev. + */ + (*job)->base.sched = &adev->rings[0]->sched; (*job)->vm = vm; (*job)->ibs = (void *)&(*job)[1]; (*job)->num_ibs = num_ibs; @@ -86,6 +90,7 @@ int amdgpu_job_alloc_with_ib(struct amdgpu_device *adev, unsigned size, void amdgpu_job_free_resources(struct amdgpu_job *job) { + struct amdgpu_ring *ring = to_amdgpu_ring(job->base.sched); struct dma_fence *f; unsigned i; @@ -93,7 +98,7 @@ void amdgpu_job_free_resources(struct amdgpu_job *job) f = job->base.s_fence ? &job->base.s_fence->finished : job->fence; for (i = 0; i < job->num_ibs; ++i) - amdgpu_ib_free(job->adev, &job->ibs[i], f); + amdgpu_ib_free(ring->adev, &job->ibs[i], f); } static void amdgpu_job_free_cb(struct drm_sched_job *s_job) @@ -167,7 +172,8 @@ static struct dma_fence *amdgpu_job_dependency(struct drm_sched_job *sched_job, if (fence && explicit) { if (drm_sched_dependency_optimized(fence, s_entity)) { - r = amdgpu_sync_fence(job->adev, &job->sched_sync, fence, false); + r = amdgpu_sync_fence(ring->adev, &job->sched_sync, + fence, false); if (r) DRM_ERROR("Error adding fence to sync (%d)\n", r); } @@ -190,7 +196,6 @@ static struct dma_fence *amdgpu_job_run(struct drm_sched_job *sched_job) { struct amdgpu_ring *ring = to_amdgpu_ring(sched_job->sched); struct dma_fence *fence = NULL, *finished; - struct amdgpu_device *adev; struct amdgpu_job *job; int r; @@ -200,13 +205,12 @@ static struct dma_fence *amdgpu_job_run(struct drm_sched_job *sched_job) } job = to_amdgpu_job(sched_job); finished = &job->base.s_fence->finished; - adev = job->adev; BUG_ON(amdgpu_sync_peek_fence(&job->sync, NULL)); trace_amdgpu_sched_run_job(job); - if (job->vram_lost_counter != atomic_read(&adev->vram_lost_counter)) + if (job->vram_lost_counter != atomic_read(&ring->adev->vram_lost_counter)) dma_fence_set_error(finished, -ECANCELED);/* skip IB as well if VRAM lost */ if (finished->error < 0) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h index d77fd232f7ce3..57cfe78a262b1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h @@ -37,7 +37,6 @@ struct amdgpu_fence; struct amdgpu_job { struct drm_sched_job base; - struct amdgpu_device *adev; struct amdgpu_vm *vm; struct amdgpu_sync sync; struct amdgpu_sync sched_sync; -- GitLab From f024e88343f712941f250f53ddb2652538ea7e95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Fri, 13 Jul 2018 14:01:08 +0200 Subject: [PATCH 1241/1506] drm/amdgpu: minor cleanup in amdgpu_job.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove superflous NULL check, fix coding style a bit, shorten error messages. Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Junwei Zhang <Jerry.Zhang@amd.com> Acked-by: Chunming Zhou <david1.zhou@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_job.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c index 9b1c54ace5834..42a4764d728e8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c @@ -33,7 +33,7 @@ static void amdgpu_job_timedout(struct drm_sched_job *s_job) struct amdgpu_ring *ring = to_amdgpu_ring(s_job->sched); struct amdgpu_job *job = to_amdgpu_job(s_job); - DRM_ERROR("ring %s timeout, last signaled seq=%u, last emitted seq=%u\n", + DRM_ERROR("ring %s timeout, signaled seq=%u, emitted seq=%u\n", job->base.sched->name, atomic_read(&ring->fence_drv.last_seq), ring->fence_drv.sync_seq); @@ -166,16 +166,17 @@ static struct dma_fence *amdgpu_job_dependency(struct drm_sched_job *sched_job, struct amdgpu_ring *ring = to_amdgpu_ring(s_entity->sched); struct amdgpu_job *job = to_amdgpu_job(sched_job); struct amdgpu_vm *vm = job->vm; + struct dma_fence *fence; bool explicit = false; int r; - struct dma_fence *fence = amdgpu_sync_get_fence(&job->sync, &explicit); + fence = amdgpu_sync_get_fence(&job->sync, &explicit); if (fence && explicit) { if (drm_sched_dependency_optimized(fence, s_entity)) { r = amdgpu_sync_fence(ring->adev, &job->sched_sync, fence, false); if (r) - DRM_ERROR("Error adding fence to sync (%d)\n", r); + DRM_ERROR("Error adding fence (%d)\n", r); } } @@ -199,10 +200,6 @@ static struct dma_fence *amdgpu_job_run(struct drm_sched_job *sched_job) struct amdgpu_job *job; int r; - if (!sched_job) { - DRM_ERROR("job is null\n"); - return NULL; - } job = to_amdgpu_job(sched_job); finished = &job->base.s_fence->finished; -- GitLab From 01f8f33e9986aed42a0366704f715cf30e7cb41c Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Tue, 17 Jul 2018 09:41:21 +0100 Subject: [PATCH 1242/1506] drm/i915: Always retire residual requests before suspend If the driver is wedged, we skip idling the GPU. However, we may still have a few requests still not retired following the wedging (since they will be waiting for a background worker trying to acquire struct_mutex). As we hold the struct_mutex, always do a quick request retirement in order to flush the wedged path. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=107257 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180717084121.28185-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_gem.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 08266791801e0..fcc73a6ab503e 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5074,6 +5074,8 @@ int i915_gem_suspend(struct drm_i915_private *i915) assert_kernel_context_is_current(i915); } + i915_retire_requests(i915); /* ensure we flush after wedging */ + mutex_unlock(&i915->drm.struct_mutex); intel_uc_suspend(i915); -- GitLab From ce2d54619a10780a0d354e10d4c83ae4fad46f41 Mon Sep 17 00:00:00 2001 From: Ayan Kumar Halder <ayan.halder@arm.com> Date: Tue, 17 Jul 2018 18:13:42 +0100 Subject: [PATCH 1243/1506] drm/fourcc: Add is_yuv field to drm_format_info to denote if the format is yuv A lot of drivers duplicate the function to check if a format is yuv or not. If we add a field (to denote whether the format is yuv or not) in the drm_format_info table, all the drivers can use this field and it will prevent duplication of similar logic. Signed-off-by: Ayan Kumar halder <ayan.halder@arm.com> Reviewed-by: Ville Syrjala <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/1531847626-22248-1-git-send-email-ayan.halder@arm.com --- drivers/gpu/drm/drm_fourcc.c | 42 ++++++++++++++++++------------------ include/drm/drm_fourcc.h | 2 ++ 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c index 5ca6395cd4d39..35c1e2742c277 100644 --- a/drivers/gpu/drm/drm_fourcc.c +++ b/drivers/gpu/drm/drm_fourcc.c @@ -152,27 +152,27 @@ const struct drm_format_info *__drm_format_info(u32 format) { .format = DRM_FORMAT_XBGR8888_A8, .depth = 32, .num_planes = 2, .cpp = { 4, 1, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true }, { .format = DRM_FORMAT_RGBX8888_A8, .depth = 32, .num_planes = 2, .cpp = { 4, 1, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true }, { .format = DRM_FORMAT_BGRX8888_A8, .depth = 32, .num_planes = 2, .cpp = { 4, 1, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true }, - { .format = DRM_FORMAT_YUV410, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 4 }, - { .format = DRM_FORMAT_YVU410, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 4 }, - { .format = DRM_FORMAT_YUV411, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 1 }, - { .format = DRM_FORMAT_YVU411, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 1 }, - { .format = DRM_FORMAT_YUV420, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 2, .vsub = 2 }, - { .format = DRM_FORMAT_YVU420, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 2, .vsub = 2 }, - { .format = DRM_FORMAT_YUV422, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 2, .vsub = 1 }, - { .format = DRM_FORMAT_YVU422, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 2, .vsub = 1 }, - { .format = DRM_FORMAT_YUV444, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 1, .vsub = 1 }, - { .format = DRM_FORMAT_YVU444, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 1, .vsub = 1 }, - { .format = DRM_FORMAT_NV12, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 2 }, - { .format = DRM_FORMAT_NV21, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 2 }, - { .format = DRM_FORMAT_NV16, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 1 }, - { .format = DRM_FORMAT_NV61, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 1 }, - { .format = DRM_FORMAT_NV24, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 1, .vsub = 1 }, - { .format = DRM_FORMAT_NV42, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 1, .vsub = 1 }, - { .format = DRM_FORMAT_YUYV, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1 }, - { .format = DRM_FORMAT_YVYU, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1 }, - { .format = DRM_FORMAT_UYVY, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1 }, - { .format = DRM_FORMAT_VYUY, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1 }, - { .format = DRM_FORMAT_AYUV, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true }, + { .format = DRM_FORMAT_YUV410, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 4, .is_yuv = true }, + { .format = DRM_FORMAT_YVU410, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 4, .is_yuv = true }, + { .format = DRM_FORMAT_YUV411, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 1, .is_yuv = true }, + { .format = DRM_FORMAT_YVU411, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 1, .is_yuv = true }, + { .format = DRM_FORMAT_YUV420, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 2, .vsub = 2, .is_yuv = true }, + { .format = DRM_FORMAT_YVU420, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 2, .vsub = 2, .is_yuv = true }, + { .format = DRM_FORMAT_YUV422, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 2, .vsub = 1, .is_yuv = true }, + { .format = DRM_FORMAT_YVU422, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 2, .vsub = 1, .is_yuv = true }, + { .format = DRM_FORMAT_YUV444, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 1, .vsub = 1, .is_yuv = true }, + { .format = DRM_FORMAT_YVU444, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 1, .vsub = 1, .is_yuv = true }, + { .format = DRM_FORMAT_NV12, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 2, .is_yuv = true }, + { .format = DRM_FORMAT_NV21, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 2, .is_yuv = true }, + { .format = DRM_FORMAT_NV16, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true }, + { .format = DRM_FORMAT_NV61, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true }, + { .format = DRM_FORMAT_NV24, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 1, .vsub = 1, .is_yuv = true }, + { .format = DRM_FORMAT_NV42, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 1, .vsub = 1, .is_yuv = true }, + { .format = DRM_FORMAT_YUYV, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true }, + { .format = DRM_FORMAT_YVYU, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true }, + { .format = DRM_FORMAT_UYVY, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true }, + { .format = DRM_FORMAT_VYUY, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true }, + { .format = DRM_FORMAT_AYUV, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true, .is_yuv = true }, }; unsigned int i; diff --git a/include/drm/drm_fourcc.h b/include/drm/drm_fourcc.h index 3e86408dac9f5..f9c15845f465b 100644 --- a/include/drm/drm_fourcc.h +++ b/include/drm/drm_fourcc.h @@ -39,6 +39,7 @@ struct drm_mode_fb_cmd2; * @hsub: Horizontal chroma subsampling factor * @vsub: Vertical chroma subsampling factor * @has_alpha: Does the format embeds an alpha component? + * @is_yuv: Is it a YUV format? */ struct drm_format_info { u32 format; @@ -48,6 +49,7 @@ struct drm_format_info { u8 hsub; u8 vsub; bool has_alpha; + bool is_yuv; }; /** -- GitLab From 9bace65934e74d47e467c44765e6a202c302fe7a Mon Sep 17 00:00:00 2001 From: Ayan Kumar Halder <ayan.halder@arm.com> Date: Tue, 17 Jul 2018 18:13:43 +0100 Subject: [PATCH 1244/1506] drm/i915: Substitute intel_format_is_yuv() with format->is_yuv drm_format_info table has a field 'is_yuv' to denote if the format is yuv or not. The driver is expected to use this instead of having a function for the same purpose. Signed-off-by: Ayan Kumar halder <ayan.halder@arm.com> Reviewed-by: Ville Syrjala <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/1531847626-22248-2-git-send-email-ayan.halder@arm.com --- drivers/gpu/drm/i915/intel_display.c | 2 +- drivers/gpu/drm/i915/intel_drv.h | 2 -- drivers/gpu/drm/i915/intel_sprite.c | 20 +++----------------- 3 files changed, 4 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index fbe5a6572d7d2..cf0901240bd1b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3657,7 +3657,7 @@ u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state, plane_color_ctl |= PLANE_COLOR_PLANE_GAMMA_DISABLE; plane_color_ctl |= glk_plane_color_ctl_alpha(fb->format->format); - if (intel_format_is_yuv(fb->format->format)) { + if (fb->format->is_yuv) { if (plane_state->base.color_encoding == DRM_COLOR_YCBCR_BT709) plane_color_ctl |= PLANE_COLOR_CSC_MODE_YUV709_TO_RGB709; else diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 0c3ac0eafde09..64111ead49977 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -2069,7 +2069,6 @@ bool intel_sdvo_init(struct drm_i915_private *dev_priv, /* intel_sprite.c */ -bool intel_format_is_yuv(u32 format); int intel_usecs_to_scanlines(const struct drm_display_mode *adjusted_mode, int usecs); struct intel_plane *intel_sprite_plane_create(struct drm_i915_private *dev_priv, @@ -2085,7 +2084,6 @@ void skl_disable_plane(struct intel_plane *plane, struct intel_crtc *crtc); bool skl_plane_get_hw_state(struct intel_plane *plane, enum pipe *pipe); bool skl_plane_has_ccs(struct drm_i915_private *dev_priv, enum pipe pipe, enum plane_id plane_id); -bool intel_format_is_yuv(uint32_t format); bool skl_plane_has_planar(struct drm_i915_private *dev_priv, enum pipe pipe, enum plane_id plane_id); diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 344c0e709b19a..1bb7bc3f84feb 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -41,20 +41,6 @@ #include <drm/i915_drm.h> #include "i915_drv.h" -bool intel_format_is_yuv(u32 format) -{ - switch (format) { - case DRM_FORMAT_YUYV: - case DRM_FORMAT_UYVY: - case DRM_FORMAT_VYUY: - case DRM_FORMAT_YVYU: - case DRM_FORMAT_NV12: - return true; - default: - return false; - } -} - int intel_usecs_to_scanlines(const struct drm_display_mode *adjusted_mode, int usecs) { @@ -404,7 +390,7 @@ chv_update_csc(const struct intel_plane_state *plane_state) const s16 *csc = csc_matrix[plane_state->base.color_encoding]; /* Seems RGB data bypasses the CSC always */ - if (!intel_format_is_yuv(fb->format->format)) + if (!fb->format->is_yuv) return; I915_WRITE_FW(SPCSCYGOFF(plane_id), SPCSC_OOFF(0) | SPCSC_IOFF(0)); @@ -439,7 +425,7 @@ vlv_update_clrc(const struct intel_plane_state *plane_state) enum plane_id plane_id = plane->id; int contrast, brightness, sh_scale, sh_sin, sh_cos; - if (intel_format_is_yuv(fb->format->format) && + if (fb->format->is_yuv && plane_state->base.color_range == DRM_COLOR_YCBCR_LIMITED_RANGE) { /* * Expand limited range to full range: @@ -1040,7 +1026,7 @@ intel_check_sprite_plane(struct intel_plane *plane, src->y1 = src_y << 16; src->y2 = (src_y + src_h) << 16; - if (intel_format_is_yuv(fb->format->format) && + if (fb->format->is_yuv && fb->format->format != DRM_FORMAT_NV12 && (src_x % 2 || src_w % 2)) { DRM_DEBUG_KMS("src x/w (%u, %u) must be a multiple of 2 for YUV planes\n", -- GitLab From d8bd23d9936bea7184a2bce1242ea646f4906d7d Mon Sep 17 00:00:00 2001 From: Ayan Kumar Halder <ayan.halder@arm.com> Date: Tue, 17 Jul 2018 18:13:44 +0100 Subject: [PATCH 1245/1506] drm/rockchip: Substitute is_yuv_support() with format->is_yuv drm_format_info table has a field 'is_yuv' to denote if the format is yuv or not. The driver is expected to use this instead of having a function for the same purpose. Signed-off-by: Ayan Kumar halder <ayan.halder@arm.com> Reviewed-by: Ville Syrjala <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/1531847626-22248-3-git-send-email-ayan.halder@arm.com --- drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 24 ++++++++------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index effecbed2d11c..1359e5c773e4f 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -243,18 +243,6 @@ static enum vop_data_format vop_convert_format(uint32_t format) } } -static bool is_yuv_support(uint32_t format) -{ - switch (format) { - case DRM_FORMAT_NV12: - case DRM_FORMAT_NV16: - case DRM_FORMAT_NV24: - return true; - default: - return false; - } -} - static uint16_t scl_vop_cal_scale(enum scale_mode mode, uint32_t src, uint32_t dst, bool is_horizontal, int vsu_mode, int *vskiplines) @@ -298,7 +286,8 @@ static void scl_vop_cal_scl_fac(struct vop *vop, const struct vop_win_data *win, uint16_t cbcr_ver_scl_mode = SCALE_NONE; int hsub = drm_format_horz_chroma_subsampling(pixel_format); int vsub = drm_format_vert_chroma_subsampling(pixel_format); - bool is_yuv = is_yuv_support(pixel_format); + const struct drm_format_info *info; + bool is_yuv = false; uint16_t cbcr_src_w = src_w / hsub; uint16_t cbcr_src_h = src_h / vsub; uint16_t vsu_mode; @@ -306,6 +295,11 @@ static void scl_vop_cal_scl_fac(struct vop *vop, const struct vop_win_data *win, uint32_t val; int vskiplines; + info = drm_format_info(pixel_format); + + if (info->is_yuv) + is_yuv = true; + if (dst_w > 3840) { DRM_DEV_ERROR(vop->dev, "Maximum dst width (3840) exceeded\n"); return; @@ -680,7 +674,7 @@ static int vop_plane_atomic_check(struct drm_plane *plane, * Src.x1 can be odd when do clip, but yuv plane start point * need align with 2 pixel. */ - if (is_yuv_support(fb->format->format) && ((state->src.x1 >> 16) % 2)) { + if (fb->format->is_yuv && ((state->src.x1 >> 16) % 2)) { DRM_ERROR("Invalid Source: Yuv format not support odd xpos\n"); return -EINVAL; } @@ -767,7 +761,7 @@ static void vop_plane_atomic_update(struct drm_plane *plane, VOP_WIN_SET(vop, win, format, format); VOP_WIN_SET(vop, win, yrgb_vir, DIV_ROUND_UP(fb->pitches[0], 4)); VOP_WIN_SET(vop, win, yrgb_mst, dma_addr); - if (is_yuv_support(fb->format->format)) { + if (fb->format->is_yuv) { int hsub = drm_format_horz_chroma_subsampling(fb->format->format); int vsub = drm_format_vert_chroma_subsampling(fb->format->format); int bpp = fb->format->cpp[1]; -- GitLab From 979c11ef39cee79d6f556091a357890962be2580 Mon Sep 17 00:00:00 2001 From: Ayan Kumar Halder <ayan.halder@arm.com> Date: Tue, 17 Jul 2018 18:13:46 +0100 Subject: [PATCH 1246/1506] drm/sun4i: Substitute sun4i_backend_format_is_yuv() with format->is_yuv drm_format_info table has a field 'is_yuv' to denote if the format is yuv or not. The driver is expected to use this instead of having a function for the same purpose. Signed-off-by: Ayan Kumar halder <ayan.halder@arm.com> Reviewed-by: Ville Syrjala <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/1531847626-22248-5-git-send-email-ayan.halder@arm.com --- drivers/gpu/drm/sun4i/sun4i_backend.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c index de0a76dfa1a26..d7950b52a1fd9 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.c +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c @@ -86,12 +86,6 @@ static inline bool sun4i_backend_format_is_packed_yuv422(uint32_t format) } } -static inline bool sun4i_backend_format_is_yuv(uint32_t format) -{ - return sun4i_backend_format_is_planar_yuv(format) || - sun4i_backend_format_is_packed_yuv422(format); -} - static void sun4i_backend_apply_color_correction(struct sunxi_engine *engine) { int i; @@ -304,7 +298,7 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend, SUN4I_BACKEND_ATTCTL_REG0_LAY_GLBALPHA_EN, val); - if (sun4i_backend_format_is_yuv(fb->format->format)) + if (fb->format->is_yuv) return sun4i_backend_update_yuv_format(backend, layer, plane); ret = sun4i_backend_drm_format_to_layer(fb->format->format, &val); @@ -384,7 +378,7 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend, */ paddr -= PHYS_OFFSET; - if (sun4i_backend_format_is_yuv(fb->format->format)) + if (fb->format->is_yuv) return sun4i_backend_update_yuv_buffer(backend, fb, paddr); /* Write the 32 lower bits of the address (in bits) */ @@ -502,7 +496,7 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine, if (fb->format->has_alpha || (plane_state->alpha != DRM_BLEND_ALPHA_OPAQUE)) num_alpha_planes++; - if (sun4i_backend_format_is_yuv(fb->format->format)) { + if (fb->format->is_yuv) { DRM_DEBUG_DRIVER("Plane FB format is YUV\n"); num_yuv_planes++; } -- GitLab From 5fd9df6ac6eec9d6c7feaf114690bbeac7f13168 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi <rodrigo.vivi@intel.com> Date: Thu, 5 Jul 2018 12:25:28 -0700 Subject: [PATCH 1247/1506] drm/i915: Kill sink_crc for good It was originally introduced following the VESA spec in order to validate PSR. However we found so many issues around sink_crc that instead of helping PSR development it only brought another layer of trouble to the table. So, sink_crc has been a black whole for us in question of time, effort and hope. First of the problems is that HW statement is clear: "Do not attempt to use aux communication with PSR enabled". So the main reason behind sink_crc is already compromised. For a while we had hope on the aux-mutex could workaround this problem on SKL+ platforms, but that mutex was not reliable, not tested, and we shouldn't use according to HW engineers. Also, nor source, nor sink designed and implemented the sink_crc to be used like we are trying to use here. Well, the sink side of things is also apparently not prepared for this case. Each panel that we tried seemed to have a different behavior with same code and same source. So, for all the time we lost on trying to ducktape all these different issues I believe it is now time to move PSR to a more reliable validation. Maybe not a perfect one as we dreamed for this sink_crc, but at least more reliable. Cc: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Reviewed-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180705192528.30515-1-rodrigo.vivi@intel.com --- drivers/gpu/drm/i915/i915_debugfs.c | 81 ------------------ drivers/gpu/drm/i915/intel_dp.c | 123 ---------------------------- drivers/gpu/drm/i915/intel_drv.h | 2 - 3 files changed, 206 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 54509e44a8567..b3aefd6235570 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2767,86 +2767,6 @@ DEFINE_SIMPLE_ATTRIBUTE(i915_edp_psr_debug_fops, i915_edp_psr_debug_get, i915_edp_psr_debug_set, "%llu\n"); -static int i915_sink_crc(struct seq_file *m, void *data) -{ - struct drm_i915_private *dev_priv = node_to_i915(m->private); - struct drm_device *dev = &dev_priv->drm; - struct intel_connector *connector; - struct drm_connector_list_iter conn_iter; - struct intel_dp *intel_dp = NULL; - struct drm_modeset_acquire_ctx ctx; - int ret; - u8 crc[6]; - - drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE); - - drm_connector_list_iter_begin(dev, &conn_iter); - - for_each_intel_connector_iter(connector, &conn_iter) { - struct drm_crtc *crtc; - struct drm_connector_state *state; - struct intel_crtc_state *crtc_state; - - if (connector->base.connector_type != DRM_MODE_CONNECTOR_eDP) - continue; - -retry: - ret = drm_modeset_lock(&dev->mode_config.connection_mutex, &ctx); - if (ret) - goto err; - - state = connector->base.state; - if (!state->best_encoder) - continue; - - crtc = state->crtc; - ret = drm_modeset_lock(&crtc->mutex, &ctx); - if (ret) - goto err; - - crtc_state = to_intel_crtc_state(crtc->state); - if (!crtc_state->base.active) - continue; - - /* - * We need to wait for all crtc updates to complete, to make - * sure any pending modesets and plane updates are completed. - */ - if (crtc_state->base.commit) { - ret = wait_for_completion_interruptible(&crtc_state->base.commit->hw_done); - - if (ret) - goto err; - } - - intel_dp = enc_to_intel_dp(state->best_encoder); - - ret = intel_dp_sink_crc(intel_dp, crtc_state, crc); - if (ret) - goto err; - - seq_printf(m, "%02x%02x%02x%02x%02x%02x\n", - crc[0], crc[1], crc[2], - crc[3], crc[4], crc[5]); - goto out; - -err: - if (ret == -EDEADLK) { - ret = drm_modeset_backoff(&ctx); - if (!ret) - goto retry; - } - goto out; - } - ret = -ENODEV; -out: - drm_connector_list_iter_end(&conn_iter); - drm_modeset_drop_locks(&ctx); - drm_modeset_acquire_fini(&ctx); - - return ret; -} - static int i915_energy_uJ(struct seq_file *m, void *data) { struct drm_i915_private *dev_priv = node_to_i915(m->private); @@ -4792,7 +4712,6 @@ static const struct drm_info_list i915_debugfs_list[] = { {"i915_ppgtt_info", i915_ppgtt_info, 0}, {"i915_llc", i915_llc, 0}, {"i915_edp_psr_status", i915_edp_psr_status, 0}, - {"i915_sink_crc_eDP1", i915_sink_crc, 0}, {"i915_energy_uJ", i915_energy_uJ, 0}, {"i915_runtime_pm_status", i915_runtime_pm_status, 0}, {"i915_power_domain_info", i915_power_domain_info, 0}, diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index fc05c82265511..5899cadf11e30 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -3874,129 +3874,6 @@ intel_dp_configure_mst(struct intel_dp *intel_dp) intel_dp->is_mst); } -static int intel_dp_sink_crc_stop(struct intel_dp *intel_dp, - struct intel_crtc_state *crtc_state, bool disable_wa) -{ - struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); - struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); - struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc); - u8 buf; - int ret = 0; - int count = 0; - int attempts = 10; - - if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK, &buf) < 0) { - DRM_DEBUG_KMS("Sink CRC couldn't be stopped properly\n"); - ret = -EIO; - goto out; - } - - if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_SINK, - buf & ~DP_TEST_SINK_START) < 0) { - DRM_DEBUG_KMS("Sink CRC couldn't be stopped properly\n"); - ret = -EIO; - goto out; - } - - do { - intel_wait_for_vblank(dev_priv, intel_crtc->pipe); - - if (drm_dp_dpcd_readb(&intel_dp->aux, - DP_TEST_SINK_MISC, &buf) < 0) { - ret = -EIO; - goto out; - } - count = buf & DP_TEST_COUNT_MASK; - } while (--attempts && count); - - if (attempts == 0) { - DRM_DEBUG_KMS("TIMEOUT: Sink CRC counter is not zeroed after calculation is stopped\n"); - ret = -ETIMEDOUT; - } - - out: - if (disable_wa) - hsw_enable_ips(crtc_state); - return ret; -} - -static int intel_dp_sink_crc_start(struct intel_dp *intel_dp, - struct intel_crtc_state *crtc_state) -{ - struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); - struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); - struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc); - u8 buf; - int ret; - - if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK_MISC, &buf) < 0) - return -EIO; - - if (!(buf & DP_TEST_CRC_SUPPORTED)) - return -ENOTTY; - - if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK, &buf) < 0) - return -EIO; - - if (buf & DP_TEST_SINK_START) { - ret = intel_dp_sink_crc_stop(intel_dp, crtc_state, false); - if (ret) - return ret; - } - - hsw_disable_ips(crtc_state); - - if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_SINK, - buf | DP_TEST_SINK_START) < 0) { - hsw_enable_ips(crtc_state); - return -EIO; - } - - intel_wait_for_vblank(dev_priv, intel_crtc->pipe); - return 0; -} - -int intel_dp_sink_crc(struct intel_dp *intel_dp, struct intel_crtc_state *crtc_state, u8 *crc) -{ - struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); - struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); - struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc); - u8 buf; - int count, ret; - int attempts = 6; - - ret = intel_dp_sink_crc_start(intel_dp, crtc_state); - if (ret) - return ret; - - do { - intel_wait_for_vblank(dev_priv, intel_crtc->pipe); - - if (drm_dp_dpcd_readb(&intel_dp->aux, - DP_TEST_SINK_MISC, &buf) < 0) { - ret = -EIO; - goto stop; - } - count = buf & DP_TEST_COUNT_MASK; - - } while (--attempts && count == 0); - - if (attempts == 0) { - DRM_ERROR("Panel is unable to calculate any CRC after 6 vblanks\n"); - ret = -ETIMEDOUT; - goto stop; - } - - if (drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_CRC_R_CR, crc, 6) < 0) { - ret = -EIO; - goto stop; - } - -stop: - intel_dp_sink_crc_stop(intel_dp, crtc_state, true); - return ret; -} - static bool intel_dp_get_sink_irq(struct intel_dp *intel_dp, u8 *sink_irq_vector) { diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index f8d5fafe1f1a7..92b68ebc7413b 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1682,8 +1682,6 @@ void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode); void intel_dp_encoder_reset(struct drm_encoder *encoder); void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder); void intel_dp_encoder_destroy(struct drm_encoder *encoder); -int intel_dp_sink_crc(struct intel_dp *intel_dp, - struct intel_crtc_state *crtc_state, u8 *crc); bool intel_dp_compute_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, struct drm_connector_state *conn_state); -- GitLab From e6d5752080e2d069643d65b0db10c411f6b45412 Mon Sep 17 00:00:00 2001 From: Feifei Xu <Feifei.Xu@amd.com> Date: Tue, 17 Jul 2018 14:54:23 +0800 Subject: [PATCH 1248/1506] drm/amdgpu/gfx9: Update golden settings for vg10. Add some UTCL registers' golden settings. Signed-off-by: Feifei Xu <Feifei.Xu@amd.com> Tested-by: Kevin Wang <Kevin1.Wang@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index a12da4a66b01c..9ab39117cc4e1 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -104,11 +104,22 @@ static const struct soc15_reg_golden golden_settings_gc_9_0_vg10[] = { SOC15_REG_GOLDEN_VALUE(GC, 0, mmCB_HW_CONTROL, 0x0000f000, 0x00012107), SOC15_REG_GOLDEN_VALUE(GC, 0, mmCB_HW_CONTROL_3, 0x30000000, 0x10000000), + SOC15_REG_GOLDEN_VALUE(GC, 0, mmCPC_UTCL1_CNTL, 0x08000000, 0x08000080), + SOC15_REG_GOLDEN_VALUE(GC, 0, mmCPF_UTCL1_CNTL, 0x08000000, 0x08000080), + SOC15_REG_GOLDEN_VALUE(GC, 0, mmCPG_UTCL1_CNTL, 0x08000000, 0x08000080), SOC15_REG_GOLDEN_VALUE(GC, 0, mmGB_ADDR_CONFIG, 0xffff77ff, 0x2a114042), SOC15_REG_GOLDEN_VALUE(GC, 0, mmGB_ADDR_CONFIG_READ, 0xffff77ff, 0x2a114042), + SOC15_REG_GOLDEN_VALUE(GC, 0, mmIA_UTCL1_CNTL, 0x08000000, 0x08000080), SOC15_REG_GOLDEN_VALUE(GC, 0, mmPA_SC_ENHANCE_1, 0x00008000, 0x00048000), + SOC15_REG_GOLDEN_VALUE(GC, 0, mmRLC_GPM_UTCL1_CNTL_0, 0x08000000, 0x08000080), + SOC15_REG_GOLDEN_VALUE(GC, 0, mmRLC_GPM_UTCL1_CNTL_1, 0x08000000, 0x08000080), + SOC15_REG_GOLDEN_VALUE(GC, 0, mmRLC_GPM_UTCL1_CNTL_2, 0x08000000, 0x08000080), + SOC15_REG_GOLDEN_VALUE(GC, 0, mmRLC_PREWALKER_UTCL1_CNTL, 0x08000000, 0x08000080), + SOC15_REG_GOLDEN_VALUE(GC, 0, mmRLC_SPM_UTCL1_CNTL, 0x08000000, 0x08000080), SOC15_REG_GOLDEN_VALUE(GC, 0, mmRMI_UTCL1_CNTL2, 0x00030000, 0x00020000), - SOC15_REG_GOLDEN_VALUE(GC, 0, mmTD_CNTL, 0x00001800, 0x00000800) + SOC15_REG_GOLDEN_VALUE(GC, 0, mmSPI_CONFIG_CNTL_1, 0x0000000f, 0x01000107), + SOC15_REG_GOLDEN_VALUE(GC, 0, mmTD_CNTL, 0x00001800, 0x00000800), + SOC15_REG_GOLDEN_VALUE(GC, 0, mmWD_UTCL1_CNTL, 0x08000000, 0x08000080) }; static const struct soc15_reg_golden golden_settings_gc_9_0_vg20[] = -- GitLab From 9d46f32bdd3e9d4bf435c5ae50f72fb475bf0620 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Mon, 16 Jul 2018 13:47:34 +0200 Subject: [PATCH 1249/1506] drm/amdgpu: allow for more flexible priority handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow to call amdgpu_ring_priority_get() after pushing the ring to the scheduler. Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Chunming Zhou <david1.zhou@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c index 19e45a3953e07..93794a85f83d8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c @@ -211,7 +211,8 @@ void amdgpu_ring_priority_get(struct amdgpu_ring *ring, if (!ring->funcs->set_priority) return; - atomic_inc(&ring->num_jobs[priority]); + if (atomic_inc_return(&ring->num_jobs[priority]) <= 0) + return; mutex_lock(&ring->priority_mutex); if (priority <= ring->priority) -- GitLab From b5286801705b39e44b824520714d503f882fef1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Mon, 16 Jul 2018 14:58:48 +0200 Subject: [PATCH 1250/1506] drm/amdgpu: change ring priority after pushing the job (v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pushing a job can change the ring assignment of an entity. v2: squash in: "drm/amdgpu: fix job priority handling" (Christian) Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Chunming Zhou <david1.zhou@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 6 +++++- drivers/gpu/drm/amd/amdgpu/amdgpu_job.c | 8 ++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 72dc9b36b937f..7c5cc33d0cda0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -1209,6 +1209,7 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, { struct amdgpu_ring *ring = p->ring; struct drm_sched_entity *entity = &p->ctx->rings[ring->idx].entity; + enum drm_sched_priority priority; struct amdgpu_job *job; unsigned i; uint64_t seq; @@ -1256,11 +1257,14 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, job->uf_sequence = seq; amdgpu_job_free_resources(job); - amdgpu_ring_priority_get(p->ring, job->base.s_priority); trace_amdgpu_cs_ioctl(job); + priority = job->base.s_priority; drm_sched_entity_push_job(&job->base, entity); + ring = to_amdgpu_ring(entity->sched); + amdgpu_ring_priority_get(ring, priority); + ttm_eu_fence_buffer_objects(&p->ticket, &p->validated, p->fence); amdgpu_mn_unlock(p->mn); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c index 42a4764d728e8..5a2c26a859845 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c @@ -126,7 +126,8 @@ void amdgpu_job_free(struct amdgpu_job *job) int amdgpu_job_submit(struct amdgpu_job *job, struct drm_sched_entity *entity, void *owner, struct dma_fence **f) { - struct amdgpu_ring *ring = to_amdgpu_ring(entity->sched); + enum drm_sched_priority priority; + struct amdgpu_ring *ring; int r; if (!f) @@ -139,9 +140,12 @@ int amdgpu_job_submit(struct amdgpu_job *job, struct drm_sched_entity *entity, job->owner = owner; *f = dma_fence_get(&job->base.s_fence->finished); amdgpu_job_free_resources(job); - amdgpu_ring_priority_get(ring, job->base.s_priority); + priority = job->base.s_priority; drm_sched_entity_push_job(&job->base, entity); + ring = to_amdgpu_ring(entity->sched); + amdgpu_ring_priority_get(ring, priority); + return 0; } -- GitLab From f3cdadb6fee9287d81d2dacd830bd5b439cb7331 Mon Sep 17 00:00:00 2001 From: Sonny Jiang <sonny.jiang@amd.com> Date: Tue, 17 Jul 2018 15:27:20 -0400 Subject: [PATCH 1251/1506] drm/amdgpu: remove internal/unused kernel module parameters Remove internal/unused kernel module parameters Signed-off-by: Sonny Jiang <sonny.jiang@amd.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 3 --- drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 12 ------------ 2 files changed, 15 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 90780b0f0ce57..44f62fda40228 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -106,11 +106,8 @@ extern int amdgpu_vm_fault_stop; extern int amdgpu_vm_debug; extern int amdgpu_vm_update_mode; extern int amdgpu_dc; -extern int amdgpu_dc_log; extern int amdgpu_sched_jobs; extern int amdgpu_sched_hw_submission; -extern int amdgpu_no_evict; -extern int amdgpu_direct_gma_size; extern uint amdgpu_pcie_gen_cap; extern uint amdgpu_pcie_lane_cap; extern uint amdgpu_cg_mask; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 529500c94675c..8843a06360fa7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -104,11 +104,8 @@ int amdgpu_vram_page_split = 512; int amdgpu_vm_update_mode = -1; int amdgpu_exp_hw_support = 0; int amdgpu_dc = -1; -int amdgpu_dc_log = 0; int amdgpu_sched_jobs = 32; int amdgpu_sched_hw_submission = 2; -int amdgpu_no_evict = 0; -int amdgpu_direct_gma_size = 0; uint amdgpu_pcie_gen_cap = 0; uint amdgpu_pcie_lane_cap = 0; uint amdgpu_cg_mask = 0xffffffff; @@ -341,9 +338,6 @@ module_param_named(exp_hw_support, amdgpu_exp_hw_support, int, 0444); MODULE_PARM_DESC(dc, "Display Core driver (1 = enable, 0 = disable, -1 = auto (default))"); module_param_named(dc, amdgpu_dc, int, 0444); -MODULE_PARM_DESC(dc_log, "Display Core Log Level (0 = minimal (default), 1 = chatty"); -module_param_named(dc_log, amdgpu_dc_log, int, 0444); - /** * DOC: sched_jobs (int) * Override the max number of jobs supported in the sw queue. The default is 32. @@ -366,12 +360,6 @@ module_param_named(sched_hw_submission, amdgpu_sched_hw_submission, int, 0444); MODULE_PARM_DESC(ppfeaturemask, "all power features enabled (default))"); module_param_named(ppfeaturemask, amdgpu_pp_feature_mask, uint, 0444); -MODULE_PARM_DESC(no_evict, "Support pinning request from user space (1 = enable, 0 = disable (default))"); -module_param_named(no_evict, amdgpu_no_evict, int, 0444); - -MODULE_PARM_DESC(direct_gma_size, "Direct GMA size in megabytes (max 96MB)"); -module_param_named(direct_gma_size, amdgpu_direct_gma_size, int, 0444); - /** * DOC: pcie_gen_cap (uint) * Override PCIE gen speed capabilities. See the CAIL flags in drivers/gpu/drm/amd/include/amd_pcie.h. -- GitLab From 7eb80427746175530f03a00ad5281c4222f17238 Mon Sep 17 00:00:00 2001 From: Huang Rui <ray.huang@amd.com> Date: Wed, 4 Jul 2018 18:08:54 +0800 Subject: [PATCH 1252/1506] drm/amdgpu: simplify the bo reference on amdgpu_bo_update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BO ptr already be initialized at definition, we needn't use the complicated reference. v2: fix typo at subject line Signed-off-by: Huang Rui <ray.huang@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 5d3d783f2d727..098dd1ba751a2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -1646,18 +1646,17 @@ int amdgpu_vm_bo_update(struct amdgpu_device *adev, uint64_t flags; int r; - if (clear || !bo_va->base.bo) { + if (clear || !bo) { mem = NULL; nodes = NULL; exclusive = NULL; } else { struct ttm_dma_tt *ttm; - mem = &bo_va->base.bo->tbo.mem; + mem = &bo->tbo.mem; nodes = mem->mm_node; if (mem->mem_type == TTM_PL_TT) { - ttm = container_of(bo_va->base.bo->tbo.ttm, - struct ttm_dma_tt, ttm); + ttm = container_of(bo->tbo.ttm, struct ttm_dma_tt, ttm); pages_addr = ttm->dma_address; } exclusive = reservation_object_get_excl(bo->tbo.resv); -- GitLab From 4b4bd04898ad8a315b4a8740ff4909ea995f0c65 Mon Sep 17 00:00:00 2001 From: Kees Cook <keescook@chromium.org> Date: Wed, 20 Jun 2018 11:26:47 -0700 Subject: [PATCH 1253/1506] drm/amdgpu/pm: Remove VLA usage In the quest to remove all stack VLA usage from the kernel[1], this uses the maximum sane buffer size and removes copy/paste code. [1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com Reviewed-by: Rex Zhu <rezhu@amd.com> Signed-off-by: Kees Cook <keescook@chromium.org> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | 100 +++++++++++-------------- 1 file changed, 42 insertions(+), 58 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c index f1404adc3a901..15a1192c1ec54 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c @@ -606,40 +606,59 @@ static ssize_t amdgpu_get_pp_dpm_sclk(struct device *dev, return snprintf(buf, PAGE_SIZE, "\n"); } -static ssize_t amdgpu_set_pp_dpm_sclk(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t count) +/* + * Worst case: 32 bits individually specified, in octal at 12 characters + * per line (+1 for \n). + */ +#define AMDGPU_MASK_BUF_MAX (32 * 13) + +static ssize_t amdgpu_read_mask(const char *buf, size_t count, uint32_t *mask) { - struct drm_device *ddev = dev_get_drvdata(dev); - struct amdgpu_device *adev = ddev->dev_private; int ret; long level; - uint32_t mask = 0; char *sub_str = NULL; char *tmp; - char buf_cpy[count]; + char buf_cpy[AMDGPU_MASK_BUF_MAX + 1]; const char delimiter[3] = {' ', '\n', '\0'}; + size_t bytes; - memcpy(buf_cpy, buf, count+1); + *mask = 0; + + bytes = min(count, sizeof(buf_cpy) - 1); + memcpy(buf_cpy, buf, bytes); + buf_cpy[bytes] = '\0'; tmp = buf_cpy; while (tmp[0]) { - sub_str = strsep(&tmp, delimiter); + sub_str = strsep(&tmp, delimiter); if (strlen(sub_str)) { ret = kstrtol(sub_str, 0, &level); - - if (ret) { - count = -EINVAL; - goto fail; - } - mask |= 1 << level; + if (ret) + return -EINVAL; + *mask |= 1 << level; } else break; } + + return 0; +} + +static ssize_t amdgpu_set_pp_dpm_sclk(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = ddev->dev_private; + int ret; + uint32_t mask = 0; + + ret = amdgpu_read_mask(buf, count, &mask); + if (ret) + return ret; + if (adev->powerplay.pp_funcs->force_clock_level) amdgpu_dpm_force_clock_level(adev, PP_SCLK, mask); -fail: return count; } @@ -664,32 +683,15 @@ static ssize_t amdgpu_set_pp_dpm_mclk(struct device *dev, struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = ddev->dev_private; int ret; - long level; uint32_t mask = 0; - char *sub_str = NULL; - char *tmp; - char buf_cpy[count]; - const char delimiter[3] = {' ', '\n', '\0'}; - memcpy(buf_cpy, buf, count+1); - tmp = buf_cpy; - while (tmp[0]) { - sub_str = strsep(&tmp, delimiter); - if (strlen(sub_str)) { - ret = kstrtol(sub_str, 0, &level); + ret = amdgpu_read_mask(buf, count, &mask); + if (ret) + return ret; - if (ret) { - count = -EINVAL; - goto fail; - } - mask |= 1 << level; - } else - break; - } if (adev->powerplay.pp_funcs->force_clock_level) amdgpu_dpm_force_clock_level(adev, PP_MCLK, mask); -fail: return count; } @@ -714,33 +716,15 @@ static ssize_t amdgpu_set_pp_dpm_pcie(struct device *dev, struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = ddev->dev_private; int ret; - long level; uint32_t mask = 0; - char *sub_str = NULL; - char *tmp; - char buf_cpy[count]; - const char delimiter[3] = {' ', '\n', '\0'}; - - memcpy(buf_cpy, buf, count+1); - tmp = buf_cpy; - while (tmp[0]) { - sub_str = strsep(&tmp, delimiter); - if (strlen(sub_str)) { - ret = kstrtol(sub_str, 0, &level); + ret = amdgpu_read_mask(buf, count, &mask); + if (ret) + return ret; - if (ret) { - count = -EINVAL; - goto fail; - } - mask |= 1 << level; - } else - break; - } if (adev->powerplay.pp_funcs->force_clock_level) amdgpu_dpm_force_clock_level(adev, PP_PCIE, mask); -fail: return count; } -- GitLab From 7af2be6d54d4eda52603e87fbb99a8fb989ccdf0 Mon Sep 17 00:00:00 2001 From: Anusha Srivatsa <anusha.srivatsa@intel.com> Date: Tue, 17 Jul 2018 14:10:58 -0700 Subject: [PATCH 1254/1506] drm/i915/icl: Add VIDEO_DIP registers The Picture Parameter Set metadata for DSC has to be sent to the panel through secondary data packets. Add the error correction registers, data registers and control registers for the same. The control registers for transcoders A and B are already defined and will be reused for Icelake purpose. This patch adds Control register for EDP and transcoder C apart from adding the PPS data and error registers. v2: reuse MMIO_TRANS2 for _PPS_DATA and _PPS_ECC. The _MMIO_TRANS2(pipe, reg) macro definition takes care of the eDp case Cc: Jani Nikula <jani.nikula@intel.com> Cc: Ville Syrjala <ville.syrjala@linux.intel.com> Cc: Manasi Navare <manasi.d.navare@intel.com> Signed-off-by: Anusha Srivatsa <anusha.srivatsa@intel.com> Reviewed-by: Manasi Navare <manasi.d.navare@intel.com> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/1531861861-10950-1-git-send-email-anusha.srivatsa@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 1f222af0324da..23e70a40d0cd8 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4605,6 +4605,16 @@ enum { #define VIDEO_DIP_ENABLE_GMP_HSW (1 << 4) #define VIDEO_DIP_ENABLE_SPD_HSW (1 << 0) +#define DRM_DIP_ENABLE (1 << 28) +#define PSR_VSC_BIT_7_SET (1 << 27) +#define VSC_SELECT_MASK (0x3 << 26) +#define VSC_SELECT_SHIFT 26 +#define VSC_DIP_HW_HEA_DATA (0 << 26) +#define VSC_DIP_HW_HEA_SW_DATA (1 << 26) +#define VSC_DIP_HW_DATA_SW_HEA (2 << 26) +#define VSC_DIP_SW_HEA_DATA (3 << 26) +#define VDIP_ENABLE_PPS (1 << 24) + /* Panel power sequencing */ #define PPS_BASE 0x61200 #define VLV_PPS_BASE (VLV_DISPLAY_BASE + PPS_BASE) @@ -7843,12 +7853,25 @@ enum { #define _HSW_VIDEO_DIP_VSC_ECC_B 0x61344 #define _HSW_VIDEO_DIP_GCP_B 0x61210 +/* Icelake PPS_DATA and _ECC DIP Registers. + * These are available for transcoders B,C and eDP. + * Adding the _A so as to reuse the _MMIO_TRANS2 + * definition, with which it offsets to the right location. + */ + +#define _ICL_VIDEO_DIP_PPS_DATA_A 0x60350 +#define _ICL_VIDEO_DIP_PPS_DATA_B 0x61350 +#define _ICL_VIDEO_DIP_PPS_ECC_A 0x603D4 +#define _ICL_VIDEO_DIP_PPS_ECC_B 0x613D4 + #define HSW_TVIDEO_DIP_CTL(trans) _MMIO_TRANS2(trans, _HSW_VIDEO_DIP_CTL_A) #define HSW_TVIDEO_DIP_AVI_DATA(trans, i) _MMIO_TRANS2(trans, _HSW_VIDEO_DIP_AVI_DATA_A + (i) * 4) #define HSW_TVIDEO_DIP_VS_DATA(trans, i) _MMIO_TRANS2(trans, _HSW_VIDEO_DIP_VS_DATA_A + (i) * 4) #define HSW_TVIDEO_DIP_SPD_DATA(trans, i) _MMIO_TRANS2(trans, _HSW_VIDEO_DIP_SPD_DATA_A + (i) * 4) #define HSW_TVIDEO_DIP_GCP(trans) _MMIO_TRANS2(trans, _HSW_VIDEO_DIP_GCP_A) #define HSW_TVIDEO_DIP_VSC_DATA(trans, i) _MMIO_TRANS2(trans, _HSW_VIDEO_DIP_VSC_DATA_A + (i) * 4) +#define ICL_VIDEO_DIP_PPS_DATA(trans, i) _MMIO_TRANS2(trans, _ICL_VIDEO_DIP_PPS_DATA_A + (i) * 4) +#define ICL_VIDEO_DIP_PPS_ECC(trans, i) _MMIO_TRANS2(trans, _ICL_VIDEO_DIP_PPS_ECC_A + (i) * 4) #define _HSW_STEREO_3D_CTL_A 0x70020 #define S3D_ENABLE (1 << 31) -- GitLab From 2efbb2f099fb75d95150bf2f4029b641ecbd1503 Mon Sep 17 00:00:00 2001 From: Anusha Srivatsa <anusha.srivatsa@intel.com> Date: Tue, 17 Jul 2018 14:10:59 -0700 Subject: [PATCH 1255/1506] i915/dp/dsc: Add DSC PPS register definitions Display Stream Compression(DSC) has a set of Picture Parameter Set(PPS) components that the encoder must communicate to the decoder. This patch adds register definitions to the PPS parameters for eDP/MIPI case and Display Port. v2: - Use _MMIO_PIPE instead of _MMIO(_PICK()). (Manasi) - Use DSC constants as arguments. (Manasi) Cc: Lucas De Marchi <lucas.demarchi@intel.com> Cc: Ville Syrjala <ville.syrjala@linux.intel.com> Cc: Manasi Navare <manasi.d.navare@intel.com> Signed-off-by: Anusha Srivatsa <anusha.srivatsa@intel.com> Reviewed-by: Manasi Navare <manasi.d.navare@intel.com> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/1531861861-10950-2-git-send-email-anusha.srivatsa@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 255 ++++++++++++++++++++++++++++++++ 1 file changed, 255 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 23e70a40d0cd8..e8687b0f906d6 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -10244,4 +10244,259 @@ enum skl_power_gate { _ICL_PHY_MISC_B) #define ICL_PHY_MISC_DE_IO_COMP_PWR_DOWN (1 << 23) +/* Icelake Display Stream Compression Registers */ +#define DSCA_PICTURE_PARAMETER_SET_0 0x6B200 +#define DSCC_PICTURE_PARAMETER_SET_0 0x6BA00 +#define _ICL_DSC0_PICTURE_PARAMETER_SET_0_PB 0x78270 +#define _ICL_DSC1_PICTURE_PARAMETER_SET_0_PB 0x78370 +#define _ICL_DSC0_PICTURE_PARAMETER_SET_0_PC 0x78470 +#define _ICL_DSC1_PICTURE_PARAMETER_SET_0_PC 0x78570 +#define ICL_DSC0_PICTURE_PARAMETER_SET_0(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC0_PICTURE_PARAMETER_SET_0_PB, \ + _ICL_DSC0_PICTURE_PARAMETER_SET_0_PC) +#define ICL_DSC1_PICTURE_PARAMETER_SET_0(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC1_PICTURE_PARAMETER_SET_0_PB, \ + _ICL_DSC1_PICTURE_PARAMETER_SET_0_PC) +#define DSC_VBR_ENABLE (1 << 19) +#define DSC_422_ENABLE (1 << 18) +#define DSC_COLOR_SPACE_CONVERSION (1 << 17) +#define DSC_BLOCK_PREDICTION (1 << 16) +#define DSC_LINE_BUF_DEPTH_SHIFT 12 +#define DSC_BPC_SHIFT 8 +#define DSC_VER_MIN_SHIFT 4 +#define DSC_VER_MAJ (0x1 << 0) + +#define DSCA_PICTURE_PARAMETER_SET_1 0x6B204 +#define DSCC_PICTURE_PARAMETER_SET_1 0x6BA04 +#define _ICL_DSC0_PICTURE_PARAMETER_SET_1_PB 0x78274 +#define _ICL_DSC1_PICTURE_PARAMETER_SET_1_PB 0x78374 +#define _ICL_DSC0_PICTURE_PARAMETER_SET_1_PC 0x78474 +#define _ICL_DSC1_PICTURE_PARAMETER_SET_1_PC 0x78574 +#define ICL_DSC0_PICTURE_PARAMETER_SET_1(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC0_PICTURE_PARAMETER_SET_1_PB, \ + _ICL_DSC0_PICTURE_PARAMETER_SET_1_PC) +#define ICL_DSC1_PICTURE_PARAMETER_SET_1(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC1_PICTURE_PARAMETER_SET_1_PB, \ + _ICL_DSC1_PICTURE_PARAMETER_SET_1_PC) +#define DSC_BPP(bpp) ((bpp) << 0) + +#define DSCA_PICTURE_PARAMETER_SET_2 0x6B208 +#define DSCC_PICTURE_PARAMETER_SET_2 0x6BA08 +#define _ICL_DSC0_PICTURE_PARAMETER_SET_2_PB 0x78278 +#define _ICL_DSC1_PICTURE_PARAMETER_SET_2_PB 0x78378 +#define _ICL_DSC0_PICTURE_PARAMETER_SET_2_PC 0x78478 +#define _ICL_DSC1_PICTURE_PARAMETER_SET_2_PC 0x78578 +#define ICL_DSC0_PICTURE_PARAMETER_SET_2(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC0_PICTURE_PARAMETER_SET_2_PB, \ + _ICL_DSC0_PICTURE_PARAMETER_SET_2_PC) +#define ICL_DSC1_PICTURE_PARAMETER_SET_2(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC1_PICTURE_PARAMETER_SET_2_PB, \ + _ICL_DSC1_PICTURE_PARAMETER_SET_2_PC) +#define DSC_PIC_WIDTH(pic_width) ((pic_width) << 16) +#define DSC_PIC_HEIGHT(pic_height) ((pic_height) << 0) + +#define DSCA_PICTURE_PARAMETER_SET_3 0x6B20C +#define DSCC_PICTURE_PARAMETER_SET_3 0x6BA0C +#define _ICL_DSC0_PICTURE_PARAMETER_SET_3_PB 0x7827C +#define _ICL_DSC1_PICTURE_PARAMETER_SET_3_PB 0x7837C +#define _ICL_DSC0_PICTURE_PARAMETER_SET_3_PC 0x7847C +#define _ICL_DSC1_PICTURE_PARAMETER_SET_3_PC 0x7857C +#define ICL_DSC0_PICTURE_PARAMETER_SET_3(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC0_PICTURE_PARAMETER_SET_3_PB, \ + _ICL_DSC0_PICTURE_PARAMETER_SET_3_PC) +#define ICL_DSC1_PICTURE_PARAMETER_SET_3(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC1_PICTURE_PARAMETER_SET_3_PB, \ + _ICL_DSC1_PICTURE_PARAMETER_SET_3_PC) +#define DSC_SLICE_WIDTH(slice_width) ((slice_width) << 16) +#define DSC_SLICE_HEIGHT(slice_height) ((slice_height) << 0) + +#define DSCA_PICTURE_PARAMETER_SET_4 0x6B210 +#define DSCC_PICTURE_PARAMETER_SET_4 0x6BA10 +#define _ICL_DSC0_PICTURE_PARAMETER_SET_4_PB 0x78280 +#define _ICL_DSC1_PICTURE_PARAMETER_SET_4_PB 0x78380 +#define _ICL_DSC0_PICTURE_PARAMETER_SET_4_PC 0x78480 +#define _ICL_DSC1_PICTURE_PARAMETER_SET_4_PC 0x78580 +#define ICL_DSC0_PICTURE_PARAMETER_SET_4(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC0_PICTURE_PARAMETER_SET_4_PB, \ + _ICL_DSC0_PICTURE_PARAMETER_SET_4_PC) +#define ICL_DSC1_PICTURE_PARAMETER_SET_4(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC0_PICTURE_PARAMETER_SET_4_PB, \ + _ICL_DSC1_PICTURE_PARAMETER_SET_4_PC) +#define DSC_INITIAL_DEC_DELAY(dec_delay) ((dec_delay) << 16) +#define DSC_INITIAL_XMIT_DELAY(xmit_delay) ((xmit_delay) << 0) + +#define DSCA_PICTURE_PARAMETER_SET_5 0x6B214 +#define DSCC_PICTURE_PARAMETER_SET_5 0x6BA14 +#define _ICL_DSC0_PICTURE_PARAMETER_SET_5_PB 0x78284 +#define _ICL_DSC1_PICTURE_PARAMETER_SET_5_PB 0x78384 +#define _ICL_DSC0_PICTURE_PARAMETER_SET_5_PC 0x78484 +#define _ICL_DSC1_PICTURE_PARAMETER_SET_5_PC 0x78584 +#define ICL_DSC0_PICTURE_PARAMETER_SET_5(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC0_PICTURE_PARAMETER_SET_5_PB, \ + _ICL_DSC0_PICTURE_PARAMETER_SET_5_PC) +#define ICL_DSC1_PICTURE_PARAMETER_SET_5(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC1_PICTURE_PARAMETER_SET_5_PC, \ + _ICL_DSC1_PICTURE_PARAMETER_SET_5_PC) +#define DSC_SCALE_DEC_INTINT(scale_dec) ((scale_dec) << 16) +#define DSC_SCALE_INC_INT(scale_inc) ((scale_inc) << 0) + +#define DSCA_PICTURE_PARAMETER_SET_6 0x6B218 +#define DSCC_PICTURE_PARAMETER_SET_6 0x6BA18 +#define _ICL_DSC0_PICTURE_PARAMETER_SET_6_PB 0x78288 +#define _ICL_DSC1_PICTURE_PARAMETER_SET_6_PB 0x78388 +#define _ICL_DSC0_PICTURE_PARAMETER_SET_6_PC 0x78488 +#define _ICL_DSC1_PICTURE_PARAMETER_SET_6_PC 0x78588 +#define ICL_DSC0_PICTURE_PARAMETER_SET_6(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC0_PICTURE_PARAMETER_SET_6_PB, \ + _ICL_DSC0_PICTURE_PARAMETER_SET_6_PC) +#define ICL_DSC1_PICTURE_PARAMETER_SET_6(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC1_PICTURE_PARAMETER_SET_6_PB, \ + _ICL_DSC1_PICTURE_PARAMETER_SET_6_PC) +#define DSC_FLATNESS_MAX_QP(max_qp) (qp << 24) +#define DSC_FLATNESS_MIN_QP(min_qp) (qp << 16) +#define DSC_FIRST_LINE_BPG_OFFSET(offset) ((offset) << 8) +#define DSC_INITIAL_SCALE_VALUE(value) ((value) << 0) + +#define DSCA_PICTURE_PARAMETER_SET_7 0x6B21C +#define DSCC_PICTURE_PARAMETER_SET_7 0x6BA1C +#define _ICL_DSC0_PICTURE_PARAMETER_SET_7_PB 0x7828C +#define _ICL_DSC1_PICTURE_PARAMETER_SET_7_PB 0x7838C +#define _ICL_DSC0_PICTURE_PARAMETER_SET_7_PC 0x7848C +#define _ICL_DSC1_PICTURE_PARAMETER_SET_7_PC 0x7858C +#define ICL_DSC0_PICTURE_PARAMETER_SET_7(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC0_PICTURE_PARAMETER_SET_7_PB, \ + _ICL_DSC0_PICTURE_PARAMETER_SET_7_PC) +#define ICL_DSC1_PICTURE_PARAMETER_SET_7(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC1_PICTURE_PARAMETER_SET_7_PB, \ + _ICL_DSC1_PICTURE_PARAMETER_SET_7_PC) +#define DSC_NFL_BPG_OFFSET(bpg_offset) ((bpg_offset) << 16) +#define DSC_SLICE_BPG_OFFSET(bpg_offset) ((bpg_offset) << 0) + +#define DSCA_PICTURE_PARAMETER_SET_8 0x6B220 +#define DSCC_PICTURE_PARAMETER_SET_8 0x6BA20 +#define _ICL_DSC0_PICTURE_PARAMETER_SET_8_PB 0x78290 +#define _ICL_DSC1_PICTURE_PARAMETER_SET_8_PB 0x78390 +#define _ICL_DSC0_PICTURE_PARAMETER_SET_8_PC 0x78490 +#define _ICL_DSC1_PICTURE_PARAMETER_SET_8_PC 0x78590 +#define ICL_DSC0_PICTURE_PARAMETER_SET_8(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC0_PICTURE_PARAMETER_SET_8_PB, \ + _ICL_DSC0_PICTURE_PARAMETER_SET_8_PC) +#define ICL_DSC1_PICTURE_PARAMETER_SET_8(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC1_PICTURE_PARAMETER_SET_8_PB, \ + _ICL_DSC1_PICTURE_PARAMETER_SET_8_PC) +#define DSC_INITIAL_OFFSET(initial_offset) ((initial_offset) << 16) +#define DSC_FINAL_OFFSET(final_offset) ((final_offset) << 0) + +#define DSCA_PICTURE_PARAMETER_SET_9 0x6B224 +#define DSCC_PICTURE_PARAMETER_SET_9 0x6BA24 +#define _ICL_DSC0_PICTURE_PARAMETER_SET_9_PB 0x78294 +#define _ICL_DSC1_PICTURE_PARAMETER_SET_9_PB 0x78394 +#define _ICL_DSC0_PICTURE_PARAMETER_SET_9_PC 0x78494 +#define _ICL_DSC1_PICTURE_PARAMETER_SET_9_PC 0x78594 +#define ICL_DSC0_PICTURE_PARAMETER_SET_9(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC0_PICTURE_PARAMETER_SET_9_PB, \ + _ICL_DSC0_PICTURE_PARAMETER_SET_9_PC) +#define ICL_DSC1_PICTURE_PARAMETER_SET_9(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC1_PICTURE_PARAMETER_SET_9_PB, \ + _ICL_DSC1_PICTURE_PARAMETER_SET_9_PC) +#define DSC_RC_EDGE_FACTOR(rc_edge_fact) ((rc_edge_fact) << 16) +#define DSC_RC_MODEL_SIZE(rc_model_size) ((rc_model_size) << 0) + +#define DSCA_PICTURE_PARAMETER_SET_10 0x6B228 +#define DSCC_PICTURE_PARAMETER_SET_10 0x6BA28 +#define _ICL_DSC0_PICTURE_PARAMETER_SET_10_PB 0x78298 +#define _ICL_DSC1_PICTURE_PARAMETER_SET_10_PB 0x78398 +#define _ICL_DSC0_PICTURE_PARAMETER_SET_10_PC 0x78498 +#define _ICL_DSC1_PICTURE_PARAMETER_SET_10_PC 0x78598 +#define ICL_DSC0_PICTURE_PARAMETER_SET_10(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC0_PICTURE_PARAMETER_SET_10_PB, \ + _ICL_DSC0_PICTURE_PARAMETER_SET_10_PC) +#define ICL_DSC1_PICTURE_PARAMETER_SET_10(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC1_PICTURE_PARAMETER_SET_10_PB, \ + _ICL_DSC1_PICTURE_PARAMETER_SET_10_PC) +#define DSC_RC_TARGET_OFF_LOW(rc_tgt_off_low) ((rc_tgt_off_low) << 20) +#define DSC_RC_TARGET_OFF_HIGH(rc_tgt_off_high) ((rc_tgt_off_high) << 16) +#define DSC_RC_QUANT_INC_LIMIT1(lim) ((lim) << 8) +#define DSC_RC_QUANT_INC_LIMIT0(lim) ((lim) << 0) + +#define DSCA_PICTURE_PARAMETER_SET_11 0x6B22C +#define DSCC_PICTURE_PARAMETER_SET_11 0x6BA2C +#define _ICL_DSC0_PICTURE_PARAMETER_SET_11_PB 0x7829C +#define _ICL_DSC1_PICTURE_PARAMETER_SET_11_PB 0x7839C +#define _ICL_DSC0_PICTURE_PARAMETER_SET_11_PC 0x7849C +#define _ICL_DSC1_PICTURE_PARAMETER_SET_11_PC 0x7859C +#define ICL_DSC0_PICTURE_PARAMETER_SET_11(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC0_PICTURE_PARAMETER_SET_11_PB, \ + _ICL_DSC0_PICTURE_PARAMETER_SET_11_PC) +#define ICL_DSC1_PICTURE_PARAMETER_SET_11(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC1_PICTURE_PARAMETER_SET_11_PB, \ + _ICL_DSC1_PICTURE_PARAMETER_SET_11_PC) + +#define DSCA_PICTURE_PARAMETER_SET_12 0x6B260 +#define DSCC_PICTURE_PARAMETER_SET_12 0x6BA60 +#define _ICL_DSC0_PICTURE_PARAMETER_SET_12_PB 0x782A0 +#define _ICL_DSC1_PICTURE_PARAMETER_SET_12_PB 0x783A0 +#define _ICL_DSC0_PICTURE_PARAMETER_SET_12_PC 0x784A0 +#define _ICL_DSC1_PICTURE_PARAMETER_SET_12_PC 0x785A0 +#define ICL_DSC0_PICTURE_PARAMETER_SET_12(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC0_PICTURE_PARAMETER_SET_12_PB, \ + _ICL_DSC0_PICTURE_PARAMETER_SET_12_PC) +#define ICL_DSC1_PICTURE_PARAMETER_SET_12(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC1_PICTURE_PARAMETER_SET_12_PB, \ + _ICL_DSC1_PICTURE_PARAMETER_SET_12_PC) + +#define DSCA_PICTURE_PARAMETER_SET_13 0x6B264 +#define DSCC_PICTURE_PARAMETER_SET_13 0x6BA64 +#define _ICL_DSC0_PICTURE_PARAMETER_SET_13_PB 0x782A4 +#define _ICL_DSC1_PICTURE_PARAMETER_SET_13_PB 0x783A4 +#define _ICL_DSC0_PICTURE_PARAMETER_SET_13_PC 0x784A4 +#define _ICL_DSC1_PICTURE_PARAMETER_SET_13_PC 0x785A4 +#define ICL_DSC0_PICTURE_PARAMETER_SET_13(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC0_PICTURE_PARAMETER_SET_13_PB, \ + _ICL_DSC0_PICTURE_PARAMETER_SET_13_PC) +#define ICL_DSC1_PICTURE_PARAMETER_SET_13(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC1_PICTURE_PARAMETER_SET_13_PB, \ + _ICL_DSC1_PICTURE_PARAMETER_SET_13_PC) + +#define DSCA_PICTURE_PARAMETER_SET_14 0x6B268 +#define DSCC_PICTURE_PARAMETER_SET_14 0x6BA68 +#define _ICL_DSC0_PICTURE_PARAMETER_SET_14_PB 0x782A8 +#define _ICL_DSC1_PICTURE_PARAMETER_SET_14_PB 0x783A8 +#define _ICL_DSC0_PICTURE_PARAMETER_SET_14_PC 0x784A8 +#define _ICL_DSC1_PICTURE_PARAMETER_SET_14_PC 0x785A8 +#define ICL_DSC0_PICTURE_PARAMETER_SET_14(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC0_PICTURE_PARAMETER_SET_14_PB, \ + _ICL_DSC0_PICTURE_PARAMETER_SET_14_PC) +#define ICL_DSC1_PICTURE_PARAMETER_SET_14(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC1_PICTURE_PARAMETER_SET_14_PB, \ + _ICL_DSC1_PICTURE_PARAMETER_SET_14_PC) + +#define DSCA_PICTURE_PARAMETER_SET_15 0x6B26C +#define DSCC_PICTURE_PARAMETER_SET_15 0x6BA6C +#define _ICL_DSC0_PICTURE_PARAMETER_SET_15_PB 0x782AC +#define _ICL_DSC1_PICTURE_PARAMETER_SET_15_PB 0x783AC +#define _ICL_DSC0_PICTURE_PARAMETER_SET_15_PC 0x784AC +#define _ICL_DSC1_PICTURE_PARAMETER_SET_15_PC 0x785AC +#define ICL_DSC0_PICTURE_PARAMETER_SET_15(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC0_PICTURE_PARAMETER_SET_15_PB, \ + _ICL_DSC0_PICTURE_PARAMETER_SET_15_PC) +#define ICL_DSC1_PICTURE_PARAMETER_SET_15(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC1_PICTURE_PARAMETER_SET_15_PB, \ + _ICL_DSC1_PICTURE_PARAMETER_SET_15_PC) + +#define DSCA_PICTURE_PARAMETER_SET_16 0x6B270 +#define DSCC_PICTURE_PARAMETER_SET_16 0x6BA70 +#define _ICL_DSC0_PICTURE_PARAMETER_SET_16_PB 0x782B0 +#define _ICL_DSC1_PICTURE_PARAMETER_SET_16_PB 0x783B0 +#define _ICL_DSC0_PICTURE_PARAMETER_SET_16_PC 0x784B0 +#define _ICL_DSC1_PICTURE_PARAMETER_SET_16_PC 0x785B0 +#define ICL_DSC0_PICTURE_PARAMETER_SET_16(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC0_PICTURE_PARAMETER_SET_16_PB, \ + _ICL_DSC0_PICTURE_PARAMETER_SET_16_PC) +#define ICL_DSC1_PICTURE_PARAMETER_SET_16(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC1_PICTURE_PARAMETER_SET_16_PB, \ + _ICL_DSC1_PICTURE_PARAMETER_SET_16_PC) +#define DSC_SLICE_PER_LINE(slice_per_line) ((slice_per_line) << 16) +#define DSC_SLICE_CHUNK_SIZE(slice_chunk_aize) (slice_chunk_size << 0) + #endif /* _I915_REG_H_ */ -- GitLab From dbda5111e2d85ff67452e9f8b82fc9eee73a224c Mon Sep 17 00:00:00 2001 From: Anusha Srivatsa <anusha.srivatsa@intel.com> Date: Tue, 17 Jul 2018 14:11:00 -0700 Subject: [PATCH 1256/1506] i915/dp/dsc: Add Rate Control Buffer Threshold Registers Add register defines and shifts that control the RC buffer threshold between encoder and decoder for eDP/MIPI and DP cases. The actual values are calculated usung a helper function. This patch adds the shifts to registers where the value will be written during atomic commit. v2: - Use _MMIO_PIPE() instead of _MMIO_(_PICK()) (Manasi) - Combine shifts (Manasi) Cc: Jani Nikula <jani.nikula@intel.com> Cc: Ville Syrjala <ville.syrjala@linux.intel.com> Cc: Manasi Navare <manasi.d.navare@intel.com> Signed-off-by: Anusha Srivatsa <anusha.srivatsa@intel.com> Reviewed-by: Manasi Navare <manasi.d.navare@intel.com> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/1531861861-10950-3-git-send-email-anusha.srivatsa@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 51 +++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index e8687b0f906d6..5825319d4d22b 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -10499,4 +10499,55 @@ enum skl_power_gate { #define DSC_SLICE_PER_LINE(slice_per_line) ((slice_per_line) << 16) #define DSC_SLICE_CHUNK_SIZE(slice_chunk_aize) (slice_chunk_size << 0) +/* Icelake Rate Control Buffer Threshold Registers */ +#define DSCA_RC_BUF_THRESH_0 _MMIO(0x6B230) +#define DSCA_RC_BUF_THRESH_0_UDW _MMIO(0x6B230 + 4) +#define DSCC_RC_BUF_THRESH_0 _MMIO(0x6BA30) +#define DSCC_RC_BUF_THRESH_0_UDW _MMIO(0x6BA30 + 4) +#define _ICL_DSC0_RC_BUF_THRESH_0_PB (0x78254) +#define _ICL_DSC0_RC_BUF_THRESH_0_UDW_PB (0x78254 + 4) +#define _ICL_DSC1_RC_BUF_THRESH_0_PB (0x78354) +#define _ICL_DSC1_RC_BUF_THRESH_0_UDW_PB (0x78354 + 4) +#define _ICL_DSC0_RC_BUF_THRESH_0_PC (0x78454) +#define _ICL_DSC0_RC_BUF_THRESH_0_UDW_PC (0x78454 + 4) +#define _ICL_DSC1_RC_BUF_THRESH_0_PC (0x78554) +#define _ICL_DSC1_RC_BUF_THRESH_0_UDW_PC (0x78554 + 4) +#define ICL_DSC0_RC_BUF_THRESH_0(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC0_RC_BUF_THRESH_0_PB, \ + _ICL_DSC0_RC_BUF_THRESH_0_PC) +#define ICL_DSC0_RC_BUF_THRESH_0_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC0_RC_BUF_THRESH_0_UDW_PB, \ + _ICL_DSC0_RC_BUF_THRESH_0_UDW_PC) +#define ICL_DSC1_RC_BUF_THRESH_0(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC1_RC_BUF_THRESH_0_PB, \ + _ICL_DSC1_RC_BUF_THRESH_0_PC) +#define ICL_DSC1_RC_BUF_THRESH_0_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC1_RC_BUF_THRESH_0_UDW_PB, \ + _ICL_DSC1_RC_BUF_THRESH_0_UDW_PC) + +#define DSCA_RC_BUF_THRESH_1 _MMIO(0x6B238) +#define DSCA_RC_BUF_THRESH_1_UDW _MMIO(0x6B238 + 4) +#define DSCC_RC_BUF_THRESH_1 _MMIO(0x6BA38) +#define DSCC_RC_BUF_THRESH_1_UDW _MMIO(0x6BA38 + 4) +#define _ICL_DSC0_RC_BUF_THRESH_1_PB (0x7825C) +#define _ICL_DSC0_RC_BUF_THRESH_1_UDW_PB (0x7825C + 4) +#define _ICL_DSC1_RC_BUF_THRESH_1_PB (0x7835C) +#define _ICL_DSC1_RC_BUF_THRESH_1_UDW_PB (0x7835C + 4) +#define _ICL_DSC0_RC_BUF_THRESH_1_PC (0x7845C) +#define _ICL_DSC0_RC_BUF_THRESH_1_UDW_PC (0x7845C + 4) +#define _ICL_DSC1_RC_BUF_THRESH_1_PC (0x7855C) +#define _ICL_DSC1_RC_BUF_THRESH_1_UDW_PC (0x7855C + 4) +#define ICL_DSC0_RC_BUF_THRESH_1(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC0_RC_BUF_THRESH_1_PB, \ + _ICL_DSC0_RC_BUF_THRESH_1_PC) +#define ICL_DSC0_RC_BUF_THRESH_1_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC0_RC_BUF_THRESH_1_UDW_PB, \ + _ICL_DSC0_RC_BUF_THRESH_1_UDW_PC) +#define ICL_DSC1_RC_BUF_THRESH_1(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC1_RC_BUF_THRESH_1_PB, \ + _ICL_DSC1_RC_BUF_THRESH_1_PC) +#define ICL_DSC1_RC_BUF_THRESH_1_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC1_RC_BUF_THRESH_1_UDW_PB, \ + _ICL_DSC1_RC_BUF_THRESH_1_UDW_PC) + #endif /* _I915_REG_H_ */ -- GitLab From c7d2959f032ddb0cb3528df4cc08b6b78acb9a09 Mon Sep 17 00:00:00 2001 From: Anusha Srivatsa <anusha.srivatsa@intel.com> Date: Tue, 17 Jul 2018 14:11:01 -0700 Subject: [PATCH 1257/1506] i915/dp/dsc: Add Rate Control Range Parameter Registers RC model has these parameters that correspond with each of 15 ranges of RC buffer threshold value in the RC model. The three elements are range_min_qp, range_max_qp and range_bpg_offset. Add the Rate Control range values for eDP/MIPI and DP case. The actual values are calculated usung a helper function. This patch adds the shifts to registers where the value will be written during atomic commit. v2: - Use _MMIO_PIPE() instead of _MMIO(_PICK()) (Manasi) - Combine shifts (Manasi) Cc: Jose Souza <jose.souza@intel.com> Cc: Jani Nikula <jani.nikula@intel.com> Cc: Ville Syrjala <ville.syrjala@linux.intel.com> Cc: Manasi Navare <manasi.d.navare@intel.com> Signed-off-by: Anusha Srivatsa <anusha.srivatsa@intel.com> Reviewed-by: Manasi Navare <manasi.d.navare@intel.com> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/1531861861-10950-4-git-send-email-anusha.srivatsa@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 104 ++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 5825319d4d22b..8af945d8a9959 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -7678,6 +7678,110 @@ enum { #define SHOTPLUG_CTL_TC _MMIO(0xc4034) #define ICP_TC_HPD_ENABLE(tc_port) (8 << (tc_port) * 4) +/* Icelake DSC Rate Control Range Parameter Registers */ +#define DSCA_RC_RANGE_PARAMETERS_0 _MMIO(0x6B240) +#define DSCA_RC_RANGE_PARAMETERS_0_UDW _MMIO(0x6B240 + 4) +#define DSCC_RC_RANGE_PARAMETERS_0 _MMIO(0x6BA40) +#define DSCC_RC_RANGE_PARAMETERS_0_UDW _MMIO(0x6BA40 + 4) +#define _ICL_DSC0_RC_RANGE_PARAMETERS_0_PB (0x78208) +#define _ICL_DSC0_RC_RANGE_PARAMETERS_0_UDW_PB (0x78208 + 4) +#define _ICL_DSC1_RC_RANGE_PARAMETERS_0_PB (0x78308) +#define _ICL_DSC1_RC_RANGE_PARAMETERS_0_UDW_PB (0x78308 + 4) +#define _ICL_DSC0_RC_RANGE_PARAMETERS_0_PC (0x78408) +#define _ICL_DSC0_RC_RANGE_PARAMETERS_0_UDW_PC (0x78408 + 4) +#define _ICL_DSC1_RC_RANGE_PARAMETERS_0_PC (0x78508) +#define _ICL_DSC1_RC_RANGE_PARAMETERS_0_UDW_PC (0x78508 + 4) +#define ICL_DSC0_RC_RANGE_PARAMETERS_0(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC0_RC_RANGE_PARAMETERS_0_PB, \ + _ICL_DSC0_RC_RANGE_PARAMETERS_0_PC) +#define ICL_DSC0_RC_RANGE_PARAMETERS_0_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC0_RC_RANGE_PARAMETERS_0_UDW_PB, \ + _ICL_DSC0_RC_RANGE_PARAMETERS_0_UDW_PC) +#define ICL_DSC1_RC_RANGE_PARAMETERS_0(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC1_RC_RANGE_PARAMETERS_0_PB, \ + _ICL_DSC1_RC_RANGE_PARAMETERS_0_PC) +#define ICL_DSC1_RC_RANGE_PARAMETERS_0_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC1_RC_RANGE_PARAMETERS_0_UDW_PB, \ + _ICL_DSC1_RC_RANGE_PARAMETERS_0_UDW_PC) +#define RC_BPG_OFFSET_SHIFT 10 +#define RC_MAX_QP_SHIFT 5 +#define RC_MIN_QP_SHIFT 0 + +#define DSCA_RC_RANGE_PARAMETERS_1 _MMIO(0x6B248) +#define DSCA_RC_RANGE_PARAMETERS_1_UDW _MMIO(0x6B248 + 4) +#define DSCC_RC_RANGE_PARAMETERS_1 _MMIO(0x6BA48) +#define DSCC_RC_RANGE_PARAMETERS_1_UDW _MMIO(0x6BA48 + 4) +#define _ICL_DSC0_RC_RANGE_PARAMETERS_1_PB (0x78210) +#define _ICL_DSC0_RC_RANGE_PARAMETERS_1_UDW_PB (0x78210 + 4) +#define _ICL_DSC1_RC_RANGE_PARAMETERS_1_PB (0x78310) +#define _ICL_DSC1_RC_RANGE_PARAMETERS_1_UDW_PB (0x78310 + 4) +#define _ICL_DSC0_RC_RANGE_PARAMETERS_1_PC (0x78410) +#define _ICL_DSC0_RC_RANGE_PARAMETERS_1_UDW_PC (0x78410 + 4) +#define _ICL_DSC1_RC_RANGE_PARAMETERS_1_PC (0x78510) +#define _ICL_DSC1_RC_RANGE_PARAMETERS_1_UDW_PC (0x78510 + 4) +#define ICL_DSC0_RC_RANGE_PARAMETERS_1(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC0_RC_RANGE_PARAMETERS_1_PB, \ + _ICL_DSC0_RC_RANGE_PARAMETERS_1_PC) +#define ICL_DSC0_RC_RANGE_PARAMETERS_1_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC0_RC_RANGE_PARAMETERS_1_UDW_PB, \ + _ICL_DSC0_RC_RANGE_PARAMETERS_1_UDW_PC) +#define ICL_DSC1_RC_RANGE_PARAMETERS_1(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC1_RC_RANGE_PARAMETERS_1_PB, \ + _ICL_DSC1_RC_RANGE_PARAMETERS_1_PC) +#define ICL_DSC1_RC_RANGE_PARAMETERS_1_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC1_RC_RANGE_PARAMETERS_1_UDW_PB, \ + _ICL_DSC1_RC_RANGE_PARAMETERS_1_UDW_PC) + +#define DSCA_RC_RANGE_PARAMETERS_2 _MMIO(0x6B250) +#define DSCA_RC_RANGE_PARAMETERS_2_UDW _MMIO(0x6B250 + 4) +#define DSCC_RC_RANGE_PARAMETERS_2 _MMIO(0x6BA50) +#define DSCC_RC_RANGE_PARAMETERS_2_UDW _MMIO(0x6BA50 + 4) +#define _ICL_DSC0_RC_RANGE_PARAMETERS_2_PB (0x78218) +#define _ICL_DSC0_RC_RANGE_PARAMETERS_2_UDW_PB (0x78218 + 4) +#define _ICL_DSC1_RC_RANGE_PARAMETERS_2_PB (0x78318) +#define _ICL_DSC1_RC_RANGE_PARAMETERS_2_UDW_PB (0x78318 + 4) +#define _ICL_DSC0_RC_RANGE_PARAMETERS_2_PC (0x78418) +#define _ICL_DSC0_RC_RANGE_PARAMETERS_2_UDW_PC (0x78418 + 4) +#define _ICL_DSC1_RC_RANGE_PARAMETERS_2_PC (0x78518) +#define _ICL_DSC1_RC_RANGE_PARAMETERS_2_UDW_PC (0x78518 + 4) +#define ICL_DSC0_RC_RANGE_PARAMETERS_2(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC0_RC_RANGE_PARAMETERS_2_PB, \ + _ICL_DSC0_RC_RANGE_PARAMETERS_2_PC) +#define ICL_DSC0_RC_RANGE_PARAMETERS_2_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC0_RC_RANGE_PARAMETERS_2_UDW_PB, \ + _ICL_DSC0_RC_RANGE_PARAMETERS_2_UDW_PC) +#define ICL_DSC1_RC_RANGE_PARAMETERS_2(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC1_RC_RANGE_PARAMETERS_2_PB, \ + _ICL_DSC1_RC_RANGE_PARAMETERS_2_PC) +#define ICL_DSC1_RC_RANGE_PARAMETERS_2_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC1_RC_RANGE_PARAMETERS_2_UDW_PB, \ + _ICL_DSC1_RC_RANGE_PARAMETERS_2_UDW_PC) + +#define DSCA_RC_RANGE_PARAMETERS_3 _MMIO(0x6B258) +#define DSCA_RC_RANGE_PARAMETERS_3_UDW _MMIO(0x6B258 + 4) +#define DSCC_RC_RANGE_PARAMETERS_3 _MMIO(0x6BA58) +#define DSCC_RC_RANGE_PARAMETERS_3_UDW _MMIO(0x6BA58 + 4) +#define _ICL_DSC0_RC_RANGE_PARAMETERS_3_PB (0x78220) +#define _ICL_DSC0_RC_RANGE_PARAMETERS_3_UDW_PB (0x78220 + 4) +#define _ICL_DSC1_RC_RANGE_PARAMETERS_3_PB (0x78320) +#define _ICL_DSC1_RC_RANGE_PARAMETERS_3_UDW_PB (0x78320 + 4) +#define _ICL_DSC0_RC_RANGE_PARAMETERS_3_PC (0x78420) +#define _ICL_DSC0_RC_RANGE_PARAMETERS_3_UDW_PC (0x78420 + 4) +#define _ICL_DSC1_RC_RANGE_PARAMETERS_3_PC (0x78520) +#define _ICL_DSC1_RC_RANGE_PARAMETERS_3_UDW_PC (0x78520 + 4) +#define ICL_DSC0_RC_RANGE_PARAMETERS_3(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC0_RC_RANGE_PARAMETERS_3_PB, \ + _ICL_DSC0_RC_RANGE_PARAMETERS_3_PC) +#define ICL_DSC0_RC_RANGE_PARAMETERS_3_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC0_RC_RANGE_PARAMETERS_3_UDW_PB, \ + _ICL_DSC0_RC_RANGE_PARAMETERS_3_UDW_PC) +#define ICL_DSC1_RC_RANGE_PARAMETERS_3(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC1_RC_RANGE_PARAMETERS_3_PB, \ + _ICL_DSC1_RC_RANGE_PARAMETERS_3_PC) +#define ICL_DSC1_RC_RANGE_PARAMETERS_3_UDW(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ + _ICL_DSC1_RC_RANGE_PARAMETERS_3_UDW_PB, \ + _ICL_DSC1_RC_RANGE_PARAMETERS_3_UDW_PC) + #define ICP_TC_HPD_LONG_DETECT(tc_port) (2 << (tc_port) * 4) #define ICP_TC_HPD_SHORT_DETECT(tc_port) (1 << (tc_port) * 4) -- GitLab From d00ddd9da79a868264997e192f9404aef1e46ba8 Mon Sep 17 00:00:00 2001 From: Ben Skeggs <bskeggs@redhat.com> Date: Wed, 18 Jul 2018 09:33:39 +1000 Subject: [PATCH 1258/1506] drm/nouveau/kms/nv50-: allocate push buffers in vidmem on pascal Workaround for issues seen on systems with large amounts of RAM, caused by display not supporting the same physical address limits as the other parts of the GPU. Signed-off-by: Ben Skeggs <bskeggs@redhat.com> --- drivers/gpu/drm/nouveau/dispnv50/disp.c | 29 +++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 7d00d833bbe5a..4a372f805eb91 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -136,12 +136,24 @@ nv50_dmac_create(struct nvif_device *device, struct nvif_object *disp, { struct nouveau_cli *cli = (void *)device->object.client; struct nv50_disp_core_channel_dma_v0 *args = data; + u8 type = NVIF_MEM_COHERENT; int ret; mutex_init(&dmac->lock); - ret = nvif_mem_init_map(&cli->mmu, NVIF_MEM_COHERENT, 0x1000, - &dmac->push); + /* Pascal added support for 47-bit physical addresses, but some + * parts of EVO still only accept 40-bit PAs. + * + * To avoid issues on systems with large amounts of RAM, and on + * systems where an IOMMU maps pages at a high address, we need + * to allocate push buffers in VRAM instead. + * + * This appears to match NVIDIA's behaviour on Pascal. + */ + if (device->info.family == NV_DEVICE_INFO_V0_PASCAL) + type |= NVIF_MEM_VRAM; + + ret = nvif_mem_init_map(&cli->mmu, type, 0x1000, &dmac->push); if (ret) return ret; @@ -216,6 +228,19 @@ void evo_kick(u32 *push, struct nv50_dmac *evoc) { struct nv50_dmac *dmac = evoc; + + /* Push buffer fetches are not coherent with BAR1, we need to ensure + * writes have been flushed right through to VRAM before writing PUT. + */ + if (dmac->push.type & NVIF_MEM_VRAM) { + struct nvif_device *device = dmac->base.device; + nvif_wr32(&device->object, 0x070000, 0x00000001); + nvif_msec(device, 2000, + if (!(nvif_rd32(&device->object, 0x070000) & 0x00000002)) + break; + ); + } + nvif_wr32(&dmac->base.user, 0x0000, (push - dmac->ptr) << 2); mutex_unlock(&dmac->lock); } -- GitLab From 209b7955e59e361fe8ba1911fac68f46355ac0cf Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Tue, 17 Jul 2018 21:29:32 +0100 Subject: [PATCH 1259/1506] drm/i915/guc: Keep guc submission permanently engaged MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We make a decision at module load whether to use the GuC backend or not, but lose that setup across set-wedge. Currently, the guc doesn't override the engine->set_default_submission hook letting execlists sneak back in temporarily on unwedging leading to an unbalanced park/unpark. v2: Remove comment about switching back temporarily to execlists on guc_submission_disable(). We currently only call disable on shutdown, and plan to also call disable before suspend and reset, in which case we will either restore guc submission or mark the driver as wedged, making the reset back to execlists pointless. v3: Move reset.prepare across Fixes: 63572937cebf ("drm/i915/execlists: Flush pending preemption events during reset") Testcase: igt/drv_module_reload/basic-reload-inject Testcase: igt/gem_eio Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: MichaÅ‚ Winiarski <michal.winiarski@intel.com> Cc: Michal Wajdeczko <michal.wajdeczko@intel.com> Reviewed-by: MichaÅ‚ Winiarski <michal.winiarski@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180717202932.1423-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_guc_submission.c | 41 ++++++++++++++------- drivers/gpu/drm/i915/intel_lrc.c | 4 +- drivers/gpu/drm/i915/intel_lrc.h | 2 + 3 files changed, 31 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_guc_submission.c b/drivers/gpu/drm/i915/intel_guc_submission.c index 0fa1eb0bfff54..4aa5e6463e7b7 100644 --- a/drivers/gpu/drm/i915/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/intel_guc_submission.c @@ -1269,6 +1269,31 @@ static void guc_submission_unpark(struct intel_engine_cs *engine) intel_engine_pin_breadcrumbs_irq(engine); } +static void guc_set_default_submission(struct intel_engine_cs *engine) +{ + /* + * We inherit a bunch of functions from execlists that we'd like + * to keep using: + * + * engine->submit_request = execlists_submit_request; + * engine->cancel_requests = execlists_cancel_requests; + * engine->schedule = execlists_schedule; + * + * But we need to override the actual submission backend in order + * to talk to the GuC. + */ + intel_execlists_set_default_submission(engine); + + engine->execlists.tasklet.func = guc_submission_tasklet; + + engine->park = guc_submission_park; + engine->unpark = guc_submission_unpark; + + engine->reset.prepare = guc_reset_prepare; + + engine->flags &= ~I915_ENGINE_SUPPORTS_STATS; +} + int intel_guc_submission_enable(struct intel_guc *guc) { struct drm_i915_private *dev_priv = guc_to_i915(guc); @@ -1307,17 +1332,8 @@ int intel_guc_submission_enable(struct intel_guc *guc) guc_interrupts_capture(dev_priv); for_each_engine(engine, dev_priv, id) { - struct intel_engine_execlists * const execlists = - &engine->execlists; - - execlists->tasklet.func = guc_submission_tasklet; - - engine->reset.prepare = guc_reset_prepare; - - engine->park = guc_submission_park; - engine->unpark = guc_submission_unpark; - - engine->flags &= ~I915_ENGINE_SUPPORTS_STATS; + engine->set_default_submission = guc_set_default_submission; + engine->set_default_submission(engine); } return 0; @@ -1331,9 +1347,6 @@ void intel_guc_submission_disable(struct intel_guc *guc) guc_interrupts_release(dev_priv); guc_clients_doorbell_fini(guc); - - /* Revert back to manual ELSP submission */ - intel_engines_reset_default_submission(dev_priv); } #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index db5351e6a3a53..c64ed9090e29d 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -2295,7 +2295,7 @@ void intel_logical_ring_cleanup(struct intel_engine_cs *engine) kfree(engine); } -static void execlists_set_default_submission(struct intel_engine_cs *engine) +void intel_execlists_set_default_submission(struct intel_engine_cs *engine) { engine->submit_request = execlists_submit_request; engine->cancel_requests = execlists_cancel_requests; @@ -2335,7 +2335,7 @@ logical_ring_default_vfuncs(struct intel_engine_cs *engine) engine->emit_breadcrumb = gen8_emit_breadcrumb; engine->emit_breadcrumb_sz = gen8_emit_breadcrumb_sz; - engine->set_default_submission = execlists_set_default_submission; + engine->set_default_submission = intel_execlists_set_default_submission; if (INTEL_GEN(engine->i915) < 11) { engine->irq_enable = gen8_logical_ring_enable_irq; diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h index 1593194e930c0..4dfb78e3ec7e4 100644 --- a/drivers/gpu/drm/i915/intel_lrc.h +++ b/drivers/gpu/drm/i915/intel_lrc.h @@ -104,4 +104,6 @@ struct i915_gem_context; void intel_lr_context_resume(struct drm_i915_private *dev_priv); +void intel_execlists_set_default_submission(struct intel_engine_cs *engine); + #endif /* _INTEL_LRC_H_ */ -- GitLab From 46b1063f91e5680eff2a6b9fe432f6aae3bef54e Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 19 Jul 2018 08:22:06 +0100 Subject: [PATCH 1260/1506] drm/i915: Handle recursive shrinker for vma->last_active allocation If we call into the shrinker for direct relcaim inside kmalloc, it will retire the requests. If we retire the vma->last_active while processing a new i915_vma_move_to_active() we can upset the delicate bookkeeping required for the cache. After the possible invocation of the shrinker, we need to double check the vma->last_active is still valid. Fixes: 8b293eb53a7d ("drm/i915: Track the last-active inside the i915_vma") Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=105600#c39 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180719072206.16015-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/i915_vma.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c index ed4e0fb558f7c..11d834f942205 100644 --- a/drivers/gpu/drm/i915/i915_vma.c +++ b/drivers/gpu/drm/i915/i915_vma.c @@ -942,6 +942,14 @@ static struct i915_gem_active *active_instance(struct i915_vma *vma, u64 idx) } active = kmalloc(sizeof(*active), GFP_KERNEL); + + /* kmalloc may retire the vma->last_active request (thanks shrinker)! */ + if (unlikely(!i915_gem_active_raw(&vma->last_active, + &vma->vm->i915->drm.struct_mutex))) { + kfree(active); + goto out; + } + if (unlikely(!active)) return ERR_PTR(-ENOMEM); -- GitLab From d78d3343dce7787a5f7fd0b3d522a3510fd26ef9 Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 19 Jul 2018 08:50:29 +0100 Subject: [PATCH 1261/1506] drm/i915/execlists: Move the assertion we have the rpm wakeref down There's a race between idling the engine and finishing off the last tasklet (as we may kick the tasklets after declaring an individual engine idle). However, since we do not need to access the device until we try to submit to the ELSP register (processing the CSB just requires normal CPU access to the HWSP, and when idle we should not need to submit!) we can defer the assertion unto that point. The assertion is still useful as it does verify that we do hold the longterm GT wakeref taken from request allocation until request completion. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=107274 Fixes: 9512f985c32d ("drm/i915/execlists: Direct submission of new requests (avoid tasklet/ksoftirqd)") Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180719075029.28643-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_lrc.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index c64ed9090e29d..174479232e943 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -452,6 +452,16 @@ static void execlists_submit_ports(struct intel_engine_cs *engine) struct execlist_port *port = execlists->port; unsigned int n; + /* + * We can skip acquiring intel_runtime_pm_get() here as it was taken + * on our behalf by the request (see i915_gem_mark_busy()) and it will + * not be relinquished until the device is idle (see + * i915_gem_idle_work_handler()). As a precaution, we make sure + * that all ELSP are drained i.e. we have processed the CSB, + * before allowing ourselves to idle and calling intel_runtime_pm_put(). + */ + GEM_BUG_ON(!engine->i915->gt.awake); + /* * ELSQ note: the submit queue is not cleared after being submitted * to the HW so we need to make sure we always clean it up. This is @@ -1043,16 +1053,6 @@ static void __execlists_submission_tasklet(struct intel_engine_cs *const engine) { lockdep_assert_held(&engine->timeline.lock); - /* - * We can skip acquiring intel_runtime_pm_get() here as it was taken - * on our behalf by the request (see i915_gem_mark_busy()) and it will - * not be relinquished until the device is idle (see - * i915_gem_idle_work_handler()). As a precaution, we make sure - * that all ELSP are drained i.e. we have processed the CSB, - * before allowing ourselves to idle and calling intel_runtime_pm_put(). - */ - GEM_BUG_ON(!engine->i915->gt.awake); - process_csb(engine); if (!execlists_is_active(&engine->execlists, EXECLISTS_ACTIVE_PREEMPT)) execlists_dequeue(engine); @@ -1073,10 +1073,7 @@ static void execlists_submission_tasklet(unsigned long data) engine->execlists.active); spin_lock_irqsave(&engine->timeline.lock, flags); - - if (engine->i915->gt.awake) /* we may be delayed until after we idle! */ - __execlists_submission_tasklet(engine); - + __execlists_submission_tasklet(engine); spin_unlock_irqrestore(&engine->timeline.lock, flags); } -- GitLab From 05c72e77ccda89ff624108b1b59a0fc43843f343 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Tue, 17 Jul 2018 20:42:14 +0300 Subject: [PATCH 1262/1506] drm/i915: Nuke the LVDS lid notifier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We broke the LVDS notifier resume thing in (presumably) commit e2c8b8701e2d ("drm/i915: Use atomic helpers for suspend, v2.") as we no longer duplicate the current state in the LVDS notifier and thus we never resume it properly either. Instead of trying to fix it again let's just kill off the lid notifier entirely. None of the machines tested thus far have apparently needed it. Originally the lid notifier was added to work around cases where the VBIOS was clobbering some of the hardware state behind the driver's back, mostly on Thinkpads. We now have a few report of Thinkpads working just fine without the notifier. So maybe it was misdiagnosed originally, or something else has changed (ACPI video stuff perhaps?). If we do end up finding a machine where the VBIOS is still causing problems I would suggest that we first try setting various bits in the VBIOS scratch registers. There are several to choose from that may instruct the VBIOS to steer clear. With the notifier gone we'll also stop looking at the panel status in ->detect(). v2: Nuke enum modeset_restore (Rodrigo) Cc: stable@vger.kernel.org Cc: Wolfgang Draxinger <wdraxinger.maillist@draxit.de> Cc: Vito Caputo <vcaputo@pengaru.com> Cc: kitsunyan <kitsunyan@airmail.cc> Cc: Joonas Saarinen <jza@saunalahti.fi> Tested-by: Vito Caputo <vcaputo@pengaru.com> # Thinkapd X61s Tested-by: kitsunyan <kitsunyan@airmail.cc> # ThinkPad X200 Tested-by: Joonas Saarinen <jza@saunalahti.fi> # Fujitsu Siemens U9210 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=105902 References: https://lists.freedesktop.org/archives/intel-gfx/2018-June/169315.html References: https://bugs.freedesktop.org/show_bug.cgi?id=21230 Fixes: e2c8b8701e2d ("drm/i915: Use atomic helpers for suspend, v2.") Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180717174216.22252-1-ville.syrjala@linux.intel.com Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> --- drivers/gpu/drm/i915/i915_drv.c | 10 --- drivers/gpu/drm/i915/i915_drv.h | 8 -- drivers/gpu/drm/i915/intel_lvds.c | 136 +----------------------------- 3 files changed, 2 insertions(+), 152 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 337b1aad5212b..343e79a44abd1 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -900,7 +900,6 @@ static int i915_driver_init_early(struct drm_i915_private *dev_priv, spin_lock_init(&dev_priv->uncore.lock); mutex_init(&dev_priv->sb_lock); - mutex_init(&dev_priv->modeset_restore_lock); mutex_init(&dev_priv->av_mutex); mutex_init(&dev_priv->wm.wm_mutex); mutex_init(&dev_priv->pps_mutex); @@ -1570,11 +1569,6 @@ static int i915_drm_suspend(struct drm_device *dev) struct pci_dev *pdev = dev_priv->drm.pdev; pci_power_t opregion_target_state; - /* ignore lid events during suspend */ - mutex_lock(&dev_priv->modeset_restore_lock); - dev_priv->modeset_restore = MODESET_SUSPENDED; - mutex_unlock(&dev_priv->modeset_restore_lock); - disable_rpm_wakeref_asserts(dev_priv); /* We do a lot of poking in a lot of registers, make sure they work @@ -1770,10 +1764,6 @@ static int i915_drm_resume(struct drm_device *dev) intel_fbdev_set_suspend(dev, FBINFO_STATE_RUNNING, false); - mutex_lock(&dev_priv->modeset_restore_lock); - dev_priv->modeset_restore = MODESET_DONE; - mutex_unlock(&dev_priv->modeset_restore_lock); - intel_opregion_notify_adapter(dev_priv, PCI_D0); enable_rpm_wakeref_asserts(dev_priv); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 08d4303abb146..995656f51b574 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1002,12 +1002,6 @@ struct i915_gem_mm { #define I915_ENGINE_WEDGED_TIMEOUT (60 * HZ) /* Reset but no recovery? */ -enum modeset_restore { - MODESET_ON_LID_OPEN, - MODESET_DONE, - MODESET_SUSPENDED, -}; - #define DP_AUX_A 0x40 #define DP_AUX_B 0x10 #define DP_AUX_C 0x20 @@ -1730,8 +1724,6 @@ struct drm_i915_private { unsigned long quirks; - enum modeset_restore modeset_restore; - struct mutex modeset_restore_lock; struct drm_atomic_state *modeset_restore_state; struct drm_modeset_acquire_ctx reset_ctx; diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index bb06744d28a43..a354041192574 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -44,8 +44,6 @@ /* Private structure for the integrated LVDS support */ struct intel_lvds_connector { struct intel_connector base; - - struct notifier_block lid_notifier; }; struct intel_lvds_pps { @@ -452,26 +450,9 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, return true; } -/* - * Detect the LVDS connection. - * - * Since LVDS doesn't have hotlug, we use the lid as a proxy. Open means - * connected and closed means disconnected. We also send hotplug events as - * needed, using lid status notification from the input layer. - */ static enum drm_connector_status intel_lvds_detect(struct drm_connector *connector, bool force) { - struct drm_i915_private *dev_priv = to_i915(connector->dev); - enum drm_connector_status status; - - DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", - connector->base.id, connector->name); - - status = intel_panel_detect(dev_priv); - if (status != connector_status_unknown) - return status; - return connector_status_connected; } @@ -496,117 +477,6 @@ static int intel_lvds_get_modes(struct drm_connector *connector) return 1; } -static int intel_no_modeset_on_lid_dmi_callback(const struct dmi_system_id *id) -{ - DRM_INFO("Skipping forced modeset for %s\n", id->ident); - return 1; -} - -/* The GPU hangs up on these systems if modeset is performed on LID open */ -static const struct dmi_system_id intel_no_modeset_on_lid[] = { - { - .callback = intel_no_modeset_on_lid_dmi_callback, - .ident = "Toshiba Tecra A11", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), - DMI_MATCH(DMI_PRODUCT_NAME, "TECRA A11"), - }, - }, - - { } /* terminating entry */ -}; - -/* - * Lid events. Note the use of 'modeset': - * - we set it to MODESET_ON_LID_OPEN on lid close, - * and set it to MODESET_DONE on open - * - we use it as a "only once" bit (ie we ignore - * duplicate events where it was already properly set) - * - the suspend/resume paths will set it to - * MODESET_SUSPENDED and ignore the lid open event, - * because they restore the mode ("lid open"). - */ -static int intel_lid_notify(struct notifier_block *nb, unsigned long val, - void *unused) -{ - struct intel_lvds_connector *lvds_connector = - container_of(nb, struct intel_lvds_connector, lid_notifier); - struct drm_connector *connector = &lvds_connector->base.base; - struct drm_device *dev = connector->dev; - struct drm_i915_private *dev_priv = to_i915(dev); - - if (dev->switch_power_state != DRM_SWITCH_POWER_ON) - return NOTIFY_OK; - - mutex_lock(&dev_priv->modeset_restore_lock); - if (dev_priv->modeset_restore == MODESET_SUSPENDED) - goto exit; - /* - * check and update the status of LVDS connector after receiving - * the LID nofication event. - */ - connector->status = connector->funcs->detect(connector, false); - - /* Don't force modeset on machines where it causes a GPU lockup */ - if (dmi_check_system(intel_no_modeset_on_lid)) - goto exit; - if (!acpi_lid_open()) { - /* do modeset on next lid open event */ - dev_priv->modeset_restore = MODESET_ON_LID_OPEN; - goto exit; - } - - if (dev_priv->modeset_restore == MODESET_DONE) - goto exit; - - /* - * Some old platform's BIOS love to wreak havoc while the lid is closed. - * We try to detect this here and undo any damage. The split for PCH - * platforms is rather conservative and a bit arbitrary expect that on - * those platforms VGA disabling requires actual legacy VGA I/O access, - * and as part of the cleanup in the hw state restore we also redisable - * the vga plane. - */ - if (!HAS_PCH_SPLIT(dev_priv)) - intel_display_resume(dev); - - dev_priv->modeset_restore = MODESET_DONE; - -exit: - mutex_unlock(&dev_priv->modeset_restore_lock); - return NOTIFY_OK; -} - -static int -intel_lvds_connector_register(struct drm_connector *connector) -{ - struct intel_lvds_connector *lvds = to_lvds_connector(connector); - int ret; - - ret = intel_connector_register(connector); - if (ret) - return ret; - - lvds->lid_notifier.notifier_call = intel_lid_notify; - if (acpi_lid_notifier_register(&lvds->lid_notifier)) { - DRM_DEBUG_KMS("lid notifier registration failed\n"); - lvds->lid_notifier.notifier_call = NULL; - } - - return 0; -} - -static void -intel_lvds_connector_unregister(struct drm_connector *connector) -{ - struct intel_lvds_connector *lvds = to_lvds_connector(connector); - - if (lvds->lid_notifier.notifier_call) - acpi_lid_notifier_unregister(&lvds->lid_notifier); - - intel_connector_unregister(connector); -} - /** * intel_lvds_destroy - unregister and free LVDS structures * @connector: connector to free @@ -639,8 +509,8 @@ static const struct drm_connector_funcs intel_lvds_connector_funcs = { .fill_modes = drm_helper_probe_single_connector_modes, .atomic_get_property = intel_digital_connector_atomic_get_property, .atomic_set_property = intel_digital_connector_atomic_set_property, - .late_register = intel_lvds_connector_register, - .early_unregister = intel_lvds_connector_unregister, + .late_register = intel_connector_register, + .early_unregister = intel_connector_unregister, .destroy = intel_lvds_destroy, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, .atomic_duplicate_state = intel_digital_connector_duplicate_state, @@ -1114,8 +984,6 @@ void intel_lvds_init(struct drm_i915_private *dev_priv) * 2) check for VBT data * 3) check to see if LVDS is already on * if none of the above, no panel - * 4) make sure lid is open - * if closed, act like it's not there for now */ /* -- GitLab From b93b41afcee272c13f4aa9df18b46ba40cce37e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Tue, 17 Jul 2018 20:42:15 +0300 Subject: [PATCH 1263/1506] drm/i915: Assume eDP is always connected MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We never registered any kind of lid notifier for eDP, so looking at the lid status is pretty much bonkers. Let's just consider eDP always connected instead. Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180717174216.22252-2-ville.syrjala@linux.intel.com Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> --- drivers/gpu/drm/i915/intel_dp.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 5899cadf11e30..fee23cf93a2b6 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -4406,14 +4406,7 @@ intel_dp_detect_dpcd(struct intel_dp *intel_dp) static enum drm_connector_status edp_detect(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); - enum drm_connector_status status; - - status = intel_panel_detect(dev_priv); - if (status == connector_status_unknown) - status = connector_status_connected; - - return status; + return connector_status_connected; } static bool ibx_digital_port_connected(struct intel_encoder *encoder) @@ -4674,7 +4667,7 @@ intel_dp_long_pulse(struct intel_connector *connector) intel_display_power_get(dev_priv, intel_dp->aux_power_domain); - /* Can't disconnect eDP, but you can close the lid... */ + /* Can't disconnect eDP */ if (intel_dp_is_edp(intel_dp)) status = edp_detect(intel_dp); else if (intel_digital_port_connected(&dp_to_dig_port(intel_dp)->base)) -- GitLab From d81be4f379e732c29e50fbf8fbdbe15980320bf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> Date: Tue, 17 Jul 2018 20:42:16 +0300 Subject: [PATCH 1264/1506] drm/i915: Remove intel_panel_detect() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With neither LVDS or eDP no longer using intel_panel_detect() we can kill it, and the accompanying modparam. Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180717174216.22252-3-ville.syrjala@linux.intel.com Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> --- drivers/gpu/drm/i915/i915_params.c | 4 ---- drivers/gpu/drm/i915/i915_params.h | 1 - drivers/gpu/drm/i915/intel_drv.h | 1 - drivers/gpu/drm/i915/intel_panel.c | 20 -------------------- 4 files changed, 26 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 817576701ed75..295e981e4a398 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -44,10 +44,6 @@ i915_param_named(modeset, int, 0400, "Use kernel modesetting [KMS] (0=disable, " "1=on, -1=force vga console preference [default])"); -i915_param_named_unsafe(panel_ignore_lid, int, 0600, - "Override lid status (0=autodetect, 1=autodetect disabled [default], " - "-1=force lid closed, -2=force lid open)"); - i915_param_named_unsafe(enable_dc, int, 0400, "Enable power-saving display C-states. " "(-1=auto [default]; 0=disable; 1=up to DC5; 2=up to DC6)"); diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h index aebe0469ddaa3..6c4d4a21474b5 100644 --- a/drivers/gpu/drm/i915/i915_params.h +++ b/drivers/gpu/drm/i915/i915_params.h @@ -36,7 +36,6 @@ struct drm_printer; #define I915_PARAMS_FOR_EACH(param) \ param(char *, vbt_firmware, NULL) \ param(int, modeset, -1) \ - param(int, panel_ignore_lid, 1) \ param(int, lvds_channel_mode, 0) \ param(int, panel_use_ssc, -1) \ param(int, vbt_sdvo_panel_type, -1) \ diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 92b68ebc7413b..edcfd85e7b944 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1889,7 +1889,6 @@ void intel_panel_enable_backlight(const struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state); void intel_panel_disable_backlight(const struct drm_connector_state *old_conn_state); void intel_panel_destroy_backlight(struct drm_connector *connector); -enum drm_connector_status intel_panel_detect(struct drm_i915_private *dev_priv); extern struct drm_display_mode *intel_find_panel_downclock( struct drm_i915_private *dev_priv, struct drm_display_mode *fixed_mode, diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 14b827ec54273..4a9f139e7b738 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -375,26 +375,6 @@ void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc, pipe_config->gmch_pfit.lvds_border_bits = border; } -enum drm_connector_status -intel_panel_detect(struct drm_i915_private *dev_priv) -{ - /* Assume that the BIOS does not lie through the OpRegion... */ - if (!i915_modparams.panel_ignore_lid && dev_priv->opregion.lid_state) { - return *dev_priv->opregion.lid_state & 0x1 ? - connector_status_connected : - connector_status_disconnected; - } - - switch (i915_modparams.panel_ignore_lid) { - case -2: - return connector_status_connected; - case -1: - return connector_status_disconnected; - default: - return connector_status_unknown; - } -} - /** * scale - scale values from one range to another * @source_val: value in range [@source_min..@source_max] -- GitLab From ef821e3f14e868779505bf08f96afb4eade53652 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi <rodrigo.vivi@intel.com> Date: Thu, 19 Jul 2018 08:47:59 -0700 Subject: [PATCH 1265/1506] drm/i915: Update DRIVER_DATE to 20180719 Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com> --- drivers/gpu/drm/i915/i915_drv.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 995656f51b574..ef1aabb751c6b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -86,8 +86,8 @@ #define DRIVER_NAME "i915" #define DRIVER_DESC "Intel Graphics" -#define DRIVER_DATE "20180712" -#define DRIVER_TIMESTAMP 1531464866 +#define DRIVER_DATE "20180719" +#define DRIVER_TIMESTAMP 1532015279 /* Use I915_STATE_WARN(x) and I915_STATE_WARN_ON() (rather than WARN() and * WARN_ON()) for hw state sanity checks to check for unexpected conditions -- GitLab From c64fb6dade1637e80ab316be42a271747ac4033b Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexander.deucher@amd.com> Date: Wed, 18 Jul 2018 16:07:11 -0500 Subject: [PATCH 1266/1506] drm/amdgpu/powerplay: use irq source defines for smu7 sources Use the newly added irq source defines rather than magic numbers for smu7 thermal interrupts. Rewiewed-by: Chunming Zhou <david1.zhou@amd.com> Reviewed-by: Rex Zhu <rezhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.c index 8eea49e4c74de..2aab1b4759459 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu_helper.c @@ -27,6 +27,7 @@ #include "atom.h" #include "ivsrcid/thm/irqsrcs_thm_9_0.h" #include "ivsrcid/smuio/irqsrcs_smuio_9_0.h" +#include "ivsrcid/ivsrcid_vislands30.h" uint8_t convert_to_vid(uint16_t vddc) { @@ -545,17 +546,17 @@ int phm_irq_process(struct amdgpu_device *adev, uint32_t src_id = entry->src_id; if (client_id == AMDGPU_IH_CLIENTID_LEGACY) { - if (src_id == 230) + if (src_id == VISLANDS30_IV_SRCID_CG_TSS_THERMAL_LOW_TO_HIGH) pr_warn("GPU over temperature range detected on PCIe %d:%d.%d!\n", PCI_BUS_NUM(adev->pdev->devfn), PCI_SLOT(adev->pdev->devfn), PCI_FUNC(adev->pdev->devfn)); - else if (src_id == 231) + else if (src_id == VISLANDS30_IV_SRCID_CG_TSS_THERMAL_HIGH_TO_LOW) pr_warn("GPU under temperature range detected on PCIe %d:%d.%d!\n", PCI_BUS_NUM(adev->pdev->devfn), PCI_SLOT(adev->pdev->devfn), PCI_FUNC(adev->pdev->devfn)); - else if (src_id == 83) + else if (src_id == VISLANDS30_IV_SRCID_GPIO_19) pr_warn("GPU Critical Temperature Fault detected on PCIe %d:%d.%d!\n", PCI_BUS_NUM(adev->pdev->devfn), PCI_SLOT(adev->pdev->devfn), -- GitLab From 1ce0688f3f6a9e9d34ae66bf779d54855def7bec Mon Sep 17 00:00:00 2001 From: Evan Quan <evan.quan@amd.com> Date: Thu, 19 Jul 2018 13:21:43 +0800 Subject: [PATCH 1267/1506] drm/amd/powerplay: fixed uninitialized value The 'result' is not initialized correctly. It causes the API return an error code even on success. Signed-off-by: Evan Quan <evan.quan@amd.com> Acked-by: Huang Rui <ray.huang@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c index 912d0d6cf4765..4ed218dd8ba7a 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c @@ -488,7 +488,7 @@ static int vega12_get_number_of_dpm_level(struct pp_hwmgr *hwmgr, static int vega12_get_dpm_frequency_by_index(struct pp_hwmgr *hwmgr, PPCLK_e clkID, uint32_t index, uint32_t *clock) { - int result; + int result = 0; /* *SMU expects the Clock ID to be in the top 16 bits. -- GitLab From 4841203102a337b4b627e6dd3a1dc8c88aec982b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= <michel.daenzer@amd.com> Date: Tue, 17 Jul 2018 12:37:45 +0200 Subject: [PATCH 1268/1506] drm/amdgpu/display: Replace CONFIG_DRM_AMD_DC_DCN1_0 with CONFIG_X86 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allowing CONFIG_DRM_AMD_DC_DCN1_0 to be disabled on X86 was an opportunity for display with Raven Ridge accidentally not working. Reviewed-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Michel Dänzer <michel.daenzer@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 2 +- drivers/gpu/drm/amd/display/Kconfig | 8 -------- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 8 ++++---- drivers/gpu/drm/amd/display/dc/Makefile | 2 +- .../display/dc/bios/command_table_helper2.c | 2 +- drivers/gpu/drm/amd/display/dc/calcs/Makefile | 2 +- drivers/gpu/drm/amd/display/dc/core/dc.c | 6 +++--- .../gpu/drm/amd/display/dc/core/dc_debug.c | 2 +- .../gpu/drm/amd/display/dc/core/dc_resource.c | 12 +++++------ drivers/gpu/drm/amd/display/dc/dc.h | 2 +- .../drm/amd/display/dc/dce/dce_clock_source.c | 6 +++--- .../drm/amd/display/dc/dce/dce_clock_source.h | 2 +- .../gpu/drm/amd/display/dc/dce/dce_clocks.c | 8 ++++---- .../gpu/drm/amd/display/dc/dce/dce_clocks.h | 2 +- drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c | 6 +++--- .../amd/display/dc/dce/dce_stream_encoder.c | 20 +++++++++---------- .../display/dc/dce110/dce110_hw_sequencer.c | 2 +- drivers/gpu/drm/amd/display/dc/gpio/Makefile | 2 +- .../gpu/drm/amd/display/dc/gpio/hw_factory.c | 4 ++-- .../drm/amd/display/dc/gpio/hw_translate.c | 4 ++-- .../gpu/drm/amd/display/dc/i2caux/Makefile | 2 +- .../gpu/drm/amd/display/dc/i2caux/i2caux.c | 4 ++-- .../gpu/drm/amd/display/dc/inc/core_types.h | 6 +++--- drivers/gpu/drm/amd/display/dc/irq/Makefile | 2 +- .../gpu/drm/amd/display/dc/irq/irq_service.c | 2 +- drivers/gpu/drm/amd/display/dc/os_types.h | 2 +- 26 files changed, 56 insertions(+), 64 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 2b2de5f3e6e35..386a7b34d2f46 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -2200,7 +2200,7 @@ bool amdgpu_device_asic_has_dc_support(enum amd_asic_type asic_type) case CHIP_VEGA10: case CHIP_VEGA12: case CHIP_VEGA20: -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 case CHIP_RAVEN: #endif return amdgpu_dc != 0; diff --git a/drivers/gpu/drm/amd/display/Kconfig b/drivers/gpu/drm/amd/display/Kconfig index 4c35625eb2c77..325083b0297e4 100644 --- a/drivers/gpu/drm/amd/display/Kconfig +++ b/drivers/gpu/drm/amd/display/Kconfig @@ -9,14 +9,6 @@ config DRM_AMD_DC support for AMDGPU. This adds required support for Vega and Raven ASICs. -config DRM_AMD_DC_DCN1_0 - bool "DCN 1.0 Raven family" - depends on DRM_AMD_DC && X86 - default y - help - Choose this option if you want to have - RV family for display engine - config DEBUG_KERNEL_DC bool "Enable kgdb break in DC" depends on DRM_AMD_DC 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 e0cf54ccc9f46..2064cb21d0ed7 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -60,7 +60,7 @@ #include "modules/inc/mod_freesync.h" -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 #include "ivsrcid/irqsrcs_dcn_1_0.h" #include "dcn/dcn_1_0_offset.h" @@ -1192,7 +1192,7 @@ static int dce110_register_irq_handlers(struct amdgpu_device *adev) return 0; } -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 /* Register IRQ sources and initialize IRQ callbacks */ static int dcn10_register_irq_handlers(struct amdgpu_device *adev) { @@ -1526,7 +1526,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) goto fail; } break; -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 case CHIP_RAVEN: if (dcn10_register_irq_handlers(dm->adev)) { DRM_ERROR("DM: Failed to initialize IRQ\n"); @@ -1725,7 +1725,7 @@ static int dm_early_init(void *handle) adev->mode_info.num_dig = 6; adev->mode_info.plane_type = dm_plane_type_default; break; -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 case CHIP_RAVEN: adev->mode_info.num_crtc = 4; adev->mode_info.num_hpd = 4; diff --git a/drivers/gpu/drm/amd/display/dc/Makefile b/drivers/gpu/drm/amd/display/dc/Makefile index aed538a4d1bac..532a515fda9a1 100644 --- a/drivers/gpu/drm/amd/display/dc/Makefile +++ b/drivers/gpu/drm/amd/display/dc/Makefile @@ -25,7 +25,7 @@ DC_LIBS = basics bios calcs dce gpio i2caux irq virtual -ifdef CONFIG_DRM_AMD_DC_DCN1_0 +ifdef CONFIG_X86 DC_LIBS += dcn10 dml endif diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c index bbbcef566c551..770ff89ba7e17 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c @@ -55,7 +55,7 @@ bool dal_bios_parser_init_cmd_tbl_helper2( case DCE_VERSION_11_22: *h = dal_cmd_tbl_helper_dce112_get_table2(); return true; -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 case DCN_VERSION_1_0: *h = dal_cmd_tbl_helper_dce112_get_table2(); return true; diff --git a/drivers/gpu/drm/amd/display/dc/calcs/Makefile b/drivers/gpu/drm/amd/display/dc/calcs/Makefile index 95f332ee3e7e6..416500e51b8dd 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/Makefile +++ b/drivers/gpu/drm/amd/display/dc/calcs/Makefile @@ -38,7 +38,7 @@ CFLAGS_dcn_calc_math.o := $(calcs_ccflags) -Wno-tautological-compare BW_CALCS = dce_calcs.o bw_fixed.o custom_float.o -ifdef CONFIG_DRM_AMD_DC_DCN1_0 +ifdef CONFIG_X86 BW_CALCS += dcn_calcs.o dcn_calc_math.o dcn_calc_auto.o endif diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index cb0be7f6994ca..733ac224e7fdc 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -476,7 +476,7 @@ static void destruct(struct dc *dc) kfree(dc->bw_dceip); dc->bw_dceip = NULL; -#ifdef CONFIG_DRM_AMD_DC_DCN1_0 +#ifdef CONFIG_X86 kfree(dc->dcn_soc); dc->dcn_soc = NULL; @@ -492,7 +492,7 @@ static bool construct(struct dc *dc, struct dc_context *dc_ctx; struct bw_calcs_dceip *dc_dceip; struct bw_calcs_vbios *dc_vbios; -#ifdef CONFIG_DRM_AMD_DC_DCN1_0 +#ifdef CONFIG_X86 struct dcn_soc_bounding_box *dcn_soc; struct dcn_ip_params *dcn_ip; #endif @@ -514,7 +514,7 @@ static bool construct(struct dc *dc, } dc->bw_vbios = dc_vbios; -#ifdef CONFIG_DRM_AMD_DC_DCN1_0 +#ifdef CONFIG_X86 dcn_soc = kzalloc(sizeof(*dcn_soc), GFP_KERNEL); if (!dcn_soc) { dm_error("%s: failed to create dcn_soc\n", __func__); diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_debug.c b/drivers/gpu/drm/amd/display/dc/core/dc_debug.c index e1ebdf7b5eaf3..caece7c13bc64 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_debug.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_debug.c @@ -348,7 +348,7 @@ void context_clock_trace( struct dc *dc, struct dc_state *context) { -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 DC_LOGGER_INIT(dc->ctx->logger); CLOCK_TRACE("Current: dispclk_khz:%d max_dppclk_khz:%d dcfclk_khz:%d\n" "dcfclk_deep_sleep_khz:%d fclk_khz:%d socclk_khz:%d\n", 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 9abe5481e40c8..2e65715f76a1c 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -41,7 +41,7 @@ #include "dce100/dce100_resource.h" #include "dce110/dce110_resource.h" #include "dce112/dce112_resource.h" -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 #include "dcn10/dcn10_resource.h" #endif #include "dce120/dce120_resource.h" @@ -85,7 +85,7 @@ enum dce_version resource_parse_asic_id(struct hw_asic_id asic_id) case FAMILY_AI: dc_version = DCE_VERSION_12_0; break; -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 case FAMILY_RV: dc_version = DCN_VERSION_1_0; break; @@ -136,7 +136,7 @@ struct resource_pool *dc_create_resource_pool( num_virtual_links, dc); break; -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 case DCN_VERSION_1_0: res_pool = dcn10_create_resource_pool( num_virtual_links, dc); @@ -1213,7 +1213,7 @@ static struct pipe_ctx *acquire_free_pipe_for_stream( } -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 static int acquire_first_split_pipe( struct resource_context *res_ctx, const struct resource_pool *pool, @@ -1284,7 +1284,7 @@ bool dc_add_plane_to_context( free_pipe = acquire_free_pipe_for_stream(context, pool, stream); -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 if (!free_pipe) { int pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream); if (pipe_idx >= 0) @@ -1882,7 +1882,7 @@ enum dc_status resource_map_pool_resources( /* acquire new resources */ pipe_idx = acquire_first_free_pipe(&context->res_ctx, pool, stream); -#ifdef CONFIG_DRM_AMD_DC_DCN1_0 +#ifdef CONFIG_X86 if (pipe_idx < 0) pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream); #endif diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index b10dc177ad61c..ceb4c37258936 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -289,7 +289,7 @@ struct dc { /* Inputs into BW and WM calculations. */ struct bw_calcs_dceip *bw_dceip; struct bw_calcs_vbios *bw_vbios; -#ifdef CONFIG_DRM_AMD_DC_DCN1_0 +#ifdef CONFIG_X86 struct dcn_soc_bounding_box *dcn_soc; struct dcn_ip_params *dcn_ip; struct display_mode_lib dml; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c index ca137757a69e1..439dcf3b596cc 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c @@ -592,7 +592,7 @@ static uint32_t dce110_get_pix_clk_dividers( case DCE_VERSION_11_2: case DCE_VERSION_11_22: case DCE_VERSION_12_0: -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 case DCN_VERSION_1_0: #endif @@ -909,7 +909,7 @@ static bool dce110_program_pix_clk( struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source); struct bp_pixel_clock_parameters bp_pc_params = {0}; -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 if (IS_FPGA_MAXIMUS_DC(clock_source->ctx->dce_environment)) { unsigned int inst = pix_clk_params->controller_id - CONTROLLER_ID_D0; unsigned dp_dto_ref_kHz = 700000; @@ -982,7 +982,7 @@ static bool dce110_program_pix_clk( case DCE_VERSION_11_2: case DCE_VERSION_11_22: case DCE_VERSION_12_0: -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 case DCN_VERSION_1_0: #endif diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h index c45e2f76189e7..801bb65707b32 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h @@ -55,7 +55,7 @@ CS_SF(PHYPLLA_PIXCLK_RESYNC_CNTL, PHYPLLA_DCCG_DEEP_COLOR_CNTL, mask_sh),\ CS_SF(PHYPLLA_PIXCLK_RESYNC_CNTL, PHYPLLA_PIXCLK_DOUBLE_RATE_ENABLE, mask_sh) -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 #define CS_COMMON_REG_LIST_DCN1_0(index, pllid) \ SRI(PIXCLK_RESYNC_CNTL, PHYPLL, pllid),\ diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c index 6882dc953a2c2..8f8a2abac3f30 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c @@ -30,7 +30,7 @@ #include "bios_parser_interface.h" #include "dc.h" #include "dmcu.h" -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 #include "dcn_calcs.h" #endif #include "core_types.h" @@ -478,7 +478,7 @@ static void dce12_update_clocks(struct dccg *dccg, } } -#ifdef CONFIG_DRM_AMD_DC_DCN1_0 +#ifdef CONFIG_X86 static int dcn1_determine_dppclk_threshold(struct dccg *dccg, struct dc_clocks *new_clocks) { bool request_dpp_div = new_clocks->dispclk_khz > new_clocks->dppclk_khz; @@ -666,7 +666,7 @@ static void dce_update_clocks(struct dccg *dccg, } } -#ifdef CONFIG_DRM_AMD_DC_DCN1_0 +#ifdef CONFIG_X86 static const struct display_clock_funcs dcn1_funcs = { .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz, .set_dispclk = dce112_set_clock, @@ -821,7 +821,7 @@ struct dccg *dce120_dccg_create(struct dc_context *ctx) return &clk_dce->base; } -#ifdef CONFIG_DRM_AMD_DC_DCN1_0 +#ifdef CONFIG_X86 struct dccg *dcn1_dccg_create(struct dc_context *ctx) { struct dc_debug *debug = &ctx->dc->debug; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h index 8a6b2d328467c..e5e44adc6c27c 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h @@ -111,7 +111,7 @@ struct dccg *dce112_dccg_create( struct dccg *dce120_dccg_create(struct dc_context *ctx); -#ifdef CONFIG_DRM_AMD_DC_DCN1_0 +#ifdef CONFIG_X86 struct dccg *dcn1_dccg_create(struct dc_context *ctx); #endif diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c index a576b8bbb3cd4..062a46543887a 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c @@ -314,7 +314,7 @@ static void dce_get_psr_wait_loop( return; } -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 static void dcn10_get_dmcu_state(struct dmcu *dmcu) { struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu); @@ -735,7 +735,7 @@ static const struct dmcu_funcs dce_funcs = { .is_dmcu_initialized = dce_is_dmcu_initialized }; -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 static const struct dmcu_funcs dcn10_funcs = { .dmcu_init = dcn10_dmcu_init, .load_iram = dcn10_dmcu_load_iram, @@ -787,7 +787,7 @@ struct dmcu *dce_dmcu_create( return &dmcu_dce->base; } -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 struct dmcu *dcn10_dmcu_create( struct dc_context *ctx, const struct dce_dmcu_registers *regs, 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 91642e6848587..b139b40178200 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 @@ -135,7 +135,7 @@ static void dce110_update_generic_info_packet( AFMT_GENERIC0_UPDATE, (packet_index == 0), AFMT_GENERIC2_UPDATE, (packet_index == 2)); } -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 if (REG(AFMT_VBI_PACKET_CONTROL1)) { switch (packet_index) { case 0: @@ -229,7 +229,7 @@ static void dce110_update_hdmi_info_packet( HDMI_GENERIC1_SEND, send, HDMI_GENERIC1_LINE, line); break; -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 case 4: if (REG(HDMI_GENERIC_PACKET_CONTROL2)) REG_UPDATE_3(HDMI_GENERIC_PACKET_CONTROL2, @@ -274,7 +274,7 @@ static void dce110_stream_encoder_dp_set_stream_attribute( struct dc_crtc_timing *crtc_timing, enum dc_color_space output_color_space) { -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 uint32_t h_active_start; uint32_t v_active_start; uint32_t misc0 = 0; @@ -317,7 +317,7 @@ static void dce110_stream_encoder_dp_set_stream_attribute( if (enc110->se_mask->DP_VID_M_DOUBLE_VALUE_EN) REG_UPDATE(DP_VID_TIMING, DP_VID_M_DOUBLE_VALUE_EN, 1); -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 if (enc110->se_mask->DP_VID_N_MUL) REG_UPDATE(DP_VID_TIMING, DP_VID_N_MUL, 1); #endif @@ -328,7 +328,7 @@ static void dce110_stream_encoder_dp_set_stream_attribute( break; } -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 if (REG(DP_MSA_MISC)) misc1 = REG_READ(DP_MSA_MISC); #endif @@ -362,7 +362,7 @@ static void dce110_stream_encoder_dp_set_stream_attribute( /* set dynamic range and YCbCr range */ -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 switch (crtc_timing->display_color_depth) { case COLOR_DEPTH_666: colorimetry_bpc = 0; @@ -441,7 +441,7 @@ static void dce110_stream_encoder_dp_set_stream_attribute( DP_DYN_RANGE, dynamic_range_rgb, DP_YCBCR_RANGE, dynamic_range_ycbcr); -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 if (REG(DP_MSA_COLORIMETRY)) REG_SET(DP_MSA_COLORIMETRY, 0, DP_MSA_MISC0, misc0); @@ -476,7 +476,7 @@ static void dce110_stream_encoder_dp_set_stream_attribute( crtc_timing->v_front_porch; -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 /* start at begining of left border */ if (REG(DP_MSA_TIMING_PARAM2)) REG_SET_2(DP_MSA_TIMING_PARAM2, 0, @@ -751,7 +751,7 @@ static void dce110_stream_encoder_update_hdmi_info_packets( dce110_update_hdmi_info_packet(enc110, 3, &info_frame->hdrsmd); } -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 if (enc110->se_mask->HDMI_DB_DISABLE) { /* for bring up, disable dp double TODO */ if (REG(HDMI_DB_CONTROL)) @@ -789,7 +789,7 @@ static void dce110_stream_encoder_stop_hdmi_info_packets( HDMI_GENERIC1_LINE, 0, HDMI_GENERIC1_SEND, 0); -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 /* stop generic packets 2 & 3 on HDMI */ if (REG(HDMI_GENERIC_PACKET_CONTROL2)) REG_SET_6(HDMI_GENERIC_PACKET_CONTROL2, 0, 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 45388bff2c7dc..33a14e163f880 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 @@ -1250,7 +1250,7 @@ static void program_scaler(const struct dc *dc, { struct tg_color color = {0}; -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 /* TOFPGA */ if (pipe_ctx->plane_res.xfm->funcs->transform_set_pixel_storage_depth == NULL) return; diff --git a/drivers/gpu/drm/amd/display/dc/gpio/Makefile b/drivers/gpu/drm/amd/display/dc/gpio/Makefile index 562ee189d780c..b9d9930a49743 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/Makefile +++ b/drivers/gpu/drm/amd/display/dc/gpio/Makefile @@ -61,7 +61,7 @@ AMD_DISPLAY_FILES += $(AMD_DAL_GPIO_DCE120) ############################################################################### # DCN 1x ############################################################################### -ifdef CONFIG_DRM_AMD_DC_DCN1_0 +ifdef CONFIG_X86 GPIO_DCN10 = hw_translate_dcn10.o hw_factory_dcn10.o AMD_DAL_GPIO_DCN10 = $(addprefix $(AMDDALPATH)/dc/gpio/dcn10/,$(GPIO_DCN10)) diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c b/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c index 0caee3523017f..83df779984e5d 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c @@ -43,7 +43,7 @@ #include "dce80/hw_factory_dce80.h" #include "dce110/hw_factory_dce110.h" #include "dce120/hw_factory_dce120.h" -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 #include "dcn10/hw_factory_dcn10.h" #endif @@ -81,7 +81,7 @@ bool dal_hw_factory_init( case DCE_VERSION_12_0: dal_hw_factory_dce120_init(factory); return true; -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 case DCN_VERSION_1_0: dal_hw_factory_dcn10_init(factory); return true; diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c b/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c index 55c7074885413..e7541310480b1 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c @@ -43,7 +43,7 @@ #include "dce80/hw_translate_dce80.h" #include "dce110/hw_translate_dce110.h" #include "dce120/hw_translate_dce120.h" -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 #include "dcn10/hw_translate_dcn10.h" #endif @@ -78,7 +78,7 @@ bool dal_hw_translate_init( case DCE_VERSION_12_0: dal_hw_translate_dce120_init(translate); return true; -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 case DCN_VERSION_1_0: dal_hw_translate_dcn10_init(translate); return true; diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/Makefile b/drivers/gpu/drm/amd/display/dc/i2caux/Makefile index 352885cb4d076..a851d07f01901 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/Makefile +++ b/drivers/gpu/drm/amd/display/dc/i2caux/Makefile @@ -71,7 +71,7 @@ AMD_DISPLAY_FILES += $(AMD_DAL_I2CAUX_DCE112) ############################################################################### # DCN 1.0 family ############################################################################### -ifdef CONFIG_DRM_AMD_DC_DCN1_0 +ifdef CONFIG_X86 I2CAUX_DCN1 = i2caux_dcn10.o AMD_DAL_I2CAUX_DCN1 = $(addprefix $(AMDDALPATH)/dc/i2caux/dcn10/,$(I2CAUX_DCN1)) diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c b/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c index 9b0bcc6b769b5..f7ed355fc84f4 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c +++ b/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c @@ -59,7 +59,7 @@ #include "dce120/i2caux_dce120.h" -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 #include "dcn10/i2caux_dcn10.h" #endif @@ -91,7 +91,7 @@ struct i2caux *dal_i2caux_create( return dal_i2caux_dce100_create(ctx); case DCE_VERSION_12_0: return dal_i2caux_dce120_create(ctx); -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 case DCN_VERSION_1_0: return dal_i2caux_dcn10_create(ctx); #endif diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h index 1db26bc0bec3a..4446652a9a9e4 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h @@ -33,7 +33,7 @@ #include "dc_bios_types.h" #include "mem_input.h" #include "hubp.h" -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 #include "mpc.h" #endif @@ -221,7 +221,7 @@ struct pipe_ctx { struct pipe_ctx *top_pipe; struct pipe_ctx *bottom_pipe; -#ifdef CONFIG_DRM_AMD_DC_DCN1_0 +#ifdef CONFIG_X86 struct _vcs_dpi_display_dlg_regs_st dlg_regs; struct _vcs_dpi_display_ttu_regs_st ttu_regs; struct _vcs_dpi_display_rq_regs_st rq_regs; @@ -276,7 +276,7 @@ struct dc_state { /* Note: these are big structures, do *not* put on stack! */ struct dm_pp_display_configuration pp_display_cfg; -#ifdef CONFIG_DRM_AMD_DC_DCN1_0 +#ifdef CONFIG_X86 struct dcn_bw_internal_vars dcn_bw_vars; #endif diff --git a/drivers/gpu/drm/amd/display/dc/irq/Makefile b/drivers/gpu/drm/amd/display/dc/irq/Makefile index 498515aad4a50..a76ee600eceea 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/Makefile +++ b/drivers/gpu/drm/amd/display/dc/irq/Makefile @@ -60,7 +60,7 @@ AMD_DISPLAY_FILES += $(AMD_DAL_IRQ_DCE12) ############################################################################### # DCN 1x ############################################################################### -ifdef CONFIG_DRM_AMD_DC_DCN1_0 +ifdef CONFIG_X86 IRQ_DCN1 = irq_service_dcn10.o AMD_DAL_IRQ_DCN1 = $(addprefix $(AMDDALPATH)/dc/irq/dcn10/,$(IRQ_DCN1)) diff --git a/drivers/gpu/drm/amd/display/dc/irq/irq_service.c b/drivers/gpu/drm/amd/display/dc/irq/irq_service.c index 604bea01fc13e..ae3fd0a235ba4 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/irq_service.c +++ b/drivers/gpu/drm/amd/display/dc/irq/irq_service.c @@ -36,7 +36,7 @@ #include "dce120/irq_service_dce120.h" -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 #include "dcn10/irq_service_dcn10.h" #endif diff --git a/drivers/gpu/drm/amd/display/dc/os_types.h b/drivers/gpu/drm/amd/display/dc/os_types.h index a407892905af2..c9fce9066ad8b 100644 --- a/drivers/gpu/drm/amd/display/dc/os_types.h +++ b/drivers/gpu/drm/amd/display/dc/os_types.h @@ -48,7 +48,7 @@ #define dm_error(fmt, ...) DRM_ERROR(fmt, ##__VA_ARGS__) -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) +#ifdef CONFIG_X86 #include <asm/fpu/api.h> #endif -- GitLab From 58c24b7c893cb1739918c875ae3cf4bb5f86ebb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Wed, 18 Jul 2018 20:28:08 +0200 Subject: [PATCH 1269/1506] drm/amdgpu: remove superflous UVD encode entity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not sure what that was every used for, but now it is completely unused. Reviewed-by: Leo Liu <leo.liu@amd.com> Signed-off-by: Christian König <christian.koenig@amd.com> Acked-by: Chunming Zhou <david1.zhou@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.h | 1 - drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c | 12 ------------ drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c | 14 -------------- 3 files changed, 27 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.h index 8b23a1b00c76c..cae3f526216b6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.h @@ -48,7 +48,6 @@ struct amdgpu_uvd_inst { struct amdgpu_ring ring_enc[AMDGPU_MAX_UVD_ENC_RINGS]; struct amdgpu_irq_src irq; struct drm_sched_entity entity; - struct drm_sched_entity entity_enc; uint32_t srbm_soft_reset; }; diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c index b796dc8375cd1..598dbeaba6368 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c @@ -418,16 +418,6 @@ static int uvd_v6_0_sw_init(void *handle) adev->uvd.num_enc_rings = 0; DRM_INFO("UVD ENC is disabled\n"); - } else { - struct drm_sched_rq *rq; - ring = &adev->uvd.inst->ring_enc[0]; - rq = &ring->sched.sched_rq[DRM_SCHED_PRIORITY_NORMAL]; - r = drm_sched_entity_init(&adev->uvd.inst->entity_enc, - &rq, 1, NULL); - if (r) { - DRM_ERROR("Failed setting up UVD ENC run queue.\n"); - return r; - } } r = amdgpu_uvd_resume(adev); @@ -463,8 +453,6 @@ static int uvd_v6_0_sw_fini(void *handle) return r; if (uvd_v6_0_enc_support(adev)) { - drm_sched_entity_destroy(&adev->uvd.inst->ring_enc[0].sched, &adev->uvd.inst->entity_enc); - for (i = 0; i < adev->uvd.num_enc_rings; ++i) amdgpu_ring_fini(&adev->uvd.inst->ring_enc[i]); } diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c index 831bb995b0ed9..db5f3d78ab12a 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c @@ -389,7 +389,6 @@ static int uvd_v7_0_early_init(void *handle) static int uvd_v7_0_sw_init(void *handle) { struct amdgpu_ring *ring; - struct drm_sched_rq *rq; int i, j, r; struct amdgpu_device *adev = (struct amdgpu_device *)handle; @@ -421,17 +420,6 @@ static int uvd_v7_0_sw_init(void *handle) DRM_INFO("PSP loading UVD firmware\n"); } - for (j = 0; j < adev->uvd.num_uvd_inst; j++) { - ring = &adev->uvd.inst[j].ring_enc[0]; - rq = &ring->sched.sched_rq[DRM_SCHED_PRIORITY_NORMAL]; - r = drm_sched_entity_init(&adev->uvd.inst[j].entity_enc, - &rq, 1, NULL); - if (r) { - DRM_ERROR("(%d)Failed setting up UVD ENC run queue.\n", j); - return r; - } - } - r = amdgpu_uvd_resume(adev); if (r) return r; @@ -484,8 +472,6 @@ static int uvd_v7_0_sw_fini(void *handle) return r; for (j = 0; j < adev->uvd.num_uvd_inst; ++j) { - drm_sched_entity_destroy(&adev->uvd.inst[j].ring_enc[0].sched, &adev->uvd.inst[j].entity_enc); - for (i = 0; i < adev->uvd.num_enc_rings; ++i) amdgpu_ring_fini(&adev->uvd.inst[j].ring_enc[i]); } -- GitLab From 5c675bf2c67c4efb36a78bebf44dc435db2daf16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Wed, 18 Jul 2018 20:30:51 +0200 Subject: [PATCH 1270/1506] drm/amdgpu: clean up UVD instance handling v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The whole handle, filp and entity handling is superfluous here. We should have reviewed that more thoughtfully. It looks like somebody just made the code instance aware without knowing the background. v2: fix one more missed case in amdgpu_uvd_suspend Reviewed-by: Leo Liu <leo.liu@amd.com> Signed-off-by: Christian König <christian.koenig@amd.com> Acked-by: Chunming Zhou <david1.zhou@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 121 ++++++++++++------------ drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.h | 10 +- 2 files changed, 64 insertions(+), 67 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c index d708970244eb7..80b5c453f8c11 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c @@ -263,21 +263,20 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev) dev_err(adev->dev, "(%d) failed to allocate UVD bo\n", r); return r; } + } - ring = &adev->uvd.inst[j].ring; - rq = &ring->sched.sched_rq[DRM_SCHED_PRIORITY_NORMAL]; - r = drm_sched_entity_init(&adev->uvd.inst[j].entity, &rq, - 1, NULL); - if (r != 0) { - DRM_ERROR("Failed setting up UVD(%d) run queue.\n", j); - return r; - } - - for (i = 0; i < adev->uvd.max_handles; ++i) { - atomic_set(&adev->uvd.inst[j].handles[i], 0); - adev->uvd.inst[j].filp[i] = NULL; - } + ring = &adev->uvd.inst[0].ring; + rq = &ring->sched.sched_rq[DRM_SCHED_PRIORITY_NORMAL]; + r = drm_sched_entity_init(&adev->uvd.entity, &rq, 1, NULL); + if (r) { + DRM_ERROR("Failed setting up UVD kernel entity.\n"); + return r; } + for (i = 0; i < adev->uvd.max_handles; ++i) { + atomic_set(&adev->uvd.handles[i], 0); + adev->uvd.filp[i] = NULL; + } + /* from uvd v5.0 HW addressing capacity increased to 64 bits */ if (!amdgpu_device_ip_block_version_cmp(adev, AMD_IP_BLOCK_TYPE_UVD, 5, 0)) adev->uvd.address_64_bit = true; @@ -306,11 +305,12 @@ int amdgpu_uvd_sw_fini(struct amdgpu_device *adev) { int i, j; + drm_sched_entity_destroy(&adev->uvd.inst->ring.sched, + &adev->uvd.entity); + for (j = 0; j < adev->uvd.num_uvd_inst; ++j) { kfree(adev->uvd.inst[j].saved_bo); - drm_sched_entity_destroy(&adev->uvd.inst[j].ring.sched, &adev->uvd.inst[j].entity); - amdgpu_bo_free_kernel(&adev->uvd.inst[j].vcpu_bo, &adev->uvd.inst[j].gpu_addr, (void **)&adev->uvd.inst[j].cpu_addr); @@ -333,20 +333,20 @@ int amdgpu_uvd_suspend(struct amdgpu_device *adev) cancel_delayed_work_sync(&adev->uvd.idle_work); + /* only valid for physical mode */ + if (adev->asic_type < CHIP_POLARIS10) { + for (i = 0; i < adev->uvd.max_handles; ++i) + if (atomic_read(&adev->uvd.handles[i])) + break; + + if (i == adev->uvd.max_handles) + return 0; + } + for (j = 0; j < adev->uvd.num_uvd_inst; ++j) { if (adev->uvd.inst[j].vcpu_bo == NULL) continue; - /* only valid for physical mode */ - if (adev->asic_type < CHIP_POLARIS10) { - for (i = 0; i < adev->uvd.max_handles; ++i) - if (atomic_read(&adev->uvd.inst[j].handles[i])) - break; - - if (i == adev->uvd.max_handles) - continue; - } - size = amdgpu_bo_size(adev->uvd.inst[j].vcpu_bo); ptr = adev->uvd.inst[j].cpu_addr; @@ -398,30 +398,27 @@ int amdgpu_uvd_resume(struct amdgpu_device *adev) void amdgpu_uvd_free_handles(struct amdgpu_device *adev, struct drm_file *filp) { - struct amdgpu_ring *ring; - int i, j, r; - - for (j = 0; j < adev->uvd.num_uvd_inst; j++) { - ring = &adev->uvd.inst[j].ring; + struct amdgpu_ring *ring = &adev->uvd.inst[0].ring; + int i, r; - for (i = 0; i < adev->uvd.max_handles; ++i) { - uint32_t handle = atomic_read(&adev->uvd.inst[j].handles[i]); - if (handle != 0 && adev->uvd.inst[j].filp[i] == filp) { - struct dma_fence *fence; - - r = amdgpu_uvd_get_destroy_msg(ring, handle, - false, &fence); - if (r) { - DRM_ERROR("Error destroying UVD(%d) %d!\n", j, r); - continue; - } + for (i = 0; i < adev->uvd.max_handles; ++i) { + uint32_t handle = atomic_read(&adev->uvd.handles[i]); - dma_fence_wait(fence, false); - dma_fence_put(fence); + if (handle != 0 && adev->uvd.filp[i] == filp) { + struct dma_fence *fence; - adev->uvd.inst[j].filp[i] = NULL; - atomic_set(&adev->uvd.inst[j].handles[i], 0); + r = amdgpu_uvd_get_destroy_msg(ring, handle, false, + &fence); + if (r) { + DRM_ERROR("Error destroying UVD %d!\n", r); + continue; } + + dma_fence_wait(fence, false); + dma_fence_put(fence); + + adev->uvd.filp[i] = NULL; + atomic_set(&adev->uvd.handles[i], 0); } } } @@ -692,20 +689,19 @@ static int amdgpu_uvd_cs_msg(struct amdgpu_uvd_cs_ctx *ctx, struct amdgpu_bo *bo, unsigned offset) { struct amdgpu_device *adev = ctx->parser->adev; - uint32_t ip_instance = ctx->parser->ring->me; int32_t *msg, msg_type, handle; void *ptr; long r; int i; if (offset & 0x3F) { - DRM_ERROR("UVD(%d) messages must be 64 byte aligned!\n", ip_instance); + DRM_ERROR("UVD messages must be 64 byte aligned!\n"); return -EINVAL; } r = amdgpu_bo_kmap(bo, &ptr); if (r) { - DRM_ERROR("Failed mapping the UVD(%d) message (%ld)!\n", ip_instance, r); + DRM_ERROR("Failed mapping the UVD) message (%ld)!\n", r); return r; } @@ -715,7 +711,7 @@ static int amdgpu_uvd_cs_msg(struct amdgpu_uvd_cs_ctx *ctx, handle = msg[2]; if (handle == 0) { - DRM_ERROR("Invalid UVD(%d) handle!\n", ip_instance); + DRM_ERROR("Invalid UVD handle!\n"); return -EINVAL; } @@ -726,18 +722,19 @@ static int amdgpu_uvd_cs_msg(struct amdgpu_uvd_cs_ctx *ctx, /* try to alloc a new handle */ for (i = 0; i < adev->uvd.max_handles; ++i) { - if (atomic_read(&adev->uvd.inst[ip_instance].handles[i]) == handle) { - DRM_ERROR("(%d)Handle 0x%x already in use!\n", ip_instance, handle); + if (atomic_read(&adev->uvd.handles[i]) == handle) { + DRM_ERROR(")Handle 0x%x already in use!\n", + handle); return -EINVAL; } - if (!atomic_cmpxchg(&adev->uvd.inst[ip_instance].handles[i], 0, handle)) { - adev->uvd.inst[ip_instance].filp[i] = ctx->parser->filp; + if (!atomic_cmpxchg(&adev->uvd.handles[i], 0, handle)) { + adev->uvd.filp[i] = ctx->parser->filp; return 0; } } - DRM_ERROR("No more free UVD(%d) handles!\n", ip_instance); + DRM_ERROR("No more free UVD handles!\n"); return -ENOSPC; case 1: @@ -749,27 +746,27 @@ static int amdgpu_uvd_cs_msg(struct amdgpu_uvd_cs_ctx *ctx, /* validate the handle */ for (i = 0; i < adev->uvd.max_handles; ++i) { - if (atomic_read(&adev->uvd.inst[ip_instance].handles[i]) == handle) { - if (adev->uvd.inst[ip_instance].filp[i] != ctx->parser->filp) { - DRM_ERROR("UVD(%d) handle collision detected!\n", ip_instance); + if (atomic_read(&adev->uvd.handles[i]) == handle) { + if (adev->uvd.filp[i] != ctx->parser->filp) { + DRM_ERROR("UVD handle collision detected!\n"); return -EINVAL; } return 0; } } - DRM_ERROR("Invalid UVD(%d) handle 0x%x!\n", ip_instance, handle); + DRM_ERROR("Invalid UVD handle 0x%x!\n", handle); return -ENOENT; case 2: /* it's a destroy msg, free the handle */ for (i = 0; i < adev->uvd.max_handles; ++i) - atomic_cmpxchg(&adev->uvd.inst[ip_instance].handles[i], handle, 0); + atomic_cmpxchg(&adev->uvd.handles[i], handle, 0); amdgpu_bo_kunmap(bo); return 0; default: - DRM_ERROR("Illegal UVD(%d) message type (%d)!\n", ip_instance, msg_type); + DRM_ERROR("Illegal UVD message type (%d)!\n", msg_type); return -EINVAL; } BUG(); @@ -1071,7 +1068,7 @@ static int amdgpu_uvd_send_msg(struct amdgpu_ring *ring, struct amdgpu_bo *bo, if (r) goto err_free; - r = amdgpu_job_submit(job, &adev->uvd.inst[ring->me].entity, + r = amdgpu_job_submit(job, &adev->uvd.entity, AMDGPU_FENCE_OWNER_UNDEFINED, &f); if (r) goto err_free; @@ -1273,7 +1270,7 @@ uint32_t amdgpu_uvd_used_handles(struct amdgpu_device *adev) * necessarily linear. So we need to count * all non-zero handles. */ - if (atomic_read(&adev->uvd.inst->handles[i])) + if (atomic_read(&adev->uvd.handles[i])) used_handles++; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.h index cae3f526216b6..66872286ab123 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.h @@ -42,12 +42,9 @@ struct amdgpu_uvd_inst { void *cpu_addr; uint64_t gpu_addr; void *saved_bo; - atomic_t handles[AMDGPU_MAX_UVD_HANDLES]; - struct drm_file *filp[AMDGPU_MAX_UVD_HANDLES]; struct amdgpu_ring ring; struct amdgpu_ring ring_enc[AMDGPU_MAX_UVD_ENC_RINGS]; struct amdgpu_irq_src irq; - struct drm_sched_entity entity; uint32_t srbm_soft_reset; }; @@ -56,10 +53,13 @@ struct amdgpu_uvd { unsigned fw_version; unsigned max_handles; unsigned num_enc_rings; - uint8_t num_uvd_inst; + uint8_t num_uvd_inst; bool address_64_bit; bool use_ctx_buf; - struct amdgpu_uvd_inst inst[AMDGPU_MAX_UVD_INSTANCES]; + struct amdgpu_uvd_inst inst[AMDGPU_MAX_UVD_INSTANCES]; + struct drm_file *filp[AMDGPU_MAX_UVD_HANDLES]; + atomic_t handles[AMDGPU_MAX_UVD_HANDLES]; + struct drm_sched_entity entity; struct delayed_work idle_work; }; -- GitLab From 3f48c6813fc62af183660fbf04edaac7e3615205 Mon Sep 17 00:00:00 2001 From: Colin Ian King <colin.king@canonical.com> Date: Tue, 17 Jul 2018 10:29:29 +0100 Subject: [PATCH 1271/1506] drm/amdgpu: fix spelling mistake "successed" -> "succeeded" Trivial fix to spelling mistake in dev_err error message. Signed-off-by: Colin Ian King <colin.king@canonical.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 386a7b34d2f46..9b8264c761f71 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -2004,7 +2004,7 @@ static int amdgpu_device_ip_reinit_early_sriov(struct amdgpu_device *adev) continue; r = block->version->funcs->hw_init(adev); - DRM_INFO("RE-INIT: %s %s\n", block->version->funcs->name, r?"failed":"successed"); + DRM_INFO("RE-INIT: %s %s\n", block->version->funcs->name, r?"failed":"succeeded"); if (r) return r; } @@ -2039,7 +2039,7 @@ static int amdgpu_device_ip_reinit_late_sriov(struct amdgpu_device *adev) continue; r = block->version->funcs->hw_init(adev); - DRM_INFO("RE-INIT: %s %s\n", block->version->funcs->name, r?"failed":"successed"); + DRM_INFO("RE-INIT: %s %s\n", block->version->funcs->name, r?"failed":"succeeded"); if (r) return r; } @@ -3091,7 +3091,7 @@ static int amdgpu_device_handle_vram_lost(struct amdgpu_device *adev) * @adev: amdgpu device pointer * * attempt to do soft-reset or full-reset and reinitialize Asic - * return 0 means successed otherwise failed + * return 0 means succeeded otherwise failed */ static int amdgpu_device_reset(struct amdgpu_device *adev) { @@ -3169,7 +3169,7 @@ static int amdgpu_device_reset(struct amdgpu_device *adev) * @from_hypervisor: request from hypervisor * * do VF FLR and reinitialize Asic - * return 0 means successed otherwise failed + * return 0 means succeeded otherwise failed */ static int amdgpu_device_reset_sriov(struct amdgpu_device *adev, bool from_hypervisor) @@ -3294,7 +3294,7 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, dev_info(adev->dev, "GPU reset(%d) failed\n", atomic_read(&adev->gpu_reset_counter)); amdgpu_vf_error_put(adev, AMDGIM_ERROR_VF_GPU_RESET_FAIL, 0, r); } else { - dev_info(adev->dev, "GPU reset(%d) successed!\n",atomic_read(&adev->gpu_reset_counter)); + dev_info(adev->dev, "GPU reset(%d) succeeded!\n",atomic_read(&adev->gpu_reset_counter)); } amdgpu_vf_error_trans_all(adev); -- GitLab From 7b42573bb8a084175500eb62c4da9d46319e3d7e Mon Sep 17 00:00:00 2001 From: Harry Wentland <harry.wentland@amd.com> Date: Thu, 19 Jul 2018 14:17:30 -0400 Subject: [PATCH 1272/1506] drm/amd/display: Drop unused backlight functions in DM These are only ever called for non-DC code. Signed-off-by: Harry Wentland <harry.wentland@amd.com> Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) 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 5fc13e71a3b51..15c7b350f4f63 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -1574,18 +1574,6 @@ static void dm_bandwidth_update(struct amdgpu_device *adev) /* TODO: implement later */ } -static void dm_set_backlight_level(struct amdgpu_encoder *amdgpu_encoder, - u8 level) -{ - /* TODO: translate amdgpu_encoder to display_index and call DAL */ -} - -static u8 dm_get_backlight_level(struct amdgpu_encoder *amdgpu_encoder) -{ - /* TODO: translate amdgpu_encoder to display_index and call DAL */ - return 0; -} - static int amdgpu_notify_freesync(struct drm_device *dev, void *data, struct drm_file *filp) { @@ -1614,10 +1602,8 @@ static int amdgpu_notify_freesync(struct drm_device *dev, void *data, static const struct amdgpu_display_funcs dm_display_funcs = { .bandwidth_update = dm_bandwidth_update, /* called unconditionally */ .vblank_get_counter = dm_vblank_get_counter,/* called unconditionally */ - .backlight_set_level = - dm_set_backlight_level,/* called unconditionally */ - .backlight_get_level = - dm_get_backlight_level,/* called unconditionally */ + .backlight_set_level = NULL, /* never called for DC */ + .backlight_get_level = NULL, /* never called for DC */ .hpd_sense = NULL,/* called unconditionally */ .hpd_set_polarity = NULL, /* called unconditionally */ .hpd_get_gpio_reg = NULL, /* VBIOS parsing. DAL does it. */ -- GitLab From 1bc460a45b9746db4b0e6be46c122c377120aace Mon Sep 17 00:00:00 2001 From: Harry Wentland <harry.wentland@amd.com> Date: Tue, 17 Jul 2018 10:51:23 -0400 Subject: [PATCH 1273/1506] drm/amd/display: Honor pplib stutter mask for all ASICs in DC [Why] We were only setting this mask for DCN, but should really use it universally for all ASICs. [How] Move the assignment out of the Raven switch statement for all ASICs other than Stoney and Carrizo. v2: Keep stutter always on for Carrizo and Stoney (Alex) Cc: Rex.Zhu@amd.com Cc: Feifei.Xu@amd.com Cc: Kenneth.Feng@amd.com Cc: Evan.Quan@amd.com Cc: Bhawanpreet.Lakha@amd.com Cc: Jordan.Lazare@amd.com Signed-off-by: Harry Wentland <harry.wentland@amd.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) 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 15c7b350f4f63..45e062022461b 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -1532,10 +1532,6 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) DRM_ERROR("DM: Failed to initialize IRQ\n"); goto fail; } - /* - * Temporary disable until pplib/smu interaction is implemented - */ - dm->dc->debug.disable_stutter = amdgpu_pp_feature_mask & PP_STUTTER_MODE ? false : true; break; #endif default: @@ -1543,6 +1539,9 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) goto fail; } + if (adev->asic_type != CHIP_CARRIZO && adev->asic_type != CHIP_STONEY) + dm->dc->debug.disable_stutter = amdgpu_pp_feature_mask & PP_STUTTER_MODE ? false : true; + return 0; fail: kfree(aencoder); -- GitLab From 4d3b9ae50ea03d3295fc9b5f5c88f49fcd0e99f9 Mon Sep 17 00:00:00 2001 From: Shirish S <shirish.s@amd.com> Date: Wed, 18 Jul 2018 13:36:26 +0530 Subject: [PATCH 1274/1506] drm/amdgpu: lock and unlock console only for amdgpu_fbdev_set_suspend [V5] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [Why] While the console_lock is held, console output will be buffered, till its unlocked it wont be emitted, hence its ideal to unlock sooner to enable debugging/detecting/fixing of any issue in the remaining sequence of events in resume path. The concern here is about consoles other than fbcon on the device, e.g. a serial console [How] This patch restructures the console_lock, console_unlock around amdgpu_fbdev_set_suspend() and moves this new block appropriately. V2: Kept amdgpu_fbdev_set_suspend after pci_set_power_state V3: Updated the commit message to clarify the real concern that this patch addresses. V4: code clean-up. V5: fixed return value Signed-off-by: Shirish S <shirish.s@amd.com> Reviewed-by: Michel Dänzer <michel.daenzer@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 9b8264c761f71..fddf54773a6ea 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -2720,15 +2720,12 @@ int amdgpu_device_resume(struct drm_device *dev, bool resume, bool fbcon) if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) return 0; - if (fbcon) - console_lock(); - if (resume) { pci_set_power_state(dev->pdev, PCI_D0); pci_restore_state(dev->pdev); r = pci_enable_device(dev->pdev); if (r) - goto unlock; + return r; } /* post card */ @@ -2741,14 +2738,14 @@ int amdgpu_device_resume(struct drm_device *dev, bool resume, bool fbcon) r = amdgpu_device_ip_resume(adev); if (r) { DRM_ERROR("amdgpu_device_ip_resume failed (%d).\n", r); - goto unlock; + return r; } amdgpu_fence_driver_resume(adev); r = amdgpu_device_ip_late_init(adev); if (r) - goto unlock; + return r; /* pin cursors */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { @@ -2783,6 +2780,9 @@ int amdgpu_device_resume(struct drm_device *dev, bool resume, bool fbcon) } drm_modeset_unlock_all(dev); } + console_lock(); + amdgpu_fbdev_set_suspend(adev, 0); + console_unlock(); } drm_kms_helper_poll_enable(dev); @@ -2806,15 +2806,7 @@ int amdgpu_device_resume(struct drm_device *dev, bool resume, bool fbcon) #ifdef CONFIG_PM dev->dev->power.disable_depth--; #endif - - if (fbcon) - amdgpu_fbdev_set_suspend(adev, 0); - -unlock: - if (fbcon) - console_unlock(); - - return r; + return 0; } /** -- GitLab From 88de542e421ac86b8148b232f822de306004e5a0 Mon Sep 17 00:00:00 2001 From: Rex Zhu <rex.zhu@amd.com> Date: Thu, 19 Jul 2018 16:21:42 +0800 Subject: [PATCH 1275/1506] drm/amd/pp: Read vbios vddc limit before use them Use the vddc limit before read them from vbios Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c index 1a0dccb3fac1f..755f23511fc31 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c @@ -289,7 +289,15 @@ static int vega10_odn_initial_default_setting(struct pp_hwmgr *hwmgr) struct phm_ppt_v1_voltage_lookup_table *vddc_lookup_table; struct phm_ppt_v1_clock_voltage_dependency_table *dep_table[3]; struct phm_ppt_v1_clock_voltage_dependency_table *od_table[3]; + struct pp_atomfwctrl_avfs_parameters avfs_params = {0}; uint32_t i; + int result; + + result = pp_atomfwctrl_get_avfs_information(hwmgr, &avfs_params); + if (!result) { + data->odn_dpm_table.max_vddc = avfs_params.ulMaxVddc; + data->odn_dpm_table.min_vddc = avfs_params.ulMinVddc; + } od_lookup_table = &odn_table->vddc_lookup_table; vddc_lookup_table = table_info->vddc_lookup_table; @@ -2072,9 +2080,6 @@ static int vega10_populate_avfs_parameters(struct pp_hwmgr *hwmgr) if (data->smu_features[GNLD_AVFS].supported) { result = pp_atomfwctrl_get_avfs_information(hwmgr, &avfs_params); if (!result) { - data->odn_dpm_table.max_vddc = avfs_params.ulMaxVddc; - data->odn_dpm_table.min_vddc = avfs_params.ulMinVddc; - pp_table->MinVoltageVid = (uint8_t) convert_to_vid((uint16_t)(avfs_params.ulMinVddc)); pp_table->MaxVoltageVid = (uint8_t) -- GitLab From a0c3bf0ff40d6c482d381fe2c577a4e6c50f522f Mon Sep 17 00:00:00 2001 From: Rex Zhu <rex.zhu@amd.com> Date: Thu, 19 Jul 2018 16:32:05 +0800 Subject: [PATCH 1276/1506] drm/amd/pp: Update clk with od setting when set power state This can fix the issue resume from S3, the user's OD setting were reverted to default. Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c index 755f23511fc31..6d93d52975ecb 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c @@ -3259,10 +3259,25 @@ static int vega10_populate_and_upload_sclk_mclk_dpm_levels( { int result = 0; struct vega10_hwmgr *data = hwmgr->backend; + struct vega10_dpm_table *dpm_table = &data->dpm_table; + struct vega10_odn_dpm_table *odn_table = &data->odn_dpm_table; + struct vega10_odn_clock_voltage_dependency_table *odn_clk_table = &odn_table->vdd_dep_on_sclk; + int count; if (!data->need_update_dpm_table) return 0; + if (hwmgr->od_enabled && data->need_update_dpm_table & DPMTABLE_OD_UPDATE_SCLK) { + for (count = 0; count < dpm_table->gfx_table.count; count++) + dpm_table->gfx_table.dpm_levels[count].value = odn_clk_table->entries[count].clk; + } + + odn_clk_table = &odn_table->vdd_dep_on_mclk; + if (hwmgr->od_enabled && data->need_update_dpm_table & DPMTABLE_OD_UPDATE_MCLK) { + for (count = 0; count < dpm_table->mem_table.count; count++) + dpm_table->mem_table.dpm_levels[count].value = odn_clk_table->entries[count].clk; + } + if (data->need_update_dpm_table & (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK + DPMTABLE_UPDATE_SOCCLK)) { result = vega10_populate_all_graphic_levels(hwmgr); -- GitLab From 97e8f102f5a9123d30258e196c6c1ea29cf52e83 Mon Sep 17 00:00:00 2001 From: Rex Zhu <rex.zhu@amd.com> Date: Tue, 17 Jul 2018 18:31:50 +0800 Subject: [PATCH 1277/1506] drm/amd/pp: Set Max clock level to display by default avoid the error in dmesg: [drm:dm_pp_get_static_clocks] *ERROR* DM_PPLIB: invalid powerlevel state: 0! Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Reviewed-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/powerplay/amd_powerplay.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c index 75c208283e5f9..7a646f94b4788 100644 --- a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c +++ b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c @@ -998,7 +998,7 @@ static int pp_get_display_power_level(void *handle, static int pp_get_current_clocks(void *handle, struct amd_pp_clock_info *clocks) { - struct amd_pp_simple_clock_info simple_clocks; + struct amd_pp_simple_clock_info simple_clocks = { 0 }; struct pp_clock_info hw_clocks; struct pp_hwmgr *hwmgr = handle; int ret = 0; @@ -1034,7 +1034,10 @@ static int pp_get_current_clocks(void *handle, clocks->max_engine_clock_in_sr = hw_clocks.max_eng_clk; clocks->min_engine_clock_in_sr = hw_clocks.min_eng_clk; - clocks->max_clocks_state = simple_clocks.level; + if (simple_clocks.level == 0) + clocks->max_clocks_state = PP_DAL_POWERLEVEL_7; + else + clocks->max_clocks_state = simple_clocks.level; if (0 == phm_get_current_shallow_sleep_clocks(hwmgr, &hwmgr->current_ps->hardware, &hw_clocks)) { clocks->max_engine_clock_in_sr = hw_clocks.max_eng_clk; @@ -1137,6 +1140,8 @@ static int pp_get_display_mode_validation_clocks(void *handle, if (!hwmgr || !hwmgr->pm_en ||!clocks) return -EINVAL; + clocks->level = PP_DAL_POWERLEVEL_7; + mutex_lock(&hwmgr->smu_lock); if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DynamicPatchPowerState)) -- GitLab From 3dbd823e53b572df1c84d73e85c518212fcdaddb Mon Sep 17 00:00:00 2001 From: Rex Zhu <rex.zhu@amd.com> Date: Tue, 17 Jul 2018 20:18:04 +0800 Subject: [PATCH 1278/1506] drm/amd/display: Convert 10kHz clks from PPLib into kHz Except special naming as *_in_khz, The default clock unit in powerplay is in 10KHz. so need to * 10 as expecting clock frequency in display is in kHz. Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Reviewed-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c index c69ae78d82b24..fbe878ae1e8c5 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c @@ -469,8 +469,8 @@ bool dm_pp_get_static_clocks( return false; static_clk_info->max_clocks_state = pp_to_dc_powerlevel_state(pp_clk_info.max_clocks_state); - static_clk_info->max_mclk_khz = pp_clk_info.max_memory_clock; - static_clk_info->max_sclk_khz = pp_clk_info.max_engine_clock; + static_clk_info->max_mclk_khz = pp_clk_info.max_memory_clock * 10; + static_clk_info->max_sclk_khz = pp_clk_info.max_engine_clock * 10; return true; } -- GitLab From ecb8c50382e2e8bfd60483e3edf8cb883f7bde62 Mon Sep 17 00:00:00 2001 From: Shirish S <shirish.s@amd.com> Date: Fri, 20 Jul 2018 17:26:50 +0530 Subject: [PATCH 1279/1506] drm/amdgpu: use drm_fb helper for console_(un)lock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch removes the usage of console_(un)lock by replacing drm_fb_helper_set_suspend() to drm_fb_helper_set_suspend_unlocked() which locks and unlocks the console instead of locking ourselves. Signed-off-by: Shirish S <shirish.s@amd.com> Reviewed-by: Michel Dänzer <michel.daenzer@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 8 ++------ drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c | 4 ++-- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index fddf54773a6ea..e57f90f444c59 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -2691,11 +2691,9 @@ int amdgpu_device_suspend(struct drm_device *dev, bool suspend, bool fbcon) DRM_ERROR("amdgpu asic reset failed\n"); } - if (fbcon) { - console_lock(); + if (fbcon) amdgpu_fbdev_set_suspend(adev, 1); - console_unlock(); - } + return 0; } @@ -2780,9 +2778,7 @@ int amdgpu_device_resume(struct drm_device *dev, bool resume, bool fbcon) } drm_modeset_unlock_all(dev); } - console_lock(); amdgpu_fbdev_set_suspend(adev, 0); - console_unlock(); } drm_kms_helper_poll_enable(dev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c index d44b76455e896..69c5d22f29bdf 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c @@ -373,8 +373,8 @@ void amdgpu_fbdev_fini(struct amdgpu_device *adev) void amdgpu_fbdev_set_suspend(struct amdgpu_device *adev, int state) { if (adev->mode_info.rfbdev) - drm_fb_helper_set_suspend(&adev->mode_info.rfbdev->helper, - state); + drm_fb_helper_set_suspend_unlocked(&adev->mode_info.rfbdev->helper, + state); } int amdgpu_fbdev_total_size(struct amdgpu_device *adev) -- GitLab From 7766484b4a18373ac557ce6ea442ef28517c8224 Mon Sep 17 00:00:00 2001 From: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Date: Fri, 20 Jul 2018 11:42:24 -0400 Subject: [PATCH 1280/1506] drm/amdgpu: Fix warning in dma_fence_is_later on resume from S3. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: amdgpu_ttm_set_buffer_funcs_status destroys adev->mman.entity on suspend without releasing adev->mman.bdev.man[TTM_PL_VRAM].move fence so on resume the new drm_sched_entity.fence_context causes the warning against the old fence context which is different. Fix: When destroying sched_entity in amdgpu_ttm_set_buffer_funcs_status release man->move and set the pointer to NULL. Signed-off-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 13977ea6a0978..8ed102933ca23 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -1927,6 +1927,8 @@ void amdgpu_ttm_set_buffer_funcs_status(struct amdgpu_device *adev, bool enable) } else { drm_sched_entity_destroy(adev->mman.entity.sched, &adev->mman.entity); + dma_fence_put(man->move); + man->move = NULL; } /* this just adjusts TTM size idea, which sets lpfn to the correct value */ -- GitLab From 9e7204beae8cbb75939acd640829e10979f2c920 Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexander.deucher@amd.com> Date: Thu, 19 Jul 2018 09:17:02 -0500 Subject: [PATCH 1281/1506] drm/amdgpu/apci: don't call sbios request function if it's not supported Check the supported functions mask before calling the bios requests method. Reviewed-by: Jim Qu <Jim.Qu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c | 53 +++++++++++++----------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c index 0d8c3fc6eacef..455617813ec4d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c @@ -364,7 +364,6 @@ static int amdgpu_atif_handler(struct amdgpu_device *adev, struct acpi_bus_event *event) { struct amdgpu_atif *atif = adev->atif; - struct atif_sbios_requests req; int count; DRM_DEBUG_DRIVER("event, device_class = %s, type = %#x\n", @@ -379,42 +378,46 @@ static int amdgpu_atif_handler(struct amdgpu_device *adev, /* Not our event */ return NOTIFY_DONE; - /* Check pending SBIOS requests */ - count = amdgpu_atif_get_sbios_requests(atif, &req); + if (atif->functions.sbios_requests) { + struct atif_sbios_requests req; - if (count <= 0) - return NOTIFY_DONE; + /* Check pending SBIOS requests */ + count = amdgpu_atif_get_sbios_requests(atif, &req); + + if (count <= 0) + return NOTIFY_DONE; - DRM_DEBUG_DRIVER("ATIF: %d pending SBIOS requests\n", count); + DRM_DEBUG_DRIVER("ATIF: %d pending SBIOS requests\n", count); - if (req.pending & ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST) { - struct amdgpu_encoder *enc = atif->encoder_for_bl; + if (req.pending & ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST) { + struct amdgpu_encoder *enc = atif->encoder_for_bl; - if (enc) { - struct amdgpu_encoder_atom_dig *dig = enc->enc_priv; + if (enc) { + struct amdgpu_encoder_atom_dig *dig = enc->enc_priv; - DRM_DEBUG_DRIVER("Changing brightness to %d\n", - req.backlight_level); + DRM_DEBUG_DRIVER("Changing brightness to %d\n", + req.backlight_level); - amdgpu_display_backlight_set_level(adev, enc, req.backlight_level); + amdgpu_display_backlight_set_level(adev, enc, req.backlight_level); #if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE) - backlight_force_update(dig->bl_dev, - BACKLIGHT_UPDATE_HOTKEY); + backlight_force_update(dig->bl_dev, + BACKLIGHT_UPDATE_HOTKEY); #endif + } } - } - if (req.pending & ATIF_DGPU_DISPLAY_EVENT) { - if ((adev->flags & AMD_IS_PX) && - amdgpu_atpx_dgpu_req_power_for_displays()) { - pm_runtime_get_sync(adev->ddev->dev); - /* Just fire off a uevent and let userspace tell us what to do */ - drm_helper_hpd_irq_event(adev->ddev); - pm_runtime_mark_last_busy(adev->ddev->dev); - pm_runtime_put_autosuspend(adev->ddev->dev); + if (req.pending & ATIF_DGPU_DISPLAY_EVENT) { + if ((adev->flags & AMD_IS_PX) && + amdgpu_atpx_dgpu_req_power_for_displays()) { + pm_runtime_get_sync(adev->ddev->dev); + /* Just fire off a uevent and let userspace tell us what to do */ + drm_helper_hpd_irq_event(adev->ddev); + pm_runtime_mark_last_busy(adev->ddev->dev); + pm_runtime_put_autosuspend(adev->ddev->dev); + } } + /* TODO: check other events */ } - /* TODO: check other events */ /* We've handled the event, stop the notifier chain. The ACPI interface * overloads ACPI_VIDEO_NOTIFY_PROBE, we don't want to send that to -- GitLab From 5b8eb0edba15b1685acbb76751fbb189de4ca310 Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexander.deucher@amd.com> Date: Thu, 19 Jul 2018 09:28:23 -0500 Subject: [PATCH 1282/1506] drm/amdgpu/acpi: skip backlight events for DC No change in behavior, just bail sooner. Reviewed-by: Jim Qu <Jim.Qu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c index 455617813ec4d..353993218f213 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c @@ -389,7 +389,9 @@ static int amdgpu_atif_handler(struct amdgpu_device *adev, DRM_DEBUG_DRIVER("ATIF: %d pending SBIOS requests\n", count); - if (req.pending & ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST) { + /* todo: add DC handling */ + if ((req.pending & ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST) && + !amdgpu_device_has_dc_support(adev)) { struct amdgpu_encoder *enc = atif->encoder_for_bl; if (enc) { -- GitLab From e7854a038015122538df4777b8c192e03b4eb6c2 Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexander.deucher@amd.com> Date: Thu, 19 Jul 2018 13:10:07 -0500 Subject: [PATCH 1283/1506] drm/amdgpu: split ip suspend into 2 phases We need to do some IPs earlier to deal with ordering issues similar to how resume is split into two phases. Do DCE first to deal with atomic, then do the rest. Acked-by: Harry Wentland <harry.wentland@amd.com> Reviewed-and-tested-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 78 +++++++++++++++++++++- 1 file changed, 76 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index e57f90f444c59..36426e66964d3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -1926,7 +1926,7 @@ static void amdgpu_device_ip_late_init_func_handler(struct work_struct *work) } /** - * amdgpu_device_ip_suspend - run suspend for hardware IPs + * amdgpu_device_ip_suspend_phase1 - run suspend for hardware IPs (phase 1) * * @adev: amdgpu_device pointer * @@ -1936,7 +1936,55 @@ static void amdgpu_device_ip_late_init_func_handler(struct work_struct *work) * in each IP into a state suitable for suspend. * Returns 0 on success, negative error code on failure. */ -int amdgpu_device_ip_suspend(struct amdgpu_device *adev) +static int amdgpu_device_ip_suspend_phase1(struct amdgpu_device *adev) +{ + int i, r; + + if (amdgpu_sriov_vf(adev)) + amdgpu_virt_request_full_gpu(adev, false); + + for (i = adev->num_ip_blocks - 1; i >= 0; i--) { + if (!adev->ip_blocks[i].status.valid) + continue; + /* displays are handled separately */ + if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_DCE) { + /* ungate blocks so that suspend can properly shut them down */ + if (adev->ip_blocks[i].version->funcs->set_clockgating_state) { + r = adev->ip_blocks[i].version->funcs->set_clockgating_state((void *)adev, + AMD_CG_STATE_UNGATE); + if (r) { + DRM_ERROR("set_clockgating_state(ungate) of IP block <%s> failed %d\n", + adev->ip_blocks[i].version->funcs->name, r); + } + } + /* XXX handle errors */ + r = adev->ip_blocks[i].version->funcs->suspend(adev); + /* XXX handle errors */ + if (r) { + DRM_ERROR("suspend of IP block <%s> failed %d\n", + adev->ip_blocks[i].version->funcs->name, r); + } + } + } + + if (amdgpu_sriov_vf(adev)) + amdgpu_virt_release_full_gpu(adev, false); + + return 0; +} + +/** + * amdgpu_device_ip_suspend_phase2 - run suspend for hardware IPs (phase 2) + * + * @adev: amdgpu_device pointer + * + * Main suspend function for hardware IPs. The list of all the hardware + * IPs that make up the asic is walked, clockgating is disabled and the + * suspend callbacks are run. suspend puts the hardware and software state + * in each IP into a state suitable for suspend. + * Returns 0 on success, negative error code on failure. + */ +static int amdgpu_device_ip_suspend_phase2(struct amdgpu_device *adev) { int i, r; @@ -1957,6 +2005,9 @@ int amdgpu_device_ip_suspend(struct amdgpu_device *adev) for (i = adev->num_ip_blocks - 1; i >= 0; i--) { if (!adev->ip_blocks[i].status.valid) continue; + /* displays are handled in phase1 */ + if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_DCE) + continue; /* ungate blocks so that suspend can properly shut them down */ if (adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_SMC && adev->ip_blocks[i].version->funcs->set_clockgating_state) { @@ -1982,6 +2033,29 @@ int amdgpu_device_ip_suspend(struct amdgpu_device *adev) return 0; } +/** + * amdgpu_device_ip_suspend - run suspend for hardware IPs + * + * @adev: amdgpu_device pointer + * + * Main suspend function for hardware IPs. The list of all the hardware + * IPs that make up the asic is walked, clockgating is disabled and the + * suspend callbacks are run. suspend puts the hardware and software state + * in each IP into a state suitable for suspend. + * Returns 0 on success, negative error code on failure. + */ +int amdgpu_device_ip_suspend(struct amdgpu_device *adev) +{ + int r; + + r = amdgpu_device_ip_suspend_phase1(adev); + if (r) + return r; + r = amdgpu_device_ip_suspend_phase2(adev); + + return r; +} + static int amdgpu_device_ip_reinit_early_sriov(struct amdgpu_device *adev) { int i, r; -- GitLab From fe1053b7859dcbe830212de43befe6c7e4f089a8 Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexander.deucher@amd.com> Date: Thu, 19 Jul 2018 13:24:33 -0500 Subject: [PATCH 1284/1506] drm/amdgpu: rework suspend and resume to deal with atomic changes Use the newly split ip suspend functions to do suspend displays first (to deal with atomic so that FBs can be unpinned before attempting to evict vram), then evict vram, then suspend the other IPs. Also move the non-DC pinning code to only be called in the non-DC cases since atomic should take care of DC. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=107065 Fixes: e00fb85 drm: Stop updating plane->crtc/fb/old_fb on atomic drivers Acked-by: Harry Wentland <harry.wentland@amd.com> Reviewed-and-tested-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 86 +++++++++++----------- 1 file changed, 45 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 36426e66964d3..61981d0701b51 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -2709,44 +2709,46 @@ int amdgpu_device_suspend(struct drm_device *dev, bool suspend, bool fbcon) drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); } drm_modeset_unlock_all(dev); - } - - amdgpu_amdkfd_suspend(adev); - - /* unpin the front buffers and cursors */ - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); - struct drm_framebuffer *fb = crtc->primary->fb; - struct amdgpu_bo *robj; - - if (amdgpu_crtc->cursor_bo) { - struct amdgpu_bo *aobj = gem_to_amdgpu_bo(amdgpu_crtc->cursor_bo); - r = amdgpu_bo_reserve(aobj, true); - if (r == 0) { - amdgpu_bo_unpin(aobj); - amdgpu_bo_unreserve(aobj); + /* unpin the front buffers and cursors */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); + struct drm_framebuffer *fb = crtc->primary->fb; + struct amdgpu_bo *robj; + + if (amdgpu_crtc->cursor_bo) { + struct amdgpu_bo *aobj = gem_to_amdgpu_bo(amdgpu_crtc->cursor_bo); + r = amdgpu_bo_reserve(aobj, true); + if (r == 0) { + amdgpu_bo_unpin(aobj); + amdgpu_bo_unreserve(aobj); + } } - } - if (fb == NULL || fb->obj[0] == NULL) { - continue; - } - robj = gem_to_amdgpu_bo(fb->obj[0]); - /* don't unpin kernel fb objects */ - if (!amdgpu_fbdev_robj_is_fb(adev, robj)) { - r = amdgpu_bo_reserve(robj, true); - if (r == 0) { - amdgpu_bo_unpin(robj); - amdgpu_bo_unreserve(robj); + if (fb == NULL || fb->obj[0] == NULL) { + continue; + } + robj = gem_to_amdgpu_bo(fb->obj[0]); + /* don't unpin kernel fb objects */ + if (!amdgpu_fbdev_robj_is_fb(adev, robj)) { + r = amdgpu_bo_reserve(robj, true); + if (r == 0) { + amdgpu_bo_unpin(robj); + amdgpu_bo_unreserve(robj); + } } } } + + amdgpu_amdkfd_suspend(adev); + + r = amdgpu_device_ip_suspend_phase1(adev); + /* evict vram memory */ amdgpu_bo_evict_vram(adev); amdgpu_fence_driver_suspend(adev); - r = amdgpu_device_ip_suspend(adev); + r = amdgpu_device_ip_suspend_phase2(adev); /* evict remaining vram memory * This second call to evict vram is to evict the gart page table @@ -2819,19 +2821,21 @@ int amdgpu_device_resume(struct drm_device *dev, bool resume, bool fbcon) if (r) return r; - /* pin cursors */ - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); - - if (amdgpu_crtc->cursor_bo) { - struct amdgpu_bo *aobj = gem_to_amdgpu_bo(amdgpu_crtc->cursor_bo); - r = amdgpu_bo_reserve(aobj, true); - if (r == 0) { - r = amdgpu_bo_pin(aobj, AMDGPU_GEM_DOMAIN_VRAM); - if (r != 0) - DRM_ERROR("Failed to pin cursor BO (%d)\n", r); - amdgpu_crtc->cursor_addr = amdgpu_bo_gpu_offset(aobj); - amdgpu_bo_unreserve(aobj); + if (!amdgpu_device_has_dc_support(adev)) { + /* pin cursors */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); + + if (amdgpu_crtc->cursor_bo) { + struct amdgpu_bo *aobj = gem_to_amdgpu_bo(amdgpu_crtc->cursor_bo); + r = amdgpu_bo_reserve(aobj, true); + if (r == 0) { + r = amdgpu_bo_pin(aobj, AMDGPU_GEM_DOMAIN_VRAM); + if (r != 0) + DRM_ERROR("Failed to pin cursor BO (%d)\n", r); + amdgpu_crtc->cursor_addr = amdgpu_bo_gpu_offset(aobj); + amdgpu_bo_unreserve(aobj); + } } } } -- GitLab From 7749a57a285342ff5664c80236a63c7fa53cbdfc Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe <alexandru-cosmin.gheorghe@arm.com> Date: Fri, 13 Jul 2018 16:10:59 +0100 Subject: [PATCH 1285/1506] drm: mali-dp: Report writeback connector as connected Older version of this patch series reported writeback as disconnected to avoid confusing userspace not aware of writeback connectors. However, the version that got merged uses a special cap (DRM_CLIENT_CAP_WRITEBACK_CONNECTORS) for this purpose. This helps us avoid some special handling of writeback connector in drm_helper_probe_single_connector_modes, see [1]. https://lists.freedesktop.org/archives/dri-devel/2018-July/183144.html Signed-off-by: Alexandru Gheorghe <alexandru-cosmin.gheorghe@arm.com> Reviewed-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Liviu Dudau <liviu.dudau@arm.com> --- drivers/gpu/drm/arm/malidp_mw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/arm/malidp_mw.c b/drivers/gpu/drm/arm/malidp_mw.c index cfd718e7e97c1..ba6ae66387c91 100644 --- a/drivers/gpu/drm/arm/malidp_mw.c +++ b/drivers/gpu/drm/arm/malidp_mw.c @@ -73,7 +73,7 @@ static void malidp_mw_connector_reset(struct drm_connector *connector) static enum drm_connector_status malidp_mw_connector_detect(struct drm_connector *connector, bool force) { - return connector_status_disconnected; + return connector_status_connected; } static void malidp_mw_connector_destroy(struct drm_connector *connector) -- GitLab From 2e012e76ad59edb4a5a175c0957a44337dc39d87 Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe <alexandru-cosmin.gheorghe@arm.com> Date: Fri, 13 Jul 2018 16:11:00 +0100 Subject: [PATCH 1286/1506] drm: mali-dp: Set encoder possible_clones Set possible_clones field to report that the writeback connector and the one driving the display could be enabled at the same time. Signed-off-by: Alexandru Gheorghe <alexandru-cosmin.gheorghe@arm.com> Acked-by: Liviu Dudau <liviu.dudau@arm.com> Signed-off-by: Liviu Dudau <liviu.dudau@arm.com> --- drivers/gpu/drm/arm/malidp_drv.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c index 5b72605573913..08b5bb219816a 100644 --- a/drivers/gpu/drm/arm/malidp_drv.c +++ b/drivers/gpu/drm/arm/malidp_drv.c @@ -616,6 +616,7 @@ static int malidp_bind(struct device *dev) struct malidp_hw_device *hwdev; struct platform_device *pdev = to_platform_device(dev); struct of_device_id const *dev_id; + struct drm_encoder *encoder; /* number of lines for the R, G and B output */ u8 output_width[MAX_OUTPUT_CHANNELS]; int ret = 0, i; @@ -737,6 +738,15 @@ static int malidp_bind(struct device *dev) goto bind_fail; } + /* We expect to have a maximum of two encoders one for the actual + * display and a virtual one for the writeback connector + */ + WARN_ON(drm->mode_config.num_encoder > 2); + list_for_each_entry(encoder, &drm->mode_config.encoder_list, head) { + encoder->possible_clones = + (1 << drm->mode_config.num_encoder) - 1; + } + ret = malidp_irq_init(pdev); if (ret < 0) goto irq_init_fail; -- GitLab From eb4d9796fa340495b519c75d0be44ae583e67ec3 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski <m.szyprowski@samsung.com> Date: Mon, 9 Jul 2018 15:44:30 +0200 Subject: [PATCH 1287/1506] drm/exynos: g2d: Convert to driver component API Exynos G2D driver is the last client of the custom Exynos 'sub-driver' framework. In the current state it doesn't really resolve any of the issues it has been designed for, as Exynos DRM is already built only as a single kernel module. Remove the custom 'sub-driver' framework and simply use generic component framework also in G2D driver. Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Inki Dae <inki.dae@samsung.com> --- drivers/gpu/drm/exynos/Makefile | 2 +- drivers/gpu/drm/exynos/exynos_drm_core.c | 119 ----------- drivers/gpu/drm/exynos/exynos_drm_drv.c | 14 +- drivers/gpu/drm/exynos/exynos_drm_drv.h | 47 +---- drivers/gpu/drm/exynos/exynos_drm_g2d.c | 257 +++++++++-------------- drivers/gpu/drm/exynos/exynos_drm_g2d.h | 11 + 6 files changed, 115 insertions(+), 335 deletions(-) delete mode 100644 drivers/gpu/drm/exynos/exynos_drm_core.c diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile index 3b323f1e04754..2ad146bbf4f54 100644 --- a/drivers/gpu/drm/exynos/Makefile +++ b/drivers/gpu/drm/exynos/Makefile @@ -4,7 +4,7 @@ # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. exynosdrm-y := exynos_drm_drv.o exynos_drm_crtc.o exynos_drm_fb.o \ - exynos_drm_gem.o exynos_drm_core.o exynos_drm_plane.o + exynos_drm_gem.o exynos_drm_plane.o exynosdrm-$(CONFIG_DRM_FBDEV_EMULATION) += exynos_drm_fbdev.o exynosdrm-$(CONFIG_DRM_EXYNOS_IOMMU) += exynos_drm_iommu.o diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c deleted file mode 100644 index b0c0621fcdf72..0000000000000 --- a/drivers/gpu/drm/exynos/exynos_drm_core.c +++ /dev/null @@ -1,119 +0,0 @@ -/* exynos_drm_core.c - * - * Copyright (c) 2011 Samsung Electronics Co., Ltd. - * Author: - * Inki Dae <inki.dae@samsung.com> - * Joonyoung Shim <jy0922.shim@samsung.com> - * Seung-Woo Kim <sw0312.kim@samsung.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -#include <drm/drmP.h> - -#include "exynos_drm_drv.h" -#include "exynos_drm_crtc.h" - -static LIST_HEAD(exynos_drm_subdrv_list); - -int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv) -{ - if (!subdrv) - return -EINVAL; - - list_add_tail(&subdrv->list, &exynos_drm_subdrv_list); - - return 0; -} - -int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv) -{ - if (!subdrv) - return -EINVAL; - - list_del(&subdrv->list); - - return 0; -} - -int exynos_drm_device_subdrv_probe(struct drm_device *dev) -{ - struct exynos_drm_subdrv *subdrv, *n; - int err; - - if (!dev) - return -EINVAL; - - list_for_each_entry_safe(subdrv, n, &exynos_drm_subdrv_list, list) { - if (subdrv->probe) { - subdrv->drm_dev = dev; - - /* - * this probe callback would be called by sub driver - * after setting of all resources to this sub driver, - * such as clock, irq and register map are done. - */ - err = subdrv->probe(dev, subdrv->dev); - if (err) { - DRM_DEBUG("exynos drm subdrv probe failed.\n"); - list_del(&subdrv->list); - continue; - } - } - } - - return 0; -} - -int exynos_drm_device_subdrv_remove(struct drm_device *dev) -{ - struct exynos_drm_subdrv *subdrv; - - if (!dev) { - WARN(1, "Unexpected drm device unregister!\n"); - return -EINVAL; - } - - list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) { - if (subdrv->remove) - subdrv->remove(dev, subdrv->dev); - } - - return 0; -} - -int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file) -{ - struct exynos_drm_subdrv *subdrv; - int ret; - - list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) { - if (subdrv->open) { - ret = subdrv->open(dev, subdrv->dev, file); - if (ret) - goto err; - } - } - - return 0; - -err: - list_for_each_entry_continue_reverse(subdrv, &exynos_drm_subdrv_list, list) { - if (subdrv->close) - subdrv->close(dev, subdrv->dev, file); - } - return ret; -} - -void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file) -{ - struct exynos_drm_subdrv *subdrv; - - list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) { - if (subdrv->close) - subdrv->close(dev, subdrv->dev, file); - } -} diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index ed3cc2989f93f..7d0164aea36b4 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -55,8 +55,7 @@ static int exynos_drm_open(struct drm_device *dev, struct drm_file *file) return -ENOMEM; file->driver_priv = file_priv; - - ret = exynos_drm_subdrv_open(dev, file); + ret = g2d_open(dev, file); if (ret) goto err_file_priv_free; @@ -70,7 +69,7 @@ static int exynos_drm_open(struct drm_device *dev, struct drm_file *file) static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file) { - exynos_drm_subdrv_close(dev, file); + g2d_close(dev, file); kfree(file->driver_priv); file->driver_priv = NULL; } @@ -240,6 +239,7 @@ static struct exynos_drm_driver_info exynos_drm_drivers[] = { DRM_COMPONENT_DRIVER | DRM_VIRTUAL_DEVICE }, { DRV_PTR(g2d_driver, CONFIG_DRM_EXYNOS_G2D), + DRM_COMPONENT_DRIVER }, { DRV_PTR(fimc_driver, CONFIG_DRM_EXYNOS_FIMC), DRM_COMPONENT_DRIVER | DRM_FIMC_DEVICE, @@ -376,11 +376,6 @@ static int exynos_drm_bind(struct device *dev) if (ret) goto err_unbind_all; - /* Probe non kms sub drivers and virtual display driver. */ - ret = exynos_drm_device_subdrv_probe(drm); - if (ret) - goto err_unbind_all; - drm_mode_config_reset(drm); /* @@ -411,7 +406,6 @@ static int exynos_drm_bind(struct device *dev) exynos_drm_fbdev_fini(drm); err_cleanup_poll: drm_kms_helper_poll_fini(drm); - exynos_drm_device_subdrv_remove(drm); err_unbind_all: component_unbind_all(drm->dev, drm); err_mode_config_cleanup: @@ -431,8 +425,6 @@ static void exynos_drm_unbind(struct device *dev) drm_dev_unregister(drm); - exynos_drm_device_subdrv_remove(drm); - exynos_drm_fbdev_fini(drm); drm_kms_helper_poll_fini(drm); diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 0f6d079a55c92..c737c4bd2c19b 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -179,17 +179,13 @@ static inline void exynos_drm_pipe_clk_enable(struct exynos_drm_crtc *crtc, crtc->pipe_clk->enable(crtc->pipe_clk, enable); } -struct exynos_drm_g2d_private { - struct device *dev; +struct drm_exynos_file_private { + /* for g2d api */ struct list_head inuse_cmdlist; struct list_head event_list; struct list_head userptr_list; }; -struct drm_exynos_file_private { - struct exynos_drm_g2d_private *g2d_priv; -}; - /* * Exynos drm private structure. * @@ -201,6 +197,7 @@ struct exynos_drm_private { struct drm_fb_helper *fb_helper; struct drm_atomic_state *suspend_state; + struct device *g2d_dev; struct device *dma_dev; void *mapping; @@ -217,44 +214,6 @@ static inline struct device *to_dma_dev(struct drm_device *dev) return priv->dma_dev; } -/* - * Exynos drm sub driver structure. - * - * @list: sub driver has its own list object to register to exynos drm driver. - * @dev: pointer to device object for subdrv device driver. - * @drm_dev: pointer to drm_device and this pointer would be set - * when sub driver calls exynos_drm_subdrv_register(). - * @probe: this callback would be called by exynos drm driver after - * subdrv is registered to it. - * @remove: this callback is used to release resources created - * by probe callback. - * @open: this would be called with drm device file open. - * @close: this would be called with drm device file close. - */ -struct exynos_drm_subdrv { - struct list_head list; - struct device *dev; - struct drm_device *drm_dev; - - int (*probe)(struct drm_device *drm_dev, struct device *dev); - void (*remove)(struct drm_device *drm_dev, struct device *dev); - int (*open)(struct drm_device *drm_dev, struct device *dev, - struct drm_file *file); - void (*close)(struct drm_device *drm_dev, struct device *dev, - struct drm_file *file); -}; - - /* This function would be called by non kms drivers such as g2d and ipp. */ -int exynos_drm_subdrv_register(struct exynos_drm_subdrv *drm_subdrv); - -/* this function removes subdrv list from exynos drm driver */ -int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *drm_subdrv); - -int exynos_drm_device_subdrv_probe(struct drm_device *dev); -int exynos_drm_device_subdrv_remove(struct drm_device *dev); -int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file); -void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file); - #ifdef CONFIG_DRM_EXYNOS_DPI struct drm_encoder *exynos_dpi_probe(struct device *dev); int exynos_dpi_remove(struct drm_encoder *encoder); diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index f68ef1b3a28c7..27b929757b437 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -9,6 +9,7 @@ #include <linux/kernel.h> #include <linux/clk.h> +#include <linux/component.h> #include <linux/err.h> #include <linux/interrupt.h> #include <linux/io.h> @@ -237,7 +238,7 @@ struct g2d_data { int irq; struct workqueue_struct *g2d_workq; struct work_struct runqueue_work; - struct exynos_drm_subdrv subdrv; + struct drm_device *drm_dev; unsigned long flags; /* cmdlist */ @@ -268,14 +269,13 @@ static int g2d_init_cmdlist(struct g2d_data *g2d) { struct device *dev = g2d->dev; struct g2d_cmdlist_node *node = g2d->cmdlist_node; - struct exynos_drm_subdrv *subdrv = &g2d->subdrv; int nr; int ret; struct g2d_buf_info *buf_info; g2d->cmdlist_dma_attrs = DMA_ATTR_WRITE_COMBINE; - g2d->cmdlist_pool_virt = dma_alloc_attrs(to_dma_dev(subdrv->drm_dev), + g2d->cmdlist_pool_virt = dma_alloc_attrs(to_dma_dev(g2d->drm_dev), G2D_CMDLIST_POOL_SIZE, &g2d->cmdlist_pool, GFP_KERNEL, g2d->cmdlist_dma_attrs); @@ -308,7 +308,7 @@ static int g2d_init_cmdlist(struct g2d_data *g2d) return 0; err: - dma_free_attrs(to_dma_dev(subdrv->drm_dev), G2D_CMDLIST_POOL_SIZE, + dma_free_attrs(to_dma_dev(g2d->drm_dev), G2D_CMDLIST_POOL_SIZE, g2d->cmdlist_pool_virt, g2d->cmdlist_pool, g2d->cmdlist_dma_attrs); return ret; @@ -316,12 +316,10 @@ static int g2d_init_cmdlist(struct g2d_data *g2d) static void g2d_fini_cmdlist(struct g2d_data *g2d) { - struct exynos_drm_subdrv *subdrv = &g2d->subdrv; - kfree(g2d->cmdlist_node); if (g2d->cmdlist_pool_virt && g2d->cmdlist_pool) { - dma_free_attrs(to_dma_dev(subdrv->drm_dev), + dma_free_attrs(to_dma_dev(g2d->drm_dev), G2D_CMDLIST_POOL_SIZE, g2d->cmdlist_pool_virt, g2d->cmdlist_pool, g2d->cmdlist_dma_attrs); @@ -355,27 +353,27 @@ static void g2d_put_cmdlist(struct g2d_data *g2d, struct g2d_cmdlist_node *node) mutex_unlock(&g2d->cmdlist_mutex); } -static void g2d_add_cmdlist_to_inuse(struct exynos_drm_g2d_private *g2d_priv, +static void g2d_add_cmdlist_to_inuse(struct drm_exynos_file_private *file_priv, struct g2d_cmdlist_node *node) { struct g2d_cmdlist_node *lnode; - if (list_empty(&g2d_priv->inuse_cmdlist)) + if (list_empty(&file_priv->inuse_cmdlist)) goto add_to_list; /* this links to base address of new cmdlist */ - lnode = list_entry(g2d_priv->inuse_cmdlist.prev, + lnode = list_entry(file_priv->inuse_cmdlist.prev, struct g2d_cmdlist_node, list); lnode->cmdlist->data[lnode->cmdlist->last] = node->dma_addr; add_to_list: - list_add_tail(&node->list, &g2d_priv->inuse_cmdlist); + list_add_tail(&node->list, &file_priv->inuse_cmdlist); if (node->event) - list_add_tail(&node->event->base.link, &g2d_priv->event_list); + list_add_tail(&node->event->base.link, &file_priv->event_list); } -static void g2d_userptr_put_dma_addr(struct drm_device *drm_dev, +static void g2d_userptr_put_dma_addr(struct g2d_data *g2d, unsigned long obj, bool force) { @@ -398,7 +396,7 @@ static void g2d_userptr_put_dma_addr(struct drm_device *drm_dev, return; out: - dma_unmap_sg(to_dma_dev(drm_dev), g2d_userptr->sgt->sgl, + dma_unmap_sg(to_dma_dev(g2d->drm_dev), g2d_userptr->sgt->sgl, g2d_userptr->sgt->nents, DMA_BIDIRECTIONAL); pages = frame_vector_pages(g2d_userptr->vec); @@ -419,16 +417,14 @@ static void g2d_userptr_put_dma_addr(struct drm_device *drm_dev, kfree(g2d_userptr); } -static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev, +static dma_addr_t *g2d_userptr_get_dma_addr(struct g2d_data *g2d, unsigned long userptr, unsigned long size, struct drm_file *filp, unsigned long *obj) { struct drm_exynos_file_private *file_priv = filp->driver_priv; - struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv; struct g2d_cmdlist_userptr *g2d_userptr; - struct g2d_data *g2d; struct sg_table *sgt; unsigned long start, end; unsigned int npages, offset; @@ -439,10 +435,8 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev, return ERR_PTR(-EINVAL); } - g2d = dev_get_drvdata(g2d_priv->dev); - /* check if userptr already exists in userptr_list. */ - list_for_each_entry(g2d_userptr, &g2d_priv->userptr_list, list) { + list_for_each_entry(g2d_userptr, &file_priv->userptr_list, list) { if (g2d_userptr->userptr == userptr) { /* * also check size because there could be same address @@ -517,7 +511,7 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev, g2d_userptr->sgt = sgt; - if (!dma_map_sg(to_dma_dev(drm_dev), sgt->sgl, sgt->nents, + if (!dma_map_sg(to_dma_dev(g2d->drm_dev), sgt->sgl, sgt->nents, DMA_BIDIRECTIONAL)) { DRM_ERROR("failed to map sgt with dma region.\n"); ret = -ENOMEM; @@ -527,7 +521,7 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev, g2d_userptr->dma_addr = sgt->sgl[0].dma_address; g2d_userptr->userptr = userptr; - list_add_tail(&g2d_userptr->list, &g2d_priv->userptr_list); + list_add_tail(&g2d_userptr->list, &file_priv->userptr_list); if (g2d->current_pool + (npages << PAGE_SHIFT) < g2d->max_pool) { g2d->current_pool += npages << PAGE_SHIFT; @@ -556,17 +550,14 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev, return ERR_PTR(ret); } -static void g2d_userptr_free_all(struct drm_device *drm_dev, - struct g2d_data *g2d, - struct drm_file *filp) +static void g2d_userptr_free_all(struct g2d_data *g2d, struct drm_file *filp) { struct drm_exynos_file_private *file_priv = filp->driver_priv; - struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv; struct g2d_cmdlist_userptr *g2d_userptr, *n; - list_for_each_entry_safe(g2d_userptr, n, &g2d_priv->userptr_list, list) + list_for_each_entry_safe(g2d_userptr, n, &file_priv->userptr_list, list) if (g2d_userptr->in_pool) - g2d_userptr_put_dma_addr(drm_dev, + g2d_userptr_put_dma_addr(g2d, (unsigned long)g2d_userptr, true); @@ -758,7 +749,7 @@ static int g2d_map_cmdlist_gem(struct g2d_data *g2d, goto err; } - addr = g2d_userptr_get_dma_addr(drm_dev, + addr = g2d_userptr_get_dma_addr(g2d, g2d_userptr.userptr, g2d_userptr.size, file, @@ -785,7 +776,6 @@ static void g2d_unmap_cmdlist_gem(struct g2d_data *g2d, struct g2d_cmdlist_node *node, struct drm_file *filp) { - struct exynos_drm_subdrv *subdrv = &g2d->subdrv; struct g2d_buf_info *buf_info = &node->buf_info; int i; @@ -800,11 +790,9 @@ static void g2d_unmap_cmdlist_gem(struct g2d_data *g2d, handle = buf_info->handles[reg_type]; if (buf_info->types[reg_type] == BUF_TYPE_GEM) - exynos_drm_gem_put_dma_addr(subdrv->drm_dev, handle, - filp); + exynos_drm_gem_put_dma_addr(g2d->drm_dev, handle, filp); else - g2d_userptr_put_dma_addr(subdrv->drm_dev, handle, - false); + g2d_userptr_put_dma_addr(g2d, handle, false); buf_info->reg_types[i] = REG_TYPE_NONE; buf_info->handles[reg_type] = 0; @@ -922,7 +910,7 @@ static void g2d_runqueue_worker(struct work_struct *work) static void g2d_finish_event(struct g2d_data *g2d, u32 cmdlist_no) { - struct drm_device *drm_dev = g2d->subdrv.drm_dev; + struct drm_device *drm_dev = g2d->drm_dev; struct g2d_runqueue_node *runqueue_node = g2d->runqueue_node; struct drm_exynos_pending_g2d_event *e; struct timespec64 now; @@ -1031,7 +1019,7 @@ static void g2d_wait_finish(struct g2d_data *g2d, struct drm_file *file) mutex_unlock(&g2d->runqueue_mutex); } -static int g2d_check_reg_offset(struct device *dev, +static int g2d_check_reg_offset(struct g2d_data *g2d, struct g2d_cmdlist_node *node, int nr, bool for_addr) { @@ -1131,7 +1119,7 @@ static int g2d_check_reg_offset(struct device *dev, return 0; err: - dev_err(dev, "Bad register offset: 0x%lx\n", cmdlist->data[index]); + dev_err(g2d->dev, "Bad register offset: 0x%lx\n", cmdlist->data[index]); return -EINVAL; } @@ -1139,23 +1127,8 @@ static int g2d_check_reg_offset(struct device *dev, int exynos_g2d_get_ver_ioctl(struct drm_device *drm_dev, void *data, struct drm_file *file) { - struct drm_exynos_file_private *file_priv = file->driver_priv; - struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv; - struct device *dev; - struct g2d_data *g2d; struct drm_exynos_g2d_get_ver *ver = data; - if (!g2d_priv) - return -ENODEV; - - dev = g2d_priv->dev; - if (!dev) - return -ENODEV; - - g2d = dev_get_drvdata(dev); - if (!g2d) - return -EFAULT; - ver->major = G2D_HW_MAJOR_VER; ver->minor = G2D_HW_MINOR_VER; @@ -1166,9 +1139,8 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data, struct drm_file *file) { struct drm_exynos_file_private *file_priv = file->driver_priv; - struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv; - struct device *dev; - struct g2d_data *g2d; + struct exynos_drm_private *priv = drm_dev->dev_private; + struct g2d_data *g2d = dev_get_drvdata(priv->g2d_dev); struct drm_exynos_g2d_set_cmdlist *req = data; struct drm_exynos_g2d_cmd *cmd; struct drm_exynos_pending_g2d_event *e; @@ -1177,17 +1149,6 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data, int size; int ret; - if (!g2d_priv) - return -ENODEV; - - dev = g2d_priv->dev; - if (!dev) - return -ENODEV; - - g2d = dev_get_drvdata(dev); - if (!g2d) - return -EFAULT; - node = g2d_get_cmdlist(g2d); if (!node) return -ENOMEM; @@ -1199,7 +1160,7 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data, */ if (req->cmd_nr > G2D_CMDLIST_DATA_NUM || req->cmd_buf_nr > G2D_CMDLIST_DATA_NUM) { - dev_err(dev, "number of submitted G2D commands exceeds limit\n"); + dev_err(g2d->dev, "number of submitted G2D commands exceeds limit\n"); return -EINVAL; } @@ -1267,7 +1228,7 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data, */ size = cmdlist->last + req->cmd_nr * 2 + req->cmd_buf_nr * 2 + 2; if (size > G2D_CMDLIST_DATA_NUM) { - dev_err(dev, "cmdlist size is too big\n"); + dev_err(g2d->dev, "cmdlist size is too big\n"); ret = -EINVAL; goto err_free_event; } @@ -1282,7 +1243,7 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data, } cmdlist->last += req->cmd_nr * 2; - ret = g2d_check_reg_offset(dev, node, req->cmd_nr, false); + ret = g2d_check_reg_offset(g2d, node, req->cmd_nr, false); if (ret < 0) goto err_free_event; @@ -1301,7 +1262,7 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data, } cmdlist->last += req->cmd_buf_nr * 2; - ret = g2d_check_reg_offset(dev, node, req->cmd_buf_nr, true); + ret = g2d_check_reg_offset(g2d, node, req->cmd_buf_nr, true); if (ret < 0) goto err_free_event; @@ -1319,7 +1280,7 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data, /* tail */ cmdlist->data[cmdlist->last] = 0; - g2d_add_cmdlist_to_inuse(g2d_priv, node); + g2d_add_cmdlist_to_inuse(file_priv, node); return 0; @@ -1337,25 +1298,13 @@ int exynos_g2d_exec_ioctl(struct drm_device *drm_dev, void *data, struct drm_file *file) { struct drm_exynos_file_private *file_priv = file->driver_priv; - struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv; - struct device *dev; - struct g2d_data *g2d; + struct exynos_drm_private *priv = drm_dev->dev_private; + struct g2d_data *g2d = dev_get_drvdata(priv->g2d_dev); struct drm_exynos_g2d_exec *req = data; struct g2d_runqueue_node *runqueue_node; struct list_head *run_cmdlist; struct list_head *event_list; - if (!g2d_priv) - return -ENODEV; - - dev = g2d_priv->dev; - if (!dev) - return -ENODEV; - - g2d = dev_get_drvdata(dev); - if (!g2d) - return -EFAULT; - runqueue_node = kmem_cache_alloc(g2d->runqueue_slab, GFP_KERNEL); if (!runqueue_node) return -ENOMEM; @@ -1367,11 +1316,11 @@ int exynos_g2d_exec_ioctl(struct drm_device *drm_dev, void *data, init_completion(&runqueue_node->complete); runqueue_node->async = req->async; - list_splice_init(&g2d_priv->inuse_cmdlist, run_cmdlist); - list_splice_init(&g2d_priv->event_list, event_list); + list_splice_init(&file_priv->inuse_cmdlist, run_cmdlist); + list_splice_init(&file_priv->event_list, event_list); if (list_empty(run_cmdlist)) { - dev_err(dev, "there is no inuse cmdlist\n"); + dev_err(g2d->dev, "there is no inuse cmdlist\n"); kmem_cache_free(g2d->runqueue_slab, runqueue_node); return -EPERM; } @@ -1395,71 +1344,28 @@ int exynos_g2d_exec_ioctl(struct drm_device *drm_dev, void *data, return 0; } -static int g2d_subdrv_probe(struct drm_device *drm_dev, struct device *dev) -{ - struct g2d_data *g2d; - int ret; - - g2d = dev_get_drvdata(dev); - if (!g2d) - return -EFAULT; - - /* allocate dma-aware cmdlist buffer. */ - ret = g2d_init_cmdlist(g2d); - if (ret < 0) { - dev_err(dev, "cmdlist init failed\n"); - return ret; - } - - ret = drm_iommu_attach_device(drm_dev, dev); - if (ret < 0) { - dev_err(dev, "failed to enable iommu.\n"); - g2d_fini_cmdlist(g2d); - } - - return ret; - -} - -static void g2d_subdrv_remove(struct drm_device *drm_dev, struct device *dev) -{ - drm_iommu_detach_device(drm_dev, dev); -} - -static int g2d_open(struct drm_device *drm_dev, struct device *dev, - struct drm_file *file) +int g2d_open(struct drm_device *drm_dev, struct drm_file *file) { struct drm_exynos_file_private *file_priv = file->driver_priv; - struct exynos_drm_g2d_private *g2d_priv; - - g2d_priv = kzalloc(sizeof(*g2d_priv), GFP_KERNEL); - if (!g2d_priv) - return -ENOMEM; - - g2d_priv->dev = dev; - file_priv->g2d_priv = g2d_priv; - INIT_LIST_HEAD(&g2d_priv->inuse_cmdlist); - INIT_LIST_HEAD(&g2d_priv->event_list); - INIT_LIST_HEAD(&g2d_priv->userptr_list); + INIT_LIST_HEAD(&file_priv->inuse_cmdlist); + INIT_LIST_HEAD(&file_priv->event_list); + INIT_LIST_HEAD(&file_priv->userptr_list); return 0; } -static void g2d_close(struct drm_device *drm_dev, struct device *dev, - struct drm_file *file) +void g2d_close(struct drm_device *drm_dev, struct drm_file *file) { struct drm_exynos_file_private *file_priv = file->driver_priv; - struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv; + struct exynos_drm_private *priv = drm_dev->dev_private; struct g2d_data *g2d; struct g2d_cmdlist_node *node, *n; - if (!dev) + if (!priv->g2d_dev) return; - g2d = dev_get_drvdata(dev); - if (!g2d) - return; + g2d = dev_get_drvdata(priv->g2d_dev); /* Remove the runqueue nodes that belong to us. */ mutex_lock(&g2d->runqueue_mutex); @@ -1480,24 +1386,70 @@ static void g2d_close(struct drm_device *drm_dev, struct device *dev, * Properly unmap these buffers here. */ mutex_lock(&g2d->cmdlist_mutex); - list_for_each_entry_safe(node, n, &g2d_priv->inuse_cmdlist, list) { + list_for_each_entry_safe(node, n, &file_priv->inuse_cmdlist, list) { g2d_unmap_cmdlist_gem(g2d, node, file); list_move_tail(&node->list, &g2d->free_cmdlist); } mutex_unlock(&g2d->cmdlist_mutex); /* release all g2d_userptr in pool. */ - g2d_userptr_free_all(drm_dev, g2d, file); + g2d_userptr_free_all(g2d, file); +} + +static int g2d_bind(struct device *dev, struct device *master, void *data) +{ + struct g2d_data *g2d = dev_get_drvdata(dev); + struct drm_device *drm_dev = data; + struct exynos_drm_private *priv = drm_dev->dev_private; + int ret; + + g2d->drm_dev = drm_dev; + + /* allocate dma-aware cmdlist buffer. */ + ret = g2d_init_cmdlist(g2d); + if (ret < 0) { + dev_err(dev, "cmdlist init failed\n"); + return ret; + } + + ret = drm_iommu_attach_device(drm_dev, dev); + if (ret < 0) { + dev_err(dev, "failed to enable iommu.\n"); + g2d_fini_cmdlist(g2d); + return ret; + } + priv->g2d_dev = dev; - kfree(file_priv->g2d_priv); + dev_info(dev, "The Exynos G2D (ver %d.%d) successfully registered.\n", + G2D_HW_MAJOR_VER, G2D_HW_MINOR_VER); + return 0; } +static void g2d_unbind(struct device *dev, struct device *master, void *data) +{ + struct g2d_data *g2d = dev_get_drvdata(dev); + struct drm_device *drm_dev = data; + struct exynos_drm_private *priv = drm_dev->dev_private; + + /* Suspend operation and wait for engine idle. */ + set_bit(G2D_BIT_SUSPEND_RUNQUEUE, &g2d->flags); + g2d_wait_finish(g2d, NULL); + priv->g2d_dev = NULL; + + cancel_work_sync(&g2d->runqueue_work); + drm_iommu_detach_device(g2d->drm_dev, dev); +} + +static const struct component_ops g2d_component_ops = { + .bind = g2d_bind, + .unbind = g2d_unbind, +}; + static int g2d_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct resource *res; struct g2d_data *g2d; - struct exynos_drm_subdrv *subdrv; int ret; g2d = devm_kzalloc(dev, sizeof(*g2d), GFP_KERNEL); @@ -1564,22 +1516,12 @@ static int g2d_probe(struct platform_device *pdev) platform_set_drvdata(pdev, g2d); - subdrv = &g2d->subdrv; - subdrv->dev = dev; - subdrv->probe = g2d_subdrv_probe; - subdrv->remove = g2d_subdrv_remove; - subdrv->open = g2d_open; - subdrv->close = g2d_close; - - ret = exynos_drm_subdrv_register(subdrv); + ret = component_add(dev, &g2d_component_ops); if (ret < 0) { dev_err(dev, "failed to register drm g2d device\n"); goto err_put_clk; } - dev_info(dev, "The Exynos G2D (ver %d.%d) successfully probed.\n", - G2D_HW_MAJOR_VER, G2D_HW_MINOR_VER); - return 0; err_put_clk: @@ -1595,12 +1537,7 @@ static int g2d_remove(struct platform_device *pdev) { struct g2d_data *g2d = platform_get_drvdata(pdev); - /* Suspend operation and wait for engine idle. */ - set_bit(G2D_BIT_SUSPEND_RUNQUEUE, &g2d->flags); - g2d_wait_finish(g2d, NULL); - - cancel_work_sync(&g2d->runqueue_work); - exynos_drm_subdrv_unregister(&g2d->subdrv); + component_del(&pdev->dev, &g2d_component_ops); /* There should be no locking needed here. */ g2d_remove_runqueue_nodes(g2d, NULL); diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.h b/drivers/gpu/drm/exynos/exynos_drm_g2d.h index 1a9c7ca8c15bb..287b2ed8f1782 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.h +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.h @@ -14,6 +14,9 @@ extern int exynos_g2d_set_cmdlist_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int exynos_g2d_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); + +extern int g2d_open(struct drm_device *drm_dev, struct drm_file *file); +extern void g2d_close(struct drm_device *drm_dev, struct drm_file *file); #else static inline int exynos_g2d_get_ver_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) @@ -33,4 +36,12 @@ static inline int exynos_g2d_exec_ioctl(struct drm_device *dev, void *data, { return -ENODEV; } + +int g2d_open(struct drm_device *drm_dev, struct drm_file *file) +{ + return 0; +} + +void g2d_close(struct drm_device *drm_dev, struct drm_file *file) +{ } #endif -- GitLab From 3aa2a5c14076e212fb3220d827c2e83806e7ce30 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski <m.szyprowski@samsung.com> Date: Mon, 9 Jul 2018 15:44:31 +0200 Subject: [PATCH 1288/1506] drm/exynos: gem: Simplify access to exynos GEM objects Replace all calls to exynos_drm_gem_get_{dma_addr,size}, by a simpler function exynos_drm_gem_get(). This lets the caller to get access to exynos_drm_gem object and extract any information about GEM object without searching object tree for getting each parameter. Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Inki Dae <inki.dae@samsung.com> --- drivers/gpu/drm/exynos/exynos_drm_g2d.c | 49 +++++++++------------ drivers/gpu/drm/exynos/exynos_drm_gem.c | 58 +++---------------------- drivers/gpu/drm/exynos/exynos_drm_gem.h | 24 ++++------ 3 files changed, 35 insertions(+), 96 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index 27b929757b437..f2481a2014bb3 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -191,7 +191,7 @@ struct g2d_buf_desc { struct g2d_buf_info { unsigned int map_nr; enum g2d_reg_type reg_types[MAX_REG_TYPE_NR]; - unsigned long handles[MAX_REG_TYPE_NR]; + void *obj[MAX_REG_TYPE_NR]; unsigned int types[MAX_REG_TYPE_NR]; struct g2d_buf_desc descs[MAX_REG_TYPE_NR]; }; @@ -374,11 +374,10 @@ static void g2d_add_cmdlist_to_inuse(struct drm_exynos_file_private *file_priv, } static void g2d_userptr_put_dma_addr(struct g2d_data *g2d, - unsigned long obj, + void *obj, bool force) { - struct g2d_cmdlist_userptr *g2d_userptr = - (struct g2d_cmdlist_userptr *)obj; + struct g2d_cmdlist_userptr *g2d_userptr = obj; struct page **pages; if (!obj) @@ -421,7 +420,7 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct g2d_data *g2d, unsigned long userptr, unsigned long size, struct drm_file *filp, - unsigned long *obj) + void **obj) { struct drm_exynos_file_private *file_priv = filp->driver_priv; struct g2d_cmdlist_userptr *g2d_userptr; @@ -444,7 +443,7 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct g2d_data *g2d, */ if (g2d_userptr->size == size) { atomic_inc(&g2d_userptr->refcount); - *obj = (unsigned long)g2d_userptr; + *obj = g2d_userptr; return &g2d_userptr->dma_addr; } @@ -528,7 +527,7 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct g2d_data *g2d, g2d_userptr->in_pool = true; } - *obj = (unsigned long)g2d_userptr; + *obj = g2d_userptr; return &g2d_userptr->dma_addr; @@ -557,9 +556,7 @@ static void g2d_userptr_free_all(struct g2d_data *g2d, struct drm_file *filp) list_for_each_entry_safe(g2d_userptr, n, &file_priv->userptr_list, list) if (g2d_userptr->in_pool) - g2d_userptr_put_dma_addr(g2d, - (unsigned long)g2d_userptr, - true); + g2d_userptr_put_dma_addr(g2d, g2d_userptr, true); g2d->current_pool = 0; } @@ -714,26 +711,23 @@ static int g2d_map_cmdlist_gem(struct g2d_data *g2d, buf_desc = &buf_info->descs[reg_type]; if (buf_info->types[reg_type] == BUF_TYPE_GEM) { - unsigned long size; + struct exynos_drm_gem *exynos_gem; - size = exynos_drm_gem_get_size(drm_dev, handle, file); - if (!size) { + exynos_gem = exynos_drm_gem_get(file, handle); + if (!exynos_gem) { ret = -EFAULT; goto err; } - if (!g2d_check_buf_desc_is_valid(buf_desc, reg_type, - size)) { + if (!g2d_check_buf_desc_is_valid(buf_desc, + reg_type, exynos_gem->size)) { + exynos_drm_gem_put(exynos_gem); ret = -EFAULT; goto err; } - addr = exynos_drm_gem_get_dma_addr(drm_dev, handle, - file); - if (IS_ERR(addr)) { - ret = -EFAULT; - goto err; - } + addr = &exynos_gem->dma_addr; + buf_info->obj[reg_type] = exynos_gem; } else { struct drm_exynos_g2d_userptr g2d_userptr; @@ -753,7 +747,7 @@ static int g2d_map_cmdlist_gem(struct g2d_data *g2d, g2d_userptr.userptr, g2d_userptr.size, file, - &handle); + &buf_info->obj[reg_type]); if (IS_ERR(addr)) { ret = -EFAULT; goto err; @@ -762,7 +756,6 @@ static int g2d_map_cmdlist_gem(struct g2d_data *g2d, cmdlist->data[reg_pos + 1] = *addr; buf_info->reg_types[i] = reg_type; - buf_info->handles[reg_type] = handle; } return 0; @@ -782,20 +775,20 @@ static void g2d_unmap_cmdlist_gem(struct g2d_data *g2d, for (i = 0; i < buf_info->map_nr; i++) { struct g2d_buf_desc *buf_desc; enum g2d_reg_type reg_type; - unsigned long handle; + void *obj; reg_type = buf_info->reg_types[i]; buf_desc = &buf_info->descs[reg_type]; - handle = buf_info->handles[reg_type]; + obj = buf_info->obj[reg_type]; if (buf_info->types[reg_type] == BUF_TYPE_GEM) - exynos_drm_gem_put_dma_addr(g2d->drm_dev, handle, filp); + exynos_drm_gem_put(obj); else - g2d_userptr_put_dma_addr(g2d, handle, false); + g2d_userptr_put_dma_addr(g2d, obj, false); buf_info->reg_types[i] = REG_TYPE_NONE; - buf_info->handles[reg_type] = 0; + buf_info->obj[reg_type] = NULL; buf_info->types[reg_type] = 0; memset(buf_desc, 0x00, sizeof(*buf_desc)); } diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c index bdf5a7655228b..34ace85feb688 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c @@ -171,26 +171,6 @@ void exynos_drm_gem_destroy(struct exynos_drm_gem *exynos_gem) kfree(exynos_gem); } -unsigned long exynos_drm_gem_get_size(struct drm_device *dev, - unsigned int gem_handle, - struct drm_file *file_priv) -{ - struct exynos_drm_gem *exynos_gem; - struct drm_gem_object *obj; - - obj = drm_gem_object_lookup(file_priv, gem_handle); - if (!obj) { - DRM_ERROR("failed to lookup gem object.\n"); - return 0; - } - - exynos_gem = to_exynos_gem(obj); - - drm_gem_object_put_unlocked(obj); - - return exynos_gem->size; -} - static struct exynos_drm_gem *exynos_drm_gem_init(struct drm_device *dev, unsigned long size) { @@ -299,43 +279,15 @@ int exynos_drm_gem_map_ioctl(struct drm_device *dev, void *data, &args->offset); } -dma_addr_t *exynos_drm_gem_get_dma_addr(struct drm_device *dev, - unsigned int gem_handle, - struct drm_file *filp) +struct exynos_drm_gem *exynos_drm_gem_get(struct drm_file *filp, + unsigned int gem_handle) { - struct exynos_drm_gem *exynos_gem; struct drm_gem_object *obj; obj = drm_gem_object_lookup(filp, gem_handle); - if (!obj) { - DRM_ERROR("failed to lookup gem object.\n"); - return ERR_PTR(-EINVAL); - } - - exynos_gem = to_exynos_gem(obj); - - return &exynos_gem->dma_addr; -} - -void exynos_drm_gem_put_dma_addr(struct drm_device *dev, - unsigned int gem_handle, - struct drm_file *filp) -{ - struct drm_gem_object *obj; - - obj = drm_gem_object_lookup(filp, gem_handle); - if (!obj) { - DRM_ERROR("failed to lookup gem object.\n"); - return; - } - - drm_gem_object_put_unlocked(obj); - - /* - * decrease obj->refcount one more time because we has already - * increased it at exynos_drm_gem_get_dma_addr(). - */ - drm_gem_object_put_unlocked(obj); + if (!obj) + return NULL; + return to_exynos_gem(obj); } static int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem *exynos_gem, diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h index 9057d7f1d6ed4..d46a62c30812c 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.h +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h @@ -77,32 +77,26 @@ int exynos_drm_gem_map_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); /* - * get dma address from gem handle and this function could be used for + * get exynos drm object from gem handle, this function could be used for * other drivers such as 2d/3d acceleration drivers. * with this function call, gem object reference count would be increased. */ -dma_addr_t *exynos_drm_gem_get_dma_addr(struct drm_device *dev, - unsigned int gem_handle, - struct drm_file *filp); +struct exynos_drm_gem *exynos_drm_gem_get(struct drm_file *filp, + unsigned int gem_handle); /* - * put dma address from gem handle and this function could be used for - * other drivers such as 2d/3d acceleration drivers. - * with this function call, gem object reference count would be decreased. + * put exynos drm object acquired from exynos_drm_gem_get(), + * gem object reference count would be decreased. */ -void exynos_drm_gem_put_dma_addr(struct drm_device *dev, - unsigned int gem_handle, - struct drm_file *filp); +static inline void exynos_drm_gem_put(struct exynos_drm_gem *exynos_gem) +{ + drm_gem_object_put_unlocked(&exynos_gem->base); +} /* get buffer information to memory region allocated by gem. */ int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -/* get buffer size to gem handle. */ -unsigned long exynos_drm_gem_get_size(struct drm_device *dev, - unsigned int gem_handle, - struct drm_file *file_priv); - /* free gem object. */ void exynos_drm_gem_free_object(struct drm_gem_object *obj); -- GitLab From e978de54957f49333266f0212bb3c27e61f0bceb Mon Sep 17 00:00:00 2001 From: Marek Szyprowski <m.szyprowski@samsung.com> Date: Mon, 9 Jul 2018 15:44:32 +0200 Subject: [PATCH 1289/1506] drm/exynos: Use common exynos_drm_gem_get()/put() functions for GEM lookup Use recently introduced common helpers to unify GEM handling code. Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Inki Dae <inki.dae@samsung.com> --- drivers/gpu/drm/exynos/exynos_drm_fb.c | 10 ++++------ drivers/gpu/drm/exynos/exynos_drm_ipp.c | 10 +++++----- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index 27b7d34d776cb..9f52382e19ee3 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c @@ -101,7 +101,6 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, { const struct drm_format_info *info = drm_get_format_info(dev, mode_cmd); struct exynos_drm_gem *exynos_gem[MAX_FB_BUFFER]; - struct drm_gem_object *obj; struct drm_framebuffer *fb; int i; int ret; @@ -112,15 +111,14 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, unsigned long size = height * mode_cmd->pitches[i] + mode_cmd->offsets[i]; - obj = drm_gem_object_lookup(file_priv, mode_cmd->handles[i]); - if (!obj) { + exynos_gem[i] = exynos_drm_gem_get(file_priv, + mode_cmd->handles[i]); + if (!exynos_gem[i]) { DRM_ERROR("failed to lookup gem object\n"); ret = -ENOENT; goto err; } - exynos_gem[i] = to_exynos_gem(obj); - if (size > exynos_gem[i]->size) { i++; ret = -EINVAL; @@ -138,7 +136,7 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, err: while (i--) - drm_gem_object_put_unlocked(&exynos_gem[i]->base); + exynos_drm_gem_put(exynos_gem[i]); return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c index b435db8fc9167..23226a0212e8f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c +++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c @@ -350,13 +350,13 @@ static int exynos_drm_ipp_task_setup_buffer(struct exynos_drm_ipp_buffer *buf, unsigned int height = (i == 0) ? buf->buf.height : DIV_ROUND_UP(buf->buf.height, buf->format->vsub); unsigned long size = height * buf->buf.pitch[i]; - struct drm_gem_object *obj = drm_gem_object_lookup(filp, + struct exynos_drm_gem *gem = exynos_drm_gem_get(filp, buf->buf.gem_id[i]); - if (!obj) { + if (!gem) { ret = -ENOENT; goto gem_free; } - buf->exynos_gem[i] = to_exynos_gem(obj); + buf->exynos_gem[i] = gem; if (size + buf->buf.offset[i] > buf->exynos_gem[i]->size) { i++; @@ -370,7 +370,7 @@ static int exynos_drm_ipp_task_setup_buffer(struct exynos_drm_ipp_buffer *buf, return 0; gem_free: while (i--) { - drm_gem_object_put_unlocked(&buf->exynos_gem[i]->base); + exynos_drm_gem_put(buf->exynos_gem[i]); buf->exynos_gem[i] = NULL; } return ret; @@ -383,7 +383,7 @@ static void exynos_drm_ipp_task_release_buf(struct exynos_drm_ipp_buffer *buf) if (!buf->exynos_gem[0]) return; for (i = 0; i < buf->format->num_planes; i++) - drm_gem_object_put_unlocked(&buf->exynos_gem[i]->base); + exynos_drm_gem_put(buf->exynos_gem[i]); } static void exynos_drm_ipp_task_free(struct exynos_drm_ipp *ipp, -- GitLab From eebdc3b49abbfc7ab574eaddebfec64df27a5cf4 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski <m.szyprowski@samsung.com> Date: Mon, 11 Jun 2018 14:24:58 +0200 Subject: [PATCH 1290/1506] drm/exynos: Drop useless check from exynos_drm_{suspend,resume} The virtual Exynos DRM device has no runtime PM enabled, so checking for its runtime suspended state is useless. Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Inki Dae <inki.dae@samsung.com> --- drivers/gpu/drm/exynos/exynos_drm_drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 7d0164aea36b4..29fe6138e182f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -152,7 +152,7 @@ static int exynos_drm_suspend(struct device *dev) struct drm_device *drm_dev = dev_get_drvdata(dev); struct exynos_drm_private *private; - if (pm_runtime_suspended(dev) || !drm_dev) + if (!drm_dev) return 0; private = drm_dev->dev_private; @@ -174,7 +174,7 @@ static int exynos_drm_resume(struct device *dev) struct drm_device *drm_dev = dev_get_drvdata(dev); struct exynos_drm_private *private; - if (pm_runtime_suspended(dev) || !drm_dev) + if (!drm_dev) return 0; private = drm_dev->dev_private; -- GitLab From dc684af6fc8d3b9be7fda67e380e91bfdc773aa5 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski <m.szyprowski@samsung.com> Date: Mon, 11 Jun 2018 14:24:59 +0200 Subject: [PATCH 1291/1506] drm/exynos: Suspend/resume display pipeline as early/late as possible In the current code, exynos_drm_suspend() function is called after all real devices (CRTCs, Encoders, etc) are suspended, because Exynos DRM virtual platform device is created as last device in the system (as a part of DRM registration). None of the devices for real hardware modules has its own system suspend/resume callbacks, so it doesn't change any order of the executed code, but it has a side-effect: runtime PM callbacks for real devices are not executed, because those devices are considered by PM core as already suspended. This might cause issues on boards with complex pipelines, where something depends on the runtime PM state of the given device. To ensure that exynos_drm_suspend() is called before any suspend callback from the real devices, assign it to .prepare callback. Same for exynos_drm_resume(), using .complete callback ensures that all real devices have been resumed when calling it. Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Inki Dae <inki.dae@samsung.com> --- drivers/gpu/drm/exynos/exynos_drm_drv.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 29fe6138e182f..b599f74692e5c 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -146,7 +146,6 @@ static struct drm_driver exynos_drm_driver = { .minor = DRIVER_MINOR, }; -#ifdef CONFIG_PM_SLEEP static int exynos_drm_suspend(struct device *dev) { struct drm_device *drm_dev = dev_get_drvdata(dev); @@ -169,25 +168,23 @@ static int exynos_drm_suspend(struct device *dev) return 0; } -static int exynos_drm_resume(struct device *dev) +static void exynos_drm_resume(struct device *dev) { struct drm_device *drm_dev = dev_get_drvdata(dev); struct exynos_drm_private *private; if (!drm_dev) - return 0; + return; private = drm_dev->dev_private; drm_atomic_helper_resume(drm_dev, private->suspend_state); exynos_drm_fbdev_resume(drm_dev); drm_kms_helper_poll_enable(drm_dev); - - return 0; } -#endif static const struct dev_pm_ops exynos_drm_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(exynos_drm_suspend, exynos_drm_resume) + .prepare = exynos_drm_suspend, + .complete = exynos_drm_resume, }; /* forward declaration */ -- GitLab From 7e915746de03e0e62d58491f22805cc5a80a581a Mon Sep 17 00:00:00 2001 From: Marek Szyprowski <m.szyprowski@samsung.com> Date: Mon, 11 Jun 2018 14:25:00 +0200 Subject: [PATCH 1292/1506] drm/exynos: Ensure suspended runtime PM state during system suspend Add calls to pm_runtime_force_{suspend,resume} as SYSTEM_SLEEP_PM_OPS for all drivers for the real Exynos DRM hardware modules. This ensures that the resources will be released for the system PM suspend/resume cycle. Exynos DRM core already takes care of suspending the whole display pipeline before PM callbacks of the real devices are called. Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Inki Dae <inki.dae@samsung.com> --- drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 2 ++ drivers/gpu/drm/exynos/exynos7_drm_decon.c | 2 ++ drivers/gpu/drm/exynos/exynos_dp.c | 3 +++ drivers/gpu/drm/exynos/exynos_drm_dsi.c | 2 ++ drivers/gpu/drm/exynos/exynos_drm_fimd.c | 2 ++ drivers/gpu/drm/exynos/exynos_drm_mic.c | 2 ++ drivers/gpu/drm/exynos/exynos_hdmi.c | 2 ++ drivers/gpu/drm/exynos/exynos_mixer.c | 2 ++ 8 files changed, 17 insertions(+) diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index e868773ea5097..94529aa823392 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -673,6 +673,8 @@ static int exynos5433_decon_resume(struct device *dev) static const struct dev_pm_ops exynos5433_decon_pm_ops = { SET_RUNTIME_PM_OPS(exynos5433_decon_suspend, exynos5433_decon_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) }; static const struct of_device_id exynos5433_decon_driver_dt_match[] = { diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c index 3931d5e33fe07..88cbd000eb094 100644 --- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c @@ -832,6 +832,8 @@ static int exynos7_decon_resume(struct device *dev) static const struct dev_pm_ops exynos7_decon_pm_ops = { SET_RUNTIME_PM_OPS(exynos7_decon_suspend, exynos7_decon_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) }; struct platform_driver decon_driver = { diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c index af7ab1ceb50f4..c8449ae4f4fed 100644 --- a/drivers/gpu/drm/exynos/exynos_dp.c +++ b/drivers/gpu/drm/exynos/exynos_dp.c @@ -16,6 +16,7 @@ #include <linux/clk.h> #include <linux/of_graph.h> #include <linux/component.h> +#include <linux/pm_runtime.h> #include <video/of_display_timing.h> #include <video/of_videomode.h> #include <video/videomode.h> @@ -278,6 +279,8 @@ static int exynos_dp_resume(struct device *dev) static const struct dev_pm_ops exynos_dp_pm_ops = { SET_RUNTIME_PM_OPS(exynos_dp_suspend, exynos_dp_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) }; static const struct of_device_id exynos_dp_match[] = { diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index a1ed6146a3b5c..781b82c2c579b 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -1863,6 +1863,8 @@ static int __maybe_unused exynos_dsi_resume(struct device *dev) static const struct dev_pm_ops exynos_dsi_pm_ops = { SET_RUNTIME_PM_OPS(exynos_dsi_suspend, exynos_dsi_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) }; struct platform_driver dsi_driver = { diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 01b1570d0c3ab..b7f56935a46bc 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -1192,6 +1192,8 @@ static int exynos_fimd_resume(struct device *dev) static const struct dev_pm_ops exynos_fimd_pm_ops = { SET_RUNTIME_PM_OPS(exynos_fimd_suspend, exynos_fimd_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) }; struct platform_driver fimd_driver = { diff --git a/drivers/gpu/drm/exynos/exynos_drm_mic.c b/drivers/gpu/drm/exynos/exynos_drm_mic.c index 2174814273e20..2fd299a58297e 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_mic.c +++ b/drivers/gpu/drm/exynos/exynos_drm_mic.c @@ -367,6 +367,8 @@ static int exynos_mic_resume(struct device *dev) static const struct dev_pm_ops exynos_mic_pm_ops = { SET_RUNTIME_PM_OPS(exynos_mic_suspend, exynos_mic_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) }; static int exynos_mic_probe(struct platform_device *pdev) diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 3a11c719a5808..2092a650df7d5 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -2093,6 +2093,8 @@ static int __maybe_unused exynos_hdmi_resume(struct device *dev) static const struct dev_pm_ops exynos_hdmi_pm_ops = { SET_RUNTIME_PM_OPS(exynos_hdmi_suspend, exynos_hdmi_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) }; struct platform_driver hdmi_driver = { diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 272c79f5f5bff..e45278e076dac 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -1271,6 +1271,8 @@ static int __maybe_unused exynos_mixer_resume(struct device *dev) static const struct dev_pm_ops exynos_mixer_pm_ops = { SET_RUNTIME_PM_OPS(exynos_mixer_suspend, exynos_mixer_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) }; struct platform_driver mixer_driver = { -- GitLab From 3f2b78d630b46c7921cb415be35f686e5293c3a4 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski <krzk@kernel.org> Date: Wed, 18 Jul 2018 21:55:20 +0200 Subject: [PATCH 1293/1506] drm/exynos/mixer: Remove unused local variable priv Remove local variable 'priv' to fix GCC warning: drivers/gpu/drm/exynos/exynos_mixer.c: In function 'mixer_initialize': drivers/gpu/drm/exynos/exynos_mixer.c:840:29: warning: variable 'priv' set but not used [-Wunused-but-set-variable] Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org> Signed-off-by: Inki Dae <inki.dae@samsung.com> --- drivers/gpu/drm/exynos/exynos_mixer.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index e45278e076dac..ffbf4a950f696 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -837,8 +837,6 @@ static int mixer_initialize(struct mixer_context *mixer_ctx, struct drm_device *drm_dev) { int ret; - struct exynos_drm_private *priv; - priv = drm_dev->dev_private; mixer_ctx->drm_dev = drm_dev; -- GitLab From 226127a67e31a9518d9516d3e4890759b379d874 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= <michel.daenzer@amd.com> Date: Thu, 19 Jul 2018 18:33:39 +0200 Subject: [PATCH 1294/1506] drm/amdgpu: Fix RLC safe mode test in gfx_v9_0_enter_rlc_safe_mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We were testing the register offset, instead of the value stored in the register, therefore always timing out the loop. This reduces suspend time of the system in the bug report below by ~600 ms. Cc: stable@vger.kernel.org Bugzilla: https://bugs.freedesktop.org/107277 Tested-by: Paul Menzel <pmenzel@molgen.mpg.de> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Reviewed-by: Junwei Zhang <Jerry.Zhang@amd.com> Signed-off-by: Michel Dänzer <michel.daenzer@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index 9ab39117cc4e1..ef00d14f86453 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -3490,7 +3490,7 @@ static void gfx_v9_0_enter_rlc_safe_mode(struct amdgpu_device *adev) /* wait for RLC_SAFE_MODE */ for (i = 0; i < adev->usec_timeout; i++) { - if (!REG_GET_FIELD(SOC15_REG_OFFSET(GC, 0, mmRLC_SAFE_MODE), RLC_SAFE_MODE, CMD)) + if (!REG_GET_FIELD(RREG32_SOC15(GC, 0, mmRLC_SAFE_MODE), RLC_SAFE_MODE, CMD)) break; udelay(1); } -- GitLab From 59a8348fc5b363a0c19be73bc9f5790e0f8f803a Mon Sep 17 00:00:00 2001 From: Evan Quan <evan.quan@amd.com> Date: Fri, 20 Jul 2018 10:13:19 +0800 Subject: [PATCH 1295/1506] drm/amd/powerplay: slow UCLK switch when multiple displays not in sync Slow switch for UCLK when there is multiple displays and they are not in sync. Signed-off-by: Evan Quan <evan.quan@amd.com> Reviewed-by: Rex Zhu <rex.zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c index 6d93d52975ecb..94e847e34b720 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c @@ -3800,7 +3800,8 @@ static int vega10_notify_smc_display_config_after_ps_adjustment( uint32_t i; struct pp_display_clock_request clock_req; - if (hwmgr->display_config->num_display > 1) + if ((hwmgr->display_config->num_display > 1) && + !hwmgr->display_config->multi_monitor_in_sync) vega10_notify_smc_display_change(hwmgr, false); else vega10_notify_smc_display_change(hwmgr, true); -- GitLab From f132d56162e670d2338902753b88ecbf29ca46a0 Mon Sep 17 00:00:00 2001 From: Evan Quan <evan.quan@amd.com> Date: Mon, 16 Jul 2018 17:23:19 +0800 Subject: [PATCH 1296/1506] drm/amd/powerplay: correct the argument for PPSMC_MSG_SetUclkFastSwitch The argument was set wrongly. Fast/slow switch was asked when there is actually a slow/fast switch needed. Signed-off-by: Evan Quan <evan.quan@amd.com> Reviewed-by: Rex Zhu <rex.zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c | 2 +- drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c index 94e847e34b720..9f5ceee0fa638 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c @@ -3725,7 +3725,7 @@ static void vega10_notify_smc_display_change(struct pp_hwmgr *hwmgr, { smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetUclkFastSwitch, - has_disp ? 0 : 1); + has_disp ? 1 : 0); } int vega10_display_clock_voltage_request(struct pp_hwmgr *hwmgr, diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c index 4ed218dd8ba7a..35f96dacb50a2 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c @@ -1334,7 +1334,7 @@ static int vega12_notify_smc_display_change(struct pp_hwmgr *hwmgr, if (data->smu_features[GNLD_DPM_UCLK].enabled) return smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetUclkFastSwitch, - has_disp ? 0 : 1); + has_disp ? 1 : 0); return 0; } -- GitLab From 92859e0d5ce558df44eb05f7d5872edc96646b24 Mon Sep 17 00:00:00 2001 From: Evan Quan <evan.quan@amd.com> Date: Mon, 16 Jul 2018 17:25:30 +0800 Subject: [PATCH 1297/1506] drm/amd/powerplay: allow slow switch only if NBPState enabled v2 Otherwise there may be potential SMU performance issues. v2: fix commit description and coding style Signed-off-by: Evan Quan <evan.quan@amd.com> Reviewed-by: Rex Zhu <rex.zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c | 3 ++- drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c index 9f5ceee0fa638..fb86c24394ff4 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c @@ -3801,7 +3801,8 @@ static int vega10_notify_smc_display_config_after_ps_adjustment( struct pp_display_clock_request clock_req; if ((hwmgr->display_config->num_display > 1) && - !hwmgr->display_config->multi_monitor_in_sync) + !hwmgr->display_config->multi_monitor_in_sync && + !hwmgr->display_config->nb_pstate_switch_disable) vega10_notify_smc_display_change(hwmgr, false); else vega10_notify_smc_display_change(hwmgr, true); diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c index 35f96dacb50a2..0789d64246ca5 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c @@ -1389,7 +1389,8 @@ static int vega12_notify_smc_display_config_after_ps_adjustment( struct pp_display_clock_request clock_req; if ((hwmgr->display_config->num_display > 1) && - !hwmgr->display_config->multi_monitor_in_sync) + !hwmgr->display_config->multi_monitor_in_sync && + !hwmgr->display_config->nb_pstate_switch_disable) vega12_notify_smc_display_change(hwmgr, false); else vega12_notify_smc_display_change(hwmgr, true); -- GitLab From 456607d816d89a442a3d5ec98b02c8bc950b5228 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= <michel.daenzer@amd.com> Date: Thu, 19 Jul 2018 17:38:18 +0200 Subject: [PATCH 1298/1506] drm/amdgpu: Don't warn on destroying a pinned BO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The warning turned out to be not so useful, as BO destruction tends to be deferred to a workqueue. Also, we should be preventing any damage from this now, so not really important anymore to fix code doing this. Acked-by: Alex Deucher <alexander.deucher@amd.com> Tested-by: Mike Lothian <mike@fireburn.co.uk> Signed-off-by: Michel Dänzer <michel.daenzer@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index b12526ce1a9d3..3010f0136de9c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -89,7 +89,7 @@ static void amdgpu_ttm_bo_destroy(struct ttm_buffer_object *tbo) struct amdgpu_device *adev = amdgpu_ttm_adev(tbo->bdev); struct amdgpu_bo *bo = ttm_to_amdgpu_bo(tbo); - if (WARN_ON_ONCE(bo->pin_count > 0)) + if (bo->pin_count > 0) amdgpu_bo_subtract_pin_size(bo); if (bo->kfd_bo) -- GitLab From 5f8181733f6e5f8a4447f844efe4bdab5ed6a30e Mon Sep 17 00:00:00 2001 From: Shirish S <shirish.s@amd.com> Date: Mon, 23 Jul 2018 15:11:51 +0530 Subject: [PATCH 1299/1506] drm/amdgpu: move the amdgpu_fbdev_set_suspend() further up MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch moves amdgpu_fbdev_set_suspend() to the beginning of suspend sequence. This is to ensure fbcon does not to write to the VRAM after GPU is powerd down. Signed-off-by: Shirish S <shirish.s@amd.com> Reviewed-by: Michel Dänzer <michel.daenzer@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 61981d0701b51..ec53d8f96d063 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -2702,6 +2702,9 @@ int amdgpu_device_suspend(struct drm_device *dev, bool suspend, bool fbcon) drm_kms_helper_poll_disable(dev); + if (fbcon) + amdgpu_fbdev_set_suspend(adev, 1); + if (!amdgpu_device_has_dc_support(adev)) { /* turn off display hw */ drm_modeset_lock_all(dev); @@ -2767,9 +2770,6 @@ int amdgpu_device_suspend(struct drm_device *dev, bool suspend, bool fbcon) DRM_ERROR("amdgpu asic reset failed\n"); } - if (fbcon) - amdgpu_fbdev_set_suspend(adev, 1); - return 0; } -- GitLab From 85344e75d0d18094789ce84f88e1c5762c74115d Mon Sep 17 00:00:00 2001 From: Mikita Lipski <mikita.lipski@amd.com> Date: Wed, 4 Jul 2018 11:19:53 -0400 Subject: [PATCH 1300/1506] drm/amd/display: Remove unnecessary warning [why] The warning message floods the dmesg log on Tonga even though it is expected to have a pix_clk set to zero, when the pipe is not active. [how] remove the assert Signed-off-by: Mikita Lipski <mikita.lipski@amd.com> Reviewed-by: Harry Wentland <Harry.Wentland@amd.com> Acked-by: Leo Li <sunpeng.li@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c index ec3221333011b..74c05e8788073 100644 --- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c @@ -149,10 +149,6 @@ static uint32_t get_max_pixel_clock_for_all_paths( max_pix_clk = pipe_ctx->stream_res.pix_clk_params.requested_pix_clk; } - - if (max_pix_clk == 0) - ASSERT(0); - return max_pix_clk; } -- GitLab From aafded888514ba2c6b613548081dedf289a71287 Mon Sep 17 00:00:00 2001 From: Tony Cheng <tony.cheng@amd.com> Date: Wed, 11 Jul 2018 15:31:24 -0400 Subject: [PATCH 1301/1506] drm/amd/display: allow diags to skip initial link training [why] diag specify what the full config and is only concerned about pass/fail at the end having inter-op code like verifiying we can actually train at reported link rate slows down diag test and add complexity we don't need [how] add dc_debug option to skip capability link trianing also remove hbr in function name as verify is not specific to hbr Signed-off-by: Tony Cheng <tony.cheng@amd.com> Reviewed-by: Ken Chalmers <ken.chalmers@amd.com> Acked-by: Leo Li <sunpeng.li@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 2 +- drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c | 7 ++++++- drivers/gpu/drm/amd/display/dc/dc.h | 1 + drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) 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 a4429c90c60c4..388a0635c38d5 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -760,7 +760,7 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) */ /* deal with non-mst cases */ - dp_hbr_verify_link_cap(link, &link->reported_link_cap); + dp_verify_link_cap(link, &link->reported_link_cap); } /* HDMI-DVI Dongle */ 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 474cd3e017521..b8e6db4382ec0 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 @@ -1086,7 +1086,7 @@ static struct dc_link_settings get_max_link_cap(struct dc_link *link) return max_link_cap; } -bool dp_hbr_verify_link_cap( +bool dp_verify_link_cap( struct dc_link *link, struct dc_link_settings *known_limit_link_setting) { @@ -1101,6 +1101,11 @@ bool dp_hbr_verify_link_cap( enum clock_source_id dp_cs_id = CLOCK_SOURCE_ID_EXTERNAL; enum link_training_result status; + if (link->dc->debug.skip_detection_link_training) { + link->verified_link_cap = *known_limit_link_setting; + return true; + } + success = false; skip_link_training = false; diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index ceb4c37258936..5e2a2acb5ad68 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -258,6 +258,7 @@ struct dc_debug { bool avoid_vbios_exec_table; bool scl_reset_length10; bool hdmi20_disable; + bool skip_detection_link_training; struct { uint32_t ltFailCount; diff --git a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h index 2f783c6500842..697b5ee738451 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h @@ -33,7 +33,7 @@ struct dc_link; struct dc_stream_state; struct dc_link_settings; -bool dp_hbr_verify_link_cap( +bool dp_verify_link_cap( struct dc_link *link, struct dc_link_settings *known_limit_link_setting); -- GitLab From 278ca8d677cf7bcecd2b2f287838e5f344f5911e Mon Sep 17 00:00:00 2001 From: David Francis <David.Francis@amd.com> Date: Wed, 11 Jul 2018 16:20:13 -0400 Subject: [PATCH 1302/1506] drm/amd/display: On dce100, set clocks to 0 on suspend [Why] When a dce100 asic was suspended, the clocks were not set to 0. Upon resume, the new clock was compared to the existing clock, they were found to be the same, and so the clock was not set. This resulted in a pernicious blackscreen. [How] In atomic commit, check to see if there are any active pipes. If no, set clocks to 0 Signed-off-by: David Francis <David.Francis@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Leo Li <sunpeng.li@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../amd/display/dc/dce100/dce100_resource.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c index 8ed8eace42be5..ad8ad4e1437cc 100644 --- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c @@ -678,9 +678,22 @@ bool dce100_validate_bandwidth( struct dc *dc, struct dc_state *context) { - /* TODO implement when needed but for now hardcode max value*/ - context->bw.dce.dispclk_khz = 681000; - context->bw.dce.yclk_khz = 250000 * MEMORY_TYPE_MULTIPLIER; + int i; + bool at_least_one_pipe = false; + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + if (context->res_ctx.pipe_ctx[i].stream) + at_least_one_pipe = true; + } + + if (at_least_one_pipe) { + /* TODO implement when needed but for now hardcode max value*/ + context->bw.dce.dispclk_khz = 681000; + context->bw.dce.yclk_khz = 250000 * MEMORY_TYPE_MULTIPLIER; + } else { + context->bw.dce.dispclk_khz = 0; + context->bw.dce.yclk_khz = 0; + } return true; } -- GitLab From 3fc9fc4cf5a1a8219ab5d9ab10dac26db78c38f4 Mon Sep 17 00:00:00 2001 From: vikrant mhaske <vikrant.mhaske@amd.com> Date: Thu, 12 Jul 2018 16:04:43 +0800 Subject: [PATCH 1303/1506] drm/amd/display: DPP CM ICSC AYCRCB8888 format support [why] Diags has POR to run the video workload using AYCRCB8888 through DCN; capture it through DWB and send it to VCN hardware to encode [how] added the code to support this format so that DPP ICSC will be able to convert it from YUV444 to internal RGB and DWB OCSC will be able to convert from internal RGB to YUV420 Signed-off-by: vikrant mhaske <vikrant.mhaske@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Leo Li <sunpeng.li@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dc_hw_types.h | 2 +- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h index 9cfd7ea845e3f..1d1f2d5ece519 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h @@ -192,7 +192,7 @@ enum surface_pixel_format { /*swaped & float*/ SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F, /*grow graphics here if necessary */ - + SURFACE_PIXEL_FORMAT_VIDEO_AYCrCb8888, SURFACE_PIXEL_FORMAT_VIDEO_BEGIN, SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr = SURFACE_PIXEL_FORMAT_VIDEO_BEGIN, 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 332354ca6529e..2138cd3c5d1dc 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c @@ -294,6 +294,10 @@ void hubp1_program_pixel_format( REG_UPDATE(DCSURF_SURFACE_CONFIG, SURFACE_PIXEL_FORMAT, 66); break; + case SURFACE_PIXEL_FORMAT_VIDEO_AYCrCb8888: + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 12); + break; default: BREAK_TO_DEBUGGER(); break; -- GitLab From 5c6ac7112fb2b73a5e4e7ac1648cdaceb558f268 Mon Sep 17 00:00:00 2001 From: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com> Date: Tue, 10 Jul 2018 17:20:17 -0400 Subject: [PATCH 1304/1506] drm/amd/display: Decouple aux from i2c [Why] Aux engine is created from i2caux layer. We want to remove this layer and use the engine directly. [How] Decouple aux engine from i2caux. Move aux engine related code to dce folder and use dc resource pool to manage the engine. And use the engine functions directly Signed-off-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com> Reviewed-by: Harry Wentland <Harry.Wentland@amd.com> Acked-by: Leo Li <sunpeng.li@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/display/dc/core/dc_link_ddc.c | 22 +- drivers/gpu/drm/amd/display/dc/dce/Makefile | 2 +- drivers/gpu/drm/amd/display/dc/dce/dce_aux.c | 942 ++++++++++++++++++ drivers/gpu/drm/amd/display/dc/dce/dce_aux.h | 111 +++ .../amd/display/dc/dce100/dce100_resource.c | 42 + .../amd/display/dc/dce110/dce110_resource.c | 45 + .../amd/display/dc/dce112/dce112_resource.c | 47 + .../amd/display/dc/dce120/dce120_resource.c | 42 + .../drm/amd/display/dc/dce80/dce80_resource.c | 44 + .../drm/amd/display/dc/dcn10/dcn10_resource.c | 44 + .../gpu/drm/amd/display/dc/i2caux/engine.h | 1 + .../gpu/drm/amd/display/dc/inc/core_types.h | 2 +- .../drm/amd/display/dc/inc/hw/aux_engine.h | 113 +++ .../gpu/drm/amd/display/dc/inc/hw/engine.h | 106 ++ 14 files changed, 1549 insertions(+), 14 deletions(-) create mode 100644 drivers/gpu/drm/amd/display/dc/dce/dce_aux.c create mode 100644 drivers/gpu/drm/amd/display/dc/dce/dce_aux.h create mode 100644 drivers/gpu/drm/amd/display/dc/inc/hw/aux_engine.h create mode 100644 drivers/gpu/drm/amd/display/dc/inc/hw/engine.h diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c index 08c9d73b9ab72..4019fe07d291e 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c @@ -33,10 +33,8 @@ #include "include/vector.h" #include "core_types.h" #include "dc_link_ddc.h" -#include "i2caux/engine.h" -#include "i2caux/i2c_engine.h" -#include "i2caux/aux_engine.h" -#include "i2caux/i2caux.h" +#include "engine.h" +#include "aux_engine.h" #define AUX_POWER_UP_WA_DELAY 500 #define I2C_OVER_AUX_DEFER_WA_DELAY 70 @@ -641,9 +639,9 @@ int dc_link_aux_transfer(struct ddc_service *ddc, enum aux_transaction_type type, enum i2caux_transaction_action action) { - struct i2caux *i2caux = ddc->ctx->i2caux; struct ddc *ddc_pin = ddc->ddc_pin; - struct aux_engine *engine; + struct engine *engine; + struct aux_engine *aux_engine; enum aux_channel_operation_result operation_result; struct aux_request_transaction_data aux_req; struct aux_reply_transaction_data aux_rep; @@ -654,7 +652,8 @@ int dc_link_aux_transfer(struct ddc_service *ddc, memset(&aux_req, 0, sizeof(aux_req)); memset(&aux_rep, 0, sizeof(aux_rep)); - engine = i2caux->funcs->acquire_aux_engine(i2caux, ddc_pin); + engine = ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]; + aux_engine = engine->funcs->acquire(engine, ddc_pin); aux_req.type = type; aux_req.action = action; @@ -664,15 +663,15 @@ int dc_link_aux_transfer(struct ddc_service *ddc, aux_req.length = size; aux_req.data = buffer; - engine->funcs->submit_channel_request(engine, &aux_req); - operation_result = engine->funcs->get_channel_status(engine, &returned_bytes); + aux_engine->funcs->submit_channel_request(aux_engine, &aux_req); + operation_result = aux_engine->funcs->get_channel_status(aux_engine, &returned_bytes); switch (operation_result) { case AUX_CHANNEL_OPERATION_SUCCEEDED: res = returned_bytes; if (res <= size && res >= 0) - res = engine->funcs->read_channel_reply(engine, size, + res = aux_engine->funcs->read_channel_reply(aux_engine, size, buffer, reply, &status); @@ -686,8 +685,7 @@ int dc_link_aux_transfer(struct ddc_service *ddc, res = -1; break; } - - i2caux->funcs->release_engine(i2caux, &engine->base); + aux_engine->base.funcs->release_engine(&aux_engine->base); return res; } diff --git a/drivers/gpu/drm/amd/display/dc/dce/Makefile b/drivers/gpu/drm/amd/display/dc/dce/Makefile index 11401fd8e5356..825537bd45455 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dce/Makefile @@ -28,7 +28,7 @@ DCE = dce_audio.o dce_stream_encoder.o dce_link_encoder.o dce_hwseq.o \ dce_mem_input.o dce_clock_source.o dce_scl_filters.o dce_transform.o \ -dce_clocks.o dce_opp.o dce_dmcu.o dce_abm.o dce_ipp.o +dce_clocks.o dce_opp.o dce_dmcu.o dce_abm.o dce_ipp.o dce_aux.o AMD_DAL_DCE = $(addprefix $(AMDDALPATH)/dc/dce/,$(DCE)) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c new file mode 100644 index 0000000000000..b28e2120767e2 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c @@ -0,0 +1,942 @@ +/* + * Copyright 2012-15 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "dm_services.h" +#include "dce_aux.h" +#include "dce/dce_11_0_sh_mask.h" + +#define CTX \ + aux110->base.base.ctx +#define REG(reg_name)\ + (aux110->regs->reg_name) + +#define DC_LOGGER \ + engine->base.ctx->logger + +#include "reg_helper.h" + +#define FROM_AUX_ENGINE(ptr) \ + container_of((ptr), struct aux_engine_dce110, base) + +#define FROM_ENGINE(ptr) \ + FROM_AUX_ENGINE(container_of((ptr), struct aux_engine, base)) + +#define FROM_AUX_ENGINE_ENGINE(ptr) \ + container_of((ptr), struct aux_engine, base) +enum { + AUX_INVALID_REPLY_RETRY_COUNTER = 1, + AUX_TIMED_OUT_RETRY_COUNTER = 2, + AUX_DEFER_RETRY_COUNTER = 6 +}; +static void release_engine( + struct engine *engine) +{ + struct aux_engine_dce110 *aux110 = FROM_ENGINE(engine); + + dal_ddc_close(engine->ddc); + + engine->ddc = NULL; + + REG_UPDATE(AUX_ARB_CONTROL, AUX_SW_DONE_USING_AUX_REG, 1); +} + +#define SW_CAN_ACCESS_AUX 1 +#define DMCU_CAN_ACCESS_AUX 2 + +static bool is_engine_available( + struct aux_engine *engine) +{ + struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine); + + uint32_t value = REG_READ(AUX_ARB_CONTROL); + uint32_t field = get_reg_field_value( + value, + AUX_ARB_CONTROL, + AUX_REG_RW_CNTL_STATUS); + + return (field != DMCU_CAN_ACCESS_AUX); +} +static bool acquire_engine( + struct aux_engine *engine) +{ + struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine); + + uint32_t value = REG_READ(AUX_ARB_CONTROL); + uint32_t field = get_reg_field_value( + value, + AUX_ARB_CONTROL, + AUX_REG_RW_CNTL_STATUS); + if (field == DMCU_CAN_ACCESS_AUX) + return false; + /* enable AUX before request SW to access AUX */ + value = REG_READ(AUX_CONTROL); + field = get_reg_field_value(value, + AUX_CONTROL, + AUX_EN); + + if (field == 0) { + set_reg_field_value( + value, + 1, + AUX_CONTROL, + AUX_EN); + + if (REG(AUX_RESET_MASK)) { + /*DP_AUX block as part of the enable sequence*/ + set_reg_field_value( + value, + 1, + AUX_CONTROL, + AUX_RESET); + } + + REG_WRITE(AUX_CONTROL, value); + + if (REG(AUX_RESET_MASK)) { + /*poll HW to make sure reset it done*/ + + REG_WAIT(AUX_CONTROL, AUX_RESET_DONE, 1, + 1, 11); + + set_reg_field_value( + value, + 0, + AUX_CONTROL, + AUX_RESET); + + REG_WRITE(AUX_CONTROL, value); + + REG_WAIT(AUX_CONTROL, AUX_RESET_DONE, 0, + 1, 11); + } + } /*if (field)*/ + + /* request SW to access AUX */ + REG_UPDATE(AUX_ARB_CONTROL, AUX_SW_USE_AUX_REG_REQ, 1); + + value = REG_READ(AUX_ARB_CONTROL); + field = get_reg_field_value( + value, + AUX_ARB_CONTROL, + AUX_REG_RW_CNTL_STATUS); + + return (field == SW_CAN_ACCESS_AUX); +} + +#define COMPOSE_AUX_SW_DATA_16_20(command, address) \ + ((command) | ((0xF0000 & (address)) >> 16)) + +#define COMPOSE_AUX_SW_DATA_8_15(address) \ + ((0xFF00 & (address)) >> 8) + +#define COMPOSE_AUX_SW_DATA_0_7(address) \ + (0xFF & (address)) + +static void submit_channel_request( + struct aux_engine *engine, + struct aux_request_transaction_data *request) +{ + struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine); + uint32_t value; + uint32_t length; + + bool is_write = + ((request->type == AUX_TRANSACTION_TYPE_DP) && + (request->action == I2CAUX_TRANSACTION_ACTION_DP_WRITE)) || + ((request->type == AUX_TRANSACTION_TYPE_I2C) && + ((request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE) || + (request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT))); + if (REG(AUXN_IMPCAL)) { + /* clear_aux_error */ + REG_UPDATE_SEQ(AUXN_IMPCAL, AUXN_CALOUT_ERROR_AK, + 1, + 0); + + REG_UPDATE_SEQ(AUXP_IMPCAL, AUXP_CALOUT_ERROR_AK, + 1, + 0); + + /* force_default_calibrate */ + REG_UPDATE_1BY1_2(AUXN_IMPCAL, + AUXN_IMPCAL_ENABLE, 1, + AUXN_IMPCAL_OVERRIDE_ENABLE, 0); + + /* bug? why AUXN update EN and OVERRIDE_EN 1 by 1 while AUX P toggles OVERRIDE? */ + + REG_UPDATE_SEQ(AUXP_IMPCAL, AUXP_IMPCAL_OVERRIDE_ENABLE, + 1, + 0); + } + /* set the delay and the number of bytes to write */ + + /* The length include + * the 4 bit header and the 20 bit address + * (that is 3 byte). + * If the requested length is non zero this means + * an addition byte specifying the length is required. + */ + + length = request->length ? 4 : 3; + if (is_write) + length += request->length; + + REG_UPDATE_2(AUX_SW_CONTROL, + AUX_SW_START_DELAY, request->delay, + AUX_SW_WR_BYTES, length); + + /* program action and address and payload data (if 'is_write') */ + value = REG_UPDATE_4(AUX_SW_DATA, + AUX_SW_INDEX, 0, + AUX_SW_DATA_RW, 0, + AUX_SW_AUTOINCREMENT_DISABLE, 1, + AUX_SW_DATA, COMPOSE_AUX_SW_DATA_16_20(request->action, request->address)); + + value = REG_SET_2(AUX_SW_DATA, value, + AUX_SW_AUTOINCREMENT_DISABLE, 0, + AUX_SW_DATA, COMPOSE_AUX_SW_DATA_8_15(request->address)); + + value = REG_SET(AUX_SW_DATA, value, + AUX_SW_DATA, COMPOSE_AUX_SW_DATA_0_7(request->address)); + + if (request->length) { + value = REG_SET(AUX_SW_DATA, value, + AUX_SW_DATA, request->length - 1); + } + + if (is_write) { + /* Load the HW buffer with the Data to be sent. + * This is relevant for write operation. + * For read, the data recived data will be + * processed in process_channel_reply(). + */ + uint32_t i = 0; + + while (i < request->length) { + value = REG_SET(AUX_SW_DATA, value, + AUX_SW_DATA, request->data[i]); + + ++i; + } + } + + REG_UPDATE(AUX_INTERRUPT_CONTROL, AUX_SW_DONE_ACK, 1); + REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 0, + 10, aux110->timeout_period/10); + REG_UPDATE(AUX_SW_CONTROL, AUX_SW_GO, 1); +} + +static int read_channel_reply(struct aux_engine *engine, uint32_t size, + uint8_t *buffer, uint8_t *reply_result, + uint32_t *sw_status) +{ + struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine); + uint32_t bytes_replied; + uint32_t reply_result_32; + + *sw_status = REG_GET(AUX_SW_STATUS, AUX_SW_REPLY_BYTE_COUNT, + &bytes_replied); + + /* In case HPD is LOW, exit AUX transaction */ + if ((*sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) + return -1; + + /* Need at least the status byte */ + if (!bytes_replied) + return -1; + + REG_UPDATE_1BY1_3(AUX_SW_DATA, + AUX_SW_INDEX, 0, + AUX_SW_AUTOINCREMENT_DISABLE, 1, + AUX_SW_DATA_RW, 1); + + REG_GET(AUX_SW_DATA, AUX_SW_DATA, &reply_result_32); + reply_result_32 = reply_result_32 >> 4; + *reply_result = (uint8_t)reply_result_32; + + if (reply_result_32 == 0) { /* ACK */ + uint32_t i = 0; + + /* First byte was already used to get the command status */ + --bytes_replied; + + /* Do not overflow buffer */ + if (bytes_replied > size) + return -1; + + while (i < bytes_replied) { + uint32_t aux_sw_data_val; + + REG_GET(AUX_SW_DATA, AUX_SW_DATA, &aux_sw_data_val); + buffer[i] = aux_sw_data_val; + ++i; + } + + return i; + } + + return 0; +} + +static void process_channel_reply( + struct aux_engine *engine, + struct aux_reply_transaction_data *reply) +{ + int bytes_replied; + uint8_t reply_result; + uint32_t sw_status; + + bytes_replied = read_channel_reply(engine, reply->length, reply->data, + &reply_result, &sw_status); + + /* in case HPD is LOW, exit AUX transaction */ + if ((sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) { + reply->status = AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON; + return; + } + + if (bytes_replied < 0) { + /* Need to handle an error case... + * Hopefully, upper layer function won't call this function if + * the number of bytes in the reply was 0, because there was + * surely an error that was asserted that should have been + * handled for hot plug case, this could happens + */ + if (!(sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) { + reply->status = AUX_TRANSACTION_REPLY_INVALID; + ASSERT_CRITICAL(false); + return; + } + } else { + + switch (reply_result) { + case 0: /* ACK */ + reply->status = AUX_TRANSACTION_REPLY_AUX_ACK; + break; + case 1: /* NACK */ + reply->status = AUX_TRANSACTION_REPLY_AUX_NACK; + break; + case 2: /* DEFER */ + reply->status = AUX_TRANSACTION_REPLY_AUX_DEFER; + break; + case 4: /* AUX ACK / I2C NACK */ + reply->status = AUX_TRANSACTION_REPLY_I2C_NACK; + break; + case 8: /* AUX ACK / I2C DEFER */ + reply->status = AUX_TRANSACTION_REPLY_I2C_DEFER; + break; + default: + reply->status = AUX_TRANSACTION_REPLY_INVALID; + } + } +} + +static enum aux_channel_operation_result get_channel_status( + struct aux_engine *engine, + uint8_t *returned_bytes) +{ + struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine); + + uint32_t value; + + if (returned_bytes == NULL) { + /*caller pass NULL pointer*/ + ASSERT_CRITICAL(false); + return AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN; + } + *returned_bytes = 0; + + /* poll to make sure that SW_DONE is asserted */ + value = REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 1, + 10, aux110->timeout_period/10); + + /* in case HPD is LOW, exit AUX transaction */ + if ((value & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) + return AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON; + + /* Note that the following bits are set in 'status.bits' + * during CTS 4.2.1.2 (FW 3.3.1): + * AUX_SW_RX_MIN_COUNT_VIOL, AUX_SW_RX_INVALID_STOP, + * AUX_SW_RX_RECV_NO_DET, AUX_SW_RX_RECV_INVALID_H. + * + * AUX_SW_RX_MIN_COUNT_VIOL is an internal, + * HW debugging bit and should be ignored. + */ + if (value & AUX_SW_STATUS__AUX_SW_DONE_MASK) { + if ((value & AUX_SW_STATUS__AUX_SW_RX_TIMEOUT_STATE_MASK) || + (value & AUX_SW_STATUS__AUX_SW_RX_TIMEOUT_MASK)) + return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT; + + else if ((value & AUX_SW_STATUS__AUX_SW_RX_INVALID_STOP_MASK) || + (value & AUX_SW_STATUS__AUX_SW_RX_RECV_NO_DET_MASK) || + (value & + AUX_SW_STATUS__AUX_SW_RX_RECV_INVALID_H_MASK) || + (value & AUX_SW_STATUS__AUX_SW_RX_RECV_INVALID_L_MASK)) + return AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY; + + *returned_bytes = get_reg_field_value(value, + AUX_SW_STATUS, + AUX_SW_REPLY_BYTE_COUNT); + + if (*returned_bytes == 0) + return + AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY; + else { + *returned_bytes -= 1; + return AUX_CHANNEL_OPERATION_SUCCEEDED; + } + } else { + /*time_elapsed >= aux_engine->timeout_period + * AUX_SW_STATUS__AUX_SW_HPD_DISCON = at this point + */ + ASSERT_CRITICAL(false); + return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT; + } +} +static void process_read_reply( + struct aux_engine *engine, + struct read_command_context *ctx) +{ + engine->funcs->process_channel_reply(engine, &ctx->reply); + + switch (ctx->reply.status) { + case AUX_TRANSACTION_REPLY_AUX_ACK: + ctx->defer_retry_aux = 0; + if (ctx->returned_byte > ctx->current_read_length) { + ctx->status = + I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR; + ctx->operation_succeeded = false; + } else if (ctx->returned_byte < ctx->current_read_length) { + ctx->current_read_length -= ctx->returned_byte; + + ctx->offset += ctx->returned_byte; + + ++ctx->invalid_reply_retry_aux_on_ack; + + if (ctx->invalid_reply_retry_aux_on_ack > + AUX_INVALID_REPLY_RETRY_COUNTER) { + ctx->status = + I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR; + ctx->operation_succeeded = false; + } + } else { + ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED; + ctx->transaction_complete = true; + ctx->operation_succeeded = true; + } + break; + case AUX_TRANSACTION_REPLY_AUX_NACK: + ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_NACK; + ctx->operation_succeeded = false; + break; + case AUX_TRANSACTION_REPLY_AUX_DEFER: + ++ctx->defer_retry_aux; + + if (ctx->defer_retry_aux > AUX_DEFER_RETRY_COUNTER) { + ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT; + ctx->operation_succeeded = false; + } + break; + case AUX_TRANSACTION_REPLY_I2C_DEFER: + ctx->defer_retry_aux = 0; + + ++ctx->defer_retry_i2c; + + if (ctx->defer_retry_i2c > AUX_DEFER_RETRY_COUNTER) { + ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT; + ctx->operation_succeeded = false; + } + break; + case AUX_TRANSACTION_REPLY_HPD_DISCON: + ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON; + ctx->operation_succeeded = false; + break; + default: + ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN; + ctx->operation_succeeded = false; + } +} +static void process_read_request( + struct aux_engine *engine, + struct read_command_context *ctx) +{ + enum aux_channel_operation_result operation_result; + + engine->funcs->submit_channel_request(engine, &ctx->request); + + operation_result = engine->funcs->get_channel_status( + engine, &ctx->returned_byte); + + switch (operation_result) { + case AUX_CHANNEL_OPERATION_SUCCEEDED: + if (ctx->returned_byte > ctx->current_read_length) { + ctx->status = + I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR; + ctx->operation_succeeded = false; + } else { + ctx->timed_out_retry_aux = 0; + ctx->invalid_reply_retry_aux = 0; + + ctx->reply.length = ctx->returned_byte; + ctx->reply.data = ctx->buffer; + + process_read_reply(engine, ctx); + } + break; + case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY: + ++ctx->invalid_reply_retry_aux; + + if (ctx->invalid_reply_retry_aux > + AUX_INVALID_REPLY_RETRY_COUNTER) { + ctx->status = + I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR; + ctx->operation_succeeded = false; + } else + udelay(400); + break; + case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT: + ++ctx->timed_out_retry_aux; + + if (ctx->timed_out_retry_aux > AUX_TIMED_OUT_RETRY_COUNTER) { + ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT; + ctx->operation_succeeded = false; + } else { + /* DP 1.2a, table 2-58: + * "S3: AUX Request CMD PENDING: + * retry 3 times, with 400usec wait on each" + * The HW timeout is set to 550usec, + * so we should not wait here + */ + } + break; + case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON: + ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON; + ctx->operation_succeeded = false; + break; + default: + ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN; + ctx->operation_succeeded = false; + } +} +static bool read_command( + struct aux_engine *engine, + struct i2caux_transaction_request *request, + bool middle_of_transaction) +{ + struct read_command_context ctx; + + ctx.buffer = request->payload.data; + ctx.current_read_length = request->payload.length; + ctx.offset = 0; + ctx.timed_out_retry_aux = 0; + ctx.invalid_reply_retry_aux = 0; + ctx.defer_retry_aux = 0; + ctx.defer_retry_i2c = 0; + ctx.invalid_reply_retry_aux_on_ack = 0; + ctx.transaction_complete = false; + ctx.operation_succeeded = true; + + if (request->payload.address_space == + I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) { + ctx.request.type = AUX_TRANSACTION_TYPE_DP; + ctx.request.action = I2CAUX_TRANSACTION_ACTION_DP_READ; + ctx.request.address = request->payload.address; + } else if (request->payload.address_space == + I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C) { + ctx.request.type = AUX_TRANSACTION_TYPE_I2C; + ctx.request.action = middle_of_transaction ? + I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT : + I2CAUX_TRANSACTION_ACTION_I2C_READ; + ctx.request.address = request->payload.address >> 1; + } else { + /* in DAL2, there was no return in such case */ + BREAK_TO_DEBUGGER(); + return false; + } + + ctx.request.delay = 0; + + do { + memset(ctx.buffer + ctx.offset, 0, ctx.current_read_length); + + ctx.request.data = ctx.buffer + ctx.offset; + ctx.request.length = ctx.current_read_length; + + process_read_request(engine, &ctx); + + request->status = ctx.status; + + if (ctx.operation_succeeded && !ctx.transaction_complete) + if (ctx.request.type == AUX_TRANSACTION_TYPE_I2C) + msleep(engine->delay); + } while (ctx.operation_succeeded && !ctx.transaction_complete); + + if (request->payload.address_space == + I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) { + DC_LOG_I2C_AUX("READ: addr:0x%x value:0x%x Result:%d", + request->payload.address, + request->payload.data[0], + ctx.operation_succeeded); + } + + return ctx.operation_succeeded; +} + +static void process_write_reply( + struct aux_engine *engine, + struct write_command_context *ctx) +{ + engine->funcs->process_channel_reply(engine, &ctx->reply); + + switch (ctx->reply.status) { + case AUX_TRANSACTION_REPLY_AUX_ACK: + ctx->operation_succeeded = true; + + if (ctx->returned_byte) { + ctx->request.action = ctx->mot ? + I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT : + I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST; + + ctx->current_write_length = 0; + + ++ctx->ack_m_retry; + + if (ctx->ack_m_retry > AUX_DEFER_RETRY_COUNTER) { + ctx->status = + I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT; + ctx->operation_succeeded = false; + } else + udelay(300); + } else { + ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED; + ctx->defer_retry_aux = 0; + ctx->ack_m_retry = 0; + ctx->transaction_complete = true; + } + break; + case AUX_TRANSACTION_REPLY_AUX_NACK: + ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_NACK; + ctx->operation_succeeded = false; + break; + case AUX_TRANSACTION_REPLY_AUX_DEFER: + ++ctx->defer_retry_aux; + + if (ctx->defer_retry_aux > ctx->max_defer_retry) { + ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT; + ctx->operation_succeeded = false; + } + break; + case AUX_TRANSACTION_REPLY_I2C_DEFER: + ctx->defer_retry_aux = 0; + ctx->current_write_length = 0; + + ctx->request.action = ctx->mot ? + I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT : + I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST; + + ++ctx->defer_retry_i2c; + + if (ctx->defer_retry_i2c > ctx->max_defer_retry) { + ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT; + ctx->operation_succeeded = false; + } + break; + case AUX_TRANSACTION_REPLY_HPD_DISCON: + ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON; + ctx->operation_succeeded = false; + break; + default: + ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN; + ctx->operation_succeeded = false; + } +} +static void process_write_request( + struct aux_engine *engine, + struct write_command_context *ctx) +{ + enum aux_channel_operation_result operation_result; + + engine->funcs->submit_channel_request(engine, &ctx->request); + + operation_result = engine->funcs->get_channel_status( + engine, &ctx->returned_byte); + + switch (operation_result) { + case AUX_CHANNEL_OPERATION_SUCCEEDED: + ctx->timed_out_retry_aux = 0; + ctx->invalid_reply_retry_aux = 0; + + ctx->reply.length = ctx->returned_byte; + ctx->reply.data = ctx->reply_data; + + process_write_reply(engine, ctx); + break; + case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY: + ++ctx->invalid_reply_retry_aux; + + if (ctx->invalid_reply_retry_aux > + AUX_INVALID_REPLY_RETRY_COUNTER) { + ctx->status = + I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR; + ctx->operation_succeeded = false; + } else + udelay(400); + break; + case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT: + ++ctx->timed_out_retry_aux; + + if (ctx->timed_out_retry_aux > AUX_TIMED_OUT_RETRY_COUNTER) { + ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT; + ctx->operation_succeeded = false; + } else { + /* DP 1.2a, table 2-58: + * "S3: AUX Request CMD PENDING: + * retry 3 times, with 400usec wait on each" + * The HW timeout is set to 550usec, + * so we should not wait here + */ + } + break; + case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON: + ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON; + ctx->operation_succeeded = false; + break; + default: + ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN; + ctx->operation_succeeded = false; + } +} +static bool write_command( + struct aux_engine *engine, + struct i2caux_transaction_request *request, + bool middle_of_transaction) +{ + struct write_command_context ctx; + + ctx.mot = middle_of_transaction; + ctx.buffer = request->payload.data; + ctx.current_write_length = request->payload.length; + ctx.timed_out_retry_aux = 0; + ctx.invalid_reply_retry_aux = 0; + ctx.defer_retry_aux = 0; + ctx.defer_retry_i2c = 0; + ctx.ack_m_retry = 0; + ctx.transaction_complete = false; + ctx.operation_succeeded = true; + + if (request->payload.address_space == + I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) { + ctx.request.type = AUX_TRANSACTION_TYPE_DP; + ctx.request.action = I2CAUX_TRANSACTION_ACTION_DP_WRITE; + ctx.request.address = request->payload.address; + } else if (request->payload.address_space == + I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C) { + ctx.request.type = AUX_TRANSACTION_TYPE_I2C; + ctx.request.action = middle_of_transaction ? + I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT : + I2CAUX_TRANSACTION_ACTION_I2C_WRITE; + ctx.request.address = request->payload.address >> 1; + } else { + /* in DAL2, there was no return in such case */ + BREAK_TO_DEBUGGER(); + return false; + } + + ctx.request.delay = 0; + + ctx.max_defer_retry = + (engine->max_defer_write_retry > AUX_DEFER_RETRY_COUNTER) ? + engine->max_defer_write_retry : AUX_DEFER_RETRY_COUNTER; + + do { + ctx.request.data = ctx.buffer; + ctx.request.length = ctx.current_write_length; + + process_write_request(engine, &ctx); + + request->status = ctx.status; + + if (ctx.operation_succeeded && !ctx.transaction_complete) + if (ctx.request.type == AUX_TRANSACTION_TYPE_I2C) + msleep(engine->delay); + } while (ctx.operation_succeeded && !ctx.transaction_complete); + + if (request->payload.address_space == + I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) { + DC_LOG_I2C_AUX("WRITE: addr:0x%x value:0x%x Result:%d", + request->payload.address, + request->payload.data[0], + ctx.operation_succeeded); + } + + return ctx.operation_succeeded; +} +static bool end_of_transaction_command( + struct aux_engine *engine, + struct i2caux_transaction_request *request) +{ + struct i2caux_transaction_request dummy_request; + uint8_t dummy_data; + + /* [tcheng] We only need to send the stop (read with MOT = 0) + * for I2C-over-Aux, not native AUX + */ + + if (request->payload.address_space != + I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C) + return false; + + dummy_request.operation = request->operation; + dummy_request.payload.address_space = request->payload.address_space; + dummy_request.payload.address = request->payload.address; + + /* + * Add a dummy byte due to some receiver quirk + * where one byte is sent along with MOT = 0. + * Ideally this should be 0. + */ + + dummy_request.payload.length = 0; + dummy_request.payload.data = &dummy_data; + + if (request->operation == I2CAUX_TRANSACTION_READ) + return read_command(engine, &dummy_request, false); + else + return write_command(engine, &dummy_request, false); + + /* according Syed, it does not need now DoDummyMOT */ +} +bool submit_request( + struct engine *engine, + struct i2caux_transaction_request *request, + bool middle_of_transaction) +{ + struct aux_engine *aux_engine = FROM_AUX_ENGINE_ENGINE(engine); + + bool result; + bool mot_used = true; + + switch (request->operation) { + case I2CAUX_TRANSACTION_READ: + result = read_command(aux_engine, request, mot_used); + break; + case I2CAUX_TRANSACTION_WRITE: + result = write_command(aux_engine, request, mot_used); + break; + default: + result = false; + } + + /* [tcheng] + * need to send stop for the last transaction to free up the AUX + * if the above command fails, this would be the last transaction + */ + + if (!middle_of_transaction || !result) + end_of_transaction_command(aux_engine, request); + + /* mask AUX interrupt */ + + return result; +} +enum i2caux_engine_type get_engine_type( + const struct engine *engine) +{ + return I2CAUX_ENGINE_TYPE_AUX; +} + +static struct aux_engine *acquire( + struct engine *engine, + struct ddc *ddc) +{ + struct aux_engine *aux_engine = FROM_AUX_ENGINE_ENGINE(engine); + enum gpio_result result; + + if (aux_engine->funcs->is_engine_available) { + /*check whether SW could use the engine*/ + if (!aux_engine->funcs->is_engine_available(aux_engine)) + return NULL; + } + + result = dal_ddc_open(ddc, GPIO_MODE_HARDWARE, + GPIO_DDC_CONFIG_TYPE_MODE_AUX); + + if (result != GPIO_RESULT_OK) + return NULL; + + if (!aux_engine->funcs->acquire_engine(aux_engine)) { + dal_ddc_close(ddc); + return NULL; + } + + engine->ddc = ddc; + + return aux_engine; +} + +static const struct aux_engine_funcs aux_engine_funcs = { + .acquire_engine = acquire_engine, + .submit_channel_request = submit_channel_request, + .process_channel_reply = process_channel_reply, + .read_channel_reply = read_channel_reply, + .get_channel_status = get_channel_status, + .is_engine_available = is_engine_available, +}; + +static const struct engine_funcs engine_funcs = { + .release_engine = release_engine, + .destroy_engine = dce110_engine_destroy, + .submit_request = submit_request, + .get_engine_type = get_engine_type, + .acquire = acquire, +}; + +void dce110_engine_destroy(struct engine **engine) +{ + + struct aux_engine_dce110 *engine110 = FROM_ENGINE(*engine); + + kfree(engine110); + *engine = NULL; + +} +struct aux_engine *dce110_aux_engine_construct(struct aux_engine_dce110 *aux_engine110, + struct dc_context *ctx, + uint32_t inst, + uint32_t timeout_period, + const struct dce110_aux_registers *regs) +{ + aux_engine110->base.base.ddc = NULL; + aux_engine110->base.base.ctx = ctx; + aux_engine110->base.delay = 0; + aux_engine110->base.max_defer_write_retry = 0; + aux_engine110->base.base.funcs = &engine_funcs; + aux_engine110->base.funcs = &aux_engine_funcs; + aux_engine110->base.base.inst = inst; + aux_engine110->timeout_period = timeout_period; + aux_engine110->regs = regs; + + return &aux_engine110->base; +} + diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h new file mode 100644 index 0000000000000..c6b2aec2e367e --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h @@ -0,0 +1,111 @@ +/* + * Copyright 2012-15 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DAL_AUX_ENGINE_DCE110_H__ +#define __DAL_AUX_ENGINE_DCE110_H__ +#include "aux_engine.h" + +#define AUX_COMMON_REG_LIST(id)\ + SRI(AUX_CONTROL, DP_AUX, id), \ + SRI(AUX_ARB_CONTROL, DP_AUX, id), \ + SRI(AUX_SW_DATA, DP_AUX, id), \ + SRI(AUX_SW_CONTROL, DP_AUX, id), \ + SRI(AUX_INTERRUPT_CONTROL, DP_AUX, id), \ + SRI(AUX_SW_STATUS, DP_AUX, id), \ + SR(AUXN_IMPCAL), \ + SR(AUXP_IMPCAL) + +struct dce110_aux_registers { + uint32_t AUX_CONTROL; + uint32_t AUX_ARB_CONTROL; + uint32_t AUX_SW_DATA; + uint32_t AUX_SW_CONTROL; + uint32_t AUX_INTERRUPT_CONTROL; + uint32_t AUX_SW_STATUS; + uint32_t AUXN_IMPCAL; + uint32_t AUXP_IMPCAL; + + uint32_t AUX_RESET_MASK; +}; + +enum { /* This is the timeout as defined in DP 1.2a, + * 2.3.4 "Detailed uPacket TX AUX CH State Description". + */ + AUX_TIMEOUT_PERIOD = 400, + + /* Ideally, the SW timeout should be just above 550usec + * which is programmed in HW. + * But the SW timeout of 600usec is not reliable, + * because on some systems, delay_in_microseconds() + * returns faster than it should. + * EPR #379763: by trial-and-error on different systems, + * 700usec is the minimum reliable SW timeout for polling + * the AUX_SW_STATUS.AUX_SW_DONE bit. + * This timeout expires *only* when there is + * AUX Error or AUX Timeout conditions - not during normal operation. + * During normal operation, AUX_SW_STATUS.AUX_SW_DONE bit is set + * at most within ~240usec. That means, + * increasing this timeout will not affect normal operation, + * and we'll timeout after + * SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD = 1600usec. + * This timeout is especially important for + * resume from S3 and CTS. + */ + SW_AUX_TIMEOUT_PERIOD_MULTIPLIER = 4 +}; +struct aux_engine_dce110 { + struct aux_engine base; + const struct dce110_aux_registers *regs; + struct { + uint32_t aux_control; + uint32_t aux_arb_control; + uint32_t aux_sw_data; + uint32_t aux_sw_control; + uint32_t aux_interrupt_control; + uint32_t aux_sw_status; + } addr; + uint32_t timeout_period; +}; + +struct aux_engine_dce110_init_data { + uint32_t engine_id; + uint32_t timeout_period; + struct dc_context *ctx; + const struct dce110_aux_registers *regs; +}; + +struct aux_engine *dce110_aux_engine_construct( + struct aux_engine_dce110 *aux_engine110, + struct dc_context *ctx, + uint32_t inst, + uint32_t timeout_period, + const struct dce110_aux_registers *regs); + +void dce110_engine_destroy(struct engine **engine); + +bool dce110_aux_engine_acquire( + struct engine *aux_engine, + struct ddc *ddc); +#endif diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c index ad8ad4e1437cc..c34c9531915ef 100644 --- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c @@ -52,6 +52,7 @@ #include "dce/dce_10_0_sh_mask.h" #include "dce/dce_dmcu.h" +#include "dce/dce_aux.h" #include "dce/dce_abm.h" #ifndef mmMC_HUB_RDREQ_DMIF_LIMIT @@ -279,7 +280,20 @@ static const struct dce_opp_shift opp_shift = { static const struct dce_opp_mask opp_mask = { OPP_COMMON_MASK_SH_LIST_DCE_100(_MASK) }; +#define aux_engine_regs(id)\ +[id] = {\ + AUX_COMMON_REG_LIST(id), \ + .AUX_RESET_MASK = 0 \ +} +static const struct dce110_aux_registers aux_engine_regs[] = { + aux_engine_regs(0), + aux_engine_regs(1), + aux_engine_regs(2), + aux_engine_regs(3), + aux_engine_regs(4), + aux_engine_regs(5) +}; #define audio_regs(id)\ [id] = {\ @@ -572,6 +586,23 @@ struct output_pixel_processor *dce100_opp_create( return &opp->base; } +struct engine *dce100_aux_engine_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct aux_engine_dce110 *aux_engine = + kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); + + if (!aux_engine) + return NULL; + + dce110_aux_engine_construct(aux_engine, ctx, inst, + SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, + &aux_engine_regs[inst]); + + return &aux_engine->base.base; +} + struct clock_source *dce100_clock_source_create( struct dc_context *ctx, struct dc_bios *bios, @@ -624,6 +655,10 @@ static void destruct(struct dce110_resource_pool *pool) kfree(DCE110TG_FROM_TG(pool->base.timing_generators[i])); pool->base.timing_generators[i] = NULL; } + + if (pool->base.engines[i] != NULL) + dce110_engine_destroy(&pool->base.engines[i]); + } for (i = 0; i < pool->base.stream_enc_count; i++) { @@ -928,6 +963,13 @@ static bool construct( "DC: failed to create output pixel processor!\n"); goto res_create_fail; } + pool->base.engines[i] = dce100_aux_engine_create(ctx, i); + if (pool->base.engines[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create aux engine!!\n"); + goto res_create_fail; + } } dc->caps.max_planes = pool->base.pipe_count; diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c index 1c902e49a7124..4a665a29191bc 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c @@ -49,6 +49,7 @@ #include "dce/dce_clock_source.h" #include "dce/dce_hwseq.h" #include "dce110/dce110_hw_sequencer.h" +#include "dce/dce_aux.h" #include "dce/dce_abm.h" #include "dce/dce_dmcu.h" @@ -306,6 +307,21 @@ static const struct dce_opp_mask opp_mask = { OPP_COMMON_MASK_SH_LIST_DCE_110(_MASK) }; +#define aux_engine_regs(id)\ +[id] = {\ + AUX_COMMON_REG_LIST(id), \ + .AUX_RESET_MASK = 0 \ +} + +static const struct dce110_aux_registers aux_engine_regs[] = { + aux_engine_regs(0), + aux_engine_regs(1), + aux_engine_regs(2), + aux_engine_regs(3), + aux_engine_regs(4), + aux_engine_regs(5) +}; + #define audio_regs(id)\ [id] = {\ AUD_COMMON_REG_LIST(id)\ @@ -588,6 +604,23 @@ static struct output_pixel_processor *dce110_opp_create( return &opp->base; } +struct engine *dce110_aux_engine_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct aux_engine_dce110 *aux_engine = + kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); + + if (!aux_engine) + return NULL; + + dce110_aux_engine_construct(aux_engine, ctx, inst, + SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, + &aux_engine_regs[inst]); + + return &aux_engine->base.base; +} + struct clock_source *dce110_clock_source_create( struct dc_context *ctx, struct dc_bios *bios, @@ -651,6 +684,10 @@ static void destruct(struct dce110_resource_pool *pool) kfree(DCE110TG_FROM_TG(pool->base.timing_generators[i])); pool->base.timing_generators[i] = NULL; } + + if (pool->base.engines[i] != NULL) + dce110_engine_destroy(&pool->base.engines[i]); + } for (i = 0; i < pool->base.stream_enc_count; i++) { @@ -1258,6 +1295,14 @@ static bool construct( "DC: failed to create output pixel processor!\n"); goto res_create_fail; } + + pool->base.engines[i] = dce110_aux_engine_create(ctx, i); + if (pool->base.engines[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create aux engine!!\n"); + goto res_create_fail; + } } dc->fbc_compressor = dce110_compressor_create(ctx); diff --git a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c index 30d5b32892d69..caf90ae2cbb04 100644 --- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c @@ -49,6 +49,7 @@ #include "dce112/dce112_hw_sequencer.h" #include "dce/dce_abm.h" #include "dce/dce_dmcu.h" +#include "dce/dce_aux.h" #include "reg_helper.h" @@ -314,6 +315,21 @@ static const struct dce_opp_mask opp_mask = { OPP_COMMON_MASK_SH_LIST_DCE_112(_MASK) }; +#define aux_engine_regs(id)\ +[id] = {\ + AUX_COMMON_REG_LIST(id), \ + .AUX_RESET_MASK = 0 \ +} + +static const struct dce110_aux_registers aux_engine_regs[] = { + aux_engine_regs(0), + aux_engine_regs(1), + aux_engine_regs(2), + aux_engine_regs(3), + aux_engine_regs(4), + aux_engine_regs(5) +}; + #define audio_regs(id)\ [id] = {\ AUD_COMMON_REG_LIST(id)\ @@ -588,6 +604,23 @@ struct output_pixel_processor *dce112_opp_create( return &opp->base; } +struct engine *dce112_aux_engine_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct aux_engine_dce110 *aux_engine = + kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); + + if (!aux_engine) + return NULL; + + dce110_aux_engine_construct(aux_engine, ctx, inst, + SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, + &aux_engine_regs[inst]); + + return &aux_engine->base.base; +} + struct clock_source *dce112_clock_source_create( struct dc_context *ctx, struct dc_bios *bios, @@ -625,6 +658,9 @@ static void destruct(struct dce110_resource_pool *pool) if (pool->base.opps[i] != NULL) dce110_opp_destroy(&pool->base.opps[i]); + if (pool->base.engines[i] != NULL) + dce110_engine_destroy(&pool->base.engines[i]); + if (pool->base.transforms[i] != NULL) dce112_transform_destroy(&pool->base.transforms[i]); @@ -640,6 +676,10 @@ static void destruct(struct dce110_resource_pool *pool) kfree(DCE110TG_FROM_TG(pool->base.timing_generators[i])); pool->base.timing_generators[i] = NULL; } + + if (pool->base.engines[i] != NULL) + dce110_engine_destroy(&pool->base.engines[i]); + } for (i = 0; i < pool->base.stream_enc_count; i++) { @@ -1208,6 +1248,13 @@ static bool construct( "DC:failed to create output pixel processor!\n"); goto res_create_fail; } + pool->base.engines[i] = dce112_aux_engine_create(ctx, i); + if (pool->base.engines[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create aux engine!!\n"); + goto res_create_fail; + } } if (!resource_construct(num_virtual_links, dc, &pool->base, diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c index 8381f27a23612..e389832c96ccb 100644 --- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c @@ -53,6 +53,7 @@ #include "dce/dce_hwseq.h" #include "dce/dce_abm.h" #include "dce/dce_dmcu.h" +#include "dce/dce_aux.h" #include "dce/dce_12_0_offset.h" #include "dce/dce_12_0_sh_mask.h" @@ -297,6 +298,20 @@ static const struct dce_opp_shift opp_shift = { static const struct dce_opp_mask opp_mask = { OPP_COMMON_MASK_SH_LIST_DCE_120(_MASK) }; + #define aux_engine_regs(id)\ +[id] = {\ + AUX_COMMON_REG_LIST(id), \ + .AUX_RESET_MASK = 0 \ +} + +static const struct dce110_aux_registers aux_engine_regs[] = { + aux_engine_regs(0), + aux_engine_regs(1), + aux_engine_regs(2), + aux_engine_regs(3), + aux_engine_regs(4), + aux_engine_regs(5) +}; #define audio_regs(id)\ [id] = {\ @@ -361,6 +376,22 @@ struct output_pixel_processor *dce120_opp_create( ctx, inst, &opp_regs[inst], &opp_shift, &opp_mask); return &opp->base; } +struct engine *dce120_aux_engine_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct aux_engine_dce110 *aux_engine = + kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); + + if (!aux_engine) + return NULL; + + dce110_aux_engine_construct(aux_engine, ctx, inst, + SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, + &aux_engine_regs[inst]); + + return &aux_engine->base.base; +} static const struct bios_registers bios_regs = { .BIOS_SCRATCH_6 = mmBIOS_SCRATCH_6 + NBIO_BASE(mmBIOS_SCRATCH_6_BASE_IDX) @@ -467,6 +498,10 @@ static void destruct(struct dce110_resource_pool *pool) kfree(DCE110TG_FROM_TG(pool->base.timing_generators[i])); pool->base.timing_generators[i] = NULL; } + + if (pool->base.engines[i] != NULL) + dce110_engine_destroy(&pool->base.engines[i]); + } for (i = 0; i < pool->base.audio_count; i++) { @@ -984,6 +1019,13 @@ static bool construct( dm_error( "DC: failed to create output pixel processor!\n"); } + pool->base.engines[i] = dce120_aux_engine_create(ctx, i); + if (pool->base.engines[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create aux engine!!\n"); + goto res_create_fail; + } /* check next valid pipe */ j++; diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c index 2ac95ec2bf963..6fb33ad2d3c80 100644 --- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c @@ -54,6 +54,7 @@ #include "reg_helper.h" #include "dce/dce_dmcu.h" +#include "dce/dce_aux.h" #include "dce/dce_abm.h" /* TODO remove this include */ @@ -298,6 +299,21 @@ static const struct dce_opp_mask opp_mask = { OPP_COMMON_MASK_SH_LIST_DCE_80(_MASK) }; +#define aux_engine_regs(id)\ +[id] = {\ + AUX_COMMON_REG_LIST(id), \ + .AUX_RESET_MASK = 0 \ +} + +static const struct dce110_aux_registers aux_engine_regs[] = { + aux_engine_regs(0), + aux_engine_regs(1), + aux_engine_regs(2), + aux_engine_regs(3), + aux_engine_regs(4), + aux_engine_regs(5) +}; + #define audio_regs(id)\ [id] = {\ AUD_COMMON_REG_LIST(id)\ @@ -448,6 +464,23 @@ static struct output_pixel_processor *dce80_opp_create( return &opp->base; } +struct engine *dce80_aux_engine_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct aux_engine_dce110 *aux_engine = + kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); + + if (!aux_engine) + return NULL; + + dce110_aux_engine_construct(aux_engine, ctx, inst, + SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, + &aux_engine_regs[inst]); + + return &aux_engine->base.base; +} + static struct stream_encoder *dce80_stream_encoder_create( enum engine_id eng_id, struct dc_context *ctx) @@ -655,6 +688,9 @@ static void destruct(struct dce110_resource_pool *pool) kfree(DCE110TG_FROM_TG(pool->base.timing_generators[i])); pool->base.timing_generators[i] = NULL; } + + if (pool->base.engines[i] != NULL) + dce110_engine_destroy(&pool->base.engines[i]); } for (i = 0; i < pool->base.stream_enc_count; i++) { @@ -899,6 +935,14 @@ static bool dce80_construct( dm_error("DC: failed to create output pixel processor!\n"); goto res_create_fail; } + + pool->base.engines[i] = dce80_aux_engine_create(ctx, i); + if (pool->base.engines[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create aux engine!!\n"); + goto res_create_fail; + } } dc->caps.max_planes = pool->base.pipe_count; diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c index 84581b3c392ba..ef8bb27356205 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c @@ -64,6 +64,7 @@ #include "reg_helper.h" #include "dce/dce_abm.h" #include "dce/dce_dmcu.h" +#include "dce/dce_aux.h" const struct _vcs_dpi_ip_params_st dcn1_0_ip = { .rob_buffer_size_kbytes = 64, @@ -356,6 +357,21 @@ static const struct dcn10_opp_mask opp_mask = { OPP_MASK_SH_LIST_DCN10(_MASK), }; +#define aux_engine_regs(id)\ +[id] = {\ + AUX_COMMON_REG_LIST(id), \ + .AUX_RESET_MASK = 0 \ +} + +static const struct dce110_aux_registers aux_engine_regs[] = { + aux_engine_regs(0), + aux_engine_regs(1), + aux_engine_regs(2), + aux_engine_regs(3), + aux_engine_regs(4), + aux_engine_regs(5) +}; + #define tf_regs(id)\ [id] = {\ TF_REG_LIST_DCN10(id),\ @@ -578,6 +594,23 @@ static struct output_pixel_processor *dcn10_opp_create( return &opp->base; } +struct engine *dcn10_aux_engine_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct aux_engine_dce110 *aux_engine = + kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); + + if (!aux_engine) + return NULL; + + dce110_aux_engine_construct(aux_engine, ctx, inst, + SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, + &aux_engine_regs[inst]); + + return &aux_engine->base.base; +} + static struct mpc *dcn10_mpc_create(struct dc_context *ctx) { struct dcn10_mpc *mpc10 = kzalloc(sizeof(struct dcn10_mpc), @@ -826,6 +859,9 @@ static void destruct(struct dcn10_resource_pool *pool) kfree(DCN10TG_FROM_TG(pool->base.timing_generators[i])); pool->base.timing_generators[i] = NULL; } + + if (pool->base.engines[i] != NULL) + pool->base.engines[i]->funcs->destroy_engine(&pool->base.engines[i]); } for (i = 0; i < pool->base.stream_enc_count; i++) @@ -1255,6 +1291,14 @@ static bool construct( goto fail; } + pool->base.engines[i] = dcn10_aux_engine_create(ctx, i); + if (pool->base.engines[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create aux engine!!\n"); + goto fail; + } + /* check next valid pipe */ j++; } diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/engine.h b/drivers/gpu/drm/amd/display/dc/i2caux/engine.h index 1e8a1585e4012..b16fb1ff687da 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/engine.h +++ b/drivers/gpu/drm/amd/display/dc/i2caux/engine.h @@ -96,6 +96,7 @@ struct engine_funcs { struct engine { const struct engine_funcs *funcs; + uint32_t inst; struct ddc *ddc; struct dc_context *ctx; }; diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h index 4446652a9a9e4..0fa385872ed33 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h @@ -138,7 +138,7 @@ struct resource_pool { struct output_pixel_processor *opps[MAX_PIPES]; struct timing_generator *timing_generators[MAX_PIPES]; struct stream_encoder *stream_enc[MAX_PIPES * 2]; - + struct engine *engines[MAX_PIPES]; struct hubbub *hubbub; struct mpc *mpc; struct pp_smu_funcs_rv *pp_smu; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/aux_engine.h b/drivers/gpu/drm/amd/display/dc/inc/hw/aux_engine.h new file mode 100644 index 0000000000000..06d7e5d4cf21d --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/aux_engine.h @@ -0,0 +1,113 @@ +/* + * Copyright 2012-15 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DAL_AUX_ENGINE_H__ +#define __DAL_AUX_ENGINE_H__ + +#include "engine.h" +#include "include/i2caux_interface.h" + +struct aux_engine; +union aux_config; +struct aux_engine_funcs { + void (*destroy)( + struct aux_engine **ptr); + bool (*acquire_engine)( + struct aux_engine *engine); + void (*configure)( + struct aux_engine *engine, + union aux_config cfg); + void (*submit_channel_request)( + struct aux_engine *engine, + struct aux_request_transaction_data *request); + void (*process_channel_reply)( + struct aux_engine *engine, + struct aux_reply_transaction_data *reply); + int (*read_channel_reply)( + struct aux_engine *engine, + uint32_t size, + uint8_t *buffer, + uint8_t *reply_result, + uint32_t *sw_status); + enum aux_channel_operation_result (*get_channel_status)( + struct aux_engine *engine, + uint8_t *returned_bytes); + bool (*is_engine_available)(struct aux_engine *engine); +}; +struct engine; +struct aux_engine { + struct engine base; + const struct aux_engine_funcs *funcs; + /* following values are expressed in milliseconds */ + uint32_t delay; + uint32_t max_defer_write_retry; + + bool acquire_reset; +}; +struct read_command_context { + uint8_t *buffer; + uint32_t current_read_length; + uint32_t offset; + enum i2caux_transaction_status status; + + struct aux_request_transaction_data request; + struct aux_reply_transaction_data reply; + + uint8_t returned_byte; + + uint32_t timed_out_retry_aux; + uint32_t invalid_reply_retry_aux; + uint32_t defer_retry_aux; + uint32_t defer_retry_i2c; + uint32_t invalid_reply_retry_aux_on_ack; + + bool transaction_complete; + bool operation_succeeded; +}; +struct write_command_context { + bool mot; + + uint8_t *buffer; + uint32_t current_write_length; + enum i2caux_transaction_status status; + + struct aux_request_transaction_data request; + struct aux_reply_transaction_data reply; + + uint8_t returned_byte; + + uint32_t timed_out_retry_aux; + uint32_t invalid_reply_retry_aux; + uint32_t defer_retry_aux; + uint32_t defer_retry_i2c; + uint32_t max_defer_retry; + uint32_t ack_m_retry; + + uint8_t reply_data[DEFAULT_AUX_MAX_DATA_SIZE]; + + bool transaction_complete; + bool operation_succeeded; +}; +#endif diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/engine.h b/drivers/gpu/drm/amd/display/dc/inc/hw/engine.h new file mode 100644 index 0000000000000..1f5476f412363 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/engine.h @@ -0,0 +1,106 @@ +/* + * Copyright 2012-15 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DAL_ENGINE_H__ +#define __DAL_ENGINE_H__ + +#include "dc_ddc_types.h" + +enum i2caux_transaction_operation { + I2CAUX_TRANSACTION_READ, + I2CAUX_TRANSACTION_WRITE +}; + +enum i2caux_transaction_address_space { + I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C = 1, + I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD +}; + +struct i2caux_transaction_payload { + enum i2caux_transaction_address_space address_space; + uint32_t address; + uint32_t length; + uint8_t *data; +}; + +enum i2caux_transaction_status { + I2CAUX_TRANSACTION_STATUS_UNKNOWN = (-1L), + I2CAUX_TRANSACTION_STATUS_SUCCEEDED, + I2CAUX_TRANSACTION_STATUS_FAILED_CHANNEL_BUSY, + I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT, + I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR, + I2CAUX_TRANSACTION_STATUS_FAILED_NACK, + I2CAUX_TRANSACTION_STATUS_FAILED_INCOMPLETE, + I2CAUX_TRANSACTION_STATUS_FAILED_OPERATION, + I2CAUX_TRANSACTION_STATUS_FAILED_INVALID_OPERATION, + I2CAUX_TRANSACTION_STATUS_FAILED_BUFFER_OVERFLOW, + I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON +}; + +struct i2caux_transaction_request { + enum i2caux_transaction_operation operation; + struct i2caux_transaction_payload payload; + enum i2caux_transaction_status status; +}; + +enum i2caux_engine_type { + I2CAUX_ENGINE_TYPE_UNKNOWN = (-1L), + I2CAUX_ENGINE_TYPE_AUX, + I2CAUX_ENGINE_TYPE_I2C_DDC_HW, + I2CAUX_ENGINE_TYPE_I2C_GENERIC_HW, + I2CAUX_ENGINE_TYPE_I2C_SW +}; + +enum i2c_default_speed { + I2CAUX_DEFAULT_I2C_HW_SPEED = 50, + I2CAUX_DEFAULT_I2C_SW_SPEED = 50 +}; + +struct engine; + +struct engine_funcs { + enum i2caux_engine_type (*get_engine_type)( + const struct engine *engine); + struct aux_engine* (*acquire)( + struct engine *engine, + struct ddc *ddc); + bool (*submit_request)( + struct engine *engine, + struct i2caux_transaction_request *request, + bool middle_of_transaction); + void (*release_engine)( + struct engine *engine); + void (*destroy_engine)( + struct engine **engine); +}; + +struct engine { + const struct engine_funcs *funcs; + uint32_t inst; + struct ddc *ddc; + struct dc_context *ctx; +}; + +#endif -- GitLab From cfd84fd36531b2f1de01b3530b6953ed34ed2c95 Mon Sep 17 00:00:00 2001 From: Jun Lei <Jun.Lei@amd.com> Date: Thu, 12 Jul 2018 10:35:01 -0400 Subject: [PATCH 1305/1506] drm/amd/display: separate dc_debug into dc_debug_options and dc_debug data [why] confusing as to which part of debug is informational, and which part causes behavioral change Signed-off-by: Jun Lei <Jun.Lei@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Leo Li <sunpeng.li@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/display/dc/calcs/dcn_calcs.c | 2 +- .../gpu/drm/amd/display/dc/core/dc_link_dp.c | 2 +- drivers/gpu/drm/amd/display/dc/dc.h | 19 +++++++++++-------- .../gpu/drm/amd/display/dc/dce/dce_clocks.c | 4 ++-- .../amd/display/dc/dce120/dce120_resource.c | 2 +- .../drm/amd/display/dc/dcn10/dcn10_resource.c | 4 ++-- 6 files changed, 18 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c index 080f777d705e7..bd039322f697b 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c @@ -676,7 +676,7 @@ static void hack_force_pipe_split(struct dcn_bw_internal_vars *v, } static void hack_bounding_box(struct dcn_bw_internal_vars *v, - struct dc_debug *dbg, + struct dc_debug_options *dbg, struct dc_state *context) { if (dbg->pipe_split_policy == MPC_SPLIT_AVOID) 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 b8e6db4382ec0..9d901ca705883 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 @@ -1029,7 +1029,7 @@ enum link_training_result dc_link_dp_perform_link_training( lt_settings.lane_settings[0].PRE_EMPHASIS); if (status != LINK_TRAINING_SUCCESS) - link->ctx->dc->debug.debug_data.ltFailCount++; + link->ctx->dc->debug_data.ltFailCount++; return status; } diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 5e2a2acb5ad68..93b8bf030ba72 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -207,7 +207,7 @@ struct dc_clocks { int phyclk_khz; }; -struct dc_debug { +struct dc_debug_options { enum visual_confirm visual_confirm; bool sanity_checks; bool max_disp_clk; @@ -259,13 +259,15 @@ struct dc_debug { bool scl_reset_length10; bool hdmi20_disable; bool skip_detection_link_training; +}; - struct { - uint32_t ltFailCount; - uint32_t i2cErrorCount; - uint32_t auxErrorCount; - } debug_data; +struct dc_debug_data { + uint32_t ltFailCount; + uint32_t i2cErrorCount; + uint32_t auxErrorCount; }; + + struct dc_state; struct resource_pool; struct dce_hwseq; @@ -274,8 +276,7 @@ struct dc { struct dc_caps caps; struct dc_cap_funcs cap_funcs; struct dc_config config; - struct dc_debug debug; - + struct dc_debug_options debug; struct dc_context *ctx; uint8_t link_count; @@ -311,6 +312,8 @@ struct dc { /* FBC compressor */ struct compressor *fbc_compressor; + + struct dc_debug_data debug_data; }; enum frame_buffer_mode { diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c index 8f8a2abac3f30..0db8d1da3d0ec 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c @@ -337,7 +337,7 @@ static int dce112_set_clock( static void dce_clock_read_integrated_info(struct dce_dccg *clk_dce) { - struct dc_debug *debug = &clk_dce->base.ctx->dc->debug; + struct dc_debug_options *debug = &clk_dce->base.ctx->dc->debug; struct dc_bios *bp = clk_dce->base.ctx->dc_bios; struct integrated_info info = { { { 0 } } }; struct dc_firmware_info fw_info = { { 0 } }; @@ -824,7 +824,7 @@ struct dccg *dce120_dccg_create(struct dc_context *ctx) #ifdef CONFIG_X86 struct dccg *dcn1_dccg_create(struct dc_context *ctx) { - struct dc_debug *debug = &ctx->dc->debug; + struct dc_debug_options *debug = &ctx->dc->debug; struct dc_bios *bp = ctx->dc_bios; struct dc_firmware_info fw_info = { { 0 } }; struct dce_dccg *clk_dce = kzalloc(sizeof(*clk_dce), GFP_KERNEL); diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c index e389832c96ccb..f7d02f2190d3e 100644 --- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c @@ -404,7 +404,7 @@ static const struct resource_caps res_cap = { .num_pll = 6, }; -static const struct dc_debug debug_defaults = { +static const struct dc_debug_options debug_defaults = { .disable_clock_gate = true, }; diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c index ef8bb27356205..cd8c22839227a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c @@ -502,7 +502,7 @@ static const struct resource_caps res_cap = { .num_pll = 4, }; -static const struct dc_debug debug_defaults_drv = { +static const struct dc_debug_options debug_defaults_drv = { .sanity_checks = true, .disable_dmcu = true, .force_abm_enable = false, @@ -530,7 +530,7 @@ static const struct dc_debug debug_defaults_drv = { .max_downscale_src_width = 3840, }; -static const struct dc_debug debug_defaults_diags = { +static const struct dc_debug_options debug_defaults_diags = { .disable_dmcu = true, .force_abm_enable = false, .timing_trace = true, -- GitLab From bb805f2b20e2200753bf0a69b3ef5332b37eb781 Mon Sep 17 00:00:00 2001 From: Harry Wentland <harry.wentland@amd.com> Date: Mon, 9 Jul 2018 17:25:42 -0400 Subject: [PATCH 1306/1506] drm/amd/display: DC 3.1.58 Signed-off-by: Harry Wentland <harry.wentland@amd.com> Reviewed-by: Aric Cyr <Aric.Cyr@amd.com> Acked-by: Leo Li <sunpeng.li@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 93b8bf030ba72..7515c0dcbdd24 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.1.56" +#define DC_VER "3.1.58" #define MAX_SURFACES 3 #define MAX_STREAMS 6 -- GitLab From ec446d09366cea199214b30810e368c5178841cd Mon Sep 17 00:00:00 2001 From: Daniel Mack <daniel@zonque.org> Date: Mon, 28 May 2018 21:53:38 +0200 Subject: [PATCH 1307/1506] drm/msm: call drm_atomic_helper_suspend() and drm_atomic_helper_resume() To make suspend and resume work on msm8916 platforms, call into the generic helpers and preserve the state across suspends. Signed-off-by: Daniel Mack <daniel@zonque.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/msm/msm_drv.c | 9 +++++++++ drivers/gpu/drm/msm/msm_drv.h | 1 + 2 files changed, 10 insertions(+) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 021a0b6f9a597..7f7321eb53127 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -894,16 +894,25 @@ static struct drm_driver msm_driver = { static int msm_pm_suspend(struct device *dev) { struct drm_device *ddev = dev_get_drvdata(dev); + struct msm_drm_private *priv = ddev->dev_private; drm_kms_helper_poll_disable(ddev); + priv->pm_state = drm_atomic_helper_suspend(ddev); + if (IS_ERR(priv->pm_state)) { + drm_kms_helper_poll_enable(ddev); + return PTR_ERR(priv->pm_state); + } + return 0; } static int msm_pm_resume(struct device *dev) { struct drm_device *ddev = dev_get_drvdata(dev); + struct msm_drm_private *priv = ddev->dev_private; + drm_atomic_helper_resume(ddev, priv->pm_state); drm_kms_helper_poll_enable(ddev); return 0; diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index b2da1fbf81e0f..17cefca1d5666 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -150,6 +150,7 @@ struct msm_drm_private { struct shrinker shrinker; struct msm_vblank_ctrl vblank_ctrl; + struct drm_atomic_state *pm_state; }; struct msm_format { -- GitLab From 6666e1a66f92988e8c85a7ac0c34f47dc7d412a0 Mon Sep 17 00:00:00 2001 From: Daniel Mack <daniel@zonque.org> Date: Mon, 28 May 2018 21:53:39 +0200 Subject: [PATCH 1308/1506] drm/msm/adreno: Add power management functions for system sleep When a msm8016 based system is woken up from suspend, the firmware in the adreno device hangs. [ 83.903416] qcom-iommu-ctx 1f09000.iommu-ctx: Unhandled context fault: fsr=0x202, iova=0x0000000000000000, fsynr=0x2, cb=1 [ 85.853633] msm 1a00000.mdss: A306: hangcheck detected gpu lockup rb 0! [ 85.853661] msm 1a00000.mdss: A306: completed fence: 370 [ 85.859073] msm 1a00000.mdss: A306: submitted fence: 372 [ 85.865113] msm 1a00000.mdss: A306: hangcheck recover! Fix this by adding pm_runtime_force_suspend/pm_runtime_force_resume as sleep ops. Signed-off-by: Daniel Mack <daniel@zonque.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/msm/adreno/adreno_device.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c index 0ae5ace65462d..01d4e09cdf85e 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_device.c +++ b/drivers/gpu/drm/msm/adreno/adreno_device.c @@ -316,6 +316,7 @@ static int adreno_suspend(struct device *dev) #endif static const struct dev_pm_ops adreno_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) SET_RUNTIME_PM_OPS(adreno_suspend, adreno_resume, NULL) }; -- GitLab From 64709686dbb38f32045e117ec5a1aaf2e3a0a3c4 Mon Sep 17 00:00:00 2001 From: Jordan Crouse <jcrouse@codeaurora.org> Date: Mon, 7 May 2018 16:47:50 -0600 Subject: [PATCH 1309/1506] drm/msm/gpu: Increase the pm runtime autosuspend for 5xx Experimentation shows that resuming power quickly after suspending ends up forcing a system hang for unknown reasons on 5xx targets. To avoid cycling the power too much (especially during init) turn up the autosuspend time for a5xx to 250ms and use pm_runtime_put_autosuspend() when applicable. Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/msm/adreno/adreno_device.c | 13 ++++++++++++- drivers/gpu/drm/msm/adreno/adreno_gpu.c | 3 ++- drivers/gpu/drm/msm/adreno/adreno_gpu.h | 1 + 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c index 01d4e09cdf85e..44813624a2866 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_device.c +++ b/drivers/gpu/drm/msm/adreno/adreno_device.c @@ -35,6 +35,7 @@ static const struct adreno_info gpulist[] = { [ADRENO_FW_PFP] = "a300_pfp.fw", }, .gmem = SZ_256K, + .inactive_period = DRM_MSM_INACTIVE_PERIOD, .init = a3xx_gpu_init, }, { .rev = ADRENO_REV(3, 0, 6, 0), @@ -45,6 +46,7 @@ static const struct adreno_info gpulist[] = { [ADRENO_FW_PFP] = "a300_pfp.fw", }, .gmem = SZ_128K, + .inactive_period = DRM_MSM_INACTIVE_PERIOD, .init = a3xx_gpu_init, }, { .rev = ADRENO_REV(3, 2, ANY_ID, ANY_ID), @@ -55,6 +57,7 @@ static const struct adreno_info gpulist[] = { [ADRENO_FW_PFP] = "a300_pfp.fw", }, .gmem = SZ_512K, + .inactive_period = DRM_MSM_INACTIVE_PERIOD, .init = a3xx_gpu_init, }, { .rev = ADRENO_REV(3, 3, 0, ANY_ID), @@ -65,6 +68,7 @@ static const struct adreno_info gpulist[] = { [ADRENO_FW_PFP] = "a330_pfp.fw", }, .gmem = SZ_1M, + .inactive_period = DRM_MSM_INACTIVE_PERIOD, .init = a3xx_gpu_init, }, { .rev = ADRENO_REV(4, 2, 0, ANY_ID), @@ -75,6 +79,7 @@ static const struct adreno_info gpulist[] = { [ADRENO_FW_PFP] = "a420_pfp.fw", }, .gmem = (SZ_1M + SZ_512K), + .inactive_period = DRM_MSM_INACTIVE_PERIOD, .init = a4xx_gpu_init, }, { .rev = ADRENO_REV(4, 3, 0, ANY_ID), @@ -85,6 +90,7 @@ static const struct adreno_info gpulist[] = { [ADRENO_FW_PFP] = "a420_pfp.fw", }, .gmem = (SZ_1M + SZ_512K), + .inactive_period = DRM_MSM_INACTIVE_PERIOD, .init = a4xx_gpu_init, }, { .rev = ADRENO_REV(5, 3, 0, 2), @@ -96,6 +102,11 @@ static const struct adreno_info gpulist[] = { [ADRENO_FW_GPMU] = "a530v3_gpmu.fw2", }, .gmem = SZ_1M, + /* + * Increase inactive period to 250 to avoid bouncing + * the GDSC which appears to make it grumpy + */ + .inactive_period = 250, .quirks = ADRENO_QUIRK_TWO_PASS_USE_WFI | ADRENO_QUIRK_FAULT_DETECT_MASK, .init = a5xx_gpu_init, @@ -158,7 +169,7 @@ struct msm_gpu *adreno_load_gpu(struct drm_device *dev) mutex_lock(&dev->struct_mutex); ret = msm_gpu_hw_init(gpu); mutex_unlock(&dev->struct_mutex); - pm_runtime_put_sync(&pdev->dev); + pm_runtime_put_autosuspend(&pdev->dev); if (ret) { dev_err(dev->dev, "gpu hw init failed: %d\n", ret); return NULL; diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index 17d0506d058c7..bcbf9f2a29f9c 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -565,7 +565,8 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, adreno_get_pwrlevels(&pdev->dev, gpu); - pm_runtime_set_autosuspend_delay(&pdev->dev, DRM_MSM_INACTIVE_PERIOD); + pm_runtime_set_autosuspend_delay(&pdev->dev, + adreno_gpu->info->inactive_period); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_enable(&pdev->dev); diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h index d6b0e7b813f40..bc9ec27e9ed85 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h @@ -84,6 +84,7 @@ struct adreno_info { enum adreno_quirks quirks; struct msm_gpu *(*init)(struct drm_device *dev); const char *zapfw; + u32 inactive_period; }; const struct adreno_info *adreno_info(struct adreno_rev rev); -- GitLab From 6e8bed6a3e2fd6f1e82ea9b1f705bbc82060a2b7 Mon Sep 17 00:00:00 2001 From: Rob Clark <robdclark@gmail.com> Date: Tue, 3 Jul 2018 08:14:32 -0400 Subject: [PATCH 1310/1506] drm/msm/mdp5: fix missing CTL flush f9cb8d8d836e fixed various race conditions with CTL flush, in particular flushing and sending the START signal before encoder state was updated. But it did this a little too well in some cases that don't trigger encoder->enable(), and CTL[n].FLUSH would never be set. When page flips happen it would paper over the bug, since the first plag flip would flush out the state to the hardware. The issue could be reproduced with, for example, modetest (without the '-v' argument). Fixes: f9cb8d8d836e drm/msm/mdp5: rework CTL START signal handling Signed-off-by: Rob Clark <robdclark@gmail.com> Reviewed-by: Sean Paul <seanpaul@chromium.org> --- drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c index 9af94e35f678d..fcd44d1d10682 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c @@ -319,7 +319,17 @@ static int mdp5_encoder_atomic_check(struct drm_encoder *encoder, mdp5_cstate->ctl = ctl; mdp5_cstate->pipeline.intf = intf; - mdp5_cstate->defer_start = true; + + /* + * This is a bit awkward, but we want to flush the CTL and hit the + * START bit at most once for an atomic update. In the non-full- + * modeset case, this is done from crtc->atomic_flush(), but that + * is too early in the case of full modeset, in which case we + * defer to encoder->enable(). But we need to *know* whether + * encoder->enable() will be called to do this: + */ + if (drm_atomic_crtc_needs_modeset(crtc_state)) + mdp5_cstate->defer_start = true; return 0; } -- GitLab From e18177cc572939ad9526bae141fc4c8f5f006de4 Mon Sep 17 00:00:00 2001 From: Sibi Sankar <sibis@codeaurora.org> Date: Tue, 29 May 2018 19:50:31 +0530 Subject: [PATCH 1311/1506] drm/msm/dsi: add dsi host helper functions support Add dsi host helper functions support for DSI v2 and DSI 6G 1.x controllers that are under version checks Signed-off-by: Sibi Sankar <sibis@codeaurora.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/msm/dsi/dsi.h | 1 + drivers/gpu/drm/msm/dsi/dsi_cfg.h | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h index 70d9a9a47acd5..80be83e8fdecc 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.h +++ b/drivers/gpu/drm/msm/dsi/dsi.h @@ -149,6 +149,7 @@ static inline int msm_dsi_pll_set_usecase(struct msm_dsi_pll *pll, #endif /* dsi host */ +struct msm_dsi_host; int msm_dsi_host_xfer_prepare(struct mipi_dsi_host *host, const struct mipi_dsi_msg *msg); void msm_dsi_host_xfer_restore(struct mipi_dsi_host *host, diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.h b/drivers/gpu/drm/msm/dsi/dsi_cfg.h index 9cfdcf1c95d5e..a795a062b7795 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_cfg.h +++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.h @@ -40,10 +40,22 @@ struct msm_dsi_config { const int num_dsi; }; +struct msm_dsi_host_cfg_ops { + int (*link_clk_enable)(struct msm_dsi_host *msm_host); + void (*link_clk_disable)(struct msm_dsi_host *msm_host); + int (*clk_init_ver)(struct msm_dsi_host *msm_host); + int (*tx_buf_alloc)(struct msm_dsi_host *msm_host, int size); + void* (*tx_buf_get)(struct msm_dsi_host *msm_host); + void (*tx_buf_put)(struct msm_dsi_host *msm_host); + int (*dma_base_get)(struct msm_dsi_host *msm_host, uint64_t *iova); + int (*calc_clk_rate)(struct msm_dsi_host *msm_host); +}; + struct msm_dsi_cfg_handler { u32 major; u32 minor; const struct msm_dsi_config *cfg; + const struct msm_dsi_host_cfg_ops *ops; }; const struct msm_dsi_cfg_handler *msm_dsi_cfg_get(u32 major, u32 minor); -- GitLab From c4d8cfe516dc54bac8837bc90ccbd878ad26c59e Mon Sep 17 00:00:00 2001 From: Sibi Sankar <sibis@codeaurora.org> Date: Tue, 29 May 2018 19:50:32 +0530 Subject: [PATCH 1312/1506] drm/msm/dsi: add implementation for helper functions Add dsi host helper function implementation for DSI v2 DSI 6G 1.x and DSI 6G v2.0+ controllers Signed-off-by: Sibi Sankar <sibis@codeaurora.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/msm/dsi/dsi.h | 15 ++ drivers/gpu/drm/msm/dsi/dsi_cfg.c | 56 ++++++-- drivers/gpu/drm/msm/dsi/dsi_host.c | 218 ++++++++++++++++++++++++++++- 3 files changed, 278 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h index 80be83e8fdecc..dfa049d876bde 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.h +++ b/drivers/gpu/drm/msm/dsi/dsi.h @@ -183,6 +183,21 @@ int msm_dsi_host_modeset_init(struct mipi_dsi_host *host, int msm_dsi_host_init(struct msm_dsi *msm_dsi); int msm_dsi_runtime_suspend(struct device *dev); int msm_dsi_runtime_resume(struct device *dev); +int dsi_link_clk_enable_6g(struct msm_dsi_host *msm_host); +int dsi_link_clk_enable_v2(struct msm_dsi_host *msm_host); +void dsi_link_clk_disable_6g(struct msm_dsi_host *msm_host); +void dsi_link_clk_disable_v2(struct msm_dsi_host *msm_host); +int dsi_tx_buf_alloc_6g(struct msm_dsi_host *msm_host, int size); +int dsi_tx_buf_alloc_v2(struct msm_dsi_host *msm_host, int size); +void *dsi_tx_buf_get_6g(struct msm_dsi_host *msm_host); +void *dsi_tx_buf_get_v2(struct msm_dsi_host *msm_host); +void dsi_tx_buf_put_6g(struct msm_dsi_host *msm_host); +int dsi_dma_base_get_6g(struct msm_dsi_host *msm_host, uint64_t *iova); +int dsi_dma_base_get_v2(struct msm_dsi_host *msm_host, uint64_t *iova); +int dsi_clk_init_v2(struct msm_dsi_host *msm_host); +int dsi_clk_init_6g_v2(struct msm_dsi_host *msm_host); +int dsi_calc_clk_rate_v2(struct msm_dsi_host *msm_host); +int dsi_calc_clk_rate_6g(struct msm_dsi_host *msm_host); /* dsi phy */ struct msm_dsi_phy; diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.c b/drivers/gpu/drm/msm/dsi/dsi_cfg.c index 0327bb54b01b4..dcdfb1bb54f98 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_cfg.c +++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.c @@ -136,20 +136,58 @@ static const struct msm_dsi_config sdm845_dsi_cfg = { .num_dsi = 2, }; +const static struct msm_dsi_host_cfg_ops msm_dsi_v2_host_ops = { + .link_clk_enable = dsi_link_clk_enable_v2, + .link_clk_disable = dsi_link_clk_disable_v2, + .clk_init_ver = dsi_clk_init_v2, + .tx_buf_alloc = dsi_tx_buf_alloc_v2, + .tx_buf_get = dsi_tx_buf_get_v2, + .tx_buf_put = NULL, + .dma_base_get = dsi_dma_base_get_v2, + .calc_clk_rate = dsi_calc_clk_rate_v2, +}; + +const static struct msm_dsi_host_cfg_ops msm_dsi_6g_host_ops = { + .link_clk_enable = dsi_link_clk_enable_6g, + .link_clk_disable = dsi_link_clk_disable_6g, + .clk_init_ver = NULL, + .tx_buf_alloc = dsi_tx_buf_alloc_6g, + .tx_buf_get = dsi_tx_buf_get_6g, + .tx_buf_put = dsi_tx_buf_put_6g, + .dma_base_get = dsi_dma_base_get_6g, + .calc_clk_rate = dsi_calc_clk_rate_6g, +}; + +const static struct msm_dsi_host_cfg_ops msm_dsi_6g_v2_host_ops = { + .link_clk_enable = dsi_link_clk_enable_6g, + .link_clk_disable = dsi_link_clk_disable_6g, + .clk_init_ver = dsi_clk_init_6g_v2, + .tx_buf_alloc = dsi_tx_buf_alloc_6g, + .tx_buf_get = dsi_tx_buf_get_6g, + .tx_buf_put = dsi_tx_buf_put_6g, + .dma_base_get = dsi_dma_base_get_6g, + .calc_clk_rate = dsi_calc_clk_rate_6g, +}; + static const struct msm_dsi_cfg_handler dsi_cfg_handlers[] = { - {MSM_DSI_VER_MAJOR_V2, MSM_DSI_V2_VER_MINOR_8064, &apq8064_dsi_cfg}, + {MSM_DSI_VER_MAJOR_V2, MSM_DSI_V2_VER_MINOR_8064, + &apq8064_dsi_cfg, &msm_dsi_v2_host_ops}, {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_0, - &msm8974_apq8084_dsi_cfg}, + &msm8974_apq8084_dsi_cfg, &msm_dsi_6g_host_ops}, {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_1, - &msm8974_apq8084_dsi_cfg}, + &msm8974_apq8084_dsi_cfg, &msm_dsi_6g_host_ops}, {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_1_1, - &msm8974_apq8084_dsi_cfg}, + &msm8974_apq8084_dsi_cfg, &msm_dsi_6g_host_ops}, {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_2, - &msm8974_apq8084_dsi_cfg}, - {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_3, &msm8994_dsi_cfg}, - {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_3_1, &msm8916_dsi_cfg}, - {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_4_1, &msm8996_dsi_cfg}, - {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_2_1, &sdm845_dsi_cfg}, + &msm8974_apq8084_dsi_cfg, &msm_dsi_6g_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_3, + &msm8994_dsi_cfg, &msm_dsi_6g_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_3_1, + &msm8916_dsi_cfg, &msm_dsi_6g_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_4_1, + &msm8996_dsi_cfg, &msm_dsi_6g_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_2_1, + &sdm845_dsi_cfg, &msm_dsi_6g_v2_host_ops}, }; const struct msm_dsi_cfg_handler *msm_dsi_cfg_get(u32 major, u32 minor) diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index 29841f440111e..414a95424d7cb 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -332,6 +332,54 @@ static int dsi_regulator_init(struct msm_dsi_host *msm_host) return 0; } +int dsi_clk_init_v2(struct msm_dsi_host *msm_host) +{ + struct platform_device *pdev = msm_host->pdev; + int ret = 0; + + msm_host->src_clk = msm_clk_get(pdev, "src"); + + if (IS_ERR(msm_host->src_clk)) { + ret = PTR_ERR(msm_host->src_clk); + pr_err("%s: can't find src clock. ret=%d\n", + __func__, ret); + msm_host->src_clk = NULL; + return ret; + } + + msm_host->esc_clk_src = clk_get_parent(msm_host->esc_clk); + if (!msm_host->esc_clk_src) { + ret = -ENODEV; + pr_err("%s: can't get esc clock parent. ret=%d\n", + __func__, ret); + return ret; + } + + msm_host->dsi_clk_src = clk_get_parent(msm_host->src_clk); + if (!msm_host->dsi_clk_src) { + ret = -ENODEV; + pr_err("%s: can't get src clock parent. ret=%d\n", + __func__, ret); + } + + return ret; +} + +int dsi_clk_init_6g_v2(struct msm_dsi_host *msm_host) +{ + struct platform_device *pdev = msm_host->pdev; + int ret = 0; + + msm_host->byte_intf_clk = msm_clk_get(pdev, "byte_intf"); + if (IS_ERR(msm_host->byte_intf_clk)) { + ret = PTR_ERR(msm_host->byte_intf_clk); + pr_err("%s: can't find byte_intf clock. ret=%d\n", + __func__, ret); + } + + return ret; +} + static int dsi_clk_init(struct msm_dsi_host *msm_host) { struct platform_device *pdev = msm_host->pdev; @@ -498,7 +546,7 @@ int msm_dsi_runtime_resume(struct device *dev) return dsi_bus_clk_enable(msm_host); } -static int dsi_link_clk_enable_6g(struct msm_dsi_host *msm_host) +int dsi_link_clk_enable_6g(struct msm_dsi_host *msm_host) { int ret; @@ -566,7 +614,7 @@ static int dsi_link_clk_enable_6g(struct msm_dsi_host *msm_host) return ret; } -static int dsi_link_clk_enable_v2(struct msm_dsi_host *msm_host) +int dsi_link_clk_enable_v2(struct msm_dsi_host *msm_host) { int ret; @@ -644,6 +692,23 @@ static int dsi_link_clk_enable(struct msm_dsi_host *msm_host) return dsi_link_clk_enable_v2(msm_host); } +void dsi_link_clk_disable_6g(struct msm_dsi_host *msm_host) +{ + clk_disable_unprepare(msm_host->esc_clk); + clk_disable_unprepare(msm_host->pixel_clk); + if (msm_host->byte_intf_clk) + clk_disable_unprepare(msm_host->byte_intf_clk); + clk_disable_unprepare(msm_host->byte_clk); +} + +void dsi_link_clk_disable_v2(struct msm_dsi_host *msm_host) +{ + clk_disable_unprepare(msm_host->pixel_clk); + clk_disable_unprepare(msm_host->src_clk); + clk_disable_unprepare(msm_host->esc_clk); + clk_disable_unprepare(msm_host->byte_clk); +} + static void dsi_link_clk_disable(struct msm_dsi_host *msm_host) { const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; @@ -662,6 +727,84 @@ static void dsi_link_clk_disable(struct msm_dsi_host *msm_host) } } +int dsi_calc_clk_rate_6g(struct msm_dsi_host *msm_host) +{ + struct drm_display_mode *mode = msm_host->mode; + u8 lanes = msm_host->lanes; + u32 bpp = dsi_get_bpp(msm_host->format); + u32 pclk_rate; + + pclk_rate = mode->clock * 1000; + if (lanes > 0) { + msm_host->byte_clk_rate = (pclk_rate * bpp) / (8 * lanes); + } else { + pr_err("%s: forcing mdss_dsi lanes to 1\n", __func__); + msm_host->byte_clk_rate = (pclk_rate * bpp) / 8; + } + + DBG("pclk=%d, bclk=%d", pclk_rate, msm_host->byte_clk_rate); + + msm_host->esc_clk_rate = clk_get_rate(msm_host->esc_clk); + + return 0; +} + +int dsi_calc_clk_rate_v2(struct msm_dsi_host *msm_host) +{ + struct drm_display_mode *mode = msm_host->mode; + u8 lanes = msm_host->lanes; + u32 bpp = dsi_get_bpp(msm_host->format); + u32 pclk_rate; + unsigned int esc_mhz, esc_div; + unsigned long byte_mhz; + + pclk_rate = mode->clock * 1000; + if (lanes > 0) { + msm_host->byte_clk_rate = (pclk_rate * bpp) / (8 * lanes); + } else { + pr_err("%s: forcing mdss_dsi lanes to 1\n", __func__); + msm_host->byte_clk_rate = (pclk_rate * bpp) / 8; + } + + DBG("pclk=%d, bclk=%d", pclk_rate, msm_host->byte_clk_rate); + + msm_host->src_clk_rate = (pclk_rate * bpp) / 8; + + /* + * esc clock is byte clock followed by a 4 bit divider, + * we need to find an escape clock frequency within the + * mipi DSI spec range within the maximum divider limit + * We iterate here between an escape clock frequencey + * between 20 Mhz to 5 Mhz and pick up the first one + * that can be supported by our divider + */ + + byte_mhz = msm_host->byte_clk_rate / 1000000; + + for (esc_mhz = 20; esc_mhz >= 5; esc_mhz--) { + esc_div = DIV_ROUND_UP(byte_mhz, esc_mhz); + + /* + * TODO: Ideally, we shouldn't know what sort of divider + * is available in mmss_cc, we're just assuming that + * it'll always be a 4 bit divider. Need to come up with + * a better way here. + */ + if (esc_div >= 1 && esc_div <= 16) + break; + } + + if (esc_mhz < 5) + return -EINVAL; + + msm_host->esc_clk_rate = msm_host->byte_clk_rate / esc_div; + + DBG("esc=%d, src=%d", msm_host->esc_clk_rate, + msm_host->src_clk_rate); + + return 0; +} + static int dsi_calc_clk_rate(struct msm_dsi_host *msm_host) { struct drm_display_mode *mode = msm_host->mode; @@ -1015,6 +1158,41 @@ static void dsi_wait4video_eng_busy(struct msm_dsi_host *msm_host) } } +int dsi_tx_buf_alloc_6g(struct msm_dsi_host *msm_host, int size) +{ + struct drm_device *dev = msm_host->dev; + struct msm_drm_private *priv = dev->dev_private; + uint64_t iova; + u8 *data; + + data = msm_gem_kernel_new(dev, size, MSM_BO_UNCACHED, + priv->kms->aspace, + &msm_host->tx_gem_obj, &iova); + + if (IS_ERR(data)) { + msm_host->tx_gem_obj = NULL; + return PTR_ERR(data); + } + + msm_host->tx_size = msm_host->tx_gem_obj->size; + + return 0; +} + +int dsi_tx_buf_alloc_v2(struct msm_dsi_host *msm_host, int size) +{ + struct drm_device *dev = msm_host->dev; + + msm_host->tx_buf = dma_alloc_coherent(dev->dev, size, + &msm_host->tx_buf_paddr, GFP_KERNEL); + if (!msm_host->tx_buf) + return -ENOMEM; + + msm_host->tx_size = size; + + return 0; +} + /* dsi_cmd */ static int dsi_tx_buf_alloc(struct msm_dsi_host *msm_host, int size) { @@ -1089,6 +1267,21 @@ static void dsi_tx_buf_free(struct msm_dsi_host *msm_host) msm_host->tx_buf_paddr); } +void *dsi_tx_buf_get_6g(struct msm_dsi_host *msm_host) +{ + return msm_gem_get_vaddr(msm_host->tx_gem_obj); +} + +void *dsi_tx_buf_get_v2(struct msm_dsi_host *msm_host) +{ + return msm_host->tx_buf; +} + +void dsi_tx_buf_put_6g(struct msm_dsi_host *msm_host) +{ + msm_gem_put_vaddr(msm_host->tx_gem_obj); +} + /* * prepare cmd buffer to be txed */ @@ -1190,6 +1383,27 @@ static int dsi_long_read_resp(u8 *buf, const struct mipi_dsi_msg *msg) return msg->rx_len; } +int dsi_dma_base_get_6g(struct msm_dsi_host *msm_host, uint64_t *dma_base) +{ + struct drm_device *dev = msm_host->dev; + struct msm_drm_private *priv = dev->dev_private; + + if (!dma_base) + return -EINVAL; + + return msm_gem_get_iova(msm_host->tx_gem_obj, + priv->kms->aspace, dma_base); +} + +int dsi_dma_base_get_v2(struct msm_dsi_host *msm_host, uint64_t *dma_base) +{ + if (!dma_base) + return -EINVAL; + + *dma_base = msm_host->tx_buf_paddr; + return 0; +} + static int dsi_cmd_dma_tx(struct msm_dsi_host *msm_host, int len) { const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; -- GitLab From 8f7ca5409063ade228a8ea0cc77b5fe9877f8cf0 Mon Sep 17 00:00:00 2001 From: Sibi Sankar <sibis@codeaurora.org> Date: Tue, 29 May 2018 19:50:33 +0530 Subject: [PATCH 1313/1506] drm/msm/dsi: replace version checks with helper functions Replace version checks with the helper functions bound to cfg_handler for DSI v2, DSI 6G 1.x and DSI 6G v2.0+ controllers Signed-off-by: Sibi Sankar <sibis@codeaurora.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/msm/dsi/dsi_host.c | 241 ++++------------------------- 1 file changed, 29 insertions(+), 212 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index 414a95424d7cb..24dfae5b01a2b 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -427,19 +427,6 @@ static int dsi_clk_init(struct msm_dsi_host *msm_host) goto exit; } - if (cfg_hnd->major == MSM_DSI_VER_MAJOR_6G && - cfg_hnd->minor >= MSM_DSI_6G_VER_MINOR_V2_2_1) { - msm_host->byte_intf_clk = msm_clk_get(pdev, "byte_intf"); - if (IS_ERR(msm_host->byte_intf_clk)) { - ret = PTR_ERR(msm_host->byte_intf_clk); - pr_err("%s: can't find byte_intf clock. ret=%d\n", - __func__, ret); - goto exit; - } - } else { - msm_host->byte_intf_clk = NULL; - } - msm_host->byte_clk_src = clk_get_parent(msm_host->byte_clk); if (!msm_host->byte_clk_src) { ret = -ENODEV; @@ -454,31 +441,8 @@ static int dsi_clk_init(struct msm_dsi_host *msm_host) goto exit; } - if (cfg_hnd->major == MSM_DSI_VER_MAJOR_V2) { - msm_host->src_clk = msm_clk_get(pdev, "src"); - if (IS_ERR(msm_host->src_clk)) { - ret = PTR_ERR(msm_host->src_clk); - pr_err("%s: can't find src clock. ret=%d\n", - __func__, ret); - msm_host->src_clk = NULL; - goto exit; - } - - msm_host->esc_clk_src = clk_get_parent(msm_host->esc_clk); - if (!msm_host->esc_clk_src) { - ret = -ENODEV; - pr_err("%s: can't get esc clock parent. ret=%d\n", - __func__, ret); - goto exit; - } - - msm_host->dsi_clk_src = clk_get_parent(msm_host->src_clk); - if (!msm_host->dsi_clk_src) { - ret = -ENODEV; - pr_err("%s: can't get src clock parent. ret=%d\n", - __func__, ret); - } - } + if (cfg_hnd->ops->clk_init_ver) + ret = cfg_hnd->ops->clk_init_ver(msm_host); exit: return ret; } @@ -682,16 +646,6 @@ int dsi_link_clk_enable_v2(struct msm_dsi_host *msm_host) return ret; } -static int dsi_link_clk_enable(struct msm_dsi_host *msm_host) -{ - const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; - - if (cfg_hnd->major == MSM_DSI_VER_MAJOR_6G) - return dsi_link_clk_enable_6g(msm_host); - else - return dsi_link_clk_enable_v2(msm_host); -} - void dsi_link_clk_disable_6g(struct msm_dsi_host *msm_host) { clk_disable_unprepare(msm_host->esc_clk); @@ -709,24 +663,6 @@ void dsi_link_clk_disable_v2(struct msm_dsi_host *msm_host) clk_disable_unprepare(msm_host->byte_clk); } -static void dsi_link_clk_disable(struct msm_dsi_host *msm_host) -{ - const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; - - if (cfg_hnd->major == MSM_DSI_VER_MAJOR_6G) { - clk_disable_unprepare(msm_host->esc_clk); - clk_disable_unprepare(msm_host->pixel_clk); - if (msm_host->byte_intf_clk) - clk_disable_unprepare(msm_host->byte_intf_clk); - clk_disable_unprepare(msm_host->byte_clk); - } else { - clk_disable_unprepare(msm_host->pixel_clk); - clk_disable_unprepare(msm_host->src_clk); - clk_disable_unprepare(msm_host->esc_clk); - clk_disable_unprepare(msm_host->byte_clk); - } -} - int dsi_calc_clk_rate_6g(struct msm_dsi_host *msm_host) { struct drm_display_mode *mode = msm_host->mode; @@ -805,73 +741,6 @@ int dsi_calc_clk_rate_v2(struct msm_dsi_host *msm_host) return 0; } -static int dsi_calc_clk_rate(struct msm_dsi_host *msm_host) -{ - struct drm_display_mode *mode = msm_host->mode; - const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; - u8 lanes = msm_host->lanes; - u32 bpp = dsi_get_bpp(msm_host->format); - u32 pclk_rate; - - if (!mode) { - pr_err("%s: mode not set\n", __func__); - return -EINVAL; - } - - pclk_rate = mode->clock * 1000; - if (lanes > 0) { - msm_host->byte_clk_rate = (pclk_rate * bpp) / (8 * lanes); - } else { - pr_err("%s: forcing mdss_dsi lanes to 1\n", __func__); - msm_host->byte_clk_rate = (pclk_rate * bpp) / 8; - } - - DBG("pclk=%d, bclk=%d", pclk_rate, msm_host->byte_clk_rate); - - msm_host->esc_clk_rate = clk_get_rate(msm_host->esc_clk); - - if (cfg_hnd->major == MSM_DSI_VER_MAJOR_V2) { - unsigned int esc_mhz, esc_div; - unsigned long byte_mhz; - - msm_host->src_clk_rate = (pclk_rate * bpp) / 8; - - /* - * esc clock is byte clock followed by a 4 bit divider, - * we need to find an escape clock frequency within the - * mipi DSI spec range within the maximum divider limit - * We iterate here between an escape clock frequencey - * between 20 Mhz to 5 Mhz and pick up the first one - * that can be supported by our divider - */ - - byte_mhz = msm_host->byte_clk_rate / 1000000; - - for (esc_mhz = 20; esc_mhz >= 5; esc_mhz--) { - esc_div = DIV_ROUND_UP(byte_mhz, esc_mhz); - - /* - * TODO: Ideally, we shouldn't know what sort of divider - * is available in mmss_cc, we're just assuming that - * it'll always be a 4 bit divider. Need to come up with - * a better way here. - */ - if (esc_div >= 1 && esc_div <= 16) - break; - } - - if (esc_mhz < 5) - return -EINVAL; - - msm_host->esc_clk_rate = msm_host->byte_clk_rate / esc_div; - - DBG("esc=%d, src=%d", msm_host->esc_clk_rate, - msm_host->src_clk_rate); - } - - return 0; -} - static void dsi_intr_ctrl(struct msm_dsi_host *msm_host, u32 mask, int enable) { u32 intr; @@ -1193,54 +1062,6 @@ int dsi_tx_buf_alloc_v2(struct msm_dsi_host *msm_host, int size) return 0; } -/* dsi_cmd */ -static int dsi_tx_buf_alloc(struct msm_dsi_host *msm_host, int size) -{ - struct drm_device *dev = msm_host->dev; - struct msm_drm_private *priv = dev->dev_private; - const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; - int ret; - uint64_t iova; - - if (cfg_hnd->major == MSM_DSI_VER_MAJOR_6G) { - msm_host->tx_gem_obj = msm_gem_new(dev, size, MSM_BO_UNCACHED); - if (IS_ERR(msm_host->tx_gem_obj)) { - ret = PTR_ERR(msm_host->tx_gem_obj); - pr_err("%s: failed to allocate gem, %d\n", - __func__, ret); - msm_host->tx_gem_obj = NULL; - return ret; - } - - ret = msm_gem_get_iova(msm_host->tx_gem_obj, - priv->kms->aspace, &iova); - if (ret) { - pr_err("%s: failed to get iova, %d\n", __func__, ret); - return ret; - } - - if (iova & 0x07) { - pr_err("%s: buf NOT 8 bytes aligned\n", __func__); - return -EINVAL; - } - - msm_host->tx_size = msm_host->tx_gem_obj->size; - } else { - msm_host->tx_buf = dma_alloc_coherent(dev->dev, size, - &msm_host->tx_buf_paddr, GFP_KERNEL); - if (!msm_host->tx_buf) { - ret = -ENOMEM; - pr_err("%s: failed to allocate tx buf, %d\n", - __func__, ret); - return ret; - } - - msm_host->tx_size = size; - } - - return 0; -} - static void dsi_tx_buf_free(struct msm_dsi_host *msm_host) { struct drm_device *dev = msm_host->dev; @@ -1306,15 +1127,11 @@ static int dsi_cmd_dma_add(struct msm_dsi_host *msm_host, return -EINVAL; } - if (cfg_hnd->major == MSM_DSI_VER_MAJOR_6G) { - data = msm_gem_get_vaddr(msm_host->tx_gem_obj); - if (IS_ERR(data)) { - ret = PTR_ERR(data); - pr_err("%s: get vaddr failed, %d\n", __func__, ret); - return ret; - } - } else { - data = msm_host->tx_buf; + data = cfg_hnd->ops->tx_buf_get(msm_host); + if (IS_ERR(data)) { + ret = PTR_ERR(data); + pr_err("%s: get vaddr failed, %d\n", __func__, ret); + return ret; } /* MSM specific command format in memory */ @@ -1335,8 +1152,8 @@ static int dsi_cmd_dma_add(struct msm_dsi_host *msm_host, if (packet.size < len) memset(data + packet.size, 0xff, len - packet.size); - if (cfg_hnd->major == MSM_DSI_VER_MAJOR_6G) - msm_gem_put_vaddr(msm_host->tx_gem_obj); + if (cfg_hnd->ops->tx_buf_put) + cfg_hnd->ops->tx_buf_put(msm_host); return len; } @@ -1407,21 +1224,14 @@ int dsi_dma_base_get_v2(struct msm_dsi_host *msm_host, uint64_t *dma_base) static int dsi_cmd_dma_tx(struct msm_dsi_host *msm_host, int len) { const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; - struct drm_device *dev = msm_host->dev; - struct msm_drm_private *priv = dev->dev_private; int ret; uint64_t dma_base; bool triggered; - if (cfg_hnd->major == MSM_DSI_VER_MAJOR_6G) { - ret = msm_gem_get_iova(msm_host->tx_gem_obj, - priv->kms->aspace, &dma_base); - if (ret) { - pr_err("%s: failed to get iova: %d\n", __func__, ret); - return ret; - } - } else { - dma_base = msm_host->tx_buf_paddr; + ret = cfg_hnd->ops->dma_base_get(msm_host, &dma_base); + if (ret) { + pr_err("%s: failed to get iova: %d\n", __func__, ret); + return ret; } reinit_completion(&msm_host->dma_comp); @@ -2059,6 +1869,7 @@ int msm_dsi_host_modeset_init(struct mipi_dsi_host *host, struct drm_device *dev) { struct msm_dsi_host *msm_host = to_msm_dsi_host(host); + const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; struct platform_device *pdev = msm_host->pdev; int ret; @@ -2079,7 +1890,7 @@ int msm_dsi_host_modeset_init(struct mipi_dsi_host *host, } msm_host->dev = dev; - ret = dsi_tx_buf_alloc(msm_host, SZ_4K); + ret = cfg_hnd->ops->tx_buf_alloc(msm_host, SZ_4K); if (ret) { pr_err("%s: alloc tx gem obj failed, %d\n", __func__, ret); return ret; @@ -2137,6 +1948,7 @@ int msm_dsi_host_xfer_prepare(struct mipi_dsi_host *host, const struct mipi_dsi_msg *msg) { struct msm_dsi_host *msm_host = to_msm_dsi_host(host); + const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; /* TODO: make sure dsi_cmd_mdp is idle. * Since DSI6G v1.2.0, we can set DSI_TRIG_CTRL.BLOCK_DMA_WITHIN_FRAME @@ -2149,7 +1961,7 @@ int msm_dsi_host_xfer_prepare(struct mipi_dsi_host *host, * mdp clock need to be enabled to receive dsi interrupt */ pm_runtime_get_sync(&msm_host->pdev->dev); - dsi_link_clk_enable(msm_host); + cfg_hnd->ops->link_clk_enable(msm_host); /* TODO: vote for bus bandwidth */ @@ -2170,6 +1982,7 @@ void msm_dsi_host_xfer_restore(struct mipi_dsi_host *host, const struct mipi_dsi_msg *msg) { struct msm_dsi_host *msm_host = to_msm_dsi_host(host); + const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_CMD_DMA_DONE, 0); dsi_write(msm_host, REG_DSI_CTRL, msm_host->dma_cmd_ctrl_restore); @@ -2179,7 +1992,7 @@ void msm_dsi_host_xfer_restore(struct mipi_dsi_host *host, /* TODO: unvote for bus bandwidth */ - dsi_link_clk_disable(msm_host); + cfg_hnd->ops->link_clk_disable(msm_host); pm_runtime_put_autosuspend(&msm_host->pdev->dev); } @@ -2343,7 +2156,6 @@ int msm_dsi_host_set_src_pll(struct mipi_dsi_host *host, struct msm_dsi_pll *src_pll) { struct msm_dsi_host *msm_host = to_msm_dsi_host(host); - const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; struct clk *byte_clk_provider, *pixel_clk_provider; int ret; @@ -2369,14 +2181,16 @@ int msm_dsi_host_set_src_pll(struct mipi_dsi_host *host, goto exit; } - if (cfg_hnd->major == MSM_DSI_VER_MAJOR_V2) { + if (msm_host->dsi_clk_src) { ret = clk_set_parent(msm_host->dsi_clk_src, pixel_clk_provider); if (ret) { pr_err("%s: can't set parent to dsi_clk_src. ret=%d\n", __func__, ret); goto exit; } + } + if (msm_host->esc_clk_src) { ret = clk_set_parent(msm_host->esc_clk_src, byte_clk_provider); if (ret) { pr_err("%s: can't set parent to esc_clk_src. ret=%d\n", @@ -2406,9 +2220,10 @@ void msm_dsi_host_get_phy_clk_req(struct mipi_dsi_host *host, struct msm_dsi_phy_clk_request *clk_req) { struct msm_dsi_host *msm_host = to_msm_dsi_host(host); + const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; int ret; - ret = dsi_calc_clk_rate(msm_host); + ret = cfg_hnd->ops->calc_clk_rate(msm_host); if (ret) { pr_err("%s: unable to calc clk rate, %d\n", __func__, ret); return; @@ -2473,6 +2288,7 @@ int msm_dsi_host_power_on(struct mipi_dsi_host *host, struct msm_dsi_phy_shared_timings *phy_shared_timings) { struct msm_dsi_host *msm_host = to_msm_dsi_host(host); + const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; int ret = 0; mutex_lock(&msm_host->dev_mutex); @@ -2491,7 +2307,7 @@ int msm_dsi_host_power_on(struct mipi_dsi_host *host, } pm_runtime_get_sync(&msm_host->pdev->dev); - ret = dsi_link_clk_enable(msm_host); + ret = cfg_hnd->ops->link_clk_enable(msm_host); if (ret) { pr_err("%s: failed to enable link clocks. ret=%d\n", __func__, ret); @@ -2518,7 +2334,7 @@ int msm_dsi_host_power_on(struct mipi_dsi_host *host, return 0; fail_disable_clk: - dsi_link_clk_disable(msm_host); + cfg_hnd->ops->link_clk_disable(msm_host); pm_runtime_put_autosuspend(&msm_host->pdev->dev); fail_disable_reg: dsi_host_regulator_disable(msm_host); @@ -2530,6 +2346,7 @@ int msm_dsi_host_power_on(struct mipi_dsi_host *host, int msm_dsi_host_power_off(struct mipi_dsi_host *host) { struct msm_dsi_host *msm_host = to_msm_dsi_host(host); + const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; mutex_lock(&msm_host->dev_mutex); if (!msm_host->power_on) { @@ -2544,7 +2361,7 @@ int msm_dsi_host_power_off(struct mipi_dsi_host *host) pinctrl_pm_select_sleep_state(&msm_host->pdev->dev); - dsi_link_clk_disable(msm_host); + cfg_hnd->ops->link_clk_disable(msm_host); pm_runtime_put_autosuspend(&msm_host->pdev->dev); dsi_host_regulator_disable(msm_host); -- GitLab From 23f9455157f62e2fc7fbe7654717bcb70eee543d Mon Sep 17 00:00:00 2001 From: Carsten Behling <carsten.behling@googlemail.com> Date: Mon, 16 Jul 2018 19:49:56 +0200 Subject: [PATCH 1314/1506] drm/msm/mdp5: negative x/y in cursor move modesetting X11 driver may provide negative x/y cordinates in mdp5_crtc_cursor_move call when rotation is enabled. Cursor buffer can overlap down to its negative width/height. ROI has to be recalculated for negative x/y indicating using the lower/right corner of the cursor buffer and hotspot must be set in MDP5_LM_CURSOR_XY_SRC_Y MDP5_LM_CURSOR_XY_SRC_X. Signed-off-by: Carsten Behling <carsten.behling@gmail.com> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c | 51 +++++++++++++++++++---- 1 file changed, 43 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c index 24e00274844b9..b1da9ce543790 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c @@ -65,7 +65,7 @@ struct mdp5_crtc { struct drm_gem_object *scanout_bo; uint64_t iova; uint32_t width, height; - uint32_t x, y; + int x, y; } cursor; }; #define to_mdp5_crtc(x) container_of(x, struct mdp5_crtc, base) @@ -760,20 +760,31 @@ static void get_roi(struct drm_crtc *crtc, uint32_t *roi_w, uint32_t *roi_h) * Cursor Region Of Interest (ROI) is a plane read from cursor * buffer to render. The ROI region is determined by the visibility of * the cursor point. In the default Cursor image the cursor point will - * be at the top left of the cursor image, unless it is specified - * otherwise using hotspot feature. + * be at the top left of the cursor image. * + * Without rotation: * If the cursor point reaches the right (xres - x < cursor.width) or * bottom (yres - y < cursor.height) boundary of the screen, then ROI * width and ROI height need to be evaluated to crop the cursor image * accordingly. * (xres-x) will be new cursor width when x > (xres - cursor.width) * (yres-y) will be new cursor height when y > (yres - cursor.height) + * + * With rotation: + * We get negative x and/or y coordinates. + * (cursor.width - abs(x)) will be new cursor width when x < 0 + * (cursor.height - abs(y)) will be new cursor width when y < 0 */ - *roi_w = min(mdp5_crtc->cursor.width, xres - + if (mdp5_crtc->cursor.x >= 0) + *roi_w = min(mdp5_crtc->cursor.width, xres - mdp5_crtc->cursor.x); - *roi_h = min(mdp5_crtc->cursor.height, yres - + else + *roi_w = mdp5_crtc->cursor.width - abs(mdp5_crtc->cursor.x); + if (mdp5_crtc->cursor.y >= 0) + *roi_h = min(mdp5_crtc->cursor.height, yres - mdp5_crtc->cursor.y); + else + *roi_h = mdp5_crtc->cursor.height - abs(mdp5_crtc->cursor.y); } static void mdp5_crtc_restore_cursor(struct drm_crtc *crtc) @@ -783,7 +794,7 @@ static void mdp5_crtc_restore_cursor(struct drm_crtc *crtc) struct mdp5_kms *mdp5_kms = get_kms(crtc); const enum mdp5_cursor_alpha cur_alpha = CURSOR_ALPHA_PER_PIXEL; uint32_t blendcfg, stride; - uint32_t x, y, width, height; + uint32_t x, y, src_x, src_y, width, height; uint32_t roi_w, roi_h; int lm; @@ -800,6 +811,26 @@ static void mdp5_crtc_restore_cursor(struct drm_crtc *crtc) get_roi(crtc, &roi_w, &roi_h); + /* If cusror buffer overlaps due to rotation on the + * upper or left screen border the pixel offset inside + * the cursor buffer of the ROI is the positive overlap + * distance. + */ + if (mdp5_crtc->cursor.x < 0) { + src_x = abs(mdp5_crtc->cursor.x); + x = 0; + } else { + src_x = 0; + } + if (mdp5_crtc->cursor.y < 0) { + src_y = abs(mdp5_crtc->cursor.y); + y = 0; + } else { + src_y = 0; + } + DBG("%s: x=%d, y=%d roi_w=%d roi_h=%d src_x=%d src_y=%d", + crtc->name, x, y, roi_w, roi_h, src_x, src_y); + mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_STRIDE(lm), stride); mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_FORMAT(lm), MDP5_LM_CURSOR_FORMAT_FORMAT(CURSOR_FMT_ARGB8888)); @@ -812,6 +843,9 @@ static void mdp5_crtc_restore_cursor(struct drm_crtc *crtc) mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_START_XY(lm), MDP5_LM_CURSOR_START_XY_Y_START(y) | MDP5_LM_CURSOR_START_XY_X_START(x)); + mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_XY(lm), + MDP5_LM_CURSOR_XY_SRC_Y(src_y) | + MDP5_LM_CURSOR_XY_SRC_X(src_x)); mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_BASE_ADDR(lm), mdp5_crtc->cursor.iova); @@ -932,8 +966,9 @@ static int mdp5_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) if (unlikely(!crtc->state->enable)) return 0; - mdp5_crtc->cursor.x = x = max(x, 0); - mdp5_crtc->cursor.y = y = max(y, 0); + /* accept negative x/y coordinates up to maximum cursor overlap */ + mdp5_crtc->cursor.x = x = max(x, -(int)mdp5_crtc->cursor.width); + mdp5_crtc->cursor.y = y = max(y, -(int)mdp5_crtc->cursor.height); get_roi(crtc, &roi_w, &roi_h); -- GitLab From ea107a183be1d6e69448d7100121c479e24b7c1d Mon Sep 17 00:00:00 2001 From: vkorjani <vikas.korjani@intel.com> Date: Tue, 10 Apr 2018 10:12:45 -0400 Subject: [PATCH 1315/1506] drm: Add support for pps and compression mode command packet After enabling DSC we need to send compression mode command packet and pps data packet, for which 2 new data types are added 07h Compression Mode Data Type Write , short write, 2 parameters 0Ah PPS Long Write (word count determines number of bytes) This patch adds support to send these packets. Cc: David Airlie <airlied@linux.ie> Cc: Jean-Christophe Plagniol-Villard <plagnioj@jcrosoft.com> Cc: Tomi Valkeinen <tomi.valkeinen@ti.com> Cc: dri-devel@lists.freedesktop.org Cc: linux-kernel@vger.kernel.org Cc: linux-fbdev@vger.kernel.org Changes in v3: - None Signed-off-by: vkorjani <vikas.korjani@intel.com> [seanpaul removed pps_write_buffer fn, added types to packet_format helpers] Signed-off-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/drm_mipi_dsi.c | 2 ++ include/video/mipi_display.h | 3 +++ 2 files changed, 5 insertions(+) diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index bc73b7f5b9fcd..80b75501f5c6a 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -392,6 +392,7 @@ bool mipi_dsi_packet_format_is_short(u8 type) case MIPI_DSI_DCS_SHORT_WRITE: case MIPI_DSI_DCS_SHORT_WRITE_PARAM: case MIPI_DSI_DCS_READ: + case MIPI_DSI_DCS_COMPRESSION_MODE: case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE: return true; } @@ -410,6 +411,7 @@ EXPORT_SYMBOL(mipi_dsi_packet_format_is_short); bool mipi_dsi_packet_format_is_long(u8 type) { switch (type) { + case MIPI_DSI_PPS_LONG_WRITE: case MIPI_DSI_NULL_PACKET: case MIPI_DSI_BLANKING_PACKET: case MIPI_DSI_GENERIC_LONG_WRITE: diff --git a/include/video/mipi_display.h b/include/video/mipi_display.h index 19aa65a355461..49a53ef8da963 100644 --- a/include/video/mipi_display.h +++ b/include/video/mipi_display.h @@ -38,6 +38,9 @@ enum { MIPI_DSI_DCS_READ = 0x06, + MIPI_DSI_DCS_COMPRESSION_MODE = 0x07, + MIPI_DSI_PPS_LONG_WRITE = 0x0A, + MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE = 0x37, MIPI_DSI_END_OF_TRANSMISSION = 0x08, -- GitLab From f8a91d45553ab581964f40b1e46bdf3d0974d339 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Wed, 18 Jul 2018 13:58:16 +0200 Subject: [PATCH 1316/1506] drm/amdgpu: clean up coding style a bit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No need to bitcast a boolean and even if we should use "!!" instead. Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index 207f238649b47..053d31017c261 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -328,35 +328,35 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file case AMDGPU_HW_IP_GFX: type = AMD_IP_BLOCK_TYPE_GFX; for (i = 0; i < adev->gfx.num_gfx_rings; i++) - ring_mask |= ((adev->gfx.gfx_ring[i].ready ? 1 : 0) << i); + ring_mask |= adev->gfx.gfx_ring[i].ready << i; ib_start_alignment = 32; ib_size_alignment = 32; break; case AMDGPU_HW_IP_COMPUTE: type = AMD_IP_BLOCK_TYPE_GFX; for (i = 0; i < adev->gfx.num_compute_rings; i++) - ring_mask |= ((adev->gfx.compute_ring[i].ready ? 1 : 0) << i); + ring_mask |= adev->gfx.compute_ring[i].ready << i; ib_start_alignment = 32; ib_size_alignment = 32; break; case AMDGPU_HW_IP_DMA: type = AMD_IP_BLOCK_TYPE_SDMA; for (i = 0; i < adev->sdma.num_instances; i++) - ring_mask |= ((adev->sdma.instance[i].ring.ready ? 1 : 0) << i); + ring_mask |= adev->sdma.instance[i].ring.ready << i; ib_start_alignment = 256; ib_size_alignment = 4; break; case AMDGPU_HW_IP_UVD: type = AMD_IP_BLOCK_TYPE_UVD; for (i = 0; i < adev->uvd.num_uvd_inst; i++) - ring_mask |= ((adev->uvd.inst[i].ring.ready ? 1 : 0) << i); + ring_mask |= adev->uvd.inst[i].ring.ready << i; ib_start_alignment = 64; ib_size_alignment = 64; break; case AMDGPU_HW_IP_VCE: type = AMD_IP_BLOCK_TYPE_VCE; for (i = 0; i < adev->vce.num_rings; i++) - ring_mask |= ((adev->vce.ring[i].ready ? 1 : 0) << i); + ring_mask |= adev->vce.ring[i].ready << i; ib_start_alignment = 4; ib_size_alignment = 1; break; @@ -365,27 +365,27 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file for (i = 0; i < adev->uvd.num_uvd_inst; i++) for (j = 0; j < adev->uvd.num_enc_rings; j++) ring_mask |= - ((adev->uvd.inst[i].ring_enc[j].ready ? 1 : 0) << - (j + i * adev->uvd.num_enc_rings)); + adev->uvd.inst[i].ring_enc[j].ready << + (j + i * adev->uvd.num_enc_rings); ib_start_alignment = 64; ib_size_alignment = 64; break; case AMDGPU_HW_IP_VCN_DEC: type = AMD_IP_BLOCK_TYPE_VCN; - ring_mask = adev->vcn.ring_dec.ready ? 1 : 0; + ring_mask = adev->vcn.ring_dec.ready; ib_start_alignment = 16; ib_size_alignment = 16; break; case AMDGPU_HW_IP_VCN_ENC: type = AMD_IP_BLOCK_TYPE_VCN; for (i = 0; i < adev->vcn.num_enc_rings; i++) - ring_mask |= ((adev->vcn.ring_enc[i].ready ? 1 : 0) << i); + ring_mask |= adev->vcn.ring_enc[i].ready << i; ib_start_alignment = 64; ib_size_alignment = 1; break; case AMDGPU_HW_IP_VCN_JPEG: type = AMD_IP_BLOCK_TYPE_VCN; - ring_mask = adev->vcn.ring_jpeg.ready ? 1 : 0; + ring_mask = adev->vcn.ring_jpeg.ready; ib_start_alignment = 16; ib_size_alignment = 16; break; -- GitLab From 4d4831a3dae3161ab5a96694462eff708dfefc71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Wed, 18 Jul 2018 14:17:59 +0200 Subject: [PATCH 1317/1506] drm/amdgpu: expose only the first UVD instance for now MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Going to completely rework the context to ring mapping with Nayan's GSoC work, but for now just stopping to expose the second UVD instance should do it. Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 13 +++++-------- drivers/gpu/drm/amd/amdgpu/amdgpu_queue_mgr.c | 9 ++------- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index 053d31017c261..c7dce14fd47d5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -286,7 +286,7 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file struct drm_crtc *crtc; uint32_t ui32 = 0; uint64_t ui64 = 0; - int i, j, found; + int i, found; int ui32_size = sizeof(ui32); if (!info->return_size || !info->return_pointer) @@ -348,8 +348,7 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file break; case AMDGPU_HW_IP_UVD: type = AMD_IP_BLOCK_TYPE_UVD; - for (i = 0; i < adev->uvd.num_uvd_inst; i++) - ring_mask |= adev->uvd.inst[i].ring.ready << i; + ring_mask |= adev->uvd.inst[0].ring.ready; ib_start_alignment = 64; ib_size_alignment = 64; break; @@ -362,11 +361,9 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file break; case AMDGPU_HW_IP_UVD_ENC: type = AMD_IP_BLOCK_TYPE_UVD; - for (i = 0; i < adev->uvd.num_uvd_inst; i++) - for (j = 0; j < adev->uvd.num_enc_rings; j++) - ring_mask |= - adev->uvd.inst[i].ring_enc[j].ready << - (j + i * adev->uvd.num_enc_rings); + for (i = 0; i < adev->uvd.num_enc_rings; i++) + ring_mask |= + adev->uvd.inst[0].ring_enc[i].ready << i; ib_start_alignment = 64; ib_size_alignment = 64; break; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_queue_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_queue_mgr.c index ea9850c9224d6..d8357290ad099 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_queue_mgr.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_queue_mgr.c @@ -66,8 +66,6 @@ static int amdgpu_identity_map(struct amdgpu_device *adev, u32 ring, struct amdgpu_ring **out_ring) { - u32 instance; - switch (mapper->hw_ip) { case AMDGPU_HW_IP_GFX: *out_ring = &adev->gfx.gfx_ring[ring]; @@ -79,16 +77,13 @@ static int amdgpu_identity_map(struct amdgpu_device *adev, *out_ring = &adev->sdma.instance[ring].ring; break; case AMDGPU_HW_IP_UVD: - instance = ring; - *out_ring = &adev->uvd.inst[instance].ring; + *out_ring = &adev->uvd.inst[0].ring; break; case AMDGPU_HW_IP_VCE: *out_ring = &adev->vce.ring[ring]; break; case AMDGPU_HW_IP_UVD_ENC: - instance = ring / adev->uvd.num_enc_rings; - *out_ring = - &adev->uvd.inst[instance].ring_enc[ring%adev->uvd.num_enc_rings]; + *out_ring = &adev->uvd.inst[0].ring_enc[ring]; break; case AMDGPU_HW_IP_VCN_DEC: *out_ring = &adev->vcn.ring_dec; -- GitLab From 122b5a05987c8bcc0f88df2fdfa39397b6002737 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Wed, 18 Jul 2018 13:06:02 +0200 Subject: [PATCH 1318/1506] MAINTAINERS: add new TTM maintainers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Roger unfortunately doesn't work for AMD any longer. So add Rui and Jerry as co-maintainer as well. Signed-off-by: Christian König <christian.koenig@amd.com> Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- MAINTAINERS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 07d1576fc7660..646f40f8c691b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4883,7 +4883,8 @@ F: Documentation/gpu/xen-front.rst DRM TTM SUBSYSTEM M: Christian Koenig <christian.koenig@amd.com> -M: Roger He <Hongbo.He@amd.com> +M: Huang Rui <ray.huang@amd.com> +M: Junwei Zhang <Jerry.Zhang@amd.com> T: git git://people.freedesktop.org/~agd5f/linux S: Maintained L: dri-devel@lists.freedesktop.org -- GitLab From dbae59466f3737acbdecaa565faf3edb8c8c4f67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Wed, 18 Jul 2018 13:16:06 +0200 Subject: [PATCH 1319/1506] MAINTAINERS: Add separate section for DC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Note that Harry and Leo Li are maintainers for that stuff. Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Michel Dänzer <michel.daenzer@amd.com> Reviewed-by: Harry Wentland <harry.wentland@amd.com> Reviewed-by: Leo Li <sunpeng.li@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 646f40f8c691b..2ba4cf8f5eef6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -728,6 +728,14 @@ S: Supported F: drivers/crypto/ccp/ F: include/linux/ccp.h +AMD DISPLAY CORE +M: Harry Wentland <harry.wentland@amd.com> +M: Leo Li <sunpeng.li@amd.com> +L: amd-gfx@lists.freedesktop.org +T: git git://people.freedesktop.org/~agd5f/linux +S: Supported +F: drivers/gpu/drm/amd/display/ + AMD FAM15H PROCESSOR POWER MONITORING DRIVER M: Huang Rui <ray.huang@amd.com> L: linux-hwmon@vger.kernel.org -- GitLab From 6beccb15c447356c40972da825e0c1ed803cfb10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Thu, 19 Jul 2018 11:39:37 +0200 Subject: [PATCH 1320/1506] MAINTAINERS: add entry for AMD PP code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add separate entry for the power managent code on AMD GPUs. Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Rex Zhu <rezhu@amd.com> Reviewed-by: Evan Quan <evan.quan@amd.com> Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 2ba4cf8f5eef6..93f189f0d60d3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -785,6 +785,14 @@ F: drivers/gpu/drm/amd/include/vi_structs.h F: drivers/gpu/drm/amd/include/v9_structs.h F: include/uapi/linux/kfd_ioctl.h +AMD POWERPLAY +M: Rex Zhu <rex.zhu@amd.com> +M: Evan Quan <evan.quan@amd.com> +L: amd-gfx@lists.freedesktop.org +S: Supported +F: drivers/gpu/drm/amd/powerplay/ +T: git git://people.freedesktop.org/~agd5f/linux + AMD SEATTLE DEVICE TREE SUPPORT M: Brijesh Singh <brijeshkumar.singh@amd.com> M: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com> -- GitLab From c704ab18e0a26a5dc7e947af6e8e01585380518b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Mon, 16 Jul 2018 16:12:24 +0200 Subject: [PATCH 1321/1506] drm/amdgpu: consistenly name amdgpu_bo_ functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just rename functions, no functional change. Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 2 -- .../gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c | 8 ++--- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 10 +++--- drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 34 +++++++++---------- drivers/gpu/drm/amd/amdgpu/amdgpu_object.h | 3 ++ drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 10 +++--- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 4 +-- 10 files changed, 39 insertions(+), 38 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 44f62fda40228..0283e2b3c851a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1801,8 +1801,6 @@ void amdgpu_display_update_priority(struct amdgpu_device *adev); void amdgpu_cs_report_moved_bytes(struct amdgpu_device *adev, u64 num_bytes, u64 num_vis_bytes); -void amdgpu_ttm_placement_from_domain(struct amdgpu_bo *abo, u32 domain); -bool amdgpu_ttm_bo_is_amdgpu_bo(struct ttm_buffer_object *bo); void amdgpu_device_vram_location(struct amdgpu_device *adev, struct amdgpu_gmc *mc, u64 base); void amdgpu_device_gart_location(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index 079af8ac2636d..fa38a960ce004 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -334,7 +334,7 @@ static int amdgpu_amdkfd_bo_validate(struct amdgpu_bo *bo, uint32_t domain, "Called with userptr BO")) return -EINVAL; - amdgpu_ttm_placement_from_domain(bo, domain); + amdgpu_bo_placement_from_domain(bo, domain); ret = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); if (ret) @@ -622,7 +622,7 @@ static int init_user_pages(struct kgd_mem *mem, struct mm_struct *mm, pr_err("%s: Failed to reserve BO\n", __func__); goto release_out; } - amdgpu_ttm_placement_from_domain(bo, mem->domain); + amdgpu_bo_placement_from_domain(bo, mem->domain); ret = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); if (ret) pr_err("%s: failed to validate BO\n", __func__); @@ -1680,7 +1680,7 @@ static int update_invalid_user_pages(struct amdkfd_process_info *process_info, if (amdgpu_bo_reserve(bo, true)) return -EAGAIN; - amdgpu_ttm_placement_from_domain(bo, AMDGPU_GEM_DOMAIN_CPU); + amdgpu_bo_placement_from_domain(bo, AMDGPU_GEM_DOMAIN_CPU); ret = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); amdgpu_bo_unreserve(bo); if (ret) { @@ -1824,7 +1824,7 @@ static int validate_invalid_user_pages(struct amdkfd_process_info *process_info) if (mem->user_pages[0]) { amdgpu_ttm_tt_set_user_pages(bo->tbo.ttm, mem->user_pages); - amdgpu_ttm_placement_from_domain(bo, mem->domain); + amdgpu_bo_placement_from_domain(bo, mem->domain); ret = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); if (ret) { pr_err("%s: failed to validate BO\n", __func__); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 7c5cc33d0cda0..c5d81d6a90e04 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -419,7 +419,7 @@ static int amdgpu_cs_bo_validate(struct amdgpu_cs_parser *p, } retry: - amdgpu_ttm_placement_from_domain(bo, domain); + amdgpu_bo_placement_from_domain(bo, domain); r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); p->bytes_moved += ctx.bytes_moved; @@ -478,7 +478,7 @@ static bool amdgpu_cs_try_evict(struct amdgpu_cs_parser *p, update_bytes_moved_vis = !amdgpu_gmc_vram_full_visible(&adev->gmc) && amdgpu_bo_in_cpu_visible_vram(bo); - amdgpu_ttm_placement_from_domain(bo, other); + amdgpu_bo_placement_from_domain(bo, other); r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); p->bytes_moved += ctx.bytes_moved; if (update_bytes_moved_vis) @@ -532,8 +532,8 @@ static int amdgpu_cs_list_validate(struct amdgpu_cs_parser *p, /* Check if we have user pages and nobody bound the BO already */ if (amdgpu_ttm_tt_userptr_needs_pages(bo->tbo.ttm) && lobj->user_pages) { - amdgpu_ttm_placement_from_domain(bo, - AMDGPU_GEM_DOMAIN_CPU); + amdgpu_bo_placement_from_domain(bo, + AMDGPU_GEM_DOMAIN_CPU); r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); if (r) return r; @@ -1655,7 +1655,7 @@ int amdgpu_cs_find_mapping(struct amdgpu_cs_parser *parser, if (!((*bo)->flags & AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS)) { (*bo)->flags |= AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS; - amdgpu_ttm_placement_from_domain(*bo, (*bo)->allowed_domains); + amdgpu_bo_placement_from_domain(*bo, (*bo)->allowed_domains); r = ttm_bo_validate(&(*bo)->tbo, &(*bo)->placement, &ctx); if (r) return r; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index bcbdcf997d207..71792d820ae0c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -344,7 +344,7 @@ int amdgpu_gem_userptr_ioctl(struct drm_device *dev, void *data, if (r) goto free_pages; - amdgpu_ttm_placement_from_domain(bo, AMDGPU_GEM_DOMAIN_GTT); + amdgpu_bo_placement_from_domain(bo, AMDGPU_GEM_DOMAIN_GTT); r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); amdgpu_bo_unreserve(bo); if (r) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 3010f0136de9c..7b3398c337f13 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -51,7 +51,7 @@ * */ -static bool amdgpu_need_backup(struct amdgpu_device *adev) +static bool amdgpu_bo_need_backup(struct amdgpu_device *adev) { if (adev->flags & AMD_IS_APU) return false; @@ -84,7 +84,7 @@ static void amdgpu_bo_subtract_pin_size(struct amdgpu_bo *bo) } } -static void amdgpu_ttm_bo_destroy(struct ttm_buffer_object *tbo) +static void amdgpu_bo_destroy(struct ttm_buffer_object *tbo) { struct amdgpu_device *adev = amdgpu_ttm_adev(tbo->bdev); struct amdgpu_bo *bo = ttm_to_amdgpu_bo(tbo); @@ -111,7 +111,7 @@ static void amdgpu_ttm_bo_destroy(struct ttm_buffer_object *tbo) } /** - * amdgpu_ttm_bo_is_amdgpu_bo - check if the buffer object is an &amdgpu_bo + * amdgpu_bo_is_amdgpu_bo - check if the buffer object is an &amdgpu_bo * @bo: buffer object to be checked * * Uses destroy function associated with the object to determine if this is @@ -120,22 +120,22 @@ static void amdgpu_ttm_bo_destroy(struct ttm_buffer_object *tbo) * Returns: * true if the object belongs to &amdgpu_bo, false if not. */ -bool amdgpu_ttm_bo_is_amdgpu_bo(struct ttm_buffer_object *bo) +bool amdgpu_bo_is_amdgpu_bo(struct ttm_buffer_object *bo) { - if (bo->destroy == &amdgpu_ttm_bo_destroy) + if (bo->destroy == &amdgpu_bo_destroy) return true; return false; } /** - * amdgpu_ttm_placement_from_domain - set buffer's placement + * amdgpu_bo_placement_from_domain - set buffer's placement * @abo: &amdgpu_bo buffer object whose placement is to be set * @domain: requested domain * * Sets buffer's placement according to requested domain and the buffer's * flags. */ -void amdgpu_ttm_placement_from_domain(struct amdgpu_bo *abo, u32 domain) +void amdgpu_bo_placement_from_domain(struct amdgpu_bo *abo, u32 domain) { struct amdgpu_device *adev = amdgpu_ttm_adev(abo->tbo.bdev); struct ttm_placement *placement = &abo->placement; @@ -488,13 +488,13 @@ static int amdgpu_bo_do_create(struct amdgpu_device *adev, #endif bo->tbo.bdev = &adev->mman.bdev; - amdgpu_ttm_placement_from_domain(bo, bp->domain); + amdgpu_bo_placement_from_domain(bo, bp->domain); if (bp->type == ttm_bo_type_kernel) bo->tbo.priority = 1; r = ttm_bo_init_reserved(&adev->mman.bdev, &bo->tbo, size, bp->type, &bo->placement, page_align, &ctx, acc_size, - NULL, bp->resv, &amdgpu_ttm_bo_destroy); + NULL, bp->resv, &amdgpu_bo_destroy); if (unlikely(r != 0)) return r; @@ -594,7 +594,7 @@ int amdgpu_bo_create(struct amdgpu_device *adev, if (r) return r; - if ((flags & AMDGPU_GEM_CREATE_SHADOW) && amdgpu_need_backup(adev)) { + if ((flags & AMDGPU_GEM_CREATE_SHADOW) && amdgpu_bo_need_backup(adev)) { if (!bp->resv) WARN_ON(reservation_object_lock((*bo_ptr)->tbo.resv, NULL)); @@ -682,7 +682,7 @@ int amdgpu_bo_validate(struct amdgpu_bo *bo) domain = bo->preferred_domains; retry: - amdgpu_ttm_placement_from_domain(bo, domain); + amdgpu_bo_placement_from_domain(bo, domain); r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); if (unlikely(r == -ENOMEM) && domain != bo->allowed_domains) { domain = bo->allowed_domains; @@ -915,7 +915,7 @@ int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain, /* force to pin into visible video ram */ if (!(bo->flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS)) bo->flags |= AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED; - amdgpu_ttm_placement_from_domain(bo, domain); + amdgpu_bo_placement_from_domain(bo, domain); for (i = 0; i < bo->placement.num_placement; i++) { unsigned fpfn, lpfn; @@ -1246,7 +1246,7 @@ void amdgpu_bo_move_notify(struct ttm_buffer_object *bo, struct amdgpu_bo *abo; struct ttm_mem_reg *old_mem = &bo->mem; - if (!amdgpu_ttm_bo_is_amdgpu_bo(bo)) + if (!amdgpu_bo_is_amdgpu_bo(bo)) return; abo = ttm_to_amdgpu_bo(bo); @@ -1263,7 +1263,7 @@ void amdgpu_bo_move_notify(struct ttm_buffer_object *bo, return; /* move_notify is called before move happens */ - trace_amdgpu_ttm_bo_move(abo, new_mem->mem_type, old_mem->mem_type); + trace_amdgpu_bo_move(abo, new_mem->mem_type, old_mem->mem_type); } /** @@ -1285,7 +1285,7 @@ int amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo) unsigned long offset, size; int r; - if (!amdgpu_ttm_bo_is_amdgpu_bo(bo)) + if (!amdgpu_bo_is_amdgpu_bo(bo)) return 0; abo = ttm_to_amdgpu_bo(bo); @@ -1307,8 +1307,8 @@ int amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo) /* hurrah the memory is not visible ! */ atomic64_inc(&adev->num_vram_cpu_page_faults); - amdgpu_ttm_placement_from_domain(abo, AMDGPU_GEM_DOMAIN_VRAM | - AMDGPU_GEM_DOMAIN_GTT); + amdgpu_bo_placement_from_domain(abo, AMDGPU_GEM_DOMAIN_VRAM | + AMDGPU_GEM_DOMAIN_GTT); /* Avoid costly evictions; only set GTT as a busy placement */ abo->placement.num_busy_placement = 1; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h index 9c3e29a04eb18..345fcd1769923 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h @@ -234,6 +234,9 @@ static inline bool amdgpu_bo_explicit_sync(struct amdgpu_bo *bo) return bo->flags & AMDGPU_GEM_CREATE_EXPLICIT_SYNC; } +bool amdgpu_bo_is_amdgpu_bo(struct ttm_buffer_object *bo); +void amdgpu_bo_placement_from_domain(struct amdgpu_bo *abo, u32 domain); + int amdgpu_bo_create(struct amdgpu_device *adev, struct amdgpu_bo_param *bp, struct amdgpu_bo **bo_ptr); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c index 3ed02f4720035..1c5d97f4b4dde 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_prime.c @@ -323,7 +323,7 @@ static int amdgpu_gem_begin_cpu_access(struct dma_buf *dma_buf, return ret; if (!bo->pin_count && (bo->allowed_domains & AMDGPU_GEM_DOMAIN_GTT)) { - amdgpu_ttm_placement_from_domain(bo, AMDGPU_GEM_DOMAIN_GTT); + amdgpu_bo_placement_from_domain(bo, AMDGPU_GEM_DOMAIN_GTT); ret = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h index 76920035eb22d..11f262f152007 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h @@ -436,7 +436,7 @@ TRACE_EVENT(amdgpu_cs_bo_status, __entry->total_bo, __entry->total_size) ); -TRACE_EVENT(amdgpu_ttm_bo_move, +TRACE_EVENT(amdgpu_bo_move, TP_PROTO(struct amdgpu_bo* bo, uint32_t new_placement, uint32_t old_placement), TP_ARGS(bo, new_placement, old_placement), TP_STRUCT__entry( diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 8ed102933ca23..6039f8e213580 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -248,7 +248,7 @@ static void amdgpu_evict_flags(struct ttm_buffer_object *bo, } /* Object isn't an AMDGPU object so ignore */ - if (!amdgpu_ttm_bo_is_amdgpu_bo(bo)) { + if (!amdgpu_bo_is_amdgpu_bo(bo)) { placement->placement = &placements; placement->busy_placement = &placements; placement->num_placement = 1; @@ -261,7 +261,7 @@ static void amdgpu_evict_flags(struct ttm_buffer_object *bo, case TTM_PL_VRAM: if (!adev->mman.buffer_funcs_enabled) { /* Move to system memory */ - amdgpu_ttm_placement_from_domain(abo, AMDGPU_GEM_DOMAIN_CPU); + amdgpu_bo_placement_from_domain(abo, AMDGPU_GEM_DOMAIN_CPU); } else if (!amdgpu_gmc_vram_full_visible(&adev->gmc) && !(abo->flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED) && amdgpu_bo_in_cpu_visible_vram(abo)) { @@ -271,7 +271,7 @@ static void amdgpu_evict_flags(struct ttm_buffer_object *bo, * BO will be evicted to GTT rather than causing other * BOs to be evicted from VRAM */ - amdgpu_ttm_placement_from_domain(abo, AMDGPU_GEM_DOMAIN_VRAM | + amdgpu_bo_placement_from_domain(abo, AMDGPU_GEM_DOMAIN_VRAM | AMDGPU_GEM_DOMAIN_GTT); abo->placements[0].fpfn = adev->gmc.visible_vram_size >> PAGE_SHIFT; abo->placements[0].lpfn = 0; @@ -279,12 +279,12 @@ static void amdgpu_evict_flags(struct ttm_buffer_object *bo, abo->placement.num_busy_placement = 1; } else { /* Move to GTT memory */ - amdgpu_ttm_placement_from_domain(abo, AMDGPU_GEM_DOMAIN_GTT); + amdgpu_bo_placement_from_domain(abo, AMDGPU_GEM_DOMAIN_GTT); } break; case TTM_PL_TT: default: - amdgpu_ttm_placement_from_domain(abo, AMDGPU_GEM_DOMAIN_CPU); + amdgpu_bo_placement_from_domain(abo, AMDGPU_GEM_DOMAIN_CPU); } *placement = abo->placement; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c index 80b5c453f8c11..e1e4810b9d9e4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c @@ -473,7 +473,7 @@ static int amdgpu_uvd_cs_pass1(struct amdgpu_uvd_cs_ctx *ctx) if (cmd == 0x0 || cmd == 0x3) { /* yes, force it into VRAM */ uint32_t domain = AMDGPU_GEM_DOMAIN_VRAM; - amdgpu_ttm_placement_from_domain(bo, domain); + amdgpu_bo_placement_from_domain(bo, domain); } amdgpu_uvd_force_into_uvd_segment(bo); @@ -1014,7 +1014,7 @@ static int amdgpu_uvd_send_msg(struct amdgpu_ring *ring, struct amdgpu_bo *bo, if (!ring->adev->uvd.address_64_bit) { struct ttm_operation_ctx ctx = { true, false }; - amdgpu_ttm_placement_from_domain(bo, AMDGPU_GEM_DOMAIN_VRAM); + amdgpu_bo_placement_from_domain(bo, AMDGPU_GEM_DOMAIN_VRAM); amdgpu_uvd_force_into_uvd_segment(bo); r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); if (r) -- GitLab From bf314ca3f10d4ba4335808dc678631908881db8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Wed, 18 Jul 2018 11:16:35 +0200 Subject: [PATCH 1322/1506] drm/amdgpu: reduce the number of placements for a BO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make struct amdgpu_bo a bit smaller. Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 2 ++ drivers/gpu/drm/amd/amdgpu/amdgpu_object.h | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 7b3398c337f13..21bfa2d8039e0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -216,6 +216,8 @@ void amdgpu_bo_placement_from_domain(struct amdgpu_bo *abo, u32 domain) c++; } + BUG_ON(c >= AMDGPU_BO_MAX_PLACEMENTS); + placement->num_placement = c; placement->placement = places; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h index 345fcd1769923..18945dd6982db 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h @@ -32,6 +32,7 @@ #include "amdgpu.h" #define AMDGPU_BO_INVALID_OFFSET LONG_MAX +#define AMDGPU_BO_MAX_PLACEMENTS 3 struct amdgpu_bo_param { unsigned long size; @@ -77,7 +78,7 @@ struct amdgpu_bo { /* Protected by tbo.reserved */ u32 preferred_domains; u32 allowed_domains; - struct ttm_place placements[AMDGPU_GEM_DOMAIN_MAX + 1]; + struct ttm_place placements[AMDGPU_BO_MAX_PLACEMENTS]; struct ttm_placement placement; struct ttm_buffer_object tbo; struct ttm_bo_kmap_obj kmap; -- GitLab From cdc50176597cb44ce25eb7331c450058775b8d2a Mon Sep 17 00:00:00 2001 From: Nayan Deshmukh <nayan26deshmukh@gmail.com> Date: Fri, 20 Jul 2018 17:51:05 +0530 Subject: [PATCH 1323/1506] drm/scheduler: modify API to avoid redundancy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit entity has a scheduler field and we don't need the sched argument in any of the functions where entity is provided. Signed-off-by: Nayan Deshmukh <nayan26deshmukh@gmail.com> Reviewed-by: Christian König <christian.koenig@amd.com> Reviewed-by: Eric Anholt <eric@anholt.net> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c | 13 +++++-------- drivers/gpu/drm/amd/amdgpu/amdgpu_job.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 3 +-- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 3 +-- drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 4 ++-- drivers/gpu/drm/etnaviv/etnaviv_drv.c | 3 +-- drivers/gpu/drm/etnaviv/etnaviv_sched.c | 4 ++-- drivers/gpu/drm/scheduler/gpu_scheduler.c | 20 +++++++++++--------- drivers/gpu/drm/v3d/v3d_drv.c | 4 +--- drivers/gpu/drm/v3d/v3d_gem.c | 2 -- include/drm/gpu_scheduler.h | 10 +++------- 13 files changed, 30 insertions(+), 42 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index c5d81d6a90e04..4d4575b3bba7a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -1232,7 +1232,7 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, job = p->job; p->job = NULL; - r = drm_sched_job_init(&job->base, &ring->sched, entity, p->filp); + r = drm_sched_job_init(&job->base, entity, p->filp); if (r) { amdgpu_job_free(job); amdgpu_mn_unlock(p->mn); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c index 83e3b320a7938..df69657610460 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c @@ -104,8 +104,7 @@ static int amdgpu_ctx_init(struct amdgpu_device *adev, failed: for (j = 0; j < i; j++) - drm_sched_entity_destroy(&adev->rings[j]->sched, - &ctx->rings[j].entity); + drm_sched_entity_destroy(&ctx->rings[j].entity); kfree(ctx->fences); ctx->fences = NULL; return r; @@ -178,8 +177,7 @@ static void amdgpu_ctx_do_release(struct kref *ref) if (ctx->adev->rings[i] == &ctx->adev->gfx.kiq.ring) continue; - drm_sched_entity_destroy(&ctx->adev->rings[i]->sched, - &ctx->rings[i].entity); + drm_sched_entity_destroy(&ctx->rings[i].entity); } amdgpu_ctx_fini(ref); @@ -466,8 +464,8 @@ void amdgpu_ctx_mgr_entity_flush(struct amdgpu_ctx_mgr *mgr) if (ctx->adev->rings[i] == &ctx->adev->gfx.kiq.ring) continue; - max_wait = drm_sched_entity_flush(&ctx->adev->rings[i]->sched, - &ctx->rings[i].entity, max_wait); + max_wait = drm_sched_entity_flush(&ctx->rings[i].entity, + max_wait); } } mutex_unlock(&mgr->lock); @@ -492,8 +490,7 @@ void amdgpu_ctx_mgr_entity_fini(struct amdgpu_ctx_mgr *mgr) continue; if (kref_read(&ctx->refcount) == 1) - drm_sched_entity_fini(&ctx->adev->rings[i]->sched, - &ctx->rings[i].entity); + drm_sched_entity_fini(&ctx->rings[i].entity); else DRM_ERROR("ctx %p is still alive\n", ctx); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c index 5a2c26a859845..631481a730e0b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c @@ -133,7 +133,7 @@ int amdgpu_job_submit(struct amdgpu_job *job, struct drm_sched_entity *entity, if (!f) return -EINVAL; - r = drm_sched_job_init(&job->base, entity->sched, entity, owner); + r = drm_sched_job_init(&job->base, entity, owner); if (r) return r; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 6039f8e213580..8c4358e36c871 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -1925,8 +1925,7 @@ void amdgpu_ttm_set_buffer_funcs_status(struct amdgpu_device *adev, bool enable) return; } } else { - drm_sched_entity_destroy(adev->mman.entity.sched, - &adev->mman.entity); + drm_sched_entity_destroy(&adev->mman.entity); dma_fence_put(man->move); man->move = NULL; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c index e1e4810b9d9e4..fca86d71fafce 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c @@ -305,8 +305,7 @@ int amdgpu_uvd_sw_fini(struct amdgpu_device *adev) { int i, j; - drm_sched_entity_destroy(&adev->uvd.inst->ring.sched, - &adev->uvd.entity); + drm_sched_entity_destroy(&adev->uvd.entity); for (j = 0; j < adev->uvd.num_uvd_inst; ++j) { kfree(adev->uvd.inst[j].saved_bo); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c index 86182c966ed6f..b6ab4f5350c80 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c @@ -221,7 +221,7 @@ int amdgpu_vce_sw_fini(struct amdgpu_device *adev) if (adev->vce.vcpu_bo == NULL) return 0; - drm_sched_entity_destroy(&adev->vce.ring[0].sched, &adev->vce.entity); + drm_sched_entity_destroy(&adev->vce.entity); amdgpu_bo_free_kernel(&adev->vce.vcpu_bo, &adev->vce.gpu_addr, (void **)&adev->vce.cpu_addr); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 098dd1ba751a2..74b4a28a41d6a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -2642,7 +2642,7 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm, vm->root.base.bo = NULL; error_free_sched_entity: - drm_sched_entity_destroy(&ring->sched, &vm->entity); + drm_sched_entity_destroy(&vm->entity); return r; } @@ -2779,7 +2779,7 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm) spin_unlock_irqrestore(&adev->vm_manager.pasid_lock, flags); } - drm_sched_entity_destroy(vm->entity.sched, &vm->entity); + drm_sched_entity_destroy(&vm->entity); if (!RB_EMPTY_ROOT(&vm->va.rb_root)) { dev_err(adev->dev, "still active bo inside vm\n"); diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c index 36414ba56b226..207532c05eb86 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c @@ -78,8 +78,7 @@ static void etnaviv_postclose(struct drm_device *dev, struct drm_file *file) gpu->lastctx = NULL; mutex_unlock(&gpu->lock); - drm_sched_entity_destroy(&gpu->sched, - &ctx->sched_entity[i]); + drm_sched_entity_destroy(&ctx->sched_entity[i]); } } diff --git a/drivers/gpu/drm/etnaviv/etnaviv_sched.c b/drivers/gpu/drm/etnaviv/etnaviv_sched.c index a74eb57af15bc..590e44b0d9639 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_sched.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_sched.c @@ -118,8 +118,8 @@ int etnaviv_sched_push_job(struct drm_sched_entity *sched_entity, { int ret; - ret = drm_sched_job_init(&submit->sched_job, &submit->gpu->sched, - sched_entity, submit->cmdbuf.ctx); + ret = drm_sched_job_init(&submit->sched_job, sched_entity, + submit->cmdbuf.ctx); if (ret) return ret; diff --git a/drivers/gpu/drm/scheduler/gpu_scheduler.c b/drivers/gpu/drm/scheduler/gpu_scheduler.c index dac71e3b4514c..a3b55c5420256 100644 --- a/drivers/gpu/drm/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/scheduler/gpu_scheduler.c @@ -273,11 +273,12 @@ static void drm_sched_entity_kill_jobs_cb(struct dma_fence *f, * * Returns the remaining time in jiffies left from the input timeout */ -long drm_sched_entity_flush(struct drm_gpu_scheduler *sched, - struct drm_sched_entity *entity, long timeout) +long drm_sched_entity_flush(struct drm_sched_entity *entity, long timeout) { + struct drm_gpu_scheduler *sched; long ret = timeout; + sched = entity->sched; if (!drm_sched_entity_is_initialized(sched, entity)) return ret; /** @@ -312,10 +313,11 @@ EXPORT_SYMBOL(drm_sched_entity_flush); * entity and signals all jobs with an error code if the process was killed. * */ -void drm_sched_entity_fini(struct drm_gpu_scheduler *sched, - struct drm_sched_entity *entity) +void drm_sched_entity_fini(struct drm_sched_entity *entity) { + struct drm_gpu_scheduler *sched; + sched = entity->sched; drm_sched_entity_set_rq(entity, NULL); /* Consumption of existing IBs wasn't completed. Forcefully @@ -373,11 +375,10 @@ EXPORT_SYMBOL(drm_sched_entity_fini); * * Calls drm_sched_entity_do_release() and drm_sched_entity_cleanup() */ -void drm_sched_entity_destroy(struct drm_gpu_scheduler *sched, - struct drm_sched_entity *entity) +void drm_sched_entity_destroy(struct drm_sched_entity *entity) { - drm_sched_entity_flush(sched, entity, MAX_WAIT_SCHED_ENTITY_Q_EMPTY); - drm_sched_entity_fini(sched, entity); + drm_sched_entity_flush(entity, MAX_WAIT_SCHED_ENTITY_Q_EMPTY); + drm_sched_entity_fini(entity); } EXPORT_SYMBOL(drm_sched_entity_destroy); @@ -740,10 +741,11 @@ EXPORT_SYMBOL(drm_sched_job_recovery); * Returns 0 for success, negative error code otherwise. */ int drm_sched_job_init(struct drm_sched_job *job, - struct drm_gpu_scheduler *sched, struct drm_sched_entity *entity, void *owner) { + struct drm_gpu_scheduler *sched = entity->sched; + job->sched = sched; job->entity = entity; job->s_priority = entity->rq - sched->sched_rq; diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c index 1dceba2b42fd6..2a85fa68ffea5 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.c +++ b/drivers/gpu/drm/v3d/v3d_drv.c @@ -145,13 +145,11 @@ v3d_open(struct drm_device *dev, struct drm_file *file) static void v3d_postclose(struct drm_device *dev, struct drm_file *file) { - struct v3d_dev *v3d = to_v3d_dev(dev); struct v3d_file_priv *v3d_priv = file->driver_priv; enum v3d_queue q; for (q = 0; q < V3D_MAX_QUEUES; q++) { - drm_sched_entity_destroy(&v3d->queue[q].sched, - &v3d_priv->sched_entity[q]); + drm_sched_entity_destroy(&v3d_priv->sched_entity[q]); } kfree(v3d_priv); diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c index e1fcbb4cd0aeb..5ce24098a5fda 100644 --- a/drivers/gpu/drm/v3d/v3d_gem.c +++ b/drivers/gpu/drm/v3d/v3d_gem.c @@ -553,7 +553,6 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data, mutex_lock(&v3d->sched_lock); if (exec->bin.start != exec->bin.end) { ret = drm_sched_job_init(&exec->bin.base, - &v3d->queue[V3D_BIN].sched, &v3d_priv->sched_entity[V3D_BIN], v3d_priv); if (ret) @@ -568,7 +567,6 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data, } ret = drm_sched_job_init(&exec->render.base, - &v3d->queue[V3D_RENDER].sched, &v3d_priv->sched_entity[V3D_RENDER], v3d_priv); if (ret) diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h index 2205e89722f6b..728346abcc81d 100644 --- a/include/drm/gpu_scheduler.h +++ b/include/drm/gpu_scheduler.h @@ -286,12 +286,9 @@ int drm_sched_entity_init(struct drm_sched_entity *entity, struct drm_sched_rq **rq_list, unsigned int num_rq_list, atomic_t *guilty); -long drm_sched_entity_flush(struct drm_gpu_scheduler *sched, - struct drm_sched_entity *entity, long timeout); -void drm_sched_entity_fini(struct drm_gpu_scheduler *sched, - struct drm_sched_entity *entity); -void drm_sched_entity_destroy(struct drm_gpu_scheduler *sched, - struct drm_sched_entity *entity); +long drm_sched_entity_flush(struct drm_sched_entity *entity, long timeout); +void drm_sched_entity_fini(struct drm_sched_entity *entity); +void drm_sched_entity_destroy(struct drm_sched_entity *entity); void drm_sched_entity_push_job(struct drm_sched_job *sched_job, struct drm_sched_entity *entity); void drm_sched_entity_set_rq(struct drm_sched_entity *entity, @@ -302,7 +299,6 @@ struct drm_sched_fence *drm_sched_fence_create( void drm_sched_fence_scheduled(struct drm_sched_fence *fence); void drm_sched_fence_finished(struct drm_sched_fence *fence); int drm_sched_job_init(struct drm_sched_job *job, - struct drm_gpu_scheduler *sched, struct drm_sched_entity *entity, void *owner); void drm_sched_hw_job_reset(struct drm_gpu_scheduler *sched, -- GitLab From 068c330419ffb3422a43cb7d34351f1ef033950f Mon Sep 17 00:00:00 2001 From: Nayan Deshmukh <nayan26deshmukh@gmail.com> Date: Fri, 20 Jul 2018 17:51:06 +0530 Subject: [PATCH 1324/1506] drm/scheduler: remove sched field from the entity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The scheduler of the entity is decided by the run queue on which it is queued. This patch avoids us the effort required to maintain a sync between rq and sched field when we start shifting entites among different rqs. Signed-off-by: Nayan Deshmukh <nayan26deshmukh@gmail.com> Reviewed-by: Christian König <christian.koenig@amd.com> Reviewed-by: Eric Anholt <eric@anholt.net> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_job.c | 4 ++-- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 6 +++--- drivers/gpu/drm/scheduler/gpu_scheduler.c | 19 +++++++++---------- drivers/gpu/drm/scheduler/sched_fence.c | 2 +- include/drm/gpu_scheduler.h | 2 -- 6 files changed, 16 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 4d4575b3bba7a..178d9ce4eba1f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -1262,7 +1262,7 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, priority = job->base.s_priority; drm_sched_entity_push_job(&job->base, entity); - ring = to_amdgpu_ring(entity->sched); + ring = to_amdgpu_ring(entity->rq->sched); amdgpu_ring_priority_get(ring, priority); ttm_eu_fence_buffer_objects(&p->ticket, &p->validated, p->fence); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c index 631481a730e0b..391e2f7c03aac 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c @@ -143,7 +143,7 @@ int amdgpu_job_submit(struct amdgpu_job *job, struct drm_sched_entity *entity, priority = job->base.s_priority; drm_sched_entity_push_job(&job->base, entity); - ring = to_amdgpu_ring(entity->sched); + ring = to_amdgpu_ring(entity->rq->sched); amdgpu_ring_priority_get(ring, priority); return 0; @@ -167,7 +167,7 @@ int amdgpu_job_submit_direct(struct amdgpu_job *job, struct amdgpu_ring *ring, static struct dma_fence *amdgpu_job_dependency(struct drm_sched_job *sched_job, struct drm_sched_entity *s_entity) { - struct amdgpu_ring *ring = to_amdgpu_ring(s_entity->sched); + struct amdgpu_ring *ring = to_amdgpu_ring(s_entity->rq->sched); struct amdgpu_job *job = to_amdgpu_job(sched_job); struct amdgpu_vm *vm = job->vm; struct dma_fence *fence; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 74b4a28a41d6a..5d7d7900ccabb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -387,7 +387,7 @@ static int amdgpu_vm_clear_bo(struct amdgpu_device *adev, ats_entries = 0; } - ring = container_of(vm->entity.sched, struct amdgpu_ring, sched); + ring = container_of(vm->entity.rq->sched, struct amdgpu_ring, sched); r = reservation_object_reserve_shared(bo->tbo.resv); if (r) @@ -1113,7 +1113,7 @@ int amdgpu_vm_update_directories(struct amdgpu_device *adev, struct amdgpu_ring *ring; struct dma_fence *fence; - ring = container_of(vm->entity.sched, struct amdgpu_ring, + ring = container_of(vm->entity.rq->sched, struct amdgpu_ring, sched); amdgpu_ring_pad_ib(ring, params.ib); @@ -1403,7 +1403,7 @@ static int amdgpu_vm_bo_update_mapping(struct amdgpu_device *adev, addr, flags); } - ring = container_of(vm->entity.sched, struct amdgpu_ring, sched); + ring = container_of(vm->entity.rq->sched, struct amdgpu_ring, sched); nptes = last - start + 1; diff --git a/drivers/gpu/drm/scheduler/gpu_scheduler.c b/drivers/gpu/drm/scheduler/gpu_scheduler.c index a3b55c5420256..3f2fc5e8242ab 100644 --- a/drivers/gpu/drm/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/scheduler/gpu_scheduler.c @@ -185,7 +185,6 @@ int drm_sched_entity_init(struct drm_sched_entity *entity, memset(entity, 0, sizeof(struct drm_sched_entity)); INIT_LIST_HEAD(&entity->list); entity->rq = rq_list[0]; - entity->sched = rq_list[0]->sched; entity->guilty = guilty; entity->last_scheduled = NULL; @@ -210,8 +209,8 @@ EXPORT_SYMBOL(drm_sched_entity_init); static bool drm_sched_entity_is_initialized(struct drm_gpu_scheduler *sched, struct drm_sched_entity *entity) { - return entity->sched == sched && - entity->rq != NULL; + return entity->rq != NULL && + entity->rq->sched == sched; } /** @@ -278,7 +277,7 @@ long drm_sched_entity_flush(struct drm_sched_entity *entity, long timeout) struct drm_gpu_scheduler *sched; long ret = timeout; - sched = entity->sched; + sched = entity->rq->sched; if (!drm_sched_entity_is_initialized(sched, entity)) return ret; /** @@ -317,7 +316,7 @@ void drm_sched_entity_fini(struct drm_sched_entity *entity) { struct drm_gpu_scheduler *sched; - sched = entity->sched; + sched = entity->rq->sched; drm_sched_entity_set_rq(entity, NULL); /* Consumption of existing IBs wasn't completed. Forcefully @@ -388,7 +387,7 @@ static void drm_sched_entity_wakeup(struct dma_fence *f, struct dma_fence_cb *cb container_of(cb, struct drm_sched_entity, cb); entity->dependency = NULL; dma_fence_put(f); - drm_sched_wakeup(entity->sched); + drm_sched_wakeup(entity->rq->sched); } static void drm_sched_entity_clear_dep(struct dma_fence *f, struct dma_fence_cb *cb) @@ -438,7 +437,7 @@ EXPORT_SYMBOL(drm_sched_entity_set_rq); bool drm_sched_dependency_optimized(struct dma_fence* fence, struct drm_sched_entity *entity) { - struct drm_gpu_scheduler *sched = entity->sched; + struct drm_gpu_scheduler *sched = entity->rq->sched; struct drm_sched_fence *s_fence; if (!fence || dma_fence_is_signaled(fence)) @@ -455,7 +454,7 @@ EXPORT_SYMBOL(drm_sched_dependency_optimized); static bool drm_sched_entity_add_dependency_cb(struct drm_sched_entity *entity) { - struct drm_gpu_scheduler *sched = entity->sched; + struct drm_gpu_scheduler *sched = entity->rq->sched; struct dma_fence * fence = entity->dependency; struct drm_sched_fence *s_fence; @@ -500,7 +499,7 @@ static bool drm_sched_entity_add_dependency_cb(struct drm_sched_entity *entity) static struct drm_sched_job * drm_sched_entity_pop_job(struct drm_sched_entity *entity) { - struct drm_gpu_scheduler *sched = entity->sched; + struct drm_gpu_scheduler *sched = entity->rq->sched; struct drm_sched_job *sched_job = to_drm_sched_job( spsc_queue_peek(&entity->job_queue)); @@ -744,7 +743,7 @@ int drm_sched_job_init(struct drm_sched_job *job, struct drm_sched_entity *entity, void *owner) { - struct drm_gpu_scheduler *sched = entity->sched; + struct drm_gpu_scheduler *sched = entity->rq->sched; job->sched = sched; job->entity = entity; diff --git a/drivers/gpu/drm/scheduler/sched_fence.c b/drivers/gpu/drm/scheduler/sched_fence.c index 45d9c3affbeac..d8d2dff9ea2f7 100644 --- a/drivers/gpu/drm/scheduler/sched_fence.c +++ b/drivers/gpu/drm/scheduler/sched_fence.c @@ -161,7 +161,7 @@ struct drm_sched_fence *drm_sched_fence_create(struct drm_sched_entity *entity, return NULL; fence->owner = owner; - fence->sched = entity->sched; + fence->sched = entity->rq->sched; spin_lock_init(&fence->lock); seq = atomic_inc_return(&entity->fence_seq); diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h index 728346abcc81d..091b9afcd184c 100644 --- a/include/drm/gpu_scheduler.h +++ b/include/drm/gpu_scheduler.h @@ -52,7 +52,6 @@ enum drm_sched_priority { * runqueue. * @rq: runqueue to which this entity belongs. * @rq_lock: lock to modify the runqueue to which this entity belongs. - * @sched: the scheduler instance to which this entity is enqueued. * @job_queue: the list of jobs of this entity. * @fence_seq: a linearly increasing seqno incremented with each * new &drm_sched_fence which is part of the entity. @@ -76,7 +75,6 @@ struct drm_sched_entity { struct list_head list; struct drm_sched_rq *rq; spinlock_t rq_lock; - struct drm_gpu_scheduler *sched; struct spsc_queue job_queue; -- GitLab From 6cdf4e87b454d1f26ef557307345dadce71d1f94 Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexander.deucher@amd.com> Date: Tue, 24 Jul 2018 11:52:58 -0500 Subject: [PATCH 1325/1506] drm/amdgpu/gmc9: clarify GPUVM fault error message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The address printed is the actual address, not the page. Reviewed-by: Junwei Zhang <Jerry.Zhang@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c index 9df94b45d17de..399a5db276497 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c @@ -269,7 +269,7 @@ static int gmc_v9_0_process_interrupt(struct amdgpu_device *adev, entry->src_id, entry->ring_id, entry->vmid, entry->pasid, task_info.process_name, task_info.tgid, task_info.task_name, task_info.pid); - dev_err(adev->dev, " at page 0x%016llx from %d\n", + dev_err(adev->dev, " at address 0x%016llx from %d\n", addr, entry->client_id); if (!amdgpu_sriov_vf(adev)) dev_err(adev->dev, -- GitLab From 586092ab4b768b01b3184d9a2541e2cf9a8d9740 Mon Sep 17 00:00:00 2001 From: Jia-Ju Bai <baijiaju1990@gmail.com> Date: Mon, 23 Jul 2018 22:29:56 +0800 Subject: [PATCH 1326/1506] gpu: drm: amdgpu: Replace mdelay with msleep in cik_pcie_gen3_enable() cik_pcie_gen3_enable() is only called by cik_common_hw_init(), which is never called in atomic context. cik_pcie_gen3_enable() calls mdelay() to busily wait, which is not necessary. mdelay() can be replaced with msleep(). This is found by a static analysis tool named DCNS written by myself. Signed-off-by: Jia-Ju Bai <baijiaju1990@gmail.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/cik.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/cik.c b/drivers/gpu/drm/amd/amdgpu/cik.c index 702e257a483ff..78ab939ae5d86 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik.c +++ b/drivers/gpu/drm/amd/amdgpu/cik.c @@ -1476,7 +1476,7 @@ static void cik_pcie_gen3_enable(struct amdgpu_device *adev) tmp |= PCIE_LC_CNTL4__LC_REDO_EQ_MASK; WREG32_PCIE(ixPCIE_LC_CNTL4, tmp); - mdelay(100); + msleep(100); /* linkctl */ pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL, &tmp16); -- GitLab From 2a8536f6e8464b8988baa7db881f30721616b0da Mon Sep 17 00:00:00 2001 From: Jeykumar Sankaran <jsanka@codeaurora.org> Date: Tue, 5 Jun 2018 19:00:54 -0700 Subject: [PATCH 1327/1506] drm: add msm compressed format modifiers Qualcomm Snapdragon chipsets uses compressed format to optimize BW across multiple IP's. This change adds needed modifier support in drm for a simple 4x4 tile based compressed variants of base formats. Changes in v3: - Removed duplicate entry for DRM_FORMAT_MOD_QCOM_COMPRESSED (Rob Clark) Changes in v4: - Remove all modifiers aside from COMPRESSED, this includes tiled and 10-bit Signed-off-by: Jeykumar Sankaran <jsanka@codeaurora.org> Signed-off-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- include/uapi/drm/drm_fourcc.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h index d43949b5bb3e3..721ab7e54d96d 100644 --- a/include/uapi/drm/drm_fourcc.h +++ b/include/uapi/drm/drm_fourcc.h @@ -299,6 +299,19 @@ extern "C" { */ #define DRM_FORMAT_MOD_SAMSUNG_64_32_TILE fourcc_mod_code(SAMSUNG, 1) +/* + * Qualcomm Compressed Format + * + * Refers to a compressed variant of the base format that is compressed. + * Implementation may be platform and base-format specific. + * + * Each macrotile consists of m x n (mostly 4 x 4) tiles. + * Pixel data pitch/stride is aligned with macrotile width. + * Pixel data height is aligned with macrotile height. + * Entire pixel data buffer is aligned with 4k(bytes). + */ +#define DRM_FORMAT_MOD_QCOM_COMPRESSED fourcc_mod_code(QCOM, 1) + /* Vivante framebuffer modifiers */ /* -- GitLab From ed9976a09b486d85ae537b5cd73e947d7dfbb136 Mon Sep 17 00:00:00 2001 From: Chandan Uddaraju <chandanu@codeaurora.org> Date: Wed, 18 Apr 2018 12:45:14 -0700 Subject: [PATCH 1328/1506] drm/msm/dsi: adjust dsi timing for dual dsi mode For dual dsi mode, the horizontal timing needs to be divided by half since both the dsi controllers will be driving this panel. Adjust the pixel clock and DSI timing accordingly. Changes in v3: - Added Archit's R-b - Rebase on dsi cleanup set in msm-next Cc: Sibi Sankar <sibis@codeaurora.org> Reviewed-by: Archit Taneja <architt@codeaurora.org> Signed-off-by: Chandan Uddaraju <chandanu@codeaurora.org> Signed-off-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/msm/dsi/dsi.h | 10 +++-- drivers/gpu/drm/msm/dsi/dsi_cfg.h | 2 +- drivers/gpu/drm/msm/dsi/dsi_host.c | 65 ++++++++++++++++++++++----- drivers/gpu/drm/msm/dsi/dsi_manager.c | 7 +-- 4 files changed, 64 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h index dfa049d876bde..d3f613c76ffa6 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.h +++ b/drivers/gpu/drm/msm/dsi/dsi.h @@ -163,7 +163,8 @@ void msm_dsi_host_cmd_xfer_commit(struct mipi_dsi_host *host, int msm_dsi_host_enable(struct mipi_dsi_host *host); int msm_dsi_host_disable(struct mipi_dsi_host *host); int msm_dsi_host_power_on(struct mipi_dsi_host *host, - struct msm_dsi_phy_shared_timings *phy_shared_timings); + struct msm_dsi_phy_shared_timings *phy_shared_timings, + bool is_dual_dsi); int msm_dsi_host_power_off(struct mipi_dsi_host *host); int msm_dsi_host_set_display_mode(struct mipi_dsi_host *host, struct drm_display_mode *mode); @@ -176,7 +177,8 @@ int msm_dsi_host_set_src_pll(struct mipi_dsi_host *host, struct msm_dsi_pll *src_pll); void msm_dsi_host_reset_phy(struct mipi_dsi_host *host); void msm_dsi_host_get_phy_clk_req(struct mipi_dsi_host *host, - struct msm_dsi_phy_clk_request *clk_req); + struct msm_dsi_phy_clk_request *clk_req, + bool is_dual_dsi); void msm_dsi_host_destroy(struct mipi_dsi_host *host); int msm_dsi_host_modeset_init(struct mipi_dsi_host *host, struct drm_device *dev); @@ -196,8 +198,8 @@ int dsi_dma_base_get_6g(struct msm_dsi_host *msm_host, uint64_t *iova); int dsi_dma_base_get_v2(struct msm_dsi_host *msm_host, uint64_t *iova); int dsi_clk_init_v2(struct msm_dsi_host *msm_host); int dsi_clk_init_6g_v2(struct msm_dsi_host *msm_host); -int dsi_calc_clk_rate_v2(struct msm_dsi_host *msm_host); -int dsi_calc_clk_rate_6g(struct msm_dsi_host *msm_host); +int dsi_calc_clk_rate_v2(struct msm_dsi_host *msm_host, bool is_dual_dsi); +int dsi_calc_clk_rate_6g(struct msm_dsi_host *msm_host, bool is_dual_dsi); /* dsi phy */ struct msm_dsi_phy; diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.h b/drivers/gpu/drm/msm/dsi/dsi_cfg.h index a795a062b7795..16c5079111109 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_cfg.h +++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.h @@ -48,7 +48,7 @@ struct msm_dsi_host_cfg_ops { void* (*tx_buf_get)(struct msm_dsi_host *msm_host); void (*tx_buf_put)(struct msm_dsi_host *msm_host); int (*dma_base_get)(struct msm_dsi_host *msm_host, uint64_t *iova); - int (*calc_clk_rate)(struct msm_dsi_host *msm_host); + int (*calc_clk_rate)(struct msm_dsi_host *msm_host, bool is_dual_dsi); }; struct msm_dsi_cfg_handler { diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index 24dfae5b01a2b..cba42ad05fb34 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -118,6 +118,7 @@ struct msm_dsi_host { struct clk *byte_intf_clk; u32 byte_clk_rate; + u32 pixel_clk_rate; u32 esc_clk_rate; /* DSI v2 specific clocks */ @@ -523,7 +524,7 @@ int dsi_link_clk_enable_6g(struct msm_dsi_host *msm_host) goto error; } - ret = clk_set_rate(msm_host->pixel_clk, msm_host->mode->clock * 1000); + ret = clk_set_rate(msm_host->pixel_clk, msm_host->pixel_clk_rate); if (ret) { pr_err("%s: Failed to set rate pixel clk, %d\n", __func__, ret); goto error; @@ -604,7 +605,7 @@ int dsi_link_clk_enable_v2(struct msm_dsi_host *msm_host) goto error; } - ret = clk_set_rate(msm_host->pixel_clk, msm_host->mode->clock * 1000); + ret = clk_set_rate(msm_host->pixel_clk, msm_host->pixel_clk_rate); if (ret) { pr_err("%s: Failed to set rate pixel clk, %d\n", __func__, ret); goto error; @@ -663,7 +664,7 @@ void dsi_link_clk_disable_v2(struct msm_dsi_host *msm_host) clk_disable_unprepare(msm_host->byte_clk); } -int dsi_calc_clk_rate_6g(struct msm_dsi_host *msm_host) +int dsi_calc_clk_rate_6g(struct msm_dsi_host *msm_host, bool is_dual_dsi) { struct drm_display_mode *mode = msm_host->mode; u8 lanes = msm_host->lanes; @@ -671,6 +672,16 @@ int dsi_calc_clk_rate_6g(struct msm_dsi_host *msm_host) u32 pclk_rate; pclk_rate = mode->clock * 1000; + + /* + * For dual DSI mode, the current DRM mode has the complete width of the + * panel. Since, the complete panel is driven by two DSI controllers, + * theclock rates have to be split between the two dsi controllers. + * Adjust the byte and pixel clock rates for each dsi host accordingly. + */ + if (is_dual_dsi) + pclk_rate /= 2; + if (lanes > 0) { msm_host->byte_clk_rate = (pclk_rate * bpp) / (8 * lanes); } else { @@ -685,7 +696,7 @@ int dsi_calc_clk_rate_6g(struct msm_dsi_host *msm_host) return 0; } -int dsi_calc_clk_rate_v2(struct msm_dsi_host *msm_host) +int dsi_calc_clk_rate_v2(struct msm_dsi_host *msm_host, bool is_dual_dsi) { struct drm_display_mode *mode = msm_host->mode; u8 lanes = msm_host->lanes; @@ -695,14 +706,26 @@ int dsi_calc_clk_rate_v2(struct msm_dsi_host *msm_host) unsigned long byte_mhz; pclk_rate = mode->clock * 1000; + + /* + * For dual DSI mode, the current DRM mode has the complete width of the + * panel. Since, the complete panel is driven by two DSI controllers, + * theclock rates have to be split between the two dsi controllers. + * Adjust the byte and pixel clock rates for each dsi host accordingly. + */ + if (is_dual_dsi) + pclk_rate /= 2; + if (lanes > 0) { msm_host->byte_clk_rate = (pclk_rate * bpp) / (8 * lanes); } else { pr_err("%s: forcing mdss_dsi lanes to 1\n", __func__); msm_host->byte_clk_rate = (pclk_rate * bpp) / 8; } + msm_host->pixel_clk_rate = pclk_rate; - DBG("pclk=%d, bclk=%d", pclk_rate, msm_host->byte_clk_rate); + DBG("pclk=%d, bclk=%d", msm_host->pixel_clk_rate, + msm_host->byte_clk_rate); msm_host->src_clk_rate = (pclk_rate * bpp) / 8; @@ -897,7 +920,7 @@ static void dsi_ctrl_config(struct msm_dsi_host *msm_host, bool enable, dsi_write(msm_host, REG_DSI_CTRL, data); } -static void dsi_timing_setup(struct msm_dsi_host *msm_host) +static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_dual_dsi) { struct drm_display_mode *mode = msm_host->mode; u32 hs_start = 0, vs_start = 0; /* take sync start as 0 */ @@ -909,10 +932,26 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host) u32 ha_end = ha_start + mode->hdisplay; u32 va_start = v_total - mode->vsync_start; u32 va_end = va_start + mode->vdisplay; + u32 hdisplay = mode->hdisplay; u32 wc; DBG(""); + /* + * For dual DSI mode, the current DRM mode has + * the complete width of the panel. Since, the complete + * panel is driven by two DSI controllers, the horizontal + * timings have to be split between the two dsi controllers. + * Adjust the DSI host timing values accordingly. + */ + if (is_dual_dsi) { + h_total /= 2; + hs_end /= 2; + ha_start /= 2; + ha_end /= 2; + hdisplay /= 2; + } + if (msm_host->mode_flags & MIPI_DSI_MODE_VIDEO) { dsi_write(msm_host, REG_DSI_ACTIVE_H, DSI_ACTIVE_H_START(ha_start) | @@ -933,7 +972,7 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host) DSI_ACTIVE_VSYNC_VPOS_END(vs_end)); } else { /* command mode */ /* image data and 1 byte write_memory_start cmd */ - wc = mode->hdisplay * dsi_get_bpp(msm_host->format) / 8 + 1; + wc = hdisplay * dsi_get_bpp(msm_host->format) / 8 + 1; dsi_write(msm_host, REG_DSI_CMD_MDP_STREAM_CTRL, DSI_CMD_MDP_STREAM_CTRL_WORD_COUNT(wc) | @@ -943,7 +982,7 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host) MIPI_DSI_DCS_LONG_WRITE)); dsi_write(msm_host, REG_DSI_CMD_MDP_STREAM_TOTAL, - DSI_CMD_MDP_STREAM_TOTAL_H_TOTAL(mode->hdisplay) | + DSI_CMD_MDP_STREAM_TOTAL_H_TOTAL(hdisplay) | DSI_CMD_MDP_STREAM_TOTAL_V_TOTAL(mode->vdisplay)); } } @@ -2217,13 +2256,14 @@ void msm_dsi_host_reset_phy(struct mipi_dsi_host *host) } void msm_dsi_host_get_phy_clk_req(struct mipi_dsi_host *host, - struct msm_dsi_phy_clk_request *clk_req) + struct msm_dsi_phy_clk_request *clk_req, + bool is_dual_dsi) { struct msm_dsi_host *msm_host = to_msm_dsi_host(host); const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; int ret; - ret = cfg_hnd->ops->calc_clk_rate(msm_host); + ret = cfg_hnd->ops->calc_clk_rate(msm_host, is_dual_dsi); if (ret) { pr_err("%s: unable to calc clk rate, %d\n", __func__, ret); return; @@ -2285,7 +2325,8 @@ static void msm_dsi_sfpb_config(struct msm_dsi_host *msm_host, bool enable) } int msm_dsi_host_power_on(struct mipi_dsi_host *host, - struct msm_dsi_phy_shared_timings *phy_shared_timings) + struct msm_dsi_phy_shared_timings *phy_shared_timings, + bool is_dual_dsi) { struct msm_dsi_host *msm_host = to_msm_dsi_host(host); const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; @@ -2321,7 +2362,7 @@ int msm_dsi_host_power_on(struct mipi_dsi_host *host, goto fail_disable_clk; } - dsi_timing_setup(msm_host); + dsi_timing_setup(msm_host, is_dual_dsi); dsi_sw_reset(msm_host); dsi_ctrl_config(msm_host, true, phy_shared_timings); diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c index d5006d6923e01..601de7012caee 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c @@ -134,8 +134,9 @@ static int enable_phy(struct msm_dsi *msm_dsi, int src_pll_id, { struct msm_dsi_phy_clk_request clk_req; int ret; + bool is_dual_dsi = IS_DUAL_DSI(); - msm_dsi_host_get_phy_clk_req(msm_dsi->host, &clk_req); + msm_dsi_host_get_phy_clk_req(msm_dsi->host, &clk_req, is_dual_dsi); ret = msm_dsi_phy_enable(msm_dsi->phy, src_pll_id, &clk_req); msm_dsi_phy_get_shared_timings(msm_dsi->phy, shared_timings); @@ -458,7 +459,7 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge) if (is_dual_dsi && (DSI_1 == id)) return; - ret = msm_dsi_host_power_on(host, &phy_shared_timings[id]); + ret = msm_dsi_host_power_on(host, &phy_shared_timings[id], is_dual_dsi); if (ret) { pr_err("%s: power on host %d failed, %d\n", __func__, id, ret); goto host_on_fail; @@ -466,7 +467,7 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge) if (is_dual_dsi && msm_dsi1) { ret = msm_dsi_host_power_on(msm_dsi1->host, - &phy_shared_timings[DSI_1]); + &phy_shared_timings[DSI_1], is_dual_dsi); if (ret) { pr_err("%s: power on host1 failed, %d\n", __func__, ret); -- GitLab From 8b03ad30e314691f7bfccc0f9fae0dffd498b667 Mon Sep 17 00:00:00 2001 From: Chandan Uddaraju <chandanu@codeaurora.org> Date: Wed, 18 Apr 2018 12:45:15 -0700 Subject: [PATCH 1329/1506] drm/msm/dsi: Use one connector for dual DSI mode Current DSI driver uses two connectors for dual DSI case even though we only have one panel. Fix this by implementing one connector/bridge for dual DSI use case. Use master DSI controllers to register one connector/bridge. Changes in v3: - None Reviewed-by: Archit Taneja <architt@codeaurora.org> Signed-off-by: Chandan Uddaraju <chandanu@codeaurora.org> [seanpaul removed unused local var causing a build warning] Signed-off-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/msm/dsi/dsi.c | 3 + drivers/gpu/drm/msm/dsi/dsi.h | 1 + drivers/gpu/drm/msm/dsi/dsi_manager.c | 112 ++++++-------------------- 3 files changed, 30 insertions(+), 86 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c index b744bcc7d8ad0..ff8164cc6738d 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.c +++ b/drivers/gpu/drm/msm/dsi/dsi.c @@ -208,6 +208,9 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev, goto fail; } + if (!msm_dsi_manager_validate_current_config(msm_dsi->id)) + goto fail; + msm_dsi->encoder = encoder; msm_dsi->bridge = msm_dsi_manager_bridge_init(msm_dsi->id); diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h index d3f613c76ffa6..08f3fc6771b78 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.h +++ b/drivers/gpu/drm/msm/dsi/dsi.h @@ -100,6 +100,7 @@ bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 dma_base, u32 len); void msm_dsi_manager_attach_dsi_device(int id, u32 device_flags); int msm_dsi_manager_register(struct msm_dsi *msm_dsi); void msm_dsi_manager_unregister(struct msm_dsi *msm_dsi); +bool msm_dsi_manager_validate_current_config(u8 id); /* msm dsi */ static inline bool msm_dsi_device_connected(struct msm_dsi *msm_dsi) diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c index 601de7012caee..8422b8753eb9a 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c @@ -306,102 +306,25 @@ static void dsi_mgr_connector_destroy(struct drm_connector *connector) kfree(dsi_connector); } -static void dsi_dual_connector_fix_modes(struct drm_connector *connector) -{ - struct drm_display_mode *mode, *m; - - /* Only support left-right mode */ - list_for_each_entry_safe(mode, m, &connector->probed_modes, head) { - mode->clock >>= 1; - mode->hdisplay >>= 1; - mode->hsync_start >>= 1; - mode->hsync_end >>= 1; - mode->htotal >>= 1; - drm_mode_set_name(mode); - } -} - -static int dsi_dual_connector_tile_init( - struct drm_connector *connector, int id) -{ - struct drm_display_mode *mode; - /* Fake topology id */ - char topo_id[8] = {'M', 'S', 'M', 'D', 'U', 'D', 'S', 'I'}; - - if (connector->tile_group) { - DBG("Tile property has been initialized"); - return 0; - } - - /* Use the first mode only for now */ - mode = list_first_entry(&connector->probed_modes, - struct drm_display_mode, - head); - if (!mode) - return -EINVAL; - - connector->tile_group = drm_mode_get_tile_group( - connector->dev, topo_id); - if (!connector->tile_group) - connector->tile_group = drm_mode_create_tile_group( - connector->dev, topo_id); - if (!connector->tile_group) { - pr_err("%s: failed to create tile group\n", __func__); - return -ENOMEM; - } - - connector->has_tile = true; - connector->tile_is_single_monitor = true; - - /* mode has been fixed */ - connector->tile_h_size = mode->hdisplay; - connector->tile_v_size = mode->vdisplay; - - /* Only support left-right mode */ - connector->num_h_tile = 2; - connector->num_v_tile = 1; - - connector->tile_v_loc = 0; - connector->tile_h_loc = (id == DSI_RIGHT) ? 1 : 0; - - return 0; -} - static int dsi_mgr_connector_get_modes(struct drm_connector *connector) { int id = dsi_mgr_connector_get_id(connector); struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id); struct drm_panel *panel = msm_dsi->panel; - int ret, num; + int num; if (!panel) return 0; - /* Since we have 2 connectors, but only 1 drm_panel in dual DSI mode, - * panel should not attach to any connector. - * Only temporarily attach panel to the current connector here, - * to let panel set mode to this connector. + /* + * In dual DSI mode, we have one connector that can be + * attached to the drm_panel. */ drm_panel_attach(panel, connector); num = drm_panel_get_modes(panel); - drm_panel_detach(panel); if (!num) return 0; - if (IS_DUAL_DSI()) { - /* report half resolution to user */ - dsi_dual_connector_fix_modes(connector); - ret = dsi_dual_connector_tile_init(connector, id); - if (ret) - return ret; - ret = drm_connector_set_tile_property(connector); - if (ret) { - pr_err("%s: set tile property failed, %d\n", - __func__, ret); - return ret; - } - } - return num; } @@ -455,8 +378,8 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge) if (ret) goto phy_en_fail; - /* Do nothing with the host if it is DSI 1 in case of dual DSI */ - if (is_dual_dsi && (DSI_1 == id)) + /* Do nothing with the host if it is slave-DSI in case of dual DSI */ + if (is_dual_dsi && !IS_MASTER_DSI_LINK(id)) return; ret = msm_dsi_host_power_on(host, &phy_shared_timings[id], is_dual_dsi); @@ -557,11 +480,11 @@ static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge) return; /* - * Do nothing with the host if it is DSI 1 in case of dual DSI. + * Do nothing with the host if it is slave-DSI in case of dual DSI. * It is safe to call dsi_mgr_phy_disable() here because a single PHY * won't be diabled until both PHYs request disable. */ - if (is_dual_dsi && (DSI_1 == id)) + if (is_dual_dsi && !IS_MASTER_DSI_LINK(id)) goto disable_phy; if (panel) { @@ -622,7 +545,7 @@ static void dsi_mgr_bridge_mode_set(struct drm_bridge *bridge, mode->vsync_end, mode->vtotal, mode->type, mode->flags); - if (is_dual_dsi && (DSI_1 == id)) + if (is_dual_dsi && !IS_MASTER_DSI_LINK(id)) return; msm_dsi_host_set_display_mode(host, adjusted_mode); @@ -690,6 +613,23 @@ struct drm_connector *msm_dsi_manager_connector_init(u8 id) return connector; } +bool msm_dsi_manager_validate_current_config(u8 id) +{ + bool is_dual_dsi = IS_DUAL_DSI(); + + /* + * For dual DSI, we only have one drm panel. For this + * use case, we register only one bridge/connector. + * Skip bridge/connector initialisation if it is + * slave-DSI for dual DSI configuration. + */ + if (is_dual_dsi && !IS_MASTER_DSI_LINK(id)) { + DBG("Skip bridge registration for slave DSI->id: %d\n", id); + return false; + } + return true; +} + /* initialize bridge */ struct drm_bridge *msm_dsi_manager_bridge_init(u8 id) { -- GitLab From 7a296796fd0b28dc229d65dd90a6b392852d9631 Mon Sep 17 00:00:00 2001 From: Rajesh Yadav <ryadav@codeaurora.org> Date: Mon, 25 Jun 2018 19:12:03 +0530 Subject: [PATCH 1330/1506] drm/msm/dsi: initialize postdiv_lock before use for 10nm pll postdiv_lock spinlock was used before initialization for 10nm pll. It causes following spin_bug: "BUG: spinlock bad magic on CPU#0". Initialize spinlock before its usage. Changes in v3: - Added Archit's R-b Reviewed-by: Archit Taneja <architt@codeaurora.org> Signed-off-by: Rajesh Yadav <ryadav@codeaurora.org> Signed-off-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c index c4c37a7df637f..4c03f0b7343ed 100644 --- a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c +++ b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c @@ -798,6 +798,8 @@ struct msm_dsi_pll *msm_dsi_pll_10nm_init(struct platform_device *pdev, int id) return ERR_PTR(-ENOMEM); } + spin_lock_init(&pll_10nm->postdiv_lock); + pll = &pll_10nm->base; pll->min_rate = 1000000000UL; pll->max_rate = 3500000000UL; -- GitLab From 425a2d24d5b3ee9efc7f490440bfa20ba9166548 Mon Sep 17 00:00:00 2001 From: Abhinav Kumar <abhinavk@codeaurora.org> Date: Fri, 15 Jun 2018 22:56:59 -0700 Subject: [PATCH 1331/1506] drm/msm/dsi: set encoder mode for DRM bridge explicitly Currently, DRM bridge for DPU relies on the default video mode setting to set the encoder mode. Add an explicit call to set the encoder mode for bridges. Changes in v3: - None Reviewed-by: Archit Taneja <architt@codeauorora.org> Signed-off-by: Abhinav Kumar <abhinavk@codeaurora.org> Signed-off-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/msm/dsi/dsi_manager.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c index 8422b8753eb9a..5224010d90e4a 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c @@ -773,6 +773,7 @@ void msm_dsi_manager_attach_dsi_device(int id, u32 device_flags) struct msm_drm_private *priv; struct msm_kms *kms; struct drm_encoder *encoder; + bool cmd_mode; /* * drm_device pointer is assigned to msm_dsi only in the modeset_init @@ -787,10 +788,11 @@ void msm_dsi_manager_attach_dsi_device(int id, u32 device_flags) priv = dev->dev_private; kms = priv->kms; encoder = msm_dsi_get_encoder(msm_dsi); + cmd_mode = !(device_flags & + MIPI_DSI_MODE_VIDEO); if (encoder && kms->funcs->set_encoder_mode) - if (!(device_flags & MIPI_DSI_MODE_VIDEO)) - kms->funcs->set_encoder_mode(kms, encoder, true); + kms->funcs->set_encoder_mode(kms, encoder, cmd_mode); } int msm_dsi_manager_register(struct msm_dsi *msm_dsi) -- GitLab From a5c6b59904222ffe2eee37e5951d1f57ac1e530f Mon Sep 17 00:00:00 2001 From: Sean Paul <seanpaul@chromium.org> Date: Fri, 13 Apr 2018 10:09:11 -0400 Subject: [PATCH 1332/1506] drm/msm: Move wait_for_vblanks into mdp complete_commit() hooks DPU doesn't use this, so push it into the mdp drivers. Changes in v3: - None Signed-off-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Rajesh Yadav <ryadav@codeaurora.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c | 2 ++ drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c | 2 ++ drivers/gpu/drm/msm/msm_atomic.c | 2 -- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c index 4b646bf9c2146..44d1cda56974d 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c @@ -125,6 +125,8 @@ static void mdp4_complete_commit(struct msm_kms *kms, struct drm_atomic_state *s struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; + drm_atomic_helper_wait_for_vblanks(mdp4_kms->dev, state); + /* see 119ecb7fd */ for_each_new_crtc_in_state(state, crtc, crtc_state, i) drm_crtc_vblank_put(crtc); diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c index 6e12e275debae..bddd625ab91bd 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c @@ -170,6 +170,8 @@ static void mdp5_complete_commit(struct msm_kms *kms, struct drm_atomic_state *s struct device *dev = &mdp5_kms->pdev->dev; struct mdp5_global_state *global_state; + drm_atomic_helper_wait_for_vblanks(mdp5_kms->dev, state); + global_state = mdp5_get_existing_global_state(mdp5_kms); if (mdp5_kms->smp) diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index f0635c3da7f48..e6f1e25c60afd 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c @@ -75,8 +75,6 @@ void msm_atomic_commit_tail(struct drm_atomic_state *state) kms->funcs->complete_commit(kms, state); - drm_atomic_helper_wait_for_vblanks(dev, state); - drm_atomic_helper_commit_hw_done(state); drm_atomic_helper_cleanup_planes(dev, state); -- GitLab From bc3220be22577e199452edbb6a24a980a4ab5c73 Mon Sep 17 00:00:00 2001 From: Rajesh Yadav <ryadav@codeaurora.org> Date: Thu, 21 Jun 2018 16:06:10 -0400 Subject: [PATCH 1333/1506] drm/msm/mdp5: subclass msm_mdss for mdp5 SoCs having mdp5 or dpu have identical tree like device hierarchy where MDSS top level wrapper manages common power resources for all child devices. Subclass msm_mdss so that msm_mdss includes common defines and mdp5/dpu mdss derivations to include any extensions. Add mdss helper interface (msm_mdss_funcs) to msm_mdss base for mdp5/dpu mdss specific implementation calls. This change subclasses msm_mdss for mdp5, dpu specific changes will be done separately. Changes in v3: - Added Archit's R-b Reviewed-by: Archit Taneja <architt@codeaurora.org> Reviewed-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Rajesh Yadav <ryadav@codeaurora.org> [seanpaul rebased on msm-next and resolved conflicts] Signed-off-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/msm/disp/mdp5/mdp5_mdss.c | 154 ++++++++++++---------- drivers/gpu/drm/msm/msm_drv.c | 22 +++- drivers/gpu/drm/msm/msm_kms.h | 17 ++- 3 files changed, 109 insertions(+), 84 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_mdss.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mdss.c index f2a0db7a8a031..1cc4e57f0226f 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_mdss.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mdss.c @@ -20,12 +20,10 @@ #include "msm_drv.h" #include "mdp5_kms.h" -/* - * If needed, this can become more specific: something like struct mdp5_mdss, - * which contains a 'struct msm_mdss base' member. - */ -struct msm_mdss { - struct drm_device *dev; +#define to_mdp5_mdss(x) container_of(x, struct mdp5_mdss, base) + +struct mdp5_mdss { + struct msm_mdss base; void __iomem *mmio, *vbif; @@ -41,22 +39,22 @@ struct msm_mdss { } irqcontroller; }; -static inline void mdss_write(struct msm_mdss *mdss, u32 reg, u32 data) +static inline void mdss_write(struct mdp5_mdss *mdp5_mdss, u32 reg, u32 data) { - msm_writel(data, mdss->mmio + reg); + msm_writel(data, mdp5_mdss->mmio + reg); } -static inline u32 mdss_read(struct msm_mdss *mdss, u32 reg) +static inline u32 mdss_read(struct mdp5_mdss *mdp5_mdss, u32 reg) { - return msm_readl(mdss->mmio + reg); + return msm_readl(mdp5_mdss->mmio + reg); } static irqreturn_t mdss_irq(int irq, void *arg) { - struct msm_mdss *mdss = arg; + struct mdp5_mdss *mdp5_mdss = arg; u32 intr; - intr = mdss_read(mdss, REG_MDSS_HW_INTR_STATUS); + intr = mdss_read(mdp5_mdss, REG_MDSS_HW_INTR_STATUS); VERB("intr=%08x", intr); @@ -64,7 +62,7 @@ static irqreturn_t mdss_irq(int irq, void *arg) irq_hw_number_t hwirq = fls(intr) - 1; generic_handle_irq(irq_find_mapping( - mdss->irqcontroller.domain, hwirq)); + mdp5_mdss->irqcontroller.domain, hwirq)); intr &= ~(1 << hwirq); } @@ -84,19 +82,19 @@ static irqreturn_t mdss_irq(int irq, void *arg) static void mdss_hw_mask_irq(struct irq_data *irqd) { - struct msm_mdss *mdss = irq_data_get_irq_chip_data(irqd); + struct mdp5_mdss *mdp5_mdss = irq_data_get_irq_chip_data(irqd); smp_mb__before_atomic(); - clear_bit(irqd->hwirq, &mdss->irqcontroller.enabled_mask); + clear_bit(irqd->hwirq, &mdp5_mdss->irqcontroller.enabled_mask); smp_mb__after_atomic(); } static void mdss_hw_unmask_irq(struct irq_data *irqd) { - struct msm_mdss *mdss = irq_data_get_irq_chip_data(irqd); + struct mdp5_mdss *mdp5_mdss = irq_data_get_irq_chip_data(irqd); smp_mb__before_atomic(); - set_bit(irqd->hwirq, &mdss->irqcontroller.enabled_mask); + set_bit(irqd->hwirq, &mdp5_mdss->irqcontroller.enabled_mask); smp_mb__after_atomic(); } @@ -109,13 +107,13 @@ static struct irq_chip mdss_hw_irq_chip = { static int mdss_hw_irqdomain_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hwirq) { - struct msm_mdss *mdss = d->host_data; + struct mdp5_mdss *mdp5_mdss = d->host_data; if (!(VALID_IRQS & (1 << hwirq))) return -EPERM; irq_set_chip_and_handler(irq, &mdss_hw_irq_chip, handle_level_irq); - irq_set_chip_data(irq, mdss); + irq_set_chip_data(irq, mdp5_mdss); return 0; } @@ -126,90 +124,99 @@ static const struct irq_domain_ops mdss_hw_irqdomain_ops = { }; -static int mdss_irq_domain_init(struct msm_mdss *mdss) +static int mdss_irq_domain_init(struct mdp5_mdss *mdp5_mdss) { - struct device *dev = mdss->dev->dev; + struct device *dev = mdp5_mdss->base.dev->dev; struct irq_domain *d; d = irq_domain_add_linear(dev->of_node, 32, &mdss_hw_irqdomain_ops, - mdss); + mdp5_mdss); if (!d) { dev_err(dev, "mdss irq domain add failed\n"); return -ENXIO; } - mdss->irqcontroller.enabled_mask = 0; - mdss->irqcontroller.domain = d; + mdp5_mdss->irqcontroller.enabled_mask = 0; + mdp5_mdss->irqcontroller.domain = d; return 0; } -int msm_mdss_enable(struct msm_mdss *mdss) +static int mdp5_mdss_enable(struct msm_mdss *mdss) { + struct mdp5_mdss *mdp5_mdss = to_mdp5_mdss(mdss); DBG(""); - clk_prepare_enable(mdss->ahb_clk); - if (mdss->axi_clk) - clk_prepare_enable(mdss->axi_clk); - if (mdss->vsync_clk) - clk_prepare_enable(mdss->vsync_clk); + clk_prepare_enable(mdp5_mdss->ahb_clk); + if (mdp5_mdss->axi_clk) + clk_prepare_enable(mdp5_mdss->axi_clk); + if (mdp5_mdss->vsync_clk) + clk_prepare_enable(mdp5_mdss->vsync_clk); return 0; } -int msm_mdss_disable(struct msm_mdss *mdss) +static int mdp5_mdss_disable(struct msm_mdss *mdss) { + struct mdp5_mdss *mdp5_mdss = to_mdp5_mdss(mdss); DBG(""); - if (mdss->vsync_clk) - clk_disable_unprepare(mdss->vsync_clk); - if (mdss->axi_clk) - clk_disable_unprepare(mdss->axi_clk); - clk_disable_unprepare(mdss->ahb_clk); + if (mdp5_mdss->vsync_clk) + clk_disable_unprepare(mdp5_mdss->vsync_clk); + if (mdp5_mdss->axi_clk) + clk_disable_unprepare(mdp5_mdss->axi_clk); + clk_disable_unprepare(mdp5_mdss->ahb_clk); return 0; } -static int msm_mdss_get_clocks(struct msm_mdss *mdss) +static int msm_mdss_get_clocks(struct mdp5_mdss *mdp5_mdss) { - struct platform_device *pdev = to_platform_device(mdss->dev->dev); + struct platform_device *pdev = + to_platform_device(mdp5_mdss->base.dev->dev); - mdss->ahb_clk = msm_clk_get(pdev, "iface"); - if (IS_ERR(mdss->ahb_clk)) - mdss->ahb_clk = NULL; + mdp5_mdss->ahb_clk = msm_clk_get(pdev, "iface"); + if (IS_ERR(mdp5_mdss->ahb_clk)) + mdp5_mdss->ahb_clk = NULL; - mdss->axi_clk = msm_clk_get(pdev, "bus"); - if (IS_ERR(mdss->axi_clk)) - mdss->axi_clk = NULL; + mdp5_mdss->axi_clk = msm_clk_get(pdev, "bus"); + if (IS_ERR(mdp5_mdss->axi_clk)) + mdp5_mdss->axi_clk = NULL; - mdss->vsync_clk = msm_clk_get(pdev, "vsync"); - if (IS_ERR(mdss->vsync_clk)) - mdss->vsync_clk = NULL; + mdp5_mdss->vsync_clk = msm_clk_get(pdev, "vsync"); + if (IS_ERR(mdp5_mdss->vsync_clk)) + mdp5_mdss->vsync_clk = NULL; return 0; } -void msm_mdss_destroy(struct drm_device *dev) +static void mdp5_mdss_destroy(struct drm_device *dev) { struct msm_drm_private *priv = dev->dev_private; - struct msm_mdss *mdss = priv->mdss; + struct mdp5_mdss *mdp5_mdss = to_mdp5_mdss(priv->mdss); - if (!mdss) + if (!mdp5_mdss) return; - irq_domain_remove(mdss->irqcontroller.domain); - mdss->irqcontroller.domain = NULL; + irq_domain_remove(mdp5_mdss->irqcontroller.domain); + mdp5_mdss->irqcontroller.domain = NULL; - regulator_disable(mdss->vdd); + regulator_disable(mdp5_mdss->vdd); pm_runtime_disable(dev->dev); } -int msm_mdss_init(struct drm_device *dev) +static const struct msm_mdss_funcs mdss_funcs = { + .enable = mdp5_mdss_enable, + .disable = mdp5_mdss_disable, + .destroy = mdp5_mdss_destroy, +}; + +int mdp5_mdss_init(struct drm_device *dev) { struct platform_device *pdev = to_platform_device(dev->dev); struct msm_drm_private *priv = dev->dev_private; - struct msm_mdss *mdss; + struct mdp5_mdss *mdp5_mdss; int ret; DBG(""); @@ -217,40 +224,40 @@ int msm_mdss_init(struct drm_device *dev) if (!of_device_is_compatible(dev->dev->of_node, "qcom,mdss")) return 0; - mdss = devm_kzalloc(dev->dev, sizeof(*mdss), GFP_KERNEL); - if (!mdss) { + mdp5_mdss = devm_kzalloc(dev->dev, sizeof(*mdp5_mdss), GFP_KERNEL); + if (!mdp5_mdss) { ret = -ENOMEM; goto fail; } - mdss->dev = dev; + mdp5_mdss->base.dev = dev; - mdss->mmio = msm_ioremap(pdev, "mdss_phys", "MDSS"); - if (IS_ERR(mdss->mmio)) { - ret = PTR_ERR(mdss->mmio); + mdp5_mdss->mmio = msm_ioremap(pdev, "mdss_phys", "MDSS"); + if (IS_ERR(mdp5_mdss->mmio)) { + ret = PTR_ERR(mdp5_mdss->mmio); goto fail; } - mdss->vbif = msm_ioremap(pdev, "vbif_phys", "VBIF"); - if (IS_ERR(mdss->vbif)) { - ret = PTR_ERR(mdss->vbif); + mdp5_mdss->vbif = msm_ioremap(pdev, "vbif_phys", "VBIF"); + if (IS_ERR(mdp5_mdss->vbif)) { + ret = PTR_ERR(mdp5_mdss->vbif); goto fail; } - ret = msm_mdss_get_clocks(mdss); + ret = msm_mdss_get_clocks(mdp5_mdss); if (ret) { dev_err(dev->dev, "failed to get clocks: %d\n", ret); goto fail; } /* Regulator to enable GDSCs in downstream kernels */ - mdss->vdd = devm_regulator_get(dev->dev, "vdd"); - if (IS_ERR(mdss->vdd)) { - ret = PTR_ERR(mdss->vdd); + mdp5_mdss->vdd = devm_regulator_get(dev->dev, "vdd"); + if (IS_ERR(mdp5_mdss->vdd)) { + ret = PTR_ERR(mdp5_mdss->vdd); goto fail; } - ret = regulator_enable(mdss->vdd); + ret = regulator_enable(mdp5_mdss->vdd); if (ret) { dev_err(dev->dev, "failed to enable regulator vdd: %d\n", ret); @@ -258,25 +265,26 @@ int msm_mdss_init(struct drm_device *dev) } ret = devm_request_irq(dev->dev, platform_get_irq(pdev, 0), - mdss_irq, 0, "mdss_isr", mdss); + mdss_irq, 0, "mdss_isr", mdp5_mdss); if (ret) { dev_err(dev->dev, "failed to init irq: %d\n", ret); goto fail_irq; } - ret = mdss_irq_domain_init(mdss); + ret = mdss_irq_domain_init(mdp5_mdss); if (ret) { dev_err(dev->dev, "failed to init sub-block irqs: %d\n", ret); goto fail_irq; } - priv->mdss = mdss; + mdp5_mdss->base.funcs = &mdss_funcs; + priv->mdss = &mdp5_mdss->base; pm_runtime_enable(dev->dev); return 0; fail_irq: - regulator_disable(mdss->vdd); + regulator_disable(mdp5_mdss->vdd); fail: return ret; } diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 7f7321eb53127..2608d3f779569 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -208,6 +208,7 @@ static int msm_drm_uninit(struct device *dev) struct drm_device *ddev = platform_get_drvdata(pdev); struct msm_drm_private *priv = ddev->dev_private; struct msm_kms *kms = priv->kms; + struct msm_mdss *mdss = priv->mdss; struct msm_vblank_ctrl *vbl_ctrl = &priv->vblank_ctrl; struct vblank_event *vbl_ev, *tmp; @@ -258,7 +259,8 @@ static int msm_drm_uninit(struct device *dev) component_unbind_all(dev, ddev); - msm_mdss_destroy(ddev); + if (mdss && mdss->funcs) + mdss->funcs->destroy(ddev); ddev->dev_private = NULL; drm_dev_unref(ddev); @@ -357,6 +359,7 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) struct drm_device *ddev; struct msm_drm_private *priv; struct msm_kms *kms; + struct msm_mdss *mdss; int ret; ddev = drm_dev_alloc(drv, dev); @@ -376,13 +379,15 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) ddev->dev_private = priv; priv->dev = ddev; - ret = msm_mdss_init(ddev); + ret = mdp5_mdss_init(ddev); if (ret) { kfree(priv); drm_dev_unref(ddev); return ret; } + mdss = priv->mdss; + priv->wq = alloc_ordered_workqueue("msm", 0); priv->atomic_wq = alloc_ordered_workqueue("msm:atomic", 0); @@ -396,7 +401,8 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) /* Bind all our sub-components: */ ret = component_bind_all(dev, ddev); if (ret) { - msm_mdss_destroy(ddev); + if (mdss && mdss->funcs) + mdss->funcs->destroy(ddev); kfree(priv); drm_dev_unref(ddev); return ret; @@ -924,11 +930,12 @@ static int msm_runtime_suspend(struct device *dev) { struct drm_device *ddev = dev_get_drvdata(dev); struct msm_drm_private *priv = ddev->dev_private; + struct msm_mdss *mdss = priv->mdss; DBG(""); - if (priv->mdss) - return msm_mdss_disable(priv->mdss); + if (mdss && mdss->funcs) + return mdss->funcs->disable(mdss); return 0; } @@ -937,11 +944,12 @@ static int msm_runtime_resume(struct device *dev) { struct drm_device *ddev = dev_get_drvdata(dev); struct msm_drm_private *priv = ddev->dev_private; + struct msm_mdss *mdss = priv->mdss; DBG(""); - if (priv->mdss) - return msm_mdss_enable(priv->mdss); + if (mdss && mdss->funcs) + return mdss->funcs->enable(mdss); return 0; } diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h index dfd92947de2c8..76c14221ffdf9 100644 --- a/drivers/gpu/drm/msm/msm_kms.h +++ b/drivers/gpu/drm/msm/msm_kms.h @@ -86,9 +86,18 @@ static inline void msm_kms_init(struct msm_kms *kms, struct msm_kms *mdp4_kms_init(struct drm_device *dev); struct msm_kms *mdp5_kms_init(struct drm_device *dev); -int msm_mdss_init(struct drm_device *dev); -void msm_mdss_destroy(struct drm_device *dev); -int msm_mdss_enable(struct msm_mdss *mdss); -int msm_mdss_disable(struct msm_mdss *mdss); + +struct msm_mdss_funcs { + int (*enable)(struct msm_mdss *mdss); + int (*disable)(struct msm_mdss *mdss); + void (*destroy)(struct drm_device *dev); +}; + +struct msm_mdss { + struct drm_device *dev; + const struct msm_mdss_funcs *funcs; +}; + +int mdp5_mdss_init(struct drm_device *dev); #endif /* __MSM_KMS_H__ */ -- GitLab From bb676df12b5e81cab57d1a212a6e9cfc343875a7 Mon Sep 17 00:00:00 2001 From: Jeykumar Sankaran <jsanka@codeaurora.org> Date: Mon, 11 Jun 2018 14:13:20 -0700 Subject: [PATCH 1334/1506] drm/msm: enable zpos normalization Enable drm core zpos normalization for planes. Changes in v3: - None Signed-off-by: Jeykumar Sankaran <jsanka@codeaurora.org> Reviewed-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/msm/msm_drv.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 2608d3f779569..9c760cee51565 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -439,6 +439,9 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) goto fail; } + /* Enable normalization of plane zpos */ + ddev->mode_config.normalize_zpos = true; + if (kms) { ret = kms->funcs->hw_init(kms); if (ret) { -- GitLab From 2d0b10fc5111bb4a902e9be378496d04c401ab81 Mon Sep 17 00:00:00 2001 From: Abhinav Kumar <abhinavk@codeaurora.org> Date: Thu, 7 Jun 2018 13:50:29 -0700 Subject: [PATCH 1335/1506] drm/msm: higher values of pclk can exceed 32 bits when multiplied by a factor Make the pclk_rate u64 to accommodate higher pixel clock rates. Changes in v3: - Converted pclk_rate to u32 (Archit) - Rebase on dsi cleanup set in msm-next Cc: Sibi Sankar <sibis@codeaurora.org> Cc: Archit Taneja <architt@codeaurora.org> Signed-off-by: Abhinav Kumar <abhinavk@codeaurora.org> Signed-off-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/msm/dsi/dsi_host.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index cba42ad05fb34..319501dcc0833 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -702,6 +702,7 @@ int dsi_calc_clk_rate_v2(struct msm_dsi_host *msm_host, bool is_dual_dsi) u8 lanes = msm_host->lanes; u32 bpp = dsi_get_bpp(msm_host->format); u32 pclk_rate; + u64 pclk_bpp; unsigned int esc_mhz, esc_div; unsigned long byte_mhz; @@ -716,13 +717,15 @@ int dsi_calc_clk_rate_v2(struct msm_dsi_host *msm_host, bool is_dual_dsi) if (is_dual_dsi) pclk_rate /= 2; + pclk_bpp = pclk_rate * bpp; if (lanes > 0) { - msm_host->byte_clk_rate = (pclk_rate * bpp) / (8 * lanes); + do_div(pclk_bpp, (8 * lanes)); } else { pr_err("%s: forcing mdss_dsi lanes to 1\n", __func__); - msm_host->byte_clk_rate = (pclk_rate * bpp) / 8; + do_div(pclk_bpp, 8); } msm_host->pixel_clk_rate = pclk_rate; + msm_host->byte_clk_rate = pclk_bpp; DBG("pclk=%d, bclk=%d", msm_host->pixel_clk_rate, msm_host->byte_clk_rate); -- GitLab From 74312fc7343efbfd95fc5e75c5c7547e9f751c22 Mon Sep 17 00:00:00 2001 From: Sean Paul <seanpaul@chromium.org> Date: Wed, 27 Jun 2018 15:15:49 -0400 Subject: [PATCH 1336/1506] drm/msm: Clean up dangling atomic_wq I missed this during the atomic conversion Changes in v3: - None Signed-off-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/msm/msm_drv.c | 4 ---- drivers/gpu/drm/msm/msm_drv.h | 1 - 2 files changed, 5 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 9c760cee51565..b73acdd529315 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -244,9 +244,6 @@ static int msm_drm_uninit(struct device *dev) flush_workqueue(priv->wq); destroy_workqueue(priv->wq); - flush_workqueue(priv->atomic_wq); - destroy_workqueue(priv->atomic_wq); - if (kms && kms->funcs) kms->funcs->destroy(kms); @@ -389,7 +386,6 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) mdss = priv->mdss; priv->wq = alloc_ordered_workqueue("msm", 0); - priv->atomic_wq = alloc_ordered_workqueue("msm:atomic", 0); INIT_LIST_HEAD(&priv->inactive_list); INIT_LIST_HEAD(&priv->vblank_ctrl.event_list); diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 17cefca1d5666..fa0376b0f42ba 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -115,7 +115,6 @@ struct msm_drm_private { struct list_head inactive_list; struct workqueue_struct *wq; - struct workqueue_struct *atomic_wq; unsigned int num_planes; struct drm_plane *planes[16]; -- GitLab From aaded2e3a1f6b776a5afd7c1168610d51f9a6a15 Mon Sep 17 00:00:00 2001 From: Jeykumar Sankaran <jsanka@codeaurora.org> Date: Wed, 27 Jun 2018 14:26:24 -0400 Subject: [PATCH 1337/1506] drm/msm: #define MDP version numbers Useful for incoming DPU support Changes in v3: - None Signed-off-by: Jeykumar Sankaran <jsanka@codeaurora.org> [seanpaul split this from the dpu megapatch] Signed-off-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/msm/msm_drv.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index b73acdd529315..67816543a0d7b 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -267,6 +267,9 @@ static int msm_drm_uninit(struct device *dev) return 0; } +#define KMS_MDP4 4 +#define KMS_MDP5 5 + static int get_mdp_ver(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -411,11 +414,11 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) msm_gem_shrinker_init(ddev); switch (get_mdp_ver(pdev)) { - case 4: + case KMS_MDP4: kms = mdp4_kms_init(ddev); priv->kms = kms; break; - case 5: + case KMS_MDP5: kms = mdp5_kms_init(ddev); break; default: @@ -1162,8 +1165,8 @@ static int msm_pdev_remove(struct platform_device *pdev) } static const struct of_device_id dt_match[] = { - { .compatible = "qcom,mdp4", .data = (void *)4 }, /* MDP4 */ - { .compatible = "qcom,mdss", .data = (void *)5 }, /* MDP5 MDSS */ + { .compatible = "qcom,mdp4", .data = (void *)KMS_MDP4 }, + { .compatible = "qcom,mdss", .data = (void *)KMS_MDP5 }, {} }; MODULE_DEVICE_TABLE(of, dt_match); -- GitLab From 77050c3febb1808ed6a0f7e9f0994278f06967ca Mon Sep 17 00:00:00 2001 From: Jeykumar Sankaran <jsanka@codeaurora.org> Date: Wed, 27 Jun 2018 14:35:28 -0400 Subject: [PATCH 1338/1506] drm/msm: Use labels for unwinding in the error path This simplifies cleanup, to make sure nothing drops out in case of error. Changes in v3: - None Signed-off-by: Jeykumar Sankaran <jsanka@codeaurora.org> [seanpaul split out of dpu megapatch and renamed labels] Signed-off-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/msm/msm_drv.c | 44 +++++++++++++++++------------------ 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 67816543a0d7b..8bd9fe8319682 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -372,19 +372,16 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) { - drm_dev_unref(ddev); - return -ENOMEM; + ret = -ENOMEM; + goto err_unref_drm_dev; } ddev->dev_private = priv; priv->dev = ddev; ret = mdp5_mdss_init(ddev); - if (ret) { - kfree(priv); - drm_dev_unref(ddev); - return ret; - } + if (ret) + goto err_free_priv; mdss = priv->mdss; @@ -399,17 +396,12 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) /* Bind all our sub-components: */ ret = component_bind_all(dev, ddev); - if (ret) { - if (mdss && mdss->funcs) - mdss->funcs->destroy(ddev); - kfree(priv); - drm_dev_unref(ddev); - return ret; - } + if (ret) + goto err_destroy_mdss; ret = msm_init_vram(ddev); if (ret) - goto fail; + goto err_msm_uninit; msm_gem_shrinker_init(ddev); @@ -435,7 +427,7 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) */ dev_err(dev, "failed to load kms\n"); ret = PTR_ERR(kms); - goto fail; + goto err_msm_uninit; } /* Enable normalization of plane zpos */ @@ -445,7 +437,7 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) ret = kms->funcs->hw_init(kms); if (ret) { dev_err(dev, "kms hw init failed: %d\n", ret); - goto fail; + goto err_msm_uninit; } } @@ -455,7 +447,7 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) ret = drm_vblank_init(ddev, priv->num_crtcs); if (ret < 0) { dev_err(dev, "failed to initialize vblank\n"); - goto fail; + goto err_msm_uninit; } if (kms) { @@ -464,13 +456,13 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) pm_runtime_put_sync(dev); if (ret < 0) { dev_err(dev, "failed to install IRQ handler\n"); - goto fail; + goto err_msm_uninit; } } ret = drm_dev_register(ddev, 0); if (ret) - goto fail; + goto err_msm_uninit; drm_mode_config_reset(ddev); @@ -481,15 +473,23 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) ret = msm_debugfs_late_init(ddev); if (ret) - goto fail; + goto err_msm_uninit; drm_kms_helper_poll_init(ddev); return 0; -fail: +err_msm_uninit: msm_drm_uninit(dev); return ret; +err_destroy_mdss: + if (mdss && mdss->funcs) + mdss->funcs->destroy(ddev); +err_free_priv: + kfree(priv); +err_unref_drm_dev: + drm_dev_unref(ddev); + return ret; } /* -- GitLab From 7305a0ceec78f34ce328845cdd6980d8eda99485 Mon Sep 17 00:00:00 2001 From: Jeykumar Sankaran <jsanka@codeaurora.org> Date: Wed, 27 Jun 2018 14:55:25 -0400 Subject: [PATCH 1339/1506] drm/msm: #define MAX_<OBJECT> in msm_drv.h dpu uses these elsewhere in the driver (in addition to increasing MAX_PLANES, that'll come later), so pull them out into #define. Changes in v3: - None Signed-off-by: Jeykumar Sankaran <jsanka@codeaurora.org> [seanpaul pulled this out of the dpu megapatch] Signed-off-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/msm/msm_drv.h | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index fa0376b0f42ba..3b206ae6423ff 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -54,6 +54,12 @@ struct msm_fence_context; struct msm_gem_address_space; struct msm_gem_vma; +#define MAX_CRTCS 8 +#define MAX_PLANES 16 +#define MAX_ENCODERS 8 +#define MAX_BRIDGES 8 +#define MAX_CONNECTORS 8 + struct msm_file_private { rwlock_t queuelock; struct list_head submitqueues; @@ -117,19 +123,19 @@ struct msm_drm_private { struct workqueue_struct *wq; unsigned int num_planes; - struct drm_plane *planes[16]; + struct drm_plane *planes[MAX_PLANES]; unsigned int num_crtcs; - struct drm_crtc *crtcs[8]; + struct drm_crtc *crtcs[MAX_CRTCS]; unsigned int num_encoders; - struct drm_encoder *encoders[8]; + struct drm_encoder *encoders[MAX_ENCODERS]; unsigned int num_bridges; - struct drm_bridge *bridges[8]; + struct drm_bridge *bridges[MAX_BRIDGES]; unsigned int num_connectors; - struct drm_connector *connectors[8]; + struct drm_connector *connectors[MAX_CONNECTORS]; /* Properties */ struct drm_property *plane_property[PLANE_PROP_MAX_NUM]; -- GitLab From 2b7ac1a8989829b085fae9750817ca3304047c04 Mon Sep 17 00:00:00 2001 From: Jeykumar Sankaran <jsanka@codeaurora.org> Date: Wed, 27 Jun 2018 13:49:23 -0400 Subject: [PATCH 1340/1506] drm/msm: Add .commit() callback to msm_kms functions Called right before wait_for_commit_done() to perform kickoff for active crtcs. Changes in v3: - None Signed-off-by: Jeykumar Sankaran <jsanka@codeaurora.org> [seanpaul split this out of the megapatch] Signed-off-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/msm/msm_atomic.c | 5 +++++ drivers/gpu/drm/msm/msm_kms.h | 1 + 2 files changed, 6 insertions(+) diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index e6f1e25c60afd..c1f1779c980f6 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c @@ -71,6 +71,11 @@ void msm_atomic_commit_tail(struct drm_atomic_state *state) drm_atomic_helper_commit_modeset_enables(dev, state); + if (kms->funcs->commit) { + DRM_DEBUG_ATOMIC("triggering commit\n"); + kms->funcs->commit(kms, state); + } + msm_atomic_wait_for_commit_done(dev, state); kms->funcs->complete_commit(kms, state); diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h index 76c14221ffdf9..761bb07cd7bf3 100644 --- a/drivers/gpu/drm/msm/msm_kms.h +++ b/drivers/gpu/drm/msm/msm_kms.h @@ -42,6 +42,7 @@ struct msm_kms_funcs { void (*disable_vblank)(struct msm_kms *kms, struct drm_crtc *crtc); /* modeset, bracketing atomic_commit(): */ void (*prepare_commit)(struct msm_kms *kms, struct drm_atomic_state *state); + void (*commit)(struct msm_kms *kms, struct drm_atomic_state *state); void (*complete_commit)(struct msm_kms *kms, struct drm_atomic_state *state); /* functions to wait for atomic commit completed on each CRTC */ void (*wait_for_crtc_commit_done)(struct msm_kms *kms, -- GitLab From 036bfeb33b89578ab924fa198213260659e08dc8 Mon Sep 17 00:00:00 2001 From: Jeykumar Sankaran <jsanka@codeaurora.org> Date: Wed, 27 Jun 2018 15:24:17 -0400 Subject: [PATCH 1341/1506] drm/msm: Add pm_suspend/resume callbacks to msm_kms Used by the dpu driver for custom suspend/resume. Changes in v3: - None Signed-off-by: Jeykumar Sankaran <jsanka@codeaurora.org> [seanpaul split this out of the megapatch] Signed-off-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/msm/msm_drv.c | 10 ++++++++++ drivers/gpu/drm/msm/msm_kms.h | 3 +++ 2 files changed, 13 insertions(+) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 8bd9fe8319682..e79ad74ca98c2 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -903,6 +903,11 @@ static int msm_pm_suspend(struct device *dev) { struct drm_device *ddev = dev_get_drvdata(dev); struct msm_drm_private *priv = ddev->dev_private; + struct msm_kms *kms = priv->kms; + + /* TODO: Use atomic helper suspend/resume */ + if (kms && kms->funcs && kms->funcs->pm_suspend) + return kms->funcs->pm_suspend(dev); drm_kms_helper_poll_disable(ddev); @@ -919,6 +924,11 @@ static int msm_pm_resume(struct device *dev) { struct drm_device *ddev = dev_get_drvdata(dev); struct msm_drm_private *priv = ddev->dev_private; + struct msm_kms *kms = priv->kms; + + /* TODO: Use atomic helper suspend/resume */ + if (kms && kms->funcs && kms->funcs->pm_resume) + return kms->funcs->pm_resume(dev); drm_atomic_helper_resume(ddev, priv->pm_state); drm_kms_helper_poll_enable(ddev); diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h index 761bb07cd7bf3..c15de28ae2ddf 100644 --- a/drivers/gpu/drm/msm/msm_kms.h +++ b/drivers/gpu/drm/msm/msm_kms.h @@ -61,6 +61,9 @@ struct msm_kms_funcs { void (*set_encoder_mode)(struct msm_kms *kms, struct drm_encoder *encoder, bool cmd_mode); + /* pm suspend/resume hooks */ + int (*pm_suspend)(struct device *dev); + int (*pm_resume)(struct device *dev); /* cleanup: */ void (*destroy)(struct msm_kms *kms); #ifdef CONFIG_DEBUG_FS -- GitLab From 25fdd5933e4c0f5fe2ea5cd59994f8ac5fbe90ef Mon Sep 17 00:00:00 2001 From: Jeykumar Sankaran <jsanka@codeaurora.org> Date: Wed, 27 Jun 2018 15:26:09 -0400 Subject: [PATCH 1342/1506] drm/msm: Add SDM845 DPU support SDM845 SoC includes the Mobile Display Sub System (MDSS) which is a top level wrapper consisting of Display Processing Unit (DPU) and display peripheral modules such as Display Serial Interface (DSI) and DisplayPort (DP). MDSS functions essentially as a back-end composition engine. It blends video and graphic images stored in the frame buffers and scans out the composed image to a display sink (over DSI/DP). The following diagram represents hardware blocks for a simple pipeline (two planes are present on a given crtc which is connected to a DSI connector): MDSS +---------------------------------+ | +-----------------------------+ | | | DPU | | | | +--------+ +--------+ | | | | | SSPP | | SSPP | | | | | +----+---+ +----+---+ | | | | | | | | | | +----v-----------v---+ | | | | | Layer Mixer (LM) | | | | | +--------------------+ | | | | +--------------------+ | | | | | PingPong (PP) | | | | | +--------------------+ | | | | +--------------------+ | | | | | INTERFACE (VIDEO) | | | | | +---+----------------+ | | | +------|----------------------+ | | | | | +------|---------------------+ | | | | DISPLAY PERIPHERALS | | | | +---v-+ +-----+ | | | | | DSI | | DP | | | | | +-----+ +-----+ | | | +----------------------------+ | +---------------------------------+ The number of DPU sub-blocks (i.e. SSPPs, LMs, PP blocks and INTFs) depends on SoC capabilities. Overview of DPU sub-blocks: --------------------------- * Source Surface Processor (SSPP): Refers to any of hardware pipes like ViG, DMA etc. Only ViG pipes are capable of performing format conversion, scaling and quality improvement for source surfaces. * Layer Mixer (LM): Blend source surfaces together (in requested zorder) * PingPong (PP): This block controls frame done interrupt output, EOL and EOF generation, overflow/underflow control. * Display interface (INTF): Timing generator and interface connecting the display peripherals. DRM components mapping to DPU architecture: ------------------------------------------ PLANEs maps to SSPPs CRTC maps to LMs Encoder maps to PPs, INTFs Data flow setup: --------------- MDSS hardware can support various data flows (e.g.): - Dual pipe: Output from two LMs combined to single display. - Split display: Output from two LMs connected to two separate interfaces. The hardware capabilities determine the number of concurrent data paths possible. Any control path (i.e. pipeline w/i DPU) can be routed to any of the hardware data paths. A given control path can be triggered, flushed and controlled independently. Changes in v3: - Move msm_media_info.h from uapi to dpu/ subdir - Remove preclose callback dpu (it's handled in core) - Fix kbuild warnings with parent_ops - Remove unused functions from dpu_core_irq - Rename mdss_phys to mdss - Rename mdp_phys address space to mdp - Drop _phys from vbif and regdma binding names Signed-off-by: Abhinav Kumar <abhinavk@codeaurora.org> Signed-off-by: Archit Taneja <architt@codeaurora.org> Signed-off-by: Chandan Uddaraju <chandanu@codeaurora.org> Signed-off-by: Jeykumar Sankaran <jsanka@codeaurora.org> Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org> Signed-off-by: Rajesh Yadav <ryadav@codeaurora.org> Signed-off-by: Sravanthi Kollukuduru <skolluku@codeaurora.org> Signed-off-by: Sean Paul <seanpaul@chromium.org> [robclark minor rebase] Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/msm/Makefile | 32 +- drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.c | 479 +++ drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.h | 153 + drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c | 637 ++++ drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.h | 133 + drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 2504 ++++++++++++++++ drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h | 484 ++++ drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.c | 2393 +++++++++++++++ drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.h | 103 + drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 2575 +++++++++++++++++ drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h | 191 ++ .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h | 453 +++ .../drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c | 905 ++++++ .../drm/msm/disp/dpu1/dpu_encoder_phys_vid.c | 922 ++++++ drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c | 1214 ++++++++ drivers/gpu/drm/msm/disp/dpu1/dpu_formats.h | 136 + drivers/gpu/drm/msm/disp/dpu1/dpu_hw_blk.c | 155 + drivers/gpu/drm/msm/disp/dpu1/dpu_hw_blk.h | 53 + .../gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c | 511 ++++ .../gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 804 +++++ .../drm/msm/disp/dpu1/dpu_hw_catalog_format.h | 168 ++ drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c | 323 +++ drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.h | 139 + drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c | 540 ++++ drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h | 218 ++ .../gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c | 1183 ++++++++ .../gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h | 257 ++ drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c | 349 +++ drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h | 128 + drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c | 261 ++ drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h | 122 + drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h | 465 +++ .../gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.c | 250 ++ .../gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h | 136 + drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c | 753 +++++ drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h | 424 +++ drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c | 398 +++ drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h | 202 ++ drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c | 452 +++ drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h | 358 +++ drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.c | 275 ++ drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h | 128 + drivers/gpu/drm/msm/disp/dpu1/dpu_hwio.h | 56 + drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c | 204 ++ drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.h | 57 + drivers/gpu/drm/msm/disp/dpu1/dpu_irq.c | 66 + drivers/gpu/drm/msm/disp/dpu1/dpu_irq.h | 59 + drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 1345 +++++++++ drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h | 402 +++ drivers/gpu/drm/msm/disp/dpu1/dpu_kms_utils.c | 153 + drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c | 245 ++ drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 1963 +++++++++++++ drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h | 175 ++ .../gpu/drm/msm/disp/dpu1/dpu_power_handle.c | 249 ++ .../gpu/drm/msm/disp/dpu1/dpu_power_handle.h | 225 ++ drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 1079 +++++++ drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 199 ++ drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h | 1007 +++++++ drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.c | 384 +++ drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.h | 94 + .../gpu/drm/msm/disp/dpu1/msm_media_info.h | 1376 +++++++++ drivers/gpu/drm/msm/msm_drv.c | 135 +- drivers/gpu/drm/msm/msm_drv.h | 81 +- drivers/gpu/drm/msm/msm_kms.h | 8 + 64 files changed, 31913 insertions(+), 15 deletions(-) create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.c create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.h create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.h create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.c create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.h create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_formats.h create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_blk.c create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_blk.h create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog_format.h create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.h create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.c create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.c create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hwio.h create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.h create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_irq.c create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_irq.h create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_kms_utils.c create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.c create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.h create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.c create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.h create mode 100644 drivers/gpu/drm/msm/disp/dpu1/msm_media_info.h diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index cd40c050b2d7f..1639ea8c0d132 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 ccflags-y := -Idrivers/gpu/drm/msm +ccflags-y += -Idrivers/gpu/drm/msm/disp/dpu1 ccflags-$(CONFIG_DRM_MSM_DSI) += -Idrivers/gpu/drm/msm/dsi msm-y := \ @@ -45,6 +46,34 @@ msm-y := \ disp/mdp5/mdp5_mixer.o \ disp/mdp5/mdp5_plane.o \ disp/mdp5/mdp5_smp.o \ + disp/dpu1/dpu_core_irq.o \ + disp/dpu1/dpu_core_perf.o \ + disp/dpu1/dpu_crtc.o \ + disp/dpu1/dpu_encoder.o \ + disp/dpu1/dpu_encoder_phys_cmd.o \ + disp/dpu1/dpu_encoder_phys_vid.o \ + disp/dpu1/dpu_formats.o \ + disp/dpu1/dpu_hw_blk.o \ + disp/dpu1/dpu_hw_catalog.o \ + disp/dpu1/dpu_hw_cdm.o \ + disp/dpu1/dpu_hw_ctl.o \ + disp/dpu1/dpu_hw_interrupts.o \ + disp/dpu1/dpu_hw_intf.o \ + disp/dpu1/dpu_hw_lm.o \ + disp/dpu1/dpu_hw_pingpong.o \ + disp/dpu1/dpu_hw_sspp.o \ + disp/dpu1/dpu_hw_top.o \ + disp/dpu1/dpu_hw_util.o \ + disp/dpu1/dpu_hw_vbif.o \ + disp/dpu1/dpu_io_util.o \ + disp/dpu1/dpu_irq.o \ + disp/dpu1/dpu_kms.o \ + disp/dpu1/dpu_kms_utils.o \ + disp/dpu1/dpu_mdss.o \ + disp/dpu1/dpu_plane.o \ + disp/dpu1/dpu_power_handle.o \ + disp/dpu1/dpu_rm.o \ + disp/dpu1/dpu_vbif.o \ msm_atomic.o \ msm_debugfs.o \ msm_drv.o \ @@ -62,7 +91,8 @@ msm-y := \ msm_ringbuffer.o \ msm_submitqueue.o -msm-$(CONFIG_DEBUG_FS) += adreno/a5xx_debugfs.o +msm-$(CONFIG_DEBUG_FS) += adreno/a5xx_debugfs.o \ + disp/dpu1/dpu_dbg.o msm-$(CONFIG_DRM_FBDEV_EMULATION) += msm_fbdev.o msm-$(CONFIG_COMMON_CLK) += disp/mdp4/mdp4_lvds_pll.o diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.c new file mode 100644 index 0000000000000..879c13fe74e05 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.c @@ -0,0 +1,479 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ + +#include <linux/debugfs.h> +#include <linux/irqdomain.h> +#include <linux/irq.h> +#include <linux/kthread.h> + +#include "dpu_core_irq.h" +#include "dpu_trace.h" + +/** + * dpu_core_irq_callback_handler - dispatch core interrupts + * @arg: private data of callback handler + * @irq_idx: interrupt index + */ +static void dpu_core_irq_callback_handler(void *arg, int irq_idx) +{ + struct dpu_kms *dpu_kms = arg; + struct dpu_irq *irq_obj = &dpu_kms->irq_obj; + struct dpu_irq_callback *cb; + unsigned long irq_flags; + + pr_debug("irq_idx=%d\n", irq_idx); + + if (list_empty(&irq_obj->irq_cb_tbl[irq_idx])) { + DRM_ERROR("no registered cb, idx:%d enable_count:%d\n", irq_idx, + atomic_read(&dpu_kms->irq_obj.enable_counts[irq_idx])); + } + + atomic_inc(&irq_obj->irq_counts[irq_idx]); + + /* + * Perform registered function callback + */ + spin_lock_irqsave(&dpu_kms->irq_obj.cb_lock, irq_flags); + list_for_each_entry(cb, &irq_obj->irq_cb_tbl[irq_idx], list) + if (cb->func) + cb->func(cb->arg, irq_idx); + spin_unlock_irqrestore(&dpu_kms->irq_obj.cb_lock, irq_flags); + + /* + * Clear pending interrupt status in HW. + * NOTE: dpu_core_irq_callback_handler is protected by top-level + * spinlock, so it is safe to clear any interrupt status here. + */ + dpu_kms->hw_intr->ops.clear_intr_status_nolock( + dpu_kms->hw_intr, + irq_idx); +} + +int dpu_core_irq_idx_lookup(struct dpu_kms *dpu_kms, + enum dpu_intr_type intr_type, u32 instance_idx) +{ + if (!dpu_kms || !dpu_kms->hw_intr || + !dpu_kms->hw_intr->ops.irq_idx_lookup) + return -EINVAL; + + return dpu_kms->hw_intr->ops.irq_idx_lookup(intr_type, + instance_idx); +} + +/** + * _dpu_core_irq_enable - enable core interrupt given by the index + * @dpu_kms: Pointer to dpu kms context + * @irq_idx: interrupt index + */ +static int _dpu_core_irq_enable(struct dpu_kms *dpu_kms, int irq_idx) +{ + unsigned long irq_flags; + int ret = 0, enable_count; + + if (!dpu_kms || !dpu_kms->hw_intr || + !dpu_kms->irq_obj.enable_counts || + !dpu_kms->irq_obj.irq_counts) { + DPU_ERROR("invalid params\n"); + return -EINVAL; + } + + if (irq_idx < 0 || irq_idx >= dpu_kms->hw_intr->irq_idx_tbl_size) { + DPU_ERROR("invalid IRQ index: [%d]\n", irq_idx); + return -EINVAL; + } + + enable_count = atomic_read(&dpu_kms->irq_obj.enable_counts[irq_idx]); + DRM_DEBUG_KMS("irq_idx=%d enable_count=%d\n", irq_idx, enable_count); + trace_dpu_core_irq_enable_idx(irq_idx, enable_count); + + if (atomic_inc_return(&dpu_kms->irq_obj.enable_counts[irq_idx]) == 1) { + ret = dpu_kms->hw_intr->ops.enable_irq( + dpu_kms->hw_intr, + irq_idx); + if (ret) + DPU_ERROR("Fail to enable IRQ for irq_idx:%d\n", + irq_idx); + + DPU_DEBUG("irq_idx=%d ret=%d\n", irq_idx, ret); + + spin_lock_irqsave(&dpu_kms->irq_obj.cb_lock, irq_flags); + /* empty callback list but interrupt is enabled */ + if (list_empty(&dpu_kms->irq_obj.irq_cb_tbl[irq_idx])) + DPU_ERROR("irq_idx=%d enabled with no callback\n", + irq_idx); + spin_unlock_irqrestore(&dpu_kms->irq_obj.cb_lock, irq_flags); + } + + return ret; +} + +int dpu_core_irq_enable(struct dpu_kms *dpu_kms, int *irq_idxs, u32 irq_count) +{ + int i, ret = 0, counts; + + if (!dpu_kms || !irq_idxs || !irq_count) { + DPU_ERROR("invalid params\n"); + return -EINVAL; + } + + counts = atomic_read(&dpu_kms->irq_obj.enable_counts[irq_idxs[0]]); + if (counts) + DRM_ERROR("irq_idx=%d enable_count=%d\n", irq_idxs[0], counts); + + for (i = 0; (i < irq_count) && !ret; i++) + ret = _dpu_core_irq_enable(dpu_kms, irq_idxs[i]); + + return ret; +} + +/** + * _dpu_core_irq_disable - disable core interrupt given by the index + * @dpu_kms: Pointer to dpu kms context + * @irq_idx: interrupt index + */ +static int _dpu_core_irq_disable(struct dpu_kms *dpu_kms, int irq_idx) +{ + int ret = 0, enable_count; + + if (!dpu_kms || !dpu_kms->hw_intr || !dpu_kms->irq_obj.enable_counts) { + DPU_ERROR("invalid params\n"); + return -EINVAL; + } + + if (irq_idx < 0 || irq_idx >= dpu_kms->hw_intr->irq_idx_tbl_size) { + DPU_ERROR("invalid IRQ index: [%d]\n", irq_idx); + return -EINVAL; + } + + enable_count = atomic_read(&dpu_kms->irq_obj.enable_counts[irq_idx]); + DRM_DEBUG_KMS("irq_idx=%d enable_count=%d\n", irq_idx, enable_count); + trace_dpu_core_irq_disable_idx(irq_idx, enable_count); + + if (atomic_dec_return(&dpu_kms->irq_obj.enable_counts[irq_idx]) == 0) { + ret = dpu_kms->hw_intr->ops.disable_irq( + dpu_kms->hw_intr, + irq_idx); + if (ret) + DPU_ERROR("Fail to disable IRQ for irq_idx:%d\n", + irq_idx); + DPU_DEBUG("irq_idx=%d ret=%d\n", irq_idx, ret); + } + + return ret; +} + +int dpu_core_irq_disable(struct dpu_kms *dpu_kms, int *irq_idxs, u32 irq_count) +{ + int i, ret = 0, counts; + + if (!dpu_kms || !irq_idxs || !irq_count) { + DPU_ERROR("invalid params\n"); + return -EINVAL; + } + + counts = atomic_read(&dpu_kms->irq_obj.enable_counts[irq_idxs[0]]); + if (counts == 2) + DRM_ERROR("irq_idx=%d enable_count=%d\n", irq_idxs[0], counts); + + for (i = 0; (i < irq_count) && !ret; i++) + ret = _dpu_core_irq_disable(dpu_kms, irq_idxs[i]); + + return ret; +} + +u32 dpu_core_irq_read(struct dpu_kms *dpu_kms, int irq_idx, bool clear) +{ + if (!dpu_kms || !dpu_kms->hw_intr || + !dpu_kms->hw_intr->ops.get_interrupt_status) + return 0; + + if (irq_idx < 0) { + DPU_ERROR("[%pS] invalid irq_idx=%d\n", + __builtin_return_address(0), irq_idx); + return 0; + } + + return dpu_kms->hw_intr->ops.get_interrupt_status(dpu_kms->hw_intr, + irq_idx, clear); +} + +int dpu_core_irq_register_callback(struct dpu_kms *dpu_kms, int irq_idx, + struct dpu_irq_callback *register_irq_cb) +{ + unsigned long irq_flags; + + if (!dpu_kms || !dpu_kms->irq_obj.irq_cb_tbl) { + DPU_ERROR("invalid params\n"); + return -EINVAL; + } + + if (!register_irq_cb || !register_irq_cb->func) { + DPU_ERROR("invalid irq_cb:%d func:%d\n", + register_irq_cb != NULL, + register_irq_cb ? + register_irq_cb->func != NULL : -1); + return -EINVAL; + } + + if (irq_idx < 0 || irq_idx >= dpu_kms->hw_intr->irq_idx_tbl_size) { + DPU_ERROR("invalid IRQ index: [%d]\n", irq_idx); + return -EINVAL; + } + + DPU_DEBUG("[%pS] irq_idx=%d\n", __builtin_return_address(0), irq_idx); + + spin_lock_irqsave(&dpu_kms->irq_obj.cb_lock, irq_flags); + trace_dpu_core_irq_register_callback(irq_idx, register_irq_cb); + list_del_init(®ister_irq_cb->list); + list_add_tail(®ister_irq_cb->list, + &dpu_kms->irq_obj.irq_cb_tbl[irq_idx]); + spin_unlock_irqrestore(&dpu_kms->irq_obj.cb_lock, irq_flags); + + return 0; +} + +int dpu_core_irq_unregister_callback(struct dpu_kms *dpu_kms, int irq_idx, + struct dpu_irq_callback *register_irq_cb) +{ + unsigned long irq_flags; + + if (!dpu_kms || !dpu_kms->irq_obj.irq_cb_tbl) { + DPU_ERROR("invalid params\n"); + return -EINVAL; + } + + if (!register_irq_cb || !register_irq_cb->func) { + DPU_ERROR("invalid irq_cb:%d func:%d\n", + register_irq_cb != NULL, + register_irq_cb ? + register_irq_cb->func != NULL : -1); + return -EINVAL; + } + + if (irq_idx < 0 || irq_idx >= dpu_kms->hw_intr->irq_idx_tbl_size) { + DPU_ERROR("invalid IRQ index: [%d]\n", irq_idx); + return -EINVAL; + } + + DPU_DEBUG("[%pS] irq_idx=%d\n", __builtin_return_address(0), irq_idx); + + spin_lock_irqsave(&dpu_kms->irq_obj.cb_lock, irq_flags); + trace_dpu_core_irq_unregister_callback(irq_idx, register_irq_cb); + list_del_init(®ister_irq_cb->list); + /* empty callback list but interrupt is still enabled */ + if (list_empty(&dpu_kms->irq_obj.irq_cb_tbl[irq_idx]) && + atomic_read(&dpu_kms->irq_obj.enable_counts[irq_idx])) + DPU_ERROR("irq_idx=%d enabled with no callback\n", irq_idx); + spin_unlock_irqrestore(&dpu_kms->irq_obj.cb_lock, irq_flags); + + return 0; +} + +static void dpu_clear_all_irqs(struct dpu_kms *dpu_kms) +{ + if (!dpu_kms || !dpu_kms->hw_intr || + !dpu_kms->hw_intr->ops.clear_all_irqs) + return; + + dpu_kms->hw_intr->ops.clear_all_irqs(dpu_kms->hw_intr); +} + +static void dpu_disable_all_irqs(struct dpu_kms *dpu_kms) +{ + if (!dpu_kms || !dpu_kms->hw_intr || + !dpu_kms->hw_intr->ops.disable_all_irqs) + return; + + dpu_kms->hw_intr->ops.disable_all_irqs(dpu_kms->hw_intr); +} + +#ifdef CONFIG_DEBUG_FS +#define DEFINE_DPU_DEBUGFS_SEQ_FOPS(__prefix) \ +static int __prefix ## _open(struct inode *inode, struct file *file) \ +{ \ + return single_open(file, __prefix ## _show, inode->i_private); \ +} \ +static const struct file_operations __prefix ## _fops = { \ + .owner = THIS_MODULE, \ + .open = __prefix ## _open, \ + .release = single_release, \ + .read = seq_read, \ + .llseek = seq_lseek, \ +} + +static int dpu_debugfs_core_irq_show(struct seq_file *s, void *v) +{ + struct dpu_irq *irq_obj = s->private; + struct dpu_irq_callback *cb; + unsigned long irq_flags; + int i, irq_count, enable_count, cb_count; + + if (!irq_obj || !irq_obj->enable_counts || !irq_obj->irq_cb_tbl) { + DPU_ERROR("invalid parameters\n"); + return 0; + } + + for (i = 0; i < irq_obj->total_irqs; i++) { + spin_lock_irqsave(&irq_obj->cb_lock, irq_flags); + cb_count = 0; + irq_count = atomic_read(&irq_obj->irq_counts[i]); + enable_count = atomic_read(&irq_obj->enable_counts[i]); + list_for_each_entry(cb, &irq_obj->irq_cb_tbl[i], list) + cb_count++; + spin_unlock_irqrestore(&irq_obj->cb_lock, irq_flags); + + if (irq_count || enable_count || cb_count) + seq_printf(s, "idx:%d irq:%d enable:%d cb:%d\n", + i, irq_count, enable_count, cb_count); + } + + return 0; +} + +DEFINE_DPU_DEBUGFS_SEQ_FOPS(dpu_debugfs_core_irq); + +int dpu_debugfs_core_irq_init(struct dpu_kms *dpu_kms, + struct dentry *parent) +{ + dpu_kms->irq_obj.debugfs_file = debugfs_create_file("core_irq", 0600, + parent, &dpu_kms->irq_obj, + &dpu_debugfs_core_irq_fops); + + return 0; +} + +void dpu_debugfs_core_irq_destroy(struct dpu_kms *dpu_kms) +{ + debugfs_remove(dpu_kms->irq_obj.debugfs_file); + dpu_kms->irq_obj.debugfs_file = NULL; +} + +#else +int dpu_debugfs_core_irq_init(struct dpu_kms *dpu_kms, + struct dentry *parent) +{ + return 0; +} + +void dpu_debugfs_core_irq_destroy(struct dpu_kms *dpu_kms) +{ +} +#endif + +void dpu_core_irq_preinstall(struct dpu_kms *dpu_kms) +{ + struct msm_drm_private *priv; + int i; + + if (!dpu_kms) { + DPU_ERROR("invalid dpu_kms\n"); + return; + } else if (!dpu_kms->dev) { + DPU_ERROR("invalid drm device\n"); + return; + } else if (!dpu_kms->dev->dev_private) { + DPU_ERROR("invalid device private\n"); + return; + } + priv = dpu_kms->dev->dev_private; + + pm_runtime_get_sync(&dpu_kms->pdev->dev); + dpu_clear_all_irqs(dpu_kms); + dpu_disable_all_irqs(dpu_kms); + pm_runtime_put_sync(&dpu_kms->pdev->dev); + + spin_lock_init(&dpu_kms->irq_obj.cb_lock); + + /* Create irq callbacks for all possible irq_idx */ + dpu_kms->irq_obj.total_irqs = dpu_kms->hw_intr->irq_idx_tbl_size; + dpu_kms->irq_obj.irq_cb_tbl = kcalloc(dpu_kms->irq_obj.total_irqs, + sizeof(struct list_head), GFP_KERNEL); + dpu_kms->irq_obj.enable_counts = kcalloc(dpu_kms->irq_obj.total_irqs, + sizeof(atomic_t), GFP_KERNEL); + dpu_kms->irq_obj.irq_counts = kcalloc(dpu_kms->irq_obj.total_irqs, + sizeof(atomic_t), GFP_KERNEL); + for (i = 0; i < dpu_kms->irq_obj.total_irqs; i++) { + INIT_LIST_HEAD(&dpu_kms->irq_obj.irq_cb_tbl[i]); + atomic_set(&dpu_kms->irq_obj.enable_counts[i], 0); + atomic_set(&dpu_kms->irq_obj.irq_counts[i], 0); + } +} + +int dpu_core_irq_postinstall(struct dpu_kms *dpu_kms) +{ + return 0; +} + +void dpu_core_irq_uninstall(struct dpu_kms *dpu_kms) +{ + struct msm_drm_private *priv; + int i; + + if (!dpu_kms) { + DPU_ERROR("invalid dpu_kms\n"); + return; + } else if (!dpu_kms->dev) { + DPU_ERROR("invalid drm device\n"); + return; + } else if (!dpu_kms->dev->dev_private) { + DPU_ERROR("invalid device private\n"); + return; + } + priv = dpu_kms->dev->dev_private; + + pm_runtime_get_sync(&dpu_kms->pdev->dev); + for (i = 0; i < dpu_kms->irq_obj.total_irqs; i++) + if (atomic_read(&dpu_kms->irq_obj.enable_counts[i]) || + !list_empty(&dpu_kms->irq_obj.irq_cb_tbl[i])) + DPU_ERROR("irq_idx=%d still enabled/registered\n", i); + + dpu_clear_all_irqs(dpu_kms); + dpu_disable_all_irqs(dpu_kms); + pm_runtime_put_sync(&dpu_kms->pdev->dev); + + kfree(dpu_kms->irq_obj.irq_cb_tbl); + kfree(dpu_kms->irq_obj.enable_counts); + kfree(dpu_kms->irq_obj.irq_counts); + dpu_kms->irq_obj.irq_cb_tbl = NULL; + dpu_kms->irq_obj.enable_counts = NULL; + dpu_kms->irq_obj.irq_counts = NULL; + dpu_kms->irq_obj.total_irqs = 0; +} + +irqreturn_t dpu_core_irq(struct dpu_kms *dpu_kms) +{ + /* + * Read interrupt status from all sources. Interrupt status are + * stored within hw_intr. + * Function will also clear the interrupt status after reading. + * Individual interrupt status bit will only get stored if it + * is enabled. + */ + dpu_kms->hw_intr->ops.get_interrupt_statuses(dpu_kms->hw_intr); + + /* + * Dispatch to HW driver to handle interrupt lookup that is being + * fired. When matching interrupt is located, HW driver will call to + * dpu_core_irq_callback_handler with the irq_idx from the lookup table. + * dpu_core_irq_callback_handler will perform the registered function + * callback, and do the interrupt status clearing once the registered + * callback is finished. + */ + dpu_kms->hw_intr->ops.dispatch_irqs( + dpu_kms->hw_intr, + dpu_core_irq_callback_handler, + dpu_kms); + + return IRQ_HANDLED; +} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.h new file mode 100644 index 0000000000000..5e98bba46af53 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.h @@ -0,0 +1,153 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef __DPU_CORE_IRQ_H__ +#define __DPU_CORE_IRQ_H__ + +#include "dpu_kms.h" +#include "dpu_hw_interrupts.h" + +/** + * dpu_core_irq_preinstall - perform pre-installation of core IRQ handler + * @dpu_kms: DPU handle + * @return: none + */ +void dpu_core_irq_preinstall(struct dpu_kms *dpu_kms); + +/** + * dpu_core_irq_postinstall - perform post-installation of core IRQ handler + * @dpu_kms: DPU handle + * @return: 0 if success; error code otherwise + */ +int dpu_core_irq_postinstall(struct dpu_kms *dpu_kms); + +/** + * dpu_core_irq_uninstall - uninstall core IRQ handler + * @dpu_kms: DPU handle + * @return: none + */ +void dpu_core_irq_uninstall(struct dpu_kms *dpu_kms); + +/** + * dpu_core_irq - core IRQ handler + * @dpu_kms: DPU handle + * @return: interrupt handling status + */ +irqreturn_t dpu_core_irq(struct dpu_kms *dpu_kms); + +/** + * dpu_core_irq_idx_lookup - IRQ helper function for lookup irq_idx from HW + * interrupt mapping table. + * @dpu_kms: DPU handle + * @intr_type: DPU HW interrupt type for lookup + * @instance_idx: DPU HW block instance defined in dpu_hw_mdss.h + * @return: irq_idx or -EINVAL when fail to lookup + */ +int dpu_core_irq_idx_lookup( + struct dpu_kms *dpu_kms, + enum dpu_intr_type intr_type, + uint32_t instance_idx); + +/** + * dpu_core_irq_enable - IRQ helper function for enabling one or more IRQs + * @dpu_kms: DPU handle + * @irq_idxs: Array of irq index + * @irq_count: Number of irq_idx provided in the array + * @return: 0 for success enabling IRQ, otherwise failure + * + * This function increments count on each enable and decrements on each + * disable. Interrupts is enabled if count is 0 before increment. + */ +int dpu_core_irq_enable( + struct dpu_kms *dpu_kms, + int *irq_idxs, + uint32_t irq_count); + +/** + * dpu_core_irq_disable - IRQ helper function for disabling one of more IRQs + * @dpu_kms: DPU handle + * @irq_idxs: Array of irq index + * @irq_count: Number of irq_idx provided in the array + * @return: 0 for success disabling IRQ, otherwise failure + * + * This function increments count on each enable and decrements on each + * disable. Interrupts is disabled if count is 0 after decrement. + */ +int dpu_core_irq_disable( + struct dpu_kms *dpu_kms, + int *irq_idxs, + uint32_t irq_count); + +/** + * dpu_core_irq_read - IRQ helper function for reading IRQ status + * @dpu_kms: DPU handle + * @irq_idx: irq index + * @clear: True to clear the irq after read + * @return: non-zero if irq detected; otherwise no irq detected + */ +u32 dpu_core_irq_read( + struct dpu_kms *dpu_kms, + int irq_idx, + bool clear); + +/** + * dpu_core_irq_register_callback - For registering callback function on IRQ + * interrupt + * @dpu_kms: DPU handle + * @irq_idx: irq index + * @irq_cb: IRQ callback structure, containing callback function + * and argument. Passing NULL for irq_cb will unregister + * the callback for the given irq_idx + * This must exist until un-registration. + * @return: 0 for success registering callback, otherwise failure + * + * This function supports registration of multiple callbacks for each interrupt. + */ +int dpu_core_irq_register_callback( + struct dpu_kms *dpu_kms, + int irq_idx, + struct dpu_irq_callback *irq_cb); + +/** + * dpu_core_irq_unregister_callback - For unregistering callback function on IRQ + * interrupt + * @dpu_kms: DPU handle + * @irq_idx: irq index + * @irq_cb: IRQ callback structure, containing callback function + * and argument. Passing NULL for irq_cb will unregister + * the callback for the given irq_idx + * This must match with registration. + * @return: 0 for success registering callback, otherwise failure + * + * This function supports registration of multiple callbacks for each interrupt. + */ +int dpu_core_irq_unregister_callback( + struct dpu_kms *dpu_kms, + int irq_idx, + struct dpu_irq_callback *irq_cb); + +/** + * dpu_debugfs_core_irq_init - register core irq debugfs + * @dpu_kms: pointer to kms + * @parent: debugfs directory root + * @Return: 0 on success + */ +int dpu_debugfs_core_irq_init(struct dpu_kms *dpu_kms, + struct dentry *parent); + +/** + * dpu_debugfs_core_irq_destroy - deregister core irq debugfs + * @dpu_kms: pointer to kms + */ +void dpu_debugfs_core_irq_destroy(struct dpu_kms *dpu_kms); + +#endif /* __DPU_CORE_IRQ_H__ */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c new file mode 100644 index 0000000000000..41c5191f9056c --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c @@ -0,0 +1,637 @@ +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ + +#include <linux/debugfs.h> +#include <linux/errno.h> +#include <linux/mutex.h> +#include <linux/sort.h> +#include <linux/clk.h> +#include <linux/bitmap.h> + +#include "dpu_kms.h" +#include "dpu_trace.h" +#include "dpu_crtc.h" +#include "dpu_core_perf.h" + +#define DPU_PERF_MODE_STRING_SIZE 128 + +/** + * enum dpu_perf_mode - performance tuning mode + * @DPU_PERF_MODE_NORMAL: performance controlled by user mode client + * @DPU_PERF_MODE_MINIMUM: performance bounded by minimum setting + * @DPU_PERF_MODE_FIXED: performance bounded by fixed setting + */ +enum dpu_perf_mode { + DPU_PERF_MODE_NORMAL, + DPU_PERF_MODE_MINIMUM, + DPU_PERF_MODE_FIXED, + DPU_PERF_MODE_MAX +}; + +static struct dpu_kms *_dpu_crtc_get_kms(struct drm_crtc *crtc) +{ + struct msm_drm_private *priv; + + if (!crtc->dev || !crtc->dev->dev_private) { + DPU_ERROR("invalid device\n"); + return NULL; + } + + priv = crtc->dev->dev_private; + if (!priv || !priv->kms) { + DPU_ERROR("invalid kms\n"); + return NULL; + } + + return to_dpu_kms(priv->kms); +} + +static bool _dpu_core_perf_crtc_is_power_on(struct drm_crtc *crtc) +{ + return dpu_crtc_is_enabled(crtc); +} + +static bool _dpu_core_video_mode_intf_connected(struct drm_crtc *crtc) +{ + struct drm_crtc *tmp_crtc; + bool intf_connected = false; + + if (!crtc) + goto end; + + drm_for_each_crtc(tmp_crtc, crtc->dev) { + if ((dpu_crtc_get_intf_mode(tmp_crtc) == INTF_MODE_VIDEO) && + _dpu_core_perf_crtc_is_power_on(tmp_crtc)) { + DPU_DEBUG("video interface connected crtc:%d\n", + tmp_crtc->base.id); + intf_connected = true; + goto end; + } + } + +end: + return intf_connected; +} + +static void _dpu_core_perf_calc_crtc(struct dpu_kms *kms, + struct drm_crtc *crtc, + struct drm_crtc_state *state, + struct dpu_core_perf_params *perf) +{ + struct dpu_crtc_state *dpu_cstate; + int i; + + if (!kms || !kms->catalog || !crtc || !state || !perf) { + DPU_ERROR("invalid parameters\n"); + return; + } + + dpu_cstate = to_dpu_crtc_state(state); + memset(perf, 0, sizeof(struct dpu_core_perf_params)); + + if (!dpu_cstate->bw_control) { + for (i = 0; i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) { + perf->bw_ctl[i] = kms->catalog->perf.max_bw_high * + 1000ULL; + perf->max_per_pipe_ib[i] = perf->bw_ctl[i]; + } + perf->core_clk_rate = kms->perf.max_core_clk_rate; + } else if (kms->perf.perf_tune.mode == DPU_PERF_MODE_MINIMUM) { + for (i = 0; i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) { + perf->bw_ctl[i] = 0; + perf->max_per_pipe_ib[i] = 0; + } + perf->core_clk_rate = 0; + } else if (kms->perf.perf_tune.mode == DPU_PERF_MODE_FIXED) { + for (i = 0; i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) { + perf->bw_ctl[i] = kms->perf.fix_core_ab_vote; + perf->max_per_pipe_ib[i] = kms->perf.fix_core_ib_vote; + } + perf->core_clk_rate = kms->perf.fix_core_clk_rate; + } + + DPU_DEBUG( + "crtc=%d clk_rate=%llu core_ib=%llu core_ab=%llu llcc_ib=%llu llcc_ab=%llu mem_ib=%llu mem_ab=%llu\n", + crtc->base.id, perf->core_clk_rate, + perf->max_per_pipe_ib[DPU_POWER_HANDLE_DBUS_ID_MNOC], + perf->bw_ctl[DPU_POWER_HANDLE_DBUS_ID_MNOC], + perf->max_per_pipe_ib[DPU_POWER_HANDLE_DBUS_ID_LLCC], + perf->bw_ctl[DPU_POWER_HANDLE_DBUS_ID_LLCC], + perf->max_per_pipe_ib[DPU_POWER_HANDLE_DBUS_ID_EBI], + perf->bw_ctl[DPU_POWER_HANDLE_DBUS_ID_EBI]); +} + +int dpu_core_perf_crtc_check(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + u32 bw, threshold; + u64 bw_sum_of_intfs = 0; + enum dpu_crtc_client_type curr_client_type; + bool is_video_mode; + struct dpu_crtc_state *dpu_cstate; + struct drm_crtc *tmp_crtc; + struct dpu_kms *kms; + int i; + + if (!crtc || !state) { + DPU_ERROR("invalid crtc\n"); + return -EINVAL; + } + + kms = _dpu_crtc_get_kms(crtc); + if (!kms || !kms->catalog) { + DPU_ERROR("invalid parameters\n"); + return 0; + } + + /* we only need bandwidth check on real-time clients (interfaces) */ + if (dpu_crtc_get_client_type(crtc) == NRT_CLIENT) + return 0; + + dpu_cstate = to_dpu_crtc_state(state); + + /* obtain new values */ + _dpu_core_perf_calc_crtc(kms, crtc, state, &dpu_cstate->new_perf); + + for (i = DPU_POWER_HANDLE_DBUS_ID_MNOC; + i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) { + bw_sum_of_intfs = dpu_cstate->new_perf.bw_ctl[i]; + curr_client_type = dpu_crtc_get_client_type(crtc); + + drm_for_each_crtc(tmp_crtc, crtc->dev) { + if (_dpu_core_perf_crtc_is_power_on(tmp_crtc) && + (dpu_crtc_get_client_type(tmp_crtc) == + curr_client_type) && + (tmp_crtc != crtc)) { + struct dpu_crtc_state *tmp_cstate = + to_dpu_crtc_state(tmp_crtc->state); + + DPU_DEBUG("crtc:%d bw:%llu ctrl:%d\n", + tmp_crtc->base.id, + tmp_cstate->new_perf.bw_ctl[i], + tmp_cstate->bw_control); + /* + * For bw check only use the bw if the + * atomic property has been already set + */ + if (tmp_cstate->bw_control) + bw_sum_of_intfs += + tmp_cstate->new_perf.bw_ctl[i]; + } + } + + /* convert bandwidth to kb */ + bw = DIV_ROUND_UP_ULL(bw_sum_of_intfs, 1000); + DPU_DEBUG("calculated bandwidth=%uk\n", bw); + + is_video_mode = dpu_crtc_get_intf_mode(crtc) == INTF_MODE_VIDEO; + threshold = (is_video_mode || + _dpu_core_video_mode_intf_connected(crtc)) ? + kms->catalog->perf.max_bw_low : + kms->catalog->perf.max_bw_high; + + DPU_DEBUG("final threshold bw limit = %d\n", threshold); + + if (!dpu_cstate->bw_control) { + DPU_DEBUG("bypass bandwidth check\n"); + } else if (!threshold) { + DPU_ERROR("no bandwidth limits specified\n"); + return -E2BIG; + } else if (bw > threshold) { + DPU_ERROR("exceeds bandwidth: %ukb > %ukb\n", bw, + threshold); + return -E2BIG; + } + } + + return 0; +} + +static int _dpu_core_perf_crtc_update_bus(struct dpu_kms *kms, + struct drm_crtc *crtc, u32 bus_id) +{ + struct dpu_core_perf_params perf = { { 0 } }; + enum dpu_crtc_client_type curr_client_type + = dpu_crtc_get_client_type(crtc); + struct drm_crtc *tmp_crtc; + struct dpu_crtc_state *dpu_cstate; + int ret = 0; + + drm_for_each_crtc(tmp_crtc, crtc->dev) { + if (_dpu_core_perf_crtc_is_power_on(tmp_crtc) && + curr_client_type == + dpu_crtc_get_client_type(tmp_crtc)) { + dpu_cstate = to_dpu_crtc_state(tmp_crtc->state); + + perf.max_per_pipe_ib[bus_id] = + max(perf.max_per_pipe_ib[bus_id], + dpu_cstate->new_perf.max_per_pipe_ib[bus_id]); + + DPU_DEBUG("crtc=%d bus_id=%d bw=%llu\n", + tmp_crtc->base.id, bus_id, + dpu_cstate->new_perf.bw_ctl[bus_id]); + } + } + return ret; +} + +/** + * @dpu_core_perf_crtc_release_bw() - request zero bandwidth + * @crtc - pointer to a crtc + * + * Function checks a state variable for the crtc, if all pending commit + * requests are done, meaning no more bandwidth is needed, release + * bandwidth request. + */ +void dpu_core_perf_crtc_release_bw(struct drm_crtc *crtc) +{ + struct drm_crtc *tmp_crtc; + struct dpu_crtc *dpu_crtc; + struct dpu_crtc_state *dpu_cstate; + struct dpu_kms *kms; + int i; + + if (!crtc) { + DPU_ERROR("invalid crtc\n"); + return; + } + + kms = _dpu_crtc_get_kms(crtc); + if (!kms || !kms->catalog) { + DPU_ERROR("invalid kms\n"); + return; + } + + dpu_crtc = to_dpu_crtc(crtc); + dpu_cstate = to_dpu_crtc_state(crtc->state); + + /* only do this for command mode rt client */ + if (dpu_crtc_get_intf_mode(crtc) != INTF_MODE_CMD) + return; + + /* + * If video interface present, cmd panel bandwidth cannot be + * released. + */ + if (dpu_crtc_get_intf_mode(crtc) == INTF_MODE_CMD) + drm_for_each_crtc(tmp_crtc, crtc->dev) { + if (_dpu_core_perf_crtc_is_power_on(tmp_crtc) && + dpu_crtc_get_intf_mode(tmp_crtc) == + INTF_MODE_VIDEO) + return; + } + + /* Release the bandwidth */ + if (kms->perf.enable_bw_release) { + trace_dpu_cmd_release_bw(crtc->base.id); + DPU_DEBUG("Release BW crtc=%d\n", crtc->base.id); + for (i = 0; i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) { + dpu_crtc->cur_perf.bw_ctl[i] = 0; + _dpu_core_perf_crtc_update_bus(kms, crtc, i); + } + } +} + +static int _dpu_core_perf_set_core_clk_rate(struct dpu_kms *kms, u64 rate) +{ + struct dss_clk *core_clk = kms->perf.core_clk; + + if (core_clk->max_rate && (rate > core_clk->max_rate)) + rate = core_clk->max_rate; + + core_clk->rate = rate; + return msm_dss_clk_set_rate(core_clk, 1); +} + +static u64 _dpu_core_perf_get_core_clk_rate(struct dpu_kms *kms) +{ + u64 clk_rate = kms->perf.perf_tune.min_core_clk; + struct drm_crtc *crtc; + struct dpu_crtc_state *dpu_cstate; + + drm_for_each_crtc(crtc, kms->dev) { + if (_dpu_core_perf_crtc_is_power_on(crtc)) { + dpu_cstate = to_dpu_crtc_state(crtc->state); + clk_rate = max(dpu_cstate->new_perf.core_clk_rate, + clk_rate); + clk_rate = clk_round_rate(kms->perf.core_clk->clk, + clk_rate); + } + } + + if (kms->perf.perf_tune.mode == DPU_PERF_MODE_FIXED) + clk_rate = kms->perf.fix_core_clk_rate; + + DPU_DEBUG("clk:%llu\n", clk_rate); + + return clk_rate; +} + +int dpu_core_perf_crtc_update(struct drm_crtc *crtc, + int params_changed, bool stop_req) +{ + struct dpu_core_perf_params *new, *old; + int update_bus = 0, update_clk = 0; + u64 clk_rate = 0; + struct dpu_crtc *dpu_crtc; + struct dpu_crtc_state *dpu_cstate; + int i; + struct msm_drm_private *priv; + struct dpu_kms *kms; + int ret; + + if (!crtc) { + DPU_ERROR("invalid crtc\n"); + return -EINVAL; + } + + kms = _dpu_crtc_get_kms(crtc); + if (!kms || !kms->catalog) { + DPU_ERROR("invalid kms\n"); + return -EINVAL; + } + priv = kms->dev->dev_private; + + dpu_crtc = to_dpu_crtc(crtc); + dpu_cstate = to_dpu_crtc_state(crtc->state); + + DPU_DEBUG("crtc:%d stop_req:%d core_clk:%llu\n", + crtc->base.id, stop_req, kms->perf.core_clk_rate); + + old = &dpu_crtc->cur_perf; + new = &dpu_cstate->new_perf; + + if (_dpu_core_perf_crtc_is_power_on(crtc) && !stop_req) { + for (i = 0; i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) { + /* + * cases for bus bandwidth update. + * 1. new bandwidth vote - "ab or ib vote" is higher + * than current vote for update request. + * 2. new bandwidth vote - "ab or ib vote" is lower + * than current vote at end of commit or stop. + */ + if ((params_changed && ((new->bw_ctl[i] > + old->bw_ctl[i]) || + (new->max_per_pipe_ib[i] > + old->max_per_pipe_ib[i]))) || + (!params_changed && ((new->bw_ctl[i] < + old->bw_ctl[i]) || + (new->max_per_pipe_ib[i] < + old->max_per_pipe_ib[i])))) { + DPU_DEBUG( + "crtc=%d p=%d new_bw=%llu,old_bw=%llu\n", + crtc->base.id, params_changed, + new->bw_ctl[i], old->bw_ctl[i]); + old->bw_ctl[i] = new->bw_ctl[i]; + old->max_per_pipe_ib[i] = + new->max_per_pipe_ib[i]; + update_bus |= BIT(i); + } + } + + if ((params_changed && + (new->core_clk_rate > old->core_clk_rate)) || + (!params_changed && + (new->core_clk_rate < old->core_clk_rate))) { + old->core_clk_rate = new->core_clk_rate; + update_clk = 1; + } + } else { + DPU_DEBUG("crtc=%d disable\n", crtc->base.id); + memset(old, 0, sizeof(*old)); + memset(new, 0, sizeof(*new)); + update_bus = ~0; + update_clk = 1; + } + trace_dpu_perf_crtc_update(crtc->base.id, + new->bw_ctl[DPU_POWER_HANDLE_DBUS_ID_MNOC], + new->bw_ctl[DPU_POWER_HANDLE_DBUS_ID_LLCC], + new->bw_ctl[DPU_POWER_HANDLE_DBUS_ID_EBI], + new->core_clk_rate, stop_req, + update_bus, update_clk); + + for (i = 0; i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) { + if (update_bus & BIT(i)) { + ret = _dpu_core_perf_crtc_update_bus(kms, crtc, i); + if (ret) { + DPU_ERROR("crtc-%d: failed to update bw vote for bus-%d\n", + crtc->base.id, i); + return ret; + } + } + } + + /* + * Update the clock after bandwidth vote to ensure + * bandwidth is available before clock rate is increased. + */ + if (update_clk) { + clk_rate = _dpu_core_perf_get_core_clk_rate(kms); + + trace_dpu_core_perf_update_clk(kms->dev, stop_req, clk_rate); + + ret = _dpu_core_perf_set_core_clk_rate(kms, clk_rate); + if (ret) { + DPU_ERROR("failed to set %s clock rate %llu\n", + kms->perf.core_clk->clk_name, clk_rate); + return ret; + } + + kms->perf.core_clk_rate = clk_rate; + DPU_DEBUG("update clk rate = %lld HZ\n", clk_rate); + } + return 0; +} + +#ifdef CONFIG_DEBUG_FS + +static ssize_t _dpu_core_perf_mode_write(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + struct dpu_core_perf *perf = file->private_data; + struct dpu_perf_cfg *cfg = &perf->catalog->perf; + u32 perf_mode = 0; + char buf[10]; + + if (!perf) + return -ENODEV; + + if (count >= sizeof(buf)) + return -EFAULT; + + if (copy_from_user(buf, user_buf, count)) + return -EFAULT; + + buf[count] = 0; /* end of string */ + + if (kstrtouint(buf, 0, &perf_mode)) + return -EFAULT; + + if (perf_mode >= DPU_PERF_MODE_MAX) + return -EFAULT; + + if (perf_mode == DPU_PERF_MODE_FIXED) { + DRM_INFO("fix performance mode\n"); + } else if (perf_mode == DPU_PERF_MODE_MINIMUM) { + /* run the driver with max clk and BW vote */ + perf->perf_tune.min_core_clk = perf->max_core_clk_rate; + perf->perf_tune.min_bus_vote = + (u64) cfg->max_bw_high * 1000; + DRM_INFO("minimum performance mode\n"); + } else if (perf_mode == DPU_PERF_MODE_NORMAL) { + /* reset the perf tune params to 0 */ + perf->perf_tune.min_core_clk = 0; + perf->perf_tune.min_bus_vote = 0; + DRM_INFO("normal performance mode\n"); + } + perf->perf_tune.mode = perf_mode; + + return count; +} + +static ssize_t _dpu_core_perf_mode_read(struct file *file, + char __user *buff, size_t count, loff_t *ppos) +{ + struct dpu_core_perf *perf = file->private_data; + int len = 0; + char buf[DPU_PERF_MODE_STRING_SIZE] = {'\0'}; + + if (!perf) + return -ENODEV; + + if (*ppos) + return 0; /* the end */ + + len = snprintf(buf, sizeof(buf), + "mode %d min_mdp_clk %llu min_bus_vote %llu\n", + perf->perf_tune.mode, + perf->perf_tune.min_core_clk, + perf->perf_tune.min_bus_vote); + if (len < 0 || len >= sizeof(buf)) + return 0; + + if ((count < sizeof(buf)) || copy_to_user(buff, buf, len)) + return -EFAULT; + + *ppos += len; /* increase offset */ + + return len; +} + +static const struct file_operations dpu_core_perf_mode_fops = { + .open = simple_open, + .read = _dpu_core_perf_mode_read, + .write = _dpu_core_perf_mode_write, +}; + +static void dpu_core_perf_debugfs_destroy(struct dpu_core_perf *perf) +{ + debugfs_remove_recursive(perf->debugfs_root); + perf->debugfs_root = NULL; +} + +int dpu_core_perf_debugfs_init(struct dpu_core_perf *perf, + struct dentry *parent) +{ + struct dpu_mdss_cfg *catalog = perf->catalog; + struct msm_drm_private *priv; + struct dpu_kms *dpu_kms; + + priv = perf->dev->dev_private; + if (!priv || !priv->kms) { + DPU_ERROR("invalid KMS reference\n"); + return -EINVAL; + } + + dpu_kms = to_dpu_kms(priv->kms); + + perf->debugfs_root = debugfs_create_dir("core_perf", parent); + if (!perf->debugfs_root) { + DPU_ERROR("failed to create core perf debugfs\n"); + return -EINVAL; + } + + debugfs_create_u64("max_core_clk_rate", 0600, perf->debugfs_root, + &perf->max_core_clk_rate); + debugfs_create_u64("core_clk_rate", 0600, perf->debugfs_root, + &perf->core_clk_rate); + debugfs_create_u32("enable_bw_release", 0600, perf->debugfs_root, + (u32 *)&perf->enable_bw_release); + debugfs_create_u32("threshold_low", 0600, perf->debugfs_root, + (u32 *)&catalog->perf.max_bw_low); + debugfs_create_u32("threshold_high", 0600, perf->debugfs_root, + (u32 *)&catalog->perf.max_bw_high); + debugfs_create_u32("min_core_ib", 0600, perf->debugfs_root, + (u32 *)&catalog->perf.min_core_ib); + debugfs_create_u32("min_llcc_ib", 0600, perf->debugfs_root, + (u32 *)&catalog->perf.min_llcc_ib); + debugfs_create_u32("min_dram_ib", 0600, perf->debugfs_root, + (u32 *)&catalog->perf.min_dram_ib); + debugfs_create_file("perf_mode", 0600, perf->debugfs_root, + (u32 *)perf, &dpu_core_perf_mode_fops); + debugfs_create_u64("fix_core_clk_rate", 0600, perf->debugfs_root, + &perf->fix_core_clk_rate); + debugfs_create_u64("fix_core_ib_vote", 0600, perf->debugfs_root, + &perf->fix_core_ib_vote); + debugfs_create_u64("fix_core_ab_vote", 0600, perf->debugfs_root, + &perf->fix_core_ab_vote); + + return 0; +} +#else +static void dpu_core_perf_debugfs_destroy(struct dpu_core_perf *perf) +{ +} + +int dpu_core_perf_debugfs_init(struct dpu_core_perf *perf, + struct dentry *parent) +{ + return 0; +} +#endif + +void dpu_core_perf_destroy(struct dpu_core_perf *perf) +{ + if (!perf) { + DPU_ERROR("invalid parameters\n"); + return; + } + + dpu_core_perf_debugfs_destroy(perf); + perf->max_core_clk_rate = 0; + perf->core_clk = NULL; + perf->phandle = NULL; + perf->catalog = NULL; + perf->dev = NULL; +} + +int dpu_core_perf_init(struct dpu_core_perf *perf, + struct drm_device *dev, + struct dpu_mdss_cfg *catalog, + struct dpu_power_handle *phandle, + struct dss_clk *core_clk) +{ + perf->dev = dev; + perf->catalog = catalog; + perf->phandle = phandle; + perf->core_clk = core_clk; + + perf->max_core_clk_rate = core_clk->max_rate; + if (!perf->max_core_clk_rate) { + DPU_DEBUG("optional max core clk rate, use default\n"); + perf->max_core_clk_rate = DPU_PERF_DEFAULT_MAX_CORE_CLK_RATE; + } + + return 0; +} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.h new file mode 100644 index 0000000000000..fbcbe0c7527af --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.h @@ -0,0 +1,133 @@ +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef _DPU_CORE_PERF_H_ +#define _DPU_CORE_PERF_H_ + +#include <linux/types.h> +#include <linux/dcache.h> +#include <linux/mutex.h> +#include <drm/drm_crtc.h> + +#include "dpu_hw_catalog.h" +#include "dpu_power_handle.h" + +#define DPU_PERF_DEFAULT_MAX_CORE_CLK_RATE 412500000 + +/** + * struct dpu_core_perf_params - definition of performance parameters + * @max_per_pipe_ib: maximum instantaneous bandwidth request + * @bw_ctl: arbitrated bandwidth request + * @core_clk_rate: core clock rate request + */ +struct dpu_core_perf_params { + u64 max_per_pipe_ib[DPU_POWER_HANDLE_DBUS_ID_MAX]; + u64 bw_ctl[DPU_POWER_HANDLE_DBUS_ID_MAX]; + u64 core_clk_rate; +}; + +/** + * struct dpu_core_perf_tune - definition of performance tuning control + * @mode: performance mode + * @min_core_clk: minimum core clock + * @min_bus_vote: minimum bus vote + */ +struct dpu_core_perf_tune { + u32 mode; + u64 min_core_clk; + u64 min_bus_vote; +}; + +/** + * struct dpu_core_perf - definition of core performance context + * @dev: Pointer to drm device + * @debugfs_root: top level debug folder + * @catalog: Pointer to catalog configuration + * @phandle: Pointer to power handler + * @core_clk: Pointer to core clock structure + * @core_clk_rate: current core clock rate + * @max_core_clk_rate: maximum allowable core clock rate + * @perf_tune: debug control for performance tuning + * @enable_bw_release: debug control for bandwidth release + * @fix_core_clk_rate: fixed core clock request in Hz used in mode 2 + * @fix_core_ib_vote: fixed core ib vote in bps used in mode 2 + * @fix_core_ab_vote: fixed core ab vote in bps used in mode 2 + */ +struct dpu_core_perf { + struct drm_device *dev; + struct dentry *debugfs_root; + struct dpu_mdss_cfg *catalog; + struct dpu_power_handle *phandle; + struct dss_clk *core_clk; + u64 core_clk_rate; + u64 max_core_clk_rate; + struct dpu_core_perf_tune perf_tune; + u32 enable_bw_release; + u64 fix_core_clk_rate; + u64 fix_core_ib_vote; + u64 fix_core_ab_vote; +}; + +/** + * dpu_core_perf_crtc_check - validate performance of the given crtc state + * @crtc: Pointer to crtc + * @state: Pointer to new crtc state + * return: zero if success, or error code otherwise + */ +int dpu_core_perf_crtc_check(struct drm_crtc *crtc, + struct drm_crtc_state *state); + +/** + * dpu_core_perf_crtc_update - update performance of the given crtc + * @crtc: Pointer to crtc + * @params_changed: true if crtc parameters are modified + * @stop_req: true if this is a stop request + * return: zero if success, or error code otherwise + */ +int dpu_core_perf_crtc_update(struct drm_crtc *crtc, + int params_changed, bool stop_req); + +/** + * dpu_core_perf_crtc_release_bw - release bandwidth of the given crtc + * @crtc: Pointer to crtc + */ +void dpu_core_perf_crtc_release_bw(struct drm_crtc *crtc); + +/** + * dpu_core_perf_destroy - destroy the given core performance context + * @perf: Pointer to core performance context + */ +void dpu_core_perf_destroy(struct dpu_core_perf *perf); + +/** + * dpu_core_perf_init - initialize the given core performance context + * @perf: Pointer to core performance context + * @dev: Pointer to drm device + * @catalog: Pointer to catalog + * @phandle: Pointer to power handle + * @core_clk: pointer to core clock + */ +int dpu_core_perf_init(struct dpu_core_perf *perf, + struct drm_device *dev, + struct dpu_mdss_cfg *catalog, + struct dpu_power_handle *phandle, + struct dss_clk *core_clk); + +/** + * dpu_core_perf_debugfs_init - initialize debugfs for core performance context + * @perf: Pointer to core performance context + * @debugfs_parent: Pointer to parent debugfs + */ +int dpu_core_perf_debugfs_init(struct dpu_core_perf *perf, + struct dentry *parent); + +#endif /* _DPU_CORE_PERF_H_ */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c new file mode 100644 index 0000000000000..bcc4796cb5da8 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -0,0 +1,2504 @@ +/* + * Copyright (c) 2014-2018 The Linux Foundation. All rights reserved. + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.com> + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ +#include <linux/sort.h> +#include <linux/debugfs.h> +#include <linux/ktime.h> +#include <drm/drm_mode.h> +#include <drm/drm_crtc.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_flip_work.h> +#include <drm/drm_rect.h> + +#include "dpu_kms.h" +#include "dpu_hw_lm.h" +#include "dpu_hw_ctl.h" +#include "dpu_crtc.h" +#include "dpu_plane.h" +#include "dpu_encoder.h" +#include "dpu_vbif.h" +#include "dpu_power_handle.h" +#include "dpu_core_perf.h" +#include "dpu_trace.h" + +#define DPU_DRM_BLEND_OP_NOT_DEFINED 0 +#define DPU_DRM_BLEND_OP_OPAQUE 1 +#define DPU_DRM_BLEND_OP_PREMULTIPLIED 2 +#define DPU_DRM_BLEND_OP_COVERAGE 3 +#define DPU_DRM_BLEND_OP_MAX 4 + +/* layer mixer index on dpu_crtc */ +#define LEFT_MIXER 0 +#define RIGHT_MIXER 1 + +#define MISR_BUFF_SIZE 256 + +static inline struct dpu_kms *_dpu_crtc_get_kms(struct drm_crtc *crtc) +{ + struct msm_drm_private *priv; + + if (!crtc || !crtc->dev || !crtc->dev->dev_private) { + DPU_ERROR("invalid crtc\n"); + return NULL; + } + priv = crtc->dev->dev_private; + if (!priv || !priv->kms) { + DPU_ERROR("invalid kms\n"); + return NULL; + } + + return to_dpu_kms(priv->kms); +} + +static inline int _dpu_crtc_power_enable(struct dpu_crtc *dpu_crtc, bool enable) +{ + struct drm_crtc *crtc; + struct msm_drm_private *priv; + struct dpu_kms *dpu_kms; + + if (!dpu_crtc) { + DPU_ERROR("invalid dpu crtc\n"); + return -EINVAL; + } + + crtc = &dpu_crtc->base; + if (!crtc->dev || !crtc->dev->dev_private) { + DPU_ERROR("invalid drm device\n"); + return -EINVAL; + } + + priv = crtc->dev->dev_private; + if (!priv->kms) { + DPU_ERROR("invalid kms\n"); + return -EINVAL; + } + + dpu_kms = to_dpu_kms(priv->kms); + + if (enable) + pm_runtime_get_sync(&dpu_kms->pdev->dev); + else + pm_runtime_put_sync(&dpu_kms->pdev->dev); + + return 0; +} + +/** + * _dpu_crtc_rp_to_crtc - get crtc from resource pool object + * @rp: Pointer to resource pool + * return: Pointer to drm crtc if success; null otherwise + */ +static struct drm_crtc *_dpu_crtc_rp_to_crtc(struct dpu_crtc_respool *rp) +{ + if (!rp) + return NULL; + + return container_of(rp, struct dpu_crtc_state, rp)->base.crtc; +} + +/** + * _dpu_crtc_rp_reclaim - reclaim unused, or all if forced, resources in pool + * @rp: Pointer to resource pool + * @force: True to reclaim all resources; otherwise, reclaim only unused ones + * return: None + */ +static void _dpu_crtc_rp_reclaim(struct dpu_crtc_respool *rp, bool force) +{ + struct dpu_crtc_res *res, *next; + struct drm_crtc *crtc; + + crtc = _dpu_crtc_rp_to_crtc(rp); + if (!crtc) { + DPU_ERROR("invalid crtc\n"); + return; + } + + DPU_DEBUG("crtc%d.%u %s\n", crtc->base.id, rp->sequence_id, + force ? "destroy" : "free_unused"); + + list_for_each_entry_safe(res, next, &rp->res_list, list) { + if (!force && !(res->flags & DPU_CRTC_RES_FLAG_FREE)) + continue; + DPU_DEBUG("crtc%d.%u reclaim res:0x%x/0x%llx/%pK/%d\n", + crtc->base.id, rp->sequence_id, + res->type, res->tag, res->val, + atomic_read(&res->refcount)); + list_del(&res->list); + if (res->ops.put) + res->ops.put(res->val); + kfree(res); + } +} + +/** + * _dpu_crtc_rp_free_unused - free unused resource in pool + * @rp: Pointer to resource pool + * return: none + */ +static void _dpu_crtc_rp_free_unused(struct dpu_crtc_respool *rp) +{ + mutex_lock(rp->rp_lock); + _dpu_crtc_rp_reclaim(rp, false); + mutex_unlock(rp->rp_lock); +} + +/** + * _dpu_crtc_rp_destroy - destroy resource pool + * @rp: Pointer to resource pool + * return: None + */ +static void _dpu_crtc_rp_destroy(struct dpu_crtc_respool *rp) +{ + mutex_lock(rp->rp_lock); + list_del_init(&rp->rp_list); + _dpu_crtc_rp_reclaim(rp, true); + mutex_unlock(rp->rp_lock); +} + +/** + * _dpu_crtc_hw_blk_get - get callback for hardware block + * @val: Resource handle + * @type: Resource type + * @tag: Search tag for given resource + * return: Resource handle + */ +static void *_dpu_crtc_hw_blk_get(void *val, u32 type, u64 tag) +{ + DPU_DEBUG("res:%d/0x%llx/%pK\n", type, tag, val); + return dpu_hw_blk_get(val, type, tag); +} + +/** + * _dpu_crtc_hw_blk_put - put callback for hardware block + * @val: Resource handle + * return: None + */ +static void _dpu_crtc_hw_blk_put(void *val) +{ + DPU_DEBUG("res://%pK\n", val); + dpu_hw_blk_put(val); +} + +/** + * _dpu_crtc_rp_duplicate - duplicate resource pool and reset reference count + * @rp: Pointer to original resource pool + * @dup_rp: Pointer to duplicated resource pool + * return: None + */ +static void _dpu_crtc_rp_duplicate(struct dpu_crtc_respool *rp, + struct dpu_crtc_respool *dup_rp) +{ + struct dpu_crtc_res *res, *dup_res; + struct drm_crtc *crtc; + + if (!rp || !dup_rp || !rp->rp_head) { + DPU_ERROR("invalid resource pool\n"); + return; + } + + crtc = _dpu_crtc_rp_to_crtc(rp); + if (!crtc) { + DPU_ERROR("invalid crtc\n"); + return; + } + + DPU_DEBUG("crtc%d.%u duplicate\n", crtc->base.id, rp->sequence_id); + + mutex_lock(rp->rp_lock); + dup_rp->sequence_id = rp->sequence_id + 1; + INIT_LIST_HEAD(&dup_rp->res_list); + dup_rp->ops = rp->ops; + list_for_each_entry(res, &rp->res_list, list) { + dup_res = kzalloc(sizeof(struct dpu_crtc_res), GFP_KERNEL); + if (!dup_res) { + mutex_unlock(rp->rp_lock); + return; + } + INIT_LIST_HEAD(&dup_res->list); + atomic_set(&dup_res->refcount, 0); + dup_res->type = res->type; + dup_res->tag = res->tag; + dup_res->val = res->val; + dup_res->ops = res->ops; + dup_res->flags = DPU_CRTC_RES_FLAG_FREE; + DPU_DEBUG("crtc%d.%u dup res:0x%x/0x%llx/%pK/%d\n", + crtc->base.id, dup_rp->sequence_id, + dup_res->type, dup_res->tag, dup_res->val, + atomic_read(&dup_res->refcount)); + list_add_tail(&dup_res->list, &dup_rp->res_list); + if (dup_res->ops.get) + dup_res->ops.get(dup_res->val, 0, -1); + } + + dup_rp->rp_lock = rp->rp_lock; + dup_rp->rp_head = rp->rp_head; + INIT_LIST_HEAD(&dup_rp->rp_list); + list_add_tail(&dup_rp->rp_list, rp->rp_head); + mutex_unlock(rp->rp_lock); +} + +/** + * _dpu_crtc_rp_reset - reset resource pool after allocation + * @rp: Pointer to original resource pool + * @rp_lock: Pointer to serialization resource pool lock + * @rp_head: Pointer to crtc resource pool head + * return: None + */ +static void _dpu_crtc_rp_reset(struct dpu_crtc_respool *rp, + struct mutex *rp_lock, struct list_head *rp_head) +{ + if (!rp || !rp_lock || !rp_head) { + DPU_ERROR("invalid resource pool\n"); + return; + } + + mutex_lock(rp_lock); + rp->rp_lock = rp_lock; + rp->rp_head = rp_head; + INIT_LIST_HEAD(&rp->rp_list); + rp->sequence_id = 0; + INIT_LIST_HEAD(&rp->res_list); + rp->ops.get = _dpu_crtc_hw_blk_get; + rp->ops.put = _dpu_crtc_hw_blk_put; + list_add_tail(&rp->rp_list, rp->rp_head); + mutex_unlock(rp_lock); +} + +/** + * _dpu_crtc_rp_add_no_lock - add given resource to resource pool without lock + * @rp: Pointer to original resource pool + * @type: Resource type + * @tag: Search tag for given resource + * @val: Resource handle + * @ops: Resource callback operations + * return: 0 if success; error code otherwise + */ +static int _dpu_crtc_rp_add_no_lock(struct dpu_crtc_respool *rp, u32 type, + u64 tag, void *val, struct dpu_crtc_res_ops *ops) +{ + struct dpu_crtc_res *res; + struct drm_crtc *crtc; + + if (!rp || !ops) { + DPU_ERROR("invalid resource pool/ops\n"); + return -EINVAL; + } + + crtc = _dpu_crtc_rp_to_crtc(rp); + if (!crtc) { + DPU_ERROR("invalid crtc\n"); + return -EINVAL; + } + + list_for_each_entry(res, &rp->res_list, list) { + if (res->type != type || res->tag != tag) + continue; + DPU_ERROR("crtc%d.%u already exist res:0x%x/0x%llx/%pK/%d\n", + crtc->base.id, rp->sequence_id, + res->type, res->tag, res->val, + atomic_read(&res->refcount)); + return -EEXIST; + } + res = kzalloc(sizeof(struct dpu_crtc_res), GFP_KERNEL); + if (!res) + return -ENOMEM; + INIT_LIST_HEAD(&res->list); + atomic_set(&res->refcount, 1); + res->type = type; + res->tag = tag; + res->val = val; + res->ops = *ops; + list_add_tail(&res->list, &rp->res_list); + DPU_DEBUG("crtc%d.%u added res:0x%x/0x%llx\n", + crtc->base.id, rp->sequence_id, type, tag); + return 0; +} + +/** + * _dpu_crtc_rp_add - add given resource to resource pool + * @rp: Pointer to original resource pool + * @type: Resource type + * @tag: Search tag for given resource + * @val: Resource handle + * @ops: Resource callback operations + * return: 0 if success; error code otherwise + */ +static int _dpu_crtc_rp_add(struct dpu_crtc_respool *rp, u32 type, u64 tag, + void *val, struct dpu_crtc_res_ops *ops) +{ + int rc; + + if (!rp) { + DPU_ERROR("invalid resource pool\n"); + return -EINVAL; + } + + mutex_lock(rp->rp_lock); + rc = _dpu_crtc_rp_add_no_lock(rp, type, tag, val, ops); + mutex_unlock(rp->rp_lock); + return rc; +} + +/** + * _dpu_crtc_rp_get - lookup the resource from given resource pool and obtain + * if available; otherwise, obtain resource from global pool + * @rp: Pointer to original resource pool + * @type: Resource type + * @tag: Search tag for given resource + * return: Resource handle if success; pointer error or null otherwise + */ +static void *_dpu_crtc_rp_get(struct dpu_crtc_respool *rp, u32 type, u64 tag) +{ + struct dpu_crtc_respool *old_rp; + struct dpu_crtc_res *res; + void *val = NULL; + int rc; + struct drm_crtc *crtc; + + if (!rp) { + DPU_ERROR("invalid resource pool\n"); + return NULL; + } + + crtc = _dpu_crtc_rp_to_crtc(rp); + if (!crtc) { + DPU_ERROR("invalid crtc\n"); + return NULL; + } + + mutex_lock(rp->rp_lock); + list_for_each_entry(res, &rp->res_list, list) { + if (res->type != type || res->tag != tag) + continue; + DPU_DEBUG("crtc%d.%u found res:0x%x/0x%llx/%pK/%d\n", + crtc->base.id, rp->sequence_id, + res->type, res->tag, res->val, + atomic_read(&res->refcount)); + atomic_inc(&res->refcount); + res->flags &= ~DPU_CRTC_RES_FLAG_FREE; + mutex_unlock(rp->rp_lock); + return res->val; + } + list_for_each_entry(res, &rp->res_list, list) { + if (res->type != type || !(res->flags & DPU_CRTC_RES_FLAG_FREE)) + continue; + DPU_DEBUG("crtc%d.%u retag res:0x%x/0x%llx/%pK/%d\n", + crtc->base.id, rp->sequence_id, + res->type, res->tag, res->val, + atomic_read(&res->refcount)); + atomic_inc(&res->refcount); + res->tag = tag; + res->flags &= ~DPU_CRTC_RES_FLAG_FREE; + mutex_unlock(rp->rp_lock); + return res->val; + } + /* not in this rp, try to grab from global pool */ + if (rp->ops.get) + val = rp->ops.get(NULL, type, -1); + if (!IS_ERR_OR_NULL(val)) + goto add_res; + /* + * Search older resource pools for hw blk with matching type, + * necessary when resource is being used by this object, + * but in previous states not yet cleaned up. + * + * This enables searching of all resources currently owned + * by this crtc even though the resource might not be used + * in the current atomic state. This allows those resources + * to be re-acquired by the new atomic state immediately + * without waiting for the resources to be fully released. + */ + else if (IS_ERR_OR_NULL(val) && (type < DPU_HW_BLK_MAX)) { + list_for_each_entry(old_rp, rp->rp_head, rp_list) { + if (old_rp == rp) + continue; + + list_for_each_entry(res, &old_rp->res_list, list) { + if (res->type != type) + continue; + DRM_DEBUG_KMS("crtc%d.%u found res:0x%x//%pK/ " + "in crtc%d.%d\n", + crtc->base.id, rp->sequence_id, + res->type, res->val, + crtc->base.id, + old_rp->sequence_id); + if (res->ops.get) + res->ops.get(res->val, 0, -1); + val = res->val; + break; + } + + if (!IS_ERR_OR_NULL(val)) + break; + } + } + if (IS_ERR_OR_NULL(val)) { + DPU_DEBUG("crtc%d.%u failed to get res:0x%x//\n", + crtc->base.id, rp->sequence_id, type); + mutex_unlock(rp->rp_lock); + return NULL; + } +add_res: + rc = _dpu_crtc_rp_add_no_lock(rp, type, tag, val, &rp->ops); + if (rc) { + DPU_ERROR("crtc%d.%u failed to add res:0x%x/0x%llx\n", + crtc->base.id, rp->sequence_id, type, tag); + if (rp->ops.put) + rp->ops.put(val); + val = NULL; + } + mutex_unlock(rp->rp_lock); + return val; +} + +/** + * _dpu_crtc_rp_put - return given resource to resource pool + * @rp: Pointer to original resource pool + * @type: Resource type + * @tag: Search tag for given resource + * return: None + */ +static void _dpu_crtc_rp_put(struct dpu_crtc_respool *rp, u32 type, u64 tag) +{ + struct dpu_crtc_res *res, *next; + struct drm_crtc *crtc; + + if (!rp) { + DPU_ERROR("invalid resource pool\n"); + return; + } + + crtc = _dpu_crtc_rp_to_crtc(rp); + if (!crtc) { + DPU_ERROR("invalid crtc\n"); + return; + } + + mutex_lock(rp->rp_lock); + list_for_each_entry_safe(res, next, &rp->res_list, list) { + if (res->type != type || res->tag != tag) + continue; + DPU_DEBUG("crtc%d.%u found res:0x%x/0x%llx/%pK/%d\n", + crtc->base.id, rp->sequence_id, + res->type, res->tag, res->val, + atomic_read(&res->refcount)); + if (res->flags & DPU_CRTC_RES_FLAG_FREE) + DPU_ERROR( + "crtc%d.%u already free res:0x%x/0x%llx/%pK/%d\n", + crtc->base.id, rp->sequence_id, + res->type, res->tag, res->val, + atomic_read(&res->refcount)); + else if (atomic_dec_return(&res->refcount) == 0) + res->flags |= DPU_CRTC_RES_FLAG_FREE; + + mutex_unlock(rp->rp_lock); + return; + } + DPU_ERROR("crtc%d.%u not found res:0x%x/0x%llx\n", + crtc->base.id, rp->sequence_id, type, tag); + mutex_unlock(rp->rp_lock); +} + +int dpu_crtc_res_add(struct drm_crtc_state *state, u32 type, u64 tag, + void *val, struct dpu_crtc_res_ops *ops) +{ + struct dpu_crtc_respool *rp; + + if (!state) { + DPU_ERROR("invalid parameters\n"); + return -EINVAL; + } + + rp = &to_dpu_crtc_state(state)->rp; + return _dpu_crtc_rp_add(rp, type, tag, val, ops); +} + +void *dpu_crtc_res_get(struct drm_crtc_state *state, u32 type, u64 tag) +{ + struct dpu_crtc_respool *rp; + void *val; + + if (!state) { + DPU_ERROR("invalid parameters\n"); + return NULL; + } + + rp = &to_dpu_crtc_state(state)->rp; + val = _dpu_crtc_rp_get(rp, type, tag); + if (IS_ERR(val)) { + DPU_ERROR("failed to get res type:0x%x:0x%llx\n", + type, tag); + return NULL; + } + + return val; +} + +void dpu_crtc_res_put(struct drm_crtc_state *state, u32 type, u64 tag) +{ + struct dpu_crtc_respool *rp; + + if (!state) { + DPU_ERROR("invalid parameters\n"); + return; + } + + rp = &to_dpu_crtc_state(state)->rp; + _dpu_crtc_rp_put(rp, type, tag); +} + +static void dpu_crtc_destroy(struct drm_crtc *crtc) +{ + struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); + + DPU_DEBUG("\n"); + + if (!crtc) + return; + + dpu_crtc->phandle = NULL; + + drm_crtc_cleanup(crtc); + mutex_destroy(&dpu_crtc->crtc_lock); + kfree(dpu_crtc); +} + +static void _dpu_crtc_setup_blend_cfg(struct dpu_crtc_mixer *mixer, + struct dpu_plane_state *pstate) +{ + struct dpu_hw_mixer *lm = mixer->hw_lm; + + /* default to opaque blending */ + lm->ops.setup_blend_config(lm, pstate->stage, 0XFF, 0, + DPU_BLEND_FG_ALPHA_FG_CONST | + DPU_BLEND_BG_ALPHA_BG_CONST); +} + +static void _dpu_crtc_program_lm_output_roi(struct drm_crtc *crtc) +{ + struct dpu_crtc *dpu_crtc; + struct dpu_crtc_state *crtc_state; + int lm_idx, lm_horiz_position; + + dpu_crtc = to_dpu_crtc(crtc); + crtc_state = to_dpu_crtc_state(crtc->state); + + lm_horiz_position = 0; + for (lm_idx = 0; lm_idx < dpu_crtc->num_mixers; lm_idx++) { + const struct drm_rect *lm_roi = &crtc_state->lm_bounds[lm_idx]; + struct dpu_hw_mixer *hw_lm = dpu_crtc->mixers[lm_idx].hw_lm; + struct dpu_hw_mixer_cfg cfg; + + if (!lm_roi || !drm_rect_visible(lm_roi)) + continue; + + cfg.out_width = drm_rect_width(lm_roi); + cfg.out_height = drm_rect_height(lm_roi); + cfg.right_mixer = lm_horiz_position++; + cfg.flags = 0; + hw_lm->ops.setup_mixer_out(hw_lm, &cfg); + } +} + +static void _dpu_crtc_blend_setup_mixer(struct drm_crtc *crtc, + struct dpu_crtc *dpu_crtc, struct dpu_crtc_mixer *mixer) +{ + struct drm_plane *plane; + struct drm_framebuffer *fb; + struct drm_plane_state *state; + struct dpu_crtc_state *cstate; + struct dpu_plane_state *pstate = NULL; + struct dpu_format *format; + struct dpu_hw_ctl *ctl; + struct dpu_hw_mixer *lm; + struct dpu_hw_stage_cfg *stage_cfg; + + u32 flush_mask; + uint32_t stage_idx, lm_idx; + int zpos_cnt[DPU_STAGE_MAX + 1] = { 0 }; + bool bg_alpha_enable = false; + + if (!dpu_crtc || !mixer) { + DPU_ERROR("invalid dpu_crtc or mixer\n"); + return; + } + + ctl = mixer->hw_ctl; + lm = mixer->hw_lm; + stage_cfg = &dpu_crtc->stage_cfg; + cstate = to_dpu_crtc_state(crtc->state); + + drm_atomic_crtc_for_each_plane(plane, crtc) { + state = plane->state; + if (!state) + continue; + + pstate = to_dpu_plane_state(state); + fb = state->fb; + + dpu_plane_get_ctl_flush(plane, ctl, &flush_mask); + + DPU_DEBUG("crtc %d stage:%d - plane %d sspp %d fb %d\n", + crtc->base.id, + pstate->stage, + plane->base.id, + dpu_plane_pipe(plane) - SSPP_VIG0, + state->fb ? state->fb->base.id : -1); + + format = to_dpu_format(msm_framebuffer_format(pstate->base.fb)); + if (!format) { + DPU_ERROR("invalid format\n"); + return; + } + + if (pstate->stage == DPU_STAGE_BASE && format->alpha_enable) + bg_alpha_enable = true; + + stage_idx = zpos_cnt[pstate->stage]++; + stage_cfg->stage[pstate->stage][stage_idx] = + dpu_plane_pipe(plane); + stage_cfg->multirect_index[pstate->stage][stage_idx] = + pstate->multirect_index; + + trace_dpu_crtc_setup_mixer(DRMID(crtc), DRMID(plane), + state, pstate, stage_idx, + dpu_plane_pipe(plane) - SSPP_VIG0, + format->base.pixel_format, + fb ? fb->modifier : 0); + + /* blend config update */ + for (lm_idx = 0; lm_idx < dpu_crtc->num_mixers; lm_idx++) { + _dpu_crtc_setup_blend_cfg(mixer + lm_idx, pstate); + + mixer[lm_idx].flush_mask |= flush_mask; + + if (bg_alpha_enable && !format->alpha_enable) + mixer[lm_idx].mixer_op_mode = 0; + else + mixer[lm_idx].mixer_op_mode |= + 1 << pstate->stage; + } + } + + _dpu_crtc_program_lm_output_roi(crtc); +} + +/** + * _dpu_crtc_blend_setup - configure crtc mixers + * @crtc: Pointer to drm crtc structure + */ +static void _dpu_crtc_blend_setup(struct drm_crtc *crtc) +{ + struct dpu_crtc *dpu_crtc; + struct dpu_crtc_state *dpu_crtc_state; + struct dpu_crtc_mixer *mixer; + struct dpu_hw_ctl *ctl; + struct dpu_hw_mixer *lm; + + int i; + + if (!crtc) + return; + + dpu_crtc = to_dpu_crtc(crtc); + dpu_crtc_state = to_dpu_crtc_state(crtc->state); + mixer = dpu_crtc->mixers; + + DPU_DEBUG("%s\n", dpu_crtc->name); + + if (dpu_crtc->num_mixers > CRTC_DUAL_MIXERS) { + DPU_ERROR("invalid number mixers: %d\n", dpu_crtc->num_mixers); + return; + } + + for (i = 0; i < dpu_crtc->num_mixers; i++) { + if (!mixer[i].hw_lm || !mixer[i].hw_ctl) { + DPU_ERROR("invalid lm or ctl assigned to mixer\n"); + return; + } + mixer[i].mixer_op_mode = 0; + mixer[i].flush_mask = 0; + if (mixer[i].hw_ctl->ops.clear_all_blendstages) + mixer[i].hw_ctl->ops.clear_all_blendstages( + mixer[i].hw_ctl); + } + + /* initialize stage cfg */ + memset(&dpu_crtc->stage_cfg, 0, sizeof(struct dpu_hw_stage_cfg)); + + _dpu_crtc_blend_setup_mixer(crtc, dpu_crtc, mixer); + + for (i = 0; i < dpu_crtc->num_mixers; i++) { + ctl = mixer[i].hw_ctl; + lm = mixer[i].hw_lm; + + lm->ops.setup_alpha_out(lm, mixer[i].mixer_op_mode); + + mixer[i].flush_mask |= ctl->ops.get_bitmask_mixer(ctl, + mixer[i].hw_lm->idx); + + /* stage config flush mask */ + ctl->ops.update_pending_flush(ctl, mixer[i].flush_mask); + + DPU_DEBUG("lm %d, op_mode 0x%X, ctl %d, flush mask 0x%x\n", + mixer[i].hw_lm->idx - LM_0, + mixer[i].mixer_op_mode, + ctl->idx - CTL_0, + mixer[i].flush_mask); + + ctl->ops.setup_blendstage(ctl, mixer[i].hw_lm->idx, + &dpu_crtc->stage_cfg); + } +} + +/** + * _dpu_crtc_complete_flip - signal pending page_flip events + * Any pending vblank events are added to the vblank_event_list + * so that the next vblank interrupt shall signal them. + * However PAGE_FLIP events are not handled through the vblank_event_list. + * This API signals any pending PAGE_FLIP events requested through + * DRM_IOCTL_MODE_PAGE_FLIP and are cached in the dpu_crtc->event. + * @crtc: Pointer to drm crtc structure + */ +static void _dpu_crtc_complete_flip(struct drm_crtc *crtc) +{ + struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); + struct drm_device *dev = crtc->dev; + unsigned long flags; + + spin_lock_irqsave(&dev->event_lock, flags); + if (dpu_crtc->event) { + DRM_DEBUG_VBL("%s: send event: %pK\n", dpu_crtc->name, + dpu_crtc->event); + trace_dpu_crtc_complete_flip(DRMID(crtc)); + drm_crtc_send_vblank_event(crtc, dpu_crtc->event); + dpu_crtc->event = NULL; + } + spin_unlock_irqrestore(&dev->event_lock, flags); +} + +enum dpu_intf_mode dpu_crtc_get_intf_mode(struct drm_crtc *crtc) +{ + struct drm_encoder *encoder; + + if (!crtc || !crtc->dev) { + DPU_ERROR("invalid crtc\n"); + return INTF_MODE_NONE; + } + + drm_for_each_encoder(encoder, crtc->dev) + if (encoder->crtc == crtc) + return dpu_encoder_get_intf_mode(encoder); + + return INTF_MODE_NONE; +} + +static void dpu_crtc_vblank_cb(void *data) +{ + struct drm_crtc *crtc = (struct drm_crtc *)data; + struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); + + /* keep statistics on vblank callback - with auto reset via debugfs */ + if (ktime_compare(dpu_crtc->vblank_cb_time, ktime_set(0, 0)) == 0) + dpu_crtc->vblank_cb_time = ktime_get(); + else + dpu_crtc->vblank_cb_count++; + _dpu_crtc_complete_flip(crtc); + drm_crtc_handle_vblank(crtc); + trace_dpu_crtc_vblank_cb(DRMID(crtc)); +} + +static void dpu_crtc_frame_event_work(struct kthread_work *work) +{ + struct msm_drm_private *priv; + struct dpu_crtc_frame_event *fevent; + struct drm_crtc *crtc; + struct dpu_crtc *dpu_crtc; + struct dpu_kms *dpu_kms; + unsigned long flags; + bool frame_done = false; + + if (!work) { + DPU_ERROR("invalid work handle\n"); + return; + } + + fevent = container_of(work, struct dpu_crtc_frame_event, work); + if (!fevent->crtc || !fevent->crtc->state) { + DPU_ERROR("invalid crtc\n"); + return; + } + + crtc = fevent->crtc; + dpu_crtc = to_dpu_crtc(crtc); + + dpu_kms = _dpu_crtc_get_kms(crtc); + if (!dpu_kms) { + DPU_ERROR("invalid kms handle\n"); + return; + } + priv = dpu_kms->dev->dev_private; + DPU_ATRACE_BEGIN("crtc_frame_event"); + + DRM_DEBUG_KMS("crtc%d event:%u ts:%lld\n", crtc->base.id, fevent->event, + ktime_to_ns(fevent->ts)); + + if (fevent->event & (DPU_ENCODER_FRAME_EVENT_DONE + | DPU_ENCODER_FRAME_EVENT_ERROR + | DPU_ENCODER_FRAME_EVENT_PANEL_DEAD)) { + + if (atomic_read(&dpu_crtc->frame_pending) < 1) { + /* this should not happen */ + DRM_ERROR("crtc%d ev:%u ts:%lld frame_pending:%d\n", + crtc->base.id, + fevent->event, + ktime_to_ns(fevent->ts), + atomic_read(&dpu_crtc->frame_pending)); + } else if (atomic_dec_return(&dpu_crtc->frame_pending) == 0) { + /* release bandwidth and other resources */ + trace_dpu_crtc_frame_event_done(DRMID(crtc), + fevent->event); + dpu_core_perf_crtc_release_bw(crtc); + } else { + trace_dpu_crtc_frame_event_more_pending(DRMID(crtc), + fevent->event); + } + + if (fevent->event & DPU_ENCODER_FRAME_EVENT_DONE) + dpu_core_perf_crtc_update(crtc, 0, false); + + if (fevent->event & (DPU_ENCODER_FRAME_EVENT_DONE + | DPU_ENCODER_FRAME_EVENT_ERROR)) + frame_done = true; + } + + if (fevent->event & DPU_ENCODER_FRAME_EVENT_PANEL_DEAD) + DPU_ERROR("crtc%d ts:%lld received panel dead event\n", + crtc->base.id, ktime_to_ns(fevent->ts)); + + if (frame_done) + complete_all(&dpu_crtc->frame_done_comp); + + spin_lock_irqsave(&dpu_crtc->spin_lock, flags); + list_add_tail(&fevent->list, &dpu_crtc->frame_event_list); + spin_unlock_irqrestore(&dpu_crtc->spin_lock, flags); + DPU_ATRACE_END("crtc_frame_event"); +} + +/* + * dpu_crtc_frame_event_cb - crtc frame event callback API. CRTC module + * registers this API to encoder for all frame event callbacks like + * frame_error, frame_done, idle_timeout, etc. Encoder may call different events + * from different context - IRQ, user thread, commit_thread, etc. Each event + * should be carefully reviewed and should be processed in proper task context + * to avoid schedulin delay or properly manage the irq context's bottom half + * processing. + */ +static void dpu_crtc_frame_event_cb(void *data, u32 event) +{ + struct drm_crtc *crtc = (struct drm_crtc *)data; + struct dpu_crtc *dpu_crtc; + struct msm_drm_private *priv; + struct dpu_crtc_frame_event *fevent; + unsigned long flags; + u32 crtc_id; + + if (!crtc || !crtc->dev || !crtc->dev->dev_private) { + DPU_ERROR("invalid parameters\n"); + return; + } + + /* Nothing to do on idle event */ + if (event & DPU_ENCODER_FRAME_EVENT_IDLE) + return; + + dpu_crtc = to_dpu_crtc(crtc); + priv = crtc->dev->dev_private; + crtc_id = drm_crtc_index(crtc); + + trace_dpu_crtc_frame_event_cb(DRMID(crtc), event); + + spin_lock_irqsave(&dpu_crtc->spin_lock, flags); + fevent = list_first_entry_or_null(&dpu_crtc->frame_event_list, + struct dpu_crtc_frame_event, list); + if (fevent) + list_del_init(&fevent->list); + spin_unlock_irqrestore(&dpu_crtc->spin_lock, flags); + + if (!fevent) { + DRM_ERROR("crtc%d event %d overflow\n", crtc->base.id, event); + return; + } + + fevent->event = event; + fevent->crtc = crtc; + fevent->ts = ktime_get(); + kthread_queue_work(&priv->event_thread[crtc_id].worker, &fevent->work); +} + +void dpu_crtc_complete_commit(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) +{ + if (!crtc || !crtc->state) { + DPU_ERROR("invalid crtc\n"); + return; + } + trace_dpu_crtc_complete_commit(DRMID(crtc)); +} + +static void _dpu_crtc_setup_mixer_for_encoder( + struct drm_crtc *crtc, + struct drm_encoder *enc) +{ + struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); + struct dpu_kms *dpu_kms = _dpu_crtc_get_kms(crtc); + struct dpu_rm *rm = &dpu_kms->rm; + struct dpu_crtc_mixer *mixer; + struct dpu_hw_ctl *last_valid_ctl = NULL; + int i; + struct dpu_rm_hw_iter lm_iter, ctl_iter; + + dpu_rm_init_hw_iter(&lm_iter, enc->base.id, DPU_HW_BLK_LM); + dpu_rm_init_hw_iter(&ctl_iter, enc->base.id, DPU_HW_BLK_CTL); + + /* Set up all the mixers and ctls reserved by this encoder */ + for (i = dpu_crtc->num_mixers; i < ARRAY_SIZE(dpu_crtc->mixers); i++) { + mixer = &dpu_crtc->mixers[i]; + + if (!dpu_rm_get_hw(rm, &lm_iter)) + break; + mixer->hw_lm = (struct dpu_hw_mixer *)lm_iter.hw; + + /* CTL may be <= LMs, if <, multiple LMs controlled by 1 CTL */ + if (!dpu_rm_get_hw(rm, &ctl_iter)) { + DPU_DEBUG("no ctl assigned to lm %d, using previous\n", + mixer->hw_lm->idx - LM_0); + mixer->hw_ctl = last_valid_ctl; + } else { + mixer->hw_ctl = (struct dpu_hw_ctl *)ctl_iter.hw; + last_valid_ctl = mixer->hw_ctl; + } + + /* Shouldn't happen, mixers are always >= ctls */ + if (!mixer->hw_ctl) { + DPU_ERROR("no valid ctls found for lm %d\n", + mixer->hw_lm->idx - LM_0); + return; + } + + mixer->encoder = enc; + + dpu_crtc->num_mixers++; + DPU_DEBUG("setup mixer %d: lm %d\n", + i, mixer->hw_lm->idx - LM_0); + DPU_DEBUG("setup mixer %d: ctl %d\n", + i, mixer->hw_ctl->idx - CTL_0); + } +} + +static void _dpu_crtc_setup_mixers(struct drm_crtc *crtc) +{ + struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); + struct drm_encoder *enc; + + dpu_crtc->num_mixers = 0; + dpu_crtc->mixers_swapped = false; + memset(dpu_crtc->mixers, 0, sizeof(dpu_crtc->mixers)); + + mutex_lock(&dpu_crtc->crtc_lock); + /* Check for mixers on all encoders attached to this crtc */ + list_for_each_entry(enc, &crtc->dev->mode_config.encoder_list, head) { + if (enc->crtc != crtc) + continue; + + _dpu_crtc_setup_mixer_for_encoder(crtc, enc); + } + + mutex_unlock(&dpu_crtc->crtc_lock); +} + +static void _dpu_crtc_setup_lm_bounds(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + struct dpu_crtc *dpu_crtc; + struct dpu_crtc_state *cstate; + struct drm_display_mode *adj_mode; + u32 crtc_split_width; + int i; + + if (!crtc || !state) { + DPU_ERROR("invalid args\n"); + return; + } + + dpu_crtc = to_dpu_crtc(crtc); + cstate = to_dpu_crtc_state(state); + + adj_mode = &state->adjusted_mode; + crtc_split_width = dpu_crtc_get_mixer_width(dpu_crtc, cstate, adj_mode); + + for (i = 0; i < dpu_crtc->num_mixers; i++) { + struct drm_rect *r = &cstate->lm_bounds[i]; + r->x1 = crtc_split_width * i; + r->y1 = 0; + r->x2 = r->x1 + crtc_split_width; + r->y2 = dpu_crtc_get_mixer_height(dpu_crtc, cstate, adj_mode); + + trace_dpu_crtc_setup_lm_bounds(DRMID(crtc), i, r); + } + + drm_mode_debug_printmodeline(adj_mode); +} + +static void dpu_crtc_atomic_begin(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) +{ + struct dpu_crtc *dpu_crtc; + struct drm_encoder *encoder; + struct drm_device *dev; + unsigned long flags; + struct dpu_crtc_smmu_state_data *smmu_state; + + if (!crtc) { + DPU_ERROR("invalid crtc\n"); + return; + } + + if (!crtc->state->enable) { + DPU_DEBUG("crtc%d -> enable %d, skip atomic_begin\n", + crtc->base.id, crtc->state->enable); + return; + } + + DPU_DEBUG("crtc%d\n", crtc->base.id); + + dpu_crtc = to_dpu_crtc(crtc); + dev = crtc->dev; + smmu_state = &dpu_crtc->smmu_state; + + if (!dpu_crtc->num_mixers) { + _dpu_crtc_setup_mixers(crtc); + _dpu_crtc_setup_lm_bounds(crtc, crtc->state); + } + + if (dpu_crtc->event) { + WARN_ON(dpu_crtc->event); + } else { + spin_lock_irqsave(&dev->event_lock, flags); + dpu_crtc->event = crtc->state->event; + crtc->state->event = NULL; + spin_unlock_irqrestore(&dev->event_lock, flags); + } + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->crtc != crtc) + continue; + + /* encoder will trigger pending mask now */ + dpu_encoder_trigger_kickoff_pending(encoder); + } + + /* + * If no mixers have been allocated in dpu_crtc_atomic_check(), + * it means we are trying to flush a CRTC whose state is disabled: + * nothing else needs to be done. + */ + if (unlikely(!dpu_crtc->num_mixers)) + return; + + _dpu_crtc_blend_setup(crtc); + + /* + * PP_DONE irq is only used by command mode for now. + * It is better to request pending before FLUSH and START trigger + * to make sure no pp_done irq missed. + * This is safe because no pp_done will happen before SW trigger + * in command mode. + */ +} + +static void dpu_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) +{ + struct dpu_crtc *dpu_crtc; + struct drm_device *dev; + struct drm_plane *plane; + struct msm_drm_private *priv; + struct msm_drm_thread *event_thread; + unsigned long flags; + struct dpu_crtc_state *cstate; + + if (!crtc || !crtc->dev || !crtc->dev->dev_private) { + DPU_ERROR("invalid crtc\n"); + return; + } + + if (!crtc->state->enable) { + DPU_DEBUG("crtc%d -> enable %d, skip atomic_flush\n", + crtc->base.id, crtc->state->enable); + return; + } + + DPU_DEBUG("crtc%d\n", crtc->base.id); + + dpu_crtc = to_dpu_crtc(crtc); + cstate = to_dpu_crtc_state(crtc->state); + dev = crtc->dev; + priv = dev->dev_private; + + if (crtc->index >= ARRAY_SIZE(priv->event_thread)) { + DPU_ERROR("invalid crtc index[%d]\n", crtc->index); + return; + } + + event_thread = &priv->event_thread[crtc->index]; + + if (dpu_crtc->event) { + DPU_DEBUG("already received dpu_crtc->event\n"); + } else { + spin_lock_irqsave(&dev->event_lock, flags); + dpu_crtc->event = crtc->state->event; + crtc->state->event = NULL; + spin_unlock_irqrestore(&dev->event_lock, flags); + } + + /* + * If no mixers has been allocated in dpu_crtc_atomic_check(), + * it means we are trying to flush a CRTC whose state is disabled: + * nothing else needs to be done. + */ + if (unlikely(!dpu_crtc->num_mixers)) + return; + + /* + * For planes without commit update, drm framework will not add + * those planes to current state since hardware update is not + * required. However, if those planes were power collapsed since + * last commit cycle, driver has to restore the hardware state + * of those planes explicitly here prior to plane flush. + */ + drm_atomic_crtc_for_each_plane(plane, crtc) + dpu_plane_restore(plane); + + /* update performance setting before crtc kickoff */ + dpu_core_perf_crtc_update(crtc, 1, false); + + /* + * Final plane updates: Give each plane a chance to complete all + * required writes/flushing before crtc's "flush + * everything" call below. + */ + drm_atomic_crtc_for_each_plane(plane, crtc) { + if (dpu_crtc->smmu_state.transition_error) + dpu_plane_set_error(plane, true); + dpu_plane_flush(plane); + } + + /* Kickoff will be scheduled by outer layer */ +} + +/** + * dpu_crtc_destroy_state - state destroy hook + * @crtc: drm CRTC + * @state: CRTC state object to release + */ +static void dpu_crtc_destroy_state(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + struct dpu_crtc *dpu_crtc; + struct dpu_crtc_state *cstate; + + if (!crtc || !state) { + DPU_ERROR("invalid argument(s)\n"); + return; + } + + dpu_crtc = to_dpu_crtc(crtc); + cstate = to_dpu_crtc_state(state); + + DPU_DEBUG("crtc%d\n", crtc->base.id); + + _dpu_crtc_rp_destroy(&cstate->rp); + + __drm_atomic_helper_crtc_destroy_state(state); + + kfree(cstate); +} + +static int _dpu_crtc_wait_for_frame_done(struct drm_crtc *crtc) +{ + struct dpu_crtc *dpu_crtc; + int ret, rc = 0; + + if (!crtc) { + DPU_ERROR("invalid argument\n"); + return -EINVAL; + } + dpu_crtc = to_dpu_crtc(crtc); + + if (!atomic_read(&dpu_crtc->frame_pending)) { + DPU_DEBUG("no frames pending\n"); + return 0; + } + + DPU_ATRACE_BEGIN("frame done completion wait"); + ret = wait_for_completion_timeout(&dpu_crtc->frame_done_comp, + msecs_to_jiffies(DPU_FRAME_DONE_TIMEOUT)); + if (!ret) { + DRM_ERROR("frame done wait timed out, ret:%d\n", ret); + rc = -ETIMEDOUT; + } + DPU_ATRACE_END("frame done completion wait"); + + return rc; +} + +void dpu_crtc_commit_kickoff(struct drm_crtc *crtc) +{ + struct drm_encoder *encoder; + struct drm_device *dev; + struct dpu_crtc *dpu_crtc; + struct msm_drm_private *priv; + struct dpu_kms *dpu_kms; + struct dpu_crtc_state *cstate; + int ret; + + if (!crtc) { + DPU_ERROR("invalid argument\n"); + return; + } + dev = crtc->dev; + dpu_crtc = to_dpu_crtc(crtc); + dpu_kms = _dpu_crtc_get_kms(crtc); + + if (!dpu_kms || !dpu_kms->dev || !dpu_kms->dev->dev_private) { + DPU_ERROR("invalid argument\n"); + return; + } + + priv = dpu_kms->dev->dev_private; + cstate = to_dpu_crtc_state(crtc->state); + + /* + * If no mixers has been allocated in dpu_crtc_atomic_check(), + * it means we are trying to start a CRTC whose state is disabled: + * nothing else needs to be done. + */ + if (unlikely(!dpu_crtc->num_mixers)) + return; + + DPU_ATRACE_BEGIN("crtc_commit"); + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + struct dpu_encoder_kickoff_params params = { 0 }; + + if (encoder->crtc != crtc) + continue; + + /* + * Encoder will flush/start now, unless it has a tx pending. + * If so, it may delay and flush at an irq event (e.g. ppdone) + */ + dpu_encoder_prepare_for_kickoff(encoder, ¶ms); + } + + /* wait for frame_event_done completion */ + DPU_ATRACE_BEGIN("wait_for_frame_done_event"); + ret = _dpu_crtc_wait_for_frame_done(crtc); + DPU_ATRACE_END("wait_for_frame_done_event"); + if (ret) { + DPU_ERROR("crtc%d wait for frame done failed;frame_pending%d\n", + crtc->base.id, + atomic_read(&dpu_crtc->frame_pending)); + goto end; + } + + if (atomic_inc_return(&dpu_crtc->frame_pending) == 1) { + /* acquire bandwidth and other resources */ + DPU_DEBUG("crtc%d first commit\n", crtc->base.id); + } else + DPU_DEBUG("crtc%d commit\n", crtc->base.id); + + dpu_crtc->play_count++; + + dpu_vbif_clear_errors(dpu_kms); + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->crtc != crtc) + continue; + + dpu_encoder_kickoff(encoder); + } + +end: + reinit_completion(&dpu_crtc->frame_done_comp); + DPU_ATRACE_END("crtc_commit"); +} + +/** + * _dpu_crtc_vblank_enable_no_lock - update power resource and vblank request + * @dpu_crtc: Pointer to dpu crtc structure + * @enable: Whether to enable/disable vblanks + * + * @Return: error code + */ +static int _dpu_crtc_vblank_enable_no_lock( + struct dpu_crtc *dpu_crtc, bool enable) +{ + struct drm_device *dev; + struct drm_crtc *crtc; + struct drm_encoder *enc; + + if (!dpu_crtc) { + DPU_ERROR("invalid crtc\n"); + return -EINVAL; + } + + crtc = &dpu_crtc->base; + dev = crtc->dev; + + if (enable) { + int ret; + + /* drop lock since power crtc cb may try to re-acquire lock */ + mutex_unlock(&dpu_crtc->crtc_lock); + ret = _dpu_crtc_power_enable(dpu_crtc, true); + mutex_lock(&dpu_crtc->crtc_lock); + if (ret) + return ret; + + list_for_each_entry(enc, &dev->mode_config.encoder_list, head) { + if (enc->crtc != crtc) + continue; + + trace_dpu_crtc_vblank_enable(DRMID(&dpu_crtc->base), + DRMID(enc), enable, + dpu_crtc); + + dpu_encoder_register_vblank_callback(enc, + dpu_crtc_vblank_cb, (void *)crtc); + } + } else { + list_for_each_entry(enc, &dev->mode_config.encoder_list, head) { + if (enc->crtc != crtc) + continue; + + trace_dpu_crtc_vblank_enable(DRMID(&dpu_crtc->base), + DRMID(enc), enable, + dpu_crtc); + + dpu_encoder_register_vblank_callback(enc, NULL, NULL); + } + + /* drop lock since power crtc cb may try to re-acquire lock */ + mutex_unlock(&dpu_crtc->crtc_lock); + _dpu_crtc_power_enable(dpu_crtc, false); + mutex_lock(&dpu_crtc->crtc_lock); + } + + return 0; +} + +/** + * _dpu_crtc_set_suspend - notify crtc of suspend enable/disable + * @crtc: Pointer to drm crtc object + * @enable: true to enable suspend, false to indicate resume + */ +static void _dpu_crtc_set_suspend(struct drm_crtc *crtc, bool enable) +{ + struct dpu_crtc *dpu_crtc; + struct msm_drm_private *priv; + struct dpu_kms *dpu_kms; + int ret = 0; + + if (!crtc || !crtc->dev || !crtc->dev->dev_private) { + DPU_ERROR("invalid crtc\n"); + return; + } + dpu_crtc = to_dpu_crtc(crtc); + priv = crtc->dev->dev_private; + + if (!priv->kms) { + DPU_ERROR("invalid crtc kms\n"); + return; + } + dpu_kms = to_dpu_kms(priv->kms); + + DRM_DEBUG_KMS("crtc%d suspend = %d\n", crtc->base.id, enable); + + mutex_lock(&dpu_crtc->crtc_lock); + + /* + * If the vblank is enabled, release a power reference on suspend + * and take it back during resume (if it is still enabled). + */ + trace_dpu_crtc_set_suspend(DRMID(&dpu_crtc->base), enable, dpu_crtc); + if (dpu_crtc->suspend == enable) + DPU_DEBUG("crtc%d suspend already set to %d, ignoring update\n", + crtc->base.id, enable); + else if (dpu_crtc->enabled && dpu_crtc->vblank_requested) { + ret = _dpu_crtc_vblank_enable_no_lock(dpu_crtc, !enable); + if (ret) + DPU_ERROR("%s vblank enable failed: %d\n", + dpu_crtc->name, ret); + } + + dpu_crtc->suspend = enable; + mutex_unlock(&dpu_crtc->crtc_lock); +} + +/** + * dpu_crtc_duplicate_state - state duplicate hook + * @crtc: Pointer to drm crtc structure + * @Returns: Pointer to new drm_crtc_state structure + */ +static struct drm_crtc_state *dpu_crtc_duplicate_state(struct drm_crtc *crtc) +{ + struct dpu_crtc *dpu_crtc; + struct dpu_crtc_state *cstate, *old_cstate; + + if (!crtc || !crtc->state) { + DPU_ERROR("invalid argument(s)\n"); + return NULL; + } + + dpu_crtc = to_dpu_crtc(crtc); + old_cstate = to_dpu_crtc_state(crtc->state); + cstate = kmemdup(old_cstate, sizeof(*old_cstate), GFP_KERNEL); + if (!cstate) { + DPU_ERROR("failed to allocate state\n"); + return NULL; + } + + /* duplicate base helper */ + __drm_atomic_helper_crtc_duplicate_state(crtc, &cstate->base); + + _dpu_crtc_rp_duplicate(&old_cstate->rp, &cstate->rp); + + return &cstate->base; +} + +/** + * dpu_crtc_reset - reset hook for CRTCs + * Resets the atomic state for @crtc by freeing the state pointer (which might + * be NULL, e.g. at driver load time) and allocating a new empty state object. + * @crtc: Pointer to drm crtc structure + */ +static void dpu_crtc_reset(struct drm_crtc *crtc) +{ + struct dpu_crtc *dpu_crtc; + struct dpu_crtc_state *cstate; + + if (!crtc) { + DPU_ERROR("invalid crtc\n"); + return; + } + + /* revert suspend actions, if necessary */ + if (dpu_kms_is_suspend_state(crtc->dev)) + _dpu_crtc_set_suspend(crtc, false); + + /* remove previous state, if present */ + if (crtc->state) { + dpu_crtc_destroy_state(crtc, crtc->state); + crtc->state = 0; + } + + dpu_crtc = to_dpu_crtc(crtc); + cstate = kzalloc(sizeof(*cstate), GFP_KERNEL); + if (!cstate) { + DPU_ERROR("failed to allocate state\n"); + return; + } + + _dpu_crtc_rp_reset(&cstate->rp, &dpu_crtc->rp_lock, + &dpu_crtc->rp_head); + + cstate->base.crtc = crtc; + crtc->state = &cstate->base; +} + +static void dpu_crtc_handle_power_event(u32 event_type, void *arg) +{ + struct drm_crtc *crtc = arg; + struct dpu_crtc *dpu_crtc; + struct drm_encoder *encoder; + struct dpu_crtc_mixer *m; + u32 i, misr_status; + + if (!crtc) { + DPU_ERROR("invalid crtc\n"); + return; + } + dpu_crtc = to_dpu_crtc(crtc); + + mutex_lock(&dpu_crtc->crtc_lock); + + trace_dpu_crtc_handle_power_event(DRMID(crtc), event_type); + + switch (event_type) { + case DPU_POWER_EVENT_POST_ENABLE: + /* restore encoder; crtc will be programmed during commit */ + drm_for_each_encoder(encoder, crtc->dev) { + if (encoder->crtc != crtc) + continue; + + dpu_encoder_virt_restore(encoder); + } + + for (i = 0; i < dpu_crtc->num_mixers; ++i) { + m = &dpu_crtc->mixers[i]; + if (!m->hw_lm || !m->hw_lm->ops.setup_misr || + !dpu_crtc->misr_enable) + continue; + + m->hw_lm->ops.setup_misr(m->hw_lm, true, + dpu_crtc->misr_frame_count); + } + break; + case DPU_POWER_EVENT_PRE_DISABLE: + for (i = 0; i < dpu_crtc->num_mixers; ++i) { + m = &dpu_crtc->mixers[i]; + if (!m->hw_lm || !m->hw_lm->ops.collect_misr || + !dpu_crtc->misr_enable) + continue; + + misr_status = m->hw_lm->ops.collect_misr(m->hw_lm); + dpu_crtc->misr_data[i] = misr_status ? misr_status : + dpu_crtc->misr_data[i]; + } + break; + case DPU_POWER_EVENT_POST_DISABLE: + /** + * Nothing to do. All the planes on the CRTC will be + * programmed for every frame + */ + break; + default: + DPU_DEBUG("event:%d not handled\n", event_type); + break; + } + + mutex_unlock(&dpu_crtc->crtc_lock); +} + +static void dpu_crtc_disable(struct drm_crtc *crtc) +{ + struct dpu_crtc *dpu_crtc; + struct dpu_crtc_state *cstate; + struct drm_display_mode *mode; + struct drm_encoder *encoder; + struct msm_drm_private *priv; + int ret; + + if (!crtc || !crtc->dev || !crtc->dev->dev_private || !crtc->state) { + DPU_ERROR("invalid crtc\n"); + return; + } + dpu_crtc = to_dpu_crtc(crtc); + cstate = to_dpu_crtc_state(crtc->state); + mode = &cstate->base.adjusted_mode; + priv = crtc->dev->dev_private; + + DRM_DEBUG_KMS("crtc%d\n", crtc->base.id); + + if (dpu_kms_is_suspend_state(crtc->dev)) + _dpu_crtc_set_suspend(crtc, true); + + mutex_lock(&dpu_crtc->crtc_lock); + + /* wait for frame_event_done completion */ + if (_dpu_crtc_wait_for_frame_done(crtc)) + DPU_ERROR("crtc%d wait for frame done failed;frame_pending%d\n", + crtc->base.id, + atomic_read(&dpu_crtc->frame_pending)); + + trace_dpu_crtc_disable(DRMID(crtc), false, dpu_crtc); + if (dpu_crtc->enabled && !dpu_crtc->suspend && + dpu_crtc->vblank_requested) { + ret = _dpu_crtc_vblank_enable_no_lock(dpu_crtc, false); + if (ret) + DPU_ERROR("%s vblank enable failed: %d\n", + dpu_crtc->name, ret); + } + dpu_crtc->enabled = false; + + if (atomic_read(&dpu_crtc->frame_pending)) { + trace_dpu_crtc_disable_frame_pending(DRMID(crtc), + atomic_read(&dpu_crtc->frame_pending)); + dpu_core_perf_crtc_release_bw(crtc); + atomic_set(&dpu_crtc->frame_pending, 0); + } + + dpu_core_perf_crtc_update(crtc, 0, true); + + drm_for_each_encoder(encoder, crtc->dev) { + if (encoder->crtc != crtc) + continue; + dpu_encoder_register_frame_event_callback(encoder, NULL, NULL); + } + + if (dpu_crtc->power_event) + dpu_power_handle_unregister_event(dpu_crtc->phandle, + dpu_crtc->power_event); + + + memset(dpu_crtc->mixers, 0, sizeof(dpu_crtc->mixers)); + dpu_crtc->num_mixers = 0; + dpu_crtc->mixers_swapped = false; + + /* disable clk & bw control until clk & bw properties are set */ + cstate->bw_control = false; + cstate->bw_split_vote = false; + + mutex_unlock(&dpu_crtc->crtc_lock); +} + +static void dpu_crtc_enable(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) +{ + struct dpu_crtc *dpu_crtc; + struct drm_encoder *encoder; + struct msm_drm_private *priv; + int ret; + + if (!crtc || !crtc->dev || !crtc->dev->dev_private) { + DPU_ERROR("invalid crtc\n"); + return; + } + priv = crtc->dev->dev_private; + + DRM_DEBUG_KMS("crtc%d\n", crtc->base.id); + dpu_crtc = to_dpu_crtc(crtc); + + drm_for_each_encoder(encoder, crtc->dev) { + if (encoder->crtc != crtc) + continue; + dpu_encoder_register_frame_event_callback(encoder, + dpu_crtc_frame_event_cb, (void *)crtc); + } + + mutex_lock(&dpu_crtc->crtc_lock); + trace_dpu_crtc_enable(DRMID(crtc), true, dpu_crtc); + if (!dpu_crtc->enabled && !dpu_crtc->suspend && + dpu_crtc->vblank_requested) { + ret = _dpu_crtc_vblank_enable_no_lock(dpu_crtc, true); + if (ret) + DPU_ERROR("%s vblank enable failed: %d\n", + dpu_crtc->name, ret); + } + dpu_crtc->enabled = true; + + mutex_unlock(&dpu_crtc->crtc_lock); + + dpu_crtc->power_event = dpu_power_handle_register_event( + dpu_crtc->phandle, + DPU_POWER_EVENT_POST_ENABLE | DPU_POWER_EVENT_POST_DISABLE | + DPU_POWER_EVENT_PRE_DISABLE, + dpu_crtc_handle_power_event, crtc, dpu_crtc->name); + +} + +struct plane_state { + struct dpu_plane_state *dpu_pstate; + const struct drm_plane_state *drm_pstate; + int stage; + u32 pipe_id; +}; + +static int dpu_crtc_atomic_check(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + struct dpu_crtc *dpu_crtc; + struct plane_state *pstates; + struct dpu_crtc_state *cstate; + + const struct drm_plane_state *pstate; + struct drm_plane *plane; + struct drm_display_mode *mode; + + int cnt = 0, rc = 0, mixer_width, i, z_pos; + + struct dpu_multirect_plane_states multirect_plane[DPU_STAGE_MAX * 2]; + int multirect_count = 0; + const struct drm_plane_state *pipe_staged[SSPP_MAX]; + int left_zpos_cnt = 0, right_zpos_cnt = 0; + struct drm_rect crtc_rect = { 0 }; + + if (!crtc) { + DPU_ERROR("invalid crtc\n"); + return -EINVAL; + } + + pstates = kzalloc(sizeof(*pstates) * DPU_STAGE_MAX * 4, GFP_KERNEL); + + dpu_crtc = to_dpu_crtc(crtc); + cstate = to_dpu_crtc_state(state); + + if (!state->enable || !state->active) { + DPU_DEBUG("crtc%d -> enable %d, active %d, skip atomic_check\n", + crtc->base.id, state->enable, state->active); + goto end; + } + + mode = &state->adjusted_mode; + DPU_DEBUG("%s: check", dpu_crtc->name); + + /* force a full mode set if active state changed */ + if (state->active_changed) + state->mode_changed = true; + + memset(pipe_staged, 0, sizeof(pipe_staged)); + + mixer_width = dpu_crtc_get_mixer_width(dpu_crtc, cstate, mode); + + _dpu_crtc_setup_lm_bounds(crtc, state); + + crtc_rect.x2 = mode->hdisplay; + crtc_rect.y2 = mode->vdisplay; + + /* get plane state for all drm planes associated with crtc state */ + drm_atomic_crtc_state_for_each_plane_state(plane, pstate, state) { + struct drm_rect dst, clip = crtc_rect; + + if (IS_ERR_OR_NULL(pstate)) { + rc = PTR_ERR(pstate); + DPU_ERROR("%s: failed to get plane%d state, %d\n", + dpu_crtc->name, plane->base.id, rc); + goto end; + } + if (cnt >= DPU_STAGE_MAX * 4) + continue; + + pstates[cnt].dpu_pstate = to_dpu_plane_state(pstate); + pstates[cnt].drm_pstate = pstate; + pstates[cnt].stage = pstate->normalized_zpos; + pstates[cnt].pipe_id = dpu_plane_pipe(plane); + + if (pipe_staged[pstates[cnt].pipe_id]) { + multirect_plane[multirect_count].r0 = + pipe_staged[pstates[cnt].pipe_id]; + multirect_plane[multirect_count].r1 = pstate; + multirect_count++; + + pipe_staged[pstates[cnt].pipe_id] = NULL; + } else { + pipe_staged[pstates[cnt].pipe_id] = pstate; + } + + cnt++; + + dst = drm_plane_state_dest(pstate); + if (!drm_rect_intersect(&clip, &dst) || + !drm_rect_equals(&clip, &dst)) { + DPU_ERROR("invalid vertical/horizontal destination\n"); + DPU_ERROR("display: " DRM_RECT_FMT " plane: " + DRM_RECT_FMT "\n", DRM_RECT_ARG(&crtc_rect), + DRM_RECT_ARG(&dst)); + rc = -E2BIG; + goto end; + } + } + + for (i = 1; i < SSPP_MAX; i++) { + if (pipe_staged[i]) { + dpu_plane_clear_multirect(pipe_staged[i]); + + if (is_dpu_plane_virtual(pipe_staged[i]->plane)) { + DPU_ERROR( + "r1 only virt plane:%d not supported\n", + pipe_staged[i]->plane->base.id); + rc = -EINVAL; + goto end; + } + } + } + + z_pos = -1; + for (i = 0; i < cnt; i++) { + /* reset counts at every new blend stage */ + if (pstates[i].stage != z_pos) { + left_zpos_cnt = 0; + right_zpos_cnt = 0; + z_pos = pstates[i].stage; + } + + /* verify z_pos setting before using it */ + if (z_pos >= DPU_STAGE_MAX - DPU_STAGE_0) { + DPU_ERROR("> %d plane stages assigned\n", + DPU_STAGE_MAX - DPU_STAGE_0); + rc = -EINVAL; + goto end; + } else if (pstates[i].drm_pstate->crtc_x < mixer_width) { + if (left_zpos_cnt == 2) { + DPU_ERROR("> 2 planes @ stage %d on left\n", + z_pos); + rc = -EINVAL; + goto end; + } + left_zpos_cnt++; + + } else { + if (right_zpos_cnt == 2) { + DPU_ERROR("> 2 planes @ stage %d on right\n", + z_pos); + rc = -EINVAL; + goto end; + } + right_zpos_cnt++; + } + + pstates[i].dpu_pstate->stage = z_pos + DPU_STAGE_0; + DPU_DEBUG("%s: zpos %d", dpu_crtc->name, z_pos); + } + + for (i = 0; i < multirect_count; i++) { + if (dpu_plane_validate_multirect_v2(&multirect_plane[i])) { + DPU_ERROR( + "multirect validation failed for planes (%d - %d)\n", + multirect_plane[i].r0->plane->base.id, + multirect_plane[i].r1->plane->base.id); + rc = -EINVAL; + goto end; + } + } + + rc = dpu_core_perf_crtc_check(crtc, state); + if (rc) { + DPU_ERROR("crtc%d failed performance check %d\n", + crtc->base.id, rc); + goto end; + } + + /* validate source split: + * use pstates sorted by stage to check planes on same stage + * we assume that all pipes are in source split so its valid to compare + * without taking into account left/right mixer placement + */ + for (i = 1; i < cnt; i++) { + struct plane_state *prv_pstate, *cur_pstate; + struct drm_rect left_rect, right_rect; + int32_t left_pid, right_pid; + int32_t stage; + + prv_pstate = &pstates[i - 1]; + cur_pstate = &pstates[i]; + if (prv_pstate->stage != cur_pstate->stage) + continue; + + stage = cur_pstate->stage; + + left_pid = prv_pstate->dpu_pstate->base.plane->base.id; + left_rect = drm_plane_state_dest(prv_pstate->drm_pstate); + + right_pid = cur_pstate->dpu_pstate->base.plane->base.id; + right_rect = drm_plane_state_dest(cur_pstate->drm_pstate); + + if (right_rect.x1 < left_rect.x1) { + swap(left_pid, right_pid); + swap(left_rect, right_rect); + } + + /** + * - planes are enumerated in pipe-priority order such that + * planes with lower drm_id must be left-most in a shared + * blend-stage when using source split. + * - planes in source split must be contiguous in width + * - planes in source split must have same dest yoff and height + */ + if (right_pid < left_pid) { + DPU_ERROR( + "invalid src split cfg. priority mismatch. stage: %d left: %d right: %d\n", + stage, left_pid, right_pid); + rc = -EINVAL; + goto end; + } else if (right_rect.x1 != drm_rect_width(&left_rect)) { + DPU_ERROR("non-contiguous coordinates for src split. " + "stage: %d left: " DRM_RECT_FMT " right: " + DRM_RECT_FMT "\n", stage, + DRM_RECT_ARG(&left_rect), + DRM_RECT_ARG(&right_rect)); + rc = -EINVAL; + goto end; + } else if (left_rect.y1 != right_rect.y1 || + drm_rect_height(&left_rect) != drm_rect_height(&right_rect)) { + DPU_ERROR("source split at stage: %d. invalid " + "yoff/height: left: " DRM_RECT_FMT " right: " + DRM_RECT_FMT "\n", stage, + DRM_RECT_ARG(&left_rect), + DRM_RECT_ARG(&right_rect)); + rc = -EINVAL; + goto end; + } + } + +end: + _dpu_crtc_rp_free_unused(&cstate->rp); + kfree(pstates); + return rc; +} + +int dpu_crtc_vblank(struct drm_crtc *crtc, bool en) +{ + struct dpu_crtc *dpu_crtc; + int ret; + + if (!crtc) { + DPU_ERROR("invalid crtc\n"); + return -EINVAL; + } + dpu_crtc = to_dpu_crtc(crtc); + + mutex_lock(&dpu_crtc->crtc_lock); + trace_dpu_crtc_vblank(DRMID(&dpu_crtc->base), en, dpu_crtc); + if (dpu_crtc->enabled && !dpu_crtc->suspend) { + ret = _dpu_crtc_vblank_enable_no_lock(dpu_crtc, en); + if (ret) + DPU_ERROR("%s vblank enable failed: %d\n", + dpu_crtc->name, ret); + } + dpu_crtc->vblank_requested = en; + mutex_unlock(&dpu_crtc->crtc_lock); + + return 0; +} + +#ifdef CONFIG_DEBUG_FS +static int _dpu_debugfs_status_show(struct seq_file *s, void *data) +{ + struct dpu_crtc *dpu_crtc; + struct dpu_plane_state *pstate = NULL; + struct dpu_crtc_mixer *m; + + struct drm_crtc *crtc; + struct drm_plane *plane; + struct drm_display_mode *mode; + struct drm_framebuffer *fb; + struct drm_plane_state *state; + struct dpu_crtc_state *cstate; + + int i, out_width; + + if (!s || !s->private) + return -EINVAL; + + dpu_crtc = s->private; + crtc = &dpu_crtc->base; + cstate = to_dpu_crtc_state(crtc->state); + + mutex_lock(&dpu_crtc->crtc_lock); + mode = &crtc->state->adjusted_mode; + out_width = dpu_crtc_get_mixer_width(dpu_crtc, cstate, mode); + + seq_printf(s, "crtc:%d width:%d height:%d\n", crtc->base.id, + mode->hdisplay, mode->vdisplay); + + seq_puts(s, "\n"); + + for (i = 0; i < dpu_crtc->num_mixers; ++i) { + m = &dpu_crtc->mixers[i]; + if (!m->hw_lm) + seq_printf(s, "\tmixer[%d] has no lm\n", i); + else if (!m->hw_ctl) + seq_printf(s, "\tmixer[%d] has no ctl\n", i); + else + seq_printf(s, "\tmixer:%d ctl:%d width:%d height:%d\n", + m->hw_lm->idx - LM_0, m->hw_ctl->idx - CTL_0, + out_width, mode->vdisplay); + } + + seq_puts(s, "\n"); + + drm_atomic_crtc_for_each_plane(plane, crtc) { + pstate = to_dpu_plane_state(plane->state); + state = plane->state; + + if (!pstate || !state) + continue; + + seq_printf(s, "\tplane:%u stage:%d\n", plane->base.id, + pstate->stage); + + if (plane->state->fb) { + fb = plane->state->fb; + + seq_printf(s, "\tfb:%d image format:%4.4s wxh:%ux%u ", + fb->base.id, (char *) &fb->format->format, + fb->width, fb->height); + for (i = 0; i < ARRAY_SIZE(fb->format->cpp); ++i) + seq_printf(s, "cpp[%d]:%u ", + i, fb->format->cpp[i]); + seq_puts(s, "\n\t"); + + seq_printf(s, "modifier:%8llu ", fb->modifier); + seq_puts(s, "\n"); + + seq_puts(s, "\t"); + for (i = 0; i < ARRAY_SIZE(fb->pitches); i++) + seq_printf(s, "pitches[%d]:%8u ", i, + fb->pitches[i]); + seq_puts(s, "\n"); + + seq_puts(s, "\t"); + for (i = 0; i < ARRAY_SIZE(fb->offsets); i++) + seq_printf(s, "offsets[%d]:%8u ", i, + fb->offsets[i]); + seq_puts(s, "\n"); + } + + seq_printf(s, "\tsrc_x:%4d src_y:%4d src_w:%4d src_h:%4d\n", + state->src_x, state->src_y, state->src_w, state->src_h); + + seq_printf(s, "\tdst x:%4d dst_y:%4d dst_w:%4d dst_h:%4d\n", + state->crtc_x, state->crtc_y, state->crtc_w, + state->crtc_h); + seq_printf(s, "\tmultirect: mode: %d index: %d\n", + pstate->multirect_mode, pstate->multirect_index); + + seq_puts(s, "\n"); + } + if (dpu_crtc->vblank_cb_count) { + ktime_t diff = ktime_sub(ktime_get(), dpu_crtc->vblank_cb_time); + s64 diff_ms = ktime_to_ms(diff); + s64 fps = diff_ms ? div_s64( + dpu_crtc->vblank_cb_count * 1000, diff_ms) : 0; + + seq_printf(s, + "vblank fps:%lld count:%u total:%llums total_framecount:%llu\n", + fps, dpu_crtc->vblank_cb_count, + ktime_to_ms(diff), dpu_crtc->play_count); + + /* reset time & count for next measurement */ + dpu_crtc->vblank_cb_count = 0; + dpu_crtc->vblank_cb_time = ktime_set(0, 0); + } + + seq_printf(s, "vblank_enable:%d\n", dpu_crtc->vblank_requested); + + mutex_unlock(&dpu_crtc->crtc_lock); + + return 0; +} + +static int _dpu_debugfs_status_open(struct inode *inode, struct file *file) +{ + return single_open(file, _dpu_debugfs_status_show, inode->i_private); +} + +static ssize_t _dpu_crtc_misr_setup(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + struct dpu_crtc *dpu_crtc; + struct dpu_crtc_mixer *m; + int i = 0, rc; + char buf[MISR_BUFF_SIZE + 1]; + u32 frame_count, enable; + size_t buff_copy; + + if (!file || !file->private_data) + return -EINVAL; + + dpu_crtc = file->private_data; + buff_copy = min_t(size_t, count, MISR_BUFF_SIZE); + if (copy_from_user(buf, user_buf, buff_copy)) { + DPU_ERROR("buffer copy failed\n"); + return -EINVAL; + } + + buf[buff_copy] = 0; /* end of string */ + + if (sscanf(buf, "%u %u", &enable, &frame_count) != 2) + return -EINVAL; + + rc = _dpu_crtc_power_enable(dpu_crtc, true); + if (rc) + return rc; + + mutex_lock(&dpu_crtc->crtc_lock); + dpu_crtc->misr_enable = enable; + dpu_crtc->misr_frame_count = frame_count; + for (i = 0; i < dpu_crtc->num_mixers; ++i) { + dpu_crtc->misr_data[i] = 0; + m = &dpu_crtc->mixers[i]; + if (!m->hw_lm || !m->hw_lm->ops.setup_misr) + continue; + + m->hw_lm->ops.setup_misr(m->hw_lm, enable, frame_count); + } + mutex_unlock(&dpu_crtc->crtc_lock); + _dpu_crtc_power_enable(dpu_crtc, false); + + return count; +} + +static ssize_t _dpu_crtc_misr_read(struct file *file, + char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dpu_crtc *dpu_crtc; + struct dpu_crtc_mixer *m; + int i = 0, rc; + u32 misr_status; + ssize_t len = 0; + char buf[MISR_BUFF_SIZE + 1] = {'\0'}; + + if (*ppos) + return 0; + + if (!file || !file->private_data) + return -EINVAL; + + dpu_crtc = file->private_data; + rc = _dpu_crtc_power_enable(dpu_crtc, true); + if (rc) + return rc; + + mutex_lock(&dpu_crtc->crtc_lock); + if (!dpu_crtc->misr_enable) { + len += snprintf(buf + len, MISR_BUFF_SIZE - len, + "disabled\n"); + goto buff_check; + } + + for (i = 0; i < dpu_crtc->num_mixers; ++i) { + m = &dpu_crtc->mixers[i]; + if (!m->hw_lm || !m->hw_lm->ops.collect_misr) + continue; + + misr_status = m->hw_lm->ops.collect_misr(m->hw_lm); + dpu_crtc->misr_data[i] = misr_status ? misr_status : + dpu_crtc->misr_data[i]; + len += snprintf(buf + len, MISR_BUFF_SIZE - len, "lm idx:%d\n", + m->hw_lm->idx - LM_0); + len += snprintf(buf + len, MISR_BUFF_SIZE - len, "0x%x\n", + dpu_crtc->misr_data[i]); + } + +buff_check: + if (count <= len) { + len = 0; + goto end; + } + + if (copy_to_user(user_buff, buf, len)) { + len = -EFAULT; + goto end; + } + + *ppos += len; /* increase offset */ + +end: + mutex_unlock(&dpu_crtc->crtc_lock); + _dpu_crtc_power_enable(dpu_crtc, false); + return len; +} + +#define DEFINE_DPU_DEBUGFS_SEQ_FOPS(__prefix) \ +static int __prefix ## _open(struct inode *inode, struct file *file) \ +{ \ + return single_open(file, __prefix ## _show, inode->i_private); \ +} \ +static const struct file_operations __prefix ## _fops = { \ + .owner = THIS_MODULE, \ + .open = __prefix ## _open, \ + .release = single_release, \ + .read = seq_read, \ + .llseek = seq_lseek, \ +} + +static int dpu_crtc_debugfs_state_show(struct seq_file *s, void *v) +{ + struct drm_crtc *crtc = (struct drm_crtc *) s->private; + struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); + struct dpu_crtc_res *res; + struct dpu_crtc_respool *rp; + int i; + + seq_printf(s, "client type: %d\n", dpu_crtc_get_client_type(crtc)); + seq_printf(s, "intf_mode: %d\n", dpu_crtc_get_intf_mode(crtc)); + seq_printf(s, "core_clk_rate: %llu\n", + dpu_crtc->cur_perf.core_clk_rate); + for (i = DPU_POWER_HANDLE_DBUS_ID_MNOC; + i < DPU_POWER_HANDLE_DBUS_ID_MAX; i++) { + seq_printf(s, "bw_ctl[%s]: %llu\n", + dpu_power_handle_get_dbus_name(i), + dpu_crtc->cur_perf.bw_ctl[i]); + seq_printf(s, "max_per_pipe_ib[%s]: %llu\n", + dpu_power_handle_get_dbus_name(i), + dpu_crtc->cur_perf.max_per_pipe_ib[i]); + } + + mutex_lock(&dpu_crtc->rp_lock); + list_for_each_entry(rp, &dpu_crtc->rp_head, rp_list) { + seq_printf(s, "rp.%d: ", rp->sequence_id); + list_for_each_entry(res, &rp->res_list, list) + seq_printf(s, "0x%x/0x%llx/%pK/%d ", + res->type, res->tag, res->val, + atomic_read(&res->refcount)); + seq_puts(s, "\n"); + } + mutex_unlock(&dpu_crtc->rp_lock); + + return 0; +} +DEFINE_DPU_DEBUGFS_SEQ_FOPS(dpu_crtc_debugfs_state); + +static int _dpu_crtc_init_debugfs(struct drm_crtc *crtc) +{ + struct dpu_crtc *dpu_crtc; + struct dpu_kms *dpu_kms; + + static const struct file_operations debugfs_status_fops = { + .open = _dpu_debugfs_status_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + }; + static const struct file_operations debugfs_misr_fops = { + .open = simple_open, + .read = _dpu_crtc_misr_read, + .write = _dpu_crtc_misr_setup, + }; + + if (!crtc) + return -EINVAL; + dpu_crtc = to_dpu_crtc(crtc); + + dpu_kms = _dpu_crtc_get_kms(crtc); + if (!dpu_kms) + return -EINVAL; + + dpu_crtc->debugfs_root = debugfs_create_dir(dpu_crtc->name, + crtc->dev->primary->debugfs_root); + if (!dpu_crtc->debugfs_root) + return -ENOMEM; + + /* don't error check these */ + debugfs_create_file("status", 0400, + dpu_crtc->debugfs_root, + dpu_crtc, &debugfs_status_fops); + debugfs_create_file("state", 0600, + dpu_crtc->debugfs_root, + &dpu_crtc->base, + &dpu_crtc_debugfs_state_fops); + debugfs_create_file("misr_data", 0600, dpu_crtc->debugfs_root, + dpu_crtc, &debugfs_misr_fops); + + return 0; +} + +static void _dpu_crtc_destroy_debugfs(struct drm_crtc *crtc) +{ + struct dpu_crtc *dpu_crtc; + + if (!crtc) + return; + dpu_crtc = to_dpu_crtc(crtc); + debugfs_remove_recursive(dpu_crtc->debugfs_root); +} +#else +static int _dpu_crtc_init_debugfs(struct drm_crtc *crtc) +{ + return 0; +} + +static void _dpu_crtc_destroy_debugfs(struct drm_crtc *crtc) +{ +} +#endif /* CONFIG_DEBUG_FS */ + +static int dpu_crtc_late_register(struct drm_crtc *crtc) +{ + return _dpu_crtc_init_debugfs(crtc); +} + +static void dpu_crtc_early_unregister(struct drm_crtc *crtc) +{ + _dpu_crtc_destroy_debugfs(crtc); +} + +static const struct drm_crtc_funcs dpu_crtc_funcs = { + .set_config = drm_atomic_helper_set_config, + .destroy = dpu_crtc_destroy, + .page_flip = drm_atomic_helper_page_flip, + .reset = dpu_crtc_reset, + .atomic_duplicate_state = dpu_crtc_duplicate_state, + .atomic_destroy_state = dpu_crtc_destroy_state, + .late_register = dpu_crtc_late_register, + .early_unregister = dpu_crtc_early_unregister, +}; + +static const struct drm_crtc_helper_funcs dpu_crtc_helper_funcs = { + .disable = dpu_crtc_disable, + .atomic_enable = dpu_crtc_enable, + .atomic_check = dpu_crtc_atomic_check, + .atomic_begin = dpu_crtc_atomic_begin, + .atomic_flush = dpu_crtc_atomic_flush, +}; + +static void _dpu_crtc_event_cb(struct kthread_work *work) +{ + struct dpu_crtc_event *event; + struct dpu_crtc *dpu_crtc; + unsigned long irq_flags; + + if (!work) { + DPU_ERROR("invalid work item\n"); + return; + } + + event = container_of(work, struct dpu_crtc_event, kt_work); + + /* set dpu_crtc to NULL for static work structures */ + dpu_crtc = event->dpu_crtc; + if (!dpu_crtc) + return; + + if (event->cb_func) + event->cb_func(&dpu_crtc->base, event->usr); + + spin_lock_irqsave(&dpu_crtc->event_lock, irq_flags); + list_add_tail(&event->list, &dpu_crtc->event_free_list); + spin_unlock_irqrestore(&dpu_crtc->event_lock, irq_flags); +} + +int dpu_crtc_event_queue(struct drm_crtc *crtc, + void (*func)(struct drm_crtc *crtc, void *usr), void *usr) +{ + unsigned long irq_flags; + struct dpu_crtc *dpu_crtc; + struct msm_drm_private *priv; + struct dpu_crtc_event *event = NULL; + u32 crtc_id; + + if (!crtc || !crtc->dev || !crtc->dev->dev_private || !func) { + DPU_ERROR("invalid parameters\n"); + return -EINVAL; + } + dpu_crtc = to_dpu_crtc(crtc); + priv = crtc->dev->dev_private; + crtc_id = drm_crtc_index(crtc); + + /* + * Obtain an event struct from the private cache. This event + * queue may be called from ISR contexts, so use a private + * cache to avoid calling any memory allocation functions. + */ + spin_lock_irqsave(&dpu_crtc->event_lock, irq_flags); + if (!list_empty(&dpu_crtc->event_free_list)) { + event = list_first_entry(&dpu_crtc->event_free_list, + struct dpu_crtc_event, list); + list_del_init(&event->list); + } + spin_unlock_irqrestore(&dpu_crtc->event_lock, irq_flags); + + if (!event) + return -ENOMEM; + + /* populate event node */ + event->dpu_crtc = dpu_crtc; + event->cb_func = func; + event->usr = usr; + + /* queue new event request */ + kthread_init_work(&event->kt_work, _dpu_crtc_event_cb); + kthread_queue_work(&priv->event_thread[crtc_id].worker, + &event->kt_work); + + return 0; +} + +static int _dpu_crtc_init_events(struct dpu_crtc *dpu_crtc) +{ + int i, rc = 0; + + if (!dpu_crtc) { + DPU_ERROR("invalid crtc\n"); + return -EINVAL; + } + + spin_lock_init(&dpu_crtc->event_lock); + + INIT_LIST_HEAD(&dpu_crtc->event_free_list); + for (i = 0; i < DPU_CRTC_MAX_EVENT_COUNT; ++i) + list_add_tail(&dpu_crtc->event_cache[i].list, + &dpu_crtc->event_free_list); + + return rc; +} + +/* initialize crtc */ +struct drm_crtc *dpu_crtc_init(struct drm_device *dev, struct drm_plane *plane) +{ + struct drm_crtc *crtc = NULL; + struct dpu_crtc *dpu_crtc = NULL; + struct msm_drm_private *priv = NULL; + struct dpu_kms *kms = NULL; + int i, rc; + + priv = dev->dev_private; + kms = to_dpu_kms(priv->kms); + + dpu_crtc = kzalloc(sizeof(*dpu_crtc), GFP_KERNEL); + if (!dpu_crtc) + return ERR_PTR(-ENOMEM); + + crtc = &dpu_crtc->base; + crtc->dev = dev; + + mutex_init(&dpu_crtc->crtc_lock); + spin_lock_init(&dpu_crtc->spin_lock); + atomic_set(&dpu_crtc->frame_pending, 0); + + mutex_init(&dpu_crtc->rp_lock); + INIT_LIST_HEAD(&dpu_crtc->rp_head); + + init_completion(&dpu_crtc->frame_done_comp); + + INIT_LIST_HEAD(&dpu_crtc->frame_event_list); + + for (i = 0; i < ARRAY_SIZE(dpu_crtc->frame_events); i++) { + INIT_LIST_HEAD(&dpu_crtc->frame_events[i].list); + list_add(&dpu_crtc->frame_events[i].list, + &dpu_crtc->frame_event_list); + kthread_init_work(&dpu_crtc->frame_events[i].work, + dpu_crtc_frame_event_work); + } + + drm_crtc_init_with_planes(dev, crtc, plane, NULL, &dpu_crtc_funcs, + NULL); + + drm_crtc_helper_add(crtc, &dpu_crtc_helper_funcs); + plane->crtc = crtc; + + /* save user friendly CRTC name for later */ + snprintf(dpu_crtc->name, DPU_CRTC_NAME_SIZE, "crtc%u", crtc->base.id); + + /* initialize event handling */ + rc = _dpu_crtc_init_events(dpu_crtc); + if (rc) { + drm_crtc_cleanup(crtc); + kfree(dpu_crtc); + return ERR_PTR(rc); + } + + dpu_crtc->phandle = &kms->phandle; + + DPU_DEBUG("%s: successfully initialized crtc\n", dpu_crtc->name); + return crtc; +} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h new file mode 100644 index 0000000000000..4a97ba16735f2 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h @@ -0,0 +1,484 @@ +/* + * Copyright (c) 2015-2018 The Linux Foundation. All rights reserved. + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.com> + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _DPU_CRTC_H_ +#define _DPU_CRTC_H_ + +#include <linux/kthread.h> +#include <drm/drm_crtc.h> +#include "dpu_kms.h" +#include "dpu_core_perf.h" +#include "dpu_hw_blk.h" + +#define DPU_CRTC_NAME_SIZE 12 + +/* define the maximum number of in-flight frame events */ +#define DPU_CRTC_FRAME_EVENT_SIZE 4 + +/** + * enum dpu_crtc_client_type: crtc client type + * @RT_CLIENT: RealTime client like video/cmd mode display + * voting through apps rsc + * @NRT_CLIENT: Non-RealTime client like WB display + * voting through apps rsc + */ +enum dpu_crtc_client_type { + RT_CLIENT, + NRT_CLIENT, +}; + +/** + * enum dpu_crtc_smmu_state: smmu state + * @ATTACHED: all the context banks are attached. + * @DETACHED: all the context banks are detached. + * @ATTACH_ALL_REQ: transient state of attaching context banks. + * @DETACH_ALL_REQ: transient state of detaching context banks. + */ +enum dpu_crtc_smmu_state { + ATTACHED = 0, + DETACHED, + ATTACH_ALL_REQ, + DETACH_ALL_REQ, +}; + +/** + * enum dpu_crtc_smmu_state_transition_type: state transition type + * @NONE: no pending state transitions + * @PRE_COMMIT: state transitions should be done before processing the commit + * @POST_COMMIT: state transitions to be done after processing the commit. + */ +enum dpu_crtc_smmu_state_transition_type { + NONE, + PRE_COMMIT, + POST_COMMIT +}; + +/** + * struct dpu_crtc_smmu_state_data: stores the smmu state and transition type + * @state: current state of smmu context banks + * @transition_type: transition request type + * @transition_error: whether there is error while transitioning the state + */ +struct dpu_crtc_smmu_state_data { + uint32_t state; + uint32_t transition_type; + uint32_t transition_error; +}; + +/** + * struct dpu_crtc_mixer: stores the map for each virtual pipeline in the CRTC + * @hw_lm: LM HW Driver context + * @hw_ctl: CTL Path HW driver context + * @encoder: Encoder attached to this lm & ctl + * @mixer_op_mode: mixer blending operation mode + * @flush_mask: mixer flush mask for ctl, mixer and pipe + */ +struct dpu_crtc_mixer { + struct dpu_hw_mixer *hw_lm; + struct dpu_hw_ctl *hw_ctl; + struct drm_encoder *encoder; + u32 mixer_op_mode; + u32 flush_mask; +}; + +/** + * struct dpu_crtc_frame_event: stores crtc frame event for crtc processing + * @work: base work structure + * @crtc: Pointer to crtc handling this event + * @list: event list + * @ts: timestamp at queue entry + * @event: event identifier + */ +struct dpu_crtc_frame_event { + struct kthread_work work; + struct drm_crtc *crtc; + struct list_head list; + ktime_t ts; + u32 event; +}; + +/** + * struct dpu_crtc_event - event callback tracking structure + * @list: Linked list tracking node + * @kt_work: Kthread worker structure + * @dpu_crtc: Pointer to associated dpu_crtc structure + * @cb_func: Pointer to callback function + * @usr: Pointer to user data to be provided to the callback + */ +struct dpu_crtc_event { + struct list_head list; + struct kthread_work kt_work; + void *dpu_crtc; + + void (*cb_func)(struct drm_crtc *crtc, void *usr); + void *usr; +}; + +/* + * Maximum number of free event structures to cache + */ +#define DPU_CRTC_MAX_EVENT_COUNT 16 + +/** + * struct dpu_crtc - virtualized CRTC data structure + * @base : Base drm crtc structure + * @name : ASCII description of this crtc + * @num_ctls : Number of ctl paths in use + * @num_mixers : Number of mixers in use + * @mixers_swapped: Whether the mixers have been swapped for left/right update + * especially in the case of DSC Merge. + * @mixers : List of active mixers + * @event : Pointer to last received drm vblank event. If there is a + * pending vblank event, this will be non-null. + * @vsync_count : Running count of received vsync events + * @drm_requested_vblank : Whether vblanks have been enabled in the encoder + * @property_info : Opaque structure for generic property support + * @property_defaults : Array of default values for generic property support + * @stage_cfg : H/w mixer stage configuration + * @debugfs_root : Parent of debugfs node + * @vblank_cb_count : count of vblank callback since last reset + * @play_count : frame count between crtc enable and disable + * @vblank_cb_time : ktime at vblank count reset + * @vblank_requested : whether the user has requested vblank events + * @suspend : whether or not a suspend operation is in progress + * @enabled : whether the DPU CRTC is currently enabled. updated in the + * commit-thread, not state-swap time which is earlier, so + * safe to make decisions on during VBLANK on/off work + * @feature_list : list of color processing features supported on a crtc + * @active_list : list of color processing features are active + * @dirty_list : list of color processing features are dirty + * @ad_dirty: list containing ad properties that are dirty + * @ad_active: list containing ad properties that are active + * @crtc_lock : crtc lock around create, destroy and access. + * @frame_pending : Whether or not an update is pending + * @frame_events : static allocation of in-flight frame events + * @frame_event_list : available frame event list + * @spin_lock : spin lock for frame event, transaction status, etc... + * @frame_done_comp : for frame_event_done synchronization + * @event_thread : Pointer to event handler thread + * @event_worker : Event worker queue + * @event_cache : Local cache of event worker structures + * @event_free_list : List of available event structures + * @event_lock : Spinlock around event handling code + * @misr_enable : boolean entry indicates misr enable/disable status. + * @misr_frame_count : misr frame count provided by client + * @misr_data : store misr data before turning off the clocks. + * @phandle: Pointer to power handler + * @power_event : registered power event handle + * @cur_perf : current performance committed to clock/bandwidth driver + * @rp_lock : serialization lock for resource pool + * @rp_head : list of active resource pool + * @scl3_cfg_lut : qseed3 lut config + */ +struct dpu_crtc { + struct drm_crtc base; + char name[DPU_CRTC_NAME_SIZE]; + + /* HW Resources reserved for the crtc */ + u32 num_ctls; + u32 num_mixers; + bool mixers_swapped; + struct dpu_crtc_mixer mixers[CRTC_DUAL_MIXERS]; + struct dpu_hw_scaler3_lut_cfg *scl3_lut_cfg; + + struct drm_pending_vblank_event *event; + u32 vsync_count; + + struct dpu_hw_stage_cfg stage_cfg; + struct dentry *debugfs_root; + + u32 vblank_cb_count; + u64 play_count; + ktime_t vblank_cb_time; + bool vblank_requested; + bool suspend; + bool enabled; + + struct list_head feature_list; + struct list_head active_list; + struct list_head dirty_list; + struct list_head ad_dirty; + struct list_head ad_active; + + struct mutex crtc_lock; + + atomic_t frame_pending; + struct dpu_crtc_frame_event frame_events[DPU_CRTC_FRAME_EVENT_SIZE]; + struct list_head frame_event_list; + spinlock_t spin_lock; + struct completion frame_done_comp; + + /* for handling internal event thread */ + struct dpu_crtc_event event_cache[DPU_CRTC_MAX_EVENT_COUNT]; + struct list_head event_free_list; + spinlock_t event_lock; + bool misr_enable; + u32 misr_frame_count; + u32 misr_data[CRTC_DUAL_MIXERS]; + + struct dpu_power_handle *phandle; + struct dpu_power_event *power_event; + + struct dpu_core_perf_params cur_perf; + + struct mutex rp_lock; + struct list_head rp_head; + + struct dpu_crtc_smmu_state_data smmu_state; +}; + +#define to_dpu_crtc(x) container_of(x, struct dpu_crtc, base) + +/** + * struct dpu_crtc_res_ops - common operations for crtc resources + * @get: get given resource + * @put: put given resource + */ +struct dpu_crtc_res_ops { + void *(*get)(void *val, u32 type, u64 tag); + void (*put)(void *val); +}; + +#define DPU_CRTC_RES_FLAG_FREE BIT(0) + +/** + * struct dpu_crtc_res - definition of crtc resources + * @list: list of crtc resource + * @type: crtc resource type + * @tag: unique identifier per type + * @refcount: reference/usage count + * @ops: callback operations + * @val: resource handle associated with type/tag + * @flags: customization flags + */ +struct dpu_crtc_res { + struct list_head list; + u32 type; + u64 tag; + atomic_t refcount; + struct dpu_crtc_res_ops ops; + void *val; + u32 flags; +}; + +/** + * dpu_crtc_respool - crtc resource pool + * @rp_lock: pointer to serialization lock + * @rp_head: pointer to head of active resource pools of this crtc + * @rp_list: list of crtc resource pool + * @sequence_id: sequence identifier, incremented per state duplication + * @res_list: list of resource managed by this resource pool + * @ops: resource operations for parent resource pool + */ +struct dpu_crtc_respool { + struct mutex *rp_lock; + struct list_head *rp_head; + struct list_head rp_list; + u32 sequence_id; + struct list_head res_list; + struct dpu_crtc_res_ops ops; +}; + +/** + * struct dpu_crtc_state - dpu container for atomic crtc state + * @base: Base drm crtc state structure + * @is_ppsplit : Whether current topology requires PPSplit special handling + * @bw_control : true if bw/clk controlled by core bw/clk properties + * @bw_split_vote : true if bw controlled by llcc/dram bw properties + * @lm_bounds : LM boundaries based on current mode full resolution, no ROI. + * Origin top left of CRTC. + * @property_state: Local storage for msm_prop properties + * @property_values: Current crtc property values + * @input_fence_timeout_ns : Cached input fence timeout, in ns + * @new_perf: new performance state being requested + */ +struct dpu_crtc_state { + struct drm_crtc_state base; + + bool bw_control; + bool bw_split_vote; + + bool is_ppsplit; + struct drm_rect lm_bounds[CRTC_DUAL_MIXERS]; + + uint64_t input_fence_timeout_ns; + + struct dpu_core_perf_params new_perf; + struct dpu_crtc_respool rp; +}; + +#define to_dpu_crtc_state(x) \ + container_of(x, struct dpu_crtc_state, base) + +/** + * dpu_crtc_get_mixer_width - get the mixer width + * Mixer width will be same as panel width(/2 for split) + */ +static inline int dpu_crtc_get_mixer_width(struct dpu_crtc *dpu_crtc, + struct dpu_crtc_state *cstate, struct drm_display_mode *mode) +{ + u32 mixer_width; + + if (!dpu_crtc || !cstate || !mode) + return 0; + + mixer_width = (dpu_crtc->num_mixers == CRTC_DUAL_MIXERS ? + mode->hdisplay / CRTC_DUAL_MIXERS : mode->hdisplay); + + return mixer_width; +} + +/** + * dpu_crtc_get_mixer_height - get the mixer height + * Mixer height will be same as panel height + */ +static inline int dpu_crtc_get_mixer_height(struct dpu_crtc *dpu_crtc, + struct dpu_crtc_state *cstate, struct drm_display_mode *mode) +{ + if (!dpu_crtc || !cstate || !mode) + return 0; + + return mode->vdisplay; +} + +/** + * dpu_crtc_frame_pending - retun the number of pending frames + * @crtc: Pointer to drm crtc object + */ +static inline int dpu_crtc_frame_pending(struct drm_crtc *crtc) +{ + struct dpu_crtc *dpu_crtc; + + if (!crtc) + return -EINVAL; + + dpu_crtc = to_dpu_crtc(crtc); + return atomic_read(&dpu_crtc->frame_pending); +} + +/** + * dpu_crtc_vblank - enable or disable vblanks for this crtc + * @crtc: Pointer to drm crtc object + * @en: true to enable vblanks, false to disable + */ +int dpu_crtc_vblank(struct drm_crtc *crtc, bool en); + +/** + * dpu_crtc_commit_kickoff - trigger kickoff of the commit for this crtc + * @crtc: Pointer to drm crtc object + */ +void dpu_crtc_commit_kickoff(struct drm_crtc *crtc); + +/** + * dpu_crtc_complete_commit - callback signalling completion of current commit + * @crtc: Pointer to drm crtc object + * @old_state: Pointer to drm crtc old state object + */ +void dpu_crtc_complete_commit(struct drm_crtc *crtc, + struct drm_crtc_state *old_state); + +/** + * dpu_crtc_init - create a new crtc object + * @dev: dpu device + * @plane: base plane + * @Return: new crtc object or error + */ +struct drm_crtc *dpu_crtc_init(struct drm_device *dev, struct drm_plane *plane); + +/** + * dpu_crtc_register_custom_event - api for enabling/disabling crtc event + * @kms: Pointer to dpu_kms + * @crtc_drm: Pointer to crtc object + * @event: Event that client is interested + * @en: Flag to enable/disable the event + */ +int dpu_crtc_register_custom_event(struct dpu_kms *kms, + struct drm_crtc *crtc_drm, u32 event, bool en); + +/** + * dpu_crtc_get_intf_mode - get interface mode of the given crtc + * @crtc: Pointert to crtc + */ +enum dpu_intf_mode dpu_crtc_get_intf_mode(struct drm_crtc *crtc); + +/** + * dpu_crtc_get_client_type - check the crtc type- rt, nrt etc. + * @crtc: Pointer to crtc + */ +static inline enum dpu_crtc_client_type dpu_crtc_get_client_type( + struct drm_crtc *crtc) +{ + struct dpu_crtc_state *cstate = + crtc ? to_dpu_crtc_state(crtc->state) : NULL; + + if (!cstate) + return NRT_CLIENT; + + return RT_CLIENT; +} + +/** + * dpu_crtc_is_enabled - check if dpu crtc is enabled or not + * @crtc: Pointer to crtc + */ +static inline bool dpu_crtc_is_enabled(struct drm_crtc *crtc) +{ + return crtc ? crtc->enabled : false; +} + +/** + * dpu_crtc_event_queue - request event callback + * @crtc: Pointer to drm crtc structure + * @func: Pointer to callback function + * @usr: Pointer to user data to be passed to callback + * Returns: Zero on success + */ +int dpu_crtc_event_queue(struct drm_crtc *crtc, + void (*func)(struct drm_crtc *crtc, void *usr), void *usr); + +/** + * dpu_crtc_res_add - add given resource to resource pool in crtc state + * @state: Pointer to drm crtc state + * @type: Resource type + * @tag: Search tag for given resource + * @val: Resource handle + * @ops: Resource callback operations + * return: 0 if success; error code otherwise + */ +int dpu_crtc_res_add(struct drm_crtc_state *state, u32 type, u64 tag, + void *val, struct dpu_crtc_res_ops *ops); + +/** + * dpu_crtc_res_get - get given resource from resource pool in crtc state + * @state: Pointer to drm crtc state + * @type: Resource type + * @tag: Search tag for given resource + * return: Resource handle if success; pointer error or null otherwise + */ +void *dpu_crtc_res_get(struct drm_crtc_state *state, u32 type, u64 tag); + +/** + * dpu_crtc_res_put - return given resource to resource pool in crtc state + * @state: Pointer to drm crtc state + * @type: Resource type + * @tag: Search tag for given resource + * return: None + */ +void dpu_crtc_res_put(struct drm_crtc_state *state, u32 type, u64 tag); + +#endif /* _DPU_CRTC_H_ */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.c new file mode 100644 index 0000000000000..ae2aee7ed9e19 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.c @@ -0,0 +1,2393 @@ +/* Copyright (c) 2009-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ + +#include <linux/delay.h> +#include <linux/spinlock.h> +#include <linux/ktime.h> +#include <linux/debugfs.h> +#include <linux/uaccess.h> +#include <linux/dma-buf.h> +#include <linux/slab.h> +#include <linux/list_sort.h> +#include <linux/pm_runtime.h> + +#include "dpu_dbg.h" +#include "disp/dpu1/dpu_hw_catalog.h" + + +#define DEFAULT_DBGBUS_DPU DPU_DBG_DUMP_IN_MEM +#define DEFAULT_DBGBUS_VBIFRT DPU_DBG_DUMP_IN_MEM +#define REG_BASE_NAME_LEN 80 + +#define DBGBUS_FLAGS_DSPP BIT(0) +#define DBGBUS_DSPP_STATUS 0x34C + +#define DBGBUS_NAME_DPU "dpu" +#define DBGBUS_NAME_VBIF_RT "vbif_rt" + +/* offsets from dpu top address for the debug buses */ +#define DBGBUS_SSPP0 0x188 +#define DBGBUS_AXI_INTF 0x194 +#define DBGBUS_SSPP1 0x298 +#define DBGBUS_DSPP 0x348 +#define DBGBUS_PERIPH 0x418 + +#define TEST_MASK(id, tp) ((id << 4) | (tp << 1) | BIT(0)) + +/* following offsets are with respect to MDP VBIF base for DBG BUS access */ +#define MMSS_VBIF_CLKON 0x4 +#define MMSS_VBIF_TEST_BUS_OUT_CTRL 0x210 +#define MMSS_VBIF_TEST_BUS_OUT 0x230 + +/* Vbif error info */ +#define MMSS_VBIF_PND_ERR 0x190 +#define MMSS_VBIF_SRC_ERR 0x194 +#define MMSS_VBIF_XIN_HALT_CTRL1 0x204 +#define MMSS_VBIF_ERR_INFO 0X1a0 +#define MMSS_VBIF_ERR_INFO_1 0x1a4 +#define MMSS_VBIF_CLIENT_NUM 14 + +/** + * struct dpu_dbg_reg_base - register region base. + * may sub-ranges: sub-ranges are used for dumping + * or may not have sub-ranges: dumping is base -> max_offset + * @reg_base_head: head of this node + * @name: register base name + * @base: base pointer + * @off: cached offset of region for manual register dumping + * @cnt: cached range of region for manual register dumping + * @max_offset: length of region + * @buf: buffer used for manual register dumping + * @buf_len: buffer length used for manual register dumping + * @cb: callback for external dump function, null if not defined + * @cb_ptr: private pointer to callback function + */ +struct dpu_dbg_reg_base { + struct list_head reg_base_head; + char name[REG_BASE_NAME_LEN]; + void __iomem *base; + size_t off; + size_t cnt; + size_t max_offset; + char *buf; + size_t buf_len; + void (*cb)(void *ptr); + void *cb_ptr; +}; + +struct dpu_debug_bus_entry { + u32 wr_addr; + u32 block_id; + u32 test_id; + void (*analyzer)(void __iomem *mem_base, + struct dpu_debug_bus_entry *entry, u32 val); +}; + +struct vbif_debug_bus_entry { + u32 disable_bus_addr; + u32 block_bus_addr; + u32 bit_offset; + u32 block_cnt; + u32 test_pnt_start; + u32 test_pnt_cnt; +}; + +struct dpu_dbg_debug_bus_common { + char *name; + u32 enable_mask; + bool include_in_deferred_work; + u32 flags; + u32 entries_size; + u32 *dumped_content; +}; + +struct dpu_dbg_dpu_debug_bus { + struct dpu_dbg_debug_bus_common cmn; + struct dpu_debug_bus_entry *entries; + u32 top_blk_off; +}; + +struct dpu_dbg_vbif_debug_bus { + struct dpu_dbg_debug_bus_common cmn; + struct vbif_debug_bus_entry *entries; +}; + +/** + * struct dpu_dbg_base - global dpu debug base structure + * @reg_base_list: list of register dumping regions + * @dev: device pointer + * @dump_work: work struct for deferring register dump work to separate thread + * @dbgbus_dpu: debug bus structure for the dpu + * @dbgbus_vbif_rt: debug bus structure for the realtime vbif + */ +static struct dpu_dbg_base { + struct list_head reg_base_list; + struct device *dev; + + struct work_struct dump_work; + + struct dpu_dbg_dpu_debug_bus dbgbus_dpu; + struct dpu_dbg_vbif_debug_bus dbgbus_vbif_rt; +} dpu_dbg_base; + +static void _dpu_debug_bus_xbar_dump(void __iomem *mem_base, + struct dpu_debug_bus_entry *entry, u32 val) +{ + dev_err(dpu_dbg_base.dev, "xbar 0x%x %d %d 0x%x\n", + entry->wr_addr, entry->block_id, entry->test_id, val); +} + +static void _dpu_debug_bus_lm_dump(void __iomem *mem_base, + struct dpu_debug_bus_entry *entry, u32 val) +{ + if (!(val & 0xFFF000)) + return; + + dev_err(dpu_dbg_base.dev, "lm 0x%x %d %d 0x%x\n", + entry->wr_addr, entry->block_id, entry->test_id, val); +} + +static void _dpu_debug_bus_ppb0_dump(void __iomem *mem_base, + struct dpu_debug_bus_entry *entry, u32 val) +{ + if (!(val & BIT(15))) + return; + + dev_err(dpu_dbg_base.dev, "ppb0 0x%x %d %d 0x%x\n", + entry->wr_addr, entry->block_id, entry->test_id, val); +} + +static void _dpu_debug_bus_ppb1_dump(void __iomem *mem_base, + struct dpu_debug_bus_entry *entry, u32 val) +{ + if (!(val & BIT(15))) + return; + + dev_err(dpu_dbg_base.dev, "ppb1 0x%x %d %d 0x%x\n", + entry->wr_addr, entry->block_id, entry->test_id, val); +} + +static struct dpu_debug_bus_entry dbg_bus_dpu_8998[] = { + + /* Unpack 0 sspp 0*/ + { DBGBUS_SSPP0, 50, 2 }, + { DBGBUS_SSPP0, 60, 2 }, + { DBGBUS_SSPP0, 70, 2 }, + { DBGBUS_SSPP0, 85, 2 }, + + /* Upack 0 sspp 1*/ + { DBGBUS_SSPP1, 50, 2 }, + { DBGBUS_SSPP1, 60, 2 }, + { DBGBUS_SSPP1, 70, 2 }, + { DBGBUS_SSPP1, 85, 2 }, + + /* scheduler */ + { DBGBUS_DSPP, 130, 0 }, + { DBGBUS_DSPP, 130, 1 }, + { DBGBUS_DSPP, 130, 2 }, + { DBGBUS_DSPP, 130, 3 }, + { DBGBUS_DSPP, 130, 4 }, + { DBGBUS_DSPP, 130, 5 }, + + /* qseed */ + { DBGBUS_SSPP0, 6, 0}, + { DBGBUS_SSPP0, 6, 1}, + { DBGBUS_SSPP0, 26, 0}, + { DBGBUS_SSPP0, 26, 1}, + { DBGBUS_SSPP1, 6, 0}, + { DBGBUS_SSPP1, 6, 1}, + { DBGBUS_SSPP1, 26, 0}, + { DBGBUS_SSPP1, 26, 1}, + + /* scale */ + { DBGBUS_SSPP0, 16, 0}, + { DBGBUS_SSPP0, 16, 1}, + { DBGBUS_SSPP0, 36, 0}, + { DBGBUS_SSPP0, 36, 1}, + { DBGBUS_SSPP1, 16, 0}, + { DBGBUS_SSPP1, 16, 1}, + { DBGBUS_SSPP1, 36, 0}, + { DBGBUS_SSPP1, 36, 1}, + + /* fetch sspp0 */ + + /* vig 0 */ + { DBGBUS_SSPP0, 0, 0 }, + { DBGBUS_SSPP0, 0, 1 }, + { DBGBUS_SSPP0, 0, 2 }, + { DBGBUS_SSPP0, 0, 3 }, + { DBGBUS_SSPP0, 0, 4 }, + { DBGBUS_SSPP0, 0, 5 }, + { DBGBUS_SSPP0, 0, 6 }, + { DBGBUS_SSPP0, 0, 7 }, + + { DBGBUS_SSPP0, 1, 0 }, + { DBGBUS_SSPP0, 1, 1 }, + { DBGBUS_SSPP0, 1, 2 }, + { DBGBUS_SSPP0, 1, 3 }, + { DBGBUS_SSPP0, 1, 4 }, + { DBGBUS_SSPP0, 1, 5 }, + { DBGBUS_SSPP0, 1, 6 }, + { DBGBUS_SSPP0, 1, 7 }, + + { DBGBUS_SSPP0, 2, 0 }, + { DBGBUS_SSPP0, 2, 1 }, + { DBGBUS_SSPP0, 2, 2 }, + { DBGBUS_SSPP0, 2, 3 }, + { DBGBUS_SSPP0, 2, 4 }, + { DBGBUS_SSPP0, 2, 5 }, + { DBGBUS_SSPP0, 2, 6 }, + { DBGBUS_SSPP0, 2, 7 }, + + { DBGBUS_SSPP0, 4, 0 }, + { DBGBUS_SSPP0, 4, 1 }, + { DBGBUS_SSPP0, 4, 2 }, + { DBGBUS_SSPP0, 4, 3 }, + { DBGBUS_SSPP0, 4, 4 }, + { DBGBUS_SSPP0, 4, 5 }, + { DBGBUS_SSPP0, 4, 6 }, + { DBGBUS_SSPP0, 4, 7 }, + + { DBGBUS_SSPP0, 5, 0 }, + { DBGBUS_SSPP0, 5, 1 }, + { DBGBUS_SSPP0, 5, 2 }, + { DBGBUS_SSPP0, 5, 3 }, + { DBGBUS_SSPP0, 5, 4 }, + { DBGBUS_SSPP0, 5, 5 }, + { DBGBUS_SSPP0, 5, 6 }, + { DBGBUS_SSPP0, 5, 7 }, + + /* vig 2 */ + { DBGBUS_SSPP0, 20, 0 }, + { DBGBUS_SSPP0, 20, 1 }, + { DBGBUS_SSPP0, 20, 2 }, + { DBGBUS_SSPP0, 20, 3 }, + { DBGBUS_SSPP0, 20, 4 }, + { DBGBUS_SSPP0, 20, 5 }, + { DBGBUS_SSPP0, 20, 6 }, + { DBGBUS_SSPP0, 20, 7 }, + + { DBGBUS_SSPP0, 21, 0 }, + { DBGBUS_SSPP0, 21, 1 }, + { DBGBUS_SSPP0, 21, 2 }, + { DBGBUS_SSPP0, 21, 3 }, + { DBGBUS_SSPP0, 21, 4 }, + { DBGBUS_SSPP0, 21, 5 }, + { DBGBUS_SSPP0, 21, 6 }, + { DBGBUS_SSPP0, 21, 7 }, + + { DBGBUS_SSPP0, 22, 0 }, + { DBGBUS_SSPP0, 22, 1 }, + { DBGBUS_SSPP0, 22, 2 }, + { DBGBUS_SSPP0, 22, 3 }, + { DBGBUS_SSPP0, 22, 4 }, + { DBGBUS_SSPP0, 22, 5 }, + { DBGBUS_SSPP0, 22, 6 }, + { DBGBUS_SSPP0, 22, 7 }, + + { DBGBUS_SSPP0, 24, 0 }, + { DBGBUS_SSPP0, 24, 1 }, + { DBGBUS_SSPP0, 24, 2 }, + { DBGBUS_SSPP0, 24, 3 }, + { DBGBUS_SSPP0, 24, 4 }, + { DBGBUS_SSPP0, 24, 5 }, + { DBGBUS_SSPP0, 24, 6 }, + { DBGBUS_SSPP0, 24, 7 }, + + { DBGBUS_SSPP0, 25, 0 }, + { DBGBUS_SSPP0, 25, 1 }, + { DBGBUS_SSPP0, 25, 2 }, + { DBGBUS_SSPP0, 25, 3 }, + { DBGBUS_SSPP0, 25, 4 }, + { DBGBUS_SSPP0, 25, 5 }, + { DBGBUS_SSPP0, 25, 6 }, + { DBGBUS_SSPP0, 25, 7 }, + + /* dma 2 */ + { DBGBUS_SSPP0, 30, 0 }, + { DBGBUS_SSPP0, 30, 1 }, + { DBGBUS_SSPP0, 30, 2 }, + { DBGBUS_SSPP0, 30, 3 }, + { DBGBUS_SSPP0, 30, 4 }, + { DBGBUS_SSPP0, 30, 5 }, + { DBGBUS_SSPP0, 30, 6 }, + { DBGBUS_SSPP0, 30, 7 }, + + { DBGBUS_SSPP0, 31, 0 }, + { DBGBUS_SSPP0, 31, 1 }, + { DBGBUS_SSPP0, 31, 2 }, + { DBGBUS_SSPP0, 31, 3 }, + { DBGBUS_SSPP0, 31, 4 }, + { DBGBUS_SSPP0, 31, 5 }, + { DBGBUS_SSPP0, 31, 6 }, + { DBGBUS_SSPP0, 31, 7 }, + + { DBGBUS_SSPP0, 32, 0 }, + { DBGBUS_SSPP0, 32, 1 }, + { DBGBUS_SSPP0, 32, 2 }, + { DBGBUS_SSPP0, 32, 3 }, + { DBGBUS_SSPP0, 32, 4 }, + { DBGBUS_SSPP0, 32, 5 }, + { DBGBUS_SSPP0, 32, 6 }, + { DBGBUS_SSPP0, 32, 7 }, + + { DBGBUS_SSPP0, 33, 0 }, + { DBGBUS_SSPP0, 33, 1 }, + { DBGBUS_SSPP0, 33, 2 }, + { DBGBUS_SSPP0, 33, 3 }, + { DBGBUS_SSPP0, 33, 4 }, + { DBGBUS_SSPP0, 33, 5 }, + { DBGBUS_SSPP0, 33, 6 }, + { DBGBUS_SSPP0, 33, 7 }, + + { DBGBUS_SSPP0, 34, 0 }, + { DBGBUS_SSPP0, 34, 1 }, + { DBGBUS_SSPP0, 34, 2 }, + { DBGBUS_SSPP0, 34, 3 }, + { DBGBUS_SSPP0, 34, 4 }, + { DBGBUS_SSPP0, 34, 5 }, + { DBGBUS_SSPP0, 34, 6 }, + { DBGBUS_SSPP0, 34, 7 }, + + { DBGBUS_SSPP0, 35, 0 }, + { DBGBUS_SSPP0, 35, 1 }, + { DBGBUS_SSPP0, 35, 2 }, + { DBGBUS_SSPP0, 35, 3 }, + + /* dma 0 */ + { DBGBUS_SSPP0, 40, 0 }, + { DBGBUS_SSPP0, 40, 1 }, + { DBGBUS_SSPP0, 40, 2 }, + { DBGBUS_SSPP0, 40, 3 }, + { DBGBUS_SSPP0, 40, 4 }, + { DBGBUS_SSPP0, 40, 5 }, + { DBGBUS_SSPP0, 40, 6 }, + { DBGBUS_SSPP0, 40, 7 }, + + { DBGBUS_SSPP0, 41, 0 }, + { DBGBUS_SSPP0, 41, 1 }, + { DBGBUS_SSPP0, 41, 2 }, + { DBGBUS_SSPP0, 41, 3 }, + { DBGBUS_SSPP0, 41, 4 }, + { DBGBUS_SSPP0, 41, 5 }, + { DBGBUS_SSPP0, 41, 6 }, + { DBGBUS_SSPP0, 41, 7 }, + + { DBGBUS_SSPP0, 42, 0 }, + { DBGBUS_SSPP0, 42, 1 }, + { DBGBUS_SSPP0, 42, 2 }, + { DBGBUS_SSPP0, 42, 3 }, + { DBGBUS_SSPP0, 42, 4 }, + { DBGBUS_SSPP0, 42, 5 }, + { DBGBUS_SSPP0, 42, 6 }, + { DBGBUS_SSPP0, 42, 7 }, + + { DBGBUS_SSPP0, 44, 0 }, + { DBGBUS_SSPP0, 44, 1 }, + { DBGBUS_SSPP0, 44, 2 }, + { DBGBUS_SSPP0, 44, 3 }, + { DBGBUS_SSPP0, 44, 4 }, + { DBGBUS_SSPP0, 44, 5 }, + { DBGBUS_SSPP0, 44, 6 }, + { DBGBUS_SSPP0, 44, 7 }, + + { DBGBUS_SSPP0, 45, 0 }, + { DBGBUS_SSPP0, 45, 1 }, + { DBGBUS_SSPP0, 45, 2 }, + { DBGBUS_SSPP0, 45, 3 }, + { DBGBUS_SSPP0, 45, 4 }, + { DBGBUS_SSPP0, 45, 5 }, + { DBGBUS_SSPP0, 45, 6 }, + { DBGBUS_SSPP0, 45, 7 }, + + /* fetch sspp1 */ + /* vig 1 */ + { DBGBUS_SSPP1, 0, 0 }, + { DBGBUS_SSPP1, 0, 1 }, + { DBGBUS_SSPP1, 0, 2 }, + { DBGBUS_SSPP1, 0, 3 }, + { DBGBUS_SSPP1, 0, 4 }, + { DBGBUS_SSPP1, 0, 5 }, + { DBGBUS_SSPP1, 0, 6 }, + { DBGBUS_SSPP1, 0, 7 }, + + { DBGBUS_SSPP1, 1, 0 }, + { DBGBUS_SSPP1, 1, 1 }, + { DBGBUS_SSPP1, 1, 2 }, + { DBGBUS_SSPP1, 1, 3 }, + { DBGBUS_SSPP1, 1, 4 }, + { DBGBUS_SSPP1, 1, 5 }, + { DBGBUS_SSPP1, 1, 6 }, + { DBGBUS_SSPP1, 1, 7 }, + + { DBGBUS_SSPP1, 2, 0 }, + { DBGBUS_SSPP1, 2, 1 }, + { DBGBUS_SSPP1, 2, 2 }, + { DBGBUS_SSPP1, 2, 3 }, + { DBGBUS_SSPP1, 2, 4 }, + { DBGBUS_SSPP1, 2, 5 }, + { DBGBUS_SSPP1, 2, 6 }, + { DBGBUS_SSPP1, 2, 7 }, + + { DBGBUS_SSPP1, 4, 0 }, + { DBGBUS_SSPP1, 4, 1 }, + { DBGBUS_SSPP1, 4, 2 }, + { DBGBUS_SSPP1, 4, 3 }, + { DBGBUS_SSPP1, 4, 4 }, + { DBGBUS_SSPP1, 4, 5 }, + { DBGBUS_SSPP1, 4, 6 }, + { DBGBUS_SSPP1, 4, 7 }, + + { DBGBUS_SSPP1, 5, 0 }, + { DBGBUS_SSPP1, 5, 1 }, + { DBGBUS_SSPP1, 5, 2 }, + { DBGBUS_SSPP1, 5, 3 }, + { DBGBUS_SSPP1, 5, 4 }, + { DBGBUS_SSPP1, 5, 5 }, + { DBGBUS_SSPP1, 5, 6 }, + { DBGBUS_SSPP1, 5, 7 }, + + /* vig 3 */ + { DBGBUS_SSPP1, 20, 0 }, + { DBGBUS_SSPP1, 20, 1 }, + { DBGBUS_SSPP1, 20, 2 }, + { DBGBUS_SSPP1, 20, 3 }, + { DBGBUS_SSPP1, 20, 4 }, + { DBGBUS_SSPP1, 20, 5 }, + { DBGBUS_SSPP1, 20, 6 }, + { DBGBUS_SSPP1, 20, 7 }, + + { DBGBUS_SSPP1, 21, 0 }, + { DBGBUS_SSPP1, 21, 1 }, + { DBGBUS_SSPP1, 21, 2 }, + { DBGBUS_SSPP1, 21, 3 }, + { DBGBUS_SSPP1, 21, 4 }, + { DBGBUS_SSPP1, 21, 5 }, + { DBGBUS_SSPP1, 21, 6 }, + { DBGBUS_SSPP1, 21, 7 }, + + { DBGBUS_SSPP1, 22, 0 }, + { DBGBUS_SSPP1, 22, 1 }, + { DBGBUS_SSPP1, 22, 2 }, + { DBGBUS_SSPP1, 22, 3 }, + { DBGBUS_SSPP1, 22, 4 }, + { DBGBUS_SSPP1, 22, 5 }, + { DBGBUS_SSPP1, 22, 6 }, + { DBGBUS_SSPP1, 22, 7 }, + + { DBGBUS_SSPP1, 24, 0 }, + { DBGBUS_SSPP1, 24, 1 }, + { DBGBUS_SSPP1, 24, 2 }, + { DBGBUS_SSPP1, 24, 3 }, + { DBGBUS_SSPP1, 24, 4 }, + { DBGBUS_SSPP1, 24, 5 }, + { DBGBUS_SSPP1, 24, 6 }, + { DBGBUS_SSPP1, 24, 7 }, + + { DBGBUS_SSPP1, 25, 0 }, + { DBGBUS_SSPP1, 25, 1 }, + { DBGBUS_SSPP1, 25, 2 }, + { DBGBUS_SSPP1, 25, 3 }, + { DBGBUS_SSPP1, 25, 4 }, + { DBGBUS_SSPP1, 25, 5 }, + { DBGBUS_SSPP1, 25, 6 }, + { DBGBUS_SSPP1, 25, 7 }, + + /* dma 3 */ + { DBGBUS_SSPP1, 30, 0 }, + { DBGBUS_SSPP1, 30, 1 }, + { DBGBUS_SSPP1, 30, 2 }, + { DBGBUS_SSPP1, 30, 3 }, + { DBGBUS_SSPP1, 30, 4 }, + { DBGBUS_SSPP1, 30, 5 }, + { DBGBUS_SSPP1, 30, 6 }, + { DBGBUS_SSPP1, 30, 7 }, + + { DBGBUS_SSPP1, 31, 0 }, + { DBGBUS_SSPP1, 31, 1 }, + { DBGBUS_SSPP1, 31, 2 }, + { DBGBUS_SSPP1, 31, 3 }, + { DBGBUS_SSPP1, 31, 4 }, + { DBGBUS_SSPP1, 31, 5 }, + { DBGBUS_SSPP1, 31, 6 }, + { DBGBUS_SSPP1, 31, 7 }, + + { DBGBUS_SSPP1, 32, 0 }, + { DBGBUS_SSPP1, 32, 1 }, + { DBGBUS_SSPP1, 32, 2 }, + { DBGBUS_SSPP1, 32, 3 }, + { DBGBUS_SSPP1, 32, 4 }, + { DBGBUS_SSPP1, 32, 5 }, + { DBGBUS_SSPP1, 32, 6 }, + { DBGBUS_SSPP1, 32, 7 }, + + { DBGBUS_SSPP1, 33, 0 }, + { DBGBUS_SSPP1, 33, 1 }, + { DBGBUS_SSPP1, 33, 2 }, + { DBGBUS_SSPP1, 33, 3 }, + { DBGBUS_SSPP1, 33, 4 }, + { DBGBUS_SSPP1, 33, 5 }, + { DBGBUS_SSPP1, 33, 6 }, + { DBGBUS_SSPP1, 33, 7 }, + + { DBGBUS_SSPP1, 34, 0 }, + { DBGBUS_SSPP1, 34, 1 }, + { DBGBUS_SSPP1, 34, 2 }, + { DBGBUS_SSPP1, 34, 3 }, + { DBGBUS_SSPP1, 34, 4 }, + { DBGBUS_SSPP1, 34, 5 }, + { DBGBUS_SSPP1, 34, 6 }, + { DBGBUS_SSPP1, 34, 7 }, + + { DBGBUS_SSPP1, 35, 0 }, + { DBGBUS_SSPP1, 35, 1 }, + { DBGBUS_SSPP1, 35, 2 }, + + /* dma 1 */ + { DBGBUS_SSPP1, 40, 0 }, + { DBGBUS_SSPP1, 40, 1 }, + { DBGBUS_SSPP1, 40, 2 }, + { DBGBUS_SSPP1, 40, 3 }, + { DBGBUS_SSPP1, 40, 4 }, + { DBGBUS_SSPP1, 40, 5 }, + { DBGBUS_SSPP1, 40, 6 }, + { DBGBUS_SSPP1, 40, 7 }, + + { DBGBUS_SSPP1, 41, 0 }, + { DBGBUS_SSPP1, 41, 1 }, + { DBGBUS_SSPP1, 41, 2 }, + { DBGBUS_SSPP1, 41, 3 }, + { DBGBUS_SSPP1, 41, 4 }, + { DBGBUS_SSPP1, 41, 5 }, + { DBGBUS_SSPP1, 41, 6 }, + { DBGBUS_SSPP1, 41, 7 }, + + { DBGBUS_SSPP1, 42, 0 }, + { DBGBUS_SSPP1, 42, 1 }, + { DBGBUS_SSPP1, 42, 2 }, + { DBGBUS_SSPP1, 42, 3 }, + { DBGBUS_SSPP1, 42, 4 }, + { DBGBUS_SSPP1, 42, 5 }, + { DBGBUS_SSPP1, 42, 6 }, + { DBGBUS_SSPP1, 42, 7 }, + + { DBGBUS_SSPP1, 44, 0 }, + { DBGBUS_SSPP1, 44, 1 }, + { DBGBUS_SSPP1, 44, 2 }, + { DBGBUS_SSPP1, 44, 3 }, + { DBGBUS_SSPP1, 44, 4 }, + { DBGBUS_SSPP1, 44, 5 }, + { DBGBUS_SSPP1, 44, 6 }, + { DBGBUS_SSPP1, 44, 7 }, + + { DBGBUS_SSPP1, 45, 0 }, + { DBGBUS_SSPP1, 45, 1 }, + { DBGBUS_SSPP1, 45, 2 }, + { DBGBUS_SSPP1, 45, 3 }, + { DBGBUS_SSPP1, 45, 4 }, + { DBGBUS_SSPP1, 45, 5 }, + { DBGBUS_SSPP1, 45, 6 }, + { DBGBUS_SSPP1, 45, 7 }, + + /* cursor 1 */ + { DBGBUS_SSPP1, 80, 0 }, + { DBGBUS_SSPP1, 80, 1 }, + { DBGBUS_SSPP1, 80, 2 }, + { DBGBUS_SSPP1, 80, 3 }, + { DBGBUS_SSPP1, 80, 4 }, + { DBGBUS_SSPP1, 80, 5 }, + { DBGBUS_SSPP1, 80, 6 }, + { DBGBUS_SSPP1, 80, 7 }, + + { DBGBUS_SSPP1, 81, 0 }, + { DBGBUS_SSPP1, 81, 1 }, + { DBGBUS_SSPP1, 81, 2 }, + { DBGBUS_SSPP1, 81, 3 }, + { DBGBUS_SSPP1, 81, 4 }, + { DBGBUS_SSPP1, 81, 5 }, + { DBGBUS_SSPP1, 81, 6 }, + { DBGBUS_SSPP1, 81, 7 }, + + { DBGBUS_SSPP1, 82, 0 }, + { DBGBUS_SSPP1, 82, 1 }, + { DBGBUS_SSPP1, 82, 2 }, + { DBGBUS_SSPP1, 82, 3 }, + { DBGBUS_SSPP1, 82, 4 }, + { DBGBUS_SSPP1, 82, 5 }, + { DBGBUS_SSPP1, 82, 6 }, + { DBGBUS_SSPP1, 82, 7 }, + + { DBGBUS_SSPP1, 83, 0 }, + { DBGBUS_SSPP1, 83, 1 }, + { DBGBUS_SSPP1, 83, 2 }, + { DBGBUS_SSPP1, 83, 3 }, + { DBGBUS_SSPP1, 83, 4 }, + { DBGBUS_SSPP1, 83, 5 }, + { DBGBUS_SSPP1, 83, 6 }, + { DBGBUS_SSPP1, 83, 7 }, + + { DBGBUS_SSPP1, 84, 0 }, + { DBGBUS_SSPP1, 84, 1 }, + { DBGBUS_SSPP1, 84, 2 }, + { DBGBUS_SSPP1, 84, 3 }, + { DBGBUS_SSPP1, 84, 4 }, + { DBGBUS_SSPP1, 84, 5 }, + { DBGBUS_SSPP1, 84, 6 }, + { DBGBUS_SSPP1, 84, 7 }, + + /* dspp */ + { DBGBUS_DSPP, 13, 0 }, + { DBGBUS_DSPP, 19, 0 }, + { DBGBUS_DSPP, 14, 0 }, + { DBGBUS_DSPP, 14, 1 }, + { DBGBUS_DSPP, 14, 3 }, + { DBGBUS_DSPP, 20, 0 }, + { DBGBUS_DSPP, 20, 1 }, + { DBGBUS_DSPP, 20, 3 }, + + /* ppb_0 */ + { DBGBUS_DSPP, 31, 0, _dpu_debug_bus_ppb0_dump }, + { DBGBUS_DSPP, 33, 0, _dpu_debug_bus_ppb0_dump }, + { DBGBUS_DSPP, 35, 0, _dpu_debug_bus_ppb0_dump }, + { DBGBUS_DSPP, 42, 0, _dpu_debug_bus_ppb0_dump }, + + /* ppb_1 */ + { DBGBUS_DSPP, 32, 0, _dpu_debug_bus_ppb1_dump }, + { DBGBUS_DSPP, 34, 0, _dpu_debug_bus_ppb1_dump }, + { DBGBUS_DSPP, 36, 0, _dpu_debug_bus_ppb1_dump }, + { DBGBUS_DSPP, 43, 0, _dpu_debug_bus_ppb1_dump }, + + /* lm_lut */ + { DBGBUS_DSPP, 109, 0 }, + { DBGBUS_DSPP, 105, 0 }, + { DBGBUS_DSPP, 103, 0 }, + + /* tear-check */ + { DBGBUS_PERIPH, 63, 0 }, + { DBGBUS_PERIPH, 64, 0 }, + { DBGBUS_PERIPH, 65, 0 }, + { DBGBUS_PERIPH, 73, 0 }, + { DBGBUS_PERIPH, 74, 0 }, + + /* crossbar */ + { DBGBUS_DSPP, 0, 0, _dpu_debug_bus_xbar_dump }, + + /* rotator */ + { DBGBUS_DSPP, 9, 0}, + + /* blend */ + /* LM0 */ + { DBGBUS_DSPP, 63, 0}, + { DBGBUS_DSPP, 63, 1}, + { DBGBUS_DSPP, 63, 2}, + { DBGBUS_DSPP, 63, 3}, + { DBGBUS_DSPP, 63, 4}, + { DBGBUS_DSPP, 63, 5}, + { DBGBUS_DSPP, 63, 6}, + { DBGBUS_DSPP, 63, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 64, 0}, + { DBGBUS_DSPP, 64, 1}, + { DBGBUS_DSPP, 64, 2}, + { DBGBUS_DSPP, 64, 3}, + { DBGBUS_DSPP, 64, 4}, + { DBGBUS_DSPP, 64, 5}, + { DBGBUS_DSPP, 64, 6}, + { DBGBUS_DSPP, 64, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 65, 0}, + { DBGBUS_DSPP, 65, 1}, + { DBGBUS_DSPP, 65, 2}, + { DBGBUS_DSPP, 65, 3}, + { DBGBUS_DSPP, 65, 4}, + { DBGBUS_DSPP, 65, 5}, + { DBGBUS_DSPP, 65, 6}, + { DBGBUS_DSPP, 65, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 66, 0}, + { DBGBUS_DSPP, 66, 1}, + { DBGBUS_DSPP, 66, 2}, + { DBGBUS_DSPP, 66, 3}, + { DBGBUS_DSPP, 66, 4}, + { DBGBUS_DSPP, 66, 5}, + { DBGBUS_DSPP, 66, 6}, + { DBGBUS_DSPP, 66, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 67, 0}, + { DBGBUS_DSPP, 67, 1}, + { DBGBUS_DSPP, 67, 2}, + { DBGBUS_DSPP, 67, 3}, + { DBGBUS_DSPP, 67, 4}, + { DBGBUS_DSPP, 67, 5}, + { DBGBUS_DSPP, 67, 6}, + { DBGBUS_DSPP, 67, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 68, 0}, + { DBGBUS_DSPP, 68, 1}, + { DBGBUS_DSPP, 68, 2}, + { DBGBUS_DSPP, 68, 3}, + { DBGBUS_DSPP, 68, 4}, + { DBGBUS_DSPP, 68, 5}, + { DBGBUS_DSPP, 68, 6}, + { DBGBUS_DSPP, 68, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 69, 0}, + { DBGBUS_DSPP, 69, 1}, + { DBGBUS_DSPP, 69, 2}, + { DBGBUS_DSPP, 69, 3}, + { DBGBUS_DSPP, 69, 4}, + { DBGBUS_DSPP, 69, 5}, + { DBGBUS_DSPP, 69, 6}, + { DBGBUS_DSPP, 69, 7, _dpu_debug_bus_lm_dump }, + + /* LM1 */ + { DBGBUS_DSPP, 70, 0}, + { DBGBUS_DSPP, 70, 1}, + { DBGBUS_DSPP, 70, 2}, + { DBGBUS_DSPP, 70, 3}, + { DBGBUS_DSPP, 70, 4}, + { DBGBUS_DSPP, 70, 5}, + { DBGBUS_DSPP, 70, 6}, + { DBGBUS_DSPP, 70, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 71, 0}, + { DBGBUS_DSPP, 71, 1}, + { DBGBUS_DSPP, 71, 2}, + { DBGBUS_DSPP, 71, 3}, + { DBGBUS_DSPP, 71, 4}, + { DBGBUS_DSPP, 71, 5}, + { DBGBUS_DSPP, 71, 6}, + { DBGBUS_DSPP, 71, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 72, 0}, + { DBGBUS_DSPP, 72, 1}, + { DBGBUS_DSPP, 72, 2}, + { DBGBUS_DSPP, 72, 3}, + { DBGBUS_DSPP, 72, 4}, + { DBGBUS_DSPP, 72, 5}, + { DBGBUS_DSPP, 72, 6}, + { DBGBUS_DSPP, 72, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 73, 0}, + { DBGBUS_DSPP, 73, 1}, + { DBGBUS_DSPP, 73, 2}, + { DBGBUS_DSPP, 73, 3}, + { DBGBUS_DSPP, 73, 4}, + { DBGBUS_DSPP, 73, 5}, + { DBGBUS_DSPP, 73, 6}, + { DBGBUS_DSPP, 73, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 74, 0}, + { DBGBUS_DSPP, 74, 1}, + { DBGBUS_DSPP, 74, 2}, + { DBGBUS_DSPP, 74, 3}, + { DBGBUS_DSPP, 74, 4}, + { DBGBUS_DSPP, 74, 5}, + { DBGBUS_DSPP, 74, 6}, + { DBGBUS_DSPP, 74, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 75, 0}, + { DBGBUS_DSPP, 75, 1}, + { DBGBUS_DSPP, 75, 2}, + { DBGBUS_DSPP, 75, 3}, + { DBGBUS_DSPP, 75, 4}, + { DBGBUS_DSPP, 75, 5}, + { DBGBUS_DSPP, 75, 6}, + { DBGBUS_DSPP, 75, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 76, 0}, + { DBGBUS_DSPP, 76, 1}, + { DBGBUS_DSPP, 76, 2}, + { DBGBUS_DSPP, 76, 3}, + { DBGBUS_DSPP, 76, 4}, + { DBGBUS_DSPP, 76, 5}, + { DBGBUS_DSPP, 76, 6}, + { DBGBUS_DSPP, 76, 7, _dpu_debug_bus_lm_dump }, + + /* LM2 */ + { DBGBUS_DSPP, 77, 0}, + { DBGBUS_DSPP, 77, 1}, + { DBGBUS_DSPP, 77, 2}, + { DBGBUS_DSPP, 77, 3}, + { DBGBUS_DSPP, 77, 4}, + { DBGBUS_DSPP, 77, 5}, + { DBGBUS_DSPP, 77, 6}, + { DBGBUS_DSPP, 77, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 78, 0}, + { DBGBUS_DSPP, 78, 1}, + { DBGBUS_DSPP, 78, 2}, + { DBGBUS_DSPP, 78, 3}, + { DBGBUS_DSPP, 78, 4}, + { DBGBUS_DSPP, 78, 5}, + { DBGBUS_DSPP, 78, 6}, + { DBGBUS_DSPP, 78, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 79, 0}, + { DBGBUS_DSPP, 79, 1}, + { DBGBUS_DSPP, 79, 2}, + { DBGBUS_DSPP, 79, 3}, + { DBGBUS_DSPP, 79, 4}, + { DBGBUS_DSPP, 79, 5}, + { DBGBUS_DSPP, 79, 6}, + { DBGBUS_DSPP, 79, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 80, 0}, + { DBGBUS_DSPP, 80, 1}, + { DBGBUS_DSPP, 80, 2}, + { DBGBUS_DSPP, 80, 3}, + { DBGBUS_DSPP, 80, 4}, + { DBGBUS_DSPP, 80, 5}, + { DBGBUS_DSPP, 80, 6}, + { DBGBUS_DSPP, 80, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 81, 0}, + { DBGBUS_DSPP, 81, 1}, + { DBGBUS_DSPP, 81, 2}, + { DBGBUS_DSPP, 81, 3}, + { DBGBUS_DSPP, 81, 4}, + { DBGBUS_DSPP, 81, 5}, + { DBGBUS_DSPP, 81, 6}, + { DBGBUS_DSPP, 81, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 82, 0}, + { DBGBUS_DSPP, 82, 1}, + { DBGBUS_DSPP, 82, 2}, + { DBGBUS_DSPP, 82, 3}, + { DBGBUS_DSPP, 82, 4}, + { DBGBUS_DSPP, 82, 5}, + { DBGBUS_DSPP, 82, 6}, + { DBGBUS_DSPP, 82, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 83, 0}, + { DBGBUS_DSPP, 83, 1}, + { DBGBUS_DSPP, 83, 2}, + { DBGBUS_DSPP, 83, 3}, + { DBGBUS_DSPP, 83, 4}, + { DBGBUS_DSPP, 83, 5}, + { DBGBUS_DSPP, 83, 6}, + { DBGBUS_DSPP, 83, 7, _dpu_debug_bus_lm_dump }, + + /* csc */ + { DBGBUS_SSPP0, 7, 0}, + { DBGBUS_SSPP0, 7, 1}, + { DBGBUS_SSPP0, 27, 0}, + { DBGBUS_SSPP0, 27, 1}, + { DBGBUS_SSPP1, 7, 0}, + { DBGBUS_SSPP1, 7, 1}, + { DBGBUS_SSPP1, 27, 0}, + { DBGBUS_SSPP1, 27, 1}, + + /* pcc */ + { DBGBUS_SSPP0, 3, 3}, + { DBGBUS_SSPP0, 23, 3}, + { DBGBUS_SSPP0, 33, 3}, + { DBGBUS_SSPP0, 43, 3}, + { DBGBUS_SSPP1, 3, 3}, + { DBGBUS_SSPP1, 23, 3}, + { DBGBUS_SSPP1, 33, 3}, + { DBGBUS_SSPP1, 43, 3}, + + /* spa */ + { DBGBUS_SSPP0, 8, 0}, + { DBGBUS_SSPP0, 28, 0}, + { DBGBUS_SSPP1, 8, 0}, + { DBGBUS_SSPP1, 28, 0}, + { DBGBUS_DSPP, 13, 0}, + { DBGBUS_DSPP, 19, 0}, + + /* igc */ + { DBGBUS_SSPP0, 9, 0}, + { DBGBUS_SSPP0, 9, 1}, + { DBGBUS_SSPP0, 9, 3}, + { DBGBUS_SSPP0, 29, 0}, + { DBGBUS_SSPP0, 29, 1}, + { DBGBUS_SSPP0, 29, 3}, + { DBGBUS_SSPP0, 17, 0}, + { DBGBUS_SSPP0, 17, 1}, + { DBGBUS_SSPP0, 17, 3}, + { DBGBUS_SSPP0, 37, 0}, + { DBGBUS_SSPP0, 37, 1}, + { DBGBUS_SSPP0, 37, 3}, + { DBGBUS_SSPP0, 46, 0}, + { DBGBUS_SSPP0, 46, 1}, + { DBGBUS_SSPP0, 46, 3}, + + { DBGBUS_SSPP1, 9, 0}, + { DBGBUS_SSPP1, 9, 1}, + { DBGBUS_SSPP1, 9, 3}, + { DBGBUS_SSPP1, 29, 0}, + { DBGBUS_SSPP1, 29, 1}, + { DBGBUS_SSPP1, 29, 3}, + { DBGBUS_SSPP1, 17, 0}, + { DBGBUS_SSPP1, 17, 1}, + { DBGBUS_SSPP1, 17, 3}, + { DBGBUS_SSPP1, 37, 0}, + { DBGBUS_SSPP1, 37, 1}, + { DBGBUS_SSPP1, 37, 3}, + { DBGBUS_SSPP1, 46, 0}, + { DBGBUS_SSPP1, 46, 1}, + { DBGBUS_SSPP1, 46, 3}, + + { DBGBUS_DSPP, 14, 0}, + { DBGBUS_DSPP, 14, 1}, + { DBGBUS_DSPP, 14, 3}, + { DBGBUS_DSPP, 20, 0}, + { DBGBUS_DSPP, 20, 1}, + { DBGBUS_DSPP, 20, 3}, + + { DBGBUS_PERIPH, 60, 0}, +}; + +static struct dpu_debug_bus_entry dbg_bus_dpu_sdm845[] = { + + /* Unpack 0 sspp 0*/ + { DBGBUS_SSPP0, 50, 2 }, + { DBGBUS_SSPP0, 60, 2 }, + { DBGBUS_SSPP0, 70, 2 }, + + /* Upack 0 sspp 1*/ + { DBGBUS_SSPP1, 50, 2 }, + { DBGBUS_SSPP1, 60, 2 }, + { DBGBUS_SSPP1, 70, 2 }, + + /* scheduler */ + { DBGBUS_DSPP, 130, 0 }, + { DBGBUS_DSPP, 130, 1 }, + { DBGBUS_DSPP, 130, 2 }, + { DBGBUS_DSPP, 130, 3 }, + { DBGBUS_DSPP, 130, 4 }, + { DBGBUS_DSPP, 130, 5 }, + + /* qseed */ + { DBGBUS_SSPP0, 6, 0}, + { DBGBUS_SSPP0, 6, 1}, + { DBGBUS_SSPP0, 26, 0}, + { DBGBUS_SSPP0, 26, 1}, + { DBGBUS_SSPP1, 6, 0}, + { DBGBUS_SSPP1, 6, 1}, + { DBGBUS_SSPP1, 26, 0}, + { DBGBUS_SSPP1, 26, 1}, + + /* scale */ + { DBGBUS_SSPP0, 16, 0}, + { DBGBUS_SSPP0, 16, 1}, + { DBGBUS_SSPP0, 36, 0}, + { DBGBUS_SSPP0, 36, 1}, + { DBGBUS_SSPP1, 16, 0}, + { DBGBUS_SSPP1, 16, 1}, + { DBGBUS_SSPP1, 36, 0}, + { DBGBUS_SSPP1, 36, 1}, + + /* fetch sspp0 */ + + /* vig 0 */ + { DBGBUS_SSPP0, 0, 0 }, + { DBGBUS_SSPP0, 0, 1 }, + { DBGBUS_SSPP0, 0, 2 }, + { DBGBUS_SSPP0, 0, 3 }, + { DBGBUS_SSPP0, 0, 4 }, + { DBGBUS_SSPP0, 0, 5 }, + { DBGBUS_SSPP0, 0, 6 }, + { DBGBUS_SSPP0, 0, 7 }, + + { DBGBUS_SSPP0, 1, 0 }, + { DBGBUS_SSPP0, 1, 1 }, + { DBGBUS_SSPP0, 1, 2 }, + { DBGBUS_SSPP0, 1, 3 }, + { DBGBUS_SSPP0, 1, 4 }, + { DBGBUS_SSPP0, 1, 5 }, + { DBGBUS_SSPP0, 1, 6 }, + { DBGBUS_SSPP0, 1, 7 }, + + { DBGBUS_SSPP0, 2, 0 }, + { DBGBUS_SSPP0, 2, 1 }, + { DBGBUS_SSPP0, 2, 2 }, + { DBGBUS_SSPP0, 2, 3 }, + { DBGBUS_SSPP0, 2, 4 }, + { DBGBUS_SSPP0, 2, 5 }, + { DBGBUS_SSPP0, 2, 6 }, + { DBGBUS_SSPP0, 2, 7 }, + + { DBGBUS_SSPP0, 4, 0 }, + { DBGBUS_SSPP0, 4, 1 }, + { DBGBUS_SSPP0, 4, 2 }, + { DBGBUS_SSPP0, 4, 3 }, + { DBGBUS_SSPP0, 4, 4 }, + { DBGBUS_SSPP0, 4, 5 }, + { DBGBUS_SSPP0, 4, 6 }, + { DBGBUS_SSPP0, 4, 7 }, + + { DBGBUS_SSPP0, 5, 0 }, + { DBGBUS_SSPP0, 5, 1 }, + { DBGBUS_SSPP0, 5, 2 }, + { DBGBUS_SSPP0, 5, 3 }, + { DBGBUS_SSPP0, 5, 4 }, + { DBGBUS_SSPP0, 5, 5 }, + { DBGBUS_SSPP0, 5, 6 }, + { DBGBUS_SSPP0, 5, 7 }, + + /* vig 2 */ + { DBGBUS_SSPP0, 20, 0 }, + { DBGBUS_SSPP0, 20, 1 }, + { DBGBUS_SSPP0, 20, 2 }, + { DBGBUS_SSPP0, 20, 3 }, + { DBGBUS_SSPP0, 20, 4 }, + { DBGBUS_SSPP0, 20, 5 }, + { DBGBUS_SSPP0, 20, 6 }, + { DBGBUS_SSPP0, 20, 7 }, + + { DBGBUS_SSPP0, 21, 0 }, + { DBGBUS_SSPP0, 21, 1 }, + { DBGBUS_SSPP0, 21, 2 }, + { DBGBUS_SSPP0, 21, 3 }, + { DBGBUS_SSPP0, 21, 4 }, + { DBGBUS_SSPP0, 21, 5 }, + { DBGBUS_SSPP0, 21, 6 }, + { DBGBUS_SSPP0, 21, 7 }, + + { DBGBUS_SSPP0, 22, 0 }, + { DBGBUS_SSPP0, 22, 1 }, + { DBGBUS_SSPP0, 22, 2 }, + { DBGBUS_SSPP0, 22, 3 }, + { DBGBUS_SSPP0, 22, 4 }, + { DBGBUS_SSPP0, 22, 5 }, + { DBGBUS_SSPP0, 22, 6 }, + { DBGBUS_SSPP0, 22, 7 }, + + { DBGBUS_SSPP0, 24, 0 }, + { DBGBUS_SSPP0, 24, 1 }, + { DBGBUS_SSPP0, 24, 2 }, + { DBGBUS_SSPP0, 24, 3 }, + { DBGBUS_SSPP0, 24, 4 }, + { DBGBUS_SSPP0, 24, 5 }, + { DBGBUS_SSPP0, 24, 6 }, + { DBGBUS_SSPP0, 24, 7 }, + + { DBGBUS_SSPP0, 25, 0 }, + { DBGBUS_SSPP0, 25, 1 }, + { DBGBUS_SSPP0, 25, 2 }, + { DBGBUS_SSPP0, 25, 3 }, + { DBGBUS_SSPP0, 25, 4 }, + { DBGBUS_SSPP0, 25, 5 }, + { DBGBUS_SSPP0, 25, 6 }, + { DBGBUS_SSPP0, 25, 7 }, + + /* dma 2 */ + { DBGBUS_SSPP0, 30, 0 }, + { DBGBUS_SSPP0, 30, 1 }, + { DBGBUS_SSPP0, 30, 2 }, + { DBGBUS_SSPP0, 30, 3 }, + { DBGBUS_SSPP0, 30, 4 }, + { DBGBUS_SSPP0, 30, 5 }, + { DBGBUS_SSPP0, 30, 6 }, + { DBGBUS_SSPP0, 30, 7 }, + + { DBGBUS_SSPP0, 31, 0 }, + { DBGBUS_SSPP0, 31, 1 }, + { DBGBUS_SSPP0, 31, 2 }, + { DBGBUS_SSPP0, 31, 3 }, + { DBGBUS_SSPP0, 31, 4 }, + { DBGBUS_SSPP0, 31, 5 }, + { DBGBUS_SSPP0, 31, 6 }, + { DBGBUS_SSPP0, 31, 7 }, + + { DBGBUS_SSPP0, 32, 0 }, + { DBGBUS_SSPP0, 32, 1 }, + { DBGBUS_SSPP0, 32, 2 }, + { DBGBUS_SSPP0, 32, 3 }, + { DBGBUS_SSPP0, 32, 4 }, + { DBGBUS_SSPP0, 32, 5 }, + { DBGBUS_SSPP0, 32, 6 }, + { DBGBUS_SSPP0, 32, 7 }, + + { DBGBUS_SSPP0, 33, 0 }, + { DBGBUS_SSPP0, 33, 1 }, + { DBGBUS_SSPP0, 33, 2 }, + { DBGBUS_SSPP0, 33, 3 }, + { DBGBUS_SSPP0, 33, 4 }, + { DBGBUS_SSPP0, 33, 5 }, + { DBGBUS_SSPP0, 33, 6 }, + { DBGBUS_SSPP0, 33, 7 }, + + { DBGBUS_SSPP0, 34, 0 }, + { DBGBUS_SSPP0, 34, 1 }, + { DBGBUS_SSPP0, 34, 2 }, + { DBGBUS_SSPP0, 34, 3 }, + { DBGBUS_SSPP0, 34, 4 }, + { DBGBUS_SSPP0, 34, 5 }, + { DBGBUS_SSPP0, 34, 6 }, + { DBGBUS_SSPP0, 34, 7 }, + + { DBGBUS_SSPP0, 35, 0 }, + { DBGBUS_SSPP0, 35, 1 }, + { DBGBUS_SSPP0, 35, 2 }, + { DBGBUS_SSPP0, 35, 3 }, + + /* dma 0 */ + { DBGBUS_SSPP0, 40, 0 }, + { DBGBUS_SSPP0, 40, 1 }, + { DBGBUS_SSPP0, 40, 2 }, + { DBGBUS_SSPP0, 40, 3 }, + { DBGBUS_SSPP0, 40, 4 }, + { DBGBUS_SSPP0, 40, 5 }, + { DBGBUS_SSPP0, 40, 6 }, + { DBGBUS_SSPP0, 40, 7 }, + + { DBGBUS_SSPP0, 41, 0 }, + { DBGBUS_SSPP0, 41, 1 }, + { DBGBUS_SSPP0, 41, 2 }, + { DBGBUS_SSPP0, 41, 3 }, + { DBGBUS_SSPP0, 41, 4 }, + { DBGBUS_SSPP0, 41, 5 }, + { DBGBUS_SSPP0, 41, 6 }, + { DBGBUS_SSPP0, 41, 7 }, + + { DBGBUS_SSPP0, 42, 0 }, + { DBGBUS_SSPP0, 42, 1 }, + { DBGBUS_SSPP0, 42, 2 }, + { DBGBUS_SSPP0, 42, 3 }, + { DBGBUS_SSPP0, 42, 4 }, + { DBGBUS_SSPP0, 42, 5 }, + { DBGBUS_SSPP0, 42, 6 }, + { DBGBUS_SSPP0, 42, 7 }, + + { DBGBUS_SSPP0, 44, 0 }, + { DBGBUS_SSPP0, 44, 1 }, + { DBGBUS_SSPP0, 44, 2 }, + { DBGBUS_SSPP0, 44, 3 }, + { DBGBUS_SSPP0, 44, 4 }, + { DBGBUS_SSPP0, 44, 5 }, + { DBGBUS_SSPP0, 44, 6 }, + { DBGBUS_SSPP0, 44, 7 }, + + { DBGBUS_SSPP0, 45, 0 }, + { DBGBUS_SSPP0, 45, 1 }, + { DBGBUS_SSPP0, 45, 2 }, + { DBGBUS_SSPP0, 45, 3 }, + { DBGBUS_SSPP0, 45, 4 }, + { DBGBUS_SSPP0, 45, 5 }, + { DBGBUS_SSPP0, 45, 6 }, + { DBGBUS_SSPP0, 45, 7 }, + + /* fetch sspp1 */ + /* vig 1 */ + { DBGBUS_SSPP1, 0, 0 }, + { DBGBUS_SSPP1, 0, 1 }, + { DBGBUS_SSPP1, 0, 2 }, + { DBGBUS_SSPP1, 0, 3 }, + { DBGBUS_SSPP1, 0, 4 }, + { DBGBUS_SSPP1, 0, 5 }, + { DBGBUS_SSPP1, 0, 6 }, + { DBGBUS_SSPP1, 0, 7 }, + + { DBGBUS_SSPP1, 1, 0 }, + { DBGBUS_SSPP1, 1, 1 }, + { DBGBUS_SSPP1, 1, 2 }, + { DBGBUS_SSPP1, 1, 3 }, + { DBGBUS_SSPP1, 1, 4 }, + { DBGBUS_SSPP1, 1, 5 }, + { DBGBUS_SSPP1, 1, 6 }, + { DBGBUS_SSPP1, 1, 7 }, + + { DBGBUS_SSPP1, 2, 0 }, + { DBGBUS_SSPP1, 2, 1 }, + { DBGBUS_SSPP1, 2, 2 }, + { DBGBUS_SSPP1, 2, 3 }, + { DBGBUS_SSPP1, 2, 4 }, + { DBGBUS_SSPP1, 2, 5 }, + { DBGBUS_SSPP1, 2, 6 }, + { DBGBUS_SSPP1, 2, 7 }, + + { DBGBUS_SSPP1, 4, 0 }, + { DBGBUS_SSPP1, 4, 1 }, + { DBGBUS_SSPP1, 4, 2 }, + { DBGBUS_SSPP1, 4, 3 }, + { DBGBUS_SSPP1, 4, 4 }, + { DBGBUS_SSPP1, 4, 5 }, + { DBGBUS_SSPP1, 4, 6 }, + { DBGBUS_SSPP1, 4, 7 }, + + { DBGBUS_SSPP1, 5, 0 }, + { DBGBUS_SSPP1, 5, 1 }, + { DBGBUS_SSPP1, 5, 2 }, + { DBGBUS_SSPP1, 5, 3 }, + { DBGBUS_SSPP1, 5, 4 }, + { DBGBUS_SSPP1, 5, 5 }, + { DBGBUS_SSPP1, 5, 6 }, + { DBGBUS_SSPP1, 5, 7 }, + + /* vig 3 */ + { DBGBUS_SSPP1, 20, 0 }, + { DBGBUS_SSPP1, 20, 1 }, + { DBGBUS_SSPP1, 20, 2 }, + { DBGBUS_SSPP1, 20, 3 }, + { DBGBUS_SSPP1, 20, 4 }, + { DBGBUS_SSPP1, 20, 5 }, + { DBGBUS_SSPP1, 20, 6 }, + { DBGBUS_SSPP1, 20, 7 }, + + { DBGBUS_SSPP1, 21, 0 }, + { DBGBUS_SSPP1, 21, 1 }, + { DBGBUS_SSPP1, 21, 2 }, + { DBGBUS_SSPP1, 21, 3 }, + { DBGBUS_SSPP1, 21, 4 }, + { DBGBUS_SSPP1, 21, 5 }, + { DBGBUS_SSPP1, 21, 6 }, + { DBGBUS_SSPP1, 21, 7 }, + + { DBGBUS_SSPP1, 22, 0 }, + { DBGBUS_SSPP1, 22, 1 }, + { DBGBUS_SSPP1, 22, 2 }, + { DBGBUS_SSPP1, 22, 3 }, + { DBGBUS_SSPP1, 22, 4 }, + { DBGBUS_SSPP1, 22, 5 }, + { DBGBUS_SSPP1, 22, 6 }, + { DBGBUS_SSPP1, 22, 7 }, + + { DBGBUS_SSPP1, 24, 0 }, + { DBGBUS_SSPP1, 24, 1 }, + { DBGBUS_SSPP1, 24, 2 }, + { DBGBUS_SSPP1, 24, 3 }, + { DBGBUS_SSPP1, 24, 4 }, + { DBGBUS_SSPP1, 24, 5 }, + { DBGBUS_SSPP1, 24, 6 }, + { DBGBUS_SSPP1, 24, 7 }, + + { DBGBUS_SSPP1, 25, 0 }, + { DBGBUS_SSPP1, 25, 1 }, + { DBGBUS_SSPP1, 25, 2 }, + { DBGBUS_SSPP1, 25, 3 }, + { DBGBUS_SSPP1, 25, 4 }, + { DBGBUS_SSPP1, 25, 5 }, + { DBGBUS_SSPP1, 25, 6 }, + { DBGBUS_SSPP1, 25, 7 }, + + /* dma 3 */ + { DBGBUS_SSPP1, 30, 0 }, + { DBGBUS_SSPP1, 30, 1 }, + { DBGBUS_SSPP1, 30, 2 }, + { DBGBUS_SSPP1, 30, 3 }, + { DBGBUS_SSPP1, 30, 4 }, + { DBGBUS_SSPP1, 30, 5 }, + { DBGBUS_SSPP1, 30, 6 }, + { DBGBUS_SSPP1, 30, 7 }, + + { DBGBUS_SSPP1, 31, 0 }, + { DBGBUS_SSPP1, 31, 1 }, + { DBGBUS_SSPP1, 31, 2 }, + { DBGBUS_SSPP1, 31, 3 }, + { DBGBUS_SSPP1, 31, 4 }, + { DBGBUS_SSPP1, 31, 5 }, + { DBGBUS_SSPP1, 31, 6 }, + { DBGBUS_SSPP1, 31, 7 }, + + { DBGBUS_SSPP1, 32, 0 }, + { DBGBUS_SSPP1, 32, 1 }, + { DBGBUS_SSPP1, 32, 2 }, + { DBGBUS_SSPP1, 32, 3 }, + { DBGBUS_SSPP1, 32, 4 }, + { DBGBUS_SSPP1, 32, 5 }, + { DBGBUS_SSPP1, 32, 6 }, + { DBGBUS_SSPP1, 32, 7 }, + + { DBGBUS_SSPP1, 33, 0 }, + { DBGBUS_SSPP1, 33, 1 }, + { DBGBUS_SSPP1, 33, 2 }, + { DBGBUS_SSPP1, 33, 3 }, + { DBGBUS_SSPP1, 33, 4 }, + { DBGBUS_SSPP1, 33, 5 }, + { DBGBUS_SSPP1, 33, 6 }, + { DBGBUS_SSPP1, 33, 7 }, + + { DBGBUS_SSPP1, 34, 0 }, + { DBGBUS_SSPP1, 34, 1 }, + { DBGBUS_SSPP1, 34, 2 }, + { DBGBUS_SSPP1, 34, 3 }, + { DBGBUS_SSPP1, 34, 4 }, + { DBGBUS_SSPP1, 34, 5 }, + { DBGBUS_SSPP1, 34, 6 }, + { DBGBUS_SSPP1, 34, 7 }, + + { DBGBUS_SSPP1, 35, 0 }, + { DBGBUS_SSPP1, 35, 1 }, + { DBGBUS_SSPP1, 35, 2 }, + + /* dma 1 */ + { DBGBUS_SSPP1, 40, 0 }, + { DBGBUS_SSPP1, 40, 1 }, + { DBGBUS_SSPP1, 40, 2 }, + { DBGBUS_SSPP1, 40, 3 }, + { DBGBUS_SSPP1, 40, 4 }, + { DBGBUS_SSPP1, 40, 5 }, + { DBGBUS_SSPP1, 40, 6 }, + { DBGBUS_SSPP1, 40, 7 }, + + { DBGBUS_SSPP1, 41, 0 }, + { DBGBUS_SSPP1, 41, 1 }, + { DBGBUS_SSPP1, 41, 2 }, + { DBGBUS_SSPP1, 41, 3 }, + { DBGBUS_SSPP1, 41, 4 }, + { DBGBUS_SSPP1, 41, 5 }, + { DBGBUS_SSPP1, 41, 6 }, + { DBGBUS_SSPP1, 41, 7 }, + + { DBGBUS_SSPP1, 42, 0 }, + { DBGBUS_SSPP1, 42, 1 }, + { DBGBUS_SSPP1, 42, 2 }, + { DBGBUS_SSPP1, 42, 3 }, + { DBGBUS_SSPP1, 42, 4 }, + { DBGBUS_SSPP1, 42, 5 }, + { DBGBUS_SSPP1, 42, 6 }, + { DBGBUS_SSPP1, 42, 7 }, + + { DBGBUS_SSPP1, 44, 0 }, + { DBGBUS_SSPP1, 44, 1 }, + { DBGBUS_SSPP1, 44, 2 }, + { DBGBUS_SSPP1, 44, 3 }, + { DBGBUS_SSPP1, 44, 4 }, + { DBGBUS_SSPP1, 44, 5 }, + { DBGBUS_SSPP1, 44, 6 }, + { DBGBUS_SSPP1, 44, 7 }, + + { DBGBUS_SSPP1, 45, 0 }, + { DBGBUS_SSPP1, 45, 1 }, + { DBGBUS_SSPP1, 45, 2 }, + { DBGBUS_SSPP1, 45, 3 }, + { DBGBUS_SSPP1, 45, 4 }, + { DBGBUS_SSPP1, 45, 5 }, + { DBGBUS_SSPP1, 45, 6 }, + { DBGBUS_SSPP1, 45, 7 }, + + /* dspp */ + { DBGBUS_DSPP, 13, 0 }, + { DBGBUS_DSPP, 19, 0 }, + { DBGBUS_DSPP, 14, 0 }, + { DBGBUS_DSPP, 14, 1 }, + { DBGBUS_DSPP, 14, 3 }, + { DBGBUS_DSPP, 20, 0 }, + { DBGBUS_DSPP, 20, 1 }, + { DBGBUS_DSPP, 20, 3 }, + + /* ppb_0 */ + { DBGBUS_DSPP, 31, 0, _dpu_debug_bus_ppb0_dump }, + { DBGBUS_DSPP, 33, 0, _dpu_debug_bus_ppb0_dump }, + { DBGBUS_DSPP, 35, 0, _dpu_debug_bus_ppb0_dump }, + { DBGBUS_DSPP, 42, 0, _dpu_debug_bus_ppb0_dump }, + + /* ppb_1 */ + { DBGBUS_DSPP, 32, 0, _dpu_debug_bus_ppb1_dump }, + { DBGBUS_DSPP, 34, 0, _dpu_debug_bus_ppb1_dump }, + { DBGBUS_DSPP, 36, 0, _dpu_debug_bus_ppb1_dump }, + { DBGBUS_DSPP, 43, 0, _dpu_debug_bus_ppb1_dump }, + + /* lm_lut */ + { DBGBUS_DSPP, 109, 0 }, + { DBGBUS_DSPP, 105, 0 }, + { DBGBUS_DSPP, 103, 0 }, + + /* crossbar */ + { DBGBUS_DSPP, 0, 0, _dpu_debug_bus_xbar_dump }, + + /* rotator */ + { DBGBUS_DSPP, 9, 0}, + + /* blend */ + /* LM0 */ + { DBGBUS_DSPP, 63, 1}, + { DBGBUS_DSPP, 63, 2}, + { DBGBUS_DSPP, 63, 3}, + { DBGBUS_DSPP, 63, 4}, + { DBGBUS_DSPP, 63, 5}, + { DBGBUS_DSPP, 63, 6}, + { DBGBUS_DSPP, 63, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 64, 1}, + { DBGBUS_DSPP, 64, 2}, + { DBGBUS_DSPP, 64, 3}, + { DBGBUS_DSPP, 64, 4}, + { DBGBUS_DSPP, 64, 5}, + { DBGBUS_DSPP, 64, 6}, + { DBGBUS_DSPP, 64, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 65, 1}, + { DBGBUS_DSPP, 65, 2}, + { DBGBUS_DSPP, 65, 3}, + { DBGBUS_DSPP, 65, 4}, + { DBGBUS_DSPP, 65, 5}, + { DBGBUS_DSPP, 65, 6}, + { DBGBUS_DSPP, 65, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 66, 1}, + { DBGBUS_DSPP, 66, 2}, + { DBGBUS_DSPP, 66, 3}, + { DBGBUS_DSPP, 66, 4}, + { DBGBUS_DSPP, 66, 5}, + { DBGBUS_DSPP, 66, 6}, + { DBGBUS_DSPP, 66, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 67, 1}, + { DBGBUS_DSPP, 67, 2}, + { DBGBUS_DSPP, 67, 3}, + { DBGBUS_DSPP, 67, 4}, + { DBGBUS_DSPP, 67, 5}, + { DBGBUS_DSPP, 67, 6}, + { DBGBUS_DSPP, 67, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 68, 1}, + { DBGBUS_DSPP, 68, 2}, + { DBGBUS_DSPP, 68, 3}, + { DBGBUS_DSPP, 68, 4}, + { DBGBUS_DSPP, 68, 5}, + { DBGBUS_DSPP, 68, 6}, + { DBGBUS_DSPP, 68, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 69, 1}, + { DBGBUS_DSPP, 69, 2}, + { DBGBUS_DSPP, 69, 3}, + { DBGBUS_DSPP, 69, 4}, + { DBGBUS_DSPP, 69, 5}, + { DBGBUS_DSPP, 69, 6}, + { DBGBUS_DSPP, 69, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 84, 1}, + { DBGBUS_DSPP, 84, 2}, + { DBGBUS_DSPP, 84, 3}, + { DBGBUS_DSPP, 84, 4}, + { DBGBUS_DSPP, 84, 5}, + { DBGBUS_DSPP, 84, 6}, + { DBGBUS_DSPP, 84, 7, _dpu_debug_bus_lm_dump }, + + + { DBGBUS_DSPP, 85, 1}, + { DBGBUS_DSPP, 85, 2}, + { DBGBUS_DSPP, 85, 3}, + { DBGBUS_DSPP, 85, 4}, + { DBGBUS_DSPP, 85, 5}, + { DBGBUS_DSPP, 85, 6}, + { DBGBUS_DSPP, 85, 7, _dpu_debug_bus_lm_dump }, + + + { DBGBUS_DSPP, 86, 1}, + { DBGBUS_DSPP, 86, 2}, + { DBGBUS_DSPP, 86, 3}, + { DBGBUS_DSPP, 86, 4}, + { DBGBUS_DSPP, 86, 5}, + { DBGBUS_DSPP, 86, 6}, + { DBGBUS_DSPP, 86, 7, _dpu_debug_bus_lm_dump }, + + + { DBGBUS_DSPP, 87, 1}, + { DBGBUS_DSPP, 87, 2}, + { DBGBUS_DSPP, 87, 3}, + { DBGBUS_DSPP, 87, 4}, + { DBGBUS_DSPP, 87, 5}, + { DBGBUS_DSPP, 87, 6}, + { DBGBUS_DSPP, 87, 7, _dpu_debug_bus_lm_dump }, + + /* LM1 */ + { DBGBUS_DSPP, 70, 1}, + { DBGBUS_DSPP, 70, 2}, + { DBGBUS_DSPP, 70, 3}, + { DBGBUS_DSPP, 70, 4}, + { DBGBUS_DSPP, 70, 5}, + { DBGBUS_DSPP, 70, 6}, + { DBGBUS_DSPP, 70, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 71, 1}, + { DBGBUS_DSPP, 71, 2}, + { DBGBUS_DSPP, 71, 3}, + { DBGBUS_DSPP, 71, 4}, + { DBGBUS_DSPP, 71, 5}, + { DBGBUS_DSPP, 71, 6}, + { DBGBUS_DSPP, 71, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 72, 1}, + { DBGBUS_DSPP, 72, 2}, + { DBGBUS_DSPP, 72, 3}, + { DBGBUS_DSPP, 72, 4}, + { DBGBUS_DSPP, 72, 5}, + { DBGBUS_DSPP, 72, 6}, + { DBGBUS_DSPP, 72, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 73, 1}, + { DBGBUS_DSPP, 73, 2}, + { DBGBUS_DSPP, 73, 3}, + { DBGBUS_DSPP, 73, 4}, + { DBGBUS_DSPP, 73, 5}, + { DBGBUS_DSPP, 73, 6}, + { DBGBUS_DSPP, 73, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 74, 1}, + { DBGBUS_DSPP, 74, 2}, + { DBGBUS_DSPP, 74, 3}, + { DBGBUS_DSPP, 74, 4}, + { DBGBUS_DSPP, 74, 5}, + { DBGBUS_DSPP, 74, 6}, + { DBGBUS_DSPP, 74, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 75, 1}, + { DBGBUS_DSPP, 75, 2}, + { DBGBUS_DSPP, 75, 3}, + { DBGBUS_DSPP, 75, 4}, + { DBGBUS_DSPP, 75, 5}, + { DBGBUS_DSPP, 75, 6}, + { DBGBUS_DSPP, 75, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 76, 1}, + { DBGBUS_DSPP, 76, 2}, + { DBGBUS_DSPP, 76, 3}, + { DBGBUS_DSPP, 76, 4}, + { DBGBUS_DSPP, 76, 5}, + { DBGBUS_DSPP, 76, 6}, + { DBGBUS_DSPP, 76, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 88, 1}, + { DBGBUS_DSPP, 88, 2}, + { DBGBUS_DSPP, 88, 3}, + { DBGBUS_DSPP, 88, 4}, + { DBGBUS_DSPP, 88, 5}, + { DBGBUS_DSPP, 88, 6}, + { DBGBUS_DSPP, 88, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 89, 1}, + { DBGBUS_DSPP, 89, 2}, + { DBGBUS_DSPP, 89, 3}, + { DBGBUS_DSPP, 89, 4}, + { DBGBUS_DSPP, 89, 5}, + { DBGBUS_DSPP, 89, 6}, + { DBGBUS_DSPP, 89, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 90, 1}, + { DBGBUS_DSPP, 90, 2}, + { DBGBUS_DSPP, 90, 3}, + { DBGBUS_DSPP, 90, 4}, + { DBGBUS_DSPP, 90, 5}, + { DBGBUS_DSPP, 90, 6}, + { DBGBUS_DSPP, 90, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 91, 1}, + { DBGBUS_DSPP, 91, 2}, + { DBGBUS_DSPP, 91, 3}, + { DBGBUS_DSPP, 91, 4}, + { DBGBUS_DSPP, 91, 5}, + { DBGBUS_DSPP, 91, 6}, + { DBGBUS_DSPP, 91, 7, _dpu_debug_bus_lm_dump }, + + /* LM2 */ + { DBGBUS_DSPP, 77, 0}, + { DBGBUS_DSPP, 77, 1}, + { DBGBUS_DSPP, 77, 2}, + { DBGBUS_DSPP, 77, 3}, + { DBGBUS_DSPP, 77, 4}, + { DBGBUS_DSPP, 77, 5}, + { DBGBUS_DSPP, 77, 6}, + { DBGBUS_DSPP, 77, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 78, 0}, + { DBGBUS_DSPP, 78, 1}, + { DBGBUS_DSPP, 78, 2}, + { DBGBUS_DSPP, 78, 3}, + { DBGBUS_DSPP, 78, 4}, + { DBGBUS_DSPP, 78, 5}, + { DBGBUS_DSPP, 78, 6}, + { DBGBUS_DSPP, 78, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 79, 0}, + { DBGBUS_DSPP, 79, 1}, + { DBGBUS_DSPP, 79, 2}, + { DBGBUS_DSPP, 79, 3}, + { DBGBUS_DSPP, 79, 4}, + { DBGBUS_DSPP, 79, 5}, + { DBGBUS_DSPP, 79, 6}, + { DBGBUS_DSPP, 79, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 80, 0}, + { DBGBUS_DSPP, 80, 1}, + { DBGBUS_DSPP, 80, 2}, + { DBGBUS_DSPP, 80, 3}, + { DBGBUS_DSPP, 80, 4}, + { DBGBUS_DSPP, 80, 5}, + { DBGBUS_DSPP, 80, 6}, + { DBGBUS_DSPP, 80, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 81, 0}, + { DBGBUS_DSPP, 81, 1}, + { DBGBUS_DSPP, 81, 2}, + { DBGBUS_DSPP, 81, 3}, + { DBGBUS_DSPP, 81, 4}, + { DBGBUS_DSPP, 81, 5}, + { DBGBUS_DSPP, 81, 6}, + { DBGBUS_DSPP, 81, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 82, 0}, + { DBGBUS_DSPP, 82, 1}, + { DBGBUS_DSPP, 82, 2}, + { DBGBUS_DSPP, 82, 3}, + { DBGBUS_DSPP, 82, 4}, + { DBGBUS_DSPP, 82, 5}, + { DBGBUS_DSPP, 82, 6}, + { DBGBUS_DSPP, 82, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 83, 0}, + { DBGBUS_DSPP, 83, 1}, + { DBGBUS_DSPP, 83, 2}, + { DBGBUS_DSPP, 83, 3}, + { DBGBUS_DSPP, 83, 4}, + { DBGBUS_DSPP, 83, 5}, + { DBGBUS_DSPP, 83, 6}, + { DBGBUS_DSPP, 83, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 92, 1}, + { DBGBUS_DSPP, 92, 2}, + { DBGBUS_DSPP, 92, 3}, + { DBGBUS_DSPP, 92, 4}, + { DBGBUS_DSPP, 92, 5}, + { DBGBUS_DSPP, 92, 6}, + { DBGBUS_DSPP, 92, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 93, 1}, + { DBGBUS_DSPP, 93, 2}, + { DBGBUS_DSPP, 93, 3}, + { DBGBUS_DSPP, 93, 4}, + { DBGBUS_DSPP, 93, 5}, + { DBGBUS_DSPP, 93, 6}, + { DBGBUS_DSPP, 93, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 94, 1}, + { DBGBUS_DSPP, 94, 2}, + { DBGBUS_DSPP, 94, 3}, + { DBGBUS_DSPP, 94, 4}, + { DBGBUS_DSPP, 94, 5}, + { DBGBUS_DSPP, 94, 6}, + { DBGBUS_DSPP, 94, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 95, 1}, + { DBGBUS_DSPP, 95, 2}, + { DBGBUS_DSPP, 95, 3}, + { DBGBUS_DSPP, 95, 4}, + { DBGBUS_DSPP, 95, 5}, + { DBGBUS_DSPP, 95, 6}, + { DBGBUS_DSPP, 95, 7, _dpu_debug_bus_lm_dump }, + + /* LM5 */ + { DBGBUS_DSPP, 110, 1}, + { DBGBUS_DSPP, 110, 2}, + { DBGBUS_DSPP, 110, 3}, + { DBGBUS_DSPP, 110, 4}, + { DBGBUS_DSPP, 110, 5}, + { DBGBUS_DSPP, 110, 6}, + { DBGBUS_DSPP, 110, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 111, 1}, + { DBGBUS_DSPP, 111, 2}, + { DBGBUS_DSPP, 111, 3}, + { DBGBUS_DSPP, 111, 4}, + { DBGBUS_DSPP, 111, 5}, + { DBGBUS_DSPP, 111, 6}, + { DBGBUS_DSPP, 111, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 112, 1}, + { DBGBUS_DSPP, 112, 2}, + { DBGBUS_DSPP, 112, 3}, + { DBGBUS_DSPP, 112, 4}, + { DBGBUS_DSPP, 112, 5}, + { DBGBUS_DSPP, 112, 6}, + { DBGBUS_DSPP, 112, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 113, 1}, + { DBGBUS_DSPP, 113, 2}, + { DBGBUS_DSPP, 113, 3}, + { DBGBUS_DSPP, 113, 4}, + { DBGBUS_DSPP, 113, 5}, + { DBGBUS_DSPP, 113, 6}, + { DBGBUS_DSPP, 113, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 114, 1}, + { DBGBUS_DSPP, 114, 2}, + { DBGBUS_DSPP, 114, 3}, + { DBGBUS_DSPP, 114, 4}, + { DBGBUS_DSPP, 114, 5}, + { DBGBUS_DSPP, 114, 6}, + { DBGBUS_DSPP, 114, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 115, 1}, + { DBGBUS_DSPP, 115, 2}, + { DBGBUS_DSPP, 115, 3}, + { DBGBUS_DSPP, 115, 4}, + { DBGBUS_DSPP, 115, 5}, + { DBGBUS_DSPP, 115, 6}, + { DBGBUS_DSPP, 115, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 116, 1}, + { DBGBUS_DSPP, 116, 2}, + { DBGBUS_DSPP, 116, 3}, + { DBGBUS_DSPP, 116, 4}, + { DBGBUS_DSPP, 116, 5}, + { DBGBUS_DSPP, 116, 6}, + { DBGBUS_DSPP, 116, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 117, 1}, + { DBGBUS_DSPP, 117, 2}, + { DBGBUS_DSPP, 117, 3}, + { DBGBUS_DSPP, 117, 4}, + { DBGBUS_DSPP, 117, 5}, + { DBGBUS_DSPP, 117, 6}, + { DBGBUS_DSPP, 117, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 118, 1}, + { DBGBUS_DSPP, 118, 2}, + { DBGBUS_DSPP, 118, 3}, + { DBGBUS_DSPP, 118, 4}, + { DBGBUS_DSPP, 118, 5}, + { DBGBUS_DSPP, 118, 6}, + { DBGBUS_DSPP, 118, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 119, 1}, + { DBGBUS_DSPP, 119, 2}, + { DBGBUS_DSPP, 119, 3}, + { DBGBUS_DSPP, 119, 4}, + { DBGBUS_DSPP, 119, 5}, + { DBGBUS_DSPP, 119, 6}, + { DBGBUS_DSPP, 119, 7, _dpu_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 120, 1}, + { DBGBUS_DSPP, 120, 2}, + { DBGBUS_DSPP, 120, 3}, + { DBGBUS_DSPP, 120, 4}, + { DBGBUS_DSPP, 120, 5}, + { DBGBUS_DSPP, 120, 6}, + { DBGBUS_DSPP, 120, 7, _dpu_debug_bus_lm_dump }, + + /* csc */ + { DBGBUS_SSPP0, 7, 0}, + { DBGBUS_SSPP0, 7, 1}, + { DBGBUS_SSPP0, 27, 0}, + { DBGBUS_SSPP0, 27, 1}, + { DBGBUS_SSPP1, 7, 0}, + { DBGBUS_SSPP1, 7, 1}, + { DBGBUS_SSPP1, 27, 0}, + { DBGBUS_SSPP1, 27, 1}, + + /* pcc */ + { DBGBUS_SSPP0, 3, 3}, + { DBGBUS_SSPP0, 23, 3}, + { DBGBUS_SSPP0, 33, 3}, + { DBGBUS_SSPP0, 43, 3}, + { DBGBUS_SSPP1, 3, 3}, + { DBGBUS_SSPP1, 23, 3}, + { DBGBUS_SSPP1, 33, 3}, + { DBGBUS_SSPP1, 43, 3}, + + /* spa */ + { DBGBUS_SSPP0, 8, 0}, + { DBGBUS_SSPP0, 28, 0}, + { DBGBUS_SSPP1, 8, 0}, + { DBGBUS_SSPP1, 28, 0}, + { DBGBUS_DSPP, 13, 0}, + { DBGBUS_DSPP, 19, 0}, + + /* igc */ + { DBGBUS_SSPP0, 17, 0}, + { DBGBUS_SSPP0, 17, 1}, + { DBGBUS_SSPP0, 17, 3}, + { DBGBUS_SSPP0, 37, 0}, + { DBGBUS_SSPP0, 37, 1}, + { DBGBUS_SSPP0, 37, 3}, + { DBGBUS_SSPP0, 46, 0}, + { DBGBUS_SSPP0, 46, 1}, + { DBGBUS_SSPP0, 46, 3}, + + { DBGBUS_SSPP1, 17, 0}, + { DBGBUS_SSPP1, 17, 1}, + { DBGBUS_SSPP1, 17, 3}, + { DBGBUS_SSPP1, 37, 0}, + { DBGBUS_SSPP1, 37, 1}, + { DBGBUS_SSPP1, 37, 3}, + { DBGBUS_SSPP1, 46, 0}, + { DBGBUS_SSPP1, 46, 1}, + { DBGBUS_SSPP1, 46, 3}, + + { DBGBUS_DSPP, 14, 0}, + { DBGBUS_DSPP, 14, 1}, + { DBGBUS_DSPP, 14, 3}, + { DBGBUS_DSPP, 20, 0}, + { DBGBUS_DSPP, 20, 1}, + { DBGBUS_DSPP, 20, 3}, + + /* intf0-3 */ + { DBGBUS_PERIPH, 0, 0}, + { DBGBUS_PERIPH, 1, 0}, + { DBGBUS_PERIPH, 2, 0}, + { DBGBUS_PERIPH, 3, 0}, + + /* te counter wrapper */ + { DBGBUS_PERIPH, 60, 0}, + + /* dsc0 */ + { DBGBUS_PERIPH, 47, 0}, + { DBGBUS_PERIPH, 47, 1}, + { DBGBUS_PERIPH, 47, 2}, + { DBGBUS_PERIPH, 47, 3}, + { DBGBUS_PERIPH, 47, 4}, + { DBGBUS_PERIPH, 47, 5}, + { DBGBUS_PERIPH, 47, 6}, + { DBGBUS_PERIPH, 47, 7}, + + /* dsc1 */ + { DBGBUS_PERIPH, 48, 0}, + { DBGBUS_PERIPH, 48, 1}, + { DBGBUS_PERIPH, 48, 2}, + { DBGBUS_PERIPH, 48, 3}, + { DBGBUS_PERIPH, 48, 4}, + { DBGBUS_PERIPH, 48, 5}, + { DBGBUS_PERIPH, 48, 6}, + { DBGBUS_PERIPH, 48, 7}, + + /* dsc2 */ + { DBGBUS_PERIPH, 51, 0}, + { DBGBUS_PERIPH, 51, 1}, + { DBGBUS_PERIPH, 51, 2}, + { DBGBUS_PERIPH, 51, 3}, + { DBGBUS_PERIPH, 51, 4}, + { DBGBUS_PERIPH, 51, 5}, + { DBGBUS_PERIPH, 51, 6}, + { DBGBUS_PERIPH, 51, 7}, + + /* dsc3 */ + { DBGBUS_PERIPH, 52, 0}, + { DBGBUS_PERIPH, 52, 1}, + { DBGBUS_PERIPH, 52, 2}, + { DBGBUS_PERIPH, 52, 3}, + { DBGBUS_PERIPH, 52, 4}, + { DBGBUS_PERIPH, 52, 5}, + { DBGBUS_PERIPH, 52, 6}, + { DBGBUS_PERIPH, 52, 7}, + + /* tear-check */ + { DBGBUS_PERIPH, 63, 0 }, + { DBGBUS_PERIPH, 64, 0 }, + { DBGBUS_PERIPH, 65, 0 }, + { DBGBUS_PERIPH, 73, 0 }, + { DBGBUS_PERIPH, 74, 0 }, + + /* cdwn */ + { DBGBUS_PERIPH, 80, 0}, + { DBGBUS_PERIPH, 80, 1}, + { DBGBUS_PERIPH, 80, 2}, + + { DBGBUS_PERIPH, 81, 0}, + { DBGBUS_PERIPH, 81, 1}, + { DBGBUS_PERIPH, 81, 2}, + + { DBGBUS_PERIPH, 82, 0}, + { DBGBUS_PERIPH, 82, 1}, + { DBGBUS_PERIPH, 82, 2}, + { DBGBUS_PERIPH, 82, 3}, + { DBGBUS_PERIPH, 82, 4}, + { DBGBUS_PERIPH, 82, 5}, + { DBGBUS_PERIPH, 82, 6}, + { DBGBUS_PERIPH, 82, 7}, + + /* hdmi */ + { DBGBUS_PERIPH, 68, 0}, + { DBGBUS_PERIPH, 68, 1}, + { DBGBUS_PERIPH, 68, 2}, + { DBGBUS_PERIPH, 68, 3}, + { DBGBUS_PERIPH, 68, 4}, + { DBGBUS_PERIPH, 68, 5}, + + /* edp */ + { DBGBUS_PERIPH, 69, 0}, + { DBGBUS_PERIPH, 69, 1}, + { DBGBUS_PERIPH, 69, 2}, + { DBGBUS_PERIPH, 69, 3}, + { DBGBUS_PERIPH, 69, 4}, + { DBGBUS_PERIPH, 69, 5}, + + /* dsi0 */ + { DBGBUS_PERIPH, 70, 0}, + { DBGBUS_PERIPH, 70, 1}, + { DBGBUS_PERIPH, 70, 2}, + { DBGBUS_PERIPH, 70, 3}, + { DBGBUS_PERIPH, 70, 4}, + { DBGBUS_PERIPH, 70, 5}, + + /* dsi1 */ + { DBGBUS_PERIPH, 71, 0}, + { DBGBUS_PERIPH, 71, 1}, + { DBGBUS_PERIPH, 71, 2}, + { DBGBUS_PERIPH, 71, 3}, + { DBGBUS_PERIPH, 71, 4}, + { DBGBUS_PERIPH, 71, 5}, +}; + +static struct vbif_debug_bus_entry vbif_dbg_bus_msm8998[] = { + {0x214, 0x21c, 16, 2, 0x0, 0xd}, /* arb clients */ + {0x214, 0x21c, 16, 2, 0x80, 0xc0}, /* arb clients */ + {0x214, 0x21c, 16, 2, 0x100, 0x140}, /* arb clients */ + {0x214, 0x21c, 0, 16, 0x0, 0xf}, /* xin blocks - axi side */ + {0x214, 0x21c, 0, 16, 0x80, 0xa4}, /* xin blocks - axi side */ + {0x214, 0x21c, 0, 15, 0x100, 0x124}, /* xin blocks - axi side */ + {0x21c, 0x214, 0, 14, 0, 0xc}, /* xin blocks - clock side */ +}; + +/** + * _dpu_dbg_enable_power - use callback to turn power on for hw register access + * @enable: whether to turn power on or off + */ +static inline void _dpu_dbg_enable_power(int enable) +{ + if (enable) + pm_runtime_get_sync(dpu_dbg_base.dev); + else + pm_runtime_put_sync(dpu_dbg_base.dev); +} + +static void _dpu_dbg_dump_dpu_dbg_bus(struct dpu_dbg_dpu_debug_bus *bus) +{ + bool in_log, in_mem; + u32 **dump_mem = NULL; + u32 *dump_addr = NULL; + u32 status = 0; + struct dpu_debug_bus_entry *head; + phys_addr_t phys = 0; + int list_size; + int i; + u32 offset; + void __iomem *mem_base = NULL; + struct dpu_dbg_reg_base *reg_base; + + if (!bus || !bus->cmn.entries_size) + return; + + list_for_each_entry(reg_base, &dpu_dbg_base.reg_base_list, + reg_base_head) + if (strlen(reg_base->name) && + !strcmp(reg_base->name, bus->cmn.name)) + mem_base = reg_base->base + bus->top_blk_off; + + if (!mem_base) { + pr_err("unable to find mem_base for %s\n", bus->cmn.name); + return; + } + + dump_mem = &bus->cmn.dumped_content; + + /* will keep in memory 4 entries of 4 bytes each */ + list_size = (bus->cmn.entries_size * 4 * 4); + + in_log = (bus->cmn.enable_mask & DPU_DBG_DUMP_IN_LOG); + in_mem = (bus->cmn.enable_mask & DPU_DBG_DUMP_IN_MEM); + + if (!in_log && !in_mem) + return; + + dev_info(dpu_dbg_base.dev, "======== start %s dump =========\n", + bus->cmn.name); + + if (in_mem) { + if (!(*dump_mem)) + *dump_mem = dma_alloc_coherent(dpu_dbg_base.dev, + list_size, &phys, GFP_KERNEL); + + if (*dump_mem) { + dump_addr = *dump_mem; + dev_info(dpu_dbg_base.dev, + "%s: start_addr:0x%pK len:0x%x\n", + __func__, dump_addr, list_size); + } else { + in_mem = false; + pr_err("dump_mem: allocation fails\n"); + } + } + + _dpu_dbg_enable_power(true); + for (i = 0; i < bus->cmn.entries_size; i++) { + head = bus->entries + i; + writel_relaxed(TEST_MASK(head->block_id, head->test_id), + mem_base + head->wr_addr); + wmb(); /* make sure test bits were written */ + + if (bus->cmn.flags & DBGBUS_FLAGS_DSPP) { + offset = DBGBUS_DSPP_STATUS; + /* keep DSPP test point enabled */ + if (head->wr_addr != DBGBUS_DSPP) + writel_relaxed(0xF, mem_base + DBGBUS_DSPP); + } else { + offset = head->wr_addr + 0x4; + } + + status = readl_relaxed(mem_base + offset); + + if (in_log) + dev_info(dpu_dbg_base.dev, + "waddr=0x%x blk=%d tst=%d val=0x%x\n", + head->wr_addr, head->block_id, + head->test_id, status); + + if (dump_addr && in_mem) { + dump_addr[i*4] = head->wr_addr; + dump_addr[i*4 + 1] = head->block_id; + dump_addr[i*4 + 2] = head->test_id; + dump_addr[i*4 + 3] = status; + } + + if (head->analyzer) + head->analyzer(mem_base, head, status); + + /* Disable debug bus once we are done */ + writel_relaxed(0, mem_base + head->wr_addr); + if (bus->cmn.flags & DBGBUS_FLAGS_DSPP && + head->wr_addr != DBGBUS_DSPP) + writel_relaxed(0x0, mem_base + DBGBUS_DSPP); + } + _dpu_dbg_enable_power(false); + + dev_info(dpu_dbg_base.dev, "======== end %s dump =========\n", + bus->cmn.name); +} + +static void _dpu_dbg_dump_vbif_debug_bus_entry( + struct vbif_debug_bus_entry *head, void __iomem *mem_base, + u32 *dump_addr, bool in_log) +{ + int i, j; + u32 val; + + if (!dump_addr && !in_log) + return; + + for (i = 0; i < head->block_cnt; i++) { + writel_relaxed(1 << (i + head->bit_offset), + mem_base + head->block_bus_addr); + /* make sure that current bus blcok enable */ + wmb(); + for (j = head->test_pnt_start; j < head->test_pnt_cnt; j++) { + writel_relaxed(j, mem_base + head->block_bus_addr + 4); + /* make sure that test point is enabled */ + wmb(); + val = readl_relaxed(mem_base + MMSS_VBIF_TEST_BUS_OUT); + if (dump_addr) { + *dump_addr++ = head->block_bus_addr; + *dump_addr++ = i; + *dump_addr++ = j; + *dump_addr++ = val; + } + if (in_log) + dev_info(dpu_dbg_base.dev, + "testpoint:%x arb/xin id=%d index=%d val=0x%x\n", + head->block_bus_addr, i, j, val); + } + } +} + +static void _dpu_dbg_dump_vbif_dbg_bus(struct dpu_dbg_vbif_debug_bus *bus) +{ + bool in_log, in_mem; + u32 **dump_mem = NULL; + u32 *dump_addr = NULL; + u32 value, d0, d1; + unsigned long reg, reg1, reg2; + struct vbif_debug_bus_entry *head; + phys_addr_t phys = 0; + int i, list_size = 0; + void __iomem *mem_base = NULL; + struct vbif_debug_bus_entry *dbg_bus; + u32 bus_size; + struct dpu_dbg_reg_base *reg_base; + + if (!bus || !bus->cmn.entries_size) + return; + + list_for_each_entry(reg_base, &dpu_dbg_base.reg_base_list, + reg_base_head) + if (strlen(reg_base->name) && + !strcmp(reg_base->name, bus->cmn.name)) + mem_base = reg_base->base; + + if (!mem_base) { + pr_err("unable to find mem_base for %s\n", bus->cmn.name); + return; + } + + dbg_bus = bus->entries; + bus_size = bus->cmn.entries_size; + list_size = bus->cmn.entries_size; + dump_mem = &bus->cmn.dumped_content; + + dev_info(dpu_dbg_base.dev, "======== start %s dump =========\n", + bus->cmn.name); + + if (!dump_mem || !dbg_bus || !bus_size || !list_size) + return; + + /* allocate memory for each test point */ + for (i = 0; i < bus_size; i++) { + head = dbg_bus + i; + list_size += (head->block_cnt * head->test_pnt_cnt); + } + + /* 4 bytes * 4 entries for each test point*/ + list_size *= 16; + + in_log = (bus->cmn.enable_mask & DPU_DBG_DUMP_IN_LOG); + in_mem = (bus->cmn.enable_mask & DPU_DBG_DUMP_IN_MEM); + + if (!in_log && !in_mem) + return; + + if (in_mem) { + if (!(*dump_mem)) + *dump_mem = dma_alloc_coherent(dpu_dbg_base.dev, + list_size, &phys, GFP_KERNEL); + + if (*dump_mem) { + dump_addr = *dump_mem; + dev_info(dpu_dbg_base.dev, + "%s: start_addr:0x%pK len:0x%x\n", + __func__, dump_addr, list_size); + } else { + in_mem = false; + pr_err("dump_mem: allocation fails\n"); + } + } + + _dpu_dbg_enable_power(true); + + value = readl_relaxed(mem_base + MMSS_VBIF_CLKON); + writel_relaxed(value | BIT(1), mem_base + MMSS_VBIF_CLKON); + + /* make sure that vbif core is on */ + wmb(); + + /** + * Extract VBIF error info based on XIN halt and error status. + * If the XIN client is not in HALT state, or an error is detected, + * then retrieve the VBIF error info for it. + */ + reg = readl_relaxed(mem_base + MMSS_VBIF_XIN_HALT_CTRL1); + reg1 = readl_relaxed(mem_base + MMSS_VBIF_PND_ERR); + reg2 = readl_relaxed(mem_base + MMSS_VBIF_SRC_ERR); + dev_err(dpu_dbg_base.dev, + "XIN HALT:0x%lX, PND ERR:0x%lX, SRC ERR:0x%lX\n", + reg, reg1, reg2); + reg >>= 16; + reg &= ~(reg1 | reg2); + for (i = 0; i < MMSS_VBIF_CLIENT_NUM; i++) { + if (!test_bit(0, ®)) { + writel_relaxed(i, mem_base + MMSS_VBIF_ERR_INFO); + /* make sure reg write goes through */ + wmb(); + + d0 = readl_relaxed(mem_base + MMSS_VBIF_ERR_INFO); + d1 = readl_relaxed(mem_base + MMSS_VBIF_ERR_INFO_1); + + dev_err(dpu_dbg_base.dev, + "Client:%d, errinfo=0x%X, errinfo1=0x%X\n", + i, d0, d1); + } + reg >>= 1; + } + + for (i = 0; i < bus_size; i++) { + head = dbg_bus + i; + + writel_relaxed(0, mem_base + head->disable_bus_addr); + writel_relaxed(BIT(0), mem_base + MMSS_VBIF_TEST_BUS_OUT_CTRL); + /* make sure that other bus is off */ + wmb(); + + _dpu_dbg_dump_vbif_debug_bus_entry(head, mem_base, dump_addr, + in_log); + if (dump_addr) + dump_addr += (head->block_cnt * head->test_pnt_cnt * 4); + } + + _dpu_dbg_enable_power(false); + + dev_info(dpu_dbg_base.dev, "======== end %s dump =========\n", + bus->cmn.name); +} + +/** + * _dpu_dump_array - dump array of register bases + * @name: string indicating origin of dump + * @dump_dbgbus_dpu: whether to dump the dpu debug bus + * @dump_dbgbus_vbif_rt: whether to dump the vbif rt debug bus + */ +static void _dpu_dump_array(const char *name, bool dump_dbgbus_dpu, + bool dump_dbgbus_vbif_rt) +{ + if (dump_dbgbus_dpu) + _dpu_dbg_dump_dpu_dbg_bus(&dpu_dbg_base.dbgbus_dpu); + + if (dump_dbgbus_vbif_rt) + _dpu_dbg_dump_vbif_dbg_bus(&dpu_dbg_base.dbgbus_vbif_rt); +} + +/** + * _dpu_dump_work - deferred dump work function + * @work: work structure + */ +static void _dpu_dump_work(struct work_struct *work) +{ + _dpu_dump_array("dpudump_workitem", + dpu_dbg_base.dbgbus_dpu.cmn.include_in_deferred_work, + dpu_dbg_base.dbgbus_vbif_rt.cmn.include_in_deferred_work); +} + +void dpu_dbg_dump(bool queue_work, const char *name, bool dump_dbgbus_dpu, + bool dump_dbgbus_vbif_rt) +{ + if (queue_work && work_pending(&dpu_dbg_base.dump_work)) + return; + + if (!queue_work) { + _dpu_dump_array(name, dump_dbgbus_dpu, dump_dbgbus_vbif_rt); + return; + } + + /* schedule work to dump later */ + dpu_dbg_base.dbgbus_dpu.cmn.include_in_deferred_work = dump_dbgbus_dpu; + dpu_dbg_base.dbgbus_vbif_rt.cmn.include_in_deferred_work = + dump_dbgbus_vbif_rt; + schedule_work(&dpu_dbg_base.dump_work); +} + +/* + * dpu_dbg_debugfs_open - debugfs open handler for debug dump + * @inode: debugfs inode + * @file: file handle + */ +static int dpu_dbg_debugfs_open(struct inode *inode, struct file *file) +{ + /* non-seekable */ + file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE); + file->private_data = inode->i_private; + return 0; +} + +/** + * dpu_dbg_dump_write - debugfs write handler for debug dump + * @file: file handler + * @user_buf: user buffer content from debugfs + * @count: size of user buffer + * @ppos: position offset of user buffer + */ +static ssize_t dpu_dbg_dump_write(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + _dpu_dump_array("dump_debugfs", true, true); + return count; +} + +static const struct file_operations dpu_dbg_dump_fops = { + .open = dpu_dbg_debugfs_open, + .write = dpu_dbg_dump_write, +}; + +int dpu_dbg_debugfs_register(struct dentry *debugfs_root) +{ + static struct dpu_dbg_base *dbg = &dpu_dbg_base; + char debug_name[80] = ""; + + if (!debugfs_root) + return -EINVAL; + + debugfs_create_file("dump", 0600, debugfs_root, NULL, + &dpu_dbg_dump_fops); + + if (dbg->dbgbus_dpu.entries) { + dbg->dbgbus_dpu.cmn.name = DBGBUS_NAME_DPU; + snprintf(debug_name, sizeof(debug_name), "%s_dbgbus", + dbg->dbgbus_dpu.cmn.name); + dbg->dbgbus_dpu.cmn.enable_mask = DEFAULT_DBGBUS_DPU; + debugfs_create_u32(debug_name, 0600, debugfs_root, + &dbg->dbgbus_dpu.cmn.enable_mask); + } + + if (dbg->dbgbus_vbif_rt.entries) { + dbg->dbgbus_vbif_rt.cmn.name = DBGBUS_NAME_VBIF_RT; + snprintf(debug_name, sizeof(debug_name), "%s_dbgbus", + dbg->dbgbus_vbif_rt.cmn.name); + dbg->dbgbus_vbif_rt.cmn.enable_mask = DEFAULT_DBGBUS_VBIFRT; + debugfs_create_u32(debug_name, 0600, debugfs_root, + &dbg->dbgbus_vbif_rt.cmn.enable_mask); + } + + return 0; +} + +static void _dpu_dbg_debugfs_destroy(void) +{ +} + +void dpu_dbg_init_dbg_buses(u32 hwversion) +{ + static struct dpu_dbg_base *dbg = &dpu_dbg_base; + + memset(&dbg->dbgbus_dpu, 0, sizeof(dbg->dbgbus_dpu)); + memset(&dbg->dbgbus_vbif_rt, 0, sizeof(dbg->dbgbus_vbif_rt)); + + if (IS_MSM8998_TARGET(hwversion)) { + dbg->dbgbus_dpu.entries = dbg_bus_dpu_8998; + dbg->dbgbus_dpu.cmn.entries_size = ARRAY_SIZE(dbg_bus_dpu_8998); + dbg->dbgbus_dpu.cmn.flags = DBGBUS_FLAGS_DSPP; + + dbg->dbgbus_vbif_rt.entries = vbif_dbg_bus_msm8998; + dbg->dbgbus_vbif_rt.cmn.entries_size = + ARRAY_SIZE(vbif_dbg_bus_msm8998); + } else if (IS_SDM845_TARGET(hwversion) || IS_SDM670_TARGET(hwversion)) { + dbg->dbgbus_dpu.entries = dbg_bus_dpu_sdm845; + dbg->dbgbus_dpu.cmn.entries_size = + ARRAY_SIZE(dbg_bus_dpu_sdm845); + dbg->dbgbus_dpu.cmn.flags = DBGBUS_FLAGS_DSPP; + + /* vbif is unchanged vs 8998 */ + dbg->dbgbus_vbif_rt.entries = vbif_dbg_bus_msm8998; + dbg->dbgbus_vbif_rt.cmn.entries_size = + ARRAY_SIZE(vbif_dbg_bus_msm8998); + } else { + pr_err("unsupported chipset id %X\n", hwversion); + } +} + +int dpu_dbg_init(struct device *dev) +{ + if (!dev) { + pr_err("invalid params\n"); + return -EINVAL; + } + + INIT_LIST_HEAD(&dpu_dbg_base.reg_base_list); + dpu_dbg_base.dev = dev; + + INIT_WORK(&dpu_dbg_base.dump_work, _dpu_dump_work); + + return 0; +} + +/** + * dpu_dbg_destroy - destroy dpu debug facilities + */ +void dpu_dbg_destroy(void) +{ + _dpu_dbg_debugfs_destroy(); +} + +void dpu_dbg_set_dpu_top_offset(u32 blk_off) +{ + dpu_dbg_base.dbgbus_dpu.top_blk_off = blk_off; +} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.h new file mode 100644 index 0000000000000..1e6fa945f98b3 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_dbg.h @@ -0,0 +1,103 @@ +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef DPU_DBG_H_ +#define DPU_DBG_H_ + +#include <stdarg.h> +#include <linux/debugfs.h> +#include <linux/list.h> + +enum dpu_dbg_dump_flag { + DPU_DBG_DUMP_IN_LOG = BIT(0), + DPU_DBG_DUMP_IN_MEM = BIT(1), +}; + +#if defined(CONFIG_DEBUG_FS) + +/** + * dpu_dbg_init_dbg_buses - initialize debug bus dumping support for the chipset + * @hwversion: Chipset revision + */ +void dpu_dbg_init_dbg_buses(u32 hwversion); + +/** + * dpu_dbg_init - initialize global dpu debug facilities: regdump + * @dev: device handle + * Returns: 0 or -ERROR + */ +int dpu_dbg_init(struct device *dev); + +/** + * dpu_dbg_debugfs_register - register entries at the given debugfs dir + * @debugfs_root: debugfs root in which to create dpu debug entries + * Returns: 0 or -ERROR + */ +int dpu_dbg_debugfs_register(struct dentry *debugfs_root); + +/** + * dpu_dbg_destroy - destroy the global dpu debug facilities + * Returns: none + */ +void dpu_dbg_destroy(void); + +/** + * dpu_dbg_dump - trigger dumping of all dpu_dbg facilities + * @queue_work: whether to queue the dumping work to the work_struct + * @name: string indicating origin of dump + * @dump_dbgbus: dump the dpu debug bus + * @dump_vbif_rt: dump the vbif rt bus + * Returns: none + */ +void dpu_dbg_dump(bool queue_work, const char *name, bool dump_dbgbus_dpu, + bool dump_dbgbus_vbif_rt); + +/** + * dpu_dbg_set_dpu_top_offset - set the target specific offset from mdss base + * address of the top registers. Used for accessing debug bus controls. + * @blk_off: offset from mdss base of the top block + */ +void dpu_dbg_set_dpu_top_offset(u32 blk_off); + +#else + +static inline void dpu_dbg_init_dbg_buses(u32 hwversion) +{ +} + +static inline int dpu_dbg_init(struct device *dev) +{ + return 0; +} + +static inline int dpu_dbg_debugfs_register(struct dentry *debugfs_root) +{ + return 0; +} + +static inline void dpu_dbg_destroy(void) +{ +} + +static inline void dpu_dbg_dump(bool queue_work, const char *name, + bool dump_dbgbus_dpu, bool dump_dbgbus_vbif_rt) +{ +} + +static inline void dpu_dbg_set_dpu_top_offset(u32 blk_off) +{ +} + +#endif /* defined(CONFIG_DEBUG_FS) */ + + +#endif /* DPU_DBG_H_ */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c new file mode 100644 index 0000000000000..27775feed32be --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -0,0 +1,2575 @@ +/* + * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.com> + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ +#include <linux/kthread.h> +#include <linux/debugfs.h> +#include <linux/seq_file.h> + +#include "msm_drv.h" +#include "dpu_kms.h" +#include <drm/drm_crtc.h> +#include <drm/drm_crtc_helper.h> +#include "dpu_hwio.h" +#include "dpu_hw_catalog.h" +#include "dpu_hw_intf.h" +#include "dpu_hw_ctl.h" +#include "dpu_formats.h" +#include "dpu_encoder_phys.h" +#include "dpu_crtc.h" +#include "dpu_trace.h" +#include "dpu_core_irq.h" + +#define DPU_DEBUG_ENC(e, fmt, ...) DPU_DEBUG("enc%d " fmt,\ + (e) ? (e)->base.base.id : -1, ##__VA_ARGS__) + +#define DPU_ERROR_ENC(e, fmt, ...) DPU_ERROR("enc%d " fmt,\ + (e) ? (e)->base.base.id : -1, ##__VA_ARGS__) + +#define DPU_DEBUG_PHYS(p, fmt, ...) DPU_DEBUG("enc%d intf%d pp%d " fmt,\ + (p) ? (p)->parent->base.id : -1, \ + (p) ? (p)->intf_idx - INTF_0 : -1, \ + (p) ? ((p)->hw_pp ? (p)->hw_pp->idx - PINGPONG_0 : -1) : -1, \ + ##__VA_ARGS__) + +#define DPU_ERROR_PHYS(p, fmt, ...) DPU_ERROR("enc%d intf%d pp%d " fmt,\ + (p) ? (p)->parent->base.id : -1, \ + (p) ? (p)->intf_idx - INTF_0 : -1, \ + (p) ? ((p)->hw_pp ? (p)->hw_pp->idx - PINGPONG_0 : -1) : -1, \ + ##__VA_ARGS__) + +/* + * Two to anticipate panels that can do cmd/vid dynamic switching + * plan is to create all possible physical encoder types, and switch between + * them at runtime + */ +#define NUM_PHYS_ENCODER_TYPES 2 + +#define MAX_PHYS_ENCODERS_PER_VIRTUAL \ + (MAX_H_TILES_PER_DISPLAY * NUM_PHYS_ENCODER_TYPES) + +#define MAX_CHANNELS_PER_ENC 2 + +#define MISR_BUFF_SIZE 256 + +#define IDLE_SHORT_TIMEOUT 1 + +#define MAX_VDISPLAY_SPLIT 1080 + +/** + * enum dpu_enc_rc_events - events for resource control state machine + * @DPU_ENC_RC_EVENT_KICKOFF: + * This event happens at NORMAL priority. + * Event that signals the start of the transfer. When this event is + * received, enable MDP/DSI core clocks. Regardless of the previous + * state, the resource should be in ON state at the end of this event. + * @DPU_ENC_RC_EVENT_FRAME_DONE: + * This event happens at INTERRUPT level. + * Event signals the end of the data transfer after the PP FRAME_DONE + * event. At the end of this event, a delayed work is scheduled to go to + * IDLE_PC state after IDLE_TIMEOUT time. + * @DPU_ENC_RC_EVENT_PRE_STOP: + * This event happens at NORMAL priority. + * This event, when received during the ON state, leave the RC STATE + * in the PRE_OFF state. It should be followed by the STOP event as + * part of encoder disable. + * If received during IDLE or OFF states, it will do nothing. + * @DPU_ENC_RC_EVENT_STOP: + * This event happens at NORMAL priority. + * When this event is received, disable all the MDP/DSI core clocks, and + * disable IRQs. It should be called from the PRE_OFF or IDLE states. + * IDLE is expected when IDLE_PC has run, and PRE_OFF did nothing. + * PRE_OFF is expected when PRE_STOP was executed during the ON state. + * Resource state should be in OFF at the end of the event. + * @DPU_ENC_RC_EVENT_ENTER_IDLE: + * This event happens at NORMAL priority from a work item. + * Event signals that there were no frame updates for IDLE_TIMEOUT time. + * This would disable MDP/DSI core clocks and change the resource state + * to IDLE. + */ +enum dpu_enc_rc_events { + DPU_ENC_RC_EVENT_KICKOFF = 1, + DPU_ENC_RC_EVENT_FRAME_DONE, + DPU_ENC_RC_EVENT_PRE_STOP, + DPU_ENC_RC_EVENT_STOP, + DPU_ENC_RC_EVENT_ENTER_IDLE +}; + +/* + * enum dpu_enc_rc_states - states that the resource control maintains + * @DPU_ENC_RC_STATE_OFF: Resource is in OFF state + * @DPU_ENC_RC_STATE_PRE_OFF: Resource is transitioning to OFF state + * @DPU_ENC_RC_STATE_ON: Resource is in ON state + * @DPU_ENC_RC_STATE_MODESET: Resource is in modeset state + * @DPU_ENC_RC_STATE_IDLE: Resource is in IDLE state + */ +enum dpu_enc_rc_states { + DPU_ENC_RC_STATE_OFF, + DPU_ENC_RC_STATE_PRE_OFF, + DPU_ENC_RC_STATE_ON, + DPU_ENC_RC_STATE_IDLE +}; + +/** + * struct dpu_encoder_virt - virtual encoder. Container of one or more physical + * encoders. Virtual encoder manages one "logical" display. Physical + * encoders manage one intf block, tied to a specific panel/sub-panel. + * Virtual encoder defers as much as possible to the physical encoders. + * Virtual encoder registers itself with the DRM Framework as the encoder. + * @base: drm_encoder base class for registration with DRM + * @enc_spin_lock: Virtual-Encoder-Wide Spin Lock for IRQ purposes + * @bus_scaling_client: Client handle to the bus scaling interface + * @num_phys_encs: Actual number of physical encoders contained. + * @phys_encs: Container of physical encoders managed. + * @cur_master: Pointer to the current master in this mode. Optimization + * Only valid after enable. Cleared as disable. + * @hw_pp Handle to the pingpong blocks used for the display. No. + * pingpong blocks can be different than num_phys_encs. + * @intfs_swapped Whether or not the phys_enc interfaces have been swapped + * for partial update right-only cases, such as pingpong + * split where virtual pingpong does not generate IRQs + * @crtc_vblank_cb: Callback into the upper layer / CRTC for + * notification of the VBLANK + * @crtc_vblank_cb_data: Data from upper layer for VBLANK notification + * @crtc_kickoff_cb: Callback into CRTC that will flush & start + * all CTL paths + * @crtc_kickoff_cb_data: Opaque user data given to crtc_kickoff_cb + * @debugfs_root: Debug file system root file node + * @enc_lock: Lock around physical encoder create/destroy and + access. + * @frame_busy_mask: Bitmask tracking which phys_enc we are still + * busy processing current command. + * Bit0 = phys_encs[0] etc. + * @crtc_frame_event_cb: callback handler for frame event + * @crtc_frame_event_cb_data: callback handler private data + * @frame_done_timeout: frame done timeout in Hz + * @frame_done_timer: watchdog timer for frame done event + * @vsync_event_timer: vsync timer + * @disp_info: local copy of msm_display_info struct + * @misr_enable: misr enable/disable status + * @misr_frame_count: misr frame count before start capturing the data + * @idle_pc_supported: indicate if idle power collaps is supported + * @rc_lock: resource control mutex lock to protect + * virt encoder over various state changes + * @rc_state: resource controller state + * @delayed_off_work: delayed worker to schedule disabling of + * clks and resources after IDLE_TIMEOUT time. + * @vsync_event_work: worker to handle vsync event for autorefresh + * @topology: topology of the display + * @mode_set_complete: flag to indicate modeset completion + * @idle_timeout: idle timeout duration in milliseconds + */ +struct dpu_encoder_virt { + struct drm_encoder base; + spinlock_t enc_spinlock; + uint32_t bus_scaling_client; + + uint32_t display_num_of_h_tiles; + + unsigned int num_phys_encs; + struct dpu_encoder_phys *phys_encs[MAX_PHYS_ENCODERS_PER_VIRTUAL]; + struct dpu_encoder_phys *cur_master; + struct dpu_hw_pingpong *hw_pp[MAX_CHANNELS_PER_ENC]; + + bool intfs_swapped; + + void (*crtc_vblank_cb)(void *); + void *crtc_vblank_cb_data; + + struct dentry *debugfs_root; + struct mutex enc_lock; + DECLARE_BITMAP(frame_busy_mask, MAX_PHYS_ENCODERS_PER_VIRTUAL); + void (*crtc_frame_event_cb)(void *, u32 event); + void *crtc_frame_event_cb_data; + + atomic_t frame_done_timeout; + struct timer_list frame_done_timer; + struct timer_list vsync_event_timer; + + struct msm_display_info disp_info; + bool misr_enable; + u32 misr_frame_count; + + bool idle_pc_supported; + struct mutex rc_lock; + enum dpu_enc_rc_states rc_state; + struct kthread_delayed_work delayed_off_work; + struct kthread_work vsync_event_work; + struct msm_display_topology topology; + bool mode_set_complete; + + u32 idle_timeout; +}; + +#define to_dpu_encoder_virt(x) container_of(x, struct dpu_encoder_virt, base) +static inline int _dpu_encoder_power_enable(struct dpu_encoder_virt *dpu_enc, + bool enable) +{ + struct drm_encoder *drm_enc; + struct msm_drm_private *priv; + struct dpu_kms *dpu_kms; + + if (!dpu_enc) { + DPU_ERROR("invalid dpu enc\n"); + return -EINVAL; + } + + drm_enc = &dpu_enc->base; + if (!drm_enc->dev || !drm_enc->dev->dev_private) { + DPU_ERROR("drm device invalid\n"); + return -EINVAL; + } + + priv = drm_enc->dev->dev_private; + if (!priv->kms) { + DPU_ERROR("invalid kms\n"); + return -EINVAL; + } + + dpu_kms = to_dpu_kms(priv->kms); + + if (enable) + pm_runtime_get_sync(&dpu_kms->pdev->dev); + else + pm_runtime_put_sync(&dpu_kms->pdev->dev); + + return 0; +} + +void dpu_encoder_helper_report_irq_timeout(struct dpu_encoder_phys *phys_enc, + enum dpu_intr_idx intr_idx) +{ + DRM_ERROR("irq timeout id=%u, intf=%d, pp=%d, intr=%d\n", + DRMID(phys_enc->parent), phys_enc->intf_idx - INTF_0, + phys_enc->hw_pp->idx - PINGPONG_0, intr_idx); + + if (phys_enc->parent_ops->handle_frame_done) + phys_enc->parent_ops->handle_frame_done( + phys_enc->parent, phys_enc, + DPU_ENCODER_FRAME_EVENT_ERROR); +} + +int dpu_encoder_helper_wait_for_irq(struct dpu_encoder_phys *phys_enc, + enum dpu_intr_idx intr_idx, + struct dpu_encoder_wait_info *wait_info) +{ + struct dpu_encoder_irq *irq; + u32 irq_status; + int ret; + + if (!phys_enc || !wait_info || intr_idx >= INTR_IDX_MAX) { + DPU_ERROR("invalid params\n"); + return -EINVAL; + } + irq = &phys_enc->irq[intr_idx]; + + /* note: do master / slave checking outside */ + + /* return EWOULDBLOCK since we know the wait isn't necessary */ + if (phys_enc->enable_state == DPU_ENC_DISABLED) { + DRM_ERROR("encoder is disabled id=%u, intr=%d, hw=%d, irq=%d", + DRMID(phys_enc->parent), intr_idx, irq->hw_idx, + irq->irq_idx); + return -EWOULDBLOCK; + } + + if (irq->irq_idx < 0) { + DRM_DEBUG_KMS("skip irq wait id=%u, intr=%d, hw=%d, irq=%s", + DRMID(phys_enc->parent), intr_idx, irq->hw_idx, + irq->name); + return 0; + } + + DRM_DEBUG_KMS("id=%u, intr=%d, hw=%d, irq=%d, pp=%d, pending_cnt=%d", + DRMID(phys_enc->parent), intr_idx, irq->hw_idx, + irq->irq_idx, phys_enc->hw_pp->idx - PINGPONG_0, + atomic_read(wait_info->atomic_cnt)); + + ret = dpu_encoder_helper_wait_event_timeout( + DRMID(phys_enc->parent), + irq->hw_idx, + wait_info); + + if (ret <= 0) { + irq_status = dpu_core_irq_read(phys_enc->dpu_kms, + irq->irq_idx, true); + if (irq_status) { + unsigned long flags; + + DRM_DEBUG_KMS("irq not triggered id=%u, intr=%d, " + "hw=%d, irq=%d, pp=%d, atomic_cnt=%d", + DRMID(phys_enc->parent), intr_idx, + irq->hw_idx, irq->irq_idx, + phys_enc->hw_pp->idx - PINGPONG_0, + atomic_read(wait_info->atomic_cnt)); + local_irq_save(flags); + irq->cb.func(phys_enc, irq->irq_idx); + local_irq_restore(flags); + ret = 0; + } else { + ret = -ETIMEDOUT; + DRM_DEBUG_KMS("irq timeout id=%u, intr=%d, " + "hw=%d, irq=%d, pp=%d, atomic_cnt=%d", + DRMID(phys_enc->parent), intr_idx, + irq->hw_idx, irq->irq_idx, + phys_enc->hw_pp->idx - PINGPONG_0, + atomic_read(wait_info->atomic_cnt)); + } + } else { + ret = 0; + trace_dpu_enc_irq_wait_success(DRMID(phys_enc->parent), + intr_idx, irq->hw_idx, irq->irq_idx, + phys_enc->hw_pp->idx - PINGPONG_0, + atomic_read(wait_info->atomic_cnt)); + } + + return ret; +} + +int dpu_encoder_helper_register_irq(struct dpu_encoder_phys *phys_enc, + enum dpu_intr_idx intr_idx) +{ + struct dpu_encoder_irq *irq; + int ret = 0; + + if (!phys_enc || intr_idx >= INTR_IDX_MAX) { + DPU_ERROR("invalid params\n"); + return -EINVAL; + } + irq = &phys_enc->irq[intr_idx]; + + if (irq->irq_idx >= 0) { + DPU_DEBUG_PHYS(phys_enc, + "skipping already registered irq %s type %d\n", + irq->name, irq->intr_type); + return 0; + } + + irq->irq_idx = dpu_core_irq_idx_lookup(phys_enc->dpu_kms, + irq->intr_type, irq->hw_idx); + if (irq->irq_idx < 0) { + DPU_ERROR_PHYS(phys_enc, + "failed to lookup IRQ index for %s type:%d\n", + irq->name, irq->intr_type); + return -EINVAL; + } + + ret = dpu_core_irq_register_callback(phys_enc->dpu_kms, irq->irq_idx, + &irq->cb); + if (ret) { + DPU_ERROR_PHYS(phys_enc, + "failed to register IRQ callback for %s\n", + irq->name); + irq->irq_idx = -EINVAL; + return ret; + } + + ret = dpu_core_irq_enable(phys_enc->dpu_kms, &irq->irq_idx, 1); + if (ret) { + DRM_ERROR("enable failed id=%u, intr=%d, hw=%d, irq=%d", + DRMID(phys_enc->parent), intr_idx, irq->hw_idx, + irq->irq_idx); + dpu_core_irq_unregister_callback(phys_enc->dpu_kms, + irq->irq_idx, &irq->cb); + irq->irq_idx = -EINVAL; + return ret; + } + + trace_dpu_enc_irq_register_success(DRMID(phys_enc->parent), intr_idx, + irq->hw_idx, irq->irq_idx); + + return ret; +} + +int dpu_encoder_helper_unregister_irq(struct dpu_encoder_phys *phys_enc, + enum dpu_intr_idx intr_idx) +{ + struct dpu_encoder_irq *irq; + int ret; + + if (!phys_enc) { + DPU_ERROR("invalid encoder\n"); + return -EINVAL; + } + irq = &phys_enc->irq[intr_idx]; + + /* silently skip irqs that weren't registered */ + if (irq->irq_idx < 0) { + DRM_ERROR("duplicate unregister id=%u, intr=%d, hw=%d, irq=%d", + DRMID(phys_enc->parent), intr_idx, irq->hw_idx, + irq->irq_idx); + return 0; + } + + ret = dpu_core_irq_disable(phys_enc->dpu_kms, &irq->irq_idx, 1); + if (ret) { + DRM_ERROR("diable failed id=%u, intr=%d, hw=%d, irq=%d ret=%d", + DRMID(phys_enc->parent), intr_idx, irq->hw_idx, + irq->irq_idx, ret); + } + + ret = dpu_core_irq_unregister_callback(phys_enc->dpu_kms, irq->irq_idx, + &irq->cb); + if (ret) { + DRM_ERROR("unreg cb fail id=%u, intr=%d, hw=%d, irq=%d ret=%d", + DRMID(phys_enc->parent), intr_idx, irq->hw_idx, + irq->irq_idx, ret); + } + + trace_dpu_enc_irq_unregister_success(DRMID(phys_enc->parent), intr_idx, + irq->hw_idx, irq->irq_idx); + + irq->irq_idx = -EINVAL; + + return 0; +} + +void dpu_encoder_get_hw_resources(struct drm_encoder *drm_enc, + struct dpu_encoder_hw_resources *hw_res, + struct drm_connector_state *conn_state) +{ + struct dpu_encoder_virt *dpu_enc = NULL; + int i = 0; + + if (!hw_res || !drm_enc || !conn_state) { + DPU_ERROR("invalid argument(s), drm_enc %d, res %d, state %d\n", + drm_enc != 0, hw_res != 0, conn_state != 0); + return; + } + + dpu_enc = to_dpu_encoder_virt(drm_enc); + DPU_DEBUG_ENC(dpu_enc, "\n"); + + /* Query resources used by phys encs, expected to be without overlap */ + memset(hw_res, 0, sizeof(*hw_res)); + hw_res->display_num_of_h_tiles = dpu_enc->display_num_of_h_tiles; + + for (i = 0; i < dpu_enc->num_phys_encs; i++) { + struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; + + if (phys && phys->ops.get_hw_resources) + phys->ops.get_hw_resources(phys, hw_res, conn_state); + } +} + +void dpu_encoder_destroy(struct drm_encoder *drm_enc) +{ + struct dpu_encoder_virt *dpu_enc = NULL; + int i = 0; + + if (!drm_enc) { + DPU_ERROR("invalid encoder\n"); + return; + } + + dpu_enc = to_dpu_encoder_virt(drm_enc); + DPU_DEBUG_ENC(dpu_enc, "\n"); + + mutex_lock(&dpu_enc->enc_lock); + + for (i = 0; i < dpu_enc->num_phys_encs; i++) { + struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; + + if (phys && phys->ops.destroy) { + phys->ops.destroy(phys); + --dpu_enc->num_phys_encs; + dpu_enc->phys_encs[i] = NULL; + } + } + + if (dpu_enc->num_phys_encs) + DPU_ERROR_ENC(dpu_enc, "expected 0 num_phys_encs not %d\n", + dpu_enc->num_phys_encs); + dpu_enc->num_phys_encs = 0; + mutex_unlock(&dpu_enc->enc_lock); + + drm_encoder_cleanup(drm_enc); + mutex_destroy(&dpu_enc->enc_lock); + + kfree(dpu_enc); +} + +void dpu_encoder_helper_split_config( + struct dpu_encoder_phys *phys_enc, + enum dpu_intf interface) +{ + struct dpu_encoder_virt *dpu_enc; + struct split_pipe_cfg cfg = { 0 }; + struct dpu_hw_mdp *hw_mdptop; + struct msm_display_info *disp_info; + + if (!phys_enc || !phys_enc->hw_mdptop || !phys_enc->parent) { + DPU_ERROR("invalid arg(s), encoder %d\n", phys_enc != 0); + return; + } + + dpu_enc = to_dpu_encoder_virt(phys_enc->parent); + hw_mdptop = phys_enc->hw_mdptop; + disp_info = &dpu_enc->disp_info; + + if (disp_info->intf_type != DRM_MODE_CONNECTOR_DSI) + return; + + /** + * disable split modes since encoder will be operating in as the only + * encoder, either for the entire use case in the case of, for example, + * single DSI, or for this frame in the case of left/right only partial + * update. + */ + if (phys_enc->split_role == ENC_ROLE_SOLO) { + if (hw_mdptop->ops.setup_split_pipe) + hw_mdptop->ops.setup_split_pipe(hw_mdptop, &cfg); + return; + } + + cfg.en = true; + cfg.mode = phys_enc->intf_mode; + cfg.intf = interface; + + if (cfg.en && phys_enc->ops.needs_single_flush && + phys_enc->ops.needs_single_flush(phys_enc)) + cfg.split_flush_en = true; + + if (phys_enc->split_role == ENC_ROLE_MASTER) { + DPU_DEBUG_ENC(dpu_enc, "enable %d\n", cfg.en); + + if (hw_mdptop->ops.setup_split_pipe) + hw_mdptop->ops.setup_split_pipe(hw_mdptop, &cfg); + } +} + +static void _dpu_encoder_adjust_mode(struct drm_connector *connector, + struct drm_display_mode *adj_mode) +{ + struct drm_display_mode *cur_mode; + + if (!connector || !adj_mode) + return; + + list_for_each_entry(cur_mode, &connector->modes, head) { + if (cur_mode->vdisplay == adj_mode->vdisplay && + cur_mode->hdisplay == adj_mode->hdisplay && + cur_mode->vrefresh == adj_mode->vrefresh) { + adj_mode->private = cur_mode->private; + adj_mode->private_flags |= cur_mode->private_flags; + } + } +} + +static struct msm_display_topology dpu_encoder_get_topology( + struct dpu_encoder_virt *dpu_enc, + struct dpu_kms *dpu_kms, + struct drm_display_mode *mode) +{ + struct msm_display_topology topology; + int i, intf_count = 0; + + for (i = 0; i < MAX_PHYS_ENCODERS_PER_VIRTUAL; i++) + if (dpu_enc->phys_encs[i]) + intf_count++; + + /* User split topology for width > 1080 */ + topology.num_lm = (mode->vdisplay > MAX_VDISPLAY_SPLIT) ? 2 : 1; + topology.num_enc = 0; + topology.num_intf = intf_count; + + return topology; +} +static int dpu_encoder_virt_atomic_check( + struct drm_encoder *drm_enc, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct dpu_encoder_virt *dpu_enc; + struct msm_drm_private *priv; + struct dpu_kms *dpu_kms; + const struct drm_display_mode *mode; + struct drm_display_mode *adj_mode; + struct msm_display_topology topology; + int i = 0; + int ret = 0; + + if (!drm_enc || !crtc_state || !conn_state) { + DPU_ERROR("invalid arg(s), drm_enc %d, crtc/conn state %d/%d\n", + drm_enc != 0, crtc_state != 0, conn_state != 0); + return -EINVAL; + } + + dpu_enc = to_dpu_encoder_virt(drm_enc); + DPU_DEBUG_ENC(dpu_enc, "\n"); + + priv = drm_enc->dev->dev_private; + dpu_kms = to_dpu_kms(priv->kms); + mode = &crtc_state->mode; + adj_mode = &crtc_state->adjusted_mode; + trace_dpu_enc_atomic_check(DRMID(drm_enc)); + + /* + * display drivers may populate private fields of the drm display mode + * structure while registering possible modes of a connector with DRM. + * These private fields are not populated back while DRM invokes + * the mode_set callbacks. This module retrieves and populates the + * private fields of the given mode. + */ + _dpu_encoder_adjust_mode(conn_state->connector, adj_mode); + + /* perform atomic check on the first physical encoder (master) */ + for (i = 0; i < dpu_enc->num_phys_encs; i++) { + struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; + + if (phys && phys->ops.atomic_check) + ret = phys->ops.atomic_check(phys, crtc_state, + conn_state); + else if (phys && phys->ops.mode_fixup) + if (!phys->ops.mode_fixup(phys, mode, adj_mode)) + ret = -EINVAL; + + if (ret) { + DPU_ERROR_ENC(dpu_enc, + "mode unsupported, phys idx %d\n", i); + break; + } + } + + topology = dpu_encoder_get_topology(dpu_enc, dpu_kms, adj_mode); + + /* Reserve dynamic resources now. Indicating AtomicTest phase */ + if (!ret) { + /* + * Avoid reserving resources when mode set is pending. Topology + * info may not be available to complete reservation. + */ + if (drm_atomic_crtc_needs_modeset(crtc_state) + && dpu_enc->mode_set_complete) { + ret = dpu_rm_reserve(&dpu_kms->rm, drm_enc, crtc_state, + conn_state, topology, true); + dpu_enc->mode_set_complete = false; + } + } + + if (!ret) + drm_mode_set_crtcinfo(adj_mode, 0); + + trace_dpu_enc_atomic_check_flags(DRMID(drm_enc), adj_mode->flags, + adj_mode->private_flags); + + return ret; +} + +static void _dpu_encoder_update_vsync_source(struct dpu_encoder_virt *dpu_enc, + struct msm_display_info *disp_info) +{ + struct dpu_vsync_source_cfg vsync_cfg = { 0 }; + struct msm_drm_private *priv; + struct dpu_kms *dpu_kms; + struct dpu_hw_mdp *hw_mdptop; + struct drm_encoder *drm_enc; + int i; + + if (!dpu_enc || !disp_info) { + DPU_ERROR("invalid param dpu_enc:%d or disp_info:%d\n", + dpu_enc != NULL, disp_info != NULL); + return; + } else if (dpu_enc->num_phys_encs > ARRAY_SIZE(dpu_enc->hw_pp)) { + DPU_ERROR("invalid num phys enc %d/%d\n", + dpu_enc->num_phys_encs, + (int) ARRAY_SIZE(dpu_enc->hw_pp)); + return; + } + + drm_enc = &dpu_enc->base; + /* this pointers are checked in virt_enable_helper */ + priv = drm_enc->dev->dev_private; + + dpu_kms = to_dpu_kms(priv->kms); + if (!dpu_kms) { + DPU_ERROR("invalid dpu_kms\n"); + return; + } + + hw_mdptop = dpu_kms->hw_mdp; + if (!hw_mdptop) { + DPU_ERROR("invalid mdptop\n"); + return; + } + + if (hw_mdptop->ops.setup_vsync_source && + disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) { + for (i = 0; i < dpu_enc->num_phys_encs; i++) + vsync_cfg.ppnumber[i] = dpu_enc->hw_pp[i]->idx; + + vsync_cfg.pp_count = dpu_enc->num_phys_encs; + if (disp_info->is_te_using_watchdog_timer) + vsync_cfg.vsync_source = DPU_VSYNC_SOURCE_WD_TIMER_0; + else + vsync_cfg.vsync_source = DPU_VSYNC0_SOURCE_GPIO; + + hw_mdptop->ops.setup_vsync_source(hw_mdptop, &vsync_cfg); + } +} + +static void _dpu_encoder_irq_control(struct drm_encoder *drm_enc, bool enable) +{ + struct dpu_encoder_virt *dpu_enc; + int i; + + if (!drm_enc) { + DPU_ERROR("invalid encoder\n"); + return; + } + + dpu_enc = to_dpu_encoder_virt(drm_enc); + + DPU_DEBUG_ENC(dpu_enc, "enable:%d\n", enable); + for (i = 0; i < dpu_enc->num_phys_encs; i++) { + struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; + + if (phys && phys->ops.irq_control) + phys->ops.irq_control(phys, enable); + } + +} + +static void _dpu_encoder_resource_control_helper(struct drm_encoder *drm_enc, + bool enable) +{ + struct msm_drm_private *priv; + struct dpu_kms *dpu_kms; + struct dpu_encoder_virt *dpu_enc; + + dpu_enc = to_dpu_encoder_virt(drm_enc); + priv = drm_enc->dev->dev_private; + dpu_kms = to_dpu_kms(priv->kms); + + trace_dpu_enc_rc_helper(DRMID(drm_enc), enable); + + if (!dpu_enc->cur_master) { + DPU_ERROR("encoder master not set\n"); + return; + } + + if (enable) { + /* enable DPU core clks */ + pm_runtime_get_sync(&dpu_kms->pdev->dev); + + /* enable all the irq */ + _dpu_encoder_irq_control(drm_enc, true); + + } else { + /* disable all the irq */ + _dpu_encoder_irq_control(drm_enc, false); + + /* disable DPU core clks */ + pm_runtime_put_sync(&dpu_kms->pdev->dev); + } + +} + +static int dpu_encoder_resource_control(struct drm_encoder *drm_enc, + u32 sw_event) +{ + struct dpu_encoder_virt *dpu_enc; + struct msm_drm_private *priv; + struct msm_drm_thread *disp_thread; + bool is_vid_mode = false; + + if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private || + !drm_enc->crtc) { + DPU_ERROR("invalid parameters\n"); + return -EINVAL; + } + dpu_enc = to_dpu_encoder_virt(drm_enc); + priv = drm_enc->dev->dev_private; + is_vid_mode = dpu_enc->disp_info.capabilities & + MSM_DISPLAY_CAP_VID_MODE; + + if (drm_enc->crtc->index >= ARRAY_SIZE(priv->disp_thread)) { + DPU_ERROR("invalid crtc index\n"); + return -EINVAL; + } + disp_thread = &priv->disp_thread[drm_enc->crtc->index]; + + /* + * when idle_pc is not supported, process only KICKOFF, STOP and MODESET + * events and return early for other events (ie wb display). + */ + if (!dpu_enc->idle_pc_supported && + (sw_event != DPU_ENC_RC_EVENT_KICKOFF && + sw_event != DPU_ENC_RC_EVENT_STOP && + sw_event != DPU_ENC_RC_EVENT_PRE_STOP)) + return 0; + + trace_dpu_enc_rc(DRMID(drm_enc), sw_event, dpu_enc->idle_pc_supported, + dpu_enc->rc_state, "begin"); + + switch (sw_event) { + case DPU_ENC_RC_EVENT_KICKOFF: + /* cancel delayed off work, if any */ + if (kthread_cancel_delayed_work_sync( + &dpu_enc->delayed_off_work)) + DPU_DEBUG_ENC(dpu_enc, "sw_event:%d, work cancelled\n", + sw_event); + + mutex_lock(&dpu_enc->rc_lock); + + /* return if the resource control is already in ON state */ + if (dpu_enc->rc_state == DPU_ENC_RC_STATE_ON) { + DRM_DEBUG_KMS("id;%u, sw_event:%d, rc in ON state\n", + DRMID(drm_enc), sw_event); + mutex_unlock(&dpu_enc->rc_lock); + return 0; + } else if (dpu_enc->rc_state != DPU_ENC_RC_STATE_OFF && + dpu_enc->rc_state != DPU_ENC_RC_STATE_IDLE) { + DRM_DEBUG_KMS("id;%u, sw_event:%d, rc in state %d\n", + DRMID(drm_enc), sw_event, + dpu_enc->rc_state); + mutex_unlock(&dpu_enc->rc_lock); + return -EINVAL; + } + + if (is_vid_mode && dpu_enc->rc_state == DPU_ENC_RC_STATE_IDLE) + _dpu_encoder_irq_control(drm_enc, true); + else + _dpu_encoder_resource_control_helper(drm_enc, true); + + dpu_enc->rc_state = DPU_ENC_RC_STATE_ON; + + trace_dpu_enc_rc(DRMID(drm_enc), sw_event, + dpu_enc->idle_pc_supported, dpu_enc->rc_state, + "kickoff"); + + mutex_unlock(&dpu_enc->rc_lock); + break; + + case DPU_ENC_RC_EVENT_FRAME_DONE: + /* + * mutex lock is not used as this event happens at interrupt + * context. And locking is not required as, the other events + * like KICKOFF and STOP does a wait-for-idle before executing + * the resource_control + */ + if (dpu_enc->rc_state != DPU_ENC_RC_STATE_ON) { + DRM_DEBUG_KMS("id:%d, sw_event:%d,rc:%d-unexpected\n", + DRMID(drm_enc), sw_event, + dpu_enc->rc_state); + return -EINVAL; + } + + /* + * schedule off work item only when there are no + * frames pending + */ + if (dpu_crtc_frame_pending(drm_enc->crtc) > 1) { + DRM_DEBUG_KMS("id:%d skip schedule work\n", + DRMID(drm_enc)); + return 0; + } + + kthread_queue_delayed_work( + &disp_thread->worker, + &dpu_enc->delayed_off_work, + msecs_to_jiffies(dpu_enc->idle_timeout)); + + trace_dpu_enc_rc(DRMID(drm_enc), sw_event, + dpu_enc->idle_pc_supported, dpu_enc->rc_state, + "frame done"); + break; + + case DPU_ENC_RC_EVENT_PRE_STOP: + /* cancel delayed off work, if any */ + if (kthread_cancel_delayed_work_sync( + &dpu_enc->delayed_off_work)) + DPU_DEBUG_ENC(dpu_enc, "sw_event:%d, work cancelled\n", + sw_event); + + mutex_lock(&dpu_enc->rc_lock); + + if (is_vid_mode && + dpu_enc->rc_state == DPU_ENC_RC_STATE_IDLE) { + _dpu_encoder_irq_control(drm_enc, true); + } + /* skip if is already OFF or IDLE, resources are off already */ + else if (dpu_enc->rc_state == DPU_ENC_RC_STATE_OFF || + dpu_enc->rc_state == DPU_ENC_RC_STATE_IDLE) { + DRM_DEBUG_KMS("id:%u, sw_event:%d, rc in %d state\n", + DRMID(drm_enc), sw_event, + dpu_enc->rc_state); + mutex_unlock(&dpu_enc->rc_lock); + return 0; + } + + dpu_enc->rc_state = DPU_ENC_RC_STATE_PRE_OFF; + + trace_dpu_enc_rc(DRMID(drm_enc), sw_event, + dpu_enc->idle_pc_supported, dpu_enc->rc_state, + "pre stop"); + + mutex_unlock(&dpu_enc->rc_lock); + break; + + case DPU_ENC_RC_EVENT_STOP: + mutex_lock(&dpu_enc->rc_lock); + + /* return if the resource control is already in OFF state */ + if (dpu_enc->rc_state == DPU_ENC_RC_STATE_OFF) { + DRM_DEBUG_KMS("id: %u, sw_event:%d, rc in OFF state\n", + DRMID(drm_enc), sw_event); + mutex_unlock(&dpu_enc->rc_lock); + return 0; + } else if (dpu_enc->rc_state == DPU_ENC_RC_STATE_ON) { + DRM_ERROR("id: %u, sw_event:%d, rc in state %d\n", + DRMID(drm_enc), sw_event, dpu_enc->rc_state); + mutex_unlock(&dpu_enc->rc_lock); + return -EINVAL; + } + + /** + * expect to arrive here only if in either idle state or pre-off + * and in IDLE state the resources are already disabled + */ + if (dpu_enc->rc_state == DPU_ENC_RC_STATE_PRE_OFF) + _dpu_encoder_resource_control_helper(drm_enc, false); + + dpu_enc->rc_state = DPU_ENC_RC_STATE_OFF; + + trace_dpu_enc_rc(DRMID(drm_enc), sw_event, + dpu_enc->idle_pc_supported, dpu_enc->rc_state, + "stop"); + + mutex_unlock(&dpu_enc->rc_lock); + break; + + case DPU_ENC_RC_EVENT_ENTER_IDLE: + mutex_lock(&dpu_enc->rc_lock); + + if (dpu_enc->rc_state != DPU_ENC_RC_STATE_ON) { + DRM_ERROR("id: %u, sw_event:%d, rc:%d !ON state\n", + DRMID(drm_enc), sw_event, dpu_enc->rc_state); + mutex_unlock(&dpu_enc->rc_lock); + return 0; + } + + /* + * if we are in ON but a frame was just kicked off, + * ignore the IDLE event, it's probably a stale timer event + */ + if (dpu_enc->frame_busy_mask[0]) { + DRM_ERROR("id:%u, sw_event:%d, rc:%d frame pending\n", + DRMID(drm_enc), sw_event, dpu_enc->rc_state); + mutex_unlock(&dpu_enc->rc_lock); + return 0; + } + + if (is_vid_mode) + _dpu_encoder_irq_control(drm_enc, false); + else + _dpu_encoder_resource_control_helper(drm_enc, false); + + dpu_enc->rc_state = DPU_ENC_RC_STATE_IDLE; + + trace_dpu_enc_rc(DRMID(drm_enc), sw_event, + dpu_enc->idle_pc_supported, dpu_enc->rc_state, + "idle"); + + mutex_unlock(&dpu_enc->rc_lock); + break; + + default: + DRM_ERROR("id:%u, unexpected sw_event: %d\n", DRMID(drm_enc), + sw_event); + trace_dpu_enc_rc(DRMID(drm_enc), sw_event, + dpu_enc->idle_pc_supported, dpu_enc->rc_state, + "error"); + break; + } + + trace_dpu_enc_rc(DRMID(drm_enc), sw_event, + dpu_enc->idle_pc_supported, dpu_enc->rc_state, + "end"); + return 0; +} + +static void dpu_encoder_virt_mode_set(struct drm_encoder *drm_enc, + struct drm_display_mode *mode, + struct drm_display_mode *adj_mode) +{ + struct dpu_encoder_virt *dpu_enc; + struct msm_drm_private *priv; + struct dpu_kms *dpu_kms; + struct list_head *connector_list; + struct drm_connector *conn = NULL, *conn_iter; + struct dpu_rm_hw_iter pp_iter; + struct msm_display_topology topology; + enum dpu_rm_topology_name topology_name; + int i = 0, ret; + + if (!drm_enc) { + DPU_ERROR("invalid encoder\n"); + return; + } + + dpu_enc = to_dpu_encoder_virt(drm_enc); + DPU_DEBUG_ENC(dpu_enc, "\n"); + + priv = drm_enc->dev->dev_private; + dpu_kms = to_dpu_kms(priv->kms); + connector_list = &dpu_kms->dev->mode_config.connector_list; + + trace_dpu_enc_mode_set(DRMID(drm_enc)); + + list_for_each_entry(conn_iter, connector_list, head) + if (conn_iter->encoder == drm_enc) + conn = conn_iter; + + if (!conn) { + DPU_ERROR_ENC(dpu_enc, "failed to find attached connector\n"); + return; + } else if (!conn->state) { + DPU_ERROR_ENC(dpu_enc, "invalid connector state\n"); + return; + } + + topology = dpu_encoder_get_topology(dpu_enc, dpu_kms, adj_mode); + + /* Reserve dynamic resources now. Indicating non-AtomicTest phase */ + ret = dpu_rm_reserve(&dpu_kms->rm, drm_enc, drm_enc->crtc->state, + conn->state, topology, false); + if (ret) { + DPU_ERROR_ENC(dpu_enc, + "failed to reserve hw resources, %d\n", ret); + return; + } + + dpu_rm_init_hw_iter(&pp_iter, drm_enc->base.id, DPU_HW_BLK_PINGPONG); + for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) { + dpu_enc->hw_pp[i] = NULL; + if (!dpu_rm_get_hw(&dpu_kms->rm, &pp_iter)) + break; + dpu_enc->hw_pp[i] = (struct dpu_hw_pingpong *) pp_iter.hw; + } + + topology_name = dpu_rm_get_topology_name(topology); + for (i = 0; i < dpu_enc->num_phys_encs; i++) { + struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; + + if (phys) { + if (!dpu_enc->hw_pp[i]) { + DPU_ERROR_ENC(dpu_enc, + "invalid pingpong block for the encoder\n"); + return; + } + phys->hw_pp = dpu_enc->hw_pp[i]; + phys->connector = conn->state->connector; + phys->topology_name = topology_name; + if (phys->ops.mode_set) + phys->ops.mode_set(phys, mode, adj_mode); + } + } + + dpu_enc->mode_set_complete = true; +} + +static void _dpu_encoder_virt_enable_helper(struct drm_encoder *drm_enc) +{ + struct dpu_encoder_virt *dpu_enc = NULL; + struct msm_drm_private *priv; + struct dpu_kms *dpu_kms; + + if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private) { + DPU_ERROR("invalid parameters\n"); + return; + } + + priv = drm_enc->dev->dev_private; + dpu_kms = to_dpu_kms(priv->kms); + if (!dpu_kms) { + DPU_ERROR("invalid dpu_kms\n"); + return; + } + + dpu_enc = to_dpu_encoder_virt(drm_enc); + if (!dpu_enc || !dpu_enc->cur_master) { + DPU_ERROR("invalid dpu encoder/master\n"); + return; + } + + if (dpu_enc->disp_info.intf_type == DRM_MODE_CONNECTOR_DisplayPort && + dpu_enc->cur_master->hw_mdptop && + dpu_enc->cur_master->hw_mdptop->ops.intf_audio_select) + dpu_enc->cur_master->hw_mdptop->ops.intf_audio_select( + dpu_enc->cur_master->hw_mdptop); + + if (dpu_enc->cur_master->hw_mdptop && + dpu_enc->cur_master->hw_mdptop->ops.reset_ubwc) + dpu_enc->cur_master->hw_mdptop->ops.reset_ubwc( + dpu_enc->cur_master->hw_mdptop, + dpu_kms->catalog); + + _dpu_encoder_update_vsync_source(dpu_enc, &dpu_enc->disp_info); +} + +void dpu_encoder_virt_restore(struct drm_encoder *drm_enc) +{ + struct dpu_encoder_virt *dpu_enc = NULL; + int i; + + if (!drm_enc) { + DPU_ERROR("invalid encoder\n"); + return; + } + dpu_enc = to_dpu_encoder_virt(drm_enc); + + for (i = 0; i < dpu_enc->num_phys_encs; i++) { + struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; + + if (phys && (phys != dpu_enc->cur_master) && phys->ops.restore) + phys->ops.restore(phys); + } + + if (dpu_enc->cur_master && dpu_enc->cur_master->ops.restore) + dpu_enc->cur_master->ops.restore(dpu_enc->cur_master); + + _dpu_encoder_virt_enable_helper(drm_enc); +} + +static void dpu_encoder_virt_enable(struct drm_encoder *drm_enc) +{ + struct dpu_encoder_virt *dpu_enc = NULL; + int i, ret = 0; + struct drm_display_mode *cur_mode = NULL; + + if (!drm_enc) { + DPU_ERROR("invalid encoder\n"); + return; + } + dpu_enc = to_dpu_encoder_virt(drm_enc); + cur_mode = &dpu_enc->base.crtc->state->adjusted_mode; + + trace_dpu_enc_enable(DRMID(drm_enc), cur_mode->hdisplay, + cur_mode->vdisplay); + + dpu_enc->cur_master = NULL; + for (i = 0; i < dpu_enc->num_phys_encs; i++) { + struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; + + if (phys && phys->ops.is_master && phys->ops.is_master(phys)) { + DPU_DEBUG_ENC(dpu_enc, "master is now idx %d\n", i); + dpu_enc->cur_master = phys; + break; + } + } + + if (!dpu_enc->cur_master) { + DPU_ERROR("virt encoder has no master! num_phys %d\n", i); + return; + } + + ret = dpu_encoder_resource_control(drm_enc, DPU_ENC_RC_EVENT_KICKOFF); + if (ret) { + DPU_ERROR_ENC(dpu_enc, "dpu resource control failed: %d\n", + ret); + return; + } + + for (i = 0; i < dpu_enc->num_phys_encs; i++) { + struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; + + if (!phys) + continue; + + if (phys != dpu_enc->cur_master) { + if (phys->ops.enable) + phys->ops.enable(phys); + } + + if (dpu_enc->misr_enable && (dpu_enc->disp_info.capabilities & + MSM_DISPLAY_CAP_VID_MODE) && phys->ops.setup_misr) + phys->ops.setup_misr(phys, true, + dpu_enc->misr_frame_count); + } + + if (dpu_enc->cur_master->ops.enable) + dpu_enc->cur_master->ops.enable(dpu_enc->cur_master); + + _dpu_encoder_virt_enable_helper(drm_enc); +} + +static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc) +{ + struct dpu_encoder_virt *dpu_enc = NULL; + struct msm_drm_private *priv; + struct dpu_kms *dpu_kms; + struct drm_display_mode *mode; + int i = 0; + + if (!drm_enc) { + DPU_ERROR("invalid encoder\n"); + return; + } else if (!drm_enc->dev) { + DPU_ERROR("invalid dev\n"); + return; + } else if (!drm_enc->dev->dev_private) { + DPU_ERROR("invalid dev_private\n"); + return; + } + + mode = &drm_enc->crtc->state->adjusted_mode; + + dpu_enc = to_dpu_encoder_virt(drm_enc); + DPU_DEBUG_ENC(dpu_enc, "\n"); + + priv = drm_enc->dev->dev_private; + dpu_kms = to_dpu_kms(priv->kms); + + trace_dpu_enc_disable(DRMID(drm_enc)); + + /* wait for idle */ + dpu_encoder_wait_for_event(drm_enc, MSM_ENC_TX_COMPLETE); + + dpu_encoder_resource_control(drm_enc, DPU_ENC_RC_EVENT_PRE_STOP); + + for (i = 0; i < dpu_enc->num_phys_encs; i++) { + struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; + + if (phys && phys->ops.disable) + phys->ops.disable(phys); + } + + /* after phys waits for frame-done, should be no more frames pending */ + if (atomic_xchg(&dpu_enc->frame_done_timeout, 0)) { + DPU_ERROR("enc%d timeout pending\n", drm_enc->base.id); + del_timer_sync(&dpu_enc->frame_done_timer); + } + + dpu_encoder_resource_control(drm_enc, DPU_ENC_RC_EVENT_STOP); + + for (i = 0; i < dpu_enc->num_phys_encs; i++) { + if (dpu_enc->phys_encs[i]) + dpu_enc->phys_encs[i]->connector = NULL; + } + + dpu_enc->cur_master = NULL; + + DPU_DEBUG_ENC(dpu_enc, "encoder disabled\n"); + + dpu_rm_release(&dpu_kms->rm, drm_enc); +} + +static enum dpu_intf dpu_encoder_get_intf(struct dpu_mdss_cfg *catalog, + enum dpu_intf_type type, u32 controller_id) +{ + int i = 0; + + for (i = 0; i < catalog->intf_count; i++) { + if (catalog->intf[i].type == type + && catalog->intf[i].controller_id == controller_id) { + return catalog->intf[i].id; + } + } + + return INTF_MAX; +} + +static void dpu_encoder_vblank_callback(struct drm_encoder *drm_enc, + struct dpu_encoder_phys *phy_enc) +{ + struct dpu_encoder_virt *dpu_enc = NULL; + unsigned long lock_flags; + + if (!drm_enc || !phy_enc) + return; + + DPU_ATRACE_BEGIN("encoder_vblank_callback"); + dpu_enc = to_dpu_encoder_virt(drm_enc); + + spin_lock_irqsave(&dpu_enc->enc_spinlock, lock_flags); + if (dpu_enc->crtc_vblank_cb) + dpu_enc->crtc_vblank_cb(dpu_enc->crtc_vblank_cb_data); + spin_unlock_irqrestore(&dpu_enc->enc_spinlock, lock_flags); + + atomic_inc(&phy_enc->vsync_cnt); + DPU_ATRACE_END("encoder_vblank_callback"); +} + +static void dpu_encoder_underrun_callback(struct drm_encoder *drm_enc, + struct dpu_encoder_phys *phy_enc) +{ + if (!phy_enc) + return; + + DPU_ATRACE_BEGIN("encoder_underrun_callback"); + atomic_inc(&phy_enc->underrun_cnt); + trace_dpu_enc_underrun_cb(DRMID(drm_enc), + atomic_read(&phy_enc->underrun_cnt)); + DPU_ATRACE_END("encoder_underrun_callback"); +} + +void dpu_encoder_register_vblank_callback(struct drm_encoder *drm_enc, + void (*vbl_cb)(void *), void *vbl_data) +{ + struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc); + unsigned long lock_flags; + bool enable; + int i; + + enable = vbl_cb ? true : false; + + if (!drm_enc) { + DPU_ERROR("invalid encoder\n"); + return; + } + trace_dpu_enc_vblank_cb(DRMID(drm_enc), enable); + + spin_lock_irqsave(&dpu_enc->enc_spinlock, lock_flags); + dpu_enc->crtc_vblank_cb = vbl_cb; + dpu_enc->crtc_vblank_cb_data = vbl_data; + spin_unlock_irqrestore(&dpu_enc->enc_spinlock, lock_flags); + + for (i = 0; i < dpu_enc->num_phys_encs; i++) { + struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; + + if (phys && phys->ops.control_vblank_irq) + phys->ops.control_vblank_irq(phys, enable); + } +} + +void dpu_encoder_register_frame_event_callback(struct drm_encoder *drm_enc, + void (*frame_event_cb)(void *, u32 event), + void *frame_event_cb_data) +{ + struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc); + unsigned long lock_flags; + bool enable; + + enable = frame_event_cb ? true : false; + + if (!drm_enc) { + DPU_ERROR("invalid encoder\n"); + return; + } + trace_dpu_enc_frame_event_cb(DRMID(drm_enc), enable); + + spin_lock_irqsave(&dpu_enc->enc_spinlock, lock_flags); + dpu_enc->crtc_frame_event_cb = frame_event_cb; + dpu_enc->crtc_frame_event_cb_data = frame_event_cb_data; + spin_unlock_irqrestore(&dpu_enc->enc_spinlock, lock_flags); +} + +static void dpu_encoder_frame_done_callback( + struct drm_encoder *drm_enc, + struct dpu_encoder_phys *ready_phys, u32 event) +{ + struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc); + unsigned int i; + + if (event & (DPU_ENCODER_FRAME_EVENT_DONE + | DPU_ENCODER_FRAME_EVENT_ERROR + | DPU_ENCODER_FRAME_EVENT_PANEL_DEAD)) { + + if (!dpu_enc->frame_busy_mask[0]) { + /** + * suppress frame_done without waiter, + * likely autorefresh + */ + trace_dpu_enc_frame_done_cb_not_busy(DRMID(drm_enc), + event, ready_phys->intf_idx); + return; + } + + /* One of the physical encoders has become idle */ + for (i = 0; i < dpu_enc->num_phys_encs; i++) { + if (dpu_enc->phys_encs[i] == ready_phys) { + clear_bit(i, dpu_enc->frame_busy_mask); + trace_dpu_enc_frame_done_cb(DRMID(drm_enc), i, + dpu_enc->frame_busy_mask[0]); + } + } + + if (!dpu_enc->frame_busy_mask[0]) { + atomic_set(&dpu_enc->frame_done_timeout, 0); + del_timer(&dpu_enc->frame_done_timer); + + dpu_encoder_resource_control(drm_enc, + DPU_ENC_RC_EVENT_FRAME_DONE); + + if (dpu_enc->crtc_frame_event_cb) + dpu_enc->crtc_frame_event_cb( + dpu_enc->crtc_frame_event_cb_data, + event); + } + } else { + if (dpu_enc->crtc_frame_event_cb) + dpu_enc->crtc_frame_event_cb( + dpu_enc->crtc_frame_event_cb_data, event); + } +} + +static void dpu_encoder_off_work(struct kthread_work *work) +{ + struct dpu_encoder_virt *dpu_enc = container_of(work, + struct dpu_encoder_virt, delayed_off_work.work); + + if (!dpu_enc) { + DPU_ERROR("invalid dpu encoder\n"); + return; + } + + dpu_encoder_resource_control(&dpu_enc->base, + DPU_ENC_RC_EVENT_ENTER_IDLE); + + dpu_encoder_frame_done_callback(&dpu_enc->base, NULL, + DPU_ENCODER_FRAME_EVENT_IDLE); +} + +/** + * _dpu_encoder_trigger_flush - trigger flush for a physical encoder + * drm_enc: Pointer to drm encoder structure + * phys: Pointer to physical encoder structure + * extra_flush_bits: Additional bit mask to include in flush trigger + */ +static inline void _dpu_encoder_trigger_flush(struct drm_encoder *drm_enc, + struct dpu_encoder_phys *phys, uint32_t extra_flush_bits) +{ + struct dpu_hw_ctl *ctl; + int pending_kickoff_cnt; + u32 ret = UINT_MAX; + + if (!drm_enc || !phys) { + DPU_ERROR("invalid argument(s), drm_enc %d, phys_enc %d\n", + drm_enc != 0, phys != 0); + return; + } + + if (!phys->hw_pp) { + DPU_ERROR("invalid pingpong hw\n"); + return; + } + + ctl = phys->hw_ctl; + if (!ctl || !ctl->ops.trigger_flush) { + DPU_ERROR("missing trigger cb\n"); + return; + } + + pending_kickoff_cnt = dpu_encoder_phys_inc_pending(phys); + + if (extra_flush_bits && ctl->ops.update_pending_flush) + ctl->ops.update_pending_flush(ctl, extra_flush_bits); + + ctl->ops.trigger_flush(ctl); + + if (ctl->ops.get_pending_flush) + ret = ctl->ops.get_pending_flush(ctl); + + trace_dpu_enc_trigger_flush(DRMID(drm_enc), phys->intf_idx, + pending_kickoff_cnt, ctl->idx, ret); +} + +/** + * _dpu_encoder_trigger_start - trigger start for a physical encoder + * phys: Pointer to physical encoder structure + */ +static inline void _dpu_encoder_trigger_start(struct dpu_encoder_phys *phys) +{ + if (!phys) { + DPU_ERROR("invalid argument(s)\n"); + return; + } + + if (!phys->hw_pp) { + DPU_ERROR("invalid pingpong hw\n"); + return; + } + + if (phys->ops.trigger_start && phys->enable_state != DPU_ENC_DISABLED) + phys->ops.trigger_start(phys); +} + +void dpu_encoder_helper_trigger_start(struct dpu_encoder_phys *phys_enc) +{ + struct dpu_hw_ctl *ctl; + + if (!phys_enc) { + DPU_ERROR("invalid encoder\n"); + return; + } + + ctl = phys_enc->hw_ctl; + if (ctl && ctl->ops.trigger_start) { + ctl->ops.trigger_start(ctl); + trace_dpu_enc_trigger_start(DRMID(phys_enc->parent), ctl->idx); + } +} + +int dpu_encoder_helper_wait_event_timeout( + int32_t drm_id, + int32_t hw_id, + struct dpu_encoder_wait_info *info) +{ + int rc = 0; + s64 expected_time = ktime_to_ms(ktime_get()) + info->timeout_ms; + s64 jiffies = msecs_to_jiffies(info->timeout_ms); + s64 time; + + do { + rc = wait_event_timeout(*(info->wq), + atomic_read(info->atomic_cnt) == 0, jiffies); + time = ktime_to_ms(ktime_get()); + + trace_dpu_enc_wait_event_timeout(drm_id, hw_id, rc, time, + expected_time, + atomic_read(info->atomic_cnt)); + /* If we timed out, counter is valid and time is less, wait again */ + } while (atomic_read(info->atomic_cnt) && (rc == 0) && + (time < expected_time)); + + return rc; +} + +void dpu_encoder_helper_hw_reset(struct dpu_encoder_phys *phys_enc) +{ + struct dpu_encoder_virt *dpu_enc; + struct dpu_hw_ctl *ctl; + int rc; + + if (!phys_enc) { + DPU_ERROR("invalid encoder\n"); + return; + } + dpu_enc = to_dpu_encoder_virt(phys_enc->parent); + ctl = phys_enc->hw_ctl; + + if (!ctl || !ctl->ops.reset) + return; + + DRM_DEBUG_KMS("id:%u ctl %d reset\n", DRMID(phys_enc->parent), + ctl->idx); + + rc = ctl->ops.reset(ctl); + if (rc) { + DPU_ERROR_ENC(dpu_enc, "ctl %d reset failure\n", ctl->idx); + dpu_dbg_dump(false, __func__, true, true); + } + + phys_enc->enable_state = DPU_ENC_ENABLED; +} + +/** + * _dpu_encoder_kickoff_phys - handle physical encoder kickoff + * Iterate through the physical encoders and perform consolidated flush + * and/or control start triggering as needed. This is done in the virtual + * encoder rather than the individual physical ones in order to handle + * use cases that require visibility into multiple physical encoders at + * a time. + * dpu_enc: Pointer to virtual encoder structure + */ +static void _dpu_encoder_kickoff_phys(struct dpu_encoder_virt *dpu_enc) +{ + struct dpu_hw_ctl *ctl; + uint32_t i, pending_flush; + unsigned long lock_flags; + + if (!dpu_enc) { + DPU_ERROR("invalid encoder\n"); + return; + } + + pending_flush = 0x0; + + /* update pending counts and trigger kickoff ctl flush atomically */ + spin_lock_irqsave(&dpu_enc->enc_spinlock, lock_flags); + + /* don't perform flush/start operations for slave encoders */ + for (i = 0; i < dpu_enc->num_phys_encs; i++) { + struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; + + if (!phys || phys->enable_state == DPU_ENC_DISABLED) + continue; + + ctl = phys->hw_ctl; + if (!ctl) + continue; + + if (phys->split_role != ENC_ROLE_SLAVE) + set_bit(i, dpu_enc->frame_busy_mask); + if (!phys->ops.needs_single_flush || + !phys->ops.needs_single_flush(phys)) + _dpu_encoder_trigger_flush(&dpu_enc->base, phys, 0x0); + else if (ctl->ops.get_pending_flush) + pending_flush |= ctl->ops.get_pending_flush(ctl); + } + + /* for split flush, combine pending flush masks and send to master */ + if (pending_flush && dpu_enc->cur_master) { + _dpu_encoder_trigger_flush( + &dpu_enc->base, + dpu_enc->cur_master, + pending_flush); + } + + _dpu_encoder_trigger_start(dpu_enc->cur_master); + + spin_unlock_irqrestore(&dpu_enc->enc_spinlock, lock_flags); +} + +bool dpu_encoder_check_mode(struct drm_encoder *drm_enc, u32 mode) +{ + struct dpu_encoder_virt *dpu_enc; + struct msm_display_info *disp_info; + + if (!drm_enc) { + DPU_ERROR("invalid encoder\n"); + return false; + } + + dpu_enc = to_dpu_encoder_virt(drm_enc); + disp_info = &dpu_enc->disp_info; + + return (disp_info->capabilities & mode); +} + +void dpu_encoder_trigger_kickoff_pending(struct drm_encoder *drm_enc) +{ + struct dpu_encoder_virt *dpu_enc; + struct dpu_encoder_phys *phys; + unsigned int i; + struct dpu_hw_ctl *ctl; + struct msm_display_info *disp_info; + + if (!drm_enc) { + DPU_ERROR("invalid encoder\n"); + return; + } + dpu_enc = to_dpu_encoder_virt(drm_enc); + disp_info = &dpu_enc->disp_info; + + for (i = 0; i < dpu_enc->num_phys_encs; i++) { + phys = dpu_enc->phys_encs[i]; + + if (phys && phys->hw_ctl) { + ctl = phys->hw_ctl; + if (ctl->ops.clear_pending_flush) + ctl->ops.clear_pending_flush(ctl); + + /* update only for command mode primary ctl */ + if ((phys == dpu_enc->cur_master) && + (disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) + && ctl->ops.trigger_pending) + ctl->ops.trigger_pending(ctl); + } + } +} + +static u32 _dpu_encoder_calculate_linetime(struct dpu_encoder_virt *dpu_enc, + struct drm_display_mode *mode) +{ + u64 pclk_rate; + u32 pclk_period; + u32 line_time; + + /* + * For linetime calculation, only operate on master encoder. + */ + if (!dpu_enc->cur_master) + return 0; + + if (!dpu_enc->cur_master->ops.get_line_count) { + DPU_ERROR("get_line_count function not defined\n"); + return 0; + } + + pclk_rate = mode->clock; /* pixel clock in kHz */ + if (pclk_rate == 0) { + DPU_ERROR("pclk is 0, cannot calculate line time\n"); + return 0; + } + + pclk_period = DIV_ROUND_UP_ULL(1000000000ull, pclk_rate); + if (pclk_period == 0) { + DPU_ERROR("pclk period is 0\n"); + return 0; + } + + /* + * Line time calculation based on Pixel clock and HTOTAL. + * Final unit is in ns. + */ + line_time = (pclk_period * mode->htotal) / 1000; + if (line_time == 0) { + DPU_ERROR("line time calculation is 0\n"); + return 0; + } + + DPU_DEBUG_ENC(dpu_enc, + "clk_rate=%lldkHz, clk_period=%d, linetime=%dns\n", + pclk_rate, pclk_period, line_time); + + return line_time; +} + +static int _dpu_encoder_wakeup_time(struct drm_encoder *drm_enc, + ktime_t *wakeup_time) +{ + struct drm_display_mode *mode; + struct dpu_encoder_virt *dpu_enc; + u32 cur_line; + u32 line_time; + u32 vtotal, time_to_vsync; + ktime_t cur_time; + + dpu_enc = to_dpu_encoder_virt(drm_enc); + + if (!drm_enc->crtc || !drm_enc->crtc->state) { + DPU_ERROR("crtc/crtc state object is NULL\n"); + return -EINVAL; + } + mode = &drm_enc->crtc->state->adjusted_mode; + + line_time = _dpu_encoder_calculate_linetime(dpu_enc, mode); + if (!line_time) + return -EINVAL; + + cur_line = dpu_enc->cur_master->ops.get_line_count(dpu_enc->cur_master); + + vtotal = mode->vtotal; + if (cur_line >= vtotal) + time_to_vsync = line_time * vtotal; + else + time_to_vsync = line_time * (vtotal - cur_line); + + if (time_to_vsync == 0) { + DPU_ERROR("time to vsync should not be zero, vtotal=%d\n", + vtotal); + return -EINVAL; + } + + cur_time = ktime_get(); + *wakeup_time = ktime_add_ns(cur_time, time_to_vsync); + + DPU_DEBUG_ENC(dpu_enc, + "cur_line=%u vtotal=%u time_to_vsync=%u, cur_time=%lld, wakeup_time=%lld\n", + cur_line, vtotal, time_to_vsync, + ktime_to_ms(cur_time), + ktime_to_ms(*wakeup_time)); + return 0; +} + +static void dpu_encoder_vsync_event_handler(struct timer_list *t) +{ + struct dpu_encoder_virt *dpu_enc = from_timer(dpu_enc, t, + vsync_event_timer); + struct drm_encoder *drm_enc = &dpu_enc->base; + struct msm_drm_private *priv; + struct msm_drm_thread *event_thread; + + if (!drm_enc->dev || !drm_enc->dev->dev_private || + !drm_enc->crtc) { + DPU_ERROR("invalid parameters\n"); + return; + } + + priv = drm_enc->dev->dev_private; + + if (drm_enc->crtc->index >= ARRAY_SIZE(priv->event_thread)) { + DPU_ERROR("invalid crtc index\n"); + return; + } + event_thread = &priv->event_thread[drm_enc->crtc->index]; + if (!event_thread) { + DPU_ERROR("event_thread not found for crtc:%d\n", + drm_enc->crtc->index); + return; + } + + del_timer(&dpu_enc->vsync_event_timer); +} + +static void dpu_encoder_vsync_event_work_handler(struct kthread_work *work) +{ + struct dpu_encoder_virt *dpu_enc = container_of(work, + struct dpu_encoder_virt, vsync_event_work); + ktime_t wakeup_time; + + if (!dpu_enc) { + DPU_ERROR("invalid dpu encoder\n"); + return; + } + + if (_dpu_encoder_wakeup_time(&dpu_enc->base, &wakeup_time)) + return; + + trace_dpu_enc_vsync_event_work(DRMID(&dpu_enc->base), wakeup_time); + mod_timer(&dpu_enc->vsync_event_timer, + nsecs_to_jiffies(ktime_to_ns(wakeup_time))); +} + +void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc, + struct dpu_encoder_kickoff_params *params) +{ + struct dpu_encoder_virt *dpu_enc; + struct dpu_encoder_phys *phys; + bool needs_hw_reset = false; + unsigned int i; + + if (!drm_enc || !params) { + DPU_ERROR("invalid args\n"); + return; + } + dpu_enc = to_dpu_encoder_virt(drm_enc); + + trace_dpu_enc_prepare_kickoff(DRMID(drm_enc)); + + /* prepare for next kickoff, may include waiting on previous kickoff */ + DPU_ATRACE_BEGIN("enc_prepare_for_kickoff"); + for (i = 0; i < dpu_enc->num_phys_encs; i++) { + phys = dpu_enc->phys_encs[i]; + if (phys) { + if (phys->ops.prepare_for_kickoff) + phys->ops.prepare_for_kickoff(phys, params); + if (phys->enable_state == DPU_ENC_ERR_NEEDS_HW_RESET) + needs_hw_reset = true; + } + } + DPU_ATRACE_END("enc_prepare_for_kickoff"); + + dpu_encoder_resource_control(drm_enc, DPU_ENC_RC_EVENT_KICKOFF); + + /* if any phys needs reset, reset all phys, in-order */ + if (needs_hw_reset) { + trace_dpu_enc_prepare_kickoff_reset(DRMID(drm_enc)); + for (i = 0; i < dpu_enc->num_phys_encs; i++) { + phys = dpu_enc->phys_encs[i]; + if (phys && phys->ops.hw_reset) + phys->ops.hw_reset(phys); + } + } +} + +void dpu_encoder_kickoff(struct drm_encoder *drm_enc) +{ + struct dpu_encoder_virt *dpu_enc; + struct dpu_encoder_phys *phys; + ktime_t wakeup_time; + unsigned int i; + + if (!drm_enc) { + DPU_ERROR("invalid encoder\n"); + return; + } + DPU_ATRACE_BEGIN("encoder_kickoff"); + dpu_enc = to_dpu_encoder_virt(drm_enc); + + trace_dpu_enc_kickoff(DRMID(drm_enc)); + + atomic_set(&dpu_enc->frame_done_timeout, + DPU_FRAME_DONE_TIMEOUT * 1000 / + drm_enc->crtc->state->adjusted_mode.vrefresh); + mod_timer(&dpu_enc->frame_done_timer, jiffies + + ((atomic_read(&dpu_enc->frame_done_timeout) * HZ) / 1000)); + + /* All phys encs are ready to go, trigger the kickoff */ + _dpu_encoder_kickoff_phys(dpu_enc); + + /* allow phys encs to handle any post-kickoff business */ + for (i = 0; i < dpu_enc->num_phys_encs; i++) { + phys = dpu_enc->phys_encs[i]; + if (phys && phys->ops.handle_post_kickoff) + phys->ops.handle_post_kickoff(phys); + } + + if (dpu_enc->disp_info.intf_type == DRM_MODE_CONNECTOR_DSI && + !_dpu_encoder_wakeup_time(drm_enc, &wakeup_time)) { + trace_dpu_enc_early_kickoff(DRMID(drm_enc), + ktime_to_ms(wakeup_time)); + mod_timer(&dpu_enc->vsync_event_timer, + nsecs_to_jiffies(ktime_to_ns(wakeup_time))); + } + + DPU_ATRACE_END("encoder_kickoff"); +} + +int dpu_encoder_helper_hw_release(struct dpu_encoder_phys *phys_enc, + struct drm_framebuffer *fb) +{ + struct drm_encoder *drm_enc; + struct dpu_hw_mixer_cfg mixer; + struct dpu_rm_hw_iter lm_iter; + bool lm_valid = false; + + if (!phys_enc || !phys_enc->parent) { + DPU_ERROR("invalid encoder\n"); + return -EINVAL; + } + + drm_enc = phys_enc->parent; + memset(&mixer, 0, sizeof(mixer)); + + /* reset associated CTL/LMs */ + if (phys_enc->hw_ctl->ops.clear_pending_flush) + phys_enc->hw_ctl->ops.clear_pending_flush(phys_enc->hw_ctl); + if (phys_enc->hw_ctl->ops.clear_all_blendstages) + phys_enc->hw_ctl->ops.clear_all_blendstages(phys_enc->hw_ctl); + + dpu_rm_init_hw_iter(&lm_iter, drm_enc->base.id, DPU_HW_BLK_LM); + while (dpu_rm_get_hw(&phys_enc->dpu_kms->rm, &lm_iter)) { + struct dpu_hw_mixer *hw_lm = (struct dpu_hw_mixer *)lm_iter.hw; + + if (!hw_lm) + continue; + + /* need to flush LM to remove it */ + if (phys_enc->hw_ctl->ops.get_bitmask_mixer && + phys_enc->hw_ctl->ops.update_pending_flush) + phys_enc->hw_ctl->ops.update_pending_flush( + phys_enc->hw_ctl, + phys_enc->hw_ctl->ops.get_bitmask_mixer( + phys_enc->hw_ctl, hw_lm->idx)); + + if (fb) { + /* assume a single LM if targeting a frame buffer */ + if (lm_valid) + continue; + + mixer.out_height = fb->height; + mixer.out_width = fb->width; + + if (hw_lm->ops.setup_mixer_out) + hw_lm->ops.setup_mixer_out(hw_lm, &mixer); + } + + lm_valid = true; + + /* only enable border color on LM */ + if (phys_enc->hw_ctl->ops.setup_blendstage) + phys_enc->hw_ctl->ops.setup_blendstage( + phys_enc->hw_ctl, hw_lm->idx, NULL); + } + + if (!lm_valid) { + DPU_DEBUG_ENC(to_dpu_encoder_virt(drm_enc), "lm not found\n"); + return -EFAULT; + } + return 0; +} + +void dpu_encoder_prepare_commit(struct drm_encoder *drm_enc) +{ + struct dpu_encoder_virt *dpu_enc; + struct dpu_encoder_phys *phys; + int i; + + if (!drm_enc) { + DPU_ERROR("invalid encoder\n"); + return; + } + dpu_enc = to_dpu_encoder_virt(drm_enc); + + for (i = 0; i < dpu_enc->num_phys_encs; i++) { + phys = dpu_enc->phys_encs[i]; + if (phys && phys->ops.prepare_commit) + phys->ops.prepare_commit(phys); + } +} + +#ifdef CONFIG_DEBUG_FS +static int _dpu_encoder_status_show(struct seq_file *s, void *data) +{ + struct dpu_encoder_virt *dpu_enc; + int i; + + if (!s || !s->private) + return -EINVAL; + + dpu_enc = s->private; + + mutex_lock(&dpu_enc->enc_lock); + for (i = 0; i < dpu_enc->num_phys_encs; i++) { + struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; + + if (!phys) + continue; + + seq_printf(s, "intf:%d vsync:%8d underrun:%8d ", + phys->intf_idx - INTF_0, + atomic_read(&phys->vsync_cnt), + atomic_read(&phys->underrun_cnt)); + + switch (phys->intf_mode) { + case INTF_MODE_VIDEO: + seq_puts(s, "mode: video\n"); + break; + case INTF_MODE_CMD: + seq_puts(s, "mode: command\n"); + break; + default: + seq_puts(s, "mode: ???\n"); + break; + } + } + mutex_unlock(&dpu_enc->enc_lock); + + return 0; +} + +static int _dpu_encoder_debugfs_status_open(struct inode *inode, + struct file *file) +{ + return single_open(file, _dpu_encoder_status_show, inode->i_private); +} + +static ssize_t _dpu_encoder_misr_setup(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + struct dpu_encoder_virt *dpu_enc; + int i = 0, rc; + char buf[MISR_BUFF_SIZE + 1]; + size_t buff_copy; + u32 frame_count, enable; + + if (!file || !file->private_data) + return -EINVAL; + + dpu_enc = file->private_data; + + buff_copy = min_t(size_t, count, MISR_BUFF_SIZE); + if (copy_from_user(buf, user_buf, buff_copy)) + return -EINVAL; + + buf[buff_copy] = 0; /* end of string */ + + if (sscanf(buf, "%u %u", &enable, &frame_count) != 2) + return -EINVAL; + + rc = _dpu_encoder_power_enable(dpu_enc, true); + if (rc) + return rc; + + mutex_lock(&dpu_enc->enc_lock); + dpu_enc->misr_enable = enable; + dpu_enc->misr_frame_count = frame_count; + for (i = 0; i < dpu_enc->num_phys_encs; i++) { + struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; + + if (!phys || !phys->ops.setup_misr) + continue; + + phys->ops.setup_misr(phys, enable, frame_count); + } + mutex_unlock(&dpu_enc->enc_lock); + _dpu_encoder_power_enable(dpu_enc, false); + + return count; +} + +static ssize_t _dpu_encoder_misr_read(struct file *file, + char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dpu_encoder_virt *dpu_enc; + int i = 0, len = 0; + char buf[MISR_BUFF_SIZE + 1] = {'\0'}; + int rc; + + if (*ppos) + return 0; + + if (!file || !file->private_data) + return -EINVAL; + + dpu_enc = file->private_data; + + rc = _dpu_encoder_power_enable(dpu_enc, true); + if (rc) + return rc; + + mutex_lock(&dpu_enc->enc_lock); + if (!dpu_enc->misr_enable) { + len += snprintf(buf + len, MISR_BUFF_SIZE - len, + "disabled\n"); + goto buff_check; + } else if (dpu_enc->disp_info.capabilities & + ~MSM_DISPLAY_CAP_VID_MODE) { + len += snprintf(buf + len, MISR_BUFF_SIZE - len, + "unsupported\n"); + goto buff_check; + } + + for (i = 0; i < dpu_enc->num_phys_encs; i++) { + struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; + + if (!phys || !phys->ops.collect_misr) + continue; + + len += snprintf(buf + len, MISR_BUFF_SIZE - len, + "Intf idx:%d\n", phys->intf_idx - INTF_0); + len += snprintf(buf + len, MISR_BUFF_SIZE - len, "0x%x\n", + phys->ops.collect_misr(phys)); + } + +buff_check: + if (count <= len) { + len = 0; + goto end; + } + + if (copy_to_user(user_buff, buf, len)) { + len = -EFAULT; + goto end; + } + + *ppos += len; /* increase offset */ + +end: + mutex_unlock(&dpu_enc->enc_lock); + _dpu_encoder_power_enable(dpu_enc, false); + return len; +} + +static int _dpu_encoder_init_debugfs(struct drm_encoder *drm_enc) +{ + struct dpu_encoder_virt *dpu_enc; + struct msm_drm_private *priv; + struct dpu_kms *dpu_kms; + int i; + + static const struct file_operations debugfs_status_fops = { + .open = _dpu_encoder_debugfs_status_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + }; + + static const struct file_operations debugfs_misr_fops = { + .open = simple_open, + .read = _dpu_encoder_misr_read, + .write = _dpu_encoder_misr_setup, + }; + + char name[DPU_NAME_SIZE]; + + if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private) { + DPU_ERROR("invalid encoder or kms\n"); + return -EINVAL; + } + + dpu_enc = to_dpu_encoder_virt(drm_enc); + priv = drm_enc->dev->dev_private; + dpu_kms = to_dpu_kms(priv->kms); + + snprintf(name, DPU_NAME_SIZE, "encoder%u", drm_enc->base.id); + + /* create overall sub-directory for the encoder */ + dpu_enc->debugfs_root = debugfs_create_dir(name, + drm_enc->dev->primary->debugfs_root); + if (!dpu_enc->debugfs_root) + return -ENOMEM; + + /* don't error check these */ + debugfs_create_file("status", 0600, + dpu_enc->debugfs_root, dpu_enc, &debugfs_status_fops); + + debugfs_create_file("misr_data", 0600, + dpu_enc->debugfs_root, dpu_enc, &debugfs_misr_fops); + + for (i = 0; i < dpu_enc->num_phys_encs; i++) + if (dpu_enc->phys_encs[i] && + dpu_enc->phys_encs[i]->ops.late_register) + dpu_enc->phys_encs[i]->ops.late_register( + dpu_enc->phys_encs[i], + dpu_enc->debugfs_root); + + return 0; +} + +static void _dpu_encoder_destroy_debugfs(struct drm_encoder *drm_enc) +{ + struct dpu_encoder_virt *dpu_enc; + + if (!drm_enc) + return; + + dpu_enc = to_dpu_encoder_virt(drm_enc); + debugfs_remove_recursive(dpu_enc->debugfs_root); +} +#else +static int _dpu_encoder_init_debugfs(struct drm_encoder *drm_enc) +{ + return 0; +} + +static void _dpu_encoder_destroy_debugfs(struct drm_encoder *drm_enc) +{ +} +#endif + +static int dpu_encoder_late_register(struct drm_encoder *encoder) +{ + return _dpu_encoder_init_debugfs(encoder); +} + +static void dpu_encoder_early_unregister(struct drm_encoder *encoder) +{ + _dpu_encoder_destroy_debugfs(encoder); +} + +static int dpu_encoder_virt_add_phys_encs( + u32 display_caps, + struct dpu_encoder_virt *dpu_enc, + struct dpu_enc_phys_init_params *params) +{ + struct dpu_encoder_phys *enc = NULL; + + DPU_DEBUG_ENC(dpu_enc, "\n"); + + /* + * We may create up to NUM_PHYS_ENCODER_TYPES physical encoder types + * in this function, check up-front. + */ + if (dpu_enc->num_phys_encs + NUM_PHYS_ENCODER_TYPES >= + ARRAY_SIZE(dpu_enc->phys_encs)) { + DPU_ERROR_ENC(dpu_enc, "too many physical encoders %d\n", + dpu_enc->num_phys_encs); + return -EINVAL; + } + + if (display_caps & MSM_DISPLAY_CAP_VID_MODE) { + enc = dpu_encoder_phys_vid_init(params); + + if (IS_ERR_OR_NULL(enc)) { + DPU_ERROR_ENC(dpu_enc, "failed to init vid enc: %ld\n", + PTR_ERR(enc)); + return enc == 0 ? -EINVAL : PTR_ERR(enc); + } + + dpu_enc->phys_encs[dpu_enc->num_phys_encs] = enc; + ++dpu_enc->num_phys_encs; + } + + if (display_caps & MSM_DISPLAY_CAP_CMD_MODE) { + enc = dpu_encoder_phys_cmd_init(params); + + if (IS_ERR_OR_NULL(enc)) { + DPU_ERROR_ENC(dpu_enc, "failed to init cmd enc: %ld\n", + PTR_ERR(enc)); + return enc == 0 ? -EINVAL : PTR_ERR(enc); + } + + dpu_enc->phys_encs[dpu_enc->num_phys_encs] = enc; + ++dpu_enc->num_phys_encs; + } + + return 0; +} + +static const struct dpu_encoder_virt_ops dpu_encoder_parent_ops = { + .handle_vblank_virt = dpu_encoder_vblank_callback, + .handle_underrun_virt = dpu_encoder_underrun_callback, + .handle_frame_done = dpu_encoder_frame_done_callback, +}; + +static int dpu_encoder_setup_display(struct dpu_encoder_virt *dpu_enc, + struct dpu_kms *dpu_kms, + struct msm_display_info *disp_info, + int *drm_enc_mode) +{ + int ret = 0; + int i = 0; + enum dpu_intf_type intf_type; + struct dpu_enc_phys_init_params phys_params; + + if (!dpu_enc || !dpu_kms) { + DPU_ERROR("invalid arg(s), enc %d kms %d\n", + dpu_enc != 0, dpu_kms != 0); + return -EINVAL; + } + + memset(&phys_params, 0, sizeof(phys_params)); + phys_params.dpu_kms = dpu_kms; + phys_params.parent = &dpu_enc->base; + phys_params.parent_ops = &dpu_encoder_parent_ops; + phys_params.enc_spinlock = &dpu_enc->enc_spinlock; + + DPU_DEBUG("\n"); + + if (disp_info->intf_type == DRM_MODE_CONNECTOR_DSI) { + *drm_enc_mode = DRM_MODE_ENCODER_DSI; + intf_type = INTF_DSI; + } else if (disp_info->intf_type == DRM_MODE_CONNECTOR_HDMIA) { + *drm_enc_mode = DRM_MODE_ENCODER_TMDS; + intf_type = INTF_HDMI; + } else if (disp_info->intf_type == DRM_MODE_CONNECTOR_DisplayPort) { + *drm_enc_mode = DRM_MODE_ENCODER_TMDS; + intf_type = INTF_DP; + } else { + DPU_ERROR_ENC(dpu_enc, "unsupported display interface type\n"); + return -EINVAL; + } + + WARN_ON(disp_info->num_of_h_tiles < 1); + + dpu_enc->display_num_of_h_tiles = disp_info->num_of_h_tiles; + + DPU_DEBUG("dsi_info->num_of_h_tiles %d\n", disp_info->num_of_h_tiles); + + if ((disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) || + (disp_info->capabilities & MSM_DISPLAY_CAP_VID_MODE)) + dpu_enc->idle_pc_supported = + dpu_kms->catalog->caps->has_idle_pc; + + mutex_lock(&dpu_enc->enc_lock); + for (i = 0; i < disp_info->num_of_h_tiles && !ret; i++) { + /* + * Left-most tile is at index 0, content is controller id + * h_tile_instance_ids[2] = {0, 1}; DSI0 = left, DSI1 = right + * h_tile_instance_ids[2] = {1, 0}; DSI1 = left, DSI0 = right + */ + u32 controller_id = disp_info->h_tile_instance[i]; + + if (disp_info->num_of_h_tiles > 1) { + if (i == 0) + phys_params.split_role = ENC_ROLE_MASTER; + else + phys_params.split_role = ENC_ROLE_SLAVE; + } else { + phys_params.split_role = ENC_ROLE_SOLO; + } + + DPU_DEBUG("h_tile_instance %d = %d, split_role %d\n", + i, controller_id, phys_params.split_role); + + phys_params.intf_idx = dpu_encoder_get_intf(dpu_kms->catalog, + intf_type, + controller_id); + if (phys_params.intf_idx == INTF_MAX) { + DPU_ERROR_ENC(dpu_enc, "could not get intf: type %d, id %d\n", + intf_type, controller_id); + ret = -EINVAL; + } + + if (!ret) { + ret = dpu_encoder_virt_add_phys_encs(disp_info->capabilities, + dpu_enc, + &phys_params); + if (ret) + DPU_ERROR_ENC(dpu_enc, "failed to add phys encs\n"); + } + } + + for (i = 0; i < dpu_enc->num_phys_encs; i++) { + struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; + + if (phys) { + atomic_set(&phys->vsync_cnt, 0); + atomic_set(&phys->underrun_cnt, 0); + } + } + mutex_unlock(&dpu_enc->enc_lock); + + return ret; +} + +static void dpu_encoder_frame_done_timeout(struct timer_list *t) +{ + struct dpu_encoder_virt *dpu_enc = from_timer(dpu_enc, t, + frame_done_timer); + struct drm_encoder *drm_enc = &dpu_enc->base; + struct msm_drm_private *priv; + u32 event; + + if (!drm_enc->dev || !drm_enc->dev->dev_private) { + DPU_ERROR("invalid parameters\n"); + return; + } + priv = drm_enc->dev->dev_private; + + if (!dpu_enc->frame_busy_mask[0] || !dpu_enc->crtc_frame_event_cb) { + DRM_DEBUG_KMS("id:%u invalid timeout frame_busy_mask=%lu\n", + DRMID(drm_enc), dpu_enc->frame_busy_mask[0]); + return; + } else if (!atomic_xchg(&dpu_enc->frame_done_timeout, 0)) { + DRM_DEBUG_KMS("id:%u invalid timeout\n", DRMID(drm_enc)); + return; + } + + DPU_ERROR_ENC(dpu_enc, "frame done timeout\n"); + + event = DPU_ENCODER_FRAME_EVENT_ERROR; + trace_dpu_enc_frame_done_timeout(DRMID(drm_enc), event); + dpu_enc->crtc_frame_event_cb(dpu_enc->crtc_frame_event_cb_data, event); +} + +static const struct drm_encoder_helper_funcs dpu_encoder_helper_funcs = { + .mode_set = dpu_encoder_virt_mode_set, + .disable = dpu_encoder_virt_disable, + .enable = dpu_kms_encoder_enable, + .atomic_check = dpu_encoder_virt_atomic_check, + + /* This is called by dpu_kms_encoder_enable */ + .commit = dpu_encoder_virt_enable, +}; + +static const struct drm_encoder_funcs dpu_encoder_funcs = { + .destroy = dpu_encoder_destroy, + .late_register = dpu_encoder_late_register, + .early_unregister = dpu_encoder_early_unregister, +}; + +int dpu_encoder_setup(struct drm_device *dev, struct drm_encoder *enc, + struct msm_display_info *disp_info) +{ + struct msm_drm_private *priv = dev->dev_private; + struct dpu_kms *dpu_kms = to_dpu_kms(priv->kms); + struct drm_encoder *drm_enc = NULL; + struct dpu_encoder_virt *dpu_enc = NULL; + int drm_enc_mode = DRM_MODE_ENCODER_NONE; + int ret = 0; + + dpu_enc = to_dpu_encoder_virt(enc); + + mutex_init(&dpu_enc->enc_lock); + ret = dpu_encoder_setup_display(dpu_enc, dpu_kms, disp_info, + &drm_enc_mode); + if (ret) + goto fail; + + dpu_enc->cur_master = NULL; + spin_lock_init(&dpu_enc->enc_spinlock); + + atomic_set(&dpu_enc->frame_done_timeout, 0); + timer_setup(&dpu_enc->frame_done_timer, + dpu_encoder_frame_done_timeout, 0); + + if (disp_info->intf_type == DRM_MODE_CONNECTOR_DSI) + timer_setup(&dpu_enc->vsync_event_timer, + dpu_encoder_vsync_event_handler, + 0); + + + mutex_init(&dpu_enc->rc_lock); + kthread_init_delayed_work(&dpu_enc->delayed_off_work, + dpu_encoder_off_work); + dpu_enc->idle_timeout = IDLE_TIMEOUT; + + kthread_init_work(&dpu_enc->vsync_event_work, + dpu_encoder_vsync_event_work_handler); + + memcpy(&dpu_enc->disp_info, disp_info, sizeof(*disp_info)); + + DPU_DEBUG_ENC(dpu_enc, "created\n"); + + return ret; + +fail: + DPU_ERROR("failed to create encoder\n"); + if (drm_enc) + dpu_encoder_destroy(drm_enc); + + return ret; + + +} + +struct drm_encoder *dpu_encoder_init(struct drm_device *dev, + int drm_enc_mode) +{ + struct dpu_encoder_virt *dpu_enc = NULL; + int rc = 0; + + dpu_enc = devm_kzalloc(dev->dev, sizeof(*dpu_enc), GFP_KERNEL); + if (!dpu_enc) + return ERR_PTR(ENOMEM); + + rc = drm_encoder_init(dev, &dpu_enc->base, &dpu_encoder_funcs, + drm_enc_mode, NULL); + if (rc) { + devm_kfree(dev->dev, dpu_enc); + return ERR_PTR(rc); + } + + drm_encoder_helper_add(&dpu_enc->base, &dpu_encoder_helper_funcs); + + return &dpu_enc->base; +} + +int dpu_encoder_wait_for_event(struct drm_encoder *drm_enc, + enum msm_event_wait event) +{ + int (*fn_wait)(struct dpu_encoder_phys *phys_enc) = NULL; + struct dpu_encoder_virt *dpu_enc = NULL; + int i, ret = 0; + + if (!drm_enc) { + DPU_ERROR("invalid encoder\n"); + return -EINVAL; + } + dpu_enc = to_dpu_encoder_virt(drm_enc); + DPU_DEBUG_ENC(dpu_enc, "\n"); + + for (i = 0; i < dpu_enc->num_phys_encs; i++) { + struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; + + switch (event) { + case MSM_ENC_COMMIT_DONE: + fn_wait = phys->ops.wait_for_commit_done; + break; + case MSM_ENC_TX_COMPLETE: + fn_wait = phys->ops.wait_for_tx_complete; + break; + case MSM_ENC_VBLANK: + fn_wait = phys->ops.wait_for_vblank; + break; + default: + DPU_ERROR_ENC(dpu_enc, "unknown wait event %d\n", + event); + return -EINVAL; + }; + + if (phys && fn_wait) { + DPU_ATRACE_BEGIN("wait_for_completion_event"); + ret = fn_wait(phys); + DPU_ATRACE_END("wait_for_completion_event"); + if (ret) + return ret; + } + } + + return ret; +} + +enum dpu_intf_mode dpu_encoder_get_intf_mode(struct drm_encoder *encoder) +{ + struct dpu_encoder_virt *dpu_enc = NULL; + int i; + + if (!encoder) { + DPU_ERROR("invalid encoder\n"); + return INTF_MODE_NONE; + } + dpu_enc = to_dpu_encoder_virt(encoder); + + if (dpu_enc->cur_master) + return dpu_enc->cur_master->intf_mode; + + for (i = 0; i < dpu_enc->num_phys_encs; i++) { + struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; + + if (phys) + return phys->intf_mode; + } + + return INTF_MODE_NONE; +} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h new file mode 100644 index 0000000000000..ce92901ed2273 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.com> + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __DPU_ENCODER_H__ +#define __DPU_ENCODER_H__ + +#include <drm/drm_crtc.h> +#include "dpu_hw_mdss.h" + +#define DPU_ENCODER_FRAME_EVENT_DONE BIT(0) +#define DPU_ENCODER_FRAME_EVENT_ERROR BIT(1) +#define DPU_ENCODER_FRAME_EVENT_PANEL_DEAD BIT(2) +#define DPU_ENCODER_FRAME_EVENT_IDLE BIT(3) + +#define IDLE_TIMEOUT (66 - 16/2) + +/** + * Encoder functions and data types + * @intfs: Interfaces this encoder is using, INTF_MODE_NONE if unused + * @needs_cdm: Encoder requests a CDM based on pixel format conversion needs + * @display_num_of_h_tiles: Number of horizontal tiles in case of split + * interface + * @topology: Topology of the display + */ +struct dpu_encoder_hw_resources { + enum dpu_intf_mode intfs[INTF_MAX]; + bool needs_cdm; + u32 display_num_of_h_tiles; +}; + +/** + * dpu_encoder_kickoff_params - info encoder requires at kickoff + * @affected_displays: bitmask, bit set means the ROI of the commit lies within + * the bounds of the physical display at the bit index + */ +struct dpu_encoder_kickoff_params { + unsigned long affected_displays; +}; + +/** + * dpu_encoder_get_hw_resources - Populate table of required hardware resources + * @encoder: encoder pointer + * @hw_res: resource table to populate with encoder required resources + * @conn_state: report hw reqs based on this proposed connector state + */ +void dpu_encoder_get_hw_resources(struct drm_encoder *encoder, + struct dpu_encoder_hw_resources *hw_res, + struct drm_connector_state *conn_state); + +/** + * dpu_encoder_register_vblank_callback - provide callback to encoder that + * will be called on the next vblank. + * @encoder: encoder pointer + * @cb: callback pointer, provide NULL to deregister and disable IRQs + * @data: user data provided to callback + */ +void dpu_encoder_register_vblank_callback(struct drm_encoder *encoder, + void (*cb)(void *), void *data); + +/** + * dpu_encoder_register_frame_event_callback - provide callback to encoder that + * will be called after the request is complete, or other events. + * @encoder: encoder pointer + * @cb: callback pointer, provide NULL to deregister + * @data: user data provided to callback + */ +void dpu_encoder_register_frame_event_callback(struct drm_encoder *encoder, + void (*cb)(void *, u32), void *data); + +/** + * dpu_encoder_prepare_for_kickoff - schedule double buffer flip of the ctl + * path (i.e. ctl flush and start) at next appropriate time. + * Immediately: if no previous commit is outstanding. + * Delayed: Block until next trigger can be issued. + * @encoder: encoder pointer + * @params: kickoff time parameters + */ +void dpu_encoder_prepare_for_kickoff(struct drm_encoder *encoder, + struct dpu_encoder_kickoff_params *params); + +/** + * dpu_encoder_trigger_kickoff_pending - Clear the flush bits from previous + * kickoff and trigger the ctl prepare progress for command mode display. + * @encoder: encoder pointer + */ +void dpu_encoder_trigger_kickoff_pending(struct drm_encoder *encoder); + +/** + * dpu_encoder_kickoff - trigger a double buffer flip of the ctl path + * (i.e. ctl flush and start) immediately. + * @encoder: encoder pointer + */ +void dpu_encoder_kickoff(struct drm_encoder *encoder); + +/** + * dpu_encoder_wait_for_event - Waits for encoder events + * @encoder: encoder pointer + * @event: event to wait for + * MSM_ENC_COMMIT_DONE - Wait for hardware to have flushed the current pending + * frames to hardware at a vblank or ctl_start + * Encoders will map this differently depending on the + * panel type. + * vid mode -> vsync_irq + * cmd mode -> ctl_start + * MSM_ENC_TX_COMPLETE - Wait for the hardware to transfer all the pixels to + * the panel. Encoders will map this differently + * depending on the panel type. + * vid mode -> vsync_irq + * cmd mode -> pp_done + * Returns: 0 on success, -EWOULDBLOCK if already signaled, error otherwise + */ +int dpu_encoder_wait_for_event(struct drm_encoder *drm_encoder, + enum msm_event_wait event); + +/* + * dpu_encoder_get_intf_mode - get interface mode of the given encoder + * @encoder: Pointer to drm encoder object + */ +enum dpu_intf_mode dpu_encoder_get_intf_mode(struct drm_encoder *encoder); + +/** + * dpu_encoder_virt_restore - restore the encoder configs + * @encoder: encoder pointer + */ +void dpu_encoder_virt_restore(struct drm_encoder *encoder); + +/** + * dpu_encoder_check_mode - check if given mode is supported or not + * @drm_enc: Pointer to drm encoder object + * @mode: Mode to be checked + * @Return: true if it is cmd mode + */ +bool dpu_encoder_check_mode(struct drm_encoder *drm_enc, u32 mode); + +/** + * dpu_encoder_init - initialize virtual encoder object + * @dev: Pointer to drm device structure + * @disp_info: Pointer to display information structure + * Returns: Pointer to newly created drm encoder + */ +struct drm_encoder *dpu_encoder_init( + struct drm_device *dev, + int drm_enc_mode); + +/** + * dpu_encoder_setup - setup dpu_encoder for the display probed + * @dev: Pointer to drm device structure + * @enc: Pointer to the drm_encoder + * @disp_info: Pointer to the display info + */ +int dpu_encoder_setup(struct drm_device *dev, struct drm_encoder *enc, + struct msm_display_info *disp_info); + +/** + * dpu_encoder_destroy - destroy previously initialized virtual encoder + * @drm_enc: Pointer to previously created drm encoder structure + */ +void dpu_encoder_destroy(struct drm_encoder *drm_enc); + +/** + * dpu_encoder_prepare_commit - prepare encoder at the very beginning of an + * atomic commit, before any registers are written + * @drm_enc: Pointer to previously created drm encoder structure + */ +void dpu_encoder_prepare_commit(struct drm_encoder *drm_enc); + +/** + * dpu_encoder_set_idle_timeout - set the idle timeout for video + * and command mode encoders. + * @drm_enc: Pointer to previously created drm encoder structure + * @idle_timeout: idle timeout duration in milliseconds + */ +void dpu_encoder_set_idle_timeout(struct drm_encoder *drm_enc, + u32 idle_timeout); + +#endif /* __DPU_ENCODER_H__ */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h new file mode 100644 index 0000000000000..8505edddcc813 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h @@ -0,0 +1,453 @@ +/* + * Copyright (c) 2015-2018 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#ifndef __DPU_ENCODER_PHYS_H__ +#define __DPU_ENCODER_PHYS_H__ + +#include <linux/jiffies.h> + +#include "dpu_kms.h" +#include "dpu_hw_intf.h" +#include "dpu_hw_pingpong.h" +#include "dpu_hw_ctl.h" +#include "dpu_hw_top.h" +#include "dpu_hw_cdm.h" +#include "dpu_encoder.h" + +#define DPU_ENCODER_NAME_MAX 16 + +/* wait for at most 2 vsync for lowest refresh rate (24hz) */ +#define KICKOFF_TIMEOUT_MS 84 +#define KICKOFF_TIMEOUT_JIFFIES msecs_to_jiffies(KICKOFF_TIMEOUT_MS) + +/** + * enum dpu_enc_split_role - Role this physical encoder will play in a + * split-panel configuration, where one panel is master, and others slaves. + * Masters have extra responsibilities, like managing the VBLANK IRQ. + * @ENC_ROLE_SOLO: This is the one and only panel. This encoder is master. + * @ENC_ROLE_MASTER: This encoder is the master of a split panel config. + * @ENC_ROLE_SLAVE: This encoder is not the master of a split panel config. + */ +enum dpu_enc_split_role { + ENC_ROLE_SOLO, + ENC_ROLE_MASTER, + ENC_ROLE_SLAVE, +}; + +/** + * enum dpu_enc_enable_state - current enabled state of the physical encoder + * @DPU_ENC_DISABLING: Encoder transitioning to disable state + * Events bounding transition are encoder type specific + * @DPU_ENC_DISABLED: Encoder is disabled + * @DPU_ENC_ENABLING: Encoder transitioning to enabled + * Events bounding transition are encoder type specific + * @DPU_ENC_ENABLED: Encoder is enabled + * @DPU_ENC_ERR_NEEDS_HW_RESET: Encoder is enabled, but requires a hw_reset + * to recover from a previous error + */ +enum dpu_enc_enable_state { + DPU_ENC_DISABLING, + DPU_ENC_DISABLED, + DPU_ENC_ENABLING, + DPU_ENC_ENABLED, + DPU_ENC_ERR_NEEDS_HW_RESET +}; + +struct dpu_encoder_phys; + +/** + * struct dpu_encoder_virt_ops - Interface the containing virtual encoder + * provides for the physical encoders to use to callback. + * @handle_vblank_virt: Notify virtual encoder of vblank IRQ reception + * Note: This is called from IRQ handler context. + * @handle_underrun_virt: Notify virtual encoder of underrun IRQ reception + * Note: This is called from IRQ handler context. + * @handle_frame_done: Notify virtual encoder that this phys encoder + * completes last request frame. + */ +struct dpu_encoder_virt_ops { + void (*handle_vblank_virt)(struct drm_encoder *, + struct dpu_encoder_phys *phys); + void (*handle_underrun_virt)(struct drm_encoder *, + struct dpu_encoder_phys *phys); + void (*handle_frame_done)(struct drm_encoder *, + struct dpu_encoder_phys *phys, u32 event); +}; + +/** + * struct dpu_encoder_phys_ops - Interface the physical encoders provide to + * the containing virtual encoder. + * @late_register: DRM Call. Add Userspace interfaces, debugfs. + * @prepare_commit: MSM Atomic Call, start of atomic commit sequence + * @is_master: Whether this phys_enc is the current master + * encoder. Can be switched at enable time. Based + * on split_role and current mode (CMD/VID). + * @mode_fixup: DRM Call. Fixup a DRM mode. + * @mode_set: DRM Call. Set a DRM mode. + * This likely caches the mode, for use at enable. + * @enable: DRM Call. Enable a DRM mode. + * @disable: DRM Call. Disable mode. + * @atomic_check: DRM Call. Atomic check new DRM state. + * @destroy: DRM Call. Destroy and release resources. + * @get_hw_resources: Populate the structure with the hardware + * resources that this phys_enc is using. + * Expect no overlap between phys_encs. + * @control_vblank_irq Register/Deregister for VBLANK IRQ + * @wait_for_commit_done: Wait for hardware to have flushed the + * current pending frames to hardware + * @wait_for_tx_complete: Wait for hardware to transfer the pixels + * to the panel + * @wait_for_vblank: Wait for VBLANK, for sub-driver internal use + * @prepare_for_kickoff: Do any work necessary prior to a kickoff + * For CMD encoder, may wait for previous tx done + * @handle_post_kickoff: Do any work necessary post-kickoff work + * @trigger_start: Process start event on physical encoder + * @needs_single_flush: Whether encoder slaves need to be flushed + * @setup_misr: Sets up MISR, enable and disables based on sysfs + * @collect_misr: Collects MISR data on frame update + * @hw_reset: Issue HW recovery such as CTL reset and clear + * DPU_ENC_ERR_NEEDS_HW_RESET state + * @irq_control: Handler to enable/disable all the encoder IRQs + * @prepare_idle_pc: phys encoder can update the vsync_enable status + * on idle power collapse prepare + * @restore: Restore all the encoder configs. + * @get_line_count: Obtain current vertical line count + */ + +struct dpu_encoder_phys_ops { + int (*late_register)(struct dpu_encoder_phys *encoder, + struct dentry *debugfs_root); + void (*prepare_commit)(struct dpu_encoder_phys *encoder); + bool (*is_master)(struct dpu_encoder_phys *encoder); + bool (*mode_fixup)(struct dpu_encoder_phys *encoder, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); + void (*mode_set)(struct dpu_encoder_phys *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); + void (*enable)(struct dpu_encoder_phys *encoder); + void (*disable)(struct dpu_encoder_phys *encoder); + int (*atomic_check)(struct dpu_encoder_phys *encoder, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state); + void (*destroy)(struct dpu_encoder_phys *encoder); + void (*get_hw_resources)(struct dpu_encoder_phys *encoder, + struct dpu_encoder_hw_resources *hw_res, + struct drm_connector_state *conn_state); + int (*control_vblank_irq)(struct dpu_encoder_phys *enc, bool enable); + int (*wait_for_commit_done)(struct dpu_encoder_phys *phys_enc); + int (*wait_for_tx_complete)(struct dpu_encoder_phys *phys_enc); + int (*wait_for_vblank)(struct dpu_encoder_phys *phys_enc); + void (*prepare_for_kickoff)(struct dpu_encoder_phys *phys_enc, + struct dpu_encoder_kickoff_params *params); + void (*handle_post_kickoff)(struct dpu_encoder_phys *phys_enc); + void (*trigger_start)(struct dpu_encoder_phys *phys_enc); + bool (*needs_single_flush)(struct dpu_encoder_phys *phys_enc); + + void (*setup_misr)(struct dpu_encoder_phys *phys_encs, + bool enable, u32 frame_count); + u32 (*collect_misr)(struct dpu_encoder_phys *phys_enc); + void (*hw_reset)(struct dpu_encoder_phys *phys_enc); + void (*irq_control)(struct dpu_encoder_phys *phys, bool enable); + void (*prepare_idle_pc)(struct dpu_encoder_phys *phys_enc); + void (*restore)(struct dpu_encoder_phys *phys); + int (*get_line_count)(struct dpu_encoder_phys *phys); +}; + +/** + * enum dpu_intr_idx - dpu encoder interrupt index + * @INTR_IDX_VSYNC: Vsync interrupt for video mode panel + * @INTR_IDX_PINGPONG: Pingpong done unterrupt for cmd mode panel + * @INTR_IDX_UNDERRUN: Underrun unterrupt for video and cmd mode panel + * @INTR_IDX_RDPTR: Readpointer done unterrupt for cmd mode panel + */ +enum dpu_intr_idx { + INTR_IDX_VSYNC, + INTR_IDX_PINGPONG, + INTR_IDX_UNDERRUN, + INTR_IDX_CTL_START, + INTR_IDX_RDPTR, + INTR_IDX_MAX, +}; + +/** + * dpu_encoder_irq - tracking structure for interrupts + * @name: string name of interrupt + * @intr_type: Encoder interrupt type + * @intr_idx: Encoder interrupt enumeration + * @hw_idx: HW Block ID + * @irq_idx: IRQ interface lookup index from DPU IRQ framework + * will be -EINVAL if IRQ is not registered + * @irq_cb: interrupt callback + */ +struct dpu_encoder_irq { + const char *name; + enum dpu_intr_type intr_type; + enum dpu_intr_idx intr_idx; + int hw_idx; + int irq_idx; + struct dpu_irq_callback cb; +}; + +/** + * struct dpu_encoder_phys - physical encoder that drives a single INTF block + * tied to a specific panel / sub-panel. Abstract type, sub-classed by + * phys_vid or phys_cmd for video mode or command mode encs respectively. + * @parent: Pointer to the containing virtual encoder + * @connector: If a mode is set, cached pointer to the active connector + * @ops: Operations exposed to the virtual encoder + * @parent_ops: Callbacks exposed by the parent to the phys_enc + * @hw_mdptop: Hardware interface to the top registers + * @hw_ctl: Hardware interface to the ctl registers + * @hw_cdm: Hardware interface to the cdm registers + * @cdm_cfg: Chroma-down hardware configuration + * @hw_pp: Hardware interface to the ping pong registers + * @dpu_kms: Pointer to the dpu_kms top level + * @cached_mode: DRM mode cached at mode_set time, acted on in enable + * @enabled: Whether the encoder has enabled and running a mode + * @split_role: Role to play in a split-panel configuration + * @intf_mode: Interface mode + * @intf_idx: Interface index on dpu hardware + * @topology_name: topology selected for the display + * @enc_spinlock: Virtual-Encoder-Wide Spin Lock for IRQ purposes + * @enable_state: Enable state tracking + * @vblank_refcount: Reference count of vblank request + * @vsync_cnt: Vsync count for the physical encoder + * @underrun_cnt: Underrun count for the physical encoder + * @pending_kickoff_cnt: Atomic counter tracking the number of kickoffs + * vs. the number of done/vblank irqs. Should hover + * between 0-2 Incremented when a new kickoff is + * scheduled. Decremented in irq handler + * @pending_ctlstart_cnt: Atomic counter tracking the number of ctl start + * pending. + * @pending_kickoff_wq: Wait queue for blocking until kickoff completes + * @irq: IRQ tracking structures + */ +struct dpu_encoder_phys { + struct drm_encoder *parent; + struct drm_connector *connector; + struct dpu_encoder_phys_ops ops; + const struct dpu_encoder_virt_ops *parent_ops; + struct dpu_hw_mdp *hw_mdptop; + struct dpu_hw_ctl *hw_ctl; + struct dpu_hw_cdm *hw_cdm; + struct dpu_hw_cdm_cfg cdm_cfg; + struct dpu_hw_pingpong *hw_pp; + struct dpu_kms *dpu_kms; + struct drm_display_mode cached_mode; + enum dpu_enc_split_role split_role; + enum dpu_intf_mode intf_mode; + enum dpu_intf intf_idx; + enum dpu_rm_topology_name topology_name; + spinlock_t *enc_spinlock; + enum dpu_enc_enable_state enable_state; + atomic_t vblank_refcount; + atomic_t vsync_cnt; + atomic_t underrun_cnt; + atomic_t pending_ctlstart_cnt; + atomic_t pending_kickoff_cnt; + wait_queue_head_t pending_kickoff_wq; + struct dpu_encoder_irq irq[INTR_IDX_MAX]; +}; + +static inline int dpu_encoder_phys_inc_pending(struct dpu_encoder_phys *phys) +{ + atomic_inc_return(&phys->pending_ctlstart_cnt); + return atomic_inc_return(&phys->pending_kickoff_cnt); +} + +/** + * struct dpu_encoder_phys_vid - sub-class of dpu_encoder_phys to handle video + * mode specific operations + * @base: Baseclass physical encoder structure + * @hw_intf: Hardware interface to the intf registers + * @timing_params: Current timing parameter + */ +struct dpu_encoder_phys_vid { + struct dpu_encoder_phys base; + struct dpu_hw_intf *hw_intf; + struct intf_timing_params timing_params; +}; + +/** + * struct dpu_encoder_phys_cmd - sub-class of dpu_encoder_phys to handle command + * mode specific operations + * @base: Baseclass physical encoder structure + * @intf_idx: Intf Block index used by this phys encoder + * @stream_sel: Stream selection for multi-stream interfaces + * @serialize_wait4pp: serialize wait4pp feature waits for pp_done interrupt + * after ctl_start instead of before next frame kickoff + * @pp_timeout_report_cnt: number of pingpong done irq timeout errors + * @pending_vblank_cnt: Atomic counter tracking pending wait for VBLANK + * @pending_vblank_wq: Wait queue for blocking until VBLANK received + */ +struct dpu_encoder_phys_cmd { + struct dpu_encoder_phys base; + int stream_sel; + bool serialize_wait4pp; + int pp_timeout_report_cnt; + atomic_t pending_vblank_cnt; + wait_queue_head_t pending_vblank_wq; +}; + +/** + * struct dpu_enc_phys_init_params - initialization parameters for phys encs + * @dpu_kms: Pointer to the dpu_kms top level + * @parent: Pointer to the containing virtual encoder + * @parent_ops: Callbacks exposed by the parent to the phys_enc + * @split_role: Role to play in a split-panel configuration + * @intf_idx: Interface index this phys_enc will control + * @enc_spinlock: Virtual-Encoder-Wide Spin Lock for IRQ purposes + */ +struct dpu_enc_phys_init_params { + struct dpu_kms *dpu_kms; + struct drm_encoder *parent; + const struct dpu_encoder_virt_ops *parent_ops; + enum dpu_enc_split_role split_role; + enum dpu_intf intf_idx; + spinlock_t *enc_spinlock; +}; + +/** + * dpu_encoder_wait_info - container for passing arguments to irq wait functions + * @wq: wait queue structure + * @atomic_cnt: wait until atomic_cnt equals zero + * @timeout_ms: timeout value in milliseconds + */ +struct dpu_encoder_wait_info { + wait_queue_head_t *wq; + atomic_t *atomic_cnt; + s64 timeout_ms; +}; + +/** + * dpu_encoder_phys_vid_init - Construct a new video mode physical encoder + * @p: Pointer to init params structure + * Return: Error code or newly allocated encoder + */ +struct dpu_encoder_phys *dpu_encoder_phys_vid_init( + struct dpu_enc_phys_init_params *p); + +/** + * dpu_encoder_phys_cmd_init - Construct a new command mode physical encoder + * @p: Pointer to init params structure + * Return: Error code or newly allocated encoder + */ +struct dpu_encoder_phys *dpu_encoder_phys_cmd_init( + struct dpu_enc_phys_init_params *p); + +/** + * dpu_encoder_helper_trigger_start - control start helper function + * This helper function may be optionally specified by physical + * encoders if they require ctl_start triggering. + * @phys_enc: Pointer to physical encoder structure + */ +void dpu_encoder_helper_trigger_start(struct dpu_encoder_phys *phys_enc); + +/** + * dpu_encoder_helper_wait_event_timeout - wait for event with timeout + * taking into account that jiffies may jump between reads leading to + * incorrectly detected timeouts. Prevent failure in this scenario by + * making sure that elapsed time during wait is valid. + * @drm_id: drm object id for logging + * @hw_id: hw instance id for logging + * @info: wait info structure + */ +int dpu_encoder_helper_wait_event_timeout( + int32_t drm_id, + int32_t hw_id, + struct dpu_encoder_wait_info *info); + +/** + * dpu_encoder_helper_hw_reset - issue ctl hw reset + * This helper function may be optionally specified by physical + * encoders if they require ctl hw reset. If state is currently + * DPU_ENC_ERR_NEEDS_HW_RESET, it is set back to DPU_ENC_ENABLED. + * @phys_enc: Pointer to physical encoder structure + */ +void dpu_encoder_helper_hw_reset(struct dpu_encoder_phys *phys_enc); + +static inline enum dpu_3d_blend_mode dpu_encoder_helper_get_3d_blend_mode( + struct dpu_encoder_phys *phys_enc) +{ + if (!phys_enc || phys_enc->enable_state == DPU_ENC_DISABLING) + return BLEND_3D_NONE; + + if (phys_enc->split_role == ENC_ROLE_SOLO && + phys_enc->topology_name == DPU_RM_TOPOLOGY_DUALPIPE_3DMERGE) + return BLEND_3D_H_ROW_INT; + + return BLEND_3D_NONE; +} + +/** + * dpu_encoder_helper_split_config - split display configuration helper function + * This helper function may be used by physical encoders to configure + * the split display related registers. + * @phys_enc: Pointer to physical encoder structure + * @interface: enum dpu_intf setting + */ +void dpu_encoder_helper_split_config( + struct dpu_encoder_phys *phys_enc, + enum dpu_intf interface); + +/** + * dpu_encoder_helper_hw_release - prepare for h/w reset during disable + * @phys_enc: Pointer to physical encoder structure + * @fb: Optional fb for specifying new mixer output resolution, may be NULL + * Return: Zero on success + */ +int dpu_encoder_helper_hw_release(struct dpu_encoder_phys *phys_enc, + struct drm_framebuffer *fb); + +/** + * dpu_encoder_helper_report_irq_timeout - utility to report error that irq has + * timed out, including reporting frame error event to crtc and debug dump + * @phys_enc: Pointer to physical encoder structure + * @intr_idx: Failing interrupt index + */ +void dpu_encoder_helper_report_irq_timeout(struct dpu_encoder_phys *phys_enc, + enum dpu_intr_idx intr_idx); + +/** + * dpu_encoder_helper_wait_for_irq - utility to wait on an irq. + * note: will call dpu_encoder_helper_wait_for_irq on timeout + * @phys_enc: Pointer to physical encoder structure + * @intr_idx: encoder interrupt index + * @wait_info: wait info struct + * @Return: 0 or -ERROR + */ +int dpu_encoder_helper_wait_for_irq(struct dpu_encoder_phys *phys_enc, + enum dpu_intr_idx intr_idx, + struct dpu_encoder_wait_info *wait_info); + +/** + * dpu_encoder_helper_register_irq - register and enable an irq + * @phys_enc: Pointer to physical encoder structure + * @intr_idx: encoder interrupt index + * @Return: 0 or -ERROR + */ +int dpu_encoder_helper_register_irq(struct dpu_encoder_phys *phys_enc, + enum dpu_intr_idx intr_idx); + +/** + * dpu_encoder_helper_unregister_irq - unregister and disable an irq + * @phys_enc: Pointer to physical encoder structure + * @intr_idx: encoder interrupt index + * @Return: 0 or -ERROR + */ +int dpu_encoder_helper_unregister_irq(struct dpu_encoder_phys *phys_enc, + enum dpu_intr_idx intr_idx); + +#endif /* __dpu_encoder_phys_H__ */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c new file mode 100644 index 0000000000000..035a5fbe1435a --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c @@ -0,0 +1,905 @@ +/* + * Copyright (c) 2015-2018 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ +#include "dpu_encoder_phys.h" +#include "dpu_hw_interrupts.h" +#include "dpu_core_irq.h" +#include "dpu_formats.h" +#include "dpu_trace.h" + +#define DPU_DEBUG_CMDENC(e, fmt, ...) DPU_DEBUG("enc%d intf%d " fmt, \ + (e) && (e)->base.parent ? \ + (e)->base.parent->base.id : -1, \ + (e) ? (e)->base.intf_idx - INTF_0 : -1, ##__VA_ARGS__) + +#define DPU_ERROR_CMDENC(e, fmt, ...) DPU_ERROR("enc%d intf%d " fmt, \ + (e) && (e)->base.parent ? \ + (e)->base.parent->base.id : -1, \ + (e) ? (e)->base.intf_idx - INTF_0 : -1, ##__VA_ARGS__) + +#define to_dpu_encoder_phys_cmd(x) \ + container_of(x, struct dpu_encoder_phys_cmd, base) + +#define PP_TIMEOUT_MAX_TRIALS 10 + +/* + * Tearcheck sync start and continue thresholds are empirically found + * based on common panels In the future, may want to allow panels to override + * these default values + */ +#define DEFAULT_TEARCHECK_SYNC_THRESH_START 4 +#define DEFAULT_TEARCHECK_SYNC_THRESH_CONTINUE 4 + +#define DPU_ENC_WR_PTR_START_TIMEOUT_US 20000 + +static inline int _dpu_encoder_phys_cmd_get_idle_timeout( + struct dpu_encoder_phys_cmd *cmd_enc) +{ + return KICKOFF_TIMEOUT_MS; +} + +static inline bool dpu_encoder_phys_cmd_is_master( + struct dpu_encoder_phys *phys_enc) +{ + return (phys_enc->split_role != ENC_ROLE_SLAVE) ? true : false; +} + +static bool dpu_encoder_phys_cmd_mode_fixup( + struct dpu_encoder_phys *phys_enc, + const struct drm_display_mode *mode, + struct drm_display_mode *adj_mode) +{ + if (phys_enc) + DPU_DEBUG_CMDENC(to_dpu_encoder_phys_cmd(phys_enc), "\n"); + return true; +} + +static void _dpu_encoder_phys_cmd_update_intf_cfg( + struct dpu_encoder_phys *phys_enc) +{ + struct dpu_encoder_phys_cmd *cmd_enc = + to_dpu_encoder_phys_cmd(phys_enc); + struct dpu_hw_ctl *ctl; + struct dpu_hw_intf_cfg intf_cfg = { 0 }; + + if (!phys_enc) + return; + + ctl = phys_enc->hw_ctl; + if (!ctl || !ctl->ops.setup_intf_cfg) + return; + + intf_cfg.intf = phys_enc->intf_idx; + intf_cfg.intf_mode_sel = DPU_CTL_MODE_SEL_CMD; + intf_cfg.stream_sel = cmd_enc->stream_sel; + intf_cfg.mode_3d = dpu_encoder_helper_get_3d_blend_mode(phys_enc); + ctl->ops.setup_intf_cfg(ctl, &intf_cfg); +} + +static void dpu_encoder_phys_cmd_pp_tx_done_irq(void *arg, int irq_idx) +{ + struct dpu_encoder_phys *phys_enc = arg; + unsigned long lock_flags; + int new_cnt; + u32 event = DPU_ENCODER_FRAME_EVENT_DONE; + + if (!phys_enc || !phys_enc->hw_pp) + return; + + DPU_ATRACE_BEGIN("pp_done_irq"); + /* notify all synchronous clients first, then asynchronous clients */ + if (phys_enc->parent_ops->handle_frame_done) + phys_enc->parent_ops->handle_frame_done(phys_enc->parent, + phys_enc, event); + + spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags); + new_cnt = atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0); + spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags); + + trace_dpu_enc_phys_cmd_pp_tx_done(DRMID(phys_enc->parent), + phys_enc->hw_pp->idx - PINGPONG_0, + new_cnt, event); + + /* Signal any waiting atomic commit thread */ + wake_up_all(&phys_enc->pending_kickoff_wq); + DPU_ATRACE_END("pp_done_irq"); +} + +static void dpu_encoder_phys_cmd_pp_rd_ptr_irq(void *arg, int irq_idx) +{ + struct dpu_encoder_phys *phys_enc = arg; + struct dpu_encoder_phys_cmd *cmd_enc; + + if (!phys_enc || !phys_enc->hw_pp) + return; + + DPU_ATRACE_BEGIN("rd_ptr_irq"); + cmd_enc = to_dpu_encoder_phys_cmd(phys_enc); + + if (phys_enc->parent_ops->handle_vblank_virt) + phys_enc->parent_ops->handle_vblank_virt(phys_enc->parent, + phys_enc); + + atomic_add_unless(&cmd_enc->pending_vblank_cnt, -1, 0); + wake_up_all(&cmd_enc->pending_vblank_wq); + DPU_ATRACE_END("rd_ptr_irq"); +} + +static void dpu_encoder_phys_cmd_ctl_start_irq(void *arg, int irq_idx) +{ + struct dpu_encoder_phys *phys_enc = arg; + struct dpu_encoder_phys_cmd *cmd_enc; + + if (!phys_enc || !phys_enc->hw_ctl) + return; + + DPU_ATRACE_BEGIN("ctl_start_irq"); + cmd_enc = to_dpu_encoder_phys_cmd(phys_enc); + + atomic_add_unless(&phys_enc->pending_ctlstart_cnt, -1, 0); + + /* Signal any waiting ctl start interrupt */ + wake_up_all(&phys_enc->pending_kickoff_wq); + DPU_ATRACE_END("ctl_start_irq"); +} + +static void dpu_encoder_phys_cmd_underrun_irq(void *arg, int irq_idx) +{ + struct dpu_encoder_phys *phys_enc = arg; + + if (!phys_enc) + return; + + if (phys_enc->parent_ops->handle_underrun_virt) + phys_enc->parent_ops->handle_underrun_virt(phys_enc->parent, + phys_enc); +} + +static void _dpu_encoder_phys_cmd_setup_irq_hw_idx( + struct dpu_encoder_phys *phys_enc) +{ + struct dpu_encoder_irq *irq; + + irq = &phys_enc->irq[INTR_IDX_CTL_START]; + irq->hw_idx = phys_enc->hw_ctl->idx; + irq->irq_idx = -EINVAL; + + irq = &phys_enc->irq[INTR_IDX_PINGPONG]; + irq->hw_idx = phys_enc->hw_pp->idx; + irq->irq_idx = -EINVAL; + + irq = &phys_enc->irq[INTR_IDX_RDPTR]; + irq->hw_idx = phys_enc->hw_pp->idx; + irq->irq_idx = -EINVAL; + + irq = &phys_enc->irq[INTR_IDX_UNDERRUN]; + irq->hw_idx = phys_enc->intf_idx; + irq->irq_idx = -EINVAL; +} + +static void dpu_encoder_phys_cmd_mode_set( + struct dpu_encoder_phys *phys_enc, + struct drm_display_mode *mode, + struct drm_display_mode *adj_mode) +{ + struct dpu_encoder_phys_cmd *cmd_enc = + to_dpu_encoder_phys_cmd(phys_enc); + struct dpu_rm *rm = &phys_enc->dpu_kms->rm; + struct dpu_rm_hw_iter iter; + int i, instance; + + if (!phys_enc || !mode || !adj_mode) { + DPU_ERROR("invalid args\n"); + return; + } + phys_enc->cached_mode = *adj_mode; + DPU_DEBUG_CMDENC(cmd_enc, "caching mode:\n"); + drm_mode_debug_printmodeline(adj_mode); + + instance = phys_enc->split_role == ENC_ROLE_SLAVE ? 1 : 0; + + /* Retrieve previously allocated HW Resources. Shouldn't fail */ + dpu_rm_init_hw_iter(&iter, phys_enc->parent->base.id, DPU_HW_BLK_CTL); + for (i = 0; i <= instance; i++) { + if (dpu_rm_get_hw(rm, &iter)) + phys_enc->hw_ctl = (struct dpu_hw_ctl *)iter.hw; + } + + if (IS_ERR_OR_NULL(phys_enc->hw_ctl)) { + DPU_ERROR_CMDENC(cmd_enc, "failed to init ctl: %ld\n", + PTR_ERR(phys_enc->hw_ctl)); + phys_enc->hw_ctl = NULL; + return; + } + + _dpu_encoder_phys_cmd_setup_irq_hw_idx(phys_enc); +} + +static int _dpu_encoder_phys_cmd_handle_ppdone_timeout( + struct dpu_encoder_phys *phys_enc) +{ + struct dpu_encoder_phys_cmd *cmd_enc = + to_dpu_encoder_phys_cmd(phys_enc); + u32 frame_event = DPU_ENCODER_FRAME_EVENT_ERROR; + bool do_log = false; + + if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_ctl) + return -EINVAL; + + cmd_enc->pp_timeout_report_cnt++; + if (cmd_enc->pp_timeout_report_cnt == PP_TIMEOUT_MAX_TRIALS) { + frame_event |= DPU_ENCODER_FRAME_EVENT_PANEL_DEAD; + do_log = true; + } else if (cmd_enc->pp_timeout_report_cnt == 1) { + do_log = true; + } + + trace_dpu_enc_phys_cmd_pdone_timeout(DRMID(phys_enc->parent), + phys_enc->hw_pp->idx - PINGPONG_0, + cmd_enc->pp_timeout_report_cnt, + atomic_read(&phys_enc->pending_kickoff_cnt), + frame_event); + + /* to avoid flooding, only log first time, and "dead" time */ + if (do_log) { + DRM_ERROR("id:%d pp:%d kickoff timeout %d cnt %d koff_cnt %d\n", + DRMID(phys_enc->parent), + phys_enc->hw_pp->idx - PINGPONG_0, + phys_enc->hw_ctl->idx - CTL_0, + cmd_enc->pp_timeout_report_cnt, + atomic_read(&phys_enc->pending_kickoff_cnt)); + + dpu_encoder_helper_unregister_irq(phys_enc, INTR_IDX_RDPTR); + dpu_dbg_dump(false, __func__, true, true); + } + + atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0); + + /* request a ctl reset before the next kickoff */ + phys_enc->enable_state = DPU_ENC_ERR_NEEDS_HW_RESET; + + if (phys_enc->parent_ops->handle_frame_done) + phys_enc->parent_ops->handle_frame_done( + phys_enc->parent, phys_enc, frame_event); + + return -ETIMEDOUT; +} + +static int _dpu_encoder_phys_cmd_wait_for_idle( + struct dpu_encoder_phys *phys_enc) +{ + struct dpu_encoder_phys_cmd *cmd_enc = + to_dpu_encoder_phys_cmd(phys_enc); + struct dpu_encoder_wait_info wait_info; + int ret; + + if (!phys_enc) { + DPU_ERROR("invalid encoder\n"); + return -EINVAL; + } + + wait_info.wq = &phys_enc->pending_kickoff_wq; + wait_info.atomic_cnt = &phys_enc->pending_kickoff_cnt; + wait_info.timeout_ms = KICKOFF_TIMEOUT_MS; + + ret = dpu_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_PINGPONG, + &wait_info); + if (ret == -ETIMEDOUT) + _dpu_encoder_phys_cmd_handle_ppdone_timeout(phys_enc); + else if (!ret) + cmd_enc->pp_timeout_report_cnt = 0; + + return ret; +} + +static int dpu_encoder_phys_cmd_control_vblank_irq( + struct dpu_encoder_phys *phys_enc, + bool enable) +{ + int ret = 0; + int refcount; + + if (!phys_enc || !phys_enc->hw_pp) { + DPU_ERROR("invalid encoder\n"); + return -EINVAL; + } + + refcount = atomic_read(&phys_enc->vblank_refcount); + + /* Slave encoders don't report vblank */ + if (!dpu_encoder_phys_cmd_is_master(phys_enc)) + goto end; + + /* protect against negative */ + if (!enable && refcount == 0) { + ret = -EINVAL; + goto end; + } + + DRM_DEBUG_KMS("id:%u pp:%d enable=%s/%d\n", DRMID(phys_enc->parent), + phys_enc->hw_pp->idx - PINGPONG_0, + enable ? "true" : "false", refcount); + + if (enable && atomic_inc_return(&phys_enc->vblank_refcount) == 1) + ret = dpu_encoder_helper_register_irq(phys_enc, INTR_IDX_RDPTR); + else if (!enable && atomic_dec_return(&phys_enc->vblank_refcount) == 0) + ret = dpu_encoder_helper_unregister_irq(phys_enc, + INTR_IDX_RDPTR); + +end: + if (ret) { + DRM_ERROR("vblank irq err id:%u pp:%d ret:%d, enable %s/%d\n", + DRMID(phys_enc->parent), + phys_enc->hw_pp->idx - PINGPONG_0, ret, + enable ? "true" : "false", refcount); + } + + return ret; +} + +void dpu_encoder_phys_cmd_irq_control(struct dpu_encoder_phys *phys_enc, + bool enable) +{ + struct dpu_encoder_phys_cmd *cmd_enc; + + if (!phys_enc) + return; + + cmd_enc = to_dpu_encoder_phys_cmd(phys_enc); + + trace_dpu_enc_phys_cmd_irq_ctrl(DRMID(phys_enc->parent), + phys_enc->hw_pp->idx - PINGPONG_0, + enable, atomic_read(&phys_enc->vblank_refcount)); + + if (enable) { + dpu_encoder_helper_register_irq(phys_enc, INTR_IDX_PINGPONG); + dpu_encoder_helper_register_irq(phys_enc, INTR_IDX_UNDERRUN); + dpu_encoder_phys_cmd_control_vblank_irq(phys_enc, true); + + if (dpu_encoder_phys_cmd_is_master(phys_enc)) + dpu_encoder_helper_register_irq(phys_enc, + INTR_IDX_CTL_START); + } else { + if (dpu_encoder_phys_cmd_is_master(phys_enc)) + dpu_encoder_helper_unregister_irq(phys_enc, + INTR_IDX_CTL_START); + + dpu_encoder_helper_unregister_irq(phys_enc, INTR_IDX_UNDERRUN); + dpu_encoder_phys_cmd_control_vblank_irq(phys_enc, false); + dpu_encoder_helper_unregister_irq(phys_enc, INTR_IDX_PINGPONG); + } +} + +static void dpu_encoder_phys_cmd_tearcheck_config( + struct dpu_encoder_phys *phys_enc) +{ + struct dpu_encoder_phys_cmd *cmd_enc = + to_dpu_encoder_phys_cmd(phys_enc); + struct dpu_hw_tear_check tc_cfg = { 0 }; + struct drm_display_mode *mode; + bool tc_enable = true; + u32 vsync_hz; + struct msm_drm_private *priv; + struct dpu_kms *dpu_kms; + + if (!phys_enc || !phys_enc->hw_pp) { + DPU_ERROR("invalid encoder\n"); + return; + } + mode = &phys_enc->cached_mode; + + DPU_DEBUG_CMDENC(cmd_enc, "pp %d\n", phys_enc->hw_pp->idx - PINGPONG_0); + + if (!phys_enc->hw_pp->ops.setup_tearcheck || + !phys_enc->hw_pp->ops.enable_tearcheck) { + DPU_DEBUG_CMDENC(cmd_enc, "tearcheck not supported\n"); + return; + } + + dpu_kms = phys_enc->dpu_kms; + if (!dpu_kms || !dpu_kms->dev || !dpu_kms->dev->dev_private) { + DPU_ERROR("invalid device\n"); + return; + } + priv = dpu_kms->dev->dev_private; + + /* + * TE default: dsi byte clock calculated base on 70 fps; + * around 14 ms to complete a kickoff cycle if te disabled; + * vclk_line base on 60 fps; write is faster than read; + * init == start == rdptr; + * + * vsync_count is ratio of MDP VSYNC clock frequency to LCD panel + * frequency divided by the no. of rows (lines) in the LCDpanel. + */ + vsync_hz = dpu_kms_get_clk_rate(dpu_kms, "vsync_clk"); + if (vsync_hz <= 0) { + DPU_DEBUG_CMDENC(cmd_enc, "invalid - vsync_hz %u\n", + vsync_hz); + return; + } + + tc_cfg.vsync_count = vsync_hz / (mode->vtotal * mode->vrefresh); + + /* enable external TE after kickoff to avoid premature autorefresh */ + tc_cfg.hw_vsync_mode = 0; + + /* + * By setting sync_cfg_height to near max register value, we essentially + * disable dpu hw generated TE signal, since hw TE will arrive first. + * Only caveat is if due to error, we hit wrap-around. + */ + tc_cfg.sync_cfg_height = 0xFFF0; + tc_cfg.vsync_init_val = mode->vdisplay; + tc_cfg.sync_threshold_start = DEFAULT_TEARCHECK_SYNC_THRESH_START; + tc_cfg.sync_threshold_continue = DEFAULT_TEARCHECK_SYNC_THRESH_CONTINUE; + tc_cfg.start_pos = mode->vdisplay; + tc_cfg.rd_ptr_irq = mode->vdisplay + 1; + + DPU_DEBUG_CMDENC(cmd_enc, + "tc %d vsync_clk_speed_hz %u vtotal %u vrefresh %u\n", + phys_enc->hw_pp->idx - PINGPONG_0, vsync_hz, + mode->vtotal, mode->vrefresh); + DPU_DEBUG_CMDENC(cmd_enc, + "tc %d enable %u start_pos %u rd_ptr_irq %u\n", + phys_enc->hw_pp->idx - PINGPONG_0, tc_enable, tc_cfg.start_pos, + tc_cfg.rd_ptr_irq); + DPU_DEBUG_CMDENC(cmd_enc, + "tc %d hw_vsync_mode %u vsync_count %u vsync_init_val %u\n", + phys_enc->hw_pp->idx - PINGPONG_0, tc_cfg.hw_vsync_mode, + tc_cfg.vsync_count, tc_cfg.vsync_init_val); + DPU_DEBUG_CMDENC(cmd_enc, + "tc %d cfgheight %u thresh_start %u thresh_cont %u\n", + phys_enc->hw_pp->idx - PINGPONG_0, tc_cfg.sync_cfg_height, + tc_cfg.sync_threshold_start, tc_cfg.sync_threshold_continue); + + phys_enc->hw_pp->ops.setup_tearcheck(phys_enc->hw_pp, &tc_cfg); + phys_enc->hw_pp->ops.enable_tearcheck(phys_enc->hw_pp, tc_enable); +} + +static void _dpu_encoder_phys_cmd_pingpong_config( + struct dpu_encoder_phys *phys_enc) +{ + struct dpu_encoder_phys_cmd *cmd_enc = + to_dpu_encoder_phys_cmd(phys_enc); + + if (!phys_enc || !phys_enc->hw_ctl || !phys_enc->hw_pp + || !phys_enc->hw_ctl->ops.setup_intf_cfg) { + DPU_ERROR("invalid arg(s), enc %d\n", phys_enc != 0); + return; + } + + DPU_DEBUG_CMDENC(cmd_enc, "pp %d, enabling mode:\n", + phys_enc->hw_pp->idx - PINGPONG_0); + drm_mode_debug_printmodeline(&phys_enc->cached_mode); + + _dpu_encoder_phys_cmd_update_intf_cfg(phys_enc); + dpu_encoder_phys_cmd_tearcheck_config(phys_enc); +} + +static bool dpu_encoder_phys_cmd_needs_single_flush( + struct dpu_encoder_phys *phys_enc) +{ + /** + * we do separate flush for each CTL and let + * CTL_START synchronize them + */ + return false; +} + +static void dpu_encoder_phys_cmd_enable_helper( + struct dpu_encoder_phys *phys_enc) +{ + struct dpu_hw_ctl *ctl; + u32 flush_mask = 0; + + if (!phys_enc || !phys_enc->hw_ctl || !phys_enc->hw_pp) { + DPU_ERROR("invalid arg(s), encoder %d\n", phys_enc != 0); + return; + } + + dpu_encoder_helper_split_config(phys_enc, phys_enc->intf_idx); + + _dpu_encoder_phys_cmd_pingpong_config(phys_enc); + + if (!dpu_encoder_phys_cmd_is_master(phys_enc)) + goto skip_flush; + + ctl = phys_enc->hw_ctl; + ctl->ops.get_bitmask_intf(ctl, &flush_mask, phys_enc->intf_idx); + ctl->ops.update_pending_flush(ctl, flush_mask); + +skip_flush: + return; +} + +static void dpu_encoder_phys_cmd_enable(struct dpu_encoder_phys *phys_enc) +{ + struct dpu_encoder_phys_cmd *cmd_enc = + to_dpu_encoder_phys_cmd(phys_enc); + + if (!phys_enc || !phys_enc->hw_pp) { + DPU_ERROR("invalid phys encoder\n"); + return; + } + + DPU_DEBUG_CMDENC(cmd_enc, "pp %d\n", phys_enc->hw_pp->idx - PINGPONG_0); + + if (phys_enc->enable_state == DPU_ENC_ENABLED) { + DPU_ERROR("already enabled\n"); + return; + } + + dpu_encoder_phys_cmd_enable_helper(phys_enc); + phys_enc->enable_state = DPU_ENC_ENABLED; +} + +static void _dpu_encoder_phys_cmd_connect_te( + struct dpu_encoder_phys *phys_enc, bool enable) +{ + if (!phys_enc || !phys_enc->hw_pp || + !phys_enc->hw_pp->ops.connect_external_te) + return; + + trace_dpu_enc_phys_cmd_connect_te(DRMID(phys_enc->parent), enable); + phys_enc->hw_pp->ops.connect_external_te(phys_enc->hw_pp, enable); +} + +static void dpu_encoder_phys_cmd_prepare_idle_pc( + struct dpu_encoder_phys *phys_enc) +{ + _dpu_encoder_phys_cmd_connect_te(phys_enc, false); +} + +static int dpu_encoder_phys_cmd_get_line_count( + struct dpu_encoder_phys *phys_enc) +{ + struct dpu_hw_pingpong *hw_pp; + + if (!phys_enc || !phys_enc->hw_pp) + return -EINVAL; + + if (!dpu_encoder_phys_cmd_is_master(phys_enc)) + return -EINVAL; + + hw_pp = phys_enc->hw_pp; + if (!hw_pp->ops.get_line_count) + return -EINVAL; + + return hw_pp->ops.get_line_count(hw_pp); +} + +static void dpu_encoder_phys_cmd_disable(struct dpu_encoder_phys *phys_enc) +{ + struct dpu_encoder_phys_cmd *cmd_enc = + to_dpu_encoder_phys_cmd(phys_enc); + + if (!phys_enc || !phys_enc->hw_pp) { + DPU_ERROR("invalid encoder\n"); + return; + } + DRM_DEBUG_KMS("id:%u pp:%d state:%d\n", DRMID(phys_enc->parent), + phys_enc->hw_pp->idx - PINGPONG_0, + phys_enc->enable_state); + + if (phys_enc->enable_state == DPU_ENC_DISABLED) { + DPU_ERROR_CMDENC(cmd_enc, "already disabled\n"); + return; + } + + if (phys_enc->hw_pp->ops.enable_tearcheck) + phys_enc->hw_pp->ops.enable_tearcheck(phys_enc->hw_pp, false); + phys_enc->enable_state = DPU_ENC_DISABLED; +} + +static void dpu_encoder_phys_cmd_destroy(struct dpu_encoder_phys *phys_enc) +{ + struct dpu_encoder_phys_cmd *cmd_enc = + to_dpu_encoder_phys_cmd(phys_enc); + + if (!phys_enc) { + DPU_ERROR("invalid encoder\n"); + return; + } + kfree(cmd_enc); +} + +static void dpu_encoder_phys_cmd_get_hw_resources( + struct dpu_encoder_phys *phys_enc, + struct dpu_encoder_hw_resources *hw_res, + struct drm_connector_state *conn_state) +{ + struct dpu_encoder_phys_cmd *cmd_enc = + to_dpu_encoder_phys_cmd(phys_enc); + + if (!phys_enc) { + DPU_ERROR("invalid encoder\n"); + return; + } + + if ((phys_enc->intf_idx - INTF_0) >= INTF_MAX) { + DPU_ERROR("invalid intf idx:%d\n", phys_enc->intf_idx); + return; + } + + DPU_DEBUG_CMDENC(cmd_enc, "\n"); + hw_res->intfs[phys_enc->intf_idx - INTF_0] = INTF_MODE_CMD; +} + +static void dpu_encoder_phys_cmd_prepare_for_kickoff( + struct dpu_encoder_phys *phys_enc, + struct dpu_encoder_kickoff_params *params) +{ + struct dpu_encoder_phys_cmd *cmd_enc = + to_dpu_encoder_phys_cmd(phys_enc); + int ret; + + if (!phys_enc || !phys_enc->hw_pp) { + DPU_ERROR("invalid encoder\n"); + return; + } + DRM_DEBUG_KMS("id:%u pp:%d pending_cnt:%d\n", DRMID(phys_enc->parent), + phys_enc->hw_pp->idx - PINGPONG_0, + atomic_read(&phys_enc->pending_kickoff_cnt)); + + /* + * Mark kickoff request as outstanding. If there are more than one, + * outstanding, then we have to wait for the previous one to complete + */ + ret = _dpu_encoder_phys_cmd_wait_for_idle(phys_enc); + if (ret) { + /* force pending_kickoff_cnt 0 to discard failed kickoff */ + atomic_set(&phys_enc->pending_kickoff_cnt, 0); + DRM_ERROR("failed wait_for_idle: id:%u ret:%d pp:%d\n", + DRMID(phys_enc->parent), ret, + phys_enc->hw_pp->idx - PINGPONG_0); + } + + DPU_DEBUG_CMDENC(cmd_enc, "pp:%d pending_cnt %d\n", + phys_enc->hw_pp->idx - PINGPONG_0, + atomic_read(&phys_enc->pending_kickoff_cnt)); +} + +static int _dpu_encoder_phys_cmd_wait_for_ctl_start( + struct dpu_encoder_phys *phys_enc) +{ + struct dpu_encoder_phys_cmd *cmd_enc = + to_dpu_encoder_phys_cmd(phys_enc); + struct dpu_encoder_wait_info wait_info; + int ret; + + if (!phys_enc || !phys_enc->hw_ctl) { + DPU_ERROR("invalid argument(s)\n"); + return -EINVAL; + } + + wait_info.wq = &phys_enc->pending_kickoff_wq; + wait_info.atomic_cnt = &phys_enc->pending_ctlstart_cnt; + wait_info.timeout_ms = KICKOFF_TIMEOUT_MS; + + ret = dpu_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_CTL_START, + &wait_info); + if (ret == -ETIMEDOUT) { + DPU_ERROR_CMDENC(cmd_enc, "ctl start interrupt wait failed\n"); + ret = -EINVAL; + } else if (!ret) + ret = 0; + + return ret; +} + +static int dpu_encoder_phys_cmd_wait_for_tx_complete( + struct dpu_encoder_phys *phys_enc) +{ + int rc; + struct dpu_encoder_phys_cmd *cmd_enc; + + if (!phys_enc) + return -EINVAL; + + cmd_enc = to_dpu_encoder_phys_cmd(phys_enc); + + rc = _dpu_encoder_phys_cmd_wait_for_idle(phys_enc); + if (rc) { + DRM_ERROR("failed wait_for_idle: id:%u ret:%d intf:%d\n", + DRMID(phys_enc->parent), rc, + phys_enc->intf_idx - INTF_0); + } + + return rc; +} + +static int dpu_encoder_phys_cmd_wait_for_commit_done( + struct dpu_encoder_phys *phys_enc) +{ + int rc = 0; + struct dpu_encoder_phys_cmd *cmd_enc; + + if (!phys_enc) + return -EINVAL; + + cmd_enc = to_dpu_encoder_phys_cmd(phys_enc); + + /* only required for master controller */ + if (dpu_encoder_phys_cmd_is_master(phys_enc)) + rc = _dpu_encoder_phys_cmd_wait_for_ctl_start(phys_enc); + + /* required for both controllers */ + if (!rc && cmd_enc->serialize_wait4pp) + dpu_encoder_phys_cmd_prepare_for_kickoff(phys_enc, NULL); + + return rc; +} + +static int dpu_encoder_phys_cmd_wait_for_vblank( + struct dpu_encoder_phys *phys_enc) +{ + int rc = 0; + struct dpu_encoder_phys_cmd *cmd_enc; + struct dpu_encoder_wait_info wait_info; + + if (!phys_enc) + return -EINVAL; + + cmd_enc = to_dpu_encoder_phys_cmd(phys_enc); + + /* only required for master controller */ + if (!dpu_encoder_phys_cmd_is_master(phys_enc)) + return rc; + + wait_info.wq = &cmd_enc->pending_vblank_wq; + wait_info.atomic_cnt = &cmd_enc->pending_vblank_cnt; + wait_info.timeout_ms = _dpu_encoder_phys_cmd_get_idle_timeout(cmd_enc); + + atomic_inc(&cmd_enc->pending_vblank_cnt); + + rc = dpu_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_RDPTR, + &wait_info); + + return rc; +} + +static void dpu_encoder_phys_cmd_handle_post_kickoff( + struct dpu_encoder_phys *phys_enc) +{ + if (!phys_enc) + return; + + /** + * re-enable external TE, either for the first time after enabling + * or if disabled for Autorefresh + */ + _dpu_encoder_phys_cmd_connect_te(phys_enc, true); +} + +static void dpu_encoder_phys_cmd_trigger_start( + struct dpu_encoder_phys *phys_enc) +{ + if (!phys_enc) + return; + + dpu_encoder_helper_trigger_start(phys_enc); +} + +static void dpu_encoder_phys_cmd_init_ops( + struct dpu_encoder_phys_ops *ops) +{ + ops->is_master = dpu_encoder_phys_cmd_is_master; + ops->mode_set = dpu_encoder_phys_cmd_mode_set; + ops->mode_fixup = dpu_encoder_phys_cmd_mode_fixup; + ops->enable = dpu_encoder_phys_cmd_enable; + ops->disable = dpu_encoder_phys_cmd_disable; + ops->destroy = dpu_encoder_phys_cmd_destroy; + ops->get_hw_resources = dpu_encoder_phys_cmd_get_hw_resources; + ops->control_vblank_irq = dpu_encoder_phys_cmd_control_vblank_irq; + ops->wait_for_commit_done = dpu_encoder_phys_cmd_wait_for_commit_done; + ops->prepare_for_kickoff = dpu_encoder_phys_cmd_prepare_for_kickoff; + ops->wait_for_tx_complete = dpu_encoder_phys_cmd_wait_for_tx_complete; + ops->wait_for_vblank = dpu_encoder_phys_cmd_wait_for_vblank; + ops->trigger_start = dpu_encoder_phys_cmd_trigger_start; + ops->needs_single_flush = dpu_encoder_phys_cmd_needs_single_flush; + ops->hw_reset = dpu_encoder_helper_hw_reset; + ops->irq_control = dpu_encoder_phys_cmd_irq_control; + ops->restore = dpu_encoder_phys_cmd_enable_helper; + ops->prepare_idle_pc = dpu_encoder_phys_cmd_prepare_idle_pc; + ops->handle_post_kickoff = dpu_encoder_phys_cmd_handle_post_kickoff; + ops->get_line_count = dpu_encoder_phys_cmd_get_line_count; +} + +struct dpu_encoder_phys *dpu_encoder_phys_cmd_init( + struct dpu_enc_phys_init_params *p) +{ + struct dpu_encoder_phys *phys_enc = NULL; + struct dpu_encoder_phys_cmd *cmd_enc = NULL; + struct dpu_hw_mdp *hw_mdp; + struct dpu_encoder_irq *irq; + int i, ret = 0; + + DPU_DEBUG("intf %d\n", p->intf_idx - INTF_0); + + cmd_enc = kzalloc(sizeof(*cmd_enc), GFP_KERNEL); + if (!cmd_enc) { + ret = -ENOMEM; + DPU_ERROR("failed to allocate\n"); + goto fail; + } + phys_enc = &cmd_enc->base; + + hw_mdp = dpu_rm_get_mdp(&p->dpu_kms->rm); + if (IS_ERR_OR_NULL(hw_mdp)) { + ret = PTR_ERR(hw_mdp); + DPU_ERROR("failed to get mdptop\n"); + goto fail_mdp_init; + } + phys_enc->hw_mdptop = hw_mdp; + phys_enc->intf_idx = p->intf_idx; + + dpu_encoder_phys_cmd_init_ops(&phys_enc->ops); + phys_enc->parent = p->parent; + phys_enc->parent_ops = p->parent_ops; + phys_enc->dpu_kms = p->dpu_kms; + phys_enc->split_role = p->split_role; + phys_enc->intf_mode = INTF_MODE_CMD; + phys_enc->enc_spinlock = p->enc_spinlock; + cmd_enc->stream_sel = 0; + phys_enc->enable_state = DPU_ENC_DISABLED; + for (i = 0; i < INTR_IDX_MAX; i++) { + irq = &phys_enc->irq[i]; + INIT_LIST_HEAD(&irq->cb.list); + irq->irq_idx = -EINVAL; + irq->hw_idx = -EINVAL; + irq->cb.arg = phys_enc; + } + + irq = &phys_enc->irq[INTR_IDX_CTL_START]; + irq->name = "ctl_start"; + irq->intr_type = DPU_IRQ_TYPE_CTL_START; + irq->intr_idx = INTR_IDX_CTL_START; + irq->cb.func = dpu_encoder_phys_cmd_ctl_start_irq; + + irq = &phys_enc->irq[INTR_IDX_PINGPONG]; + irq->name = "pp_done"; + irq->intr_type = DPU_IRQ_TYPE_PING_PONG_COMP; + irq->intr_idx = INTR_IDX_PINGPONG; + irq->cb.func = dpu_encoder_phys_cmd_pp_tx_done_irq; + + irq = &phys_enc->irq[INTR_IDX_RDPTR]; + irq->name = "pp_rd_ptr"; + irq->intr_type = DPU_IRQ_TYPE_PING_PONG_RD_PTR; + irq->intr_idx = INTR_IDX_RDPTR; + irq->cb.func = dpu_encoder_phys_cmd_pp_rd_ptr_irq; + + irq = &phys_enc->irq[INTR_IDX_UNDERRUN]; + irq->name = "underrun"; + irq->intr_type = DPU_IRQ_TYPE_INTF_UNDER_RUN; + irq->intr_idx = INTR_IDX_UNDERRUN; + irq->cb.func = dpu_encoder_phys_cmd_underrun_irq; + + atomic_set(&phys_enc->vblank_refcount, 0); + atomic_set(&phys_enc->pending_kickoff_cnt, 0); + atomic_set(&phys_enc->pending_ctlstart_cnt, 0); + atomic_set(&cmd_enc->pending_vblank_cnt, 0); + init_waitqueue_head(&phys_enc->pending_kickoff_wq); + init_waitqueue_head(&cmd_enc->pending_vblank_wq); + + DPU_DEBUG_CMDENC(cmd_enc, "created\n"); + + return phys_enc; + +fail_mdp_init: + kfree(cmd_enc); +fail: + return ERR_PTR(ret); +} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c new file mode 100644 index 0000000000000..14fc7c2a6bb76 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c @@ -0,0 +1,922 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ +#include "dpu_encoder_phys.h" +#include "dpu_hw_interrupts.h" +#include "dpu_core_irq.h" +#include "dpu_formats.h" +#include "dpu_trace.h" + +#define DPU_DEBUG_VIDENC(e, fmt, ...) DPU_DEBUG("enc%d intf%d " fmt, \ + (e) && (e)->base.parent ? \ + (e)->base.parent->base.id : -1, \ + (e) && (e)->hw_intf ? \ + (e)->hw_intf->idx - INTF_0 : -1, ##__VA_ARGS__) + +#define DPU_ERROR_VIDENC(e, fmt, ...) DPU_ERROR("enc%d intf%d " fmt, \ + (e) && (e)->base.parent ? \ + (e)->base.parent->base.id : -1, \ + (e) && (e)->hw_intf ? \ + (e)->hw_intf->idx - INTF_0 : -1, ##__VA_ARGS__) + +#define to_dpu_encoder_phys_vid(x) \ + container_of(x, struct dpu_encoder_phys_vid, base) + +static bool dpu_encoder_phys_vid_is_master( + struct dpu_encoder_phys *phys_enc) +{ + bool ret = false; + + if (phys_enc->split_role != ENC_ROLE_SLAVE) + ret = true; + + return ret; +} + +static void drm_mode_to_intf_timing_params( + const struct dpu_encoder_phys_vid *vid_enc, + const struct drm_display_mode *mode, + struct intf_timing_params *timing) +{ + memset(timing, 0, sizeof(*timing)); + + if ((mode->htotal < mode->hsync_end) + || (mode->hsync_start < mode->hdisplay) + || (mode->vtotal < mode->vsync_end) + || (mode->vsync_start < mode->vdisplay) + || (mode->hsync_end < mode->hsync_start) + || (mode->vsync_end < mode->vsync_start)) { + DPU_ERROR( + "invalid params - hstart:%d,hend:%d,htot:%d,hdisplay:%d\n", + mode->hsync_start, mode->hsync_end, + mode->htotal, mode->hdisplay); + DPU_ERROR("vstart:%d,vend:%d,vtot:%d,vdisplay:%d\n", + mode->vsync_start, mode->vsync_end, + mode->vtotal, mode->vdisplay); + return; + } + + /* + * https://www.kernel.org/doc/htmldocs/drm/ch02s05.html + * Active Region Front Porch Sync Back Porch + * <-----------------><------------><-----><-----------> + * <- [hv]display ---> + * <--------- [hv]sync_start ------> + * <----------------- [hv]sync_end -------> + * <---------------------------- [hv]total -------------> + */ + timing->width = mode->hdisplay; /* active width */ + timing->height = mode->vdisplay; /* active height */ + timing->xres = timing->width; + timing->yres = timing->height; + timing->h_back_porch = mode->htotal - mode->hsync_end; + timing->h_front_porch = mode->hsync_start - mode->hdisplay; + timing->v_back_porch = mode->vtotal - mode->vsync_end; + timing->v_front_porch = mode->vsync_start - mode->vdisplay; + timing->hsync_pulse_width = mode->hsync_end - mode->hsync_start; + timing->vsync_pulse_width = mode->vsync_end - mode->vsync_start; + timing->hsync_polarity = (mode->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0; + timing->vsync_polarity = (mode->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0; + timing->border_clr = 0; + timing->underflow_clr = 0xff; + timing->hsync_skew = mode->hskew; + + /* DSI controller cannot handle active-low sync signals. */ + if (vid_enc->hw_intf->cap->type == INTF_DSI) { + timing->hsync_polarity = 0; + timing->vsync_polarity = 0; + } + + /* + * For edp only: + * DISPLAY_V_START = (VBP * HCYCLE) + HBP + * DISPLAY_V_END = (VBP + VACTIVE) * HCYCLE - 1 - HFP + */ + /* + * if (vid_enc->hw->cap->type == INTF_EDP) { + * display_v_start += mode->htotal - mode->hsync_start; + * display_v_end -= mode->hsync_start - mode->hdisplay; + * } + */ +} + +static inline u32 get_horizontal_total(const struct intf_timing_params *timing) +{ + u32 active = timing->xres; + u32 inactive = + timing->h_back_porch + timing->h_front_porch + + timing->hsync_pulse_width; + return active + inactive; +} + +static inline u32 get_vertical_total(const struct intf_timing_params *timing) +{ + u32 active = timing->yres; + u32 inactive = + timing->v_back_porch + timing->v_front_porch + + timing->vsync_pulse_width; + return active + inactive; +} + +/* + * programmable_fetch_get_num_lines: + * Number of fetch lines in vertical front porch + * @timing: Pointer to the intf timing information for the requested mode + * + * Returns the number of fetch lines in vertical front porch at which mdp + * can start fetching the next frame. + * + * Number of needed prefetch lines is anything that cannot be absorbed in the + * start of frame time (back porch + vsync pulse width). + * + * Some panels have very large VFP, however we only need a total number of + * lines based on the chip worst case latencies. + */ +static u32 programmable_fetch_get_num_lines( + struct dpu_encoder_phys_vid *vid_enc, + const struct intf_timing_params *timing) +{ + u32 worst_case_needed_lines = + vid_enc->hw_intf->cap->prog_fetch_lines_worst_case; + u32 start_of_frame_lines = + timing->v_back_porch + timing->vsync_pulse_width; + u32 needed_vfp_lines = worst_case_needed_lines - start_of_frame_lines; + u32 actual_vfp_lines = 0; + + /* Fetch must be outside active lines, otherwise undefined. */ + if (start_of_frame_lines >= worst_case_needed_lines) { + DPU_DEBUG_VIDENC(vid_enc, + "prog fetch is not needed, large vbp+vsw\n"); + actual_vfp_lines = 0; + } else if (timing->v_front_porch < needed_vfp_lines) { + /* Warn fetch needed, but not enough porch in panel config */ + pr_warn_once + ("low vbp+vfp may lead to perf issues in some cases\n"); + DPU_DEBUG_VIDENC(vid_enc, + "less vfp than fetch req, using entire vfp\n"); + actual_vfp_lines = timing->v_front_porch; + } else { + DPU_DEBUG_VIDENC(vid_enc, "room in vfp for needed prefetch\n"); + actual_vfp_lines = needed_vfp_lines; + } + + DPU_DEBUG_VIDENC(vid_enc, + "v_front_porch %u v_back_porch %u vsync_pulse_width %u\n", + timing->v_front_porch, timing->v_back_porch, + timing->vsync_pulse_width); + DPU_DEBUG_VIDENC(vid_enc, + "wc_lines %u needed_vfp_lines %u actual_vfp_lines %u\n", + worst_case_needed_lines, needed_vfp_lines, actual_vfp_lines); + + return actual_vfp_lines; +} + +/* + * programmable_fetch_config: Programs HW to prefetch lines by offsetting + * the start of fetch into the vertical front porch for cases where the + * vsync pulse width and vertical back porch time is insufficient + * + * Gets # of lines to pre-fetch, then calculate VSYNC counter value. + * HW layer requires VSYNC counter of first pixel of tgt VFP line. + * + * @timing: Pointer to the intf timing information for the requested mode + */ +static void programmable_fetch_config(struct dpu_encoder_phys *phys_enc, + const struct intf_timing_params *timing) +{ + struct dpu_encoder_phys_vid *vid_enc = + to_dpu_encoder_phys_vid(phys_enc); + struct intf_prog_fetch f = { 0 }; + u32 vfp_fetch_lines = 0; + u32 horiz_total = 0; + u32 vert_total = 0; + u32 vfp_fetch_start_vsync_counter = 0; + unsigned long lock_flags; + + if (WARN_ON_ONCE(!vid_enc->hw_intf->ops.setup_prg_fetch)) + return; + + vfp_fetch_lines = programmable_fetch_get_num_lines(vid_enc, timing); + if (vfp_fetch_lines) { + vert_total = get_vertical_total(timing); + horiz_total = get_horizontal_total(timing); + vfp_fetch_start_vsync_counter = + (vert_total - vfp_fetch_lines) * horiz_total + 1; + f.enable = 1; + f.fetch_start = vfp_fetch_start_vsync_counter; + } + + DPU_DEBUG_VIDENC(vid_enc, + "vfp_fetch_lines %u vfp_fetch_start_vsync_counter %u\n", + vfp_fetch_lines, vfp_fetch_start_vsync_counter); + + spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags); + vid_enc->hw_intf->ops.setup_prg_fetch(vid_enc->hw_intf, &f); + spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags); +} + +static bool dpu_encoder_phys_vid_mode_fixup( + struct dpu_encoder_phys *phys_enc, + const struct drm_display_mode *mode, + struct drm_display_mode *adj_mode) +{ + if (phys_enc) + DPU_DEBUG_VIDENC(to_dpu_encoder_phys_vid(phys_enc), "\n"); + + /* + * Modifying mode has consequences when the mode comes back to us + */ + return true; +} + +static void dpu_encoder_phys_vid_setup_timing_engine( + struct dpu_encoder_phys *phys_enc) +{ + struct dpu_encoder_phys_vid *vid_enc; + struct drm_display_mode mode; + struct intf_timing_params timing_params = { 0 }; + const struct dpu_format *fmt = NULL; + u32 fmt_fourcc = DRM_FORMAT_RGB888; + unsigned long lock_flags; + struct dpu_hw_intf_cfg intf_cfg = { 0 }; + + if (!phys_enc || !phys_enc->hw_ctl->ops.setup_intf_cfg) { + DPU_ERROR("invalid encoder %d\n", phys_enc != 0); + return; + } + + mode = phys_enc->cached_mode; + vid_enc = to_dpu_encoder_phys_vid(phys_enc); + if (!vid_enc->hw_intf->ops.setup_timing_gen) { + DPU_ERROR("timing engine setup is not supported\n"); + return; + } + + DPU_DEBUG_VIDENC(vid_enc, "enabling mode:\n"); + drm_mode_debug_printmodeline(&mode); + + if (phys_enc->split_role != ENC_ROLE_SOLO) { + mode.hdisplay >>= 1; + mode.htotal >>= 1; + mode.hsync_start >>= 1; + mode.hsync_end >>= 1; + + DPU_DEBUG_VIDENC(vid_enc, + "split_role %d, halve horizontal %d %d %d %d\n", + phys_enc->split_role, + mode.hdisplay, mode.htotal, + mode.hsync_start, mode.hsync_end); + } + + drm_mode_to_intf_timing_params(vid_enc, &mode, &timing_params); + + fmt = dpu_get_dpu_format(fmt_fourcc); + DPU_DEBUG_VIDENC(vid_enc, "fmt_fourcc 0x%X\n", fmt_fourcc); + + intf_cfg.intf = vid_enc->hw_intf->idx; + intf_cfg.intf_mode_sel = DPU_CTL_MODE_SEL_VID; + intf_cfg.stream_sel = 0; /* Don't care value for video mode */ + intf_cfg.mode_3d = dpu_encoder_helper_get_3d_blend_mode(phys_enc); + + spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags); + vid_enc->hw_intf->ops.setup_timing_gen(vid_enc->hw_intf, + &timing_params, fmt); + phys_enc->hw_ctl->ops.setup_intf_cfg(phys_enc->hw_ctl, &intf_cfg); + spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags); + + programmable_fetch_config(phys_enc, &timing_params); + + vid_enc->timing_params = timing_params; +} + +static void dpu_encoder_phys_vid_vblank_irq(void *arg, int irq_idx) +{ + struct dpu_encoder_phys *phys_enc = arg; + struct dpu_hw_ctl *hw_ctl; + unsigned long lock_flags; + u32 flush_register = 0; + int new_cnt = -1, old_cnt = -1; + + if (!phys_enc) + return; + + hw_ctl = phys_enc->hw_ctl; + if (!hw_ctl) + return; + + DPU_ATRACE_BEGIN("vblank_irq"); + + if (phys_enc->parent_ops->handle_vblank_virt) + phys_enc->parent_ops->handle_vblank_virt(phys_enc->parent, + phys_enc); + + old_cnt = atomic_read(&phys_enc->pending_kickoff_cnt); + + /* + * only decrement the pending flush count if we've actually flushed + * hardware. due to sw irq latency, vblank may have already happened + * so we need to double-check with hw that it accepted the flush bits + */ + spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags); + if (hw_ctl && hw_ctl->ops.get_flush_register) + flush_register = hw_ctl->ops.get_flush_register(hw_ctl); + + if (flush_register == 0) + new_cnt = atomic_add_unless(&phys_enc->pending_kickoff_cnt, + -1, 0); + spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags); + + /* Signal any waiting atomic commit thread */ + wake_up_all(&phys_enc->pending_kickoff_wq); + DPU_ATRACE_END("vblank_irq"); +} + +static void dpu_encoder_phys_vid_underrun_irq(void *arg, int irq_idx) +{ + struct dpu_encoder_phys *phys_enc = arg; + + if (!phys_enc) + return; + + if (phys_enc->parent_ops->handle_underrun_virt) + phys_enc->parent_ops->handle_underrun_virt(phys_enc->parent, + phys_enc); +} + +static bool _dpu_encoder_phys_is_dual_ctl(struct dpu_encoder_phys *phys_enc) +{ + if (!phys_enc) + return false; + + if (phys_enc->topology_name == DPU_RM_TOPOLOGY_DUALPIPE) + return true; + + return false; +} + +static bool dpu_encoder_phys_vid_needs_single_flush( + struct dpu_encoder_phys *phys_enc) +{ + return (phys_enc && _dpu_encoder_phys_is_dual_ctl(phys_enc)); +} + +static void _dpu_encoder_phys_vid_setup_irq_hw_idx( + struct dpu_encoder_phys *phys_enc) +{ + struct dpu_encoder_irq *irq; + + /* + * Initialize irq->hw_idx only when irq is not registered. + * Prevent invalidating irq->irq_idx as modeset may be + * called many times during dfps. + */ + + irq = &phys_enc->irq[INTR_IDX_VSYNC]; + if (irq->irq_idx < 0) + irq->hw_idx = phys_enc->intf_idx; + + irq = &phys_enc->irq[INTR_IDX_UNDERRUN]; + if (irq->irq_idx < 0) + irq->hw_idx = phys_enc->intf_idx; +} + +static void dpu_encoder_phys_vid_mode_set( + struct dpu_encoder_phys *phys_enc, + struct drm_display_mode *mode, + struct drm_display_mode *adj_mode) +{ + struct dpu_rm *rm; + struct dpu_rm_hw_iter iter; + int i, instance; + struct dpu_encoder_phys_vid *vid_enc; + + if (!phys_enc || !phys_enc->dpu_kms) { + DPU_ERROR("invalid encoder/kms\n"); + return; + } + + rm = &phys_enc->dpu_kms->rm; + vid_enc = to_dpu_encoder_phys_vid(phys_enc); + + if (adj_mode) { + phys_enc->cached_mode = *adj_mode; + drm_mode_debug_printmodeline(adj_mode); + DPU_DEBUG_VIDENC(vid_enc, "caching mode:\n"); + } + + instance = phys_enc->split_role == ENC_ROLE_SLAVE ? 1 : 0; + + /* Retrieve previously allocated HW Resources. Shouldn't fail */ + dpu_rm_init_hw_iter(&iter, phys_enc->parent->base.id, DPU_HW_BLK_CTL); + for (i = 0; i <= instance; i++) { + if (dpu_rm_get_hw(rm, &iter)) + phys_enc->hw_ctl = (struct dpu_hw_ctl *)iter.hw; + } + if (IS_ERR_OR_NULL(phys_enc->hw_ctl)) { + DPU_ERROR_VIDENC(vid_enc, "failed to init ctl, %ld\n", + PTR_ERR(phys_enc->hw_ctl)); + phys_enc->hw_ctl = NULL; + return; + } + + _dpu_encoder_phys_vid_setup_irq_hw_idx(phys_enc); +} + +static int dpu_encoder_phys_vid_control_vblank_irq( + struct dpu_encoder_phys *phys_enc, + bool enable) +{ + int ret = 0; + struct dpu_encoder_phys_vid *vid_enc; + int refcount; + + if (!phys_enc) { + DPU_ERROR("invalid encoder\n"); + return -EINVAL; + } + + refcount = atomic_read(&phys_enc->vblank_refcount); + vid_enc = to_dpu_encoder_phys_vid(phys_enc); + + /* Slave encoders don't report vblank */ + if (!dpu_encoder_phys_vid_is_master(phys_enc)) + goto end; + + /* protect against negative */ + if (!enable && refcount == 0) { + ret = -EINVAL; + goto end; + } + + DRM_DEBUG_KMS("id:%u enable=%d/%d\n", DRMID(phys_enc->parent), enable, + atomic_read(&phys_enc->vblank_refcount)); + + if (enable && atomic_inc_return(&phys_enc->vblank_refcount) == 1) + ret = dpu_encoder_helper_register_irq(phys_enc, INTR_IDX_VSYNC); + else if (!enable && atomic_dec_return(&phys_enc->vblank_refcount) == 0) + ret = dpu_encoder_helper_unregister_irq(phys_enc, + INTR_IDX_VSYNC); + +end: + if (ret) { + DRM_ERROR("failed: id:%u intf:%d ret:%d enable:%d refcnt:%d\n", + DRMID(phys_enc->parent), + vid_enc->hw_intf->idx - INTF_0, ret, enable, + refcount); + } + return ret; +} + +static void dpu_encoder_phys_vid_enable(struct dpu_encoder_phys *phys_enc) +{ + struct msm_drm_private *priv; + struct dpu_encoder_phys_vid *vid_enc; + struct dpu_hw_intf *intf; + struct dpu_hw_ctl *ctl; + u32 flush_mask = 0; + + if (!phys_enc || !phys_enc->parent || !phys_enc->parent->dev || + !phys_enc->parent->dev->dev_private) { + DPU_ERROR("invalid encoder/device\n"); + return; + } + priv = phys_enc->parent->dev->dev_private; + + vid_enc = to_dpu_encoder_phys_vid(phys_enc); + intf = vid_enc->hw_intf; + ctl = phys_enc->hw_ctl; + if (!vid_enc->hw_intf || !phys_enc->hw_ctl) { + DPU_ERROR("invalid hw_intf %d hw_ctl %d\n", + vid_enc->hw_intf != 0, phys_enc->hw_ctl != 0); + return; + } + + DPU_DEBUG_VIDENC(vid_enc, "\n"); + + if (WARN_ON(!vid_enc->hw_intf->ops.enable_timing)) + return; + + dpu_encoder_helper_split_config(phys_enc, vid_enc->hw_intf->idx); + + dpu_encoder_phys_vid_setup_timing_engine(phys_enc); + + /* + * For single flush cases (dual-ctl or pp-split), skip setting the + * flush bit for the slave intf, since both intfs use same ctl + * and HW will only flush the master. + */ + if (dpu_encoder_phys_vid_needs_single_flush(phys_enc) && + !dpu_encoder_phys_vid_is_master(phys_enc)) + goto skip_flush; + + ctl->ops.get_bitmask_intf(ctl, &flush_mask, intf->idx); + ctl->ops.update_pending_flush(ctl, flush_mask); + +skip_flush: + DPU_DEBUG_VIDENC(vid_enc, "update pending flush ctl %d flush_mask %x\n", + ctl->idx - CTL_0, flush_mask); + + /* ctl_flush & timing engine enable will be triggered by framework */ + if (phys_enc->enable_state == DPU_ENC_DISABLED) + phys_enc->enable_state = DPU_ENC_ENABLING; +} + +static void dpu_encoder_phys_vid_destroy(struct dpu_encoder_phys *phys_enc) +{ + struct dpu_encoder_phys_vid *vid_enc; + + if (!phys_enc) { + DPU_ERROR("invalid encoder\n"); + return; + } + + vid_enc = to_dpu_encoder_phys_vid(phys_enc); + DPU_DEBUG_VIDENC(vid_enc, "\n"); + kfree(vid_enc); +} + +static void dpu_encoder_phys_vid_get_hw_resources( + struct dpu_encoder_phys *phys_enc, + struct dpu_encoder_hw_resources *hw_res, + struct drm_connector_state *conn_state) +{ + struct dpu_encoder_phys_vid *vid_enc; + + if (!phys_enc || !hw_res) { + DPU_ERROR("invalid arg(s), enc %d hw_res %d conn_state %d\n", + phys_enc != 0, hw_res != 0, conn_state != 0); + return; + } + + vid_enc = to_dpu_encoder_phys_vid(phys_enc); + if (!vid_enc->hw_intf) { + DPU_ERROR("invalid arg(s), hw_intf\n"); + return; + } + + DPU_DEBUG_VIDENC(vid_enc, "\n"); + hw_res->intfs[vid_enc->hw_intf->idx - INTF_0] = INTF_MODE_VIDEO; +} + +static int _dpu_encoder_phys_vid_wait_for_vblank( + struct dpu_encoder_phys *phys_enc, bool notify) +{ + struct dpu_encoder_wait_info wait_info; + int ret; + + if (!phys_enc) { + pr_err("invalid encoder\n"); + return -EINVAL; + } + + wait_info.wq = &phys_enc->pending_kickoff_wq; + wait_info.atomic_cnt = &phys_enc->pending_kickoff_cnt; + wait_info.timeout_ms = KICKOFF_TIMEOUT_MS; + + if (!dpu_encoder_phys_vid_is_master(phys_enc)) { + if (notify && phys_enc->parent_ops->handle_frame_done) + phys_enc->parent_ops->handle_frame_done( + phys_enc->parent, phys_enc, + DPU_ENCODER_FRAME_EVENT_DONE); + return 0; + } + + /* Wait for kickoff to complete */ + ret = dpu_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_VSYNC, + &wait_info); + + if (ret == -ETIMEDOUT) { + dpu_encoder_helper_report_irq_timeout(phys_enc, INTR_IDX_VSYNC); + } else if (!ret && notify && phys_enc->parent_ops->handle_frame_done) + phys_enc->parent_ops->handle_frame_done( + phys_enc->parent, phys_enc, + DPU_ENCODER_FRAME_EVENT_DONE); + + return ret; +} + +static int dpu_encoder_phys_vid_wait_for_vblank( + struct dpu_encoder_phys *phys_enc) +{ + return _dpu_encoder_phys_vid_wait_for_vblank(phys_enc, true); +} + +static void dpu_encoder_phys_vid_prepare_for_kickoff( + struct dpu_encoder_phys *phys_enc, + struct dpu_encoder_kickoff_params *params) +{ + struct dpu_encoder_phys_vid *vid_enc; + struct dpu_hw_ctl *ctl; + int rc; + + if (!phys_enc || !params) { + DPU_ERROR("invalid encoder/parameters\n"); + return; + } + vid_enc = to_dpu_encoder_phys_vid(phys_enc); + + ctl = phys_enc->hw_ctl; + if (!ctl || !ctl->ops.wait_reset_status) + return; + + /* + * hw supports hardware initiated ctl reset, so before we kickoff a new + * frame, need to check and wait for hw initiated ctl reset completion + */ + rc = ctl->ops.wait_reset_status(ctl); + if (rc) { + DPU_ERROR_VIDENC(vid_enc, "ctl %d reset failure: %d\n", + ctl->idx, rc); + dpu_encoder_helper_unregister_irq(phys_enc, INTR_IDX_VSYNC); + dpu_dbg_dump(false, __func__, true, true); + } +} + +static void dpu_encoder_phys_vid_disable(struct dpu_encoder_phys *phys_enc) +{ + struct msm_drm_private *priv; + struct dpu_encoder_phys_vid *vid_enc; + unsigned long lock_flags; + int ret; + + if (!phys_enc || !phys_enc->parent || !phys_enc->parent->dev || + !phys_enc->parent->dev->dev_private) { + DPU_ERROR("invalid encoder/device\n"); + return; + } + priv = phys_enc->parent->dev->dev_private; + + vid_enc = to_dpu_encoder_phys_vid(phys_enc); + if (!vid_enc->hw_intf || !phys_enc->hw_ctl) { + DPU_ERROR("invalid hw_intf %d hw_ctl %d\n", + vid_enc->hw_intf != 0, phys_enc->hw_ctl != 0); + return; + } + + DPU_DEBUG_VIDENC(vid_enc, "\n"); + + if (WARN_ON(!vid_enc->hw_intf->ops.enable_timing)) + return; + + if (phys_enc->enable_state == DPU_ENC_DISABLED) { + DPU_ERROR("already disabled\n"); + return; + } + + spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags); + vid_enc->hw_intf->ops.enable_timing(vid_enc->hw_intf, 0); + if (dpu_encoder_phys_vid_is_master(phys_enc)) + dpu_encoder_phys_inc_pending(phys_enc); + spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags); + + /* + * Wait for a vsync so we know the ENABLE=0 latched before + * the (connector) source of the vsync's gets disabled, + * otherwise we end up in a funny state if we re-enable + * before the disable latches, which results that some of + * the settings changes for the new modeset (like new + * scanout buffer) don't latch properly.. + */ + if (dpu_encoder_phys_vid_is_master(phys_enc)) { + ret = _dpu_encoder_phys_vid_wait_for_vblank(phys_enc, false); + if (ret) { + atomic_set(&phys_enc->pending_kickoff_cnt, 0); + DRM_ERROR("wait disable failed: id:%u intf:%d ret:%d\n", + DRMID(phys_enc->parent), + vid_enc->hw_intf->idx - INTF_0, ret); + } + } + + phys_enc->enable_state = DPU_ENC_DISABLED; +} + +static void dpu_encoder_phys_vid_handle_post_kickoff( + struct dpu_encoder_phys *phys_enc) +{ + unsigned long lock_flags; + struct dpu_encoder_phys_vid *vid_enc; + + if (!phys_enc) { + DPU_ERROR("invalid encoder\n"); + return; + } + + vid_enc = to_dpu_encoder_phys_vid(phys_enc); + DPU_DEBUG_VIDENC(vid_enc, "enable_state %d\n", phys_enc->enable_state); + + /* + * Video mode must flush CTL before enabling timing engine + * Video encoders need to turn on their interfaces now + */ + if (phys_enc->enable_state == DPU_ENC_ENABLING) { + trace_dpu_enc_phys_vid_post_kickoff(DRMID(phys_enc->parent), + vid_enc->hw_intf->idx - INTF_0); + spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags); + vid_enc->hw_intf->ops.enable_timing(vid_enc->hw_intf, 1); + spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags); + phys_enc->enable_state = DPU_ENC_ENABLED; + } +} + +static void dpu_encoder_phys_vid_irq_control(struct dpu_encoder_phys *phys_enc, + bool enable) +{ + struct dpu_encoder_phys_vid *vid_enc; + int ret; + + if (!phys_enc) + return; + + vid_enc = to_dpu_encoder_phys_vid(phys_enc); + + trace_dpu_enc_phys_vid_irq_ctrl(DRMID(phys_enc->parent), + vid_enc->hw_intf->idx - INTF_0, + enable, + atomic_read(&phys_enc->vblank_refcount)); + + if (enable) { + ret = dpu_encoder_phys_vid_control_vblank_irq(phys_enc, true); + if (ret) + return; + + dpu_encoder_helper_register_irq(phys_enc, INTR_IDX_UNDERRUN); + } else { + dpu_encoder_phys_vid_control_vblank_irq(phys_enc, false); + dpu_encoder_helper_unregister_irq(phys_enc, INTR_IDX_UNDERRUN); + } +} + +static void dpu_encoder_phys_vid_setup_misr(struct dpu_encoder_phys *phys_enc, + bool enable, u32 frame_count) +{ + struct dpu_encoder_phys_vid *vid_enc; + + if (!phys_enc) + return; + vid_enc = to_dpu_encoder_phys_vid(phys_enc); + + if (vid_enc->hw_intf && vid_enc->hw_intf->ops.setup_misr) + vid_enc->hw_intf->ops.setup_misr(vid_enc->hw_intf, + enable, frame_count); +} + +static u32 dpu_encoder_phys_vid_collect_misr(struct dpu_encoder_phys *phys_enc) +{ + struct dpu_encoder_phys_vid *vid_enc; + + if (!phys_enc) + return 0; + vid_enc = to_dpu_encoder_phys_vid(phys_enc); + + return vid_enc->hw_intf && vid_enc->hw_intf->ops.collect_misr ? + vid_enc->hw_intf->ops.collect_misr(vid_enc->hw_intf) : 0; +} + +static int dpu_encoder_phys_vid_get_line_count( + struct dpu_encoder_phys *phys_enc) +{ + struct dpu_encoder_phys_vid *vid_enc; + + if (!phys_enc) + return -EINVAL; + + if (!dpu_encoder_phys_vid_is_master(phys_enc)) + return -EINVAL; + + vid_enc = to_dpu_encoder_phys_vid(phys_enc); + if (!vid_enc->hw_intf || !vid_enc->hw_intf->ops.get_line_count) + return -EINVAL; + + return vid_enc->hw_intf->ops.get_line_count(vid_enc->hw_intf); +} + +static void dpu_encoder_phys_vid_init_ops(struct dpu_encoder_phys_ops *ops) +{ + ops->is_master = dpu_encoder_phys_vid_is_master; + ops->mode_set = dpu_encoder_phys_vid_mode_set; + ops->mode_fixup = dpu_encoder_phys_vid_mode_fixup; + ops->enable = dpu_encoder_phys_vid_enable; + ops->disable = dpu_encoder_phys_vid_disable; + ops->destroy = dpu_encoder_phys_vid_destroy; + ops->get_hw_resources = dpu_encoder_phys_vid_get_hw_resources; + ops->control_vblank_irq = dpu_encoder_phys_vid_control_vblank_irq; + ops->wait_for_commit_done = dpu_encoder_phys_vid_wait_for_vblank; + ops->wait_for_vblank = dpu_encoder_phys_vid_wait_for_vblank; + ops->wait_for_tx_complete = dpu_encoder_phys_vid_wait_for_vblank; + ops->irq_control = dpu_encoder_phys_vid_irq_control; + ops->prepare_for_kickoff = dpu_encoder_phys_vid_prepare_for_kickoff; + ops->handle_post_kickoff = dpu_encoder_phys_vid_handle_post_kickoff; + ops->needs_single_flush = dpu_encoder_phys_vid_needs_single_flush; + ops->setup_misr = dpu_encoder_phys_vid_setup_misr; + ops->collect_misr = dpu_encoder_phys_vid_collect_misr; + ops->hw_reset = dpu_encoder_helper_hw_reset; + ops->get_line_count = dpu_encoder_phys_vid_get_line_count; +} + +struct dpu_encoder_phys *dpu_encoder_phys_vid_init( + struct dpu_enc_phys_init_params *p) +{ + struct dpu_encoder_phys *phys_enc = NULL; + struct dpu_encoder_phys_vid *vid_enc = NULL; + struct dpu_rm_hw_iter iter; + struct dpu_hw_mdp *hw_mdp; + struct dpu_encoder_irq *irq; + int i, ret = 0; + + if (!p) { + ret = -EINVAL; + goto fail; + } + + vid_enc = kzalloc(sizeof(*vid_enc), GFP_KERNEL); + if (!vid_enc) { + ret = -ENOMEM; + goto fail; + } + + phys_enc = &vid_enc->base; + + hw_mdp = dpu_rm_get_mdp(&p->dpu_kms->rm); + if (IS_ERR_OR_NULL(hw_mdp)) { + ret = PTR_ERR(hw_mdp); + DPU_ERROR("failed to get mdptop\n"); + goto fail; + } + phys_enc->hw_mdptop = hw_mdp; + phys_enc->intf_idx = p->intf_idx; + + /** + * hw_intf resource permanently assigned to this encoder + * Other resources allocated at atomic commit time by use case + */ + dpu_rm_init_hw_iter(&iter, 0, DPU_HW_BLK_INTF); + while (dpu_rm_get_hw(&p->dpu_kms->rm, &iter)) { + struct dpu_hw_intf *hw_intf = (struct dpu_hw_intf *)iter.hw; + + if (hw_intf->idx == p->intf_idx) { + vid_enc->hw_intf = hw_intf; + break; + } + } + + if (!vid_enc->hw_intf) { + ret = -EINVAL; + DPU_ERROR("failed to get hw_intf\n"); + goto fail; + } + + DPU_DEBUG_VIDENC(vid_enc, "\n"); + + dpu_encoder_phys_vid_init_ops(&phys_enc->ops); + phys_enc->parent = p->parent; + phys_enc->parent_ops = p->parent_ops; + phys_enc->dpu_kms = p->dpu_kms; + phys_enc->split_role = p->split_role; + phys_enc->intf_mode = INTF_MODE_VIDEO; + phys_enc->enc_spinlock = p->enc_spinlock; + for (i = 0; i < INTR_IDX_MAX; i++) { + irq = &phys_enc->irq[i]; + INIT_LIST_HEAD(&irq->cb.list); + irq->irq_idx = -EINVAL; + irq->hw_idx = -EINVAL; + irq->cb.arg = phys_enc; + } + + irq = &phys_enc->irq[INTR_IDX_VSYNC]; + irq->name = "vsync_irq"; + irq->intr_type = DPU_IRQ_TYPE_INTF_VSYNC; + irq->intr_idx = INTR_IDX_VSYNC; + irq->cb.func = dpu_encoder_phys_vid_vblank_irq; + + irq = &phys_enc->irq[INTR_IDX_UNDERRUN]; + irq->name = "underrun"; + irq->intr_type = DPU_IRQ_TYPE_INTF_UNDER_RUN; + irq->intr_idx = INTR_IDX_UNDERRUN; + irq->cb.func = dpu_encoder_phys_vid_underrun_irq; + + atomic_set(&phys_enc->vblank_refcount, 0); + atomic_set(&phys_enc->pending_kickoff_cnt, 0); + init_waitqueue_head(&phys_enc->pending_kickoff_wq); + phys_enc->enable_state = DPU_ENC_DISABLED; + + DPU_DEBUG_VIDENC(vid_enc, "created intf idx:%d\n", p->intf_idx); + + return phys_enc; + +fail: + DPU_ERROR("failed to create encoder\n"); + if (vid_enc) + dpu_encoder_phys_vid_destroy(phys_enc); + + return ERR_PTR(ret); +} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c new file mode 100644 index 0000000000000..8189539b06201 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c @@ -0,0 +1,1214 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ + +#include <uapi/drm/drm_fourcc.h> + +#include "msm_media_info.h" +#include "dpu_kms.h" +#include "dpu_formats.h" + +#define DPU_UBWC_META_MACRO_W_H 16 +#define DPU_UBWC_META_BLOCK_SIZE 256 +#define DPU_UBWC_PLANE_SIZE_ALIGNMENT 4096 + +#define DPU_TILE_HEIGHT_DEFAULT 1 +#define DPU_TILE_HEIGHT_TILED 4 +#define DPU_TILE_HEIGHT_UBWC 4 +#define DPU_TILE_HEIGHT_NV12 8 + +#define DPU_MAX_IMG_WIDTH 0x3FFF +#define DPU_MAX_IMG_HEIGHT 0x3FFF + +/** + * DPU supported format packing, bpp, and other format + * information. + * DPU currently only supports interleaved RGB formats + * UBWC support for a pixel format is indicated by the flag, + * there is additional meta data plane for such formats + */ + +#define INTERLEAVED_RGB_FMT(fmt, a, r, g, b, e0, e1, e2, e3, uc, alpha, \ +bp, flg, fm, np) \ +{ \ + .base.pixel_format = DRM_FORMAT_ ## fmt, \ + .fetch_planes = DPU_PLANE_INTERLEAVED, \ + .alpha_enable = alpha, \ + .element = { (e0), (e1), (e2), (e3) }, \ + .bits = { g, b, r, a }, \ + .chroma_sample = DPU_CHROMA_RGB, \ + .unpack_align_msb = 0, \ + .unpack_tight = 1, \ + .unpack_count = uc, \ + .bpp = bp, \ + .fetch_mode = fm, \ + .flag = {(flg)}, \ + .num_planes = np, \ + .tile_height = DPU_TILE_HEIGHT_DEFAULT \ +} + +#define INTERLEAVED_RGB_FMT_TILED(fmt, a, r, g, b, e0, e1, e2, e3, uc, \ +alpha, bp, flg, fm, np, th) \ +{ \ + .base.pixel_format = DRM_FORMAT_ ## fmt, \ + .fetch_planes = DPU_PLANE_INTERLEAVED, \ + .alpha_enable = alpha, \ + .element = { (e0), (e1), (e2), (e3) }, \ + .bits = { g, b, r, a }, \ + .chroma_sample = DPU_CHROMA_RGB, \ + .unpack_align_msb = 0, \ + .unpack_tight = 1, \ + .unpack_count = uc, \ + .bpp = bp, \ + .fetch_mode = fm, \ + .flag = {(flg)}, \ + .num_planes = np, \ + .tile_height = th \ +} + + +#define INTERLEAVED_YUV_FMT(fmt, a, r, g, b, e0, e1, e2, e3, \ +alpha, chroma, count, bp, flg, fm, np) \ +{ \ + .base.pixel_format = DRM_FORMAT_ ## fmt, \ + .fetch_planes = DPU_PLANE_INTERLEAVED, \ + .alpha_enable = alpha, \ + .element = { (e0), (e1), (e2), (e3)}, \ + .bits = { g, b, r, a }, \ + .chroma_sample = chroma, \ + .unpack_align_msb = 0, \ + .unpack_tight = 1, \ + .unpack_count = count, \ + .bpp = bp, \ + .fetch_mode = fm, \ + .flag = {(flg)}, \ + .num_planes = np, \ + .tile_height = DPU_TILE_HEIGHT_DEFAULT \ +} + +#define PSEUDO_YUV_FMT(fmt, a, r, g, b, e0, e1, chroma, flg, fm, np) \ +{ \ + .base.pixel_format = DRM_FORMAT_ ## fmt, \ + .fetch_planes = DPU_PLANE_PSEUDO_PLANAR, \ + .alpha_enable = false, \ + .element = { (e0), (e1), 0, 0 }, \ + .bits = { g, b, r, a }, \ + .chroma_sample = chroma, \ + .unpack_align_msb = 0, \ + .unpack_tight = 1, \ + .unpack_count = 2, \ + .bpp = 2, \ + .fetch_mode = fm, \ + .flag = {(flg)}, \ + .num_planes = np, \ + .tile_height = DPU_TILE_HEIGHT_DEFAULT \ +} + +#define PSEUDO_YUV_FMT_TILED(fmt, a, r, g, b, e0, e1, chroma, \ +flg, fm, np, th) \ +{ \ + .base.pixel_format = DRM_FORMAT_ ## fmt, \ + .fetch_planes = DPU_PLANE_PSEUDO_PLANAR, \ + .alpha_enable = false, \ + .element = { (e0), (e1), 0, 0 }, \ + .bits = { g, b, r, a }, \ + .chroma_sample = chroma, \ + .unpack_align_msb = 0, \ + .unpack_tight = 1, \ + .unpack_count = 2, \ + .bpp = 2, \ + .fetch_mode = fm, \ + .flag = {(flg)}, \ + .num_planes = np, \ + .tile_height = th \ +} + +#define PSEUDO_YUV_FMT_LOOSE(fmt, a, r, g, b, e0, e1, chroma, flg, fm, np)\ +{ \ + .base.pixel_format = DRM_FORMAT_ ## fmt, \ + .fetch_planes = DPU_PLANE_PSEUDO_PLANAR, \ + .alpha_enable = false, \ + .element = { (e0), (e1), 0, 0 }, \ + .bits = { g, b, r, a }, \ + .chroma_sample = chroma, \ + .unpack_align_msb = 1, \ + .unpack_tight = 0, \ + .unpack_count = 2, \ + .bpp = 2, \ + .fetch_mode = fm, \ + .flag = {(flg)}, \ + .num_planes = np, \ + .tile_height = DPU_TILE_HEIGHT_DEFAULT \ +} + +#define PSEUDO_YUV_FMT_LOOSE_TILED(fmt, a, r, g, b, e0, e1, chroma, \ +flg, fm, np, th) \ +{ \ + .base.pixel_format = DRM_FORMAT_ ## fmt, \ + .fetch_planes = DPU_PLANE_PSEUDO_PLANAR, \ + .alpha_enable = false, \ + .element = { (e0), (e1), 0, 0 }, \ + .bits = { g, b, r, a }, \ + .chroma_sample = chroma, \ + .unpack_align_msb = 1, \ + .unpack_tight = 0, \ + .unpack_count = 2, \ + .bpp = 2, \ + .fetch_mode = fm, \ + .flag = {(flg)}, \ + .num_planes = np, \ + .tile_height = th \ +} + + +#define PLANAR_YUV_FMT(fmt, a, r, g, b, e0, e1, e2, alpha, chroma, bp, \ +flg, fm, np) \ +{ \ + .base.pixel_format = DRM_FORMAT_ ## fmt, \ + .fetch_planes = DPU_PLANE_PLANAR, \ + .alpha_enable = alpha, \ + .element = { (e0), (e1), (e2), 0 }, \ + .bits = { g, b, r, a }, \ + .chroma_sample = chroma, \ + .unpack_align_msb = 0, \ + .unpack_tight = 1, \ + .unpack_count = 1, \ + .bpp = bp, \ + .fetch_mode = fm, \ + .flag = {(flg)}, \ + .num_planes = np, \ + .tile_height = DPU_TILE_HEIGHT_DEFAULT \ +} + +/* + * struct dpu_media_color_map - maps drm format to media format + * @format: DRM base pixel format + * @color: Media API color related to DRM format + */ +struct dpu_media_color_map { + uint32_t format; + uint32_t color; +}; + +static const struct dpu_format dpu_format_map[] = { + INTERLEAVED_RGB_FMT(ARGB8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, + true, 4, 0, + DPU_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(ABGR8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + true, 4, 0, + DPU_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(XBGR8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + true, 4, 0, + DPU_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(RGBA8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, + true, 4, 0, + DPU_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(BGRA8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, + true, 4, 0, + DPU_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(BGRX8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, + false, 4, 0, + DPU_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(XRGB8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, + false, 4, 0, + DPU_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(RGBX8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, + false, 4, 0, + DPU_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(RGB888, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C0_G_Y, C2_R_Cr, 0, 3, + false, 3, 0, + DPU_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(BGR888, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3, + false, 3, 0, + DPU_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(RGB565, + 0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT, + C1_B_Cb, C0_G_Y, C2_R_Cr, 0, 3, + false, 2, 0, + DPU_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(BGR565, + 0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3, + false, 2, 0, + DPU_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(ARGB1555, + COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT, + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, + true, 2, 0, + DPU_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(ABGR1555, + COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + true, 2, 0, + DPU_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(RGBA5551, + COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT, + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, + true, 2, 0, + DPU_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(BGRA5551, + COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, + true, 2, 0, + DPU_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(XRGB1555, + COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT, + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, + false, 2, 0, + DPU_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(XBGR1555, + COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + false, 2, 0, + DPU_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(RGBX5551, + COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT, + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, + false, 2, 0, + DPU_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(BGRX5551, + COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, + false, 2, 0, + DPU_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(ARGB4444, + COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT, + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, + true, 2, 0, + DPU_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(ABGR4444, + COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + true, 2, 0, + DPU_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(RGBA4444, + COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT, + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, + true, 2, 0, + DPU_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(BGRA4444, + COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, + true, 2, 0, + DPU_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(XRGB4444, + COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT, + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, + false, 2, 0, + DPU_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(XBGR4444, + COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + false, 2, 0, + DPU_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(RGBX4444, + COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT, + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, + false, 2, 0, + DPU_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(BGRX4444, + COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, + false, 2, 0, + DPU_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(BGRA1010102, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, + true, 4, DPU_FORMAT_FLAG_DX, + DPU_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(RGBA1010102, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, + true, 4, DPU_FORMAT_FLAG_DX, + DPU_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(ABGR2101010, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + true, 4, DPU_FORMAT_FLAG_DX, + DPU_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(ARGB2101010, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, + true, 4, DPU_FORMAT_FLAG_DX, + DPU_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(XRGB2101010, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, + false, 4, DPU_FORMAT_FLAG_DX, + DPU_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(BGRX1010102, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, + false, 4, DPU_FORMAT_FLAG_DX, + DPU_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(XBGR2101010, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + false, 4, DPU_FORMAT_FLAG_DX, + DPU_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(RGBX1010102, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, + false, 4, DPU_FORMAT_FLAG_DX, + DPU_FETCH_LINEAR, 1), + + PSEUDO_YUV_FMT(NV12, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C2_R_Cr, + DPU_CHROMA_420, DPU_FORMAT_FLAG_YUV, + DPU_FETCH_LINEAR, 2), + + PSEUDO_YUV_FMT(NV21, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C1_B_Cb, + DPU_CHROMA_420, DPU_FORMAT_FLAG_YUV, + DPU_FETCH_LINEAR, 2), + + PSEUDO_YUV_FMT(NV16, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C2_R_Cr, + DPU_CHROMA_H2V1, DPU_FORMAT_FLAG_YUV, + DPU_FETCH_LINEAR, 2), + + PSEUDO_YUV_FMT(NV61, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C1_B_Cb, + DPU_CHROMA_H2V1, DPU_FORMAT_FLAG_YUV, + DPU_FETCH_LINEAR, 2), + + INTERLEAVED_YUV_FMT(VYUY, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C0_G_Y, + false, DPU_CHROMA_H2V1, 4, 2, DPU_FORMAT_FLAG_YUV, + DPU_FETCH_LINEAR, 2), + + INTERLEAVED_YUV_FMT(UYVY, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C0_G_Y, C2_R_Cr, C0_G_Y, + false, DPU_CHROMA_H2V1, 4, 2, DPU_FORMAT_FLAG_YUV, + DPU_FETCH_LINEAR, 2), + + INTERLEAVED_YUV_FMT(YUYV, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C0_G_Y, C1_B_Cb, C0_G_Y, C2_R_Cr, + false, DPU_CHROMA_H2V1, 4, 2, DPU_FORMAT_FLAG_YUV, + DPU_FETCH_LINEAR, 2), + + INTERLEAVED_YUV_FMT(YVYU, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C0_G_Y, C2_R_Cr, C0_G_Y, C1_B_Cb, + false, DPU_CHROMA_H2V1, 4, 2, DPU_FORMAT_FLAG_YUV, + DPU_FETCH_LINEAR, 2), + + PLANAR_YUV_FMT(YUV420, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C1_B_Cb, C0_G_Y, + false, DPU_CHROMA_420, 1, DPU_FORMAT_FLAG_YUV, + DPU_FETCH_LINEAR, 3), + + PLANAR_YUV_FMT(YVU420, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C2_R_Cr, C0_G_Y, + false, DPU_CHROMA_420, 1, DPU_FORMAT_FLAG_YUV, + DPU_FETCH_LINEAR, 3), +}; + +/* + * A5x tile formats tables: + * These tables hold the A5x tile formats supported. + */ +static const struct dpu_format dpu_format_map_tile[] = { + INTERLEAVED_RGB_FMT_TILED(BGR565, + 0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3, + false, 2, 0, + DPU_FETCH_UBWC, 1, DPU_TILE_HEIGHT_TILED), + + INTERLEAVED_RGB_FMT_TILED(ARGB8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, + true, 4, 0, + DPU_FETCH_UBWC, 1, DPU_TILE_HEIGHT_TILED), + + INTERLEAVED_RGB_FMT_TILED(ABGR8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, + true, 4, 0, + DPU_FETCH_UBWC, 1, DPU_TILE_HEIGHT_TILED), + + INTERLEAVED_RGB_FMT_TILED(XBGR8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + false, 4, 0, + DPU_FETCH_UBWC, 1, DPU_TILE_HEIGHT_TILED), + + INTERLEAVED_RGB_FMT_TILED(RGBA8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + true, 4, 0, + DPU_FETCH_UBWC, 1, DPU_TILE_HEIGHT_TILED), + + INTERLEAVED_RGB_FMT_TILED(BGRA8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, + true, 4, 0, + DPU_FETCH_UBWC, 1, DPU_TILE_HEIGHT_TILED), + + INTERLEAVED_RGB_FMT_TILED(BGRX8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, + false, 4, 0, + DPU_FETCH_UBWC, 1, DPU_TILE_HEIGHT_TILED), + + INTERLEAVED_RGB_FMT_TILED(XRGB8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, + false, 4, 0, + DPU_FETCH_UBWC, 1, DPU_TILE_HEIGHT_TILED), + + INTERLEAVED_RGB_FMT_TILED(RGBX8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + false, 4, 0, + DPU_FETCH_UBWC, 1, DPU_TILE_HEIGHT_TILED), + + INTERLEAVED_RGB_FMT_TILED(ABGR2101010, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + true, 4, DPU_FORMAT_FLAG_DX, + DPU_FETCH_UBWC, 1, DPU_TILE_HEIGHT_TILED), + + INTERLEAVED_RGB_FMT_TILED(XBGR2101010, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + true, 4, DPU_FORMAT_FLAG_DX, + DPU_FETCH_UBWC, 1, DPU_TILE_HEIGHT_TILED), + + PSEUDO_YUV_FMT_TILED(NV12, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C2_R_Cr, + DPU_CHROMA_420, DPU_FORMAT_FLAG_YUV, + DPU_FETCH_UBWC, 2, DPU_TILE_HEIGHT_NV12), + + PSEUDO_YUV_FMT_TILED(NV21, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C1_B_Cb, + DPU_CHROMA_420, DPU_FORMAT_FLAG_YUV, + DPU_FETCH_UBWC, 2, DPU_TILE_HEIGHT_NV12), +}; + +/* + * UBWC formats table: + * This table holds the UBWC formats supported. + * If a compression ratio needs to be used for this or any other format, + * the data will be passed by user-space. + */ +static const struct dpu_format dpu_format_map_ubwc[] = { + INTERLEAVED_RGB_FMT_TILED(BGR565, + 0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3, + false, 2, DPU_FORMAT_FLAG_COMPRESSED, + DPU_FETCH_UBWC, 2, DPU_TILE_HEIGHT_UBWC), + + INTERLEAVED_RGB_FMT_TILED(ABGR8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + true, 4, DPU_FORMAT_FLAG_COMPRESSED, + DPU_FETCH_UBWC, 2, DPU_TILE_HEIGHT_UBWC), + + INTERLEAVED_RGB_FMT_TILED(XBGR8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + false, 4, DPU_FORMAT_FLAG_COMPRESSED, + DPU_FETCH_UBWC, 2, DPU_TILE_HEIGHT_UBWC), + + INTERLEAVED_RGB_FMT_TILED(ABGR2101010, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + true, 4, DPU_FORMAT_FLAG_DX | DPU_FORMAT_FLAG_COMPRESSED, + DPU_FETCH_UBWC, 2, DPU_TILE_HEIGHT_UBWC), + + INTERLEAVED_RGB_FMT_TILED(XBGR2101010, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + true, 4, DPU_FORMAT_FLAG_DX | DPU_FORMAT_FLAG_COMPRESSED, + DPU_FETCH_UBWC, 2, DPU_TILE_HEIGHT_UBWC), + + PSEUDO_YUV_FMT_TILED(NV12, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C2_R_Cr, + DPU_CHROMA_420, DPU_FORMAT_FLAG_YUV | + DPU_FORMAT_FLAG_COMPRESSED, + DPU_FETCH_UBWC, 4, DPU_TILE_HEIGHT_NV12), +}; + +static const struct dpu_format dpu_format_map_p010[] = { + PSEUDO_YUV_FMT_LOOSE(NV12, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C2_R_Cr, + DPU_CHROMA_420, (DPU_FORMAT_FLAG_YUV | DPU_FORMAT_FLAG_DX), + DPU_FETCH_LINEAR, 2), +}; + +static const struct dpu_format dpu_format_map_p010_ubwc[] = { + PSEUDO_YUV_FMT_LOOSE_TILED(NV12, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C2_R_Cr, + DPU_CHROMA_420, (DPU_FORMAT_FLAG_YUV | DPU_FORMAT_FLAG_DX | + DPU_FORMAT_FLAG_COMPRESSED), + DPU_FETCH_UBWC, 4, DPU_TILE_HEIGHT_NV12), +}; + +static const struct dpu_format dpu_format_map_tp10_ubwc[] = { + PSEUDO_YUV_FMT_TILED(NV12, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C2_R_Cr, + DPU_CHROMA_420, (DPU_FORMAT_FLAG_YUV | DPU_FORMAT_FLAG_DX | + DPU_FORMAT_FLAG_COMPRESSED), + DPU_FETCH_UBWC, 4, DPU_TILE_HEIGHT_NV12), +}; + +/* _dpu_get_v_h_subsample_rate - Get subsample rates for all formats we support + * Note: Not using the drm_format_*_subsampling since we have formats + */ +static void _dpu_get_v_h_subsample_rate( + enum dpu_chroma_samp_type chroma_sample, + uint32_t *v_sample, + uint32_t *h_sample) +{ + if (!v_sample || !h_sample) + return; + + switch (chroma_sample) { + case DPU_CHROMA_H2V1: + *v_sample = 1; + *h_sample = 2; + break; + case DPU_CHROMA_H1V2: + *v_sample = 2; + *h_sample = 1; + break; + case DPU_CHROMA_420: + *v_sample = 2; + *h_sample = 2; + break; + default: + *v_sample = 1; + *h_sample = 1; + break; + } +} + +static int _dpu_format_get_media_color_ubwc(const struct dpu_format *fmt) +{ + static const struct dpu_media_color_map dpu_media_ubwc_map[] = { + {DRM_FORMAT_ABGR8888, COLOR_FMT_RGBA8888_UBWC}, + {DRM_FORMAT_XBGR8888, COLOR_FMT_RGBA8888_UBWC}, + {DRM_FORMAT_ABGR2101010, COLOR_FMT_RGBA1010102_UBWC}, + {DRM_FORMAT_XBGR2101010, COLOR_FMT_RGBA1010102_UBWC}, + {DRM_FORMAT_BGR565, COLOR_FMT_RGB565_UBWC}, + }; + int color_fmt = -1; + int i; + + if (fmt->base.pixel_format == DRM_FORMAT_NV12) { + if (DPU_FORMAT_IS_DX(fmt)) { + if (fmt->unpack_tight) + color_fmt = COLOR_FMT_NV12_BPP10_UBWC; + else + color_fmt = COLOR_FMT_P010_UBWC; + } else + color_fmt = COLOR_FMT_NV12_UBWC; + return color_fmt; + } + + for (i = 0; i < ARRAY_SIZE(dpu_media_ubwc_map); ++i) + if (fmt->base.pixel_format == dpu_media_ubwc_map[i].format) { + color_fmt = dpu_media_ubwc_map[i].color; + break; + } + return color_fmt; +} + +static int _dpu_format_get_plane_sizes_ubwc( + const struct dpu_format *fmt, + const uint32_t width, + const uint32_t height, + struct dpu_hw_fmt_layout *layout) +{ + int i; + int color; + bool meta = DPU_FORMAT_IS_UBWC(fmt); + + memset(layout, 0, sizeof(struct dpu_hw_fmt_layout)); + layout->format = fmt; + layout->width = width; + layout->height = height; + layout->num_planes = fmt->num_planes; + + color = _dpu_format_get_media_color_ubwc(fmt); + if (color < 0) { + DRM_ERROR("UBWC format not supported for fmt: %4.4s\n", + (char *)&fmt->base.pixel_format); + return -EINVAL; + } + + if (DPU_FORMAT_IS_YUV(layout->format)) { + uint32_t y_sclines, uv_sclines; + uint32_t y_meta_scanlines = 0; + uint32_t uv_meta_scanlines = 0; + + layout->num_planes = 2; + layout->plane_pitch[0] = VENUS_Y_STRIDE(color, width); + y_sclines = VENUS_Y_SCANLINES(color, height); + layout->plane_size[0] = MSM_MEDIA_ALIGN(layout->plane_pitch[0] * + y_sclines, DPU_UBWC_PLANE_SIZE_ALIGNMENT); + + layout->plane_pitch[1] = VENUS_UV_STRIDE(color, width); + uv_sclines = VENUS_UV_SCANLINES(color, height); + layout->plane_size[1] = MSM_MEDIA_ALIGN(layout->plane_pitch[1] * + uv_sclines, DPU_UBWC_PLANE_SIZE_ALIGNMENT); + + if (!meta) + goto done; + + layout->num_planes += 2; + layout->plane_pitch[2] = VENUS_Y_META_STRIDE(color, width); + y_meta_scanlines = VENUS_Y_META_SCANLINES(color, height); + layout->plane_size[2] = MSM_MEDIA_ALIGN(layout->plane_pitch[2] * + y_meta_scanlines, DPU_UBWC_PLANE_SIZE_ALIGNMENT); + + layout->plane_pitch[3] = VENUS_UV_META_STRIDE(color, width); + uv_meta_scanlines = VENUS_UV_META_SCANLINES(color, height); + layout->plane_size[3] = MSM_MEDIA_ALIGN(layout->plane_pitch[3] * + uv_meta_scanlines, DPU_UBWC_PLANE_SIZE_ALIGNMENT); + + } else { + uint32_t rgb_scanlines, rgb_meta_scanlines; + + layout->num_planes = 1; + + layout->plane_pitch[0] = VENUS_RGB_STRIDE(color, width); + rgb_scanlines = VENUS_RGB_SCANLINES(color, height); + layout->plane_size[0] = MSM_MEDIA_ALIGN(layout->plane_pitch[0] * + rgb_scanlines, DPU_UBWC_PLANE_SIZE_ALIGNMENT); + + if (!meta) + goto done; + layout->num_planes += 2; + layout->plane_pitch[2] = VENUS_RGB_META_STRIDE(color, width); + rgb_meta_scanlines = VENUS_RGB_META_SCANLINES(color, height); + layout->plane_size[2] = MSM_MEDIA_ALIGN(layout->plane_pitch[2] * + rgb_meta_scanlines, DPU_UBWC_PLANE_SIZE_ALIGNMENT); + } + +done: + for (i = 0; i < DPU_MAX_PLANES; i++) + layout->total_size += layout->plane_size[i]; + + return 0; +} + +static int _dpu_format_get_plane_sizes_linear( + const struct dpu_format *fmt, + const uint32_t width, + const uint32_t height, + struct dpu_hw_fmt_layout *layout, + const uint32_t *pitches) +{ + int i; + + memset(layout, 0, sizeof(struct dpu_hw_fmt_layout)); + layout->format = fmt; + layout->width = width; + layout->height = height; + layout->num_planes = fmt->num_planes; + + /* Due to memset above, only need to set planes of interest */ + if (fmt->fetch_planes == DPU_PLANE_INTERLEAVED) { + layout->num_planes = 1; + layout->plane_size[0] = width * height * layout->format->bpp; + layout->plane_pitch[0] = width * layout->format->bpp; + } else { + uint32_t v_subsample, h_subsample; + uint32_t chroma_samp; + uint32_t bpp = 1; + + chroma_samp = fmt->chroma_sample; + _dpu_get_v_h_subsample_rate(chroma_samp, &v_subsample, + &h_subsample); + + if (width % h_subsample || height % v_subsample) { + DRM_ERROR("mismatch in subsample vs dimensions\n"); + return -EINVAL; + } + + if ((fmt->base.pixel_format == DRM_FORMAT_NV12) && + (DPU_FORMAT_IS_DX(fmt))) + bpp = 2; + layout->plane_pitch[0] = width * bpp; + layout->plane_pitch[1] = layout->plane_pitch[0] / h_subsample; + layout->plane_size[0] = layout->plane_pitch[0] * height; + layout->plane_size[1] = layout->plane_pitch[1] * + (height / v_subsample); + + if (fmt->fetch_planes == DPU_PLANE_PSEUDO_PLANAR) { + layout->num_planes = 2; + layout->plane_size[1] *= 2; + layout->plane_pitch[1] *= 2; + } else { + /* planar */ + layout->num_planes = 3; + layout->plane_size[2] = layout->plane_size[1]; + layout->plane_pitch[2] = layout->plane_pitch[1]; + } + } + + /* + * linear format: allow user allocated pitches if they are greater than + * the requirement. + * ubwc format: pitch values are computed uniformly across + * all the components based on ubwc specifications. + */ + for (i = 0; i < layout->num_planes && i < DPU_MAX_PLANES; ++i) { + if (pitches && layout->plane_pitch[i] < pitches[i]) + layout->plane_pitch[i] = pitches[i]; + } + + for (i = 0; i < DPU_MAX_PLANES; i++) + layout->total_size += layout->plane_size[i]; + + return 0; +} + +int dpu_format_get_plane_sizes( + const struct dpu_format *fmt, + const uint32_t w, + const uint32_t h, + struct dpu_hw_fmt_layout *layout, + const uint32_t *pitches) +{ + if (!layout || !fmt) { + DRM_ERROR("invalid pointer\n"); + return -EINVAL; + } + + if ((w > DPU_MAX_IMG_WIDTH) || (h > DPU_MAX_IMG_HEIGHT)) { + DRM_ERROR("image dimensions outside max range\n"); + return -ERANGE; + } + + if (DPU_FORMAT_IS_UBWC(fmt) || DPU_FORMAT_IS_TILE(fmt)) + return _dpu_format_get_plane_sizes_ubwc(fmt, w, h, layout); + + return _dpu_format_get_plane_sizes_linear(fmt, w, h, layout, pitches); +} + +int dpu_format_get_block_size(const struct dpu_format *fmt, + uint32_t *w, uint32_t *h) +{ + if (!fmt || !w || !h) { + DRM_ERROR("invalid pointer\n"); + return -EINVAL; + } + + /* TP10 is 96x96 and all others are 128x128 */ + if (DPU_FORMAT_IS_YUV(fmt) && DPU_FORMAT_IS_DX(fmt) && + (fmt->num_planes == 2) && fmt->unpack_tight) + *w = *h = 96; + else + *w = *h = 128; + + return 0; +} + +uint32_t dpu_format_get_framebuffer_size( + const uint32_t format, + const uint32_t width, + const uint32_t height, + const uint32_t *pitches, + const uint64_t modifiers) +{ + const struct dpu_format *fmt; + struct dpu_hw_fmt_layout layout; + + fmt = dpu_get_dpu_format_ext(format, modifiers); + if (!fmt) + return 0; + + if (!pitches) + return -EINVAL; + + if (dpu_format_get_plane_sizes(fmt, width, height, &layout, pitches)) + layout.total_size = 0; + + return layout.total_size; +} + +static int _dpu_format_populate_addrs_ubwc( + struct msm_gem_address_space *aspace, + struct drm_framebuffer *fb, + struct dpu_hw_fmt_layout *layout) +{ + uint32_t base_addr = 0; + bool meta; + + if (!fb || !layout) { + DRM_ERROR("invalid pointers\n"); + return -EINVAL; + } + + if (aspace) + base_addr = msm_framebuffer_iova(fb, aspace, 0); + if (!base_addr) { + DRM_ERROR("failed to retrieve base addr\n"); + return -EFAULT; + } + + meta = DPU_FORMAT_IS_UBWC(layout->format); + + /* Per-format logic for verifying active planes */ + if (DPU_FORMAT_IS_YUV(layout->format)) { + /************************************************/ + /* UBWC ** */ + /* buffer ** DPU PLANE */ + /* format ** */ + /************************************************/ + /* ------------------- ** -------------------- */ + /* | Y meta | ** | Y bitstream | */ + /* | data | ** | plane | */ + /* ------------------- ** -------------------- */ + /* | Y bitstream | ** | CbCr bitstream | */ + /* | data | ** | plane | */ + /* ------------------- ** -------------------- */ + /* | Cbcr metadata | ** | Y meta | */ + /* | data | ** | plane | */ + /* ------------------- ** -------------------- */ + /* | CbCr bitstream | ** | CbCr meta | */ + /* | data | ** | plane | */ + /* ------------------- ** -------------------- */ + /************************************************/ + + /* configure Y bitstream plane */ + layout->plane_addr[0] = base_addr + layout->plane_size[2]; + + /* configure CbCr bitstream plane */ + layout->plane_addr[1] = base_addr + layout->plane_size[0] + + layout->plane_size[2] + layout->plane_size[3]; + + if (!meta) + goto done; + + /* configure Y metadata plane */ + layout->plane_addr[2] = base_addr; + + /* configure CbCr metadata plane */ + layout->plane_addr[3] = base_addr + layout->plane_size[0] + + layout->plane_size[2]; + + } else { + /************************************************/ + /* UBWC ** */ + /* buffer ** DPU PLANE */ + /* format ** */ + /************************************************/ + /* ------------------- ** -------------------- */ + /* | RGB meta | ** | RGB bitstream | */ + /* | data | ** | plane | */ + /* ------------------- ** -------------------- */ + /* | RGB bitstream | ** | NONE | */ + /* | data | ** | | */ + /* ------------------- ** -------------------- */ + /* ** | RGB meta | */ + /* ** | plane | */ + /* ** -------------------- */ + /************************************************/ + + layout->plane_addr[0] = base_addr + layout->plane_size[2]; + layout->plane_addr[1] = 0; + + if (!meta) + goto done; + + layout->plane_addr[2] = base_addr; + layout->plane_addr[3] = 0; + } +done: + return 0; +} + +static int _dpu_format_populate_addrs_linear( + struct msm_gem_address_space *aspace, + struct drm_framebuffer *fb, + struct dpu_hw_fmt_layout *layout) +{ + unsigned int i; + + /* Can now check the pitches given vs pitches expected */ + for (i = 0; i < layout->num_planes; ++i) { + if (layout->plane_pitch[i] > fb->pitches[i]) { + DRM_ERROR("plane %u expected pitch %u, fb %u\n", + i, layout->plane_pitch[i], fb->pitches[i]); + return -EINVAL; + } + } + + /* Populate addresses for simple formats here */ + for (i = 0; i < layout->num_planes; ++i) { + if (aspace) + layout->plane_addr[i] = + msm_framebuffer_iova(fb, aspace, i); + if (!layout->plane_addr[i]) { + DRM_ERROR("failed to retrieve base addr\n"); + return -EFAULT; + } + } + + return 0; +} + +int dpu_format_populate_layout( + struct msm_gem_address_space *aspace, + struct drm_framebuffer *fb, + struct dpu_hw_fmt_layout *layout) +{ + uint32_t plane_addr[DPU_MAX_PLANES]; + int i, ret; + + if (!fb || !layout) { + DRM_ERROR("invalid arguments\n"); + return -EINVAL; + } + + if ((fb->width > DPU_MAX_IMG_WIDTH) || + (fb->height > DPU_MAX_IMG_HEIGHT)) { + DRM_ERROR("image dimensions outside max range\n"); + return -ERANGE; + } + + layout->format = to_dpu_format(msm_framebuffer_format(fb)); + + /* Populate the plane sizes etc via get_format */ + ret = dpu_format_get_plane_sizes(layout->format, fb->width, fb->height, + layout, fb->pitches); + if (ret) + return ret; + + for (i = 0; i < DPU_MAX_PLANES; ++i) + plane_addr[i] = layout->plane_addr[i]; + + /* Populate the addresses given the fb */ + if (DPU_FORMAT_IS_UBWC(layout->format) || + DPU_FORMAT_IS_TILE(layout->format)) + ret = _dpu_format_populate_addrs_ubwc(aspace, fb, layout); + else + ret = _dpu_format_populate_addrs_linear(aspace, fb, layout); + + /* check if anything changed */ + if (!ret && !memcmp(plane_addr, layout->plane_addr, sizeof(plane_addr))) + ret = -EAGAIN; + + return ret; +} + +int dpu_format_check_modified_format( + const struct msm_kms *kms, + const struct msm_format *msm_fmt, + const struct drm_mode_fb_cmd2 *cmd, + struct drm_gem_object **bos) +{ + int ret, i, num_base_fmt_planes; + const struct dpu_format *fmt; + struct dpu_hw_fmt_layout layout; + uint32_t bos_total_size = 0; + + if (!msm_fmt || !cmd || !bos) { + DRM_ERROR("invalid arguments\n"); + return -EINVAL; + } + + fmt = to_dpu_format(msm_fmt); + num_base_fmt_planes = drm_format_num_planes(fmt->base.pixel_format); + + ret = dpu_format_get_plane_sizes(fmt, cmd->width, cmd->height, + &layout, cmd->pitches); + if (ret) + return ret; + + for (i = 0; i < num_base_fmt_planes; i++) { + if (!bos[i]) { + DRM_ERROR("invalid handle for plane %d\n", i); + return -EINVAL; + } + if ((i == 0) || (bos[i] != bos[0])) + bos_total_size += bos[i]->size; + } + + if (bos_total_size < layout.total_size) { + DRM_ERROR("buffers total size too small %u expected %u\n", + bos_total_size, layout.total_size); + return -EINVAL; + } + + return 0; +} + +const struct dpu_format *dpu_get_dpu_format_ext( + const uint32_t format, + const uint64_t modifier) +{ + uint32_t i = 0; + const struct dpu_format *fmt = NULL; + const struct dpu_format *map = NULL; + ssize_t map_size = 0; + + /* + * Currently only support exactly zero or one modifier. + * All planes use the same modifier. + */ + DPU_DEBUG("plane format modifier 0x%llX\n", modifier); + + switch (modifier) { + case 0: + map = dpu_format_map; + map_size = ARRAY_SIZE(dpu_format_map); + break; + case DRM_FORMAT_MOD_QCOM_COMPRESSED: + map = dpu_format_map_ubwc; + map_size = ARRAY_SIZE(dpu_format_map_ubwc); + DPU_DEBUG("found fmt: %4.4s DRM_FORMAT_MOD_QCOM_COMPRESSED\n", + (char *)&format); + break; + default: + DPU_ERROR("unsupported format modifier %llX\n", modifier); + return NULL; + } + + for (i = 0; i < map_size; i++) { + if (format == map[i].base.pixel_format) { + fmt = &map[i]; + break; + } + } + + if (fmt == NULL) + DPU_ERROR("unsupported fmt: %4.4s modifier 0x%llX\n", + (char *)&format, modifier); + else + DPU_DEBUG("fmt %4.4s mod 0x%llX ubwc %d yuv %d\n", + (char *)&format, modifier, + DPU_FORMAT_IS_UBWC(fmt), + DPU_FORMAT_IS_YUV(fmt)); + + return fmt; +} + +const struct msm_format *dpu_get_msm_format( + struct msm_kms *kms, + const uint32_t format, + const uint64_t modifiers) +{ + const struct dpu_format *fmt = dpu_get_dpu_format_ext(format, + modifiers); + if (fmt) + return &fmt->base; + return NULL; +} + +uint32_t dpu_populate_formats( + const struct dpu_format_extended *format_list, + uint32_t *pixel_formats, + uint64_t *pixel_modifiers, + uint32_t pixel_formats_max) +{ + uint32_t i, fourcc_format; + + if (!format_list || !pixel_formats) + return 0; + + for (i = 0, fourcc_format = 0; + format_list->fourcc_format && i < pixel_formats_max; + ++format_list) { + /* verify if listed format is in dpu_format_map? */ + + /* optionally return modified formats */ + if (pixel_modifiers) { + /* assume same modifier for all fb planes */ + pixel_formats[i] = format_list->fourcc_format; + pixel_modifiers[i++] = format_list->modifier; + } else { + /* assume base formats grouped together */ + if (fourcc_format != format_list->fourcc_format) { + fourcc_format = format_list->fourcc_format; + pixel_formats[i++] = fourcc_format; + } + } + } + + return i; +} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.h new file mode 100644 index 0000000000000..b55bfd13e2962 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.h @@ -0,0 +1,136 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef _DPU_FORMATS_H +#define _DPU_FORMATS_H + +#include <drm/drm_fourcc.h> +#include "msm_gem.h" +#include "dpu_hw_mdss.h" + +/** + * dpu_get_dpu_format_ext() - Returns dpu format structure pointer. + * @format: DRM FourCC Code + * @modifiers: format modifier array from client, one per plane + */ +const struct dpu_format *dpu_get_dpu_format_ext( + const uint32_t format, + const uint64_t modifier); + +#define dpu_get_dpu_format(f) dpu_get_dpu_format_ext(f, 0) + +/** + * dpu_get_msm_format - get an dpu_format by its msm_format base + * callback function registers with the msm_kms layer + * @kms: kms driver + * @format: DRM FourCC Code + * @modifiers: data layout modifier + */ +const struct msm_format *dpu_get_msm_format( + struct msm_kms *kms, + const uint32_t format, + const uint64_t modifiers); + +/** + * dpu_populate_formats - populate the given array with fourcc codes supported + * @format_list: pointer to list of possible formats + * @pixel_formats: array to populate with fourcc codes + * @pixel_modifiers: array to populate with drm modifiers, can be NULL + * @pixel_formats_max: length of pixel formats array + * Return: number of elements populated + */ +uint32_t dpu_populate_formats( + const struct dpu_format_extended *format_list, + uint32_t *pixel_formats, + uint64_t *pixel_modifiers, + uint32_t pixel_formats_max); + +/** + * dpu_format_get_plane_sizes - calculate size and layout of given buffer format + * @fmt: pointer to dpu_format + * @w: width of the buffer + * @h: height of the buffer + * @layout: layout of the buffer + * @pitches: array of size [DPU_MAX_PLANES] to populate + * pitch for each plane + * + * Return: size of the buffer + */ +int dpu_format_get_plane_sizes( + const struct dpu_format *fmt, + const uint32_t w, + const uint32_t h, + struct dpu_hw_fmt_layout *layout, + const uint32_t *pitches); + +/** + * dpu_format_get_block_size - get block size of given format when + * operating in block mode + * @fmt: pointer to dpu_format + * @w: pointer to width of the block + * @h: pointer to height of the block + * + * Return: 0 if success; error oode otherwise + */ +int dpu_format_get_block_size(const struct dpu_format *fmt, + uint32_t *w, uint32_t *h); + +/** + * dpu_format_check_modified_format - validate format and buffers for + * dpu non-standard, i.e. modified format + * @kms: kms driver + * @msm_fmt: pointer to the msm_fmt base pointer of an dpu_format + * @cmd: fb_cmd2 structure user request + * @bos: gem buffer object list + * + * Return: error code on failure, 0 on success + */ +int dpu_format_check_modified_format( + const struct msm_kms *kms, + const struct msm_format *msm_fmt, + const struct drm_mode_fb_cmd2 *cmd, + struct drm_gem_object **bos); + +/** + * dpu_format_populate_layout - populate the given format layout based on + * mmu, fb, and format found in the fb + * @aspace: address space pointer + * @fb: framebuffer pointer + * @fmtl: format layout structure to populate + * + * Return: error code on failure, -EAGAIN if success but the addresses + * are the same as before or 0 if new addresses were populated + */ +int dpu_format_populate_layout( + struct msm_gem_address_space *aspace, + struct drm_framebuffer *fb, + struct dpu_hw_fmt_layout *fmtl); + +/** + * dpu_format_get_framebuffer_size - get framebuffer memory size + * @format: DRM pixel format + * @width: pixel width + * @height: pixel height + * @pitches: array of size [DPU_MAX_PLANES] to populate + * pitch for each plane + * @modifiers: drm modifier + * + * Return: memory size required for frame buffer + */ +uint32_t dpu_format_get_framebuffer_size( + const uint32_t format, + const uint32_t width, + const uint32_t height, + const uint32_t *pitches, + const uint64_t modifiers); + +#endif /*_DPU_FORMATS_H */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_blk.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_blk.c new file mode 100644 index 0000000000000..58d29e43faefd --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_blk.c @@ -0,0 +1,155 @@ +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ + +#include <linux/mutex.h> +#include <linux/errno.h> +#include <linux/slab.h> + +#include "dpu_hw_mdss.h" +#include "dpu_hw_blk.h" + +/* Serialization lock for dpu_hw_blk_list */ +static DEFINE_MUTEX(dpu_hw_blk_lock); + +/* List of all hw block objects */ +static LIST_HEAD(dpu_hw_blk_list); + +/** + * dpu_hw_blk_init - initialize hw block object + * @type: hw block type - enum dpu_hw_blk_type + * @id: instance id of the hw block + * @ops: Pointer to block operations + * return: 0 if success; error code otherwise + */ +int dpu_hw_blk_init(struct dpu_hw_blk *hw_blk, u32 type, int id, + struct dpu_hw_blk_ops *ops) +{ + if (!hw_blk) { + pr_err("invalid parameters\n"); + return -EINVAL; + } + + INIT_LIST_HEAD(&hw_blk->list); + hw_blk->type = type; + hw_blk->id = id; + atomic_set(&hw_blk->refcount, 0); + + if (ops) + hw_blk->ops = *ops; + + mutex_lock(&dpu_hw_blk_lock); + list_add(&hw_blk->list, &dpu_hw_blk_list); + mutex_unlock(&dpu_hw_blk_lock); + + return 0; +} + +/** + * dpu_hw_blk_destroy - destroy hw block object. + * @hw_blk: pointer to hw block object + * return: none + */ +void dpu_hw_blk_destroy(struct dpu_hw_blk *hw_blk) +{ + if (!hw_blk) { + pr_err("invalid parameters\n"); + return; + } + + if (atomic_read(&hw_blk->refcount)) + pr_err("hw_blk:%d.%d invalid refcount\n", hw_blk->type, + hw_blk->id); + + mutex_lock(&dpu_hw_blk_lock); + list_del(&hw_blk->list); + mutex_unlock(&dpu_hw_blk_lock); +} + +/** + * dpu_hw_blk_get - get hw_blk from free pool + * @hw_blk: if specified, increment reference count only + * @type: if hw_blk is not specified, allocate the next available of this type + * @id: if specified (>= 0), allocate the given instance of the above type + * return: pointer to hw block object + */ +struct dpu_hw_blk *dpu_hw_blk_get(struct dpu_hw_blk *hw_blk, u32 type, int id) +{ + struct dpu_hw_blk *curr; + int rc, refcount; + + if (!hw_blk) { + mutex_lock(&dpu_hw_blk_lock); + list_for_each_entry(curr, &dpu_hw_blk_list, list) { + if ((curr->type != type) || + (id >= 0 && curr->id != id) || + (id < 0 && + atomic_read(&curr->refcount))) + continue; + + hw_blk = curr; + break; + } + mutex_unlock(&dpu_hw_blk_lock); + } + + if (!hw_blk) { + pr_debug("no hw_blk:%d\n", type); + return NULL; + } + + refcount = atomic_inc_return(&hw_blk->refcount); + + if (refcount == 1 && hw_blk->ops.start) { + rc = hw_blk->ops.start(hw_blk); + if (rc) { + pr_err("failed to start hw_blk:%d rc:%d\n", type, rc); + goto error_start; + } + } + + pr_debug("hw_blk:%d.%d refcount:%d\n", hw_blk->type, + hw_blk->id, refcount); + return hw_blk; + +error_start: + dpu_hw_blk_put(hw_blk); + return ERR_PTR(rc); +} + +/** + * dpu_hw_blk_put - put hw_blk to free pool if decremented refcount is zero + * @hw_blk: hw block to be freed + * @free_blk: function to be called when reference count goes to zero + */ +void dpu_hw_blk_put(struct dpu_hw_blk *hw_blk) +{ + if (!hw_blk) { + pr_err("invalid parameters\n"); + return; + } + + pr_debug("hw_blk:%d.%d refcount:%d\n", hw_blk->type, hw_blk->id, + atomic_read(&hw_blk->refcount)); + + if (!atomic_read(&hw_blk->refcount)) { + pr_err("hw_blk:%d.%d invalid put\n", hw_blk->type, hw_blk->id); + return; + } + + if (atomic_dec_return(&hw_blk->refcount)) + return; + + if (hw_blk->ops.stop) + hw_blk->ops.stop(hw_blk); +} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_blk.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_blk.h new file mode 100644 index 0000000000000..0f4ca8af1ec5a --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_blk.h @@ -0,0 +1,53 @@ +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef _DPU_HW_BLK_H +#define _DPU_HW_BLK_H + +#include <linux/types.h> +#include <linux/list.h> +#include <linux/atomic.h> + +struct dpu_hw_blk; + +/** + * struct dpu_hw_blk_ops - common hardware block operations + * @start: start operation on first get + * @stop: stop operation on last put + */ +struct dpu_hw_blk_ops { + int (*start)(struct dpu_hw_blk *); + void (*stop)(struct dpu_hw_blk *); +}; + +/** + * struct dpu_hw_blk - definition of hardware block object + * @list: list of hardware blocks + * @type: hardware block type + * @id: instance id + * @refcount: reference/usage count + */ +struct dpu_hw_blk { + struct list_head list; + u32 type; + int id; + atomic_t refcount; + struct dpu_hw_blk_ops ops; +}; + +int dpu_hw_blk_init(struct dpu_hw_blk *hw_blk, u32 type, int id, + struct dpu_hw_blk_ops *ops); +void dpu_hw_blk_destroy(struct dpu_hw_blk *hw_blk); + +struct dpu_hw_blk *dpu_hw_blk_get(struct dpu_hw_blk *hw_blk, u32 type, int id); +void dpu_hw_blk_put(struct dpu_hw_blk *hw_blk); +#endif /*_DPU_HW_BLK_H */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c new file mode 100644 index 0000000000000..1793cfd29a070 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c @@ -0,0 +1,511 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ +#include <linux/slab.h> +#include <linux/of_address.h> +#include <linux/platform_device.h> +#include "dpu_hw_mdss.h" +#include "dpu_hw_catalog.h" +#include "dpu_hw_catalog_format.h" +#include "dpu_kms.h" + +#define VIG_SDM845_MASK \ + (BIT(DPU_SSPP_SRC) | BIT(DPU_SSPP_SCALER_QSEED3) | BIT(DPU_SSPP_QOS) |\ + BIT(DPU_SSPP_CSC_10BIT) | BIT(DPU_SSPP_CDP) | BIT(DPU_SSPP_QOS_8LVL) |\ + BIT(DPU_SSPP_TS_PREFILL) | BIT(DPU_SSPP_EXCL_RECT)) + +#define DMA_SDM845_MASK \ + (BIT(DPU_SSPP_SRC) | BIT(DPU_SSPP_QOS) | BIT(DPU_SSPP_QOS_8LVL) |\ + BIT(DPU_SSPP_TS_PREFILL) | BIT(DPU_SSPP_TS_PREFILL_REC1) |\ + BIT(DPU_SSPP_CDP) | BIT(DPU_SSPP_EXCL_RECT)) + +#define MIXER_SDM845_MASK \ + (BIT(DPU_MIXER_SOURCESPLIT) | BIT(DPU_DIM_LAYER)) + +#define PINGPONG_SDM845_MASK BIT(DPU_PINGPONG_DITHER) + +#define PINGPONG_SDM845_SPLIT_MASK \ + (PINGPONG_SDM845_MASK | BIT(DPU_PINGPONG_TE2)) + +#define DEFAULT_PIXEL_RAM_SIZE (50 * 1024) +#define DEFAULT_DPU_LINE_WIDTH 2048 +#define DEFAULT_DPU_OUTPUT_LINE_WIDTH 2560 + +#define MAX_HORZ_DECIMATION 4 +#define MAX_VERT_DECIMATION 4 + +#define MAX_UPSCALE_RATIO 20 +#define MAX_DOWNSCALE_RATIO 4 +#define SSPP_UNITY_SCALE 1 + +#define STRCAT(X, Y) (X Y) + +/************************************************************* + * DPU sub blocks config + *************************************************************/ +/* DPU top level caps */ +static const struct dpu_caps sdm845_dpu_caps = { + .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH, + .max_mixer_blendstages = 0xb, + .qseed_type = DPU_SSPP_SCALER_QSEED3, + .smart_dma_rev = DPU_SSPP_SMART_DMA_V2, + .ubwc_version = DPU_HW_UBWC_VER_20, + .has_src_split = true, + .has_dim_layer = true, + .has_idle_pc = true, +}; + +static struct dpu_mdp_cfg sdm845_mdp[] = { + { + .name = "top_0", .id = MDP_TOP, + .base = 0x0, .len = 0x45C, + .features = 0, + .highest_bank_bit = 0x2, + .has_dest_scaler = true, + .clk_ctrls[DPU_CLK_CTRL_VIG0] = { + .reg_off = 0x2AC, .bit_off = 0}, + .clk_ctrls[DPU_CLK_CTRL_VIG1] = { + .reg_off = 0x2B4, .bit_off = 0}, + .clk_ctrls[DPU_CLK_CTRL_VIG2] = { + .reg_off = 0x2BC, .bit_off = 0}, + .clk_ctrls[DPU_CLK_CTRL_VIG3] = { + .reg_off = 0x2C4, .bit_off = 0}, + .clk_ctrls[DPU_CLK_CTRL_DMA0] = { + .reg_off = 0x2AC, .bit_off = 8}, + .clk_ctrls[DPU_CLK_CTRL_DMA1] = { + .reg_off = 0x2B4, .bit_off = 8}, + .clk_ctrls[DPU_CLK_CTRL_CURSOR0] = { + .reg_off = 0x2BC, .bit_off = 8}, + .clk_ctrls[DPU_CLK_CTRL_CURSOR1] = { + .reg_off = 0x2C4, .bit_off = 8}, + }, +}; + +/************************************************************* + * CTL sub blocks config + *************************************************************/ +static struct dpu_ctl_cfg sdm845_ctl[] = { + { + .name = "ctl_0", .id = CTL_0, + .base = 0x1000, .len = 0xE4, + .features = BIT(DPU_CTL_SPLIT_DISPLAY) + }, + { + .name = "ctl_1", .id = CTL_1, + .base = 0x1200, .len = 0xE4, + .features = BIT(DPU_CTL_SPLIT_DISPLAY) + }, + { + .name = "ctl_2", .id = CTL_2, + .base = 0x1400, .len = 0xE4, + .features = 0 + }, + { + .name = "ctl_3", .id = CTL_3, + .base = 0x1600, .len = 0xE4, + .features = 0 + }, + { + .name = "ctl_4", .id = CTL_4, + .base = 0x1800, .len = 0xE4, + .features = 0 + }, +}; + +/************************************************************* + * SSPP sub blocks config + *************************************************************/ + +/* SSPP common configuration */ +static const struct dpu_sspp_blks_common sdm845_sspp_common = { + .maxlinewidth = DEFAULT_DPU_OUTPUT_LINE_WIDTH, + .pixel_ram_size = DEFAULT_PIXEL_RAM_SIZE, + .maxhdeciexp = MAX_HORZ_DECIMATION, + .maxvdeciexp = MAX_VERT_DECIMATION, +}; + +#define _VIG_SBLK(num, sdma_pri) \ + { \ + .common = &sdm845_sspp_common, \ + .maxdwnscale = MAX_DOWNSCALE_RATIO, \ + .maxupscale = MAX_UPSCALE_RATIO, \ + .smart_dma_priority = sdma_pri, \ + .src_blk = {.name = STRCAT("sspp_src_", num), \ + .id = DPU_SSPP_SRC, .base = 0x00, .len = 0x150,}, \ + .scaler_blk = {.name = STRCAT("sspp_scaler", num), \ + .id = DPU_SSPP_SCALER_QSEED3, \ + .base = 0xa00, .len = 0xa0,}, \ + .csc_blk = {.name = STRCAT("sspp_csc", num), \ + .id = DPU_SSPP_CSC_10BIT, \ + .base = 0x1a00, .len = 0x100,}, \ + .format_list = plane_formats_yuv, \ + .virt_format_list = plane_formats, \ + } + +#define _DMA_SBLK(num, sdma_pri) \ + { \ + .common = &sdm845_sspp_common, \ + .maxdwnscale = SSPP_UNITY_SCALE, \ + .maxupscale = SSPP_UNITY_SCALE, \ + .smart_dma_priority = sdma_pri, \ + .src_blk = {.name = STRCAT("sspp_src_", num), \ + .id = DPU_SSPP_SRC, .base = 0x00, .len = 0x150,}, \ + .format_list = plane_formats, \ + .virt_format_list = plane_formats, \ + } + +static const struct dpu_sspp_sub_blks sdm845_vig_sblk_0 = _VIG_SBLK("0", 5); +static const struct dpu_sspp_sub_blks sdm845_vig_sblk_1 = _VIG_SBLK("1", 6); +static const struct dpu_sspp_sub_blks sdm845_vig_sblk_2 = _VIG_SBLK("2", 7); +static const struct dpu_sspp_sub_blks sdm845_vig_sblk_3 = _VIG_SBLK("3", 8); + +static const struct dpu_sspp_sub_blks sdm845_dma_sblk_0 = _DMA_SBLK("8", 1); +static const struct dpu_sspp_sub_blks sdm845_dma_sblk_1 = _DMA_SBLK("9", 2); +static const struct dpu_sspp_sub_blks sdm845_dma_sblk_2 = _DMA_SBLK("10", 3); +static const struct dpu_sspp_sub_blks sdm845_dma_sblk_3 = _DMA_SBLK("11", 4); + +#define SSPP_VIG_BLK(_name, _id, _base, _sblk, _xinid, _clkctrl) \ + { \ + .name = _name, .id = _id, \ + .base = _base, .len = 0x1c8, \ + .features = VIG_SDM845_MASK, \ + .sblk = &_sblk, \ + .xin_id = _xinid, \ + .type = SSPP_TYPE_VIG, \ + .clk_ctrl = _clkctrl \ + } + +#define SSPP_DMA_BLK(_name, _id, _base, _sblk, _xinid, _clkctrl) \ + { \ + .name = _name, .id = _id, \ + .base = _base, .len = 0x1c8, \ + .features = DMA_SDM845_MASK, \ + .sblk = &_sblk, \ + .xin_id = _xinid, \ + .type = SSPP_TYPE_DMA, \ + .clk_ctrl = _clkctrl \ + } + +static struct dpu_sspp_cfg sdm845_sspp[] = { + SSPP_VIG_BLK("sspp_0", SSPP_VIG0, 0x4000, + sdm845_vig_sblk_0, 0, DPU_CLK_CTRL_VIG0), + SSPP_VIG_BLK("sspp_1", SSPP_VIG1, 0x6000, + sdm845_vig_sblk_1, 4, DPU_CLK_CTRL_VIG1), + SSPP_VIG_BLK("sspp_2", SSPP_VIG2, 0x8000, + sdm845_vig_sblk_2, 8, DPU_CLK_CTRL_VIG2), + SSPP_VIG_BLK("sspp_3", SSPP_VIG3, 0xa000, + sdm845_vig_sblk_3, 12, DPU_CLK_CTRL_VIG3), + SSPP_DMA_BLK("sspp_8", SSPP_DMA0, 0x24000, + sdm845_dma_sblk_0, 1, DPU_CLK_CTRL_DMA0), + SSPP_DMA_BLK("sspp_9", SSPP_DMA1, 0x26000, + sdm845_dma_sblk_1, 5, DPU_CLK_CTRL_DMA1), + SSPP_DMA_BLK("sspp_10", SSPP_DMA2, 0x28000, + sdm845_dma_sblk_2, 9, DPU_CLK_CTRL_CURSOR0), + SSPP_DMA_BLK("sspp_11", SSPP_DMA3, 0x2a000, + sdm845_dma_sblk_3, 13, DPU_CLK_CTRL_CURSOR1), +}; + +/************************************************************* + * MIXER sub blocks config + *************************************************************/ +static const struct dpu_lm_sub_blks sdm845_lm_sblk = { + .maxwidth = DEFAULT_DPU_OUTPUT_LINE_WIDTH, + .maxblendstages = 11, /* excluding base layer */ + .blendstage_base = { /* offsets relative to mixer base */ + 0x20, 0x38, 0x50, 0x68, 0x80, 0x98, + 0xb0, 0xc8, 0xe0, 0xf8, 0x110 + }, +}; + +#define LM_BLK(_name, _id, _base, _ds, _pp, _lmpair) \ + { \ + .name = _name, .id = _id, \ + .base = _base, .len = 0x320, \ + .features = MIXER_SDM845_MASK, \ + .sblk = &sdm845_lm_sblk, \ + .ds = _ds, \ + .pingpong = _pp, \ + .lm_pair_mask = (1 << _lmpair) \ + } + +static struct dpu_lm_cfg sdm845_lm[] = { + LM_BLK("lm_0", LM_0, 0x44000, DS_0, PINGPONG_0, LM_1), + LM_BLK("lm_1", LM_1, 0x45000, DS_1, PINGPONG_1, LM_0), + LM_BLK("lm_2", LM_2, 0x46000, DS_MAX, PINGPONG_2, LM_5), + LM_BLK("lm_3", LM_3, 0x0, DS_MAX, PINGPONG_MAX, 0), + LM_BLK("lm_4", LM_4, 0x0, DS_MAX, PINGPONG_MAX, 0), + LM_BLK("lm_5", LM_5, 0x49000, DS_MAX, PINGPONG_3, LM_2), +}; + +/************************************************************* + * DS sub blocks config + *************************************************************/ +static const struct dpu_ds_top_cfg sdm845_ds_top = { + .name = "ds_top_0", .id = DS_TOP, + .base = 0x60000, .len = 0xc, + .maxinputwidth = DEFAULT_DPU_LINE_WIDTH, + .maxoutputwidth = DEFAULT_DPU_OUTPUT_LINE_WIDTH, + .maxupscale = MAX_UPSCALE_RATIO, +}; + +#define DS_BLK(_name, _id, _base) \ + {\ + .name = _name, .id = _id, \ + .base = _base, .len = 0x800, \ + .features = DPU_SSPP_SCALER_QSEED3, \ + .top = &sdm845_ds_top \ + } + +static struct dpu_ds_cfg sdm845_ds[] = { + DS_BLK("ds_0", DS_0, 0x800), + DS_BLK("ds_1", DS_1, 0x1000), +}; + +/************************************************************* + * PINGPONG sub blocks config + *************************************************************/ +static const struct dpu_pingpong_sub_blks sdm845_pp_sblk_te = { + .te2 = {.id = DPU_PINGPONG_TE2, .base = 0x2000, .len = 0x0, + .version = 0x1}, + .dither = {.id = DPU_PINGPONG_DITHER, .base = 0x30e0, + .len = 0x20, .version = 0x10000}, +}; + +static const struct dpu_pingpong_sub_blks sdm845_pp_sblk = { + .dither = {.id = DPU_PINGPONG_DITHER, .base = 0x30e0, + .len = 0x20, .version = 0x10000}, +}; + +#define PP_BLK_TE(_name, _id, _base) \ + {\ + .name = _name, .id = _id, \ + .base = _base, .len = 0xd4, \ + .features = PINGPONG_SDM845_SPLIT_MASK, \ + .sblk = &sdm845_pp_sblk_te \ + } +#define PP_BLK(_name, _id, _base) \ + {\ + .name = _name, .id = _id, \ + .base = _base, .len = 0xd4, \ + .features = PINGPONG_SDM845_MASK, \ + .sblk = &sdm845_pp_sblk \ + } + +static struct dpu_pingpong_cfg sdm845_pp[] = { + PP_BLK_TE("pingpong_0", PINGPONG_0, 0x70000), + PP_BLK_TE("pingpong_1", PINGPONG_1, 0x70800), + PP_BLK("pingpong_2", PINGPONG_2, 0x71000), + PP_BLK("pingpong_3", PINGPONG_3, 0x71800), +}; + +/************************************************************* + * INTF sub blocks config + *************************************************************/ +#define INTF_BLK(_name, _id, _base, _type, _ctrl_id) \ + {\ + .name = _name, .id = _id, \ + .base = _base, .len = 0x280, \ + .type = _type, \ + .controller_id = _ctrl_id, \ + .prog_fetch_lines_worst_case = 24 \ + } + +static struct dpu_intf_cfg sdm845_intf[] = { + INTF_BLK("intf_0", INTF_0, 0x6A000, INTF_DP, 0), + INTF_BLK("intf_1", INTF_1, 0x6A800, INTF_DSI, 0), + INTF_BLK("intf_2", INTF_2, 0x6B000, INTF_DSI, 1), + INTF_BLK("intf_3", INTF_3, 0x6B800, INTF_DP, 1), +}; + +/************************************************************* + * CDM sub blocks config + *************************************************************/ +static struct dpu_cdm_cfg sdm845_cdm[] = { + { + .name = "cdm_0", .id = CDM_0, + .base = 0x79200, .len = 0x224, + .features = 0, + .intf_connect = BIT(INTF_3), + }, +}; + +/************************************************************* + * VBIF sub blocks config + *************************************************************/ +/* VBIF QOS remap */ +static u32 sdm845_rt_pri_lvl[] = {3, 3, 4, 4, 5, 5, 6, 6}; +static u32 sdm845_nrt_pri_lvl[] = {3, 3, 3, 3, 3, 3, 3, 3}; + +static struct dpu_vbif_cfg sdm845_vbif[] = { + { + .name = "vbif_0", .id = VBIF_0, + .base = 0, .len = 0x1040, + .features = BIT(DPU_VBIF_QOS_REMAP), + .xin_halt_timeout = 0x4000, + .qos_rt_tbl = { + .npriority_lvl = ARRAY_SIZE(sdm845_rt_pri_lvl), + .priority_lvl = sdm845_rt_pri_lvl, + }, + .qos_nrt_tbl = { + .npriority_lvl = ARRAY_SIZE(sdm845_nrt_pri_lvl), + .priority_lvl = sdm845_nrt_pri_lvl, + }, + .memtype_count = 14, + .memtype = {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}, + }, +}; + +static struct dpu_reg_dma_cfg sdm845_regdma = { + .base = 0x0, .version = 0x1, .trigger_sel_off = 0x119c +}; + +/************************************************************* + * PERF data config + *************************************************************/ + +/* SSPP QOS LUTs */ +static struct dpu_qos_lut_entry sdm845_qos_linear[] = { + {.fl = 4, .lut = 0x357}, + {.fl = 5, .lut = 0x3357}, + {.fl = 6, .lut = 0x23357}, + {.fl = 7, .lut = 0x223357}, + {.fl = 8, .lut = 0x2223357}, + {.fl = 9, .lut = 0x22223357}, + {.fl = 10, .lut = 0x222223357}, + {.fl = 11, .lut = 0x2222223357}, + {.fl = 12, .lut = 0x22222223357}, + {.fl = 13, .lut = 0x222222223357}, + {.fl = 14, .lut = 0x1222222223357}, + {.fl = 0, .lut = 0x11222222223357} +}; + +static struct dpu_qos_lut_entry sdm845_qos_macrotile[] = { + {.fl = 10, .lut = 0x344556677}, + {.fl = 11, .lut = 0x3344556677}, + {.fl = 12, .lut = 0x23344556677}, + {.fl = 13, .lut = 0x223344556677}, + {.fl = 14, .lut = 0x1223344556677}, + {.fl = 0, .lut = 0x112233344556677}, +}; + +static struct dpu_qos_lut_entry sdm845_qos_nrt[] = { + {.fl = 0, .lut = 0x0}, +}; + +static struct dpu_perf_cfg sdm845_perf_data = { + .max_bw_low = 6800000, + .max_bw_high = 6800000, + .min_core_ib = 2400000, + .min_llcc_ib = 800000, + .min_dram_ib = 800000, + .core_ib_ff = "6.0", + .core_clk_ff = "1.0", + .comp_ratio_rt = + "NV12/5/1/1.23 AB24/5/1/1.23 XB24/5/1/1.23", + .comp_ratio_nrt = + "NV12/5/1/1.25 AB24/5/1/1.25 XB24/5/1/1.25", + .undersized_prefill_lines = 2, + .xtra_prefill_lines = 2, + .dest_scale_prefill_lines = 3, + .macrotile_prefill_lines = 4, + .yuv_nv12_prefill_lines = 8, + .linear_prefill_lines = 1, + .downscaling_prefill_lines = 1, + .amortizable_threshold = 25, + .min_prefill_lines = 24, + .danger_lut_tbl = {0xf, 0xffff, 0x0}, + .qos_lut_tbl = { + {.nentry = ARRAY_SIZE(sdm845_qos_linear), + .entries = sdm845_qos_linear + }, + {.nentry = ARRAY_SIZE(sdm845_qos_macrotile), + .entries = sdm845_qos_macrotile + }, + {.nentry = ARRAY_SIZE(sdm845_qos_nrt), + .entries = sdm845_qos_nrt + }, + }, + .cdp_cfg = { + {.rd_enable = 1, .wr_enable = 1}, + {.rd_enable = 1, .wr_enable = 0} + }, +}; + +/************************************************************* + * Hardware catalog init + *************************************************************/ + +/* + * sdm845_cfg_init(): populate sdm845 dpu sub-blocks reg offsets + * and instance counts. + */ +void sdm845_cfg_init(struct dpu_mdss_cfg *dpu_cfg) +{ + *dpu_cfg = (struct dpu_mdss_cfg){ + .caps = &sdm845_dpu_caps, + .mdp_count = ARRAY_SIZE(sdm845_mdp), + .mdp = sdm845_mdp, + .ctl_count = ARRAY_SIZE(sdm845_ctl), + .ctl = sdm845_ctl, + .sspp_count = ARRAY_SIZE(sdm845_sspp), + .sspp = sdm845_sspp, + .mixer_count = ARRAY_SIZE(sdm845_lm), + .mixer = sdm845_lm, + .ds_count = ARRAY_SIZE(sdm845_ds), + .ds = sdm845_ds, + .pingpong_count = ARRAY_SIZE(sdm845_pp), + .pingpong = sdm845_pp, + .cdm_count = ARRAY_SIZE(sdm845_cdm), + .cdm = sdm845_cdm, + .intf_count = ARRAY_SIZE(sdm845_intf), + .intf = sdm845_intf, + .vbif_count = ARRAY_SIZE(sdm845_vbif), + .vbif = sdm845_vbif, + .reg_dma_count = 1, + .dma_cfg = sdm845_regdma, + .perf = sdm845_perf_data, + }; +} + +static struct dpu_mdss_hw_cfg_handler cfg_handler[] = { + { .hw_rev = DPU_HW_VER_400, .cfg_init = sdm845_cfg_init}, + { .hw_rev = DPU_HW_VER_401, .cfg_init = sdm845_cfg_init}, +}; + +void dpu_hw_catalog_deinit(struct dpu_mdss_cfg *dpu_cfg) +{ + kfree(dpu_cfg); +} + +struct dpu_mdss_cfg *dpu_hw_catalog_init(u32 hw_rev) +{ + int i; + struct dpu_mdss_cfg *dpu_cfg; + + dpu_cfg = kzalloc(sizeof(*dpu_cfg), GFP_KERNEL); + if (!dpu_cfg) + return ERR_PTR(-ENOMEM); + + for (i = 0; i < ARRAY_SIZE(cfg_handler); i++) { + if (cfg_handler[i].hw_rev == hw_rev) { + cfg_handler[i].cfg_init(dpu_cfg); + dpu_cfg->hwversion = hw_rev; + return dpu_cfg; + } + } + + DPU_ERROR("unsupported chipset id:%X\n", hw_rev); + dpu_hw_catalog_deinit(dpu_cfg); + return ERR_PTR(-ENODEV); +} + diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h new file mode 100644 index 0000000000000..f0cb0d4fc80ea --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h @@ -0,0 +1,804 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef _DPU_HW_CATALOG_H +#define _DPU_HW_CATALOG_H + +#include <linux/kernel.h> +#include <linux/bug.h> +#include <linux/bitmap.h> +#include <linux/err.h> +#include <drm/drmP.h> + +/** + * Max hardware block count: For ex: max 12 SSPP pipes or + * 5 ctl paths. In all cases, it can have max 12 hardware blocks + * based on current design + */ +#define MAX_BLOCKS 12 + +#define DPU_HW_VER(MAJOR, MINOR, STEP) (((MAJOR & 0xF) << 28) |\ + ((MINOR & 0xFFF) << 16) |\ + (STEP & 0xFFFF)) + +#define DPU_HW_MAJOR(rev) ((rev) >> 28) +#define DPU_HW_MINOR(rev) (((rev) >> 16) & 0xFFF) +#define DPU_HW_STEP(rev) ((rev) & 0xFFFF) +#define DPU_HW_MAJOR_MINOR(rev) ((rev) >> 16) + +#define IS_DPU_MAJOR_MINOR_SAME(rev1, rev2) \ + (DPU_HW_MAJOR_MINOR((rev1)) == DPU_HW_MAJOR_MINOR((rev2))) + +#define DPU_HW_VER_170 DPU_HW_VER(1, 7, 0) /* 8996 v1.0 */ +#define DPU_HW_VER_171 DPU_HW_VER(1, 7, 1) /* 8996 v2.0 */ +#define DPU_HW_VER_172 DPU_HW_VER(1, 7, 2) /* 8996 v3.0 */ +#define DPU_HW_VER_300 DPU_HW_VER(3, 0, 0) /* 8998 v1.0 */ +#define DPU_HW_VER_301 DPU_HW_VER(3, 0, 1) /* 8998 v1.1 */ +#define DPU_HW_VER_400 DPU_HW_VER(4, 0, 0) /* sdm845 v1.0 */ +#define DPU_HW_VER_401 DPU_HW_VER(4, 0, 1) /* sdm845 v2.0 */ +#define DPU_HW_VER_410 DPU_HW_VER(4, 1, 0) /* sdm670 v1.0 */ +#define DPU_HW_VER_500 DPU_HW_VER(5, 0, 0) /* sdm855 v1.0 */ + + +#define IS_MSM8996_TARGET(rev) IS_DPU_MAJOR_MINOR_SAME((rev), DPU_HW_VER_170) +#define IS_MSM8998_TARGET(rev) IS_DPU_MAJOR_MINOR_SAME((rev), DPU_HW_VER_300) +#define IS_SDM845_TARGET(rev) IS_DPU_MAJOR_MINOR_SAME((rev), DPU_HW_VER_400) +#define IS_SDM670_TARGET(rev) IS_DPU_MAJOR_MINOR_SAME((rev), DPU_HW_VER_410) +#define IS_SDM855_TARGET(rev) IS_DPU_MAJOR_MINOR_SAME((rev), DPU_HW_VER_500) + + +#define DPU_HW_BLK_NAME_LEN 16 + +#define MAX_IMG_WIDTH 0x3fff +#define MAX_IMG_HEIGHT 0x3fff + +#define CRTC_DUAL_MIXERS 2 + +#define MAX_XIN_COUNT 16 + +/** + * Supported UBWC feature versions + */ +enum { + DPU_HW_UBWC_VER_10 = 0x100, + DPU_HW_UBWC_VER_20 = 0x200, + DPU_HW_UBWC_VER_30 = 0x300, +}; + +#define IS_UBWC_20_SUPPORTED(rev) ((rev) >= DPU_HW_UBWC_VER_20) + +/** + * MDP TOP BLOCK features + * @DPU_MDP_PANIC_PER_PIPE Panic configuration needs to be be done per pipe + * @DPU_MDP_10BIT_SUPPORT, Chipset supports 10 bit pixel formats + * @DPU_MDP_BWC, MDSS HW supports Bandwidth compression. + * @DPU_MDP_UBWC_1_0, This chipsets supports Universal Bandwidth + * compression initial revision + * @DPU_MDP_UBWC_1_5, Universal Bandwidth compression version 1.5 + * @DPU_MDP_MAX Maximum value + + */ +enum { + DPU_MDP_PANIC_PER_PIPE = 0x1, + DPU_MDP_10BIT_SUPPORT, + DPU_MDP_BWC, + DPU_MDP_UBWC_1_0, + DPU_MDP_UBWC_1_5, + DPU_MDP_MAX +}; + +/** + * SSPP sub-blocks/features + * @DPU_SSPP_SRC Src and fetch part of the pipes, + * @DPU_SSPP_SCALER_QSEED2, QSEED2 algorithm support + * @DPU_SSPP_SCALER_QSEED3, QSEED3 alogorithm support + * @DPU_SSPP_SCALER_RGB, RGB Scaler, supported by RGB pipes + * @DPU_SSPP_CSC, Support of Color space converion + * @DPU_SSPP_CSC_10BIT, Support of 10-bit Color space conversion + * @DPU_SSPP_CURSOR, SSPP can be used as a cursor layer + * @DPU_SSPP_QOS, SSPP support QoS control, danger/safe/creq + * @DPU_SSPP_QOS_8LVL, SSPP support 8-level QoS control + * @DPU_SSPP_EXCL_RECT, SSPP supports exclusion rect + * @DPU_SSPP_SMART_DMA_V1, SmartDMA 1.0 support + * @DPU_SSPP_SMART_DMA_V2, SmartDMA 2.0 support + * @DPU_SSPP_TS_PREFILL Supports prefill with traffic shaper + * @DPU_SSPP_TS_PREFILL_REC1 Supports prefill with traffic shaper multirec + * @DPU_SSPP_CDP Supports client driven prefetch + * @DPU_SSPP_MAX maximum value + */ +enum { + DPU_SSPP_SRC = 0x1, + DPU_SSPP_SCALER_QSEED2, + DPU_SSPP_SCALER_QSEED3, + DPU_SSPP_SCALER_RGB, + DPU_SSPP_CSC, + DPU_SSPP_CSC_10BIT, + DPU_SSPP_CURSOR, + DPU_SSPP_QOS, + DPU_SSPP_QOS_8LVL, + DPU_SSPP_EXCL_RECT, + DPU_SSPP_SMART_DMA_V1, + DPU_SSPP_SMART_DMA_V2, + DPU_SSPP_TS_PREFILL, + DPU_SSPP_TS_PREFILL_REC1, + DPU_SSPP_CDP, + DPU_SSPP_MAX +}; + +/* + * MIXER sub-blocks/features + * @DPU_MIXER_LAYER Layer mixer layer blend configuration, + * @DPU_MIXER_SOURCESPLIT Layer mixer supports source-split configuration + * @DPU_MIXER_GC Gamma correction block + * @DPU_DIM_LAYER Layer mixer supports dim layer + * @DPU_MIXER_MAX maximum value + */ +enum { + DPU_MIXER_LAYER = 0x1, + DPU_MIXER_SOURCESPLIT, + DPU_MIXER_GC, + DPU_DIM_LAYER, + DPU_MIXER_MAX +}; + +/** + * PINGPONG sub-blocks + * @DPU_PINGPONG_TE Tear check block + * @DPU_PINGPONG_TE2 Additional tear check block for split pipes + * @DPU_PINGPONG_SPLIT PP block supports split fifo + * @DPU_PINGPONG_SLAVE PP block is a suitable slave for split fifo + * @DPU_PINGPONG_DITHER, Dither blocks + * @DPU_PINGPONG_MAX + */ +enum { + DPU_PINGPONG_TE = 0x1, + DPU_PINGPONG_TE2, + DPU_PINGPONG_SPLIT, + DPU_PINGPONG_SLAVE, + DPU_PINGPONG_DITHER, + DPU_PINGPONG_MAX +}; + +/** + * CTL sub-blocks + * @DPU_CTL_SPLIT_DISPLAY CTL supports video mode split display + * @DPU_CTL_MAX + */ +enum { + DPU_CTL_SPLIT_DISPLAY = 0x1, + DPU_CTL_MAX +}; + +/** + * VBIF sub-blocks and features + * @DPU_VBIF_QOS_OTLIM VBIF supports OT Limit + * @DPU_VBIF_QOS_REMAP VBIF supports QoS priority remap + * @DPU_VBIF_MAX maximum value + */ +enum { + DPU_VBIF_QOS_OTLIM = 0x1, + DPU_VBIF_QOS_REMAP, + DPU_VBIF_MAX +}; + +/** + * MACRO DPU_HW_BLK_INFO - information of HW blocks inside DPU + * @name: string name for debug purposes + * @id: enum identifying this block + * @base: register base offset to mdss + * @len: length of hardware block + * @features bit mask identifying sub-blocks/features + */ +#define DPU_HW_BLK_INFO \ + char name[DPU_HW_BLK_NAME_LEN]; \ + u32 id; \ + u32 base; \ + u32 len; \ + unsigned long features + +/** + * MACRO DPU_HW_SUBBLK_INFO - information of HW sub-block inside DPU + * @name: string name for debug purposes + * @id: enum identifying this sub-block + * @base: offset of this sub-block relative to the block + * offset + * @len register block length of this sub-block + */ +#define DPU_HW_SUBBLK_INFO \ + char name[DPU_HW_BLK_NAME_LEN]; \ + u32 id; \ + u32 base; \ + u32 len + +/** + * struct dpu_src_blk: SSPP part of the source pipes + * @info: HW register and features supported by this sub-blk + */ +struct dpu_src_blk { + DPU_HW_SUBBLK_INFO; +}; + +/** + * struct dpu_scaler_blk: Scaler information + * @info: HW register and features supported by this sub-blk + * @version: qseed block revision + */ +struct dpu_scaler_blk { + DPU_HW_SUBBLK_INFO; + u32 version; +}; + +struct dpu_csc_blk { + DPU_HW_SUBBLK_INFO; +}; + +/** + * struct dpu_pp_blk : Pixel processing sub-blk information + * @info: HW register and features supported by this sub-blk + * @version: HW Algorithm version + */ +struct dpu_pp_blk { + DPU_HW_SUBBLK_INFO; + u32 version; +}; + +/** + * struct dpu_format_extended - define dpu specific pixel format+modifier + * @fourcc_format: Base FOURCC pixel format code + * @modifier: 64-bit drm format modifier, same modifier must be applied to all + * framebuffer planes + */ +struct dpu_format_extended { + uint32_t fourcc_format; + uint64_t modifier; +}; + +/** + * enum dpu_qos_lut_usage - define QoS LUT use cases + */ +enum dpu_qos_lut_usage { + DPU_QOS_LUT_USAGE_LINEAR, + DPU_QOS_LUT_USAGE_MACROTILE, + DPU_QOS_LUT_USAGE_NRT, + DPU_QOS_LUT_USAGE_MAX, +}; + +/** + * struct dpu_qos_lut_entry - define QoS LUT table entry + * @fl: fill level, or zero on last entry to indicate default lut + * @lut: lut to use if equal to or less than fill level + */ +struct dpu_qos_lut_entry { + u32 fl; + u64 lut; +}; + +/** + * struct dpu_qos_lut_tbl - define QoS LUT table + * @nentry: number of entry in this table + * @entries: Pointer to table entries + */ +struct dpu_qos_lut_tbl { + u32 nentry; + struct dpu_qos_lut_entry *entries; +}; + +/** + * struct dpu_caps - define DPU capabilities + * @max_mixer_width max layer mixer line width support. + * @max_mixer_blendstages max layer mixer blend stages or + * supported z order + * @qseed_type qseed2 or qseed3 support. + * @smart_dma_rev Supported version of SmartDMA feature. + * @ubwc_version UBWC feature version (0x0 for not supported) + * @has_src_split source split feature status + * @has_dim_layer dim layer feature status + * @has_idle_pc indicate if idle power collapse feature is supported + */ +struct dpu_caps { + u32 max_mixer_width; + u32 max_mixer_blendstages; + u32 qseed_type; + u32 smart_dma_rev; + u32 ubwc_version; + bool has_src_split; + bool has_dim_layer; + bool has_idle_pc; +}; + +/** + * struct dpu_sspp_blks_common : SSPP sub-blocks common configuration + * @maxwidth: max pixelwidth supported by this pipe + * @pixel_ram_size: size of latency hiding and de-tiling buffer in bytes + * @maxhdeciexp: max horizontal decimation supported by this pipe + * (max is 2^value) + * @maxvdeciexp: max vertical decimation supported by this pipe + * (max is 2^value) + */ +struct dpu_sspp_blks_common { + u32 maxlinewidth; + u32 pixel_ram_size; + u32 maxhdeciexp; + u32 maxvdeciexp; +}; + +/** + * struct dpu_sspp_sub_blks : SSPP sub-blocks + * common: Pointer to common configurations shared by sub blocks + * @creq_vblank: creq priority during vertical blanking + * @danger_vblank: danger priority during vertical blanking + * @maxdwnscale: max downscale ratio supported(without DECIMATION) + * @maxupscale: maxupscale ratio supported + * @smart_dma_priority: hw priority of rect1 of multirect pipe + * @max_per_pipe_bw: maximum allowable bandwidth of this pipe in kBps + * @src_blk: + * @scaler_blk: + * @csc_blk: + * @hsic: + * @memcolor: + * @pcc_blk: + * @igc_blk: + * @format_list: Pointer to list of supported formats + * @virt_format_list: Pointer to list of supported formats for virtual planes + */ +struct dpu_sspp_sub_blks { + const struct dpu_sspp_blks_common *common; + u32 creq_vblank; + u32 danger_vblank; + u32 maxdwnscale; + u32 maxupscale; + u32 smart_dma_priority; + u32 max_per_pipe_bw; + struct dpu_src_blk src_blk; + struct dpu_scaler_blk scaler_blk; + struct dpu_pp_blk csc_blk; + struct dpu_pp_blk hsic_blk; + struct dpu_pp_blk memcolor_blk; + struct dpu_pp_blk pcc_blk; + struct dpu_pp_blk igc_blk; + + const struct dpu_format_extended *format_list; + const struct dpu_format_extended *virt_format_list; +}; + +/** + * struct dpu_lm_sub_blks: information of mixer block + * @maxwidth: Max pixel width supported by this mixer + * @maxblendstages: Max number of blend-stages supported + * @blendstage_base: Blend-stage register base offset + * @gc: gamma correction block + */ +struct dpu_lm_sub_blks { + u32 maxwidth; + u32 maxblendstages; + u32 blendstage_base[MAX_BLOCKS]; + struct dpu_pp_blk gc; +}; + +struct dpu_pingpong_sub_blks { + struct dpu_pp_blk te; + struct dpu_pp_blk te2; + struct dpu_pp_blk dither; +}; + +/** + * dpu_clk_ctrl_type - Defines top level clock control signals + */ +enum dpu_clk_ctrl_type { + DPU_CLK_CTRL_NONE, + DPU_CLK_CTRL_VIG0, + DPU_CLK_CTRL_VIG1, + DPU_CLK_CTRL_VIG2, + DPU_CLK_CTRL_VIG3, + DPU_CLK_CTRL_VIG4, + DPU_CLK_CTRL_RGB0, + DPU_CLK_CTRL_RGB1, + DPU_CLK_CTRL_RGB2, + DPU_CLK_CTRL_RGB3, + DPU_CLK_CTRL_DMA0, + DPU_CLK_CTRL_DMA1, + DPU_CLK_CTRL_CURSOR0, + DPU_CLK_CTRL_CURSOR1, + DPU_CLK_CTRL_INLINE_ROT0_SSPP, + DPU_CLK_CTRL_MAX, +}; + +/* struct dpu_clk_ctrl_reg : Clock control register + * @reg_off: register offset + * @bit_off: bit offset + */ +struct dpu_clk_ctrl_reg { + u32 reg_off; + u32 bit_off; +}; + +/* struct dpu_mdp_cfg : MDP TOP-BLK instance info + * @id: index identifying this block + * @base: register base offset to mdss + * @features bit mask identifying sub-blocks/features + * @highest_bank_bit: UBWC parameter + * @ubwc_static: ubwc static configuration + * @ubwc_swizzle: ubwc default swizzle setting + * @has_dest_scaler: indicates support of destination scaler + * @clk_ctrls clock control register definition + */ +struct dpu_mdp_cfg { + DPU_HW_BLK_INFO; + u32 highest_bank_bit; + u32 ubwc_static; + u32 ubwc_swizzle; + bool has_dest_scaler; + struct dpu_clk_ctrl_reg clk_ctrls[DPU_CLK_CTRL_MAX]; +}; + +/* struct dpu_mdp_cfg : MDP TOP-BLK instance info + * @id: index identifying this block + * @base: register base offset to mdss + * @features bit mask identifying sub-blocks/features + */ +struct dpu_ctl_cfg { + DPU_HW_BLK_INFO; +}; + +/** + * struct dpu_sspp_cfg - information of source pipes + * @id: index identifying this block + * @base register offset of this block + * @features bit mask identifying sub-blocks/features + * @sblk: SSPP sub-blocks information + * @xin_id: bus client identifier + * @clk_ctrl clock control identifier + * @type sspp type identifier + */ +struct dpu_sspp_cfg { + DPU_HW_BLK_INFO; + const struct dpu_sspp_sub_blks *sblk; + u32 xin_id; + enum dpu_clk_ctrl_type clk_ctrl; + u32 type; +}; + +/** + * struct dpu_lm_cfg - information of layer mixer blocks + * @id: index identifying this block + * @base register offset of this block + * @features bit mask identifying sub-blocks/features + * @sblk: LM Sub-blocks information + * @pingpong: ID of connected PingPong, PINGPONG_MAX if unsupported + * @ds: ID of connected DS, DS_MAX if unsupported + * @lm_pair_mask: Bitmask of LMs that can be controlled by same CTL + */ +struct dpu_lm_cfg { + DPU_HW_BLK_INFO; + const struct dpu_lm_sub_blks *sblk; + u32 pingpong; + u32 ds; + unsigned long lm_pair_mask; +}; + +/** + * struct dpu_ds_top_cfg - information of dest scaler top + * @id enum identifying this block + * @base register offset of this block + * @features bit mask identifying features + * @version hw version of dest scaler + * @maxinputwidth maximum input line width + * @maxoutputwidth maximum output line width + * @maxupscale maximum upscale ratio + */ +struct dpu_ds_top_cfg { + DPU_HW_BLK_INFO; + u32 version; + u32 maxinputwidth; + u32 maxoutputwidth; + u32 maxupscale; +}; + +/** + * struct dpu_ds_cfg - information of dest scaler blocks + * @id enum identifying this block + * @base register offset wrt DS top offset + * @features bit mask identifying features + * @version hw version of the qseed block + * @top DS top information + */ +struct dpu_ds_cfg { + DPU_HW_BLK_INFO; + u32 version; + const struct dpu_ds_top_cfg *top; +}; + +/** + * struct dpu_pingpong_cfg - information of PING-PONG blocks + * @id enum identifying this block + * @base register offset of this block + * @features bit mask identifying sub-blocks/features + * @sblk sub-blocks information + */ +struct dpu_pingpong_cfg { + DPU_HW_BLK_INFO; + const struct dpu_pingpong_sub_blks *sblk; +}; + +/** + * struct dpu_cdm_cfg - information of chroma down blocks + * @id enum identifying this block + * @base register offset of this block + * @features bit mask identifying sub-blocks/features + * @intf_connect Bitmask of INTF IDs this CDM can connect to + */ +struct dpu_cdm_cfg { + DPU_HW_BLK_INFO; + unsigned long intf_connect; +}; + +/** + * struct dpu_intf_cfg - information of timing engine blocks + * @id enum identifying this block + * @base register offset of this block + * @features bit mask identifying sub-blocks/features + * @type: Interface type(DSI, DP, HDMI) + * @controller_id: Controller Instance ID in case of multiple of intf type + * @prog_fetch_lines_worst_case Worst case latency num lines needed to prefetch + */ +struct dpu_intf_cfg { + DPU_HW_BLK_INFO; + u32 type; /* interface type*/ + u32 controller_id; + u32 prog_fetch_lines_worst_case; +}; + +/** + * struct dpu_vbif_dynamic_ot_cfg - dynamic OT setting + * @pps pixel per seconds + * @ot_limit OT limit to use up to specified pixel per second + */ +struct dpu_vbif_dynamic_ot_cfg { + u64 pps; + u32 ot_limit; +}; + +/** + * struct dpu_vbif_dynamic_ot_tbl - dynamic OT setting table + * @count length of cfg + * @cfg pointer to array of configuration settings with + * ascending requirements + */ +struct dpu_vbif_dynamic_ot_tbl { + u32 count; + struct dpu_vbif_dynamic_ot_cfg *cfg; +}; + +/** + * struct dpu_vbif_qos_tbl - QoS priority table + * @npriority_lvl num of priority level + * @priority_lvl pointer to array of priority level in ascending order + */ +struct dpu_vbif_qos_tbl { + u32 npriority_lvl; + u32 *priority_lvl; +}; + +/** + * struct dpu_vbif_cfg - information of VBIF blocks + * @id enum identifying this block + * @base register offset of this block + * @features bit mask identifying sub-blocks/features + * @ot_rd_limit default OT read limit + * @ot_wr_limit default OT write limit + * @xin_halt_timeout maximum time (in usec) for xin to halt + * @dynamic_ot_rd_tbl dynamic OT read configuration table + * @dynamic_ot_wr_tbl dynamic OT write configuration table + * @qos_rt_tbl real-time QoS priority table + * @qos_nrt_tbl non-real-time QoS priority table + * @memtype_count number of defined memtypes + * @memtype array of xin memtype definitions + */ +struct dpu_vbif_cfg { + DPU_HW_BLK_INFO; + u32 default_ot_rd_limit; + u32 default_ot_wr_limit; + u32 xin_halt_timeout; + struct dpu_vbif_dynamic_ot_tbl dynamic_ot_rd_tbl; + struct dpu_vbif_dynamic_ot_tbl dynamic_ot_wr_tbl; + struct dpu_vbif_qos_tbl qos_rt_tbl; + struct dpu_vbif_qos_tbl qos_nrt_tbl; + u32 memtype_count; + u32 memtype[MAX_XIN_COUNT]; +}; +/** + * struct dpu_reg_dma_cfg - information of lut dma blocks + * @id enum identifying this block + * @base register offset of this block + * @features bit mask identifying sub-blocks/features + * @version version of lutdma hw block + * @trigger_sel_off offset to trigger select registers of lutdma + */ +struct dpu_reg_dma_cfg { + DPU_HW_BLK_INFO; + u32 version; + u32 trigger_sel_off; +}; + +/** + * Define CDP use cases + * @DPU_PERF_CDP_UDAGE_RT: real-time use cases + * @DPU_PERF_CDP_USAGE_NRT: non real-time use cases such as WFD + */ +enum { + DPU_PERF_CDP_USAGE_RT, + DPU_PERF_CDP_USAGE_NRT, + DPU_PERF_CDP_USAGE_MAX +}; + +/** + * struct dpu_perf_cdp_cfg - define CDP use case configuration + * @rd_enable: true if read pipe CDP is enabled + * @wr_enable: true if write pipe CDP is enabled + */ +struct dpu_perf_cdp_cfg { + bool rd_enable; + bool wr_enable; +}; + +/** + * struct dpu_perf_cfg - performance control settings + * @max_bw_low low threshold of maximum bandwidth (kbps) + * @max_bw_high high threshold of maximum bandwidth (kbps) + * @min_core_ib minimum bandwidth for core (kbps) + * @min_core_ib minimum mnoc ib vote in kbps + * @min_llcc_ib minimum llcc ib vote in kbps + * @min_dram_ib minimum dram ib vote in kbps + * @core_ib_ff core instantaneous bandwidth fudge factor + * @core_clk_ff core clock fudge factor + * @comp_ratio_rt string of 0 or more of <fourcc>/<ven>/<mod>/<comp ratio> + * @comp_ratio_nrt string of 0 or more of <fourcc>/<ven>/<mod>/<comp ratio> + * @undersized_prefill_lines undersized prefill in lines + * @xtra_prefill_lines extra prefill latency in lines + * @dest_scale_prefill_lines destination scaler latency in lines + * @macrotile_perfill_lines macrotile latency in lines + * @yuv_nv12_prefill_lines yuv_nv12 latency in lines + * @linear_prefill_lines linear latency in lines + * @downscaling_prefill_lines downscaling latency in lines + * @amortizable_theshold minimum y position for traffic shaping prefill + * @min_prefill_lines minimum pipeline latency in lines + * @safe_lut_tbl: LUT tables for safe signals + * @danger_lut_tbl: LUT tables for danger signals + * @qos_lut_tbl: LUT tables for QoS signals + * @cdp_cfg cdp use case configurations + */ +struct dpu_perf_cfg { + u32 max_bw_low; + u32 max_bw_high; + u32 min_core_ib; + u32 min_llcc_ib; + u32 min_dram_ib; + const char *core_ib_ff; + const char *core_clk_ff; + const char *comp_ratio_rt; + const char *comp_ratio_nrt; + u32 undersized_prefill_lines; + u32 xtra_prefill_lines; + u32 dest_scale_prefill_lines; + u32 macrotile_prefill_lines; + u32 yuv_nv12_prefill_lines; + u32 linear_prefill_lines; + u32 downscaling_prefill_lines; + u32 amortizable_threshold; + u32 min_prefill_lines; + u32 safe_lut_tbl[DPU_QOS_LUT_USAGE_MAX]; + u32 danger_lut_tbl[DPU_QOS_LUT_USAGE_MAX]; + struct dpu_qos_lut_tbl qos_lut_tbl[DPU_QOS_LUT_USAGE_MAX]; + struct dpu_perf_cdp_cfg cdp_cfg[DPU_PERF_CDP_USAGE_MAX]; +}; + +/** + * struct dpu_mdss_cfg - information of MDSS HW + * This is the main catalog data structure representing + * this HW version. Contains number of instances, + * register offsets, capabilities of the all MDSS HW sub-blocks. + * + * @dma_formats Supported formats for dma pipe + * @cursor_formats Supported formats for cursor pipe + * @vig_formats Supported formats for vig pipe + */ +struct dpu_mdss_cfg { + u32 hwversion; + + const struct dpu_caps *caps; + + u32 mdp_count; + struct dpu_mdp_cfg *mdp; + + u32 ctl_count; + struct dpu_ctl_cfg *ctl; + + u32 sspp_count; + struct dpu_sspp_cfg *sspp; + + u32 mixer_count; + struct dpu_lm_cfg *mixer; + + u32 ds_count; + struct dpu_ds_cfg *ds; + + u32 pingpong_count; + struct dpu_pingpong_cfg *pingpong; + + u32 cdm_count; + struct dpu_cdm_cfg *cdm; + + u32 intf_count; + struct dpu_intf_cfg *intf; + + u32 vbif_count; + struct dpu_vbif_cfg *vbif; + + u32 reg_dma_count; + struct dpu_reg_dma_cfg dma_cfg; + + u32 ad_count; + + /* Add additional block data structures here */ + + struct dpu_perf_cfg perf; + struct dpu_format_extended *dma_formats; + struct dpu_format_extended *cursor_formats; + struct dpu_format_extended *vig_formats; +}; + +struct dpu_mdss_hw_cfg_handler { + u32 hw_rev; + void (*cfg_init)(struct dpu_mdss_cfg *dpu_cfg); +}; + +/* + * Access Macros + */ +#define BLK_MDP(s) ((s)->mdp) +#define BLK_CTL(s) ((s)->ctl) +#define BLK_VIG(s) ((s)->vig) +#define BLK_RGB(s) ((s)->rgb) +#define BLK_DMA(s) ((s)->dma) +#define BLK_CURSOR(s) ((s)->cursor) +#define BLK_MIXER(s) ((s)->mixer) +#define BLK_DS(s) ((s)->ds) +#define BLK_PINGPONG(s) ((s)->pingpong) +#define BLK_CDM(s) ((s)->cdm) +#define BLK_INTF(s) ((s)->intf) +#define BLK_AD(s) ((s)->ad) + +/** + * dpu_hw_catalog_init - dpu hardware catalog init API retrieves + * hardcoded target specific catalog information in config structure + * @hw_rev: caller needs provide the hardware revision. + * + * Return: dpu config structure + */ +struct dpu_mdss_cfg *dpu_hw_catalog_init(u32 hw_rev); + +/** + * dpu_hw_catalog_deinit - dpu hardware catalog cleanup + * @dpu_cfg: pointer returned from init function + */ +void dpu_hw_catalog_deinit(struct dpu_mdss_cfg *dpu_cfg); + +/** + * dpu_hw_sspp_multirect_enabled - check multirect enabled for the sspp + * @cfg: pointer to sspp cfg + */ +static inline bool dpu_hw_sspp_multirect_enabled(const struct dpu_sspp_cfg *cfg) +{ + return test_bit(DPU_SSPP_SMART_DMA_V1, &cfg->features) || + test_bit(DPU_SSPP_SMART_DMA_V2, &cfg->features); +} +#endif /* _DPU_HW_CATALOG_H */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog_format.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog_format.h new file mode 100644 index 0000000000000..3c9f028628ef1 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog_format.h @@ -0,0 +1,168 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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 "dpu_hw_mdss.h" + +static const struct dpu_format_extended plane_formats[] = { + {DRM_FORMAT_ARGB8888, 0}, + {DRM_FORMAT_ABGR8888, 0}, + {DRM_FORMAT_RGBA8888, 0}, + {DRM_FORMAT_ABGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED}, + {DRM_FORMAT_BGRA8888, 0}, + {DRM_FORMAT_XRGB8888, 0}, + {DRM_FORMAT_RGBX8888, 0}, + {DRM_FORMAT_BGRX8888, 0}, + {DRM_FORMAT_XBGR8888, 0}, + {DRM_FORMAT_XBGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED}, + {DRM_FORMAT_RGB888, 0}, + {DRM_FORMAT_BGR888, 0}, + {DRM_FORMAT_RGB565, 0}, + {DRM_FORMAT_BGR565, DRM_FORMAT_MOD_QCOM_COMPRESSED}, + {DRM_FORMAT_BGR565, 0}, + {DRM_FORMAT_ARGB1555, 0}, + {DRM_FORMAT_ABGR1555, 0}, + {DRM_FORMAT_RGBA5551, 0}, + {DRM_FORMAT_BGRA5551, 0}, + {DRM_FORMAT_XRGB1555, 0}, + {DRM_FORMAT_XBGR1555, 0}, + {DRM_FORMAT_RGBX5551, 0}, + {DRM_FORMAT_BGRX5551, 0}, + {DRM_FORMAT_ARGB4444, 0}, + {DRM_FORMAT_ABGR4444, 0}, + {DRM_FORMAT_RGBA4444, 0}, + {DRM_FORMAT_BGRA4444, 0}, + {DRM_FORMAT_XRGB4444, 0}, + {DRM_FORMAT_XBGR4444, 0}, + {DRM_FORMAT_RGBX4444, 0}, + {DRM_FORMAT_BGRX4444, 0}, + {0, 0}, +}; + +static const struct dpu_format_extended plane_formats_yuv[] = { + {DRM_FORMAT_ARGB8888, 0}, + {DRM_FORMAT_ABGR8888, 0}, + {DRM_FORMAT_RGBA8888, 0}, + {DRM_FORMAT_BGRX8888, 0}, + {DRM_FORMAT_ABGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED}, + {DRM_FORMAT_BGRA8888, 0}, + {DRM_FORMAT_XRGB8888, 0}, + {DRM_FORMAT_XBGR8888, 0}, + {DRM_FORMAT_RGBX8888, 0}, + {DRM_FORMAT_XBGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED}, + {DRM_FORMAT_RGB888, 0}, + {DRM_FORMAT_BGR888, 0}, + {DRM_FORMAT_RGB565, 0}, + {DRM_FORMAT_BGR565, DRM_FORMAT_MOD_QCOM_COMPRESSED}, + {DRM_FORMAT_BGR565, 0}, + {DRM_FORMAT_ARGB1555, 0}, + {DRM_FORMAT_ABGR1555, 0}, + {DRM_FORMAT_RGBA5551, 0}, + {DRM_FORMAT_BGRA5551, 0}, + {DRM_FORMAT_XRGB1555, 0}, + {DRM_FORMAT_XBGR1555, 0}, + {DRM_FORMAT_RGBX5551, 0}, + {DRM_FORMAT_BGRX5551, 0}, + {DRM_FORMAT_ARGB4444, 0}, + {DRM_FORMAT_ABGR4444, 0}, + {DRM_FORMAT_RGBA4444, 0}, + {DRM_FORMAT_BGRA4444, 0}, + {DRM_FORMAT_XRGB4444, 0}, + {DRM_FORMAT_XBGR4444, 0}, + {DRM_FORMAT_RGBX4444, 0}, + {DRM_FORMAT_BGRX4444, 0}, + + {DRM_FORMAT_NV12, 0}, + {DRM_FORMAT_NV12, DRM_FORMAT_MOD_QCOM_COMPRESSED}, + {DRM_FORMAT_NV21, 0}, + {DRM_FORMAT_NV16, 0}, + {DRM_FORMAT_NV61, 0}, + {DRM_FORMAT_VYUY, 0}, + {DRM_FORMAT_UYVY, 0}, + {DRM_FORMAT_YUYV, 0}, + {DRM_FORMAT_YVYU, 0}, + {DRM_FORMAT_YUV420, 0}, + {DRM_FORMAT_YVU420, 0}, + {0, 0}, +}; + +static const struct dpu_format_extended cursor_formats[] = { + {DRM_FORMAT_ARGB8888, 0}, + {DRM_FORMAT_ABGR8888, 0}, + {DRM_FORMAT_RGBA8888, 0}, + {DRM_FORMAT_BGRA8888, 0}, + {DRM_FORMAT_XRGB8888, 0}, + {DRM_FORMAT_ARGB1555, 0}, + {DRM_FORMAT_ABGR1555, 0}, + {DRM_FORMAT_RGBA5551, 0}, + {DRM_FORMAT_BGRA5551, 0}, + {DRM_FORMAT_ARGB4444, 0}, + {DRM_FORMAT_ABGR4444, 0}, + {DRM_FORMAT_RGBA4444, 0}, + {DRM_FORMAT_BGRA4444, 0}, + {0, 0}, +}; + +static const struct dpu_format_extended wb2_formats[] = { + {DRM_FORMAT_RGB565, 0}, + {DRM_FORMAT_BGR565, DRM_FORMAT_MOD_QCOM_COMPRESSED}, + {DRM_FORMAT_RGB888, 0}, + {DRM_FORMAT_ARGB8888, 0}, + {DRM_FORMAT_RGBA8888, 0}, + {DRM_FORMAT_ABGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED}, + {DRM_FORMAT_XRGB8888, 0}, + {DRM_FORMAT_RGBX8888, 0}, + {DRM_FORMAT_XBGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED}, + {DRM_FORMAT_ARGB1555, 0}, + {DRM_FORMAT_RGBA5551, 0}, + {DRM_FORMAT_XRGB1555, 0}, + {DRM_FORMAT_RGBX5551, 0}, + {DRM_FORMAT_ARGB4444, 0}, + {DRM_FORMAT_RGBA4444, 0}, + {DRM_FORMAT_RGBX4444, 0}, + {DRM_FORMAT_XRGB4444, 0}, + + {DRM_FORMAT_BGR565, 0}, + {DRM_FORMAT_BGR888, 0}, + {DRM_FORMAT_ABGR8888, 0}, + {DRM_FORMAT_BGRA8888, 0}, + {DRM_FORMAT_BGRX8888, 0}, + {DRM_FORMAT_XBGR8888, 0}, + {DRM_FORMAT_ABGR1555, 0}, + {DRM_FORMAT_BGRA5551, 0}, + {DRM_FORMAT_XBGR1555, 0}, + {DRM_FORMAT_BGRX5551, 0}, + {DRM_FORMAT_ABGR4444, 0}, + {DRM_FORMAT_BGRA4444, 0}, + {DRM_FORMAT_BGRX4444, 0}, + {DRM_FORMAT_XBGR4444, 0}, + + {DRM_FORMAT_YUV420, 0}, + {DRM_FORMAT_NV12, 0}, + {DRM_FORMAT_NV12, DRM_FORMAT_MOD_QCOM_COMPRESSED}, + {DRM_FORMAT_NV16, 0}, + {DRM_FORMAT_YUYV, 0}, + + {0, 0}, +}; + +static const struct dpu_format_extended rgb_10bit_formats[] = { + {DRM_FORMAT_BGRA1010102, 0}, + {DRM_FORMAT_BGRX1010102, 0}, + {DRM_FORMAT_RGBA1010102, 0}, + {DRM_FORMAT_RGBX1010102, 0}, + {DRM_FORMAT_ABGR2101010, 0}, + {DRM_FORMAT_ABGR2101010, DRM_FORMAT_MOD_QCOM_COMPRESSED}, + {DRM_FORMAT_XBGR2101010, 0}, + {DRM_FORMAT_XBGR2101010, DRM_FORMAT_MOD_QCOM_COMPRESSED}, + {DRM_FORMAT_ARGB2101010, 0}, + {DRM_FORMAT_XRGB2101010, 0}, +}; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c new file mode 100644 index 0000000000000..da6f0609be5f0 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c @@ -0,0 +1,323 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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 "dpu_hw_mdss.h" +#include "dpu_hwio.h" +#include "dpu_hw_catalog.h" +#include "dpu_hw_cdm.h" +#include "dpu_dbg.h" +#include "dpu_kms.h" + +#define CDM_CSC_10_OPMODE 0x000 +#define CDM_CSC_10_BASE 0x004 + +#define CDM_CDWN2_OP_MODE 0x100 +#define CDM_CDWN2_CLAMP_OUT 0x104 +#define CDM_CDWN2_PARAMS_3D_0 0x108 +#define CDM_CDWN2_PARAMS_3D_1 0x10C +#define CDM_CDWN2_COEFF_COSITE_H_0 0x110 +#define CDM_CDWN2_COEFF_COSITE_H_1 0x114 +#define CDM_CDWN2_COEFF_COSITE_H_2 0x118 +#define CDM_CDWN2_COEFF_OFFSITE_H_0 0x11C +#define CDM_CDWN2_COEFF_OFFSITE_H_1 0x120 +#define CDM_CDWN2_COEFF_OFFSITE_H_2 0x124 +#define CDM_CDWN2_COEFF_COSITE_V 0x128 +#define CDM_CDWN2_COEFF_OFFSITE_V 0x12C +#define CDM_CDWN2_OUT_SIZE 0x130 + +#define CDM_HDMI_PACK_OP_MODE 0x200 +#define CDM_CSC_10_MATRIX_COEFF_0 0x004 + +/** + * Horizontal coefficients for cosite chroma downscale + * s13 representation of coefficients + */ +static u32 cosite_h_coeff[] = {0x00000016, 0x000001cc, 0x0100009e}; + +/** + * Horizontal coefficients for offsite chroma downscale + */ +static u32 offsite_h_coeff[] = {0x000b0005, 0x01db01eb, 0x00e40046}; + +/** + * Vertical coefficients for cosite chroma downscale + */ +static u32 cosite_v_coeff[] = {0x00080004}; +/** + * Vertical coefficients for offsite chroma downscale + */ +static u32 offsite_v_coeff[] = {0x00060002}; + +/* Limited Range rgb2yuv coeff with clamp and bias values for CSC 10 module */ +static struct dpu_csc_cfg rgb2yuv_cfg = { + { + 0x0083, 0x0102, 0x0032, + 0x1fb5, 0x1f6c, 0x00e1, + 0x00e1, 0x1f45, 0x1fdc + }, + { 0x00, 0x00, 0x00 }, + { 0x0040, 0x0200, 0x0200 }, + { 0x000, 0x3ff, 0x000, 0x3ff, 0x000, 0x3ff }, + { 0x040, 0x3ac, 0x040, 0x3c0, 0x040, 0x3c0 }, +}; + +static struct dpu_cdm_cfg *_cdm_offset(enum dpu_cdm cdm, + struct dpu_mdss_cfg *m, + void __iomem *addr, + struct dpu_hw_blk_reg_map *b) +{ + int i; + + for (i = 0; i < m->cdm_count; i++) { + if (cdm == m->cdm[i].id) { + b->base_off = addr; + b->blk_off = m->cdm[i].base; + b->length = m->cdm[i].len; + b->hwversion = m->hwversion; + b->log_mask = DPU_DBG_MASK_CDM; + return &m->cdm[i]; + } + } + + return ERR_PTR(-EINVAL); +} + +static int dpu_hw_cdm_setup_csc_10bit(struct dpu_hw_cdm *ctx, + struct dpu_csc_cfg *data) +{ + dpu_hw_csc_setup(&ctx->hw, CDM_CSC_10_MATRIX_COEFF_0, data, true); + + return 0; +} + +static int dpu_hw_cdm_setup_cdwn(struct dpu_hw_cdm *ctx, + struct dpu_hw_cdm_cfg *cfg) +{ + struct dpu_hw_blk_reg_map *c = &ctx->hw; + u32 opmode = 0; + u32 out_size = 0; + + if (cfg->output_bit_depth == CDM_CDWN_OUTPUT_10BIT) + opmode &= ~BIT(7); + else + opmode |= BIT(7); + + /* ENABLE DWNS_H bit */ + opmode |= BIT(1); + + switch (cfg->h_cdwn_type) { + case CDM_CDWN_DISABLE: + /* CLEAR METHOD_H field */ + opmode &= ~(0x18); + /* CLEAR DWNS_H bit */ + opmode &= ~BIT(1); + break; + case CDM_CDWN_PIXEL_DROP: + /* Clear METHOD_H field (pixel drop is 0) */ + opmode &= ~(0x18); + break; + case CDM_CDWN_AVG: + /* Clear METHOD_H field (Average is 0x1) */ + opmode &= ~(0x18); + opmode |= (0x1 << 0x3); + break; + case CDM_CDWN_COSITE: + /* Clear METHOD_H field (Average is 0x2) */ + opmode &= ~(0x18); + opmode |= (0x2 << 0x3); + /* Co-site horizontal coefficients */ + DPU_REG_WRITE(c, CDM_CDWN2_COEFF_COSITE_H_0, + cosite_h_coeff[0]); + DPU_REG_WRITE(c, CDM_CDWN2_COEFF_COSITE_H_1, + cosite_h_coeff[1]); + DPU_REG_WRITE(c, CDM_CDWN2_COEFF_COSITE_H_2, + cosite_h_coeff[2]); + break; + case CDM_CDWN_OFFSITE: + /* Clear METHOD_H field (Average is 0x3) */ + opmode &= ~(0x18); + opmode |= (0x3 << 0x3); + + /* Off-site horizontal coefficients */ + DPU_REG_WRITE(c, CDM_CDWN2_COEFF_OFFSITE_H_0, + offsite_h_coeff[0]); + DPU_REG_WRITE(c, CDM_CDWN2_COEFF_OFFSITE_H_1, + offsite_h_coeff[1]); + DPU_REG_WRITE(c, CDM_CDWN2_COEFF_OFFSITE_H_2, + offsite_h_coeff[2]); + break; + default: + pr_err("%s invalid horz down sampling type\n", __func__); + return -EINVAL; + } + + /* ENABLE DWNS_V bit */ + opmode |= BIT(2); + + switch (cfg->v_cdwn_type) { + case CDM_CDWN_DISABLE: + /* CLEAR METHOD_V field */ + opmode &= ~(0x60); + /* CLEAR DWNS_V bit */ + opmode &= ~BIT(2); + break; + case CDM_CDWN_PIXEL_DROP: + /* Clear METHOD_V field (pixel drop is 0) */ + opmode &= ~(0x60); + break; + case CDM_CDWN_AVG: + /* Clear METHOD_V field (Average is 0x1) */ + opmode &= ~(0x60); + opmode |= (0x1 << 0x5); + break; + case CDM_CDWN_COSITE: + /* Clear METHOD_V field (Average is 0x2) */ + opmode &= ~(0x60); + opmode |= (0x2 << 0x5); + /* Co-site vertical coefficients */ + DPU_REG_WRITE(c, + CDM_CDWN2_COEFF_COSITE_V, + cosite_v_coeff[0]); + break; + case CDM_CDWN_OFFSITE: + /* Clear METHOD_V field (Average is 0x3) */ + opmode &= ~(0x60); + opmode |= (0x3 << 0x5); + + /* Off-site vertical coefficients */ + DPU_REG_WRITE(c, + CDM_CDWN2_COEFF_OFFSITE_V, + offsite_v_coeff[0]); + break; + default: + return -EINVAL; + } + + if (cfg->v_cdwn_type || cfg->h_cdwn_type) + opmode |= BIT(0); /* EN CDWN module */ + else + opmode &= ~BIT(0); + + out_size = (cfg->output_width & 0xFFFF) | + ((cfg->output_height & 0xFFFF) << 16); + DPU_REG_WRITE(c, CDM_CDWN2_OUT_SIZE, out_size); + DPU_REG_WRITE(c, CDM_CDWN2_OP_MODE, opmode); + DPU_REG_WRITE(c, CDM_CDWN2_CLAMP_OUT, + ((0x3FF << 16) | 0x0)); + + return 0; +} + +int dpu_hw_cdm_enable(struct dpu_hw_cdm *ctx, + struct dpu_hw_cdm_cfg *cdm) +{ + struct dpu_hw_blk_reg_map *c = &ctx->hw; + const struct dpu_format *fmt = cdm->output_fmt; + struct cdm_output_cfg cdm_cfg = { 0 }; + u32 opmode = 0; + u32 csc = 0; + + if (!DPU_FORMAT_IS_YUV(fmt)) + return -EINVAL; + + if (cdm->output_type == CDM_CDWN_OUTPUT_HDMI) { + if (fmt->chroma_sample != DPU_CHROMA_H1V2) + return -EINVAL; /*unsupported format */ + opmode = BIT(0); + opmode |= (fmt->chroma_sample << 1); + cdm_cfg.intf_en = true; + } + + csc |= BIT(2); + csc &= ~BIT(1); + csc |= BIT(0); + + if (ctx->hw_mdp && ctx->hw_mdp->ops.setup_cdm_output) + ctx->hw_mdp->ops.setup_cdm_output(ctx->hw_mdp, &cdm_cfg); + + DPU_REG_WRITE(c, CDM_CSC_10_OPMODE, csc); + DPU_REG_WRITE(c, CDM_HDMI_PACK_OP_MODE, opmode); + return 0; +} + +void dpu_hw_cdm_disable(struct dpu_hw_cdm *ctx) +{ + struct cdm_output_cfg cdm_cfg = { 0 }; + + if (ctx->hw_mdp && ctx->hw_mdp->ops.setup_cdm_output) + ctx->hw_mdp->ops.setup_cdm_output(ctx->hw_mdp, &cdm_cfg); +} + +static void _setup_cdm_ops(struct dpu_hw_cdm_ops *ops, + unsigned long features) +{ + ops->setup_csc_data = dpu_hw_cdm_setup_csc_10bit; + ops->setup_cdwn = dpu_hw_cdm_setup_cdwn; + ops->enable = dpu_hw_cdm_enable; + ops->disable = dpu_hw_cdm_disable; +} + +static struct dpu_hw_blk_ops dpu_hw_ops = { + .start = NULL, + .stop = NULL, +}; + +struct dpu_hw_cdm *dpu_hw_cdm_init(enum dpu_cdm idx, + void __iomem *addr, + struct dpu_mdss_cfg *m, + struct dpu_hw_mdp *hw_mdp) +{ + struct dpu_hw_cdm *c; + struct dpu_cdm_cfg *cfg; + int rc; + + c = kzalloc(sizeof(*c), GFP_KERNEL); + if (!c) + return ERR_PTR(-ENOMEM); + + cfg = _cdm_offset(idx, m, addr, &c->hw); + if (IS_ERR_OR_NULL(cfg)) { + kfree(c); + return ERR_PTR(-EINVAL); + } + + c->idx = idx; + c->caps = cfg; + _setup_cdm_ops(&c->ops, c->caps->features); + c->hw_mdp = hw_mdp; + + rc = dpu_hw_blk_init(&c->base, DPU_HW_BLK_CDM, idx, &dpu_hw_ops); + if (rc) { + DPU_ERROR("failed to init hw blk %d\n", rc); + goto blk_init_error; + } + + /* + * Perform any default initialization for the chroma down module + * @setup default csc coefficients + */ + dpu_hw_cdm_setup_csc_10bit(c, &rgb2yuv_cfg); + + return c; + +blk_init_error: + kzfree(c); + + return ERR_PTR(rc); +} + +void dpu_hw_cdm_destroy(struct dpu_hw_cdm *cdm) +{ + if (cdm) + dpu_hw_blk_destroy(&cdm->base); + kfree(cdm); +} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.h new file mode 100644 index 0000000000000..5cceb1ecb8e03 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.h @@ -0,0 +1,139 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef _DPU_HW_CDM_H +#define _DPU_HW_CDM_H + +#include "dpu_hw_mdss.h" +#include "dpu_hw_top.h" +#include "dpu_hw_blk.h" + +struct dpu_hw_cdm; + +struct dpu_hw_cdm_cfg { + u32 output_width; + u32 output_height; + u32 output_bit_depth; + u32 h_cdwn_type; + u32 v_cdwn_type; + const struct dpu_format *output_fmt; + u32 output_type; + int flags; +}; + +enum dpu_hw_cdwn_type { + CDM_CDWN_DISABLE, + CDM_CDWN_PIXEL_DROP, + CDM_CDWN_AVG, + CDM_CDWN_COSITE, + CDM_CDWN_OFFSITE, +}; + +enum dpu_hw_cdwn_output_type { + CDM_CDWN_OUTPUT_HDMI, + CDM_CDWN_OUTPUT_WB, +}; + +enum dpu_hw_cdwn_output_bit_depth { + CDM_CDWN_OUTPUT_8BIT, + CDM_CDWN_OUTPUT_10BIT, +}; + +/** + * struct dpu_hw_cdm_ops : Interface to the chroma down Hw driver functions + * Assumption is these functions will be called after + * clocks are enabled + * @setup_csc: Programs the csc matrix + * @setup_cdwn: Sets up the chroma down sub module + * @enable: Enables the output to interface and programs the + * output packer + * @disable: Puts the cdm in bypass mode + */ +struct dpu_hw_cdm_ops { + /** + * Programs the CSC matrix for conversion from RGB space to YUV space, + * it is optional to call this function as this matrix is automatically + * set during initialization, user should call this if it wants + * to program a different matrix than default matrix. + * @cdm: Pointer to the chroma down context structure + * @data Pointer to CSC configuration data + * return: 0 if success; error code otherwise + */ + int (*setup_csc_data)(struct dpu_hw_cdm *cdm, + struct dpu_csc_cfg *data); + + /** + * Programs the Chroma downsample part. + * @cdm Pointer to chroma down context + */ + int (*setup_cdwn)(struct dpu_hw_cdm *cdm, + struct dpu_hw_cdm_cfg *cfg); + + /** + * Enable the CDM module + * @cdm Pointer to chroma down context + */ + int (*enable)(struct dpu_hw_cdm *cdm, + struct dpu_hw_cdm_cfg *cfg); + + /** + * Disable the CDM module + * @cdm Pointer to chroma down context + */ + void (*disable)(struct dpu_hw_cdm *cdm); +}; + +struct dpu_hw_cdm { + struct dpu_hw_blk base; + struct dpu_hw_blk_reg_map hw; + + /* chroma down */ + const struct dpu_cdm_cfg *caps; + enum dpu_cdm idx; + + /* mdp top hw driver */ + struct dpu_hw_mdp *hw_mdp; + + /* ops */ + struct dpu_hw_cdm_ops ops; +}; + +/** + * dpu_hw_cdm - convert base object dpu_hw_base to container + * @hw: Pointer to base hardware block + * return: Pointer to hardware block container + */ +static inline struct dpu_hw_cdm *to_dpu_hw_cdm(struct dpu_hw_blk *hw) +{ + return container_of(hw, struct dpu_hw_cdm, base); +} + +/** + * dpu_hw_cdm_init - initializes the cdm hw driver object. + * should be called once before accessing every cdm. + * @idx: cdm index for which driver object is required + * @addr: mapped register io address of MDP + * @m : pointer to mdss catalog data + * @hw_mdp: pointer to mdp top hw driver object + */ +struct dpu_hw_cdm *dpu_hw_cdm_init(enum dpu_cdm idx, + void __iomem *addr, + struct dpu_mdss_cfg *m, + struct dpu_hw_mdp *hw_mdp); + +/** + * dpu_hw_cdm_destroy - destroys CDM driver context + * @cdm: pointer to CDM driver context + */ +void dpu_hw_cdm_destroy(struct dpu_hw_cdm *cdm); + +#endif /*_DPU_HW_CDM_H */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c new file mode 100644 index 0000000000000..06be7cf7ce505 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c @@ -0,0 +1,540 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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 <linux/delay.h> +#include "dpu_hwio.h" +#include "dpu_hw_ctl.h" +#include "dpu_dbg.h" +#include "dpu_kms.h" + +#define CTL_LAYER(lm) \ + (((lm) == LM_5) ? (0x024) : (((lm) - LM_0) * 0x004)) +#define CTL_LAYER_EXT(lm) \ + (0x40 + (((lm) - LM_0) * 0x004)) +#define CTL_LAYER_EXT2(lm) \ + (0x70 + (((lm) - LM_0) * 0x004)) +#define CTL_LAYER_EXT3(lm) \ + (0xA0 + (((lm) - LM_0) * 0x004)) +#define CTL_TOP 0x014 +#define CTL_FLUSH 0x018 +#define CTL_START 0x01C +#define CTL_PREPARE 0x0d0 +#define CTL_SW_RESET 0x030 +#define CTL_LAYER_EXTN_OFFSET 0x40 + +#define CTL_MIXER_BORDER_OUT BIT(24) +#define CTL_FLUSH_MASK_CTL BIT(17) + +#define DPU_REG_RESET_TIMEOUT_US 2000 + +static struct dpu_ctl_cfg *_ctl_offset(enum dpu_ctl ctl, + struct dpu_mdss_cfg *m, + void __iomem *addr, + struct dpu_hw_blk_reg_map *b) +{ + int i; + + for (i = 0; i < m->ctl_count; i++) { + if (ctl == m->ctl[i].id) { + b->base_off = addr; + b->blk_off = m->ctl[i].base; + b->length = m->ctl[i].len; + b->hwversion = m->hwversion; + b->log_mask = DPU_DBG_MASK_CTL; + return &m->ctl[i]; + } + } + return ERR_PTR(-ENOMEM); +} + +static int _mixer_stages(const struct dpu_lm_cfg *mixer, int count, + enum dpu_lm lm) +{ + int i; + int stages = -EINVAL; + + for (i = 0; i < count; i++) { + if (lm == mixer[i].id) { + stages = mixer[i].sblk->maxblendstages; + break; + } + } + + return stages; +} + +static inline void dpu_hw_ctl_trigger_start(struct dpu_hw_ctl *ctx) +{ + DPU_REG_WRITE(&ctx->hw, CTL_START, 0x1); +} + +static inline void dpu_hw_ctl_trigger_pending(struct dpu_hw_ctl *ctx) +{ + DPU_REG_WRITE(&ctx->hw, CTL_PREPARE, 0x1); +} + +static inline void dpu_hw_ctl_clear_pending_flush(struct dpu_hw_ctl *ctx) +{ + ctx->pending_flush_mask = 0x0; +} + +static inline void dpu_hw_ctl_update_pending_flush(struct dpu_hw_ctl *ctx, + u32 flushbits) +{ + ctx->pending_flush_mask |= flushbits; +} + +static u32 dpu_hw_ctl_get_pending_flush(struct dpu_hw_ctl *ctx) +{ + if (!ctx) + return 0x0; + + return ctx->pending_flush_mask; +} + +static inline void dpu_hw_ctl_trigger_flush(struct dpu_hw_ctl *ctx) +{ + + DPU_REG_WRITE(&ctx->hw, CTL_FLUSH, ctx->pending_flush_mask); +} + +static inline u32 dpu_hw_ctl_get_flush_register(struct dpu_hw_ctl *ctx) +{ + struct dpu_hw_blk_reg_map *c = &ctx->hw; + + return DPU_REG_READ(c, CTL_FLUSH); +} + +static inline uint32_t dpu_hw_ctl_get_bitmask_sspp(struct dpu_hw_ctl *ctx, + enum dpu_sspp sspp) +{ + uint32_t flushbits = 0; + + switch (sspp) { + case SSPP_VIG0: + flushbits = BIT(0); + break; + case SSPP_VIG1: + flushbits = BIT(1); + break; + case SSPP_VIG2: + flushbits = BIT(2); + break; + case SSPP_VIG3: + flushbits = BIT(18); + break; + case SSPP_RGB0: + flushbits = BIT(3); + break; + case SSPP_RGB1: + flushbits = BIT(4); + break; + case SSPP_RGB2: + flushbits = BIT(5); + break; + case SSPP_RGB3: + flushbits = BIT(19); + break; + case SSPP_DMA0: + flushbits = BIT(11); + break; + case SSPP_DMA1: + flushbits = BIT(12); + break; + case SSPP_DMA2: + flushbits = BIT(24); + break; + case SSPP_DMA3: + flushbits = BIT(25); + break; + case SSPP_CURSOR0: + flushbits = BIT(22); + break; + case SSPP_CURSOR1: + flushbits = BIT(23); + break; + default: + break; + } + + return flushbits; +} + +static inline uint32_t dpu_hw_ctl_get_bitmask_mixer(struct dpu_hw_ctl *ctx, + enum dpu_lm lm) +{ + uint32_t flushbits = 0; + + switch (lm) { + case LM_0: + flushbits = BIT(6); + break; + case LM_1: + flushbits = BIT(7); + break; + case LM_2: + flushbits = BIT(8); + break; + case LM_3: + flushbits = BIT(9); + break; + case LM_4: + flushbits = BIT(10); + break; + case LM_5: + flushbits = BIT(20); + break; + default: + return -EINVAL; + } + + flushbits |= CTL_FLUSH_MASK_CTL; + + return flushbits; +} + +static inline int dpu_hw_ctl_get_bitmask_intf(struct dpu_hw_ctl *ctx, + u32 *flushbits, enum dpu_intf intf) +{ + switch (intf) { + case INTF_0: + *flushbits |= BIT(31); + break; + case INTF_1: + *flushbits |= BIT(30); + break; + case INTF_2: + *flushbits |= BIT(29); + break; + case INTF_3: + *flushbits |= BIT(28); + break; + default: + return -EINVAL; + } + return 0; +} + +static inline int dpu_hw_ctl_get_bitmask_cdm(struct dpu_hw_ctl *ctx, + u32 *flushbits, enum dpu_cdm cdm) +{ + switch (cdm) { + case CDM_0: + *flushbits |= BIT(26); + break; + default: + return -EINVAL; + } + return 0; +} + +static u32 dpu_hw_ctl_poll_reset_status(struct dpu_hw_ctl *ctx, u32 timeout_us) +{ + struct dpu_hw_blk_reg_map *c = &ctx->hw; + ktime_t timeout; + u32 status; + + timeout = ktime_add_us(ktime_get(), timeout_us); + + /* + * it takes around 30us to have mdp finish resetting its ctl path + * poll every 50us so that reset should be completed at 1st poll + */ + do { + status = DPU_REG_READ(c, CTL_SW_RESET); + status &= 0x1; + if (status) + usleep_range(20, 50); + } while (status && ktime_compare_safe(ktime_get(), timeout) < 0); + + return status; +} + +static int dpu_hw_ctl_reset_control(struct dpu_hw_ctl *ctx) +{ + struct dpu_hw_blk_reg_map *c = &ctx->hw; + + pr_debug("issuing hw ctl reset for ctl:%d\n", ctx->idx); + DPU_REG_WRITE(c, CTL_SW_RESET, 0x1); + if (dpu_hw_ctl_poll_reset_status(ctx, DPU_REG_RESET_TIMEOUT_US)) + return -EINVAL; + + return 0; +} + +static int dpu_hw_ctl_wait_reset_status(struct dpu_hw_ctl *ctx) +{ + struct dpu_hw_blk_reg_map *c = &ctx->hw; + u32 status; + + status = DPU_REG_READ(c, CTL_SW_RESET); + status &= 0x01; + if (!status) + return 0; + + pr_debug("hw ctl reset is set for ctl:%d\n", ctx->idx); + if (dpu_hw_ctl_poll_reset_status(ctx, DPU_REG_RESET_TIMEOUT_US)) { + pr_err("hw recovery is not complete for ctl:%d\n", ctx->idx); + return -EINVAL; + } + + return 0; +} + +static void dpu_hw_ctl_clear_all_blendstages(struct dpu_hw_ctl *ctx) +{ + struct dpu_hw_blk_reg_map *c = &ctx->hw; + int i; + + for (i = 0; i < ctx->mixer_count; i++) { + DPU_REG_WRITE(c, CTL_LAYER(LM_0 + i), 0); + DPU_REG_WRITE(c, CTL_LAYER_EXT(LM_0 + i), 0); + DPU_REG_WRITE(c, CTL_LAYER_EXT2(LM_0 + i), 0); + DPU_REG_WRITE(c, CTL_LAYER_EXT3(LM_0 + i), 0); + } +} + +static void dpu_hw_ctl_setup_blendstage(struct dpu_hw_ctl *ctx, + enum dpu_lm lm, struct dpu_hw_stage_cfg *stage_cfg) +{ + struct dpu_hw_blk_reg_map *c = &ctx->hw; + u32 mixercfg = 0, mixercfg_ext = 0, mix, ext; + u32 mixercfg_ext2 = 0, mixercfg_ext3 = 0; + int i, j; + u8 stages; + int pipes_per_stage; + + stages = _mixer_stages(ctx->mixer_hw_caps, ctx->mixer_count, lm); + if (stages < 0) + return; + + if (test_bit(DPU_MIXER_SOURCESPLIT, + &ctx->mixer_hw_caps->features)) + pipes_per_stage = PIPES_PER_STAGE; + else + pipes_per_stage = 1; + + mixercfg = CTL_MIXER_BORDER_OUT; /* always set BORDER_OUT */ + + if (!stage_cfg) + goto exit; + + for (i = 0; i <= stages; i++) { + /* overflow to ext register if 'i + 1 > 7' */ + mix = (i + 1) & 0x7; + ext = i >= 7; + + for (j = 0 ; j < pipes_per_stage; j++) { + enum dpu_sspp_multirect_index rect_index = + stage_cfg->multirect_index[i][j]; + + switch (stage_cfg->stage[i][j]) { + case SSPP_VIG0: + if (rect_index == DPU_SSPP_RECT_1) { + mixercfg_ext3 |= ((i + 1) & 0xF) << 0; + } else { + mixercfg |= mix << 0; + mixercfg_ext |= ext << 0; + } + break; + case SSPP_VIG1: + if (rect_index == DPU_SSPP_RECT_1) { + mixercfg_ext3 |= ((i + 1) & 0xF) << 4; + } else { + mixercfg |= mix << 3; + mixercfg_ext |= ext << 2; + } + break; + case SSPP_VIG2: + if (rect_index == DPU_SSPP_RECT_1) { + mixercfg_ext3 |= ((i + 1) & 0xF) << 8; + } else { + mixercfg |= mix << 6; + mixercfg_ext |= ext << 4; + } + break; + case SSPP_VIG3: + if (rect_index == DPU_SSPP_RECT_1) { + mixercfg_ext3 |= ((i + 1) & 0xF) << 12; + } else { + mixercfg |= mix << 26; + mixercfg_ext |= ext << 6; + } + break; + case SSPP_RGB0: + mixercfg |= mix << 9; + mixercfg_ext |= ext << 8; + break; + case SSPP_RGB1: + mixercfg |= mix << 12; + mixercfg_ext |= ext << 10; + break; + case SSPP_RGB2: + mixercfg |= mix << 15; + mixercfg_ext |= ext << 12; + break; + case SSPP_RGB3: + mixercfg |= mix << 29; + mixercfg_ext |= ext << 14; + break; + case SSPP_DMA0: + if (rect_index == DPU_SSPP_RECT_1) { + mixercfg_ext2 |= ((i + 1) & 0xF) << 8; + } else { + mixercfg |= mix << 18; + mixercfg_ext |= ext << 16; + } + break; + case SSPP_DMA1: + if (rect_index == DPU_SSPP_RECT_1) { + mixercfg_ext2 |= ((i + 1) & 0xF) << 12; + } else { + mixercfg |= mix << 21; + mixercfg_ext |= ext << 18; + } + break; + case SSPP_DMA2: + if (rect_index == DPU_SSPP_RECT_1) { + mixercfg_ext2 |= ((i + 1) & 0xF) << 16; + } else { + mix |= (i + 1) & 0xF; + mixercfg_ext2 |= mix << 0; + } + break; + case SSPP_DMA3: + if (rect_index == DPU_SSPP_RECT_1) { + mixercfg_ext2 |= ((i + 1) & 0xF) << 20; + } else { + mix |= (i + 1) & 0xF; + mixercfg_ext2 |= mix << 4; + } + break; + case SSPP_CURSOR0: + mixercfg_ext |= ((i + 1) & 0xF) << 20; + break; + case SSPP_CURSOR1: + mixercfg_ext |= ((i + 1) & 0xF) << 26; + break; + default: + break; + } + } + } + +exit: + DPU_REG_WRITE(c, CTL_LAYER(lm), mixercfg); + DPU_REG_WRITE(c, CTL_LAYER_EXT(lm), mixercfg_ext); + DPU_REG_WRITE(c, CTL_LAYER_EXT2(lm), mixercfg_ext2); + DPU_REG_WRITE(c, CTL_LAYER_EXT3(lm), mixercfg_ext3); +} + +static void dpu_hw_ctl_intf_cfg(struct dpu_hw_ctl *ctx, + struct dpu_hw_intf_cfg *cfg) +{ + struct dpu_hw_blk_reg_map *c = &ctx->hw; + u32 intf_cfg = 0; + + intf_cfg |= (cfg->intf & 0xF) << 4; + + if (cfg->mode_3d) { + intf_cfg |= BIT(19); + intf_cfg |= (cfg->mode_3d - 0x1) << 20; + } + + switch (cfg->intf_mode_sel) { + case DPU_CTL_MODE_SEL_VID: + intf_cfg &= ~BIT(17); + intf_cfg &= ~(0x3 << 15); + break; + case DPU_CTL_MODE_SEL_CMD: + intf_cfg |= BIT(17); + intf_cfg |= ((cfg->stream_sel & 0x3) << 15); + break; + default: + pr_err("unknown interface type %d\n", cfg->intf_mode_sel); + return; + } + + DPU_REG_WRITE(c, CTL_TOP, intf_cfg); +} + +static void _setup_ctl_ops(struct dpu_hw_ctl_ops *ops, + unsigned long cap) +{ + ops->clear_pending_flush = dpu_hw_ctl_clear_pending_flush; + ops->update_pending_flush = dpu_hw_ctl_update_pending_flush; + ops->get_pending_flush = dpu_hw_ctl_get_pending_flush; + ops->trigger_flush = dpu_hw_ctl_trigger_flush; + ops->get_flush_register = dpu_hw_ctl_get_flush_register; + ops->trigger_start = dpu_hw_ctl_trigger_start; + ops->trigger_pending = dpu_hw_ctl_trigger_pending; + ops->setup_intf_cfg = dpu_hw_ctl_intf_cfg; + ops->reset = dpu_hw_ctl_reset_control; + ops->wait_reset_status = dpu_hw_ctl_wait_reset_status; + ops->clear_all_blendstages = dpu_hw_ctl_clear_all_blendstages; + ops->setup_blendstage = dpu_hw_ctl_setup_blendstage; + ops->get_bitmask_sspp = dpu_hw_ctl_get_bitmask_sspp; + ops->get_bitmask_mixer = dpu_hw_ctl_get_bitmask_mixer; + ops->get_bitmask_intf = dpu_hw_ctl_get_bitmask_intf; + ops->get_bitmask_cdm = dpu_hw_ctl_get_bitmask_cdm; +}; + +static struct dpu_hw_blk_ops dpu_hw_ops = { + .start = NULL, + .stop = NULL, +}; + +struct dpu_hw_ctl *dpu_hw_ctl_init(enum dpu_ctl idx, + void __iomem *addr, + struct dpu_mdss_cfg *m) +{ + struct dpu_hw_ctl *c; + struct dpu_ctl_cfg *cfg; + int rc; + + c = kzalloc(sizeof(*c), GFP_KERNEL); + if (!c) + return ERR_PTR(-ENOMEM); + + cfg = _ctl_offset(idx, m, addr, &c->hw); + if (IS_ERR_OR_NULL(cfg)) { + kfree(c); + pr_err("failed to create dpu_hw_ctl %d\n", idx); + return ERR_PTR(-EINVAL); + } + + c->caps = cfg; + _setup_ctl_ops(&c->ops, c->caps->features); + c->idx = idx; + c->mixer_count = m->mixer_count; + c->mixer_hw_caps = m->mixer; + + rc = dpu_hw_blk_init(&c->base, DPU_HW_BLK_CTL, idx, &dpu_hw_ops); + if (rc) { + DPU_ERROR("failed to init hw blk %d\n", rc); + goto blk_init_error; + } + + return c; + +blk_init_error: + kzfree(c); + + return ERR_PTR(rc); +} + +void dpu_hw_ctl_destroy(struct dpu_hw_ctl *ctx) +{ + if (ctx) + dpu_hw_blk_destroy(&ctx->base); + kfree(ctx); +} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h new file mode 100644 index 0000000000000..c66a71f8b839f --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h @@ -0,0 +1,218 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef _DPU_HW_CTL_H +#define _DPU_HW_CTL_H + +#include "dpu_hw_mdss.h" +#include "dpu_hw_util.h" +#include "dpu_hw_catalog.h" +#include "dpu_hw_sspp.h" +#include "dpu_hw_blk.h" + +/** + * dpu_ctl_mode_sel: Interface mode selection + * DPU_CTL_MODE_SEL_VID: Video mode interface + * DPU_CTL_MODE_SEL_CMD: Command mode interface + */ +enum dpu_ctl_mode_sel { + DPU_CTL_MODE_SEL_VID = 0, + DPU_CTL_MODE_SEL_CMD +}; + +struct dpu_hw_ctl; +/** + * struct dpu_hw_stage_cfg - blending stage cfg + * @stage : SSPP_ID at each stage + * @multirect_index: index of the rectangle of SSPP. + */ +struct dpu_hw_stage_cfg { + enum dpu_sspp stage[DPU_STAGE_MAX][PIPES_PER_STAGE]; + enum dpu_sspp_multirect_index multirect_index + [DPU_STAGE_MAX][PIPES_PER_STAGE]; +}; + +/** + * struct dpu_hw_intf_cfg :Describes how the DPU writes data to output interface + * @intf : Interface id + * @mode_3d: 3d mux configuration + * @intf_mode_sel: Interface mode, cmd / vid + * @stream_sel: Stream selection for multi-stream interfaces + */ +struct dpu_hw_intf_cfg { + enum dpu_intf intf; + enum dpu_3d_blend_mode mode_3d; + enum dpu_ctl_mode_sel intf_mode_sel; + int stream_sel; +}; + +/** + * struct dpu_hw_ctl_ops - Interface to the wb Hw driver functions + * Assumption is these functions will be called after clocks are enabled + */ +struct dpu_hw_ctl_ops { + /** + * kickoff hw operation for Sw controlled interfaces + * DSI cmd mode and WB interface are SW controlled + * @ctx : ctl path ctx pointer + */ + void (*trigger_start)(struct dpu_hw_ctl *ctx); + + /** + * kickoff prepare is in progress hw operation for sw + * controlled interfaces: DSI cmd mode and WB interface + * are SW controlled + * @ctx : ctl path ctx pointer + */ + void (*trigger_pending)(struct dpu_hw_ctl *ctx); + + /** + * Clear the value of the cached pending_flush_mask + * No effect on hardware + * @ctx : ctl path ctx pointer + */ + void (*clear_pending_flush)(struct dpu_hw_ctl *ctx); + + /** + * Query the value of the cached pending_flush_mask + * No effect on hardware + * @ctx : ctl path ctx pointer + */ + u32 (*get_pending_flush)(struct dpu_hw_ctl *ctx); + + /** + * OR in the given flushbits to the cached pending_flush_mask + * No effect on hardware + * @ctx : ctl path ctx pointer + * @flushbits : module flushmask + */ + void (*update_pending_flush)(struct dpu_hw_ctl *ctx, + u32 flushbits); + + /** + * Write the value of the pending_flush_mask to hardware + * @ctx : ctl path ctx pointer + */ + void (*trigger_flush)(struct dpu_hw_ctl *ctx); + + /** + * Read the value of the flush register + * @ctx : ctl path ctx pointer + * @Return: value of the ctl flush register. + */ + u32 (*get_flush_register)(struct dpu_hw_ctl *ctx); + + /** + * Setup ctl_path interface config + * @ctx + * @cfg : interface config structure pointer + */ + void (*setup_intf_cfg)(struct dpu_hw_ctl *ctx, + struct dpu_hw_intf_cfg *cfg); + + int (*reset)(struct dpu_hw_ctl *c); + + /* + * wait_reset_status - checks ctl reset status + * @ctx : ctl path ctx pointer + * + * This function checks the ctl reset status bit. + * If the reset bit is set, it keeps polling the status till the hw + * reset is complete. + * Returns: 0 on success or -error if reset incomplete within interval + */ + int (*wait_reset_status)(struct dpu_hw_ctl *ctx); + + uint32_t (*get_bitmask_sspp)(struct dpu_hw_ctl *ctx, + enum dpu_sspp blk); + + uint32_t (*get_bitmask_mixer)(struct dpu_hw_ctl *ctx, + enum dpu_lm blk); + + int (*get_bitmask_intf)(struct dpu_hw_ctl *ctx, + u32 *flushbits, + enum dpu_intf blk); + + int (*get_bitmask_cdm)(struct dpu_hw_ctl *ctx, + u32 *flushbits, + enum dpu_cdm blk); + + /** + * Set all blend stages to disabled + * @ctx : ctl path ctx pointer + */ + void (*clear_all_blendstages)(struct dpu_hw_ctl *ctx); + + /** + * Configure layer mixer to pipe configuration + * @ctx : ctl path ctx pointer + * @lm : layer mixer enumeration + * @cfg : blend stage configuration + */ + void (*setup_blendstage)(struct dpu_hw_ctl *ctx, + enum dpu_lm lm, struct dpu_hw_stage_cfg *cfg); +}; + +/** + * struct dpu_hw_ctl : CTL PATH driver object + * @base: hardware block base structure + * @hw: block register map object + * @idx: control path index + * @caps: control path capabilities + * @mixer_count: number of mixers + * @mixer_hw_caps: mixer hardware capabilities + * @pending_flush_mask: storage for pending ctl_flush managed via ops + * @ops: operation list + */ +struct dpu_hw_ctl { + struct dpu_hw_blk base; + struct dpu_hw_blk_reg_map hw; + + /* ctl path */ + int idx; + const struct dpu_ctl_cfg *caps; + int mixer_count; + const struct dpu_lm_cfg *mixer_hw_caps; + u32 pending_flush_mask; + + /* ops */ + struct dpu_hw_ctl_ops ops; +}; + +/** + * dpu_hw_ctl - convert base object dpu_hw_base to container + * @hw: Pointer to base hardware block + * return: Pointer to hardware block container + */ +static inline struct dpu_hw_ctl *to_dpu_hw_ctl(struct dpu_hw_blk *hw) +{ + return container_of(hw, struct dpu_hw_ctl, base); +} + +/** + * dpu_hw_ctl_init(): Initializes the ctl_path hw driver object. + * should be called before accessing every ctl path registers. + * @idx: ctl_path index for which driver object is required + * @addr: mapped register io address of MDP + * @m : pointer to mdss catalog data + */ +struct dpu_hw_ctl *dpu_hw_ctl_init(enum dpu_ctl idx, + void __iomem *addr, + struct dpu_mdss_cfg *m); + +/** + * dpu_hw_ctl_destroy(): Destroys ctl driver context + * should be called to free the context + */ +void dpu_hw_ctl_destroy(struct dpu_hw_ctl *ctx); + +#endif /*_DPU_HW_CTL_H */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c new file mode 100644 index 0000000000000..c0b7f00493658 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c @@ -0,0 +1,1183 @@ +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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 <linux/bitops.h> +#include <linux/slab.h> + +#include "dpu_kms.h" +#include "dpu_hw_interrupts.h" +#include "dpu_hw_util.h" +#include "dpu_hw_mdss.h" + +/** + * Register offsets in MDSS register file for the interrupt registers + * w.r.t. to the MDP base + */ +#define MDP_SSPP_TOP0_OFF 0x0 +#define MDP_INTF_0_OFF 0x6A000 +#define MDP_INTF_1_OFF 0x6A800 +#define MDP_INTF_2_OFF 0x6B000 +#define MDP_INTF_3_OFF 0x6B800 +#define MDP_INTF_4_OFF 0x6C000 +#define MDP_AD4_0_OFF 0x7C000 +#define MDP_AD4_1_OFF 0x7D000 +#define MDP_AD4_INTR_EN_OFF 0x41c +#define MDP_AD4_INTR_CLEAR_OFF 0x424 +#define MDP_AD4_INTR_STATUS_OFF 0x420 + +/** + * WB interrupt status bit definitions + */ +#define DPU_INTR_WB_0_DONE BIT(0) +#define DPU_INTR_WB_1_DONE BIT(1) +#define DPU_INTR_WB_2_DONE BIT(4) + +/** + * WDOG timer interrupt status bit definitions + */ +#define DPU_INTR_WD_TIMER_0_DONE BIT(2) +#define DPU_INTR_WD_TIMER_1_DONE BIT(3) +#define DPU_INTR_WD_TIMER_2_DONE BIT(5) +#define DPU_INTR_WD_TIMER_3_DONE BIT(6) +#define DPU_INTR_WD_TIMER_4_DONE BIT(7) + +/** + * Pingpong interrupt status bit definitions + */ +#define DPU_INTR_PING_PONG_0_DONE BIT(8) +#define DPU_INTR_PING_PONG_1_DONE BIT(9) +#define DPU_INTR_PING_PONG_2_DONE BIT(10) +#define DPU_INTR_PING_PONG_3_DONE BIT(11) +#define DPU_INTR_PING_PONG_0_RD_PTR BIT(12) +#define DPU_INTR_PING_PONG_1_RD_PTR BIT(13) +#define DPU_INTR_PING_PONG_2_RD_PTR BIT(14) +#define DPU_INTR_PING_PONG_3_RD_PTR BIT(15) +#define DPU_INTR_PING_PONG_0_WR_PTR BIT(16) +#define DPU_INTR_PING_PONG_1_WR_PTR BIT(17) +#define DPU_INTR_PING_PONG_2_WR_PTR BIT(18) +#define DPU_INTR_PING_PONG_3_WR_PTR BIT(19) +#define DPU_INTR_PING_PONG_0_AUTOREFRESH_DONE BIT(20) +#define DPU_INTR_PING_PONG_1_AUTOREFRESH_DONE BIT(21) +#define DPU_INTR_PING_PONG_2_AUTOREFRESH_DONE BIT(22) +#define DPU_INTR_PING_PONG_3_AUTOREFRESH_DONE BIT(23) + +/** + * Interface interrupt status bit definitions + */ +#define DPU_INTR_INTF_0_UNDERRUN BIT(24) +#define DPU_INTR_INTF_1_UNDERRUN BIT(26) +#define DPU_INTR_INTF_2_UNDERRUN BIT(28) +#define DPU_INTR_INTF_3_UNDERRUN BIT(30) +#define DPU_INTR_INTF_0_VSYNC BIT(25) +#define DPU_INTR_INTF_1_VSYNC BIT(27) +#define DPU_INTR_INTF_2_VSYNC BIT(29) +#define DPU_INTR_INTF_3_VSYNC BIT(31) + +/** + * Pingpong Secondary interrupt status bit definitions + */ +#define DPU_INTR_PING_PONG_S0_AUTOREFRESH_DONE BIT(0) +#define DPU_INTR_PING_PONG_S0_WR_PTR BIT(4) +#define DPU_INTR_PING_PONG_S0_RD_PTR BIT(8) +#define DPU_INTR_PING_PONG_S0_TEAR_DETECTED BIT(22) +#define DPU_INTR_PING_PONG_S0_TE_DETECTED BIT(28) + +/** + * Pingpong TEAR detection interrupt status bit definitions + */ +#define DPU_INTR_PING_PONG_0_TEAR_DETECTED BIT(16) +#define DPU_INTR_PING_PONG_1_TEAR_DETECTED BIT(17) +#define DPU_INTR_PING_PONG_2_TEAR_DETECTED BIT(18) +#define DPU_INTR_PING_PONG_3_TEAR_DETECTED BIT(19) + +/** + * Pingpong TE detection interrupt status bit definitions + */ +#define DPU_INTR_PING_PONG_0_TE_DETECTED BIT(24) +#define DPU_INTR_PING_PONG_1_TE_DETECTED BIT(25) +#define DPU_INTR_PING_PONG_2_TE_DETECTED BIT(26) +#define DPU_INTR_PING_PONG_3_TE_DETECTED BIT(27) + +/** + * Ctl start interrupt status bit definitions + */ +#define DPU_INTR_CTL_0_START BIT(9) +#define DPU_INTR_CTL_1_START BIT(10) +#define DPU_INTR_CTL_2_START BIT(11) +#define DPU_INTR_CTL_3_START BIT(12) +#define DPU_INTR_CTL_4_START BIT(13) + +/** + * Concurrent WB overflow interrupt status bit definitions + */ +#define DPU_INTR_CWB_2_OVERFLOW BIT(14) +#define DPU_INTR_CWB_3_OVERFLOW BIT(15) + +/** + * Histogram VIG done interrupt status bit definitions + */ +#define DPU_INTR_HIST_VIG_0_DONE BIT(0) +#define DPU_INTR_HIST_VIG_1_DONE BIT(4) +#define DPU_INTR_HIST_VIG_2_DONE BIT(8) +#define DPU_INTR_HIST_VIG_3_DONE BIT(10) + +/** + * Histogram VIG reset Sequence done interrupt status bit definitions + */ +#define DPU_INTR_HIST_VIG_0_RSTSEQ_DONE BIT(1) +#define DPU_INTR_HIST_VIG_1_RSTSEQ_DONE BIT(5) +#define DPU_INTR_HIST_VIG_2_RSTSEQ_DONE BIT(9) +#define DPU_INTR_HIST_VIG_3_RSTSEQ_DONE BIT(11) + +/** + * Histogram DSPP done interrupt status bit definitions + */ +#define DPU_INTR_HIST_DSPP_0_DONE BIT(12) +#define DPU_INTR_HIST_DSPP_1_DONE BIT(16) +#define DPU_INTR_HIST_DSPP_2_DONE BIT(20) +#define DPU_INTR_HIST_DSPP_3_DONE BIT(22) + +/** + * Histogram DSPP reset Sequence done interrupt status bit definitions + */ +#define DPU_INTR_HIST_DSPP_0_RSTSEQ_DONE BIT(13) +#define DPU_INTR_HIST_DSPP_1_RSTSEQ_DONE BIT(17) +#define DPU_INTR_HIST_DSPP_2_RSTSEQ_DONE BIT(21) +#define DPU_INTR_HIST_DSPP_3_RSTSEQ_DONE BIT(23) + +/** + * INTF interrupt status bit definitions + */ +#define DPU_INTR_VIDEO_INTO_STATIC BIT(0) +#define DPU_INTR_VIDEO_OUTOF_STATIC BIT(1) +#define DPU_INTR_DSICMD_0_INTO_STATIC BIT(2) +#define DPU_INTR_DSICMD_0_OUTOF_STATIC BIT(3) +#define DPU_INTR_DSICMD_1_INTO_STATIC BIT(4) +#define DPU_INTR_DSICMD_1_OUTOF_STATIC BIT(5) +#define DPU_INTR_DSICMD_2_INTO_STATIC BIT(6) +#define DPU_INTR_DSICMD_2_OUTOF_STATIC BIT(7) +#define DPU_INTR_PROG_LINE BIT(8) + +/** + * AD4 interrupt status bit definitions + */ +#define DPU_INTR_BRIGHTPR_UPDATED BIT(4) +#define DPU_INTR_DARKENH_UPDATED BIT(3) +#define DPU_INTR_STREN_OUTROI_UPDATED BIT(2) +#define DPU_INTR_STREN_INROI_UPDATED BIT(1) +#define DPU_INTR_BACKLIGHT_UPDATED BIT(0) +/** + * struct dpu_intr_reg - array of DPU register sets + * @clr_off: offset to CLEAR reg + * @en_off: offset to ENABLE reg + * @status_off: offset to STATUS reg + */ +struct dpu_intr_reg { + u32 clr_off; + u32 en_off; + u32 status_off; +}; + +/** + * struct dpu_irq_type - maps each irq with i/f + * @intr_type: type of interrupt listed in dpu_intr_type + * @instance_idx: instance index of the associated HW block in DPU + * @irq_mask: corresponding bit in the interrupt status reg + * @reg_idx: which reg set to use + */ +struct dpu_irq_type { + u32 intr_type; + u32 instance_idx; + u32 irq_mask; + u32 reg_idx; +}; + +/** + * List of DPU interrupt registers + */ +static const struct dpu_intr_reg dpu_intr_set[] = { + { + MDP_SSPP_TOP0_OFF+INTR_CLEAR, + MDP_SSPP_TOP0_OFF+INTR_EN, + MDP_SSPP_TOP0_OFF+INTR_STATUS + }, + { + MDP_SSPP_TOP0_OFF+INTR2_CLEAR, + MDP_SSPP_TOP0_OFF+INTR2_EN, + MDP_SSPP_TOP0_OFF+INTR2_STATUS + }, + { + MDP_SSPP_TOP0_OFF+HIST_INTR_CLEAR, + MDP_SSPP_TOP0_OFF+HIST_INTR_EN, + MDP_SSPP_TOP0_OFF+HIST_INTR_STATUS + }, + { + MDP_INTF_0_OFF+INTF_INTR_CLEAR, + MDP_INTF_0_OFF+INTF_INTR_EN, + MDP_INTF_0_OFF+INTF_INTR_STATUS + }, + { + MDP_INTF_1_OFF+INTF_INTR_CLEAR, + MDP_INTF_1_OFF+INTF_INTR_EN, + MDP_INTF_1_OFF+INTF_INTR_STATUS + }, + { + MDP_INTF_2_OFF+INTF_INTR_CLEAR, + MDP_INTF_2_OFF+INTF_INTR_EN, + MDP_INTF_2_OFF+INTF_INTR_STATUS + }, + { + MDP_INTF_3_OFF+INTF_INTR_CLEAR, + MDP_INTF_3_OFF+INTF_INTR_EN, + MDP_INTF_3_OFF+INTF_INTR_STATUS + }, + { + MDP_INTF_4_OFF+INTF_INTR_CLEAR, + MDP_INTF_4_OFF+INTF_INTR_EN, + MDP_INTF_4_OFF+INTF_INTR_STATUS + }, + { + MDP_AD4_0_OFF + MDP_AD4_INTR_CLEAR_OFF, + MDP_AD4_0_OFF + MDP_AD4_INTR_EN_OFF, + MDP_AD4_0_OFF + MDP_AD4_INTR_STATUS_OFF, + }, + { + MDP_AD4_1_OFF + MDP_AD4_INTR_CLEAR_OFF, + MDP_AD4_1_OFF + MDP_AD4_INTR_EN_OFF, + MDP_AD4_1_OFF + MDP_AD4_INTR_STATUS_OFF, + } +}; + +/** + * IRQ mapping table - use for lookup an irq_idx in this table that have + * a matching interface type and instance index. + */ +static const struct dpu_irq_type dpu_irq_map[] = { + /* BEGIN MAP_RANGE: 0-31, INTR */ + /* irq_idx: 0-3 */ + { DPU_IRQ_TYPE_WB_ROT_COMP, WB_0, DPU_INTR_WB_0_DONE, 0}, + { DPU_IRQ_TYPE_WB_ROT_COMP, WB_1, DPU_INTR_WB_1_DONE, 0}, + { DPU_IRQ_TYPE_WD_TIMER, WD_TIMER_0, DPU_INTR_WD_TIMER_0_DONE, 0}, + { DPU_IRQ_TYPE_WD_TIMER, WD_TIMER_1, DPU_INTR_WD_TIMER_1_DONE, 0}, + /* irq_idx: 4-7 */ + { DPU_IRQ_TYPE_WB_WFD_COMP, WB_2, DPU_INTR_WB_2_DONE, 0}, + { DPU_IRQ_TYPE_WD_TIMER, WD_TIMER_2, DPU_INTR_WD_TIMER_2_DONE, 0}, + { DPU_IRQ_TYPE_WD_TIMER, WD_TIMER_3, DPU_INTR_WD_TIMER_3_DONE, 0}, + { DPU_IRQ_TYPE_WD_TIMER, WD_TIMER_4, DPU_INTR_WD_TIMER_4_DONE, 0}, + /* irq_idx: 8-11 */ + { DPU_IRQ_TYPE_PING_PONG_COMP, PINGPONG_0, + DPU_INTR_PING_PONG_0_DONE, 0}, + { DPU_IRQ_TYPE_PING_PONG_COMP, PINGPONG_1, + DPU_INTR_PING_PONG_1_DONE, 0}, + { DPU_IRQ_TYPE_PING_PONG_COMP, PINGPONG_2, + DPU_INTR_PING_PONG_2_DONE, 0}, + { DPU_IRQ_TYPE_PING_PONG_COMP, PINGPONG_3, + DPU_INTR_PING_PONG_3_DONE, 0}, + /* irq_idx: 12-15 */ + { DPU_IRQ_TYPE_PING_PONG_RD_PTR, PINGPONG_0, + DPU_INTR_PING_PONG_0_RD_PTR, 0}, + { DPU_IRQ_TYPE_PING_PONG_RD_PTR, PINGPONG_1, + DPU_INTR_PING_PONG_1_RD_PTR, 0}, + { DPU_IRQ_TYPE_PING_PONG_RD_PTR, PINGPONG_2, + DPU_INTR_PING_PONG_2_RD_PTR, 0}, + { DPU_IRQ_TYPE_PING_PONG_RD_PTR, PINGPONG_3, + DPU_INTR_PING_PONG_3_RD_PTR, 0}, + /* irq_idx: 16-19 */ + { DPU_IRQ_TYPE_PING_PONG_WR_PTR, PINGPONG_0, + DPU_INTR_PING_PONG_0_WR_PTR, 0}, + { DPU_IRQ_TYPE_PING_PONG_WR_PTR, PINGPONG_1, + DPU_INTR_PING_PONG_1_WR_PTR, 0}, + { DPU_IRQ_TYPE_PING_PONG_WR_PTR, PINGPONG_2, + DPU_INTR_PING_PONG_2_WR_PTR, 0}, + { DPU_IRQ_TYPE_PING_PONG_WR_PTR, PINGPONG_3, + DPU_INTR_PING_PONG_3_WR_PTR, 0}, + /* irq_idx: 20-23 */ + { DPU_IRQ_TYPE_PING_PONG_AUTO_REF, PINGPONG_0, + DPU_INTR_PING_PONG_0_AUTOREFRESH_DONE, 0}, + { DPU_IRQ_TYPE_PING_PONG_AUTO_REF, PINGPONG_1, + DPU_INTR_PING_PONG_1_AUTOREFRESH_DONE, 0}, + { DPU_IRQ_TYPE_PING_PONG_AUTO_REF, PINGPONG_2, + DPU_INTR_PING_PONG_2_AUTOREFRESH_DONE, 0}, + { DPU_IRQ_TYPE_PING_PONG_AUTO_REF, PINGPONG_3, + DPU_INTR_PING_PONG_3_AUTOREFRESH_DONE, 0}, + /* irq_idx: 24-27 */ + { DPU_IRQ_TYPE_INTF_UNDER_RUN, INTF_0, DPU_INTR_INTF_0_UNDERRUN, 0}, + { DPU_IRQ_TYPE_INTF_VSYNC, INTF_0, DPU_INTR_INTF_0_VSYNC, 0}, + { DPU_IRQ_TYPE_INTF_UNDER_RUN, INTF_1, DPU_INTR_INTF_1_UNDERRUN, 0}, + { DPU_IRQ_TYPE_INTF_VSYNC, INTF_1, DPU_INTR_INTF_1_VSYNC, 0}, + /* irq_idx: 28-31 */ + { DPU_IRQ_TYPE_INTF_UNDER_RUN, INTF_2, DPU_INTR_INTF_2_UNDERRUN, 0}, + { DPU_IRQ_TYPE_INTF_VSYNC, INTF_2, DPU_INTR_INTF_2_VSYNC, 0}, + { DPU_IRQ_TYPE_INTF_UNDER_RUN, INTF_3, DPU_INTR_INTF_3_UNDERRUN, 0}, + { DPU_IRQ_TYPE_INTF_VSYNC, INTF_3, DPU_INTR_INTF_3_VSYNC, 0}, + + /* BEGIN MAP_RANGE: 32-64, INTR2 */ + /* irq_idx: 32-35 */ + { DPU_IRQ_TYPE_PING_PONG_AUTO_REF, PINGPONG_S0, + DPU_INTR_PING_PONG_S0_AUTOREFRESH_DONE, 1}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 1}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 1}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 1}, + /* irq_idx: 36-39 */ + { DPU_IRQ_TYPE_PING_PONG_WR_PTR, PINGPONG_S0, + DPU_INTR_PING_PONG_S0_WR_PTR, 1}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 1}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 1}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 1}, + /* irq_idx: 40 */ + { DPU_IRQ_TYPE_PING_PONG_RD_PTR, PINGPONG_S0, + DPU_INTR_PING_PONG_S0_RD_PTR, 1}, + /* irq_idx: 41-45 */ + { DPU_IRQ_TYPE_CTL_START, CTL_0, + DPU_INTR_CTL_0_START, 1}, + { DPU_IRQ_TYPE_CTL_START, CTL_1, + DPU_INTR_CTL_1_START, 1}, + { DPU_IRQ_TYPE_CTL_START, CTL_2, + DPU_INTR_CTL_2_START, 1}, + { DPU_IRQ_TYPE_CTL_START, CTL_3, + DPU_INTR_CTL_3_START, 1}, + { DPU_IRQ_TYPE_CTL_START, CTL_4, + DPU_INTR_CTL_4_START, 1}, + /* irq_idx: 46-47 */ + { DPU_IRQ_TYPE_CWB_OVERFLOW, CWB_2, DPU_INTR_CWB_2_OVERFLOW, 1}, + { DPU_IRQ_TYPE_CWB_OVERFLOW, CWB_3, DPU_INTR_CWB_3_OVERFLOW, 1}, + /* irq_idx: 48-51 */ + { DPU_IRQ_TYPE_PING_PONG_TEAR_CHECK, PINGPONG_0, + DPU_INTR_PING_PONG_0_TEAR_DETECTED, 1}, + { DPU_IRQ_TYPE_PING_PONG_TEAR_CHECK, PINGPONG_1, + DPU_INTR_PING_PONG_1_TEAR_DETECTED, 1}, + { DPU_IRQ_TYPE_PING_PONG_TEAR_CHECK, PINGPONG_2, + DPU_INTR_PING_PONG_2_TEAR_DETECTED, 1}, + { DPU_IRQ_TYPE_PING_PONG_TEAR_CHECK, PINGPONG_3, + DPU_INTR_PING_PONG_3_TEAR_DETECTED, 1}, + /* irq_idx: 52-55 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 1}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 1}, + { DPU_IRQ_TYPE_PING_PONG_TEAR_CHECK, PINGPONG_S0, + DPU_INTR_PING_PONG_S0_TEAR_DETECTED, 1}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 1}, + /* irq_idx: 56-59 */ + { DPU_IRQ_TYPE_PING_PONG_TE_CHECK, PINGPONG_0, + DPU_INTR_PING_PONG_0_TE_DETECTED, 1}, + { DPU_IRQ_TYPE_PING_PONG_TE_CHECK, PINGPONG_1, + DPU_INTR_PING_PONG_1_TE_DETECTED, 1}, + { DPU_IRQ_TYPE_PING_PONG_TE_CHECK, PINGPONG_2, + DPU_INTR_PING_PONG_2_TE_DETECTED, 1}, + { DPU_IRQ_TYPE_PING_PONG_TE_CHECK, PINGPONG_3, + DPU_INTR_PING_PONG_3_TE_DETECTED, 1}, + /* irq_idx: 60-63 */ + { DPU_IRQ_TYPE_PING_PONG_TE_CHECK, PINGPONG_S0, + DPU_INTR_PING_PONG_S0_TE_DETECTED, 1}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 1}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 1}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 1}, + + /* BEGIN MAP_RANGE: 64-95 HIST */ + /* irq_idx: 64-67 */ + { DPU_IRQ_TYPE_HIST_VIG_DONE, SSPP_VIG0, DPU_INTR_HIST_VIG_0_DONE, 2}, + { DPU_IRQ_TYPE_HIST_VIG_RSTSEQ, SSPP_VIG0, + DPU_INTR_HIST_VIG_0_RSTSEQ_DONE, 2}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 2}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 2}, + /* irq_idx: 68-71 */ + { DPU_IRQ_TYPE_HIST_VIG_DONE, SSPP_VIG1, DPU_INTR_HIST_VIG_1_DONE, 2}, + { DPU_IRQ_TYPE_HIST_VIG_RSTSEQ, SSPP_VIG1, + DPU_INTR_HIST_VIG_1_RSTSEQ_DONE, 2}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 2}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 2}, + /* irq_idx: 72-75 */ + { DPU_IRQ_TYPE_HIST_VIG_DONE, SSPP_VIG2, DPU_INTR_HIST_VIG_2_DONE, 2}, + { DPU_IRQ_TYPE_HIST_VIG_RSTSEQ, SSPP_VIG2, + DPU_INTR_HIST_VIG_2_RSTSEQ_DONE, 2}, + { DPU_IRQ_TYPE_HIST_VIG_DONE, SSPP_VIG3, DPU_INTR_HIST_VIG_3_DONE, 2}, + { DPU_IRQ_TYPE_HIST_VIG_RSTSEQ, SSPP_VIG3, + DPU_INTR_HIST_VIG_3_RSTSEQ_DONE, 2}, + /* irq_idx: 76-79 */ + { DPU_IRQ_TYPE_HIST_DSPP_DONE, DSPP_0, DPU_INTR_HIST_DSPP_0_DONE, 2}, + { DPU_IRQ_TYPE_HIST_DSPP_RSTSEQ, DSPP_0, + DPU_INTR_HIST_DSPP_0_RSTSEQ_DONE, 2}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 2}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 2}, + /* irq_idx: 80-83 */ + { DPU_IRQ_TYPE_HIST_DSPP_DONE, DSPP_1, DPU_INTR_HIST_DSPP_1_DONE, 2}, + { DPU_IRQ_TYPE_HIST_DSPP_RSTSEQ, DSPP_1, + DPU_INTR_HIST_DSPP_1_RSTSEQ_DONE, 2}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 2}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 2}, + /* irq_idx: 84-87 */ + { DPU_IRQ_TYPE_HIST_DSPP_DONE, DSPP_2, DPU_INTR_HIST_DSPP_2_DONE, 2}, + { DPU_IRQ_TYPE_HIST_DSPP_RSTSEQ, DSPP_2, + DPU_INTR_HIST_DSPP_2_RSTSEQ_DONE, 2}, + { DPU_IRQ_TYPE_HIST_DSPP_DONE, DSPP_3, DPU_INTR_HIST_DSPP_3_DONE, 2}, + { DPU_IRQ_TYPE_HIST_DSPP_RSTSEQ, DSPP_3, + DPU_INTR_HIST_DSPP_3_RSTSEQ_DONE, 2}, + /* irq_idx: 88-91 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 2}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 2}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 2}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 2}, + /* irq_idx: 92-95 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 2}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 2}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 2}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 2}, + + /* BEGIN MAP_RANGE: 96-127 INTF_0_INTR */ + /* irq_idx: 96-99 */ + { DPU_IRQ_TYPE_SFI_VIDEO_IN, INTF_0, + DPU_INTR_VIDEO_INTO_STATIC, 3}, + { DPU_IRQ_TYPE_SFI_VIDEO_OUT, INTF_0, + DPU_INTR_VIDEO_OUTOF_STATIC, 3}, + { DPU_IRQ_TYPE_SFI_CMD_0_IN, INTF_0, + DPU_INTR_DSICMD_0_INTO_STATIC, 3}, + { DPU_IRQ_TYPE_SFI_CMD_0_OUT, INTF_0, + DPU_INTR_DSICMD_0_OUTOF_STATIC, 3}, + /* irq_idx: 100-103 */ + { DPU_IRQ_TYPE_SFI_CMD_1_IN, INTF_0, + DPU_INTR_DSICMD_1_INTO_STATIC, 3}, + { DPU_IRQ_TYPE_SFI_CMD_1_OUT, INTF_0, + DPU_INTR_DSICMD_1_OUTOF_STATIC, 3}, + { DPU_IRQ_TYPE_SFI_CMD_2_IN, INTF_0, + DPU_INTR_DSICMD_2_INTO_STATIC, 3}, + { DPU_IRQ_TYPE_SFI_CMD_2_OUT, INTF_0, + DPU_INTR_DSICMD_2_OUTOF_STATIC, 3}, + /* irq_idx: 104-107 */ + { DPU_IRQ_TYPE_PROG_LINE, INTF_0, DPU_INTR_PROG_LINE, 3}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 3}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 3}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 3}, + /* irq_idx: 108-111 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 3}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 3}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 3}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 3}, + /* irq_idx: 112-115 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 3}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 3}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 3}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 3}, + /* irq_idx: 116-119 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 3}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 3}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 3}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 3}, + /* irq_idx: 120-123 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 3}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 3}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 3}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 3}, + /* irq_idx: 124-127 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 3}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 3}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 3}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 3}, + + /* BEGIN MAP_RANGE: 128-159 INTF_1_INTR */ + /* irq_idx: 128-131 */ + { DPU_IRQ_TYPE_SFI_VIDEO_IN, INTF_1, + DPU_INTR_VIDEO_INTO_STATIC, 4}, + { DPU_IRQ_TYPE_SFI_VIDEO_OUT, INTF_1, + DPU_INTR_VIDEO_OUTOF_STATIC, 4}, + { DPU_IRQ_TYPE_SFI_CMD_0_IN, INTF_1, + DPU_INTR_DSICMD_0_INTO_STATIC, 4}, + { DPU_IRQ_TYPE_SFI_CMD_0_OUT, INTF_1, + DPU_INTR_DSICMD_0_OUTOF_STATIC, 4}, + /* irq_idx: 132-135 */ + { DPU_IRQ_TYPE_SFI_CMD_1_IN, INTF_1, + DPU_INTR_DSICMD_1_INTO_STATIC, 4}, + { DPU_IRQ_TYPE_SFI_CMD_1_OUT, INTF_1, + DPU_INTR_DSICMD_1_OUTOF_STATIC, 4}, + { DPU_IRQ_TYPE_SFI_CMD_2_IN, INTF_1, + DPU_INTR_DSICMD_2_INTO_STATIC, 4}, + { DPU_IRQ_TYPE_SFI_CMD_2_OUT, INTF_1, + DPU_INTR_DSICMD_2_OUTOF_STATIC, 4}, + /* irq_idx: 136-139 */ + { DPU_IRQ_TYPE_PROG_LINE, INTF_1, DPU_INTR_PROG_LINE, 4}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 4}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 4}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 4}, + /* irq_idx: 140-143 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 4}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 4}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 4}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 4}, + /* irq_idx: 144-147 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 4}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 4}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 4}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 4}, + /* irq_idx: 148-151 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 4}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 4}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 4}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 4}, + /* irq_idx: 152-155 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 4}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 4}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 4}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 4}, + /* irq_idx: 156-159 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 4}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 4}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 4}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 4}, + + /* BEGIN MAP_RANGE: 160-191 INTF_2_INTR */ + /* irq_idx: 160-163 */ + { DPU_IRQ_TYPE_SFI_VIDEO_IN, INTF_2, + DPU_INTR_VIDEO_INTO_STATIC, 5}, + { DPU_IRQ_TYPE_SFI_VIDEO_OUT, INTF_2, + DPU_INTR_VIDEO_OUTOF_STATIC, 5}, + { DPU_IRQ_TYPE_SFI_CMD_0_IN, INTF_2, + DPU_INTR_DSICMD_0_INTO_STATIC, 5}, + { DPU_IRQ_TYPE_SFI_CMD_0_OUT, INTF_2, + DPU_INTR_DSICMD_0_OUTOF_STATIC, 5}, + /* irq_idx: 164-167 */ + { DPU_IRQ_TYPE_SFI_CMD_1_IN, INTF_2, + DPU_INTR_DSICMD_1_INTO_STATIC, 5}, + { DPU_IRQ_TYPE_SFI_CMD_1_OUT, INTF_2, + DPU_INTR_DSICMD_1_OUTOF_STATIC, 5}, + { DPU_IRQ_TYPE_SFI_CMD_2_IN, INTF_2, + DPU_INTR_DSICMD_2_INTO_STATIC, 5}, + { DPU_IRQ_TYPE_SFI_CMD_2_OUT, INTF_2, + DPU_INTR_DSICMD_2_OUTOF_STATIC, 5}, + /* irq_idx: 168-171 */ + { DPU_IRQ_TYPE_PROG_LINE, INTF_2, DPU_INTR_PROG_LINE, 5}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 5}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 5}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 5}, + /* irq_idx: 172-175 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 5}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 5}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 5}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 5}, + /* irq_idx: 176-179 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 5}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 5}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 5}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 5}, + /* irq_idx: 180-183 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 5}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 5}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 5}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 5}, + /* irq_idx: 184-187 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 5}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 5}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 5}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 5}, + /* irq_idx: 188-191 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 5}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 5}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 5}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 5}, + + /* BEGIN MAP_RANGE: 192-223 INTF_3_INTR */ + /* irq_idx: 192-195 */ + { DPU_IRQ_TYPE_SFI_VIDEO_IN, INTF_3, + DPU_INTR_VIDEO_INTO_STATIC, 6}, + { DPU_IRQ_TYPE_SFI_VIDEO_OUT, INTF_3, + DPU_INTR_VIDEO_OUTOF_STATIC, 6}, + { DPU_IRQ_TYPE_SFI_CMD_0_IN, INTF_3, + DPU_INTR_DSICMD_0_INTO_STATIC, 6}, + { DPU_IRQ_TYPE_SFI_CMD_0_OUT, INTF_3, + DPU_INTR_DSICMD_0_OUTOF_STATIC, 6}, + /* irq_idx: 196-199 */ + { DPU_IRQ_TYPE_SFI_CMD_1_IN, INTF_3, + DPU_INTR_DSICMD_1_INTO_STATIC, 6}, + { DPU_IRQ_TYPE_SFI_CMD_1_OUT, INTF_3, + DPU_INTR_DSICMD_1_OUTOF_STATIC, 6}, + { DPU_IRQ_TYPE_SFI_CMD_2_IN, INTF_3, + DPU_INTR_DSICMD_2_INTO_STATIC, 6}, + { DPU_IRQ_TYPE_SFI_CMD_2_OUT, INTF_3, + DPU_INTR_DSICMD_2_OUTOF_STATIC, 6}, + /* irq_idx: 200-203 */ + { DPU_IRQ_TYPE_PROG_LINE, INTF_3, DPU_INTR_PROG_LINE, 6}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 6}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 6}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 6}, + /* irq_idx: 204-207 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 6}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 6}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 6}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 6}, + /* irq_idx: 208-211 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 6}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 6}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 6}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 6}, + /* irq_idx: 212-215 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 6}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 6}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 6}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 6}, + /* irq_idx: 216-219 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 6}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 6}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 6}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 6}, + /* irq_idx: 220-223 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 6}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 6}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 6}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 6}, + + /* BEGIN MAP_RANGE: 224-255 INTF_4_INTR */ + /* irq_idx: 224-227 */ + { DPU_IRQ_TYPE_SFI_VIDEO_IN, INTF_4, + DPU_INTR_VIDEO_INTO_STATIC, 7}, + { DPU_IRQ_TYPE_SFI_VIDEO_OUT, INTF_4, + DPU_INTR_VIDEO_OUTOF_STATIC, 7}, + { DPU_IRQ_TYPE_SFI_CMD_0_IN, INTF_4, + DPU_INTR_DSICMD_0_INTO_STATIC, 7}, + { DPU_IRQ_TYPE_SFI_CMD_0_OUT, INTF_4, + DPU_INTR_DSICMD_0_OUTOF_STATIC, 7}, + /* irq_idx: 228-231 */ + { DPU_IRQ_TYPE_SFI_CMD_1_IN, INTF_4, + DPU_INTR_DSICMD_1_INTO_STATIC, 7}, + { DPU_IRQ_TYPE_SFI_CMD_1_OUT, INTF_4, + DPU_INTR_DSICMD_1_OUTOF_STATIC, 7}, + { DPU_IRQ_TYPE_SFI_CMD_2_IN, INTF_4, + DPU_INTR_DSICMD_2_INTO_STATIC, 7}, + { DPU_IRQ_TYPE_SFI_CMD_2_OUT, INTF_4, + DPU_INTR_DSICMD_2_OUTOF_STATIC, 7}, + /* irq_idx: 232-235 */ + { DPU_IRQ_TYPE_PROG_LINE, INTF_4, DPU_INTR_PROG_LINE, 7}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 7}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 7}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 7}, + /* irq_idx: 236-239 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 7}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 7}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 7}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 7}, + /* irq_idx: 240-243 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 7}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 7}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 7}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 7}, + /* irq_idx: 244-247 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 7}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 7}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 7}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 7}, + /* irq_idx: 248-251 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 7}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 7}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 7}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 7}, + /* irq_idx: 252-255 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 7}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 7}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 7}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 7}, + + /* BEGIN MAP_RANGE: 256-287 AD4_0_INTR */ + /* irq_idx: 256-259 */ + { DPU_IRQ_TYPE_AD4_BL_DONE, DSPP_0, DPU_INTR_BACKLIGHT_UPDATED, 8}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 8}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 8}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 8}, + /* irq_idx: 260-263 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 8}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 8}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 8}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 8}, + /* irq_idx: 264-267 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 8}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 8}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 8}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 8}, + /* irq_idx: 268-271 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 8}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 8}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 8}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 8}, + /* irq_idx: 272-275 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 8}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 8}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 8}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 8}, + /* irq_idx: 276-279 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 8}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 8}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 8}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 8}, + /* irq_idx: 280-283 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 8}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 8}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 8}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 8}, + /* irq_idx: 284-287 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 8}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 8}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 8}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 8}, + + /* BEGIN MAP_RANGE: 288-319 AD4_1_INTR */ + /* irq_idx: 288-291 */ + { DPU_IRQ_TYPE_AD4_BL_DONE, DSPP_1, DPU_INTR_BACKLIGHT_UPDATED, 9}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 9}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 9}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 9}, + /* irq_idx: 292-295 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 9}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 9}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 9}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 9}, + /* irq_idx: 296-299 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 9}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 9}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 9}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 9}, + /* irq_idx: 300-303 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 9}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 9}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 9}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 9}, + /* irq_idx: 304-307 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 9}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 9}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 9}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 9}, + /* irq_idx: 308-311 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 9}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 9}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 9}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 9}, + /* irq_idx: 312-315 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 9}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 9}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 9}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 9}, + /* irq_idx: 315-319 */ + { DPU_IRQ_TYPE_RESERVED, 0, 0, 9}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 9}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 9}, + { DPU_IRQ_TYPE_RESERVED, 0, 0, 9}, +}; + +static int dpu_hw_intr_irqidx_lookup(enum dpu_intr_type intr_type, + u32 instance_idx) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(dpu_irq_map); i++) { + if (intr_type == dpu_irq_map[i].intr_type && + instance_idx == dpu_irq_map[i].instance_idx) + return i; + } + + pr_debug("IRQ lookup fail!! intr_type=%d, instance_idx=%d\n", + intr_type, instance_idx); + return -EINVAL; +} + +static void dpu_hw_intr_set_mask(struct dpu_hw_intr *intr, uint32_t reg_off, + uint32_t mask) +{ + if (!intr) + return; + + DPU_REG_WRITE(&intr->hw, reg_off, mask); + + /* ensure register writes go through */ + wmb(); +} + +static void dpu_hw_intr_dispatch_irq(struct dpu_hw_intr *intr, + void (*cbfunc)(void *, int), + void *arg) +{ + int reg_idx; + int irq_idx; + int start_idx; + int end_idx; + u32 irq_status; + unsigned long irq_flags; + + if (!intr) + return; + + /* + * The dispatcher will save the IRQ status before calling here. + * Now need to go through each IRQ status and find matching + * irq lookup index. + */ + spin_lock_irqsave(&intr->irq_lock, irq_flags); + for (reg_idx = 0; reg_idx < ARRAY_SIZE(dpu_intr_set); reg_idx++) { + irq_status = intr->save_irq_status[reg_idx]; + + /* + * Each Interrupt register has a range of 32 indexes, and + * that is static for dpu_irq_map. + */ + start_idx = reg_idx * 32; + end_idx = start_idx + 32; + + if (start_idx >= ARRAY_SIZE(dpu_irq_map) || + end_idx > ARRAY_SIZE(dpu_irq_map)) + continue; + + /* + * Search through matching intr status from irq map. + * start_idx and end_idx defined the search range in + * the dpu_irq_map. + */ + for (irq_idx = start_idx; + (irq_idx < end_idx) && irq_status; + irq_idx++) + if ((irq_status & dpu_irq_map[irq_idx].irq_mask) && + (dpu_irq_map[irq_idx].reg_idx == reg_idx)) { + /* + * Once a match on irq mask, perform a callback + * to the given cbfunc. cbfunc will take care + * the interrupt status clearing. If cbfunc is + * not provided, then the interrupt clearing + * is here. + */ + if (cbfunc) + cbfunc(arg, irq_idx); + else + intr->ops.clear_intr_status_nolock( + intr, irq_idx); + + /* + * When callback finish, clear the irq_status + * with the matching mask. Once irq_status + * is all cleared, the search can be stopped. + */ + irq_status &= ~dpu_irq_map[irq_idx].irq_mask; + } + } + spin_unlock_irqrestore(&intr->irq_lock, irq_flags); +} + +static int dpu_hw_intr_enable_irq(struct dpu_hw_intr *intr, int irq_idx) +{ + int reg_idx; + unsigned long irq_flags; + const struct dpu_intr_reg *reg; + const struct dpu_irq_type *irq; + const char *dbgstr = NULL; + uint32_t cache_irq_mask; + + if (!intr) + return -EINVAL; + + if (irq_idx < 0 || irq_idx >= ARRAY_SIZE(dpu_irq_map)) { + pr_err("invalid IRQ index: [%d]\n", irq_idx); + return -EINVAL; + } + + irq = &dpu_irq_map[irq_idx]; + reg_idx = irq->reg_idx; + reg = &dpu_intr_set[reg_idx]; + + spin_lock_irqsave(&intr->irq_lock, irq_flags); + cache_irq_mask = intr->cache_irq_mask[reg_idx]; + if (cache_irq_mask & irq->irq_mask) { + dbgstr = "DPU IRQ already set:"; + } else { + dbgstr = "DPU IRQ enabled:"; + + cache_irq_mask |= irq->irq_mask; + /* Cleaning any pending interrupt */ + DPU_REG_WRITE(&intr->hw, reg->clr_off, irq->irq_mask); + /* Enabling interrupts with the new mask */ + DPU_REG_WRITE(&intr->hw, reg->en_off, cache_irq_mask); + + /* ensure register write goes through */ + wmb(); + + intr->cache_irq_mask[reg_idx] = cache_irq_mask; + } + spin_unlock_irqrestore(&intr->irq_lock, irq_flags); + + pr_debug("%s MASK:0x%.8x, CACHE-MASK:0x%.8x\n", dbgstr, + irq->irq_mask, cache_irq_mask); + + return 0; +} + +static int dpu_hw_intr_disable_irq_nolock(struct dpu_hw_intr *intr, int irq_idx) +{ + int reg_idx; + const struct dpu_intr_reg *reg; + const struct dpu_irq_type *irq; + const char *dbgstr = NULL; + uint32_t cache_irq_mask; + + if (!intr) + return -EINVAL; + + if (irq_idx < 0 || irq_idx >= ARRAY_SIZE(dpu_irq_map)) { + pr_err("invalid IRQ index: [%d]\n", irq_idx); + return -EINVAL; + } + + irq = &dpu_irq_map[irq_idx]; + reg_idx = irq->reg_idx; + reg = &dpu_intr_set[reg_idx]; + + cache_irq_mask = intr->cache_irq_mask[reg_idx]; + if ((cache_irq_mask & irq->irq_mask) == 0) { + dbgstr = "DPU IRQ is already cleared:"; + } else { + dbgstr = "DPU IRQ mask disable:"; + + cache_irq_mask &= ~irq->irq_mask; + /* Disable interrupts based on the new mask */ + DPU_REG_WRITE(&intr->hw, reg->en_off, cache_irq_mask); + /* Cleaning any pending interrupt */ + DPU_REG_WRITE(&intr->hw, reg->clr_off, irq->irq_mask); + + /* ensure register write goes through */ + wmb(); + + intr->cache_irq_mask[reg_idx] = cache_irq_mask; + } + + pr_debug("%s MASK:0x%.8x, CACHE-MASK:0x%.8x\n", dbgstr, + irq->irq_mask, cache_irq_mask); + + return 0; +} + +static int dpu_hw_intr_disable_irq(struct dpu_hw_intr *intr, int irq_idx) +{ + unsigned long irq_flags; + + if (!intr) + return -EINVAL; + + if (irq_idx < 0 || irq_idx >= ARRAY_SIZE(dpu_irq_map)) { + pr_err("invalid IRQ index: [%d]\n", irq_idx); + return -EINVAL; + } + + spin_lock_irqsave(&intr->irq_lock, irq_flags); + dpu_hw_intr_disable_irq_nolock(intr, irq_idx); + spin_unlock_irqrestore(&intr->irq_lock, irq_flags); + + return 0; +} + +static int dpu_hw_intr_clear_irqs(struct dpu_hw_intr *intr) +{ + int i; + + if (!intr) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(dpu_intr_set); i++) + DPU_REG_WRITE(&intr->hw, dpu_intr_set[i].clr_off, 0xffffffff); + + /* ensure register writes go through */ + wmb(); + + return 0; +} + +static int dpu_hw_intr_disable_irqs(struct dpu_hw_intr *intr) +{ + int i; + + if (!intr) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(dpu_intr_set); i++) + DPU_REG_WRITE(&intr->hw, dpu_intr_set[i].en_off, 0x00000000); + + /* ensure register writes go through */ + wmb(); + + return 0; +} + +static int dpu_hw_intr_get_valid_interrupts(struct dpu_hw_intr *intr, + uint32_t *mask) +{ + if (!intr || !mask) + return -EINVAL; + + *mask = IRQ_SOURCE_MDP | IRQ_SOURCE_DSI0 | IRQ_SOURCE_DSI1 + | IRQ_SOURCE_HDMI | IRQ_SOURCE_EDP; + + return 0; +} + +static void dpu_hw_intr_get_interrupt_statuses(struct dpu_hw_intr *intr) +{ + int i; + u32 enable_mask; + unsigned long irq_flags; + + if (!intr) + return; + + spin_lock_irqsave(&intr->irq_lock, irq_flags); + for (i = 0; i < ARRAY_SIZE(dpu_intr_set); i++) { + /* Read interrupt status */ + intr->save_irq_status[i] = DPU_REG_READ(&intr->hw, + dpu_intr_set[i].status_off); + + /* Read enable mask */ + enable_mask = DPU_REG_READ(&intr->hw, dpu_intr_set[i].en_off); + + /* and clear the interrupt */ + if (intr->save_irq_status[i]) + DPU_REG_WRITE(&intr->hw, dpu_intr_set[i].clr_off, + intr->save_irq_status[i]); + + /* Finally update IRQ status based on enable mask */ + intr->save_irq_status[i] &= enable_mask; + } + + /* ensure register writes go through */ + wmb(); + + spin_unlock_irqrestore(&intr->irq_lock, irq_flags); +} + +static void dpu_hw_intr_clear_intr_status_nolock(struct dpu_hw_intr *intr, + int irq_idx) +{ + int reg_idx; + + if (!intr) + return; + + reg_idx = dpu_irq_map[irq_idx].reg_idx; + DPU_REG_WRITE(&intr->hw, dpu_intr_set[reg_idx].clr_off, + dpu_irq_map[irq_idx].irq_mask); + + /* ensure register writes go through */ + wmb(); +} + +static void dpu_hw_intr_clear_interrupt_status(struct dpu_hw_intr *intr, + int irq_idx) +{ + unsigned long irq_flags; + + if (!intr) + return; + + spin_lock_irqsave(&intr->irq_lock, irq_flags); + dpu_hw_intr_clear_intr_status_nolock(intr, irq_idx); + spin_unlock_irqrestore(&intr->irq_lock, irq_flags); +} + +static u32 dpu_hw_intr_get_interrupt_status(struct dpu_hw_intr *intr, + int irq_idx, bool clear) +{ + int reg_idx; + unsigned long irq_flags; + u32 intr_status; + + if (!intr) + return 0; + + if (irq_idx >= ARRAY_SIZE(dpu_irq_map) || irq_idx < 0) { + pr_err("invalid IRQ index: [%d]\n", irq_idx); + return 0; + } + + spin_lock_irqsave(&intr->irq_lock, irq_flags); + + reg_idx = dpu_irq_map[irq_idx].reg_idx; + intr_status = DPU_REG_READ(&intr->hw, + dpu_intr_set[reg_idx].status_off) & + dpu_irq_map[irq_idx].irq_mask; + if (intr_status && clear) + DPU_REG_WRITE(&intr->hw, dpu_intr_set[reg_idx].clr_off, + intr_status); + + /* ensure register writes go through */ + wmb(); + + spin_unlock_irqrestore(&intr->irq_lock, irq_flags); + + return intr_status; +} + +static void __setup_intr_ops(struct dpu_hw_intr_ops *ops) +{ + ops->set_mask = dpu_hw_intr_set_mask; + ops->irq_idx_lookup = dpu_hw_intr_irqidx_lookup; + ops->enable_irq = dpu_hw_intr_enable_irq; + ops->disable_irq = dpu_hw_intr_disable_irq; + ops->dispatch_irqs = dpu_hw_intr_dispatch_irq; + ops->clear_all_irqs = dpu_hw_intr_clear_irqs; + ops->disable_all_irqs = dpu_hw_intr_disable_irqs; + ops->get_valid_interrupts = dpu_hw_intr_get_valid_interrupts; + ops->get_interrupt_statuses = dpu_hw_intr_get_interrupt_statuses; + ops->clear_interrupt_status = dpu_hw_intr_clear_interrupt_status; + ops->clear_intr_status_nolock = dpu_hw_intr_clear_intr_status_nolock; + ops->get_interrupt_status = dpu_hw_intr_get_interrupt_status; +} + +static void __intr_offset(struct dpu_mdss_cfg *m, + void __iomem *addr, struct dpu_hw_blk_reg_map *hw) +{ + hw->base_off = addr; + hw->blk_off = m->mdp[0].base; + hw->hwversion = m->hwversion; +} + +struct dpu_hw_intr *dpu_hw_intr_init(void __iomem *addr, + struct dpu_mdss_cfg *m) +{ + struct dpu_hw_intr *intr; + + if (!addr || !m) + return ERR_PTR(-EINVAL); + + intr = kzalloc(sizeof(*intr), GFP_KERNEL); + if (!intr) + return ERR_PTR(-ENOMEM); + + __intr_offset(m, addr, &intr->hw); + __setup_intr_ops(&intr->ops); + + intr->irq_idx_tbl_size = ARRAY_SIZE(dpu_irq_map); + + intr->cache_irq_mask = kcalloc(ARRAY_SIZE(dpu_intr_set), sizeof(u32), + GFP_KERNEL); + if (intr->cache_irq_mask == NULL) { + kfree(intr); + return ERR_PTR(-ENOMEM); + } + + intr->save_irq_status = kcalloc(ARRAY_SIZE(dpu_intr_set), sizeof(u32), + GFP_KERNEL); + if (intr->save_irq_status == NULL) { + kfree(intr->cache_irq_mask); + kfree(intr); + return ERR_PTR(-ENOMEM); + } + + spin_lock_init(&intr->irq_lock); + + return intr; +} + +void dpu_hw_intr_destroy(struct dpu_hw_intr *intr) +{ + if (intr) { + kfree(intr->cache_irq_mask); + kfree(intr->save_irq_status); + kfree(intr); + } +} + diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h new file mode 100644 index 0000000000000..61e4cba36562f --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h @@ -0,0 +1,257 @@ +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef _DPU_HW_INTERRUPTS_H +#define _DPU_HW_INTERRUPTS_H + +#include <linux/types.h> + +#include "dpu_hwio.h" +#include "dpu_hw_catalog.h" +#include "dpu_hw_util.h" +#include "dpu_hw_mdss.h" + +#define IRQ_SOURCE_MDP BIT(0) +#define IRQ_SOURCE_DSI0 BIT(4) +#define IRQ_SOURCE_DSI1 BIT(5) +#define IRQ_SOURCE_HDMI BIT(8) +#define IRQ_SOURCE_EDP BIT(12) +#define IRQ_SOURCE_MHL BIT(16) + +/** + * dpu_intr_type - HW Interrupt Type + * @DPU_IRQ_TYPE_WB_ROT_COMP: WB rotator done + * @DPU_IRQ_TYPE_WB_WFD_COMP: WB WFD done + * @DPU_IRQ_TYPE_PING_PONG_COMP: PingPong done + * @DPU_IRQ_TYPE_PING_PONG_RD_PTR: PingPong read pointer + * @DPU_IRQ_TYPE_PING_PONG_WR_PTR: PingPong write pointer + * @DPU_IRQ_TYPE_PING_PONG_AUTO_REF: PingPong auto refresh + * @DPU_IRQ_TYPE_PING_PONG_TEAR_CHECK: PingPong Tear check + * @DPU_IRQ_TYPE_PING_PONG_TE_CHECK: PingPong TE detection + * @DPU_IRQ_TYPE_INTF_UNDER_RUN: INTF underrun + * @DPU_IRQ_TYPE_INTF_VSYNC: INTF VSYNC + * @DPU_IRQ_TYPE_CWB_OVERFLOW: Concurrent WB overflow + * @DPU_IRQ_TYPE_HIST_VIG_DONE: VIG Histogram done + * @DPU_IRQ_TYPE_HIST_VIG_RSTSEQ: VIG Histogram reset + * @DPU_IRQ_TYPE_HIST_DSPP_DONE: DSPP Histogram done + * @DPU_IRQ_TYPE_HIST_DSPP_RSTSEQ: DSPP Histogram reset + * @DPU_IRQ_TYPE_WD_TIMER: Watchdog timer + * @DPU_IRQ_TYPE_SFI_VIDEO_IN: Video static frame INTR into static + * @DPU_IRQ_TYPE_SFI_VIDEO_OUT: Video static frame INTR out-of static + * @DPU_IRQ_TYPE_SFI_CMD_0_IN: DSI CMD0 static frame INTR into static + * @DPU_IRQ_TYPE_SFI_CMD_0_OUT: DSI CMD0 static frame INTR out-of static + * @DPU_IRQ_TYPE_SFI_CMD_1_IN: DSI CMD1 static frame INTR into static + * @DPU_IRQ_TYPE_SFI_CMD_1_OUT: DSI CMD1 static frame INTR out-of static + * @DPU_IRQ_TYPE_SFI_CMD_2_IN: DSI CMD2 static frame INTR into static + * @DPU_IRQ_TYPE_SFI_CMD_2_OUT: DSI CMD2 static frame INTR out-of static + * @DPU_IRQ_TYPE_PROG_LINE: Programmable Line interrupt + * @DPU_IRQ_TYPE_AD4_BL_DONE: AD4 backlight + * @DPU_IRQ_TYPE_CTL_START: Control start + * @DPU_IRQ_TYPE_RESERVED: Reserved for expansion + */ +enum dpu_intr_type { + DPU_IRQ_TYPE_WB_ROT_COMP, + DPU_IRQ_TYPE_WB_WFD_COMP, + DPU_IRQ_TYPE_PING_PONG_COMP, + DPU_IRQ_TYPE_PING_PONG_RD_PTR, + DPU_IRQ_TYPE_PING_PONG_WR_PTR, + DPU_IRQ_TYPE_PING_PONG_AUTO_REF, + DPU_IRQ_TYPE_PING_PONG_TEAR_CHECK, + DPU_IRQ_TYPE_PING_PONG_TE_CHECK, + DPU_IRQ_TYPE_INTF_UNDER_RUN, + DPU_IRQ_TYPE_INTF_VSYNC, + DPU_IRQ_TYPE_CWB_OVERFLOW, + DPU_IRQ_TYPE_HIST_VIG_DONE, + DPU_IRQ_TYPE_HIST_VIG_RSTSEQ, + DPU_IRQ_TYPE_HIST_DSPP_DONE, + DPU_IRQ_TYPE_HIST_DSPP_RSTSEQ, + DPU_IRQ_TYPE_WD_TIMER, + DPU_IRQ_TYPE_SFI_VIDEO_IN, + DPU_IRQ_TYPE_SFI_VIDEO_OUT, + DPU_IRQ_TYPE_SFI_CMD_0_IN, + DPU_IRQ_TYPE_SFI_CMD_0_OUT, + DPU_IRQ_TYPE_SFI_CMD_1_IN, + DPU_IRQ_TYPE_SFI_CMD_1_OUT, + DPU_IRQ_TYPE_SFI_CMD_2_IN, + DPU_IRQ_TYPE_SFI_CMD_2_OUT, + DPU_IRQ_TYPE_PROG_LINE, + DPU_IRQ_TYPE_AD4_BL_DONE, + DPU_IRQ_TYPE_CTL_START, + DPU_IRQ_TYPE_RESERVED, +}; + +struct dpu_hw_intr; + +/** + * Interrupt operations. + */ +struct dpu_hw_intr_ops { + /** + * set_mask - Programs the given interrupt register with the + * given interrupt mask. Register value will get overwritten. + * @intr: HW interrupt handle + * @reg_off: MDSS HW register offset + * @irqmask: IRQ mask value + */ + void (*set_mask)( + struct dpu_hw_intr *intr, + uint32_t reg, + uint32_t irqmask); + + /** + * irq_idx_lookup - Lookup IRQ index on the HW interrupt type + * Used for all irq related ops + * @intr_type: Interrupt type defined in dpu_intr_type + * @instance_idx: HW interrupt block instance + * @return: irq_idx or -EINVAL for lookup fail + */ + int (*irq_idx_lookup)( + enum dpu_intr_type intr_type, + u32 instance_idx); + + /** + * enable_irq - Enable IRQ based on lookup IRQ index + * @intr: HW interrupt handle + * @irq_idx: Lookup irq index return from irq_idx_lookup + * @return: 0 for success, otherwise failure + */ + int (*enable_irq)( + struct dpu_hw_intr *intr, + int irq_idx); + + /** + * disable_irq - Disable IRQ based on lookup IRQ index + * @intr: HW interrupt handle + * @irq_idx: Lookup irq index return from irq_idx_lookup + * @return: 0 for success, otherwise failure + */ + int (*disable_irq)( + struct dpu_hw_intr *intr, + int irq_idx); + + /** + * clear_all_irqs - Clears all the interrupts (i.e. acknowledges + * any asserted IRQs). Useful during reset. + * @intr: HW interrupt handle + * @return: 0 for success, otherwise failure + */ + int (*clear_all_irqs)( + struct dpu_hw_intr *intr); + + /** + * disable_all_irqs - Disables all the interrupts. Useful during reset. + * @intr: HW interrupt handle + * @return: 0 for success, otherwise failure + */ + int (*disable_all_irqs)( + struct dpu_hw_intr *intr); + + /** + * dispatch_irqs - IRQ dispatcher will call the given callback + * function when a matching interrupt status bit is + * found in the irq mapping table. + * @intr: HW interrupt handle + * @cbfunc: Callback function pointer + * @arg: Argument to pass back during callback + */ + void (*dispatch_irqs)( + struct dpu_hw_intr *intr, + void (*cbfunc)(void *arg, int irq_idx), + void *arg); + + /** + * get_interrupt_statuses - Gets and store value from all interrupt + * status registers that are currently fired. + * @intr: HW interrupt handle + */ + void (*get_interrupt_statuses)( + struct dpu_hw_intr *intr); + + /** + * clear_interrupt_status - Clears HW interrupt status based on given + * lookup IRQ index. + * @intr: HW interrupt handle + * @irq_idx: Lookup irq index return from irq_idx_lookup + */ + void (*clear_interrupt_status)( + struct dpu_hw_intr *intr, + int irq_idx); + + /** + * clear_intr_status_nolock() - clears the HW interrupts without lock + * @intr: HW interrupt handle + * @irq_idx: Lookup irq index return from irq_idx_lookup + */ + void (*clear_intr_status_nolock)( + struct dpu_hw_intr *intr, + int irq_idx); + + /** + * get_interrupt_status - Gets HW interrupt status, and clear if set, + * based on given lookup IRQ index. + * @intr: HW interrupt handle + * @irq_idx: Lookup irq index return from irq_idx_lookup + * @clear: True to clear irq after read + */ + u32 (*get_interrupt_status)( + struct dpu_hw_intr *intr, + int irq_idx, + bool clear); + + /** + * get_valid_interrupts - Gets a mask of all valid interrupt sources + * within DPU. These are actually status bits + * within interrupt registers that specify the + * source of the interrupt in IRQs. For example, + * valid interrupt sources can be MDP, DSI, + * HDMI etc. + * @intr: HW interrupt handle + * @mask: Returning the interrupt source MASK + * @return: 0 for success, otherwise failure + */ + int (*get_valid_interrupts)( + struct dpu_hw_intr *intr, + uint32_t *mask); +}; + +/** + * struct dpu_hw_intr: hw interrupts handling data structure + * @hw: virtual address mapping + * @ops: function pointer mapping for IRQ handling + * @cache_irq_mask: array of IRQ enable masks reg storage created during init + * @save_irq_status: array of IRQ status reg storage created during init + * @irq_idx_tbl_size: total number of irq_idx mapped in the hw_interrupts + * @irq_lock: spinlock for accessing IRQ resources + */ +struct dpu_hw_intr { + struct dpu_hw_blk_reg_map hw; + struct dpu_hw_intr_ops ops; + u32 *cache_irq_mask; + u32 *save_irq_status; + u32 irq_idx_tbl_size; + spinlock_t irq_lock; +}; + +/** + * dpu_hw_intr_init(): Initializes the interrupts hw object + * @addr: mapped register io address of MDP + * @m : pointer to mdss catalog data + */ +struct dpu_hw_intr *dpu_hw_intr_init(void __iomem *addr, + struct dpu_mdss_cfg *m); + +/** + * dpu_hw_intr_destroy(): Cleanup interrutps hw object + * @intr: pointer to interrupts hw object + */ +void dpu_hw_intr_destroy(struct dpu_hw_intr *intr); +#endif diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c new file mode 100644 index 0000000000000..d280df5613c9a --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c @@ -0,0 +1,349 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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 "dpu_hwio.h" +#include "dpu_hw_catalog.h" +#include "dpu_hw_intf.h" +#include "dpu_dbg.h" +#include "dpu_kms.h" + +#define INTF_TIMING_ENGINE_EN 0x000 +#define INTF_CONFIG 0x004 +#define INTF_HSYNC_CTL 0x008 +#define INTF_VSYNC_PERIOD_F0 0x00C +#define INTF_VSYNC_PERIOD_F1 0x010 +#define INTF_VSYNC_PULSE_WIDTH_F0 0x014 +#define INTF_VSYNC_PULSE_WIDTH_F1 0x018 +#define INTF_DISPLAY_V_START_F0 0x01C +#define INTF_DISPLAY_V_START_F1 0x020 +#define INTF_DISPLAY_V_END_F0 0x024 +#define INTF_DISPLAY_V_END_F1 0x028 +#define INTF_ACTIVE_V_START_F0 0x02C +#define INTF_ACTIVE_V_START_F1 0x030 +#define INTF_ACTIVE_V_END_F0 0x034 +#define INTF_ACTIVE_V_END_F1 0x038 +#define INTF_DISPLAY_HCTL 0x03C +#define INTF_ACTIVE_HCTL 0x040 +#define INTF_BORDER_COLOR 0x044 +#define INTF_UNDERFLOW_COLOR 0x048 +#define INTF_HSYNC_SKEW 0x04C +#define INTF_POLARITY_CTL 0x050 +#define INTF_TEST_CTL 0x054 +#define INTF_TP_COLOR0 0x058 +#define INTF_TP_COLOR1 0x05C +#define INTF_FRAME_LINE_COUNT_EN 0x0A8 +#define INTF_FRAME_COUNT 0x0AC +#define INTF_LINE_COUNT 0x0B0 + +#define INTF_DEFLICKER_CONFIG 0x0F0 +#define INTF_DEFLICKER_STRNG_COEFF 0x0F4 +#define INTF_DEFLICKER_WEAK_COEFF 0x0F8 + +#define INTF_DSI_CMD_MODE_TRIGGER_EN 0x084 +#define INTF_PANEL_FORMAT 0x090 +#define INTF_TPG_ENABLE 0x100 +#define INTF_TPG_MAIN_CONTROL 0x104 +#define INTF_TPG_VIDEO_CONFIG 0x108 +#define INTF_TPG_COMPONENT_LIMITS 0x10C +#define INTF_TPG_RECTANGLE 0x110 +#define INTF_TPG_INITIAL_VALUE 0x114 +#define INTF_TPG_BLK_WHITE_PATTERN_FRAMES 0x118 +#define INTF_TPG_RGB_MAPPING 0x11C +#define INTF_PROG_FETCH_START 0x170 +#define INTF_PROG_ROT_START 0x174 + +#define INTF_FRAME_LINE_COUNT_EN 0x0A8 +#define INTF_FRAME_COUNT 0x0AC +#define INTF_LINE_COUNT 0x0B0 + +#define INTF_MISR_CTRL 0x180 +#define INTF_MISR_SIGNATURE 0x184 + +static struct dpu_intf_cfg *_intf_offset(enum dpu_intf intf, + struct dpu_mdss_cfg *m, + void __iomem *addr, + struct dpu_hw_blk_reg_map *b) +{ + int i; + + for (i = 0; i < m->intf_count; i++) { + if ((intf == m->intf[i].id) && + (m->intf[i].type != INTF_NONE)) { + b->base_off = addr; + b->blk_off = m->intf[i].base; + b->length = m->intf[i].len; + b->hwversion = m->hwversion; + b->log_mask = DPU_DBG_MASK_INTF; + return &m->intf[i]; + } + } + + return ERR_PTR(-EINVAL); +} + +static void dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *ctx, + const struct intf_timing_params *p, + const struct dpu_format *fmt) +{ + struct dpu_hw_blk_reg_map *c = &ctx->hw; + u32 hsync_period, vsync_period; + u32 display_v_start, display_v_end; + u32 hsync_start_x, hsync_end_x; + u32 active_h_start, active_h_end; + u32 active_v_start, active_v_end; + u32 active_hctl, display_hctl, hsync_ctl; + u32 polarity_ctl, den_polarity, hsync_polarity, vsync_polarity; + u32 panel_format; + u32 intf_cfg; + + /* read interface_cfg */ + intf_cfg = DPU_REG_READ(c, INTF_CONFIG); + hsync_period = p->hsync_pulse_width + p->h_back_porch + p->width + + p->h_front_porch; + vsync_period = p->vsync_pulse_width + p->v_back_porch + p->height + + p->v_front_porch; + + display_v_start = ((p->vsync_pulse_width + p->v_back_porch) * + hsync_period) + p->hsync_skew; + display_v_end = ((vsync_period - p->v_front_porch) * hsync_period) + + p->hsync_skew - 1; + + if (ctx->cap->type == INTF_EDP || ctx->cap->type == INTF_DP) { + display_v_start += p->hsync_pulse_width + p->h_back_porch; + display_v_end -= p->h_front_porch; + } + + hsync_start_x = p->h_back_porch + p->hsync_pulse_width; + hsync_end_x = hsync_period - p->h_front_porch - 1; + + if (p->width != p->xres) { + active_h_start = hsync_start_x; + active_h_end = active_h_start + p->xres - 1; + } else { + active_h_start = 0; + active_h_end = 0; + } + + if (p->height != p->yres) { + active_v_start = display_v_start; + active_v_end = active_v_start + (p->yres * hsync_period) - 1; + } else { + active_v_start = 0; + active_v_end = 0; + } + + if (active_h_end) { + active_hctl = (active_h_end << 16) | active_h_start; + intf_cfg |= BIT(29); /* ACTIVE_H_ENABLE */ + } else { + active_hctl = 0; + } + + if (active_v_end) + intf_cfg |= BIT(30); /* ACTIVE_V_ENABLE */ + + hsync_ctl = (hsync_period << 16) | p->hsync_pulse_width; + display_hctl = (hsync_end_x << 16) | hsync_start_x; + + den_polarity = 0; + if (ctx->cap->type == INTF_HDMI) { + hsync_polarity = p->yres >= 720 ? 0 : 1; + vsync_polarity = p->yres >= 720 ? 0 : 1; + } else { + hsync_polarity = 0; + vsync_polarity = 0; + } + polarity_ctl = (den_polarity << 2) | /* DEN Polarity */ + (vsync_polarity << 1) | /* VSYNC Polarity */ + (hsync_polarity << 0); /* HSYNC Polarity */ + + if (!DPU_FORMAT_IS_YUV(fmt)) + panel_format = (fmt->bits[C0_G_Y] | + (fmt->bits[C1_B_Cb] << 2) | + (fmt->bits[C2_R_Cr] << 4) | + (0x21 << 8)); + else + /* Interface treats all the pixel data in RGB888 format */ + panel_format = (COLOR_8BIT | + (COLOR_8BIT << 2) | + (COLOR_8BIT << 4) | + (0x21 << 8)); + + DPU_REG_WRITE(c, INTF_HSYNC_CTL, hsync_ctl); + DPU_REG_WRITE(c, INTF_VSYNC_PERIOD_F0, vsync_period * hsync_period); + DPU_REG_WRITE(c, INTF_VSYNC_PULSE_WIDTH_F0, + p->vsync_pulse_width * hsync_period); + DPU_REG_WRITE(c, INTF_DISPLAY_HCTL, display_hctl); + DPU_REG_WRITE(c, INTF_DISPLAY_V_START_F0, display_v_start); + DPU_REG_WRITE(c, INTF_DISPLAY_V_END_F0, display_v_end); + DPU_REG_WRITE(c, INTF_ACTIVE_HCTL, active_hctl); + DPU_REG_WRITE(c, INTF_ACTIVE_V_START_F0, active_v_start); + DPU_REG_WRITE(c, INTF_ACTIVE_V_END_F0, active_v_end); + DPU_REG_WRITE(c, INTF_BORDER_COLOR, p->border_clr); + DPU_REG_WRITE(c, INTF_UNDERFLOW_COLOR, p->underflow_clr); + DPU_REG_WRITE(c, INTF_HSYNC_SKEW, p->hsync_skew); + DPU_REG_WRITE(c, INTF_POLARITY_CTL, polarity_ctl); + DPU_REG_WRITE(c, INTF_FRAME_LINE_COUNT_EN, 0x3); + DPU_REG_WRITE(c, INTF_CONFIG, intf_cfg); + DPU_REG_WRITE(c, INTF_PANEL_FORMAT, panel_format); +} + +static void dpu_hw_intf_enable_timing_engine( + struct dpu_hw_intf *intf, + u8 enable) +{ + struct dpu_hw_blk_reg_map *c = &intf->hw; + /* Note: Display interface select is handled in top block hw layer */ + DPU_REG_WRITE(c, INTF_TIMING_ENGINE_EN, enable != 0); +} + +static void dpu_hw_intf_setup_prg_fetch( + struct dpu_hw_intf *intf, + const struct intf_prog_fetch *fetch) +{ + struct dpu_hw_blk_reg_map *c = &intf->hw; + int fetch_enable; + + /* + * Fetch should always be outside the active lines. If the fetching + * is programmed within active region, hardware behavior is unknown. + */ + + fetch_enable = DPU_REG_READ(c, INTF_CONFIG); + if (fetch->enable) { + fetch_enable |= BIT(31); + DPU_REG_WRITE(c, INTF_PROG_FETCH_START, + fetch->fetch_start); + } else { + fetch_enable &= ~BIT(31); + } + + DPU_REG_WRITE(c, INTF_CONFIG, fetch_enable); +} + +static void dpu_hw_intf_get_status( + struct dpu_hw_intf *intf, + struct intf_status *s) +{ + struct dpu_hw_blk_reg_map *c = &intf->hw; + + s->is_en = DPU_REG_READ(c, INTF_TIMING_ENGINE_EN); + if (s->is_en) { + s->frame_count = DPU_REG_READ(c, INTF_FRAME_COUNT); + s->line_count = DPU_REG_READ(c, INTF_LINE_COUNT); + } else { + s->line_count = 0; + s->frame_count = 0; + } +} + +static void dpu_hw_intf_setup_misr(struct dpu_hw_intf *intf, + bool enable, u32 frame_count) +{ + struct dpu_hw_blk_reg_map *c = &intf->hw; + u32 config = 0; + + DPU_REG_WRITE(c, INTF_MISR_CTRL, MISR_CTRL_STATUS_CLEAR); + /* clear misr data */ + wmb(); + + if (enable) + config = (frame_count & MISR_FRAME_COUNT_MASK) | + MISR_CTRL_ENABLE | INTF_MISR_CTRL_FREE_RUN_MASK; + + DPU_REG_WRITE(c, INTF_MISR_CTRL, config); +} + +static u32 dpu_hw_intf_collect_misr(struct dpu_hw_intf *intf) +{ + struct dpu_hw_blk_reg_map *c = &intf->hw; + + return DPU_REG_READ(c, INTF_MISR_SIGNATURE); +} + +static u32 dpu_hw_intf_get_line_count(struct dpu_hw_intf *intf) +{ + struct dpu_hw_blk_reg_map *c; + + if (!intf) + return 0; + + c = &intf->hw; + + return DPU_REG_READ(c, INTF_LINE_COUNT); +} + +static void _setup_intf_ops(struct dpu_hw_intf_ops *ops, + unsigned long cap) +{ + ops->setup_timing_gen = dpu_hw_intf_setup_timing_engine; + ops->setup_prg_fetch = dpu_hw_intf_setup_prg_fetch; + ops->get_status = dpu_hw_intf_get_status; + ops->enable_timing = dpu_hw_intf_enable_timing_engine; + ops->setup_misr = dpu_hw_intf_setup_misr; + ops->collect_misr = dpu_hw_intf_collect_misr; + ops->get_line_count = dpu_hw_intf_get_line_count; +} + +static struct dpu_hw_blk_ops dpu_hw_ops = { + .start = NULL, + .stop = NULL, +}; + +struct dpu_hw_intf *dpu_hw_intf_init(enum dpu_intf idx, + void __iomem *addr, + struct dpu_mdss_cfg *m) +{ + struct dpu_hw_intf *c; + struct dpu_intf_cfg *cfg; + int rc; + + c = kzalloc(sizeof(*c), GFP_KERNEL); + if (!c) + return ERR_PTR(-ENOMEM); + + cfg = _intf_offset(idx, m, addr, &c->hw); + if (IS_ERR_OR_NULL(cfg)) { + kfree(c); + pr_err("failed to create dpu_hw_intf %d\n", idx); + return ERR_PTR(-EINVAL); + } + + /* + * Assign ops + */ + c->idx = idx; + c->cap = cfg; + c->mdss = m; + _setup_intf_ops(&c->ops, c->cap->features); + + rc = dpu_hw_blk_init(&c->base, DPU_HW_BLK_INTF, idx, &dpu_hw_ops); + if (rc) { + DPU_ERROR("failed to init hw blk %d\n", rc); + goto blk_init_error; + } + + return c; + +blk_init_error: + kzfree(c); + + return ERR_PTR(rc); +} + +void dpu_hw_intf_destroy(struct dpu_hw_intf *intf) +{ + if (intf) + dpu_hw_blk_destroy(&intf->base); + kfree(intf); +} + diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h new file mode 100644 index 0000000000000..a79d735da68d9 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h @@ -0,0 +1,128 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef _DPU_HW_INTF_H +#define _DPU_HW_INTF_H + +#include "dpu_hw_catalog.h" +#include "dpu_hw_mdss.h" +#include "dpu_hw_util.h" +#include "dpu_hw_blk.h" + +struct dpu_hw_intf; + +/* intf timing settings */ +struct intf_timing_params { + u32 width; /* active width */ + u32 height; /* active height */ + u32 xres; /* Display panel width */ + u32 yres; /* Display panel height */ + + u32 h_back_porch; + u32 h_front_porch; + u32 v_back_porch; + u32 v_front_porch; + u32 hsync_pulse_width; + u32 vsync_pulse_width; + u32 hsync_polarity; + u32 vsync_polarity; + u32 border_clr; + u32 underflow_clr; + u32 hsync_skew; +}; + +struct intf_prog_fetch { + u8 enable; + /* vsync counter for the front porch pixel line */ + u32 fetch_start; +}; + +struct intf_status { + u8 is_en; /* interface timing engine is enabled or not */ + u32 frame_count; /* frame count since timing engine enabled */ + u32 line_count; /* current line count including blanking */ +}; + +/** + * struct dpu_hw_intf_ops : Interface to the interface Hw driver functions + * Assumption is these functions will be called after clocks are enabled + * @ setup_timing_gen : programs the timing engine + * @ setup_prog_fetch : enables/disables the programmable fetch logic + * @ enable_timing: enable/disable timing engine + * @ get_status: returns if timing engine is enabled or not + * @ setup_misr: enables/disables MISR in HW register + * @ collect_misr: reads and stores MISR data from HW register + * @ get_line_count: reads current vertical line counter + */ +struct dpu_hw_intf_ops { + void (*setup_timing_gen)(struct dpu_hw_intf *intf, + const struct intf_timing_params *p, + const struct dpu_format *fmt); + + void (*setup_prg_fetch)(struct dpu_hw_intf *intf, + const struct intf_prog_fetch *fetch); + + void (*enable_timing)(struct dpu_hw_intf *intf, + u8 enable); + + void (*get_status)(struct dpu_hw_intf *intf, + struct intf_status *status); + + void (*setup_misr)(struct dpu_hw_intf *intf, + bool enable, u32 frame_count); + + u32 (*collect_misr)(struct dpu_hw_intf *intf); + + u32 (*get_line_count)(struct dpu_hw_intf *intf); +}; + +struct dpu_hw_intf { + struct dpu_hw_blk base; + struct dpu_hw_blk_reg_map hw; + + /* intf */ + enum dpu_intf idx; + const struct dpu_intf_cfg *cap; + const struct dpu_mdss_cfg *mdss; + + /* ops */ + struct dpu_hw_intf_ops ops; +}; + +/** + * to_dpu_hw_intf - convert base object dpu_hw_base to container + * @hw: Pointer to base hardware block + * return: Pointer to hardware block container + */ +static inline struct dpu_hw_intf *to_dpu_hw_intf(struct dpu_hw_blk *hw) +{ + return container_of(hw, struct dpu_hw_intf, base); +} + +/** + * dpu_hw_intf_init(): Initializes the intf driver for the passed + * interface idx. + * @idx: interface index for which driver object is required + * @addr: mapped register io address of MDP + * @m : pointer to mdss catalog data + */ +struct dpu_hw_intf *dpu_hw_intf_init(enum dpu_intf idx, + void __iomem *addr, + struct dpu_mdss_cfg *m); + +/** + * dpu_hw_intf_destroy(): Destroys INTF driver context + * @intf: Pointer to INTF driver context + */ +void dpu_hw_intf_destroy(struct dpu_hw_intf *intf); + +#endif /*_DPU_HW_INTF_H */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c new file mode 100644 index 0000000000000..4ab72b0f07a5e --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c @@ -0,0 +1,261 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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 "dpu_kms.h" +#include "dpu_hw_catalog.h" +#include "dpu_hwio.h" +#include "dpu_hw_lm.h" +#include "dpu_hw_mdss.h" +#include "dpu_dbg.h" +#include "dpu_kms.h" + +#define LM_OP_MODE 0x00 +#define LM_OUT_SIZE 0x04 +#define LM_BORDER_COLOR_0 0x08 +#define LM_BORDER_COLOR_1 0x010 + +/* These register are offset to mixer base + stage base */ +#define LM_BLEND0_OP 0x00 +#define LM_BLEND0_CONST_ALPHA 0x04 +#define LM_FG_COLOR_FILL_COLOR_0 0x08 +#define LM_FG_COLOR_FILL_COLOR_1 0x0C +#define LM_FG_COLOR_FILL_SIZE 0x10 +#define LM_FG_COLOR_FILL_XY 0x14 + +#define LM_BLEND0_FG_ALPHA 0x04 +#define LM_BLEND0_BG_ALPHA 0x08 + +#define LM_MISR_CTRL 0x310 +#define LM_MISR_SIGNATURE 0x314 + +static struct dpu_lm_cfg *_lm_offset(enum dpu_lm mixer, + struct dpu_mdss_cfg *m, + void __iomem *addr, + struct dpu_hw_blk_reg_map *b) +{ + int i; + + for (i = 0; i < m->mixer_count; i++) { + if (mixer == m->mixer[i].id) { + b->base_off = addr; + b->blk_off = m->mixer[i].base; + b->length = m->mixer[i].len; + b->hwversion = m->hwversion; + b->log_mask = DPU_DBG_MASK_LM; + return &m->mixer[i]; + } + } + + return ERR_PTR(-ENOMEM); +} + +/** + * _stage_offset(): returns the relative offset of the blend registers + * for the stage to be setup + * @c: mixer ctx contains the mixer to be programmed + * @stage: stage index to setup + */ +static inline int _stage_offset(struct dpu_hw_mixer *ctx, enum dpu_stage stage) +{ + const struct dpu_lm_sub_blks *sblk = ctx->cap->sblk; + int rc; + + if (stage == DPU_STAGE_BASE) + rc = -EINVAL; + else if (stage <= sblk->maxblendstages) + rc = sblk->blendstage_base[stage - DPU_STAGE_0]; + else + rc = -EINVAL; + + return rc; +} + +static void dpu_hw_lm_setup_out(struct dpu_hw_mixer *ctx, + struct dpu_hw_mixer_cfg *mixer) +{ + struct dpu_hw_blk_reg_map *c = &ctx->hw; + u32 outsize; + u32 op_mode; + + op_mode = DPU_REG_READ(c, LM_OP_MODE); + + outsize = mixer->out_height << 16 | mixer->out_width; + DPU_REG_WRITE(c, LM_OUT_SIZE, outsize); + + /* SPLIT_LEFT_RIGHT */ + if (mixer->right_mixer) + op_mode |= BIT(31); + else + op_mode &= ~BIT(31); + DPU_REG_WRITE(c, LM_OP_MODE, op_mode); +} + +static void dpu_hw_lm_setup_border_color(struct dpu_hw_mixer *ctx, + struct dpu_mdss_color *color, + u8 border_en) +{ + struct dpu_hw_blk_reg_map *c = &ctx->hw; + + if (border_en) { + DPU_REG_WRITE(c, LM_BORDER_COLOR_0, + (color->color_0 & 0xFFF) | + ((color->color_1 & 0xFFF) << 0x10)); + DPU_REG_WRITE(c, LM_BORDER_COLOR_1, + (color->color_2 & 0xFFF) | + ((color->color_3 & 0xFFF) << 0x10)); + } +} + +static void dpu_hw_lm_setup_blend_config_sdm845(struct dpu_hw_mixer *ctx, + u32 stage, u32 fg_alpha, u32 bg_alpha, u32 blend_op) +{ + struct dpu_hw_blk_reg_map *c = &ctx->hw; + int stage_off; + u32 const_alpha; + + if (stage == DPU_STAGE_BASE) + return; + + stage_off = _stage_offset(ctx, stage); + if (WARN_ON(stage_off < 0)) + return; + + const_alpha = (bg_alpha & 0xFF) | ((fg_alpha & 0xFF) << 16); + DPU_REG_WRITE(c, LM_BLEND0_CONST_ALPHA + stage_off, const_alpha); + DPU_REG_WRITE(c, LM_BLEND0_OP + stage_off, blend_op); +} + +static void dpu_hw_lm_setup_blend_config(struct dpu_hw_mixer *ctx, + u32 stage, u32 fg_alpha, u32 bg_alpha, u32 blend_op) +{ + struct dpu_hw_blk_reg_map *c = &ctx->hw; + int stage_off; + + if (stage == DPU_STAGE_BASE) + return; + + stage_off = _stage_offset(ctx, stage); + if (WARN_ON(stage_off < 0)) + return; + + DPU_REG_WRITE(c, LM_BLEND0_FG_ALPHA + stage_off, fg_alpha); + DPU_REG_WRITE(c, LM_BLEND0_BG_ALPHA + stage_off, bg_alpha); + DPU_REG_WRITE(c, LM_BLEND0_OP + stage_off, blend_op); +} + +static void dpu_hw_lm_setup_color3(struct dpu_hw_mixer *ctx, + uint32_t mixer_op_mode) +{ + struct dpu_hw_blk_reg_map *c = &ctx->hw; + int op_mode; + + /* read the existing op_mode configuration */ + op_mode = DPU_REG_READ(c, LM_OP_MODE); + + op_mode = (op_mode & (BIT(31) | BIT(30))) | mixer_op_mode; + + DPU_REG_WRITE(c, LM_OP_MODE, op_mode); +} + +static void dpu_hw_lm_gc(struct dpu_hw_mixer *mixer, + void *cfg) +{ +} + +static void dpu_hw_lm_setup_misr(struct dpu_hw_mixer *ctx, + bool enable, u32 frame_count) +{ + struct dpu_hw_blk_reg_map *c = &ctx->hw; + u32 config = 0; + + DPU_REG_WRITE(c, LM_MISR_CTRL, MISR_CTRL_STATUS_CLEAR); + /* clear misr data */ + wmb(); + + if (enable) + config = (frame_count & MISR_FRAME_COUNT_MASK) | + MISR_CTRL_ENABLE | INTF_MISR_CTRL_FREE_RUN_MASK; + + DPU_REG_WRITE(c, LM_MISR_CTRL, config); +} + +static u32 dpu_hw_lm_collect_misr(struct dpu_hw_mixer *ctx) +{ + struct dpu_hw_blk_reg_map *c = &ctx->hw; + + return DPU_REG_READ(c, LM_MISR_SIGNATURE); +} + +static void _setup_mixer_ops(struct dpu_mdss_cfg *m, + struct dpu_hw_lm_ops *ops, + unsigned long features) +{ + ops->setup_mixer_out = dpu_hw_lm_setup_out; + if (IS_SDM845_TARGET(m->hwversion) || IS_SDM670_TARGET(m->hwversion)) + ops->setup_blend_config = dpu_hw_lm_setup_blend_config_sdm845; + else + ops->setup_blend_config = dpu_hw_lm_setup_blend_config; + ops->setup_alpha_out = dpu_hw_lm_setup_color3; + ops->setup_border_color = dpu_hw_lm_setup_border_color; + ops->setup_gc = dpu_hw_lm_gc; + ops->setup_misr = dpu_hw_lm_setup_misr; + ops->collect_misr = dpu_hw_lm_collect_misr; +}; + +static struct dpu_hw_blk_ops dpu_hw_ops = { + .start = NULL, + .stop = NULL, +}; + +struct dpu_hw_mixer *dpu_hw_lm_init(enum dpu_lm idx, + void __iomem *addr, + struct dpu_mdss_cfg *m) +{ + struct dpu_hw_mixer *c; + struct dpu_lm_cfg *cfg; + int rc; + + c = kzalloc(sizeof(*c), GFP_KERNEL); + if (!c) + return ERR_PTR(-ENOMEM); + + cfg = _lm_offset(idx, m, addr, &c->hw); + if (IS_ERR_OR_NULL(cfg)) { + kfree(c); + return ERR_PTR(-EINVAL); + } + + /* Assign ops */ + c->idx = idx; + c->cap = cfg; + _setup_mixer_ops(m, &c->ops, c->cap->features); + + rc = dpu_hw_blk_init(&c->base, DPU_HW_BLK_LM, idx, &dpu_hw_ops); + if (rc) { + DPU_ERROR("failed to init hw blk %d\n", rc); + goto blk_init_error; + } + + return c; + +blk_init_error: + kzfree(c); + + return ERR_PTR(rc); +} + +void dpu_hw_lm_destroy(struct dpu_hw_mixer *lm) +{ + if (lm) + dpu_hw_blk_destroy(&lm->base); + kfree(lm); +} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h new file mode 100644 index 0000000000000..e29e5dab31bff --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h @@ -0,0 +1,122 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef _DPU_HW_LM_H +#define _DPU_HW_LM_H + +#include "dpu_hw_mdss.h" +#include "dpu_hw_util.h" +#include "dpu_hw_blk.h" + +struct dpu_hw_mixer; + +struct dpu_hw_mixer_cfg { + u32 out_width; + u32 out_height; + bool right_mixer; + int flags; +}; + +struct dpu_hw_color3_cfg { + u8 keep_fg[DPU_STAGE_MAX]; +}; + +/** + * + * struct dpu_hw_lm_ops : Interface to the mixer Hw driver functions + * Assumption is these functions will be called after clocks are enabled + */ +struct dpu_hw_lm_ops { + /* + * Sets up mixer output width and height + * and border color if enabled + */ + void (*setup_mixer_out)(struct dpu_hw_mixer *ctx, + struct dpu_hw_mixer_cfg *cfg); + + /* + * Alpha blending configuration + * for the specified stage + */ + void (*setup_blend_config)(struct dpu_hw_mixer *ctx, uint32_t stage, + uint32_t fg_alpha, uint32_t bg_alpha, uint32_t blend_op); + + /* + * Alpha color component selection from either fg or bg + */ + void (*setup_alpha_out)(struct dpu_hw_mixer *ctx, uint32_t mixer_op); + + /** + * setup_border_color : enable/disable border color + */ + void (*setup_border_color)(struct dpu_hw_mixer *ctx, + struct dpu_mdss_color *color, + u8 border_en); + /** + * setup_gc : enable/disable gamma correction feature + */ + void (*setup_gc)(struct dpu_hw_mixer *mixer, + void *cfg); + + /* setup_misr: enables/disables MISR in HW register */ + void (*setup_misr)(struct dpu_hw_mixer *ctx, + bool enable, u32 frame_count); + + /* collect_misr: reads and stores MISR data from HW register */ + u32 (*collect_misr)(struct dpu_hw_mixer *ctx); +}; + +struct dpu_hw_mixer { + struct dpu_hw_blk base; + struct dpu_hw_blk_reg_map hw; + + /* lm */ + enum dpu_lm idx; + const struct dpu_lm_cfg *cap; + const struct dpu_mdp_cfg *mdp; + const struct dpu_ctl_cfg *ctl; + + /* ops */ + struct dpu_hw_lm_ops ops; + + /* store mixer info specific to display */ + struct dpu_hw_mixer_cfg cfg; +}; + +/** + * to_dpu_hw_mixer - convert base object dpu_hw_base to container + * @hw: Pointer to base hardware block + * return: Pointer to hardware block container + */ +static inline struct dpu_hw_mixer *to_dpu_hw_mixer(struct dpu_hw_blk *hw) +{ + return container_of(hw, struct dpu_hw_mixer, base); +} + +/** + * dpu_hw_lm_init(): Initializes the mixer hw driver object. + * should be called once before accessing every mixer. + * @idx: mixer index for which driver object is required + * @addr: mapped register io address of MDP + * @m : pointer to mdss catalog data + */ +struct dpu_hw_mixer *dpu_hw_lm_init(enum dpu_lm idx, + void __iomem *addr, + struct dpu_mdss_cfg *m); + +/** + * dpu_hw_lm_destroy(): Destroys layer mixer driver context + * @lm: Pointer to LM driver context + */ +void dpu_hw_lm_destroy(struct dpu_hw_mixer *lm); + +#endif /*_DPU_HW_LM_H */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h new file mode 100644 index 0000000000000..35e6bf930924e --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h @@ -0,0 +1,465 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef _DPU_HW_MDSS_H +#define _DPU_HW_MDSS_H + +#include <linux/kernel.h> +#include <linux/err.h> + +#include "msm_drv.h" + +#define DPU_DBG_NAME "dpu" + +#define DPU_NONE 0 + +#ifndef DPU_CSC_MATRIX_COEFF_SIZE +#define DPU_CSC_MATRIX_COEFF_SIZE 9 +#endif + +#ifndef DPU_CSC_CLAMP_SIZE +#define DPU_CSC_CLAMP_SIZE 6 +#endif + +#ifndef DPU_CSC_BIAS_SIZE +#define DPU_CSC_BIAS_SIZE 3 +#endif + +#ifndef DPU_MAX_PLANES +#define DPU_MAX_PLANES 4 +#endif + +#define PIPES_PER_STAGE 2 +#ifndef DPU_MAX_DE_CURVES +#define DPU_MAX_DE_CURVES 3 +#endif + +enum dpu_format_flags { + DPU_FORMAT_FLAG_YUV_BIT, + DPU_FORMAT_FLAG_DX_BIT, + DPU_FORMAT_FLAG_COMPRESSED_BIT, + DPU_FORMAT_FLAG_BIT_MAX, +}; + +#define DPU_FORMAT_FLAG_YUV BIT(DPU_FORMAT_FLAG_YUV_BIT) +#define DPU_FORMAT_FLAG_DX BIT(DPU_FORMAT_FLAG_DX_BIT) +#define DPU_FORMAT_FLAG_COMPRESSED BIT(DPU_FORMAT_FLAG_COMPRESSED_BIT) +#define DPU_FORMAT_IS_YUV(X) \ + (test_bit(DPU_FORMAT_FLAG_YUV_BIT, (X)->flag)) +#define DPU_FORMAT_IS_DX(X) \ + (test_bit(DPU_FORMAT_FLAG_DX_BIT, (X)->flag)) +#define DPU_FORMAT_IS_LINEAR(X) ((X)->fetch_mode == DPU_FETCH_LINEAR) +#define DPU_FORMAT_IS_TILE(X) \ + (((X)->fetch_mode == DPU_FETCH_UBWC) && \ + !test_bit(DPU_FORMAT_FLAG_COMPRESSED_BIT, (X)->flag)) +#define DPU_FORMAT_IS_UBWC(X) \ + (((X)->fetch_mode == DPU_FETCH_UBWC) && \ + test_bit(DPU_FORMAT_FLAG_COMPRESSED_BIT, (X)->flag)) + +#define DPU_BLEND_FG_ALPHA_FG_CONST (0 << 0) +#define DPU_BLEND_FG_ALPHA_BG_CONST (1 << 0) +#define DPU_BLEND_FG_ALPHA_FG_PIXEL (2 << 0) +#define DPU_BLEND_FG_ALPHA_BG_PIXEL (3 << 0) +#define DPU_BLEND_FG_INV_ALPHA (1 << 2) +#define DPU_BLEND_FG_MOD_ALPHA (1 << 3) +#define DPU_BLEND_FG_INV_MOD_ALPHA (1 << 4) +#define DPU_BLEND_FG_TRANSP_EN (1 << 5) +#define DPU_BLEND_BG_ALPHA_FG_CONST (0 << 8) +#define DPU_BLEND_BG_ALPHA_BG_CONST (1 << 8) +#define DPU_BLEND_BG_ALPHA_FG_PIXEL (2 << 8) +#define DPU_BLEND_BG_ALPHA_BG_PIXEL (3 << 8) +#define DPU_BLEND_BG_INV_ALPHA (1 << 10) +#define DPU_BLEND_BG_MOD_ALPHA (1 << 11) +#define DPU_BLEND_BG_INV_MOD_ALPHA (1 << 12) +#define DPU_BLEND_BG_TRANSP_EN (1 << 13) + +#define DPU_VSYNC0_SOURCE_GPIO 0 +#define DPU_VSYNC1_SOURCE_GPIO 1 +#define DPU_VSYNC2_SOURCE_GPIO 2 +#define DPU_VSYNC_SOURCE_INTF_0 3 +#define DPU_VSYNC_SOURCE_INTF_1 4 +#define DPU_VSYNC_SOURCE_INTF_2 5 +#define DPU_VSYNC_SOURCE_INTF_3 6 +#define DPU_VSYNC_SOURCE_WD_TIMER_4 11 +#define DPU_VSYNC_SOURCE_WD_TIMER_3 12 +#define DPU_VSYNC_SOURCE_WD_TIMER_2 13 +#define DPU_VSYNC_SOURCE_WD_TIMER_1 14 +#define DPU_VSYNC_SOURCE_WD_TIMER_0 15 + +enum dpu_hw_blk_type { + DPU_HW_BLK_TOP = 0, + DPU_HW_BLK_SSPP, + DPU_HW_BLK_LM, + DPU_HW_BLK_CTL, + DPU_HW_BLK_CDM, + DPU_HW_BLK_PINGPONG, + DPU_HW_BLK_INTF, + DPU_HW_BLK_WB, + DPU_HW_BLK_MAX, +}; + +enum dpu_mdp { + MDP_TOP = 0x1, + MDP_MAX, +}; + +enum dpu_sspp { + SSPP_NONE, + SSPP_VIG0, + SSPP_VIG1, + SSPP_VIG2, + SSPP_VIG3, + SSPP_RGB0, + SSPP_RGB1, + SSPP_RGB2, + SSPP_RGB3, + SSPP_DMA0, + SSPP_DMA1, + SSPP_DMA2, + SSPP_DMA3, + SSPP_CURSOR0, + SSPP_CURSOR1, + SSPP_MAX +}; + +enum dpu_sspp_type { + SSPP_TYPE_VIG, + SSPP_TYPE_RGB, + SSPP_TYPE_DMA, + SSPP_TYPE_CURSOR, + SSPP_TYPE_MAX +}; + +enum dpu_lm { + LM_0 = 1, + LM_1, + LM_2, + LM_3, + LM_4, + LM_5, + LM_6, + LM_MAX +}; + +enum dpu_stage { + DPU_STAGE_BASE = 0, + DPU_STAGE_0, + DPU_STAGE_1, + DPU_STAGE_2, + DPU_STAGE_3, + DPU_STAGE_4, + DPU_STAGE_5, + DPU_STAGE_6, + DPU_STAGE_7, + DPU_STAGE_8, + DPU_STAGE_9, + DPU_STAGE_10, + DPU_STAGE_MAX +}; +enum dpu_dspp { + DSPP_0 = 1, + DSPP_1, + DSPP_2, + DSPP_3, + DSPP_MAX +}; + +enum dpu_ds { + DS_TOP, + DS_0, + DS_1, + DS_MAX +}; + +enum dpu_ctl { + CTL_0 = 1, + CTL_1, + CTL_2, + CTL_3, + CTL_4, + CTL_MAX +}; + +enum dpu_cdm { + CDM_0 = 1, + CDM_1, + CDM_MAX +}; + +enum dpu_pingpong { + PINGPONG_0 = 1, + PINGPONG_1, + PINGPONG_2, + PINGPONG_3, + PINGPONG_4, + PINGPONG_S0, + PINGPONG_MAX +}; + +enum dpu_intf { + INTF_0 = 1, + INTF_1, + INTF_2, + INTF_3, + INTF_4, + INTF_5, + INTF_6, + INTF_MAX +}; + +enum dpu_intf_type { + INTF_NONE = 0x0, + INTF_DSI = 0x1, + INTF_HDMI = 0x3, + INTF_LCDC = 0x5, + INTF_EDP = 0x9, + INTF_DP = 0xa, + INTF_TYPE_MAX, + + /* virtual interfaces */ + INTF_WB = 0x100, +}; + +enum dpu_intf_mode { + INTF_MODE_NONE = 0, + INTF_MODE_CMD, + INTF_MODE_VIDEO, + INTF_MODE_WB_BLOCK, + INTF_MODE_WB_LINE, + INTF_MODE_MAX +}; + +enum dpu_wb { + WB_0 = 1, + WB_1, + WB_2, + WB_3, + WB_MAX +}; + +enum dpu_ad { + AD_0 = 0x1, + AD_1, + AD_MAX +}; + +enum dpu_cwb { + CWB_0 = 0x1, + CWB_1, + CWB_2, + CWB_3, + CWB_MAX +}; + +enum dpu_wd_timer { + WD_TIMER_0 = 0x1, + WD_TIMER_1, + WD_TIMER_2, + WD_TIMER_3, + WD_TIMER_4, + WD_TIMER_5, + WD_TIMER_MAX +}; + +enum dpu_vbif { + VBIF_0, + VBIF_1, + VBIF_MAX, + VBIF_RT = VBIF_0, + VBIF_NRT = VBIF_1 +}; + +enum dpu_iommu_domain { + DPU_IOMMU_DOMAIN_UNSECURE, + DPU_IOMMU_DOMAIN_SECURE, + DPU_IOMMU_DOMAIN_MAX +}; + +/** + * DPU HW,Component order color map + */ +enum { + C0_G_Y = 0, + C1_B_Cb = 1, + C2_R_Cr = 2, + C3_ALPHA = 3 +}; + +/** + * enum dpu_plane_type - defines how the color component pixel packing + * @DPU_PLANE_INTERLEAVED : Color components in single plane + * @DPU_PLANE_PLANAR : Color component in separate planes + * @DPU_PLANE_PSEUDO_PLANAR : Chroma components interleaved in separate plane + */ +enum dpu_plane_type { + DPU_PLANE_INTERLEAVED, + DPU_PLANE_PLANAR, + DPU_PLANE_PSEUDO_PLANAR, +}; + +/** + * enum dpu_chroma_samp_type - chroma sub-samplng type + * @DPU_CHROMA_RGB : No chroma subsampling + * @DPU_CHROMA_H2V1 : Chroma pixels are horizontally subsampled + * @DPU_CHROMA_H1V2 : Chroma pixels are vertically subsampled + * @DPU_CHROMA_420 : 420 subsampling + */ +enum dpu_chroma_samp_type { + DPU_CHROMA_RGB, + DPU_CHROMA_H2V1, + DPU_CHROMA_H1V2, + DPU_CHROMA_420 +}; + +/** + * dpu_fetch_type - Defines How DPU HW fetches data + * @DPU_FETCH_LINEAR : fetch is line by line + * @DPU_FETCH_TILE : fetches data in Z order from a tile + * @DPU_FETCH_UBWC : fetch and decompress data + */ +enum dpu_fetch_type { + DPU_FETCH_LINEAR, + DPU_FETCH_TILE, + DPU_FETCH_UBWC +}; + +/** + * Value of enum chosen to fit the number of bits + * expected by the HW programming. + */ +enum { + COLOR_ALPHA_1BIT = 0, + COLOR_ALPHA_4BIT = 1, + COLOR_4BIT = 0, + COLOR_5BIT = 1, /* No 5-bit Alpha */ + COLOR_6BIT = 2, /* 6-Bit Alpha also = 2 */ + COLOR_8BIT = 3, /* 8-Bit Alpha also = 3 */ +}; + +/** + * enum dpu_3d_blend_mode + * Desribes how the 3d data is blended + * @BLEND_3D_NONE : 3d blending not enabled + * @BLEND_3D_FRAME_INT : Frame interleaving + * @BLEND_3D_H_ROW_INT : Horizontal row interleaving + * @BLEND_3D_V_ROW_INT : vertical row interleaving + * @BLEND_3D_COL_INT : column interleaving + * @BLEND_3D_MAX : + */ +enum dpu_3d_blend_mode { + BLEND_3D_NONE = 0, + BLEND_3D_FRAME_INT, + BLEND_3D_H_ROW_INT, + BLEND_3D_V_ROW_INT, + BLEND_3D_COL_INT, + BLEND_3D_MAX +}; + +/** struct dpu_format - defines the format configuration which + * allows DPU HW to correctly fetch and decode the format + * @base: base msm_format struture containing fourcc code + * @fetch_planes: how the color components are packed in pixel format + * @element: element color ordering + * @bits: element bit widths + * @chroma_sample: chroma sub-samplng type + * @unpack_align_msb: unpack aligned, 0 to LSB, 1 to MSB + * @unpack_tight: 0 for loose, 1 for tight + * @unpack_count: 0 = 1 component, 1 = 2 component + * @bpp: bytes per pixel + * @alpha_enable: whether the format has an alpha channel + * @num_planes: number of planes (including meta data planes) + * @fetch_mode: linear, tiled, or ubwc hw fetch behavior + * @is_yuv: is format a yuv variant + * @flag: usage bit flags + * @tile_width: format tile width + * @tile_height: format tile height + */ +struct dpu_format { + struct msm_format base; + enum dpu_plane_type fetch_planes; + u8 element[DPU_MAX_PLANES]; + u8 bits[DPU_MAX_PLANES]; + enum dpu_chroma_samp_type chroma_sample; + u8 unpack_align_msb; + u8 unpack_tight; + u8 unpack_count; + u8 bpp; + u8 alpha_enable; + u8 num_planes; + enum dpu_fetch_type fetch_mode; + DECLARE_BITMAP(flag, DPU_FORMAT_FLAG_BIT_MAX); + u16 tile_width; + u16 tile_height; +}; +#define to_dpu_format(x) container_of(x, struct dpu_format, base) + +/** + * struct dpu_hw_fmt_layout - format information of the source pixel data + * @format: pixel format parameters + * @num_planes: number of planes (including meta data planes) + * @width: image width + * @height: image height + * @total_size: total size in bytes + * @plane_addr: address of each plane + * @plane_size: length of each plane + * @plane_pitch: pitch of each plane + */ +struct dpu_hw_fmt_layout { + const struct dpu_format *format; + uint32_t num_planes; + uint32_t width; + uint32_t height; + uint32_t total_size; + uint32_t plane_addr[DPU_MAX_PLANES]; + uint32_t plane_size[DPU_MAX_PLANES]; + uint32_t plane_pitch[DPU_MAX_PLANES]; +}; + +struct dpu_csc_cfg { + /* matrix coefficients in S15.16 format */ + uint32_t csc_mv[DPU_CSC_MATRIX_COEFF_SIZE]; + uint32_t csc_pre_bv[DPU_CSC_BIAS_SIZE]; + uint32_t csc_post_bv[DPU_CSC_BIAS_SIZE]; + uint32_t csc_pre_lv[DPU_CSC_CLAMP_SIZE]; + uint32_t csc_post_lv[DPU_CSC_CLAMP_SIZE]; +}; + +/** + * struct dpu_mdss_color - mdss color description + * color 0 : green + * color 1 : blue + * color 2 : red + * color 3 : alpha + */ +struct dpu_mdss_color { + u32 color_0; + u32 color_1; + u32 color_2; + u32 color_3; +}; + +/* + * Define bit masks for h/w logging. + */ +#define DPU_DBG_MASK_NONE (1 << 0) +#define DPU_DBG_MASK_CDM (1 << 1) +#define DPU_DBG_MASK_INTF (1 << 2) +#define DPU_DBG_MASK_LM (1 << 3) +#define DPU_DBG_MASK_CTL (1 << 4) +#define DPU_DBG_MASK_PINGPONG (1 << 5) +#define DPU_DBG_MASK_SSPP (1 << 6) +#define DPU_DBG_MASK_WB (1 << 7) +#define DPU_DBG_MASK_TOP (1 << 8) +#define DPU_DBG_MASK_VBIF (1 << 9) +#define DPU_DBG_MASK_ROT (1 << 10) + +#endif /* _DPU_HW_MDSS_H */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.c new file mode 100644 index 0000000000000..cc3a623903f4f --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.c @@ -0,0 +1,250 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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 <linux/iopoll.h> + +#include "dpu_hw_mdss.h" +#include "dpu_hwio.h" +#include "dpu_hw_catalog.h" +#include "dpu_hw_pingpong.h" +#include "dpu_dbg.h" +#include "dpu_kms.h" +#include "dpu_trace.h" + +#define PP_TEAR_CHECK_EN 0x000 +#define PP_SYNC_CONFIG_VSYNC 0x004 +#define PP_SYNC_CONFIG_HEIGHT 0x008 +#define PP_SYNC_WRCOUNT 0x00C +#define PP_VSYNC_INIT_VAL 0x010 +#define PP_INT_COUNT_VAL 0x014 +#define PP_SYNC_THRESH 0x018 +#define PP_START_POS 0x01C +#define PP_RD_PTR_IRQ 0x020 +#define PP_WR_PTR_IRQ 0x024 +#define PP_OUT_LINE_COUNT 0x028 +#define PP_LINE_COUNT 0x02C + +#define PP_FBC_MODE 0x034 +#define PP_FBC_BUDGET_CTL 0x038 +#define PP_FBC_LOSSY_MODE 0x03C + +static struct dpu_pingpong_cfg *_pingpong_offset(enum dpu_pingpong pp, + struct dpu_mdss_cfg *m, + void __iomem *addr, + struct dpu_hw_blk_reg_map *b) +{ + int i; + + for (i = 0; i < m->pingpong_count; i++) { + if (pp == m->pingpong[i].id) { + b->base_off = addr; + b->blk_off = m->pingpong[i].base; + b->length = m->pingpong[i].len; + b->hwversion = m->hwversion; + b->log_mask = DPU_DBG_MASK_PINGPONG; + return &m->pingpong[i]; + } + } + + return ERR_PTR(-EINVAL); +} + +static int dpu_hw_pp_setup_te_config(struct dpu_hw_pingpong *pp, + struct dpu_hw_tear_check *te) +{ + struct dpu_hw_blk_reg_map *c; + int cfg; + + if (!pp || !te) + return -EINVAL; + c = &pp->hw; + + cfg = BIT(19); /*VSYNC_COUNTER_EN */ + if (te->hw_vsync_mode) + cfg |= BIT(20); + + cfg |= te->vsync_count; + + DPU_REG_WRITE(c, PP_SYNC_CONFIG_VSYNC, cfg); + DPU_REG_WRITE(c, PP_SYNC_CONFIG_HEIGHT, te->sync_cfg_height); + DPU_REG_WRITE(c, PP_VSYNC_INIT_VAL, te->vsync_init_val); + DPU_REG_WRITE(c, PP_RD_PTR_IRQ, te->rd_ptr_irq); + DPU_REG_WRITE(c, PP_START_POS, te->start_pos); + DPU_REG_WRITE(c, PP_SYNC_THRESH, + ((te->sync_threshold_continue << 16) | + te->sync_threshold_start)); + DPU_REG_WRITE(c, PP_SYNC_WRCOUNT, + (te->start_pos + te->sync_threshold_start + 1)); + + return 0; +} + +static int dpu_hw_pp_poll_timeout_wr_ptr(struct dpu_hw_pingpong *pp, + u32 timeout_us) +{ + struct dpu_hw_blk_reg_map *c; + u32 val; + int rc; + + if (!pp) + return -EINVAL; + + c = &pp->hw; + rc = readl_poll_timeout(c->base_off + c->blk_off + PP_LINE_COUNT, + val, (val & 0xffff) >= 1, 10, timeout_us); + + return rc; +} + +static int dpu_hw_pp_enable_te(struct dpu_hw_pingpong *pp, bool enable) +{ + struct dpu_hw_blk_reg_map *c; + + if (!pp) + return -EINVAL; + c = &pp->hw; + + DPU_REG_WRITE(c, PP_TEAR_CHECK_EN, enable); + return 0; +} + +static int dpu_hw_pp_connect_external_te(struct dpu_hw_pingpong *pp, + bool enable_external_te) +{ + struct dpu_hw_blk_reg_map *c = &pp->hw; + u32 cfg; + int orig; + + if (!pp) + return -EINVAL; + + c = &pp->hw; + cfg = DPU_REG_READ(c, PP_SYNC_CONFIG_VSYNC); + orig = (bool)(cfg & BIT(20)); + if (enable_external_te) + cfg |= BIT(20); + else + cfg &= ~BIT(20); + DPU_REG_WRITE(c, PP_SYNC_CONFIG_VSYNC, cfg); + trace_dpu_pp_connect_ext_te(pp->idx - PINGPONG_0, cfg); + + return orig; +} + +static int dpu_hw_pp_get_vsync_info(struct dpu_hw_pingpong *pp, + struct dpu_hw_pp_vsync_info *info) +{ + struct dpu_hw_blk_reg_map *c; + u32 val; + + if (!pp || !info) + return -EINVAL; + c = &pp->hw; + + val = DPU_REG_READ(c, PP_VSYNC_INIT_VAL); + info->rd_ptr_init_val = val & 0xffff; + + val = DPU_REG_READ(c, PP_INT_COUNT_VAL); + info->rd_ptr_frame_count = (val & 0xffff0000) >> 16; + info->rd_ptr_line_count = val & 0xffff; + + val = DPU_REG_READ(c, PP_LINE_COUNT); + info->wr_ptr_line_count = val & 0xffff; + + return 0; +} + +static u32 dpu_hw_pp_get_line_count(struct dpu_hw_pingpong *pp) +{ + struct dpu_hw_blk_reg_map *c = &pp->hw; + u32 height, init; + u32 line = 0xFFFF; + + if (!pp) + return 0; + c = &pp->hw; + + init = DPU_REG_READ(c, PP_VSYNC_INIT_VAL) & 0xFFFF; + height = DPU_REG_READ(c, PP_SYNC_CONFIG_HEIGHT) & 0xFFFF; + + if (height < init) + goto line_count_exit; + + line = DPU_REG_READ(c, PP_INT_COUNT_VAL) & 0xFFFF; + + if (line < init) + line += (0xFFFF - init); + else + line -= init; + +line_count_exit: + return line; +} + +static void _setup_pingpong_ops(struct dpu_hw_pingpong_ops *ops, + const struct dpu_pingpong_cfg *hw_cap) +{ + ops->setup_tearcheck = dpu_hw_pp_setup_te_config; + ops->enable_tearcheck = dpu_hw_pp_enable_te; + ops->connect_external_te = dpu_hw_pp_connect_external_te; + ops->get_vsync_info = dpu_hw_pp_get_vsync_info; + ops->poll_timeout_wr_ptr = dpu_hw_pp_poll_timeout_wr_ptr; + ops->get_line_count = dpu_hw_pp_get_line_count; +}; + +static struct dpu_hw_blk_ops dpu_hw_ops = { + .start = NULL, + .stop = NULL, +}; + +struct dpu_hw_pingpong *dpu_hw_pingpong_init(enum dpu_pingpong idx, + void __iomem *addr, + struct dpu_mdss_cfg *m) +{ + struct dpu_hw_pingpong *c; + struct dpu_pingpong_cfg *cfg; + int rc; + + c = kzalloc(sizeof(*c), GFP_KERNEL); + if (!c) + return ERR_PTR(-ENOMEM); + + cfg = _pingpong_offset(idx, m, addr, &c->hw); + if (IS_ERR_OR_NULL(cfg)) { + kfree(c); + return ERR_PTR(-EINVAL); + } + + c->idx = idx; + c->caps = cfg; + _setup_pingpong_ops(&c->ops, c->caps); + + rc = dpu_hw_blk_init(&c->base, DPU_HW_BLK_PINGPONG, idx, &dpu_hw_ops); + if (rc) { + DPU_ERROR("failed to init hw blk %d\n", rc); + goto blk_init_error; + } + + return c; + +blk_init_error: + kzfree(c); + + return ERR_PTR(rc); +} + +void dpu_hw_pingpong_destroy(struct dpu_hw_pingpong *pp) +{ + if (pp) + dpu_hw_blk_destroy(&pp->base); + kfree(pp); +} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h new file mode 100644 index 0000000000000..3caccd7d6a3e1 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h @@ -0,0 +1,136 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef _DPU_HW_PINGPONG_H +#define _DPU_HW_PINGPONG_H + +#include "dpu_hw_catalog.h" +#include "dpu_hw_mdss.h" +#include "dpu_hw_util.h" +#include "dpu_hw_blk.h" + +struct dpu_hw_pingpong; + +struct dpu_hw_tear_check { + /* + * This is ratio of MDP VSYNC clk freq(Hz) to + * refresh rate divided by no of lines + */ + u32 vsync_count; + u32 sync_cfg_height; + u32 vsync_init_val; + u32 sync_threshold_start; + u32 sync_threshold_continue; + u32 start_pos; + u32 rd_ptr_irq; + u8 hw_vsync_mode; +}; + +struct dpu_hw_pp_vsync_info { + u32 rd_ptr_init_val; /* value of rd pointer at vsync edge */ + u32 rd_ptr_frame_count; /* num frames sent since enabling interface */ + u32 rd_ptr_line_count; /* current line on panel (rd ptr) */ + u32 wr_ptr_line_count; /* current line within pp fifo (wr ptr) */ +}; + +/** + * + * struct dpu_hw_pingpong_ops : Interface to the pingpong Hw driver functions + * Assumption is these functions will be called after clocks are enabled + * @setup_tearcheck : program tear check values + * @enable_tearcheck : enables tear check + * @get_vsync_info : retries timing info of the panel + * @setup_dither : function to program the dither hw block + * @get_line_count: obtain current vertical line counter + */ +struct dpu_hw_pingpong_ops { + /** + * enables vysnc generation and sets up init value of + * read pointer and programs the tear check cofiguration + */ + int (*setup_tearcheck)(struct dpu_hw_pingpong *pp, + struct dpu_hw_tear_check *cfg); + + /** + * enables tear check block + */ + int (*enable_tearcheck)(struct dpu_hw_pingpong *pp, + bool enable); + + /** + * read, modify, write to either set or clear listening to external TE + * @Return: 1 if TE was originally connected, 0 if not, or -ERROR + */ + int (*connect_external_te)(struct dpu_hw_pingpong *pp, + bool enable_external_te); + + /** + * provides the programmed and current + * line_count + */ + int (*get_vsync_info)(struct dpu_hw_pingpong *pp, + struct dpu_hw_pp_vsync_info *info); + + /** + * poll until write pointer transmission starts + * @Return: 0 on success, -ETIMEDOUT on timeout + */ + int (*poll_timeout_wr_ptr)(struct dpu_hw_pingpong *pp, u32 timeout_us); + + /** + * Obtain current vertical line counter + */ + u32 (*get_line_count)(struct dpu_hw_pingpong *pp); +}; + +struct dpu_hw_pingpong { + struct dpu_hw_blk base; + struct dpu_hw_blk_reg_map hw; + + /* pingpong */ + enum dpu_pingpong idx; + const struct dpu_pingpong_cfg *caps; + + /* ops */ + struct dpu_hw_pingpong_ops ops; +}; + +/** + * dpu_hw_pingpong - convert base object dpu_hw_base to container + * @hw: Pointer to base hardware block + * return: Pointer to hardware block container + */ +static inline struct dpu_hw_pingpong *to_dpu_hw_pingpong(struct dpu_hw_blk *hw) +{ + return container_of(hw, struct dpu_hw_pingpong, base); +} + +/** + * dpu_hw_pingpong_init - initializes the pingpong driver for the passed + * pingpong idx. + * @idx: Pingpong index for which driver object is required + * @addr: Mapped register io address of MDP + * @m: Pointer to mdss catalog data + * Returns: Error code or allocated dpu_hw_pingpong context + */ +struct dpu_hw_pingpong *dpu_hw_pingpong_init(enum dpu_pingpong idx, + void __iomem *addr, + struct dpu_mdss_cfg *m); + +/** + * dpu_hw_pingpong_destroy - destroys pingpong driver context + * should be called to free the context + * @pp: Pointer to PP driver context returned by dpu_hw_pingpong_init + */ +void dpu_hw_pingpong_destroy(struct dpu_hw_pingpong *pp); + +#endif /*_DPU_HW_PINGPONG_H */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c new file mode 100644 index 0000000000000..c25b52a6b2198 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c @@ -0,0 +1,753 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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 "dpu_hwio.h" +#include "dpu_hw_catalog.h" +#include "dpu_hw_lm.h" +#include "dpu_hw_sspp.h" +#include "dpu_dbg.h" +#include "dpu_kms.h" + +#define DPU_FETCH_CONFIG_RESET_VALUE 0x00000087 + +/* DPU_SSPP_SRC */ +#define SSPP_SRC_SIZE 0x00 +#define SSPP_SRC_XY 0x08 +#define SSPP_OUT_SIZE 0x0c +#define SSPP_OUT_XY 0x10 +#define SSPP_SRC0_ADDR 0x14 +#define SSPP_SRC1_ADDR 0x18 +#define SSPP_SRC2_ADDR 0x1C +#define SSPP_SRC3_ADDR 0x20 +#define SSPP_SRC_YSTRIDE0 0x24 +#define SSPP_SRC_YSTRIDE1 0x28 +#define SSPP_SRC_FORMAT 0x30 +#define SSPP_SRC_UNPACK_PATTERN 0x34 +#define SSPP_SRC_OP_MODE 0x38 + +/* SSPP_MULTIRECT*/ +#define SSPP_SRC_SIZE_REC1 0x16C +#define SSPP_SRC_XY_REC1 0x168 +#define SSPP_OUT_SIZE_REC1 0x160 +#define SSPP_OUT_XY_REC1 0x164 +#define SSPP_SRC_FORMAT_REC1 0x174 +#define SSPP_SRC_UNPACK_PATTERN_REC1 0x178 +#define SSPP_SRC_OP_MODE_REC1 0x17C +#define SSPP_MULTIRECT_OPMODE 0x170 +#define SSPP_SRC_CONSTANT_COLOR_REC1 0x180 +#define SSPP_EXCL_REC_SIZE_REC1 0x184 +#define SSPP_EXCL_REC_XY_REC1 0x188 + +#define MDSS_MDP_OP_DEINTERLACE BIT(22) +#define MDSS_MDP_OP_DEINTERLACE_ODD BIT(23) +#define MDSS_MDP_OP_IGC_ROM_1 BIT(18) +#define MDSS_MDP_OP_IGC_ROM_0 BIT(17) +#define MDSS_MDP_OP_IGC_EN BIT(16) +#define MDSS_MDP_OP_FLIP_UD BIT(14) +#define MDSS_MDP_OP_FLIP_LR BIT(13) +#define MDSS_MDP_OP_BWC_EN BIT(0) +#define MDSS_MDP_OP_PE_OVERRIDE BIT(31) +#define MDSS_MDP_OP_BWC_LOSSLESS (0 << 1) +#define MDSS_MDP_OP_BWC_Q_HIGH (1 << 1) +#define MDSS_MDP_OP_BWC_Q_MED (2 << 1) + +#define SSPP_SRC_CONSTANT_COLOR 0x3c +#define SSPP_EXCL_REC_CTL 0x40 +#define SSPP_UBWC_STATIC_CTRL 0x44 +#define SSPP_FETCH_CONFIG 0x048 +#define SSPP_DANGER_LUT 0x60 +#define SSPP_SAFE_LUT 0x64 +#define SSPP_CREQ_LUT 0x68 +#define SSPP_QOS_CTRL 0x6C +#define SSPP_DECIMATION_CONFIG 0xB4 +#define SSPP_SRC_ADDR_SW_STATUS 0x70 +#define SSPP_CREQ_LUT_0 0x74 +#define SSPP_CREQ_LUT_1 0x78 +#define SSPP_SW_PIX_EXT_C0_LR 0x100 +#define SSPP_SW_PIX_EXT_C0_TB 0x104 +#define SSPP_SW_PIX_EXT_C0_REQ_PIXELS 0x108 +#define SSPP_SW_PIX_EXT_C1C2_LR 0x110 +#define SSPP_SW_PIX_EXT_C1C2_TB 0x114 +#define SSPP_SW_PIX_EXT_C1C2_REQ_PIXELS 0x118 +#define SSPP_SW_PIX_EXT_C3_LR 0x120 +#define SSPP_SW_PIX_EXT_C3_TB 0x124 +#define SSPP_SW_PIX_EXT_C3_REQ_PIXELS 0x128 +#define SSPP_TRAFFIC_SHAPER 0x130 +#define SSPP_CDP_CNTL 0x134 +#define SSPP_UBWC_ERROR_STATUS 0x138 +#define SSPP_TRAFFIC_SHAPER_PREFILL 0x150 +#define SSPP_TRAFFIC_SHAPER_REC1_PREFILL 0x154 +#define SSPP_TRAFFIC_SHAPER_REC1 0x158 +#define SSPP_EXCL_REC_SIZE 0x1B4 +#define SSPP_EXCL_REC_XY 0x1B8 +#define SSPP_VIG_OP_MODE 0x0 +#define SSPP_VIG_CSC_10_OP_MODE 0x0 +#define SSPP_TRAFFIC_SHAPER_BPC_MAX 0xFF + +/* SSPP_QOS_CTRL */ +#define SSPP_QOS_CTRL_VBLANK_EN BIT(16) +#define SSPP_QOS_CTRL_DANGER_SAFE_EN BIT(0) +#define SSPP_QOS_CTRL_DANGER_VBLANK_MASK 0x3 +#define SSPP_QOS_CTRL_DANGER_VBLANK_OFF 4 +#define SSPP_QOS_CTRL_CREQ_VBLANK_MASK 0x3 +#define SSPP_QOS_CTRL_CREQ_VBLANK_OFF 20 + +/* DPU_SSPP_SCALER_QSEED2 */ +#define SCALE_CONFIG 0x04 +#define COMP0_3_PHASE_STEP_X 0x10 +#define COMP0_3_PHASE_STEP_Y 0x14 +#define COMP1_2_PHASE_STEP_X 0x18 +#define COMP1_2_PHASE_STEP_Y 0x1c +#define COMP0_3_INIT_PHASE_X 0x20 +#define COMP0_3_INIT_PHASE_Y 0x24 +#define COMP1_2_INIT_PHASE_X 0x28 +#define COMP1_2_INIT_PHASE_Y 0x2C +#define VIG_0_QSEED2_SHARP 0x30 + +/* + * Definitions for ViG op modes + */ +#define VIG_OP_CSC_DST_DATAFMT BIT(19) +#define VIG_OP_CSC_SRC_DATAFMT BIT(18) +#define VIG_OP_CSC_EN BIT(17) +#define VIG_OP_MEM_PROT_CONT BIT(15) +#define VIG_OP_MEM_PROT_VAL BIT(14) +#define VIG_OP_MEM_PROT_SAT BIT(13) +#define VIG_OP_MEM_PROT_HUE BIT(12) +#define VIG_OP_HIST BIT(8) +#define VIG_OP_SKY_COL BIT(7) +#define VIG_OP_FOIL BIT(6) +#define VIG_OP_SKIN_COL BIT(5) +#define VIG_OP_PA_EN BIT(4) +#define VIG_OP_PA_SAT_ZERO_EXP BIT(2) +#define VIG_OP_MEM_PROT_BLEND BIT(1) + +/* + * Definitions for CSC 10 op modes + */ +#define VIG_CSC_10_SRC_DATAFMT BIT(1) +#define VIG_CSC_10_EN BIT(0) +#define CSC_10BIT_OFFSET 4 + +/* traffic shaper clock in Hz */ +#define TS_CLK 19200000 + +static inline int _sspp_subblk_offset(struct dpu_hw_pipe *ctx, + int s_id, + u32 *idx) +{ + int rc = 0; + const struct dpu_sspp_sub_blks *sblk = ctx->cap->sblk; + + if (!ctx) + return -EINVAL; + + switch (s_id) { + case DPU_SSPP_SRC: + *idx = sblk->src_blk.base; + break; + case DPU_SSPP_SCALER_QSEED2: + case DPU_SSPP_SCALER_QSEED3: + case DPU_SSPP_SCALER_RGB: + *idx = sblk->scaler_blk.base; + break; + case DPU_SSPP_CSC: + case DPU_SSPP_CSC_10BIT: + *idx = sblk->csc_blk.base; + break; + default: + rc = -EINVAL; + } + + return rc; +} + +static void dpu_hw_sspp_setup_multirect(struct dpu_hw_pipe *ctx, + enum dpu_sspp_multirect_index index, + enum dpu_sspp_multirect_mode mode) +{ + u32 mode_mask; + u32 idx; + + if (_sspp_subblk_offset(ctx, DPU_SSPP_SRC, &idx)) + return; + + if (index == DPU_SSPP_RECT_SOLO) { + /** + * if rect index is RECT_SOLO, we cannot expect a + * virtual plane sharing the same SSPP id. So we go + * and disable multirect + */ + mode_mask = 0; + } else { + mode_mask = DPU_REG_READ(&ctx->hw, SSPP_MULTIRECT_OPMODE + idx); + mode_mask |= index; + if (mode == DPU_SSPP_MULTIRECT_TIME_MX) + mode_mask |= BIT(2); + else + mode_mask &= ~BIT(2); + } + + DPU_REG_WRITE(&ctx->hw, SSPP_MULTIRECT_OPMODE + idx, mode_mask); +} + +static void _sspp_setup_opmode(struct dpu_hw_pipe *ctx, + u32 mask, u8 en) +{ + u32 idx; + u32 opmode; + + if (!test_bit(DPU_SSPP_SCALER_QSEED2, &ctx->cap->features) || + _sspp_subblk_offset(ctx, DPU_SSPP_SCALER_QSEED2, &idx) || + !test_bit(DPU_SSPP_CSC, &ctx->cap->features)) + return; + + opmode = DPU_REG_READ(&ctx->hw, SSPP_VIG_OP_MODE + idx); + + if (en) + opmode |= mask; + else + opmode &= ~mask; + + DPU_REG_WRITE(&ctx->hw, SSPP_VIG_OP_MODE + idx, opmode); +} + +static void _sspp_setup_csc10_opmode(struct dpu_hw_pipe *ctx, + u32 mask, u8 en) +{ + u32 idx; + u32 opmode; + + if (_sspp_subblk_offset(ctx, DPU_SSPP_CSC_10BIT, &idx)) + return; + + opmode = DPU_REG_READ(&ctx->hw, SSPP_VIG_CSC_10_OP_MODE + idx); + if (en) + opmode |= mask; + else + opmode &= ~mask; + + DPU_REG_WRITE(&ctx->hw, SSPP_VIG_CSC_10_OP_MODE + idx, opmode); +} + +/** + * Setup source pixel format, flip, + */ +static void dpu_hw_sspp_setup_format(struct dpu_hw_pipe *ctx, + const struct dpu_format *fmt, u32 flags, + enum dpu_sspp_multirect_index rect_mode) +{ + struct dpu_hw_blk_reg_map *c; + u32 chroma_samp, unpack, src_format; + u32 opmode = 0; + u32 fast_clear = 0; + u32 op_mode_off, unpack_pat_off, format_off; + u32 idx; + + if (_sspp_subblk_offset(ctx, DPU_SSPP_SRC, &idx) || !fmt) + return; + + if (rect_mode == DPU_SSPP_RECT_SOLO || rect_mode == DPU_SSPP_RECT_0) { + op_mode_off = SSPP_SRC_OP_MODE; + unpack_pat_off = SSPP_SRC_UNPACK_PATTERN; + format_off = SSPP_SRC_FORMAT; + } else { + op_mode_off = SSPP_SRC_OP_MODE_REC1; + unpack_pat_off = SSPP_SRC_UNPACK_PATTERN_REC1; + format_off = SSPP_SRC_FORMAT_REC1; + } + + c = &ctx->hw; + opmode = DPU_REG_READ(c, op_mode_off + idx); + opmode &= ~(MDSS_MDP_OP_FLIP_LR | MDSS_MDP_OP_FLIP_UD | + MDSS_MDP_OP_BWC_EN | MDSS_MDP_OP_PE_OVERRIDE); + + if (flags & DPU_SSPP_FLIP_LR) + opmode |= MDSS_MDP_OP_FLIP_LR; + if (flags & DPU_SSPP_FLIP_UD) + opmode |= MDSS_MDP_OP_FLIP_UD; + + chroma_samp = fmt->chroma_sample; + if (flags & DPU_SSPP_SOURCE_ROTATED_90) { + if (chroma_samp == DPU_CHROMA_H2V1) + chroma_samp = DPU_CHROMA_H1V2; + else if (chroma_samp == DPU_CHROMA_H1V2) + chroma_samp = DPU_CHROMA_H2V1; + } + + src_format = (chroma_samp << 23) | (fmt->fetch_planes << 19) | + (fmt->bits[C3_ALPHA] << 6) | (fmt->bits[C2_R_Cr] << 4) | + (fmt->bits[C1_B_Cb] << 2) | (fmt->bits[C0_G_Y] << 0); + + if (flags & DPU_SSPP_ROT_90) + src_format |= BIT(11); /* ROT90 */ + + if (fmt->alpha_enable && fmt->fetch_planes == DPU_PLANE_INTERLEAVED) + src_format |= BIT(8); /* SRCC3_EN */ + + if (flags & DPU_SSPP_SOLID_FILL) + src_format |= BIT(22); + + unpack = (fmt->element[3] << 24) | (fmt->element[2] << 16) | + (fmt->element[1] << 8) | (fmt->element[0] << 0); + src_format |= ((fmt->unpack_count - 1) << 12) | + (fmt->unpack_tight << 17) | + (fmt->unpack_align_msb << 18) | + ((fmt->bpp - 1) << 9); + + if (fmt->fetch_mode != DPU_FETCH_LINEAR) { + if (DPU_FORMAT_IS_UBWC(fmt)) + opmode |= MDSS_MDP_OP_BWC_EN; + src_format |= (fmt->fetch_mode & 3) << 30; /*FRAME_FORMAT */ + DPU_REG_WRITE(c, SSPP_FETCH_CONFIG, + DPU_FETCH_CONFIG_RESET_VALUE | + ctx->mdp->highest_bank_bit << 18); + if (IS_UBWC_20_SUPPORTED(ctx->catalog->caps->ubwc_version)) { + fast_clear = fmt->alpha_enable ? BIT(31) : 0; + DPU_REG_WRITE(c, SSPP_UBWC_STATIC_CTRL, + fast_clear | (ctx->mdp->ubwc_swizzle) | + (ctx->mdp->highest_bank_bit << 4)); + } + } + + opmode |= MDSS_MDP_OP_PE_OVERRIDE; + + /* if this is YUV pixel format, enable CSC */ + if (DPU_FORMAT_IS_YUV(fmt)) + src_format |= BIT(15); + + if (DPU_FORMAT_IS_DX(fmt)) + src_format |= BIT(14); + + /* update scaler opmode, if appropriate */ + if (test_bit(DPU_SSPP_CSC, &ctx->cap->features)) + _sspp_setup_opmode(ctx, VIG_OP_CSC_EN | VIG_OP_CSC_SRC_DATAFMT, + DPU_FORMAT_IS_YUV(fmt)); + else if (test_bit(DPU_SSPP_CSC_10BIT, &ctx->cap->features)) + _sspp_setup_csc10_opmode(ctx, + VIG_CSC_10_EN | VIG_CSC_10_SRC_DATAFMT, + DPU_FORMAT_IS_YUV(fmt)); + + DPU_REG_WRITE(c, format_off + idx, src_format); + DPU_REG_WRITE(c, unpack_pat_off + idx, unpack); + DPU_REG_WRITE(c, op_mode_off + idx, opmode); + + /* clear previous UBWC error */ + DPU_REG_WRITE(c, SSPP_UBWC_ERROR_STATUS + idx, BIT(31)); +} + +static void dpu_hw_sspp_setup_pe_config(struct dpu_hw_pipe *ctx, + struct dpu_hw_pixel_ext *pe_ext) +{ + struct dpu_hw_blk_reg_map *c; + u8 color; + u32 lr_pe[4], tb_pe[4], tot_req_pixels[4]; + const u32 bytemask = 0xff; + const u32 shortmask = 0xffff; + u32 idx; + + if (_sspp_subblk_offset(ctx, DPU_SSPP_SRC, &idx) || !pe_ext) + return; + + c = &ctx->hw; + + /* program SW pixel extension override for all pipes*/ + for (color = 0; color < DPU_MAX_PLANES; color++) { + /* color 2 has the same set of registers as color 1 */ + if (color == 2) + continue; + + lr_pe[color] = ((pe_ext->right_ftch[color] & bytemask) << 24)| + ((pe_ext->right_rpt[color] & bytemask) << 16)| + ((pe_ext->left_ftch[color] & bytemask) << 8)| + (pe_ext->left_rpt[color] & bytemask); + + tb_pe[color] = ((pe_ext->btm_ftch[color] & bytemask) << 24)| + ((pe_ext->btm_rpt[color] & bytemask) << 16)| + ((pe_ext->top_ftch[color] & bytemask) << 8)| + (pe_ext->top_rpt[color] & bytemask); + + tot_req_pixels[color] = (((pe_ext->roi_h[color] + + pe_ext->num_ext_pxls_top[color] + + pe_ext->num_ext_pxls_btm[color]) & shortmask) << 16) | + ((pe_ext->roi_w[color] + + pe_ext->num_ext_pxls_left[color] + + pe_ext->num_ext_pxls_right[color]) & shortmask); + } + + /* color 0 */ + DPU_REG_WRITE(c, SSPP_SW_PIX_EXT_C0_LR + idx, lr_pe[0]); + DPU_REG_WRITE(c, SSPP_SW_PIX_EXT_C0_TB + idx, tb_pe[0]); + DPU_REG_WRITE(c, SSPP_SW_PIX_EXT_C0_REQ_PIXELS + idx, + tot_req_pixels[0]); + + /* color 1 and color 2 */ + DPU_REG_WRITE(c, SSPP_SW_PIX_EXT_C1C2_LR + idx, lr_pe[1]); + DPU_REG_WRITE(c, SSPP_SW_PIX_EXT_C1C2_TB + idx, tb_pe[1]); + DPU_REG_WRITE(c, SSPP_SW_PIX_EXT_C1C2_REQ_PIXELS + idx, + tot_req_pixels[1]); + + /* color 3 */ + DPU_REG_WRITE(c, SSPP_SW_PIX_EXT_C3_LR + idx, lr_pe[3]); + DPU_REG_WRITE(c, SSPP_SW_PIX_EXT_C3_TB + idx, lr_pe[3]); + DPU_REG_WRITE(c, SSPP_SW_PIX_EXT_C3_REQ_PIXELS + idx, + tot_req_pixels[3]); +} + +static void _dpu_hw_sspp_setup_scaler3(struct dpu_hw_pipe *ctx, + struct dpu_hw_pipe_cfg *sspp, + struct dpu_hw_pixel_ext *pe, + void *scaler_cfg) +{ + u32 idx; + struct dpu_hw_scaler3_cfg *scaler3_cfg = scaler_cfg; + + (void)pe; + if (_sspp_subblk_offset(ctx, DPU_SSPP_SCALER_QSEED3, &idx) || !sspp + || !scaler3_cfg || !ctx || !ctx->cap || !ctx->cap->sblk) + return; + + dpu_hw_setup_scaler3(&ctx->hw, scaler3_cfg, idx, + ctx->cap->sblk->scaler_blk.version, + sspp->layout.format); +} + +static u32 _dpu_hw_sspp_get_scaler3_ver(struct dpu_hw_pipe *ctx) +{ + u32 idx; + + if (!ctx || _sspp_subblk_offset(ctx, DPU_SSPP_SCALER_QSEED3, &idx)) + return 0; + + return dpu_hw_get_scaler3_ver(&ctx->hw, idx); +} + +/** + * dpu_hw_sspp_setup_rects() + */ +static void dpu_hw_sspp_setup_rects(struct dpu_hw_pipe *ctx, + struct dpu_hw_pipe_cfg *cfg, + enum dpu_sspp_multirect_index rect_index) +{ + struct dpu_hw_blk_reg_map *c; + u32 src_size, src_xy, dst_size, dst_xy, ystride0, ystride1; + u32 src_size_off, src_xy_off, out_size_off, out_xy_off; + u32 idx; + + if (_sspp_subblk_offset(ctx, DPU_SSPP_SRC, &idx) || !cfg) + return; + + c = &ctx->hw; + + if (rect_index == DPU_SSPP_RECT_SOLO || rect_index == DPU_SSPP_RECT_0) { + src_size_off = SSPP_SRC_SIZE; + src_xy_off = SSPP_SRC_XY; + out_size_off = SSPP_OUT_SIZE; + out_xy_off = SSPP_OUT_XY; + } else { + src_size_off = SSPP_SRC_SIZE_REC1; + src_xy_off = SSPP_SRC_XY_REC1; + out_size_off = SSPP_OUT_SIZE_REC1; + out_xy_off = SSPP_OUT_XY_REC1; + } + + + /* src and dest rect programming */ + src_xy = (cfg->src_rect.y1 << 16) | cfg->src_rect.x1; + src_size = (drm_rect_height(&cfg->src_rect) << 16) | + drm_rect_width(&cfg->src_rect); + dst_xy = (cfg->dst_rect.y1 << 16) | cfg->dst_rect.x1; + dst_size = (drm_rect_height(&cfg->dst_rect) << 16) | + drm_rect_width(&cfg->dst_rect); + + if (rect_index == DPU_SSPP_RECT_SOLO) { + ystride0 = (cfg->layout.plane_pitch[0]) | + (cfg->layout.plane_pitch[1] << 16); + ystride1 = (cfg->layout.plane_pitch[2]) | + (cfg->layout.plane_pitch[3] << 16); + } else { + ystride0 = DPU_REG_READ(c, SSPP_SRC_YSTRIDE0 + idx); + ystride1 = DPU_REG_READ(c, SSPP_SRC_YSTRIDE1 + idx); + + if (rect_index == DPU_SSPP_RECT_0) { + ystride0 = (ystride0 & 0xFFFF0000) | + (cfg->layout.plane_pitch[0] & 0x0000FFFF); + ystride1 = (ystride1 & 0xFFFF0000)| + (cfg->layout.plane_pitch[2] & 0x0000FFFF); + } else { + ystride0 = (ystride0 & 0x0000FFFF) | + ((cfg->layout.plane_pitch[0] << 16) & + 0xFFFF0000); + ystride1 = (ystride1 & 0x0000FFFF) | + ((cfg->layout.plane_pitch[2] << 16) & + 0xFFFF0000); + } + } + + /* rectangle register programming */ + DPU_REG_WRITE(c, src_size_off + idx, src_size); + DPU_REG_WRITE(c, src_xy_off + idx, src_xy); + DPU_REG_WRITE(c, out_size_off + idx, dst_size); + DPU_REG_WRITE(c, out_xy_off + idx, dst_xy); + + DPU_REG_WRITE(c, SSPP_SRC_YSTRIDE0 + idx, ystride0); + DPU_REG_WRITE(c, SSPP_SRC_YSTRIDE1 + idx, ystride1); +} + +static void dpu_hw_sspp_setup_sourceaddress(struct dpu_hw_pipe *ctx, + struct dpu_hw_pipe_cfg *cfg, + enum dpu_sspp_multirect_index rect_mode) +{ + int i; + u32 idx; + + if (_sspp_subblk_offset(ctx, DPU_SSPP_SRC, &idx)) + return; + + if (rect_mode == DPU_SSPP_RECT_SOLO) { + for (i = 0; i < ARRAY_SIZE(cfg->layout.plane_addr); i++) + DPU_REG_WRITE(&ctx->hw, SSPP_SRC0_ADDR + idx + i * 0x4, + cfg->layout.plane_addr[i]); + } else if (rect_mode == DPU_SSPP_RECT_0) { + DPU_REG_WRITE(&ctx->hw, SSPP_SRC0_ADDR + idx, + cfg->layout.plane_addr[0]); + DPU_REG_WRITE(&ctx->hw, SSPP_SRC2_ADDR + idx, + cfg->layout.plane_addr[2]); + } else { + DPU_REG_WRITE(&ctx->hw, SSPP_SRC1_ADDR + idx, + cfg->layout.plane_addr[0]); + DPU_REG_WRITE(&ctx->hw, SSPP_SRC3_ADDR + idx, + cfg->layout.plane_addr[2]); + } +} + +static void dpu_hw_sspp_setup_csc(struct dpu_hw_pipe *ctx, + struct dpu_csc_cfg *data) +{ + u32 idx; + bool csc10 = false; + + if (_sspp_subblk_offset(ctx, DPU_SSPP_CSC, &idx) || !data) + return; + + if (test_bit(DPU_SSPP_CSC_10BIT, &ctx->cap->features)) { + idx += CSC_10BIT_OFFSET; + csc10 = true; + } + + dpu_hw_csc_setup(&ctx->hw, idx, data, csc10); +} + +static void dpu_hw_sspp_setup_solidfill(struct dpu_hw_pipe *ctx, u32 color, enum + dpu_sspp_multirect_index rect_index) +{ + u32 idx; + + if (_sspp_subblk_offset(ctx, DPU_SSPP_SRC, &idx)) + return; + + if (rect_index == DPU_SSPP_RECT_SOLO || rect_index == DPU_SSPP_RECT_0) + DPU_REG_WRITE(&ctx->hw, SSPP_SRC_CONSTANT_COLOR + idx, color); + else + DPU_REG_WRITE(&ctx->hw, SSPP_SRC_CONSTANT_COLOR_REC1 + idx, + color); +} + +static void dpu_hw_sspp_setup_danger_safe_lut(struct dpu_hw_pipe *ctx, + struct dpu_hw_pipe_qos_cfg *cfg) +{ + u32 idx; + + if (_sspp_subblk_offset(ctx, DPU_SSPP_SRC, &idx)) + return; + + DPU_REG_WRITE(&ctx->hw, SSPP_DANGER_LUT + idx, cfg->danger_lut); + DPU_REG_WRITE(&ctx->hw, SSPP_SAFE_LUT + idx, cfg->safe_lut); +} + +static void dpu_hw_sspp_setup_creq_lut(struct dpu_hw_pipe *ctx, + struct dpu_hw_pipe_qos_cfg *cfg) +{ + u32 idx; + + if (_sspp_subblk_offset(ctx, DPU_SSPP_SRC, &idx)) + return; + + if (ctx->cap && test_bit(DPU_SSPP_QOS_8LVL, &ctx->cap->features)) { + DPU_REG_WRITE(&ctx->hw, SSPP_CREQ_LUT_0 + idx, cfg->creq_lut); + DPU_REG_WRITE(&ctx->hw, SSPP_CREQ_LUT_1 + idx, + cfg->creq_lut >> 32); + } else { + DPU_REG_WRITE(&ctx->hw, SSPP_CREQ_LUT + idx, cfg->creq_lut); + } +} + +static void dpu_hw_sspp_setup_qos_ctrl(struct dpu_hw_pipe *ctx, + struct dpu_hw_pipe_qos_cfg *cfg) +{ + u32 idx; + u32 qos_ctrl = 0; + + if (_sspp_subblk_offset(ctx, DPU_SSPP_SRC, &idx)) + return; + + if (cfg->vblank_en) { + qos_ctrl |= ((cfg->creq_vblank & + SSPP_QOS_CTRL_CREQ_VBLANK_MASK) << + SSPP_QOS_CTRL_CREQ_VBLANK_OFF); + qos_ctrl |= ((cfg->danger_vblank & + SSPP_QOS_CTRL_DANGER_VBLANK_MASK) << + SSPP_QOS_CTRL_DANGER_VBLANK_OFF); + qos_ctrl |= SSPP_QOS_CTRL_VBLANK_EN; + } + + if (cfg->danger_safe_en) + qos_ctrl |= SSPP_QOS_CTRL_DANGER_SAFE_EN; + + DPU_REG_WRITE(&ctx->hw, SSPP_QOS_CTRL + idx, qos_ctrl); +} + +static void dpu_hw_sspp_setup_cdp(struct dpu_hw_pipe *ctx, + struct dpu_hw_pipe_cdp_cfg *cfg) +{ + u32 idx; + u32 cdp_cntl = 0; + + if (!ctx || !cfg) + return; + + if (_sspp_subblk_offset(ctx, DPU_SSPP_SRC, &idx)) + return; + + if (cfg->enable) + cdp_cntl |= BIT(0); + if (cfg->ubwc_meta_enable) + cdp_cntl |= BIT(1); + if (cfg->tile_amortize_enable) + cdp_cntl |= BIT(2); + if (cfg->preload_ahead == DPU_SSPP_CDP_PRELOAD_AHEAD_64) + cdp_cntl |= BIT(3); + + DPU_REG_WRITE(&ctx->hw, SSPP_CDP_CNTL, cdp_cntl); +} + +static void _setup_layer_ops(struct dpu_hw_pipe *c, + unsigned long features) +{ + if (test_bit(DPU_SSPP_SRC, &features)) { + c->ops.setup_format = dpu_hw_sspp_setup_format; + c->ops.setup_rects = dpu_hw_sspp_setup_rects; + c->ops.setup_sourceaddress = dpu_hw_sspp_setup_sourceaddress; + c->ops.setup_solidfill = dpu_hw_sspp_setup_solidfill; + c->ops.setup_pe = dpu_hw_sspp_setup_pe_config; + } + + if (test_bit(DPU_SSPP_QOS, &features)) { + c->ops.setup_danger_safe_lut = + dpu_hw_sspp_setup_danger_safe_lut; + c->ops.setup_creq_lut = dpu_hw_sspp_setup_creq_lut; + c->ops.setup_qos_ctrl = dpu_hw_sspp_setup_qos_ctrl; + } + + if (test_bit(DPU_SSPP_CSC, &features) || + test_bit(DPU_SSPP_CSC_10BIT, &features)) + c->ops.setup_csc = dpu_hw_sspp_setup_csc; + + if (dpu_hw_sspp_multirect_enabled(c->cap)) + c->ops.setup_multirect = dpu_hw_sspp_setup_multirect; + + if (test_bit(DPU_SSPP_SCALER_QSEED3, &features)) { + c->ops.setup_scaler = _dpu_hw_sspp_setup_scaler3; + c->ops.get_scaler_ver = _dpu_hw_sspp_get_scaler3_ver; + } + + if (test_bit(DPU_SSPP_CDP, &features)) + c->ops.setup_cdp = dpu_hw_sspp_setup_cdp; +} + +static struct dpu_sspp_cfg *_sspp_offset(enum dpu_sspp sspp, + void __iomem *addr, + struct dpu_mdss_cfg *catalog, + struct dpu_hw_blk_reg_map *b) +{ + int i; + + if ((sspp < SSPP_MAX) && catalog && addr && b) { + for (i = 0; i < catalog->sspp_count; i++) { + if (sspp == catalog->sspp[i].id) { + b->base_off = addr; + b->blk_off = catalog->sspp[i].base; + b->length = catalog->sspp[i].len; + b->hwversion = catalog->hwversion; + b->log_mask = DPU_DBG_MASK_SSPP; + return &catalog->sspp[i]; + } + } + } + + return ERR_PTR(-ENOMEM); +} + +static struct dpu_hw_blk_ops dpu_hw_ops = { + .start = NULL, + .stop = NULL, +}; + +struct dpu_hw_pipe *dpu_hw_sspp_init(enum dpu_sspp idx, + void __iomem *addr, struct dpu_mdss_cfg *catalog, + bool is_virtual_pipe) +{ + struct dpu_hw_pipe *hw_pipe; + struct dpu_sspp_cfg *cfg; + int rc; + + if (!addr || !catalog) + return ERR_PTR(-EINVAL); + + hw_pipe = kzalloc(sizeof(*hw_pipe), GFP_KERNEL); + if (!hw_pipe) + return ERR_PTR(-ENOMEM); + + cfg = _sspp_offset(idx, addr, catalog, &hw_pipe->hw); + if (IS_ERR_OR_NULL(cfg)) { + kfree(hw_pipe); + return ERR_PTR(-EINVAL); + } + + /* Assign ops */ + hw_pipe->catalog = catalog; + hw_pipe->mdp = &catalog->mdp[0]; + hw_pipe->idx = idx; + hw_pipe->cap = cfg; + _setup_layer_ops(hw_pipe, hw_pipe->cap->features); + + rc = dpu_hw_blk_init(&hw_pipe->base, DPU_HW_BLK_SSPP, idx, &dpu_hw_ops); + if (rc) { + DPU_ERROR("failed to init hw blk %d\n", rc); + goto blk_init_error; + } + + return hw_pipe; + +blk_init_error: + kzfree(hw_pipe); + + return ERR_PTR(rc); +} + +void dpu_hw_sspp_destroy(struct dpu_hw_pipe *ctx) +{ + if (ctx) + dpu_hw_blk_destroy(&ctx->base); + kfree(ctx); +} + diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h new file mode 100644 index 0000000000000..4d81e5f5ce1b4 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h @@ -0,0 +1,424 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef _DPU_HW_SSPP_H +#define _DPU_HW_SSPP_H + +#include "dpu_hw_catalog.h" +#include "dpu_hw_mdss.h" +#include "dpu_hw_util.h" +#include "dpu_hw_blk.h" +#include "dpu_formats.h" + +struct dpu_hw_pipe; + +/** + * Flags + */ +#define DPU_SSPP_FLIP_LR BIT(0) +#define DPU_SSPP_FLIP_UD BIT(1) +#define DPU_SSPP_SOURCE_ROTATED_90 BIT(2) +#define DPU_SSPP_ROT_90 BIT(3) +#define DPU_SSPP_SOLID_FILL BIT(4) + +/** + * Define all scaler feature bits in catalog + */ +#define DPU_SSPP_SCALER ((1UL << DPU_SSPP_SCALER_RGB) | \ + (1UL << DPU_SSPP_SCALER_QSEED2) | \ + (1UL << DPU_SSPP_SCALER_QSEED3)) + +/** + * Component indices + */ +enum { + DPU_SSPP_COMP_0, + DPU_SSPP_COMP_1_2, + DPU_SSPP_COMP_2, + DPU_SSPP_COMP_3, + + DPU_SSPP_COMP_MAX +}; + +/** + * DPU_SSPP_RECT_SOLO - multirect disabled + * DPU_SSPP_RECT_0 - rect0 of a multirect pipe + * DPU_SSPP_RECT_1 - rect1 of a multirect pipe + * + * Note: HW supports multirect with either RECT0 or + * RECT1. Considering no benefit of such configs over + * SOLO mode and to keep the plane management simple, + * we dont support single rect multirect configs. + */ +enum dpu_sspp_multirect_index { + DPU_SSPP_RECT_SOLO = 0, + DPU_SSPP_RECT_0, + DPU_SSPP_RECT_1, +}; + +enum dpu_sspp_multirect_mode { + DPU_SSPP_MULTIRECT_NONE = 0, + DPU_SSPP_MULTIRECT_PARALLEL, + DPU_SSPP_MULTIRECT_TIME_MX, +}; + +enum { + DPU_FRAME_LINEAR, + DPU_FRAME_TILE_A4X, + DPU_FRAME_TILE_A5X, +}; + +enum dpu_hw_filter { + DPU_SCALE_FILTER_NEAREST = 0, + DPU_SCALE_FILTER_BIL, + DPU_SCALE_FILTER_PCMN, + DPU_SCALE_FILTER_CA, + DPU_SCALE_FILTER_MAX +}; + +enum dpu_hw_filter_alpa { + DPU_SCALE_ALPHA_PIXEL_REP, + DPU_SCALE_ALPHA_BIL +}; + +enum dpu_hw_filter_yuv { + DPU_SCALE_2D_4X4, + DPU_SCALE_2D_CIR, + DPU_SCALE_1D_SEP, + DPU_SCALE_BIL +}; + +struct dpu_hw_sharp_cfg { + u32 strength; + u32 edge_thr; + u32 smooth_thr; + u32 noise_thr; +}; + +struct dpu_hw_pixel_ext { + /* scaling factors are enabled for this input layer */ + uint8_t enable_pxl_ext; + + int init_phase_x[DPU_MAX_PLANES]; + int phase_step_x[DPU_MAX_PLANES]; + int init_phase_y[DPU_MAX_PLANES]; + int phase_step_y[DPU_MAX_PLANES]; + + /* + * Number of pixels extension in left, right, top and bottom direction + * for all color components. This pixel value for each color component + * should be sum of fetch + repeat pixels. + */ + int num_ext_pxls_left[DPU_MAX_PLANES]; + int num_ext_pxls_right[DPU_MAX_PLANES]; + int num_ext_pxls_top[DPU_MAX_PLANES]; + int num_ext_pxls_btm[DPU_MAX_PLANES]; + + /* + * Number of pixels needs to be overfetched in left, right, top and + * bottom directions from source image for scaling. + */ + int left_ftch[DPU_MAX_PLANES]; + int right_ftch[DPU_MAX_PLANES]; + int top_ftch[DPU_MAX_PLANES]; + int btm_ftch[DPU_MAX_PLANES]; + + /* + * Number of pixels needs to be repeated in left, right, top and + * bottom directions for scaling. + */ + int left_rpt[DPU_MAX_PLANES]; + int right_rpt[DPU_MAX_PLANES]; + int top_rpt[DPU_MAX_PLANES]; + int btm_rpt[DPU_MAX_PLANES]; + + uint32_t roi_w[DPU_MAX_PLANES]; + uint32_t roi_h[DPU_MAX_PLANES]; + + /* + * Filter type to be used for scaling in horizontal and vertical + * directions + */ + enum dpu_hw_filter horz_filter[DPU_MAX_PLANES]; + enum dpu_hw_filter vert_filter[DPU_MAX_PLANES]; + +}; + +/** + * struct dpu_hw_pipe_cfg : Pipe description + * @layout: format layout information for programming buffer to hardware + * @src_rect: src ROI, caller takes into account the different operations + * such as decimation, flip etc to program this field + * @dest_rect: destination ROI. + * @index: index of the rectangle of SSPP + * @mode: parallel or time multiplex multirect mode + */ +struct dpu_hw_pipe_cfg { + struct dpu_hw_fmt_layout layout; + struct drm_rect src_rect; + struct drm_rect dst_rect; + enum dpu_sspp_multirect_index index; + enum dpu_sspp_multirect_mode mode; +}; + +/** + * struct dpu_hw_pipe_qos_cfg : Source pipe QoS configuration + * @danger_lut: LUT for generate danger level based on fill level + * @safe_lut: LUT for generate safe level based on fill level + * @creq_lut: LUT for generate creq level based on fill level + * @creq_vblank: creq value generated to vbif during vertical blanking + * @danger_vblank: danger value generated during vertical blanking + * @vblank_en: enable creq_vblank and danger_vblank during vblank + * @danger_safe_en: enable danger safe generation + */ +struct dpu_hw_pipe_qos_cfg { + u32 danger_lut; + u32 safe_lut; + u64 creq_lut; + u32 creq_vblank; + u32 danger_vblank; + bool vblank_en; + bool danger_safe_en; +}; + +/** + * enum CDP preload ahead address size + */ +enum { + DPU_SSPP_CDP_PRELOAD_AHEAD_32, + DPU_SSPP_CDP_PRELOAD_AHEAD_64 +}; + +/** + * struct dpu_hw_pipe_cdp_cfg : CDP configuration + * @enable: true to enable CDP + * @ubwc_meta_enable: true to enable ubwc metadata preload + * @tile_amortize_enable: true to enable amortization control for tile format + * @preload_ahead: number of request to preload ahead + * DPU_SSPP_CDP_PRELOAD_AHEAD_32, + * DPU_SSPP_CDP_PRELOAD_AHEAD_64 + */ +struct dpu_hw_pipe_cdp_cfg { + bool enable; + bool ubwc_meta_enable; + bool tile_amortize_enable; + u32 preload_ahead; +}; + +/** + * struct dpu_hw_pipe_ts_cfg - traffic shaper configuration + * @size: size to prefill in bytes, or zero to disable + * @time: time to prefill in usec, or zero to disable + */ +struct dpu_hw_pipe_ts_cfg { + u64 size; + u64 time; +}; + +/** + * struct dpu_hw_sspp_ops - interface to the SSPP Hw driver functions + * Caller must call the init function to get the pipe context for each pipe + * Assumption is these functions will be called after clocks are enabled + */ +struct dpu_hw_sspp_ops { + /** + * setup_format - setup pixel format cropping rectangle, flip + * @ctx: Pointer to pipe context + * @cfg: Pointer to pipe config structure + * @flags: Extra flags for format config + * @index: rectangle index in multirect + */ + void (*setup_format)(struct dpu_hw_pipe *ctx, + const struct dpu_format *fmt, u32 flags, + enum dpu_sspp_multirect_index index); + + /** + * setup_rects - setup pipe ROI rectangles + * @ctx: Pointer to pipe context + * @cfg: Pointer to pipe config structure + * @index: rectangle index in multirect + */ + void (*setup_rects)(struct dpu_hw_pipe *ctx, + struct dpu_hw_pipe_cfg *cfg, + enum dpu_sspp_multirect_index index); + + /** + * setup_pe - setup pipe pixel extension + * @ctx: Pointer to pipe context + * @pe_ext: Pointer to pixel ext settings + */ + void (*setup_pe)(struct dpu_hw_pipe *ctx, + struct dpu_hw_pixel_ext *pe_ext); + + /** + * setup_sourceaddress - setup pipe source addresses + * @ctx: Pointer to pipe context + * @cfg: Pointer to pipe config structure + * @index: rectangle index in multirect + */ + void (*setup_sourceaddress)(struct dpu_hw_pipe *ctx, + struct dpu_hw_pipe_cfg *cfg, + enum dpu_sspp_multirect_index index); + + /** + * setup_csc - setup color space coversion + * @ctx: Pointer to pipe context + * @data: Pointer to config structure + */ + void (*setup_csc)(struct dpu_hw_pipe *ctx, struct dpu_csc_cfg *data); + + /** + * setup_solidfill - enable/disable colorfill + * @ctx: Pointer to pipe context + * @const_color: Fill color value + * @flags: Pipe flags + * @index: rectangle index in multirect + */ + void (*setup_solidfill)(struct dpu_hw_pipe *ctx, u32 color, + enum dpu_sspp_multirect_index index); + + /** + * setup_multirect - setup multirect configuration + * @ctx: Pointer to pipe context + * @index: rectangle index in multirect + * @mode: parallel fetch / time multiplex multirect mode + */ + + void (*setup_multirect)(struct dpu_hw_pipe *ctx, + enum dpu_sspp_multirect_index index, + enum dpu_sspp_multirect_mode mode); + + /** + * setup_sharpening - setup sharpening + * @ctx: Pointer to pipe context + * @cfg: Pointer to config structure + */ + void (*setup_sharpening)(struct dpu_hw_pipe *ctx, + struct dpu_hw_sharp_cfg *cfg); + + /** + * setup_danger_safe_lut - setup danger safe LUTs + * @ctx: Pointer to pipe context + * @cfg: Pointer to pipe QoS configuration + * + */ + void (*setup_danger_safe_lut)(struct dpu_hw_pipe *ctx, + struct dpu_hw_pipe_qos_cfg *cfg); + + /** + * setup_creq_lut - setup CREQ LUT + * @ctx: Pointer to pipe context + * @cfg: Pointer to pipe QoS configuration + * + */ + void (*setup_creq_lut)(struct dpu_hw_pipe *ctx, + struct dpu_hw_pipe_qos_cfg *cfg); + + /** + * setup_qos_ctrl - setup QoS control + * @ctx: Pointer to pipe context + * @cfg: Pointer to pipe QoS configuration + * + */ + void (*setup_qos_ctrl)(struct dpu_hw_pipe *ctx, + struct dpu_hw_pipe_qos_cfg *cfg); + + /** + * setup_histogram - setup histograms + * @ctx: Pointer to pipe context + * @cfg: Pointer to histogram configuration + */ + void (*setup_histogram)(struct dpu_hw_pipe *ctx, + void *cfg); + + /** + * setup_scaler - setup scaler + * @ctx: Pointer to pipe context + * @pipe_cfg: Pointer to pipe configuration + * @pe_cfg: Pointer to pixel extension configuration + * @scaler_cfg: Pointer to scaler configuration + */ + void (*setup_scaler)(struct dpu_hw_pipe *ctx, + struct dpu_hw_pipe_cfg *pipe_cfg, + struct dpu_hw_pixel_ext *pe_cfg, + void *scaler_cfg); + + /** + * get_scaler_ver - get scaler h/w version + * @ctx: Pointer to pipe context + */ + u32 (*get_scaler_ver)(struct dpu_hw_pipe *ctx); + + /** + * setup_cdp - setup client driven prefetch + * @ctx: Pointer to pipe context + * @cfg: Pointer to cdp configuration + */ + void (*setup_cdp)(struct dpu_hw_pipe *ctx, + struct dpu_hw_pipe_cdp_cfg *cfg); +}; + +/** + * struct dpu_hw_pipe - pipe description + * @base: hardware block base structure + * @hw: block hardware details + * @catalog: back pointer to catalog + * @mdp: pointer to associated mdp portion of the catalog + * @idx: pipe index + * @cap: pointer to layer_cfg + * @ops: pointer to operations possible for this pipe + */ +struct dpu_hw_pipe { + struct dpu_hw_blk base; + struct dpu_hw_blk_reg_map hw; + struct dpu_mdss_cfg *catalog; + struct dpu_mdp_cfg *mdp; + + /* Pipe */ + enum dpu_sspp idx; + const struct dpu_sspp_cfg *cap; + + /* Ops */ + struct dpu_hw_sspp_ops ops; +}; + +/** + * dpu_hw_pipe - convert base object dpu_hw_base to container + * @hw: Pointer to base hardware block + * return: Pointer to hardware block container + */ +static inline struct dpu_hw_pipe *to_dpu_hw_pipe(struct dpu_hw_blk *hw) +{ + return container_of(hw, struct dpu_hw_pipe, base); +} + +/** + * dpu_hw_sspp_init - initializes the sspp hw driver object. + * Should be called once before accessing every pipe. + * @idx: Pipe index for which driver object is required + * @addr: Mapped register io address of MDP + * @catalog : Pointer to mdss catalog data + * @is_virtual_pipe: is this pipe virtual pipe + */ +struct dpu_hw_pipe *dpu_hw_sspp_init(enum dpu_sspp idx, + void __iomem *addr, struct dpu_mdss_cfg *catalog, + bool is_virtual_pipe); + +/** + * dpu_hw_sspp_destroy(): Destroys SSPP driver context + * should be called during Hw pipe cleanup. + * @ctx: Pointer to SSPP driver context returned by dpu_hw_sspp_init + */ +void dpu_hw_sspp_destroy(struct dpu_hw_pipe *ctx); + +#endif /*_DPU_HW_SSPP_H */ + diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c new file mode 100644 index 0000000000000..42fc72cf48dd0 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c @@ -0,0 +1,398 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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 "dpu_hwio.h" +#include "dpu_hw_catalog.h" +#include "dpu_hw_top.h" +#include "dpu_dbg.h" +#include "dpu_kms.h" + +#define SSPP_SPARE 0x28 +#define UBWC_STATIC 0x144 + +#define FLD_SPLIT_DISPLAY_CMD BIT(1) +#define FLD_SMART_PANEL_FREE_RUN BIT(2) +#define FLD_INTF_1_SW_TRG_MUX BIT(4) +#define FLD_INTF_2_SW_TRG_MUX BIT(8) +#define FLD_TE_LINE_INTER_WATERLEVEL_MASK 0xFFFF + +#define DANGER_STATUS 0x360 +#define SAFE_STATUS 0x364 + +#define TE_LINE_INTERVAL 0x3F4 + +#define TRAFFIC_SHAPER_EN BIT(31) +#define TRAFFIC_SHAPER_RD_CLIENT(num) (0x030 + (num * 4)) +#define TRAFFIC_SHAPER_WR_CLIENT(num) (0x060 + (num * 4)) +#define TRAFFIC_SHAPER_FIXPOINT_FACTOR 4 + +#define MDP_WD_TIMER_0_CTL 0x380 +#define MDP_WD_TIMER_0_CTL2 0x384 +#define MDP_WD_TIMER_0_LOAD_VALUE 0x388 +#define MDP_WD_TIMER_1_CTL 0x390 +#define MDP_WD_TIMER_1_CTL2 0x394 +#define MDP_WD_TIMER_1_LOAD_VALUE 0x398 +#define MDP_WD_TIMER_2_CTL 0x420 +#define MDP_WD_TIMER_2_CTL2 0x424 +#define MDP_WD_TIMER_2_LOAD_VALUE 0x428 +#define MDP_WD_TIMER_3_CTL 0x430 +#define MDP_WD_TIMER_3_CTL2 0x434 +#define MDP_WD_TIMER_3_LOAD_VALUE 0x438 +#define MDP_WD_TIMER_4_CTL 0x440 +#define MDP_WD_TIMER_4_CTL2 0x444 +#define MDP_WD_TIMER_4_LOAD_VALUE 0x448 + +#define MDP_TICK_COUNT 16 +#define XO_CLK_RATE 19200 +#define MS_TICKS_IN_SEC 1000 + +#define CALCULATE_WD_LOAD_VALUE(fps) \ + ((uint32_t)((MS_TICKS_IN_SEC * XO_CLK_RATE)/(MDP_TICK_COUNT * fps))) + +#define DCE_SEL 0x450 + +static void dpu_hw_setup_split_pipe(struct dpu_hw_mdp *mdp, + struct split_pipe_cfg *cfg) +{ + struct dpu_hw_blk_reg_map *c; + u32 upper_pipe = 0; + u32 lower_pipe = 0; + + if (!mdp || !cfg) + return; + + c = &mdp->hw; + + if (cfg->en) { + if (cfg->mode == INTF_MODE_CMD) { + lower_pipe = FLD_SPLIT_DISPLAY_CMD; + /* interface controlling sw trigger */ + if (cfg->intf == INTF_2) + lower_pipe |= FLD_INTF_1_SW_TRG_MUX; + else + lower_pipe |= FLD_INTF_2_SW_TRG_MUX; + upper_pipe = lower_pipe; + } else { + if (cfg->intf == INTF_2) { + lower_pipe = FLD_INTF_1_SW_TRG_MUX; + upper_pipe = FLD_INTF_2_SW_TRG_MUX; + } else { + lower_pipe = FLD_INTF_2_SW_TRG_MUX; + upper_pipe = FLD_INTF_1_SW_TRG_MUX; + } + } + } + + DPU_REG_WRITE(c, SSPP_SPARE, cfg->split_flush_en ? 0x1 : 0x0); + DPU_REG_WRITE(c, SPLIT_DISPLAY_LOWER_PIPE_CTRL, lower_pipe); + DPU_REG_WRITE(c, SPLIT_DISPLAY_UPPER_PIPE_CTRL, upper_pipe); + DPU_REG_WRITE(c, SPLIT_DISPLAY_EN, cfg->en & 0x1); +} + +static void dpu_hw_setup_cdm_output(struct dpu_hw_mdp *mdp, + struct cdm_output_cfg *cfg) +{ + struct dpu_hw_blk_reg_map *c; + u32 out_ctl = 0; + + if (!mdp || !cfg) + return; + + c = &mdp->hw; + + if (cfg->intf_en) + out_ctl |= BIT(19); + + DPU_REG_WRITE(c, MDP_OUT_CTL_0, out_ctl); +} + +static bool dpu_hw_setup_clk_force_ctrl(struct dpu_hw_mdp *mdp, + enum dpu_clk_ctrl_type clk_ctrl, bool enable) +{ + struct dpu_hw_blk_reg_map *c; + u32 reg_off, bit_off; + u32 reg_val, new_val; + bool clk_forced_on; + + if (!mdp) + return false; + + c = &mdp->hw; + + if (clk_ctrl <= DPU_CLK_CTRL_NONE || clk_ctrl >= DPU_CLK_CTRL_MAX) + return false; + + reg_off = mdp->caps->clk_ctrls[clk_ctrl].reg_off; + bit_off = mdp->caps->clk_ctrls[clk_ctrl].bit_off; + + reg_val = DPU_REG_READ(c, reg_off); + + if (enable) + new_val = reg_val | BIT(bit_off); + else + new_val = reg_val & ~BIT(bit_off); + + DPU_REG_WRITE(c, reg_off, new_val); + + clk_forced_on = !(reg_val & BIT(bit_off)); + + return clk_forced_on; +} + + +static void dpu_hw_get_danger_status(struct dpu_hw_mdp *mdp, + struct dpu_danger_safe_status *status) +{ + struct dpu_hw_blk_reg_map *c; + u32 value; + + if (!mdp || !status) + return; + + c = &mdp->hw; + + value = DPU_REG_READ(c, DANGER_STATUS); + status->mdp = (value >> 0) & 0x3; + status->sspp[SSPP_VIG0] = (value >> 4) & 0x3; + status->sspp[SSPP_VIG1] = (value >> 6) & 0x3; + status->sspp[SSPP_VIG2] = (value >> 8) & 0x3; + status->sspp[SSPP_VIG3] = (value >> 10) & 0x3; + status->sspp[SSPP_RGB0] = (value >> 12) & 0x3; + status->sspp[SSPP_RGB1] = (value >> 14) & 0x3; + status->sspp[SSPP_RGB2] = (value >> 16) & 0x3; + status->sspp[SSPP_RGB3] = (value >> 18) & 0x3; + status->sspp[SSPP_DMA0] = (value >> 20) & 0x3; + status->sspp[SSPP_DMA1] = (value >> 22) & 0x3; + status->sspp[SSPP_DMA2] = (value >> 28) & 0x3; + status->sspp[SSPP_DMA3] = (value >> 30) & 0x3; + status->sspp[SSPP_CURSOR0] = (value >> 24) & 0x3; + status->sspp[SSPP_CURSOR1] = (value >> 26) & 0x3; +} + +static void dpu_hw_setup_vsync_source(struct dpu_hw_mdp *mdp, + struct dpu_vsync_source_cfg *cfg) +{ + struct dpu_hw_blk_reg_map *c; + u32 reg, wd_load_value, wd_ctl, wd_ctl2, i; + static const u32 pp_offset[PINGPONG_MAX] = {0xC, 0x8, 0x4, 0x13, 0x18}; + + if (!mdp || !cfg || (cfg->pp_count > ARRAY_SIZE(cfg->ppnumber))) + return; + + c = &mdp->hw; + reg = DPU_REG_READ(c, MDP_VSYNC_SEL); + for (i = 0; i < cfg->pp_count; i++) { + int pp_idx = cfg->ppnumber[i] - PINGPONG_0; + + if (pp_idx >= ARRAY_SIZE(pp_offset)) + continue; + + reg &= ~(0xf << pp_offset[pp_idx]); + reg |= (cfg->vsync_source & 0xf) << pp_offset[pp_idx]; + } + DPU_REG_WRITE(c, MDP_VSYNC_SEL, reg); + + if (cfg->vsync_source >= DPU_VSYNC_SOURCE_WD_TIMER_4 && + cfg->vsync_source <= DPU_VSYNC_SOURCE_WD_TIMER_0) { + switch (cfg->vsync_source) { + case DPU_VSYNC_SOURCE_WD_TIMER_4: + wd_load_value = MDP_WD_TIMER_4_LOAD_VALUE; + wd_ctl = MDP_WD_TIMER_4_CTL; + wd_ctl2 = MDP_WD_TIMER_4_CTL2; + break; + case DPU_VSYNC_SOURCE_WD_TIMER_3: + wd_load_value = MDP_WD_TIMER_3_LOAD_VALUE; + wd_ctl = MDP_WD_TIMER_3_CTL; + wd_ctl2 = MDP_WD_TIMER_3_CTL2; + break; + case DPU_VSYNC_SOURCE_WD_TIMER_2: + wd_load_value = MDP_WD_TIMER_2_LOAD_VALUE; + wd_ctl = MDP_WD_TIMER_2_CTL; + wd_ctl2 = MDP_WD_TIMER_2_CTL2; + break; + case DPU_VSYNC_SOURCE_WD_TIMER_1: + wd_load_value = MDP_WD_TIMER_1_LOAD_VALUE; + wd_ctl = MDP_WD_TIMER_1_CTL; + wd_ctl2 = MDP_WD_TIMER_1_CTL2; + break; + case DPU_VSYNC_SOURCE_WD_TIMER_0: + default: + wd_load_value = MDP_WD_TIMER_0_LOAD_VALUE; + wd_ctl = MDP_WD_TIMER_0_CTL; + wd_ctl2 = MDP_WD_TIMER_0_CTL2; + break; + } + + DPU_REG_WRITE(c, wd_load_value, + CALCULATE_WD_LOAD_VALUE(cfg->frame_rate)); + + DPU_REG_WRITE(c, wd_ctl, BIT(0)); /* clear timer */ + reg = DPU_REG_READ(c, wd_ctl2); + reg |= BIT(8); /* enable heartbeat timer */ + reg |= BIT(0); /* enable WD timer */ + DPU_REG_WRITE(c, wd_ctl2, reg); + + /* make sure that timers are enabled/disabled for vsync state */ + wmb(); + } +} + +static void dpu_hw_get_safe_status(struct dpu_hw_mdp *mdp, + struct dpu_danger_safe_status *status) +{ + struct dpu_hw_blk_reg_map *c; + u32 value; + + if (!mdp || !status) + return; + + c = &mdp->hw; + + value = DPU_REG_READ(c, SAFE_STATUS); + status->mdp = (value >> 0) & 0x1; + status->sspp[SSPP_VIG0] = (value >> 4) & 0x1; + status->sspp[SSPP_VIG1] = (value >> 6) & 0x1; + status->sspp[SSPP_VIG2] = (value >> 8) & 0x1; + status->sspp[SSPP_VIG3] = (value >> 10) & 0x1; + status->sspp[SSPP_RGB0] = (value >> 12) & 0x1; + status->sspp[SSPP_RGB1] = (value >> 14) & 0x1; + status->sspp[SSPP_RGB2] = (value >> 16) & 0x1; + status->sspp[SSPP_RGB3] = (value >> 18) & 0x1; + status->sspp[SSPP_DMA0] = (value >> 20) & 0x1; + status->sspp[SSPP_DMA1] = (value >> 22) & 0x1; + status->sspp[SSPP_DMA2] = (value >> 28) & 0x1; + status->sspp[SSPP_DMA3] = (value >> 30) & 0x1; + status->sspp[SSPP_CURSOR0] = (value >> 24) & 0x1; + status->sspp[SSPP_CURSOR1] = (value >> 26) & 0x1; +} + +void dpu_hw_reset_ubwc(struct dpu_hw_mdp *mdp, struct dpu_mdss_cfg *m) +{ + struct dpu_hw_blk_reg_map c; + + if (!mdp || !m) + return; + + if (!IS_UBWC_20_SUPPORTED(m->caps->ubwc_version)) + return; + + /* force blk offset to zero to access beginning of register region */ + c = mdp->hw; + c.blk_off = 0x0; + DPU_REG_WRITE(&c, UBWC_STATIC, m->mdp[0].ubwc_static); +} + +static void dpu_hw_intf_audio_select(struct dpu_hw_mdp *mdp) +{ + struct dpu_hw_blk_reg_map *c; + + if (!mdp) + return; + + c = &mdp->hw; + + DPU_REG_WRITE(c, HDMI_DP_CORE_SELECT, 0x1); +} + +static void _setup_mdp_ops(struct dpu_hw_mdp_ops *ops, + unsigned long cap) +{ + ops->setup_split_pipe = dpu_hw_setup_split_pipe; + ops->setup_cdm_output = dpu_hw_setup_cdm_output; + ops->setup_clk_force_ctrl = dpu_hw_setup_clk_force_ctrl; + ops->get_danger_status = dpu_hw_get_danger_status; + ops->setup_vsync_source = dpu_hw_setup_vsync_source; + ops->get_safe_status = dpu_hw_get_safe_status; + ops->reset_ubwc = dpu_hw_reset_ubwc; + ops->intf_audio_select = dpu_hw_intf_audio_select; +} + +static const struct dpu_mdp_cfg *_top_offset(enum dpu_mdp mdp, + const struct dpu_mdss_cfg *m, + void __iomem *addr, + struct dpu_hw_blk_reg_map *b) +{ + int i; + + if (!m || !addr || !b) + return ERR_PTR(-EINVAL); + + for (i = 0; i < m->mdp_count; i++) { + if (mdp == m->mdp[i].id) { + b->base_off = addr; + b->blk_off = m->mdp[i].base; + b->length = m->mdp[i].len; + b->hwversion = m->hwversion; + b->log_mask = DPU_DBG_MASK_TOP; + return &m->mdp[i]; + } + } + + return ERR_PTR(-EINVAL); +} + +static struct dpu_hw_blk_ops dpu_hw_ops = { + .start = NULL, + .stop = NULL, +}; + +struct dpu_hw_mdp *dpu_hw_mdptop_init(enum dpu_mdp idx, + void __iomem *addr, + const struct dpu_mdss_cfg *m) +{ + struct dpu_hw_mdp *mdp; + const struct dpu_mdp_cfg *cfg; + int rc; + + if (!addr || !m) + return ERR_PTR(-EINVAL); + + mdp = kzalloc(sizeof(*mdp), GFP_KERNEL); + if (!mdp) + return ERR_PTR(-ENOMEM); + + cfg = _top_offset(idx, m, addr, &mdp->hw); + if (IS_ERR_OR_NULL(cfg)) { + kfree(mdp); + return ERR_PTR(-EINVAL); + } + + /* + * Assign ops + */ + mdp->idx = idx; + mdp->caps = cfg; + _setup_mdp_ops(&mdp->ops, mdp->caps->features); + + rc = dpu_hw_blk_init(&mdp->base, DPU_HW_BLK_TOP, idx, &dpu_hw_ops); + if (rc) { + DPU_ERROR("failed to init hw blk %d\n", rc); + goto blk_init_error; + } + + dpu_dbg_set_dpu_top_offset(mdp->hw.blk_off); + + return mdp; + +blk_init_error: + kzfree(mdp); + + return ERR_PTR(rc); +} + +void dpu_hw_mdp_destroy(struct dpu_hw_mdp *mdp) +{ + if (mdp) + dpu_hw_blk_destroy(&mdp->base); + kfree(mdp); +} + diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h new file mode 100644 index 0000000000000..899925aaa6d75 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h @@ -0,0 +1,202 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef _DPU_HW_TOP_H +#define _DPU_HW_TOP_H + +#include "dpu_hw_catalog.h" +#include "dpu_hw_mdss.h" +#include "dpu_hw_util.h" +#include "dpu_hw_blk.h" + +struct dpu_hw_mdp; + +/** + * struct traffic_shaper_cfg: traffic shaper configuration + * @en : enable/disable traffic shaper + * @rd_client : true if read client; false if write client + * @client_id : client identifier + * @bpc_denom : denominator of byte per clk + * @bpc_numer : numerator of byte per clk + */ +struct traffic_shaper_cfg { + bool en; + bool rd_client; + u32 client_id; + u32 bpc_denom; + u64 bpc_numer; +}; + +/** + * struct split_pipe_cfg - pipe configuration for dual display panels + * @en : Enable/disable dual pipe confguration + * @mode : Panel interface mode + * @intf : Interface id for main control path + * @split_flush_en: Allows both the paths to be flushed when master path is + * flushed + */ +struct split_pipe_cfg { + bool en; + enum dpu_intf_mode mode; + enum dpu_intf intf; + bool split_flush_en; +}; + +/** + * struct cdm_output_cfg: output configuration for cdm + * @intf_en : enable/disable interface output + */ +struct cdm_output_cfg { + bool intf_en; +}; + +/** + * struct dpu_danger_safe_status: danger and safe status signals + * @mdp: top level status + * @sspp: source pipe status + */ +struct dpu_danger_safe_status { + u8 mdp; + u8 sspp[SSPP_MAX]; +}; + +/** + * struct dpu_vsync_source_cfg - configure vsync source and configure the + * watchdog timers if required. + * @pp_count: number of ping pongs active + * @frame_rate: Display frame rate + * @ppnumber: ping pong index array + * @vsync_source: vsync source selection + */ +struct dpu_vsync_source_cfg { + u32 pp_count; + u32 frame_rate; + u32 ppnumber[PINGPONG_MAX]; + u32 vsync_source; +}; + +/** + * struct dpu_hw_mdp_ops - interface to the MDP TOP Hw driver functions + * Assumption is these functions will be called after clocks are enabled. + * @setup_split_pipe : Programs the pipe control registers + * @setup_pp_split : Programs the pp split control registers + * @setup_cdm_output : programs cdm control + * @setup_traffic_shaper : programs traffic shaper control + */ +struct dpu_hw_mdp_ops { + /** setup_split_pipe() : Regsiters are not double buffered, thisk + * function should be called before timing control enable + * @mdp : mdp top context driver + * @cfg : upper and lower part of pipe configuration + */ + void (*setup_split_pipe)(struct dpu_hw_mdp *mdp, + struct split_pipe_cfg *p); + + /** + * setup_cdm_output() : Setup selection control of the cdm data path + * @mdp : mdp top context driver + * @cfg : cdm output configuration + */ + void (*setup_cdm_output)(struct dpu_hw_mdp *mdp, + struct cdm_output_cfg *cfg); + + /** + * setup_traffic_shaper() : Setup traffic shaper control + * @mdp : mdp top context driver + * @cfg : traffic shaper configuration + */ + void (*setup_traffic_shaper)(struct dpu_hw_mdp *mdp, + struct traffic_shaper_cfg *cfg); + + /** + * setup_clk_force_ctrl - set clock force control + * @mdp: mdp top context driver + * @clk_ctrl: clock to be controlled + * @enable: force on enable + * @return: if the clock is forced-on by this function + */ + bool (*setup_clk_force_ctrl)(struct dpu_hw_mdp *mdp, + enum dpu_clk_ctrl_type clk_ctrl, bool enable); + + /** + * get_danger_status - get danger status + * @mdp: mdp top context driver + * @status: Pointer to danger safe status + */ + void (*get_danger_status)(struct dpu_hw_mdp *mdp, + struct dpu_danger_safe_status *status); + + /** + * setup_vsync_source - setup vsync source configuration details + * @mdp: mdp top context driver + * @cfg: vsync source selection configuration + */ + void (*setup_vsync_source)(struct dpu_hw_mdp *mdp, + struct dpu_vsync_source_cfg *cfg); + + /** + * get_safe_status - get safe status + * @mdp: mdp top context driver + * @status: Pointer to danger safe status + */ + void (*get_safe_status)(struct dpu_hw_mdp *mdp, + struct dpu_danger_safe_status *status); + + /** + * reset_ubwc - reset top level UBWC configuration + * @mdp: mdp top context driver + * @m: pointer to mdss catalog data + */ + void (*reset_ubwc)(struct dpu_hw_mdp *mdp, struct dpu_mdss_cfg *m); + + /** + * intf_audio_select - select the external interface for audio + * @mdp: mdp top context driver + */ + void (*intf_audio_select)(struct dpu_hw_mdp *mdp); +}; + +struct dpu_hw_mdp { + struct dpu_hw_blk base; + struct dpu_hw_blk_reg_map hw; + + /* top */ + enum dpu_mdp idx; + const struct dpu_mdp_cfg *caps; + + /* ops */ + struct dpu_hw_mdp_ops ops; +}; + +/** + * to_dpu_hw_mdp - convert base object dpu_hw_base to container + * @hw: Pointer to base hardware block + * return: Pointer to hardware block container + */ +static inline struct dpu_hw_mdp *to_dpu_hw_mdp(struct dpu_hw_blk *hw) +{ + return container_of(hw, struct dpu_hw_mdp, base); +} + +/** + * dpu_hw_mdptop_init - initializes the top driver for the passed idx + * @idx: Interface index for which driver object is required + * @addr: Mapped register io address of MDP + * @m: Pointer to mdss catalog data + */ +struct dpu_hw_mdp *dpu_hw_mdptop_init(enum dpu_mdp idx, + void __iomem *addr, + const struct dpu_mdss_cfg *m); + +void dpu_hw_mdp_destroy(struct dpu_hw_mdp *mdp); + +#endif /*_DPU_HW_TOP_H */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c new file mode 100644 index 0000000000000..1ba571e94b328 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c @@ -0,0 +1,452 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ +#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ + +#include "msm_drv.h" +#include "dpu_kms.h" +#include "dpu_hw_mdss.h" +#include "dpu_hw_util.h" + +/* using a file static variables for debugfs access */ +static u32 dpu_hw_util_log_mask = DPU_DBG_MASK_NONE; + +/* DPU_SCALER_QSEED3 */ +#define QSEED3_HW_VERSION 0x00 +#define QSEED3_OP_MODE 0x04 +#define QSEED3_RGB2Y_COEFF 0x08 +#define QSEED3_PHASE_INIT 0x0C +#define QSEED3_PHASE_STEP_Y_H 0x10 +#define QSEED3_PHASE_STEP_Y_V 0x14 +#define QSEED3_PHASE_STEP_UV_H 0x18 +#define QSEED3_PHASE_STEP_UV_V 0x1C +#define QSEED3_PRELOAD 0x20 +#define QSEED3_DE_SHARPEN 0x24 +#define QSEED3_DE_SHARPEN_CTL 0x28 +#define QSEED3_DE_SHAPE_CTL 0x2C +#define QSEED3_DE_THRESHOLD 0x30 +#define QSEED3_DE_ADJUST_DATA_0 0x34 +#define QSEED3_DE_ADJUST_DATA_1 0x38 +#define QSEED3_DE_ADJUST_DATA_2 0x3C +#define QSEED3_SRC_SIZE_Y_RGB_A 0x40 +#define QSEED3_SRC_SIZE_UV 0x44 +#define QSEED3_DST_SIZE 0x48 +#define QSEED3_COEF_LUT_CTRL 0x4C +#define QSEED3_COEF_LUT_SWAP_BIT 0 +#define QSEED3_COEF_LUT_DIR_BIT 1 +#define QSEED3_COEF_LUT_Y_CIR_BIT 2 +#define QSEED3_COEF_LUT_UV_CIR_BIT 3 +#define QSEED3_COEF_LUT_Y_SEP_BIT 4 +#define QSEED3_COEF_LUT_UV_SEP_BIT 5 +#define QSEED3_BUFFER_CTRL 0x50 +#define QSEED3_CLK_CTRL0 0x54 +#define QSEED3_CLK_CTRL1 0x58 +#define QSEED3_CLK_STATUS 0x5C +#define QSEED3_MISR_CTRL 0x70 +#define QSEED3_MISR_SIGNATURE_0 0x74 +#define QSEED3_MISR_SIGNATURE_1 0x78 +#define QSEED3_PHASE_INIT_Y_H 0x90 +#define QSEED3_PHASE_INIT_Y_V 0x94 +#define QSEED3_PHASE_INIT_UV_H 0x98 +#define QSEED3_PHASE_INIT_UV_V 0x9C +#define QSEED3_COEF_LUT 0x100 +#define QSEED3_FILTERS 5 +#define QSEED3_LUT_REGIONS 4 +#define QSEED3_CIRCULAR_LUTS 9 +#define QSEED3_SEPARABLE_LUTS 10 +#define QSEED3_LUT_SIZE 60 +#define QSEED3_ENABLE 2 +#define QSEED3_DIR_LUT_SIZE (200 * sizeof(u32)) +#define QSEED3_CIR_LUT_SIZE \ + (QSEED3_LUT_SIZE * QSEED3_CIRCULAR_LUTS * sizeof(u32)) +#define QSEED3_SEP_LUT_SIZE \ + (QSEED3_LUT_SIZE * QSEED3_SEPARABLE_LUTS * sizeof(u32)) + +void dpu_reg_write(struct dpu_hw_blk_reg_map *c, + u32 reg_off, + u32 val, + const char *name) +{ + /* don't need to mutex protect this */ + if (c->log_mask & dpu_hw_util_log_mask) + DPU_DEBUG_DRIVER("[%s:0x%X] <= 0x%X\n", + name, c->blk_off + reg_off, val); + writel_relaxed(val, c->base_off + c->blk_off + reg_off); +} + +int dpu_reg_read(struct dpu_hw_blk_reg_map *c, u32 reg_off) +{ + return readl_relaxed(c->base_off + c->blk_off + reg_off); +} + +u32 *dpu_hw_util_get_log_mask_ptr(void) +{ + return &dpu_hw_util_log_mask; +} + +void dpu_set_scaler_v2(struct dpu_hw_scaler3_cfg *cfg, + const struct dpu_drm_scaler_v2 *scale_v2) +{ + int i; + + cfg->enable = scale_v2->enable; + cfg->dir_en = scale_v2->dir_en; + + for (i = 0; i < DPU_MAX_PLANES; i++) { + cfg->init_phase_x[i] = scale_v2->init_phase_x[i]; + cfg->phase_step_x[i] = scale_v2->phase_step_x[i]; + cfg->init_phase_y[i] = scale_v2->init_phase_y[i]; + cfg->phase_step_y[i] = scale_v2->phase_step_y[i]; + + cfg->preload_x[i] = scale_v2->preload_x[i]; + cfg->preload_y[i] = scale_v2->preload_y[i]; + cfg->src_width[i] = scale_v2->src_width[i]; + cfg->src_height[i] = scale_v2->src_height[i]; + } + + cfg->dst_width = scale_v2->dst_width; + cfg->dst_height = scale_v2->dst_height; + + cfg->y_rgb_filter_cfg = scale_v2->y_rgb_filter_cfg; + cfg->uv_filter_cfg = scale_v2->uv_filter_cfg; + cfg->alpha_filter_cfg = scale_v2->alpha_filter_cfg; + cfg->blend_cfg = scale_v2->blend_cfg; + + cfg->lut_flag = scale_v2->lut_flag; + cfg->dir_lut_idx = scale_v2->dir_lut_idx; + cfg->y_rgb_cir_lut_idx = scale_v2->y_rgb_cir_lut_idx; + cfg->uv_cir_lut_idx = scale_v2->uv_cir_lut_idx; + cfg->y_rgb_sep_lut_idx = scale_v2->y_rgb_sep_lut_idx; + cfg->uv_sep_lut_idx = scale_v2->uv_sep_lut_idx; + + cfg->de.enable = scale_v2->de.enable; + cfg->de.sharpen_level1 = scale_v2->de.sharpen_level1; + cfg->de.sharpen_level2 = scale_v2->de.sharpen_level2; + cfg->de.clip = scale_v2->de.clip; + cfg->de.limit = scale_v2->de.limit; + cfg->de.thr_quiet = scale_v2->de.thr_quiet; + cfg->de.thr_dieout = scale_v2->de.thr_dieout; + cfg->de.thr_low = scale_v2->de.thr_low; + cfg->de.thr_high = scale_v2->de.thr_high; + cfg->de.prec_shift = scale_v2->de.prec_shift; + + for (i = 0; i < DPU_MAX_DE_CURVES; i++) { + cfg->de.adjust_a[i] = scale_v2->de.adjust_a[i]; + cfg->de.adjust_b[i] = scale_v2->de.adjust_b[i]; + cfg->de.adjust_c[i] = scale_v2->de.adjust_c[i]; + } +} + +static void _dpu_hw_setup_scaler3_lut(struct dpu_hw_blk_reg_map *c, + struct dpu_hw_scaler3_cfg *scaler3_cfg, u32 offset) +{ + int i, j, filter; + int config_lut = 0x0; + unsigned long lut_flags; + u32 lut_addr, lut_offset, lut_len; + u32 *lut[QSEED3_FILTERS] = {NULL, NULL, NULL, NULL, NULL}; + static const uint32_t off_tbl[QSEED3_FILTERS][QSEED3_LUT_REGIONS][2] = { + {{18, 0x000}, {12, 0x120}, {12, 0x1E0}, {8, 0x2A0} }, + {{6, 0x320}, {3, 0x3E0}, {3, 0x440}, {3, 0x4A0} }, + {{6, 0x500}, {3, 0x5c0}, {3, 0x620}, {3, 0x680} }, + {{6, 0x380}, {3, 0x410}, {3, 0x470}, {3, 0x4d0} }, + {{6, 0x560}, {3, 0x5f0}, {3, 0x650}, {3, 0x6b0} }, + }; + + lut_flags = (unsigned long) scaler3_cfg->lut_flag; + if (test_bit(QSEED3_COEF_LUT_DIR_BIT, &lut_flags) && + (scaler3_cfg->dir_len == QSEED3_DIR_LUT_SIZE)) { + lut[0] = scaler3_cfg->dir_lut; + config_lut = 1; + } + if (test_bit(QSEED3_COEF_LUT_Y_CIR_BIT, &lut_flags) && + (scaler3_cfg->y_rgb_cir_lut_idx < QSEED3_CIRCULAR_LUTS) && + (scaler3_cfg->cir_len == QSEED3_CIR_LUT_SIZE)) { + lut[1] = scaler3_cfg->cir_lut + + scaler3_cfg->y_rgb_cir_lut_idx * QSEED3_LUT_SIZE; + config_lut = 1; + } + if (test_bit(QSEED3_COEF_LUT_UV_CIR_BIT, &lut_flags) && + (scaler3_cfg->uv_cir_lut_idx < QSEED3_CIRCULAR_LUTS) && + (scaler3_cfg->cir_len == QSEED3_CIR_LUT_SIZE)) { + lut[2] = scaler3_cfg->cir_lut + + scaler3_cfg->uv_cir_lut_idx * QSEED3_LUT_SIZE; + config_lut = 1; + } + if (test_bit(QSEED3_COEF_LUT_Y_SEP_BIT, &lut_flags) && + (scaler3_cfg->y_rgb_sep_lut_idx < QSEED3_SEPARABLE_LUTS) && + (scaler3_cfg->sep_len == QSEED3_SEP_LUT_SIZE)) { + lut[3] = scaler3_cfg->sep_lut + + scaler3_cfg->y_rgb_sep_lut_idx * QSEED3_LUT_SIZE; + config_lut = 1; + } + if (test_bit(QSEED3_COEF_LUT_UV_SEP_BIT, &lut_flags) && + (scaler3_cfg->uv_sep_lut_idx < QSEED3_SEPARABLE_LUTS) && + (scaler3_cfg->sep_len == QSEED3_SEP_LUT_SIZE)) { + lut[4] = scaler3_cfg->sep_lut + + scaler3_cfg->uv_sep_lut_idx * QSEED3_LUT_SIZE; + config_lut = 1; + } + + if (config_lut) { + for (filter = 0; filter < QSEED3_FILTERS; filter++) { + if (!lut[filter]) + continue; + lut_offset = 0; + for (i = 0; i < QSEED3_LUT_REGIONS; i++) { + lut_addr = QSEED3_COEF_LUT + offset + + off_tbl[filter][i][1]; + lut_len = off_tbl[filter][i][0] << 2; + for (j = 0; j < lut_len; j++) { + DPU_REG_WRITE(c, + lut_addr, + (lut[filter])[lut_offset++]); + lut_addr += 4; + } + } + } + } + + if (test_bit(QSEED3_COEF_LUT_SWAP_BIT, &lut_flags)) + DPU_REG_WRITE(c, QSEED3_COEF_LUT_CTRL + offset, BIT(0)); + +} + +static void _dpu_hw_setup_scaler3_de(struct dpu_hw_blk_reg_map *c, + struct dpu_hw_scaler3_de_cfg *de_cfg, u32 offset) +{ + u32 sharp_lvl, sharp_ctl, shape_ctl, de_thr; + u32 adjust_a, adjust_b, adjust_c; + + if (!de_cfg->enable) + return; + + sharp_lvl = (de_cfg->sharpen_level1 & 0x1FF) | + ((de_cfg->sharpen_level2 & 0x1FF) << 16); + + sharp_ctl = ((de_cfg->limit & 0xF) << 9) | + ((de_cfg->prec_shift & 0x7) << 13) | + ((de_cfg->clip & 0x7) << 16); + + shape_ctl = (de_cfg->thr_quiet & 0xFF) | + ((de_cfg->thr_dieout & 0x3FF) << 16); + + de_thr = (de_cfg->thr_low & 0x3FF) | + ((de_cfg->thr_high & 0x3FF) << 16); + + adjust_a = (de_cfg->adjust_a[0] & 0x3FF) | + ((de_cfg->adjust_a[1] & 0x3FF) << 10) | + ((de_cfg->adjust_a[2] & 0x3FF) << 20); + + adjust_b = (de_cfg->adjust_b[0] & 0x3FF) | + ((de_cfg->adjust_b[1] & 0x3FF) << 10) | + ((de_cfg->adjust_b[2] & 0x3FF) << 20); + + adjust_c = (de_cfg->adjust_c[0] & 0x3FF) | + ((de_cfg->adjust_c[1] & 0x3FF) << 10) | + ((de_cfg->adjust_c[2] & 0x3FF) << 20); + + DPU_REG_WRITE(c, QSEED3_DE_SHARPEN + offset, sharp_lvl); + DPU_REG_WRITE(c, QSEED3_DE_SHARPEN_CTL + offset, sharp_ctl); + DPU_REG_WRITE(c, QSEED3_DE_SHAPE_CTL + offset, shape_ctl); + DPU_REG_WRITE(c, QSEED3_DE_THRESHOLD + offset, de_thr); + DPU_REG_WRITE(c, QSEED3_DE_ADJUST_DATA_0 + offset, adjust_a); + DPU_REG_WRITE(c, QSEED3_DE_ADJUST_DATA_1 + offset, adjust_b); + DPU_REG_WRITE(c, QSEED3_DE_ADJUST_DATA_2 + offset, adjust_c); + +} + +void dpu_hw_setup_scaler3(struct dpu_hw_blk_reg_map *c, + struct dpu_hw_scaler3_cfg *scaler3_cfg, + u32 scaler_offset, u32 scaler_version, + const struct dpu_format *format) +{ + u32 op_mode = 0; + u32 phase_init, preload, src_y_rgb, src_uv, dst; + + if (!scaler3_cfg->enable) + goto end; + + op_mode |= BIT(0); + op_mode |= (scaler3_cfg->y_rgb_filter_cfg & 0x3) << 16; + + if (format && DPU_FORMAT_IS_YUV(format)) { + op_mode |= BIT(12); + op_mode |= (scaler3_cfg->uv_filter_cfg & 0x3) << 24; + } + + op_mode |= (scaler3_cfg->blend_cfg & 1) << 31; + op_mode |= (scaler3_cfg->dir_en) ? BIT(4) : 0; + + preload = + ((scaler3_cfg->preload_x[0] & 0x7F) << 0) | + ((scaler3_cfg->preload_y[0] & 0x7F) << 8) | + ((scaler3_cfg->preload_x[1] & 0x7F) << 16) | + ((scaler3_cfg->preload_y[1] & 0x7F) << 24); + + src_y_rgb = (scaler3_cfg->src_width[0] & 0x1FFFF) | + ((scaler3_cfg->src_height[0] & 0x1FFFF) << 16); + + src_uv = (scaler3_cfg->src_width[1] & 0x1FFFF) | + ((scaler3_cfg->src_height[1] & 0x1FFFF) << 16); + + dst = (scaler3_cfg->dst_width & 0x1FFFF) | + ((scaler3_cfg->dst_height & 0x1FFFF) << 16); + + if (scaler3_cfg->de.enable) { + _dpu_hw_setup_scaler3_de(c, &scaler3_cfg->de, scaler_offset); + op_mode |= BIT(8); + } + + if (scaler3_cfg->lut_flag) + _dpu_hw_setup_scaler3_lut(c, scaler3_cfg, + scaler_offset); + + if (scaler_version == 0x1002) { + phase_init = + ((scaler3_cfg->init_phase_x[0] & 0x3F) << 0) | + ((scaler3_cfg->init_phase_y[0] & 0x3F) << 8) | + ((scaler3_cfg->init_phase_x[1] & 0x3F) << 16) | + ((scaler3_cfg->init_phase_y[1] & 0x3F) << 24); + DPU_REG_WRITE(c, QSEED3_PHASE_INIT + scaler_offset, phase_init); + } else { + DPU_REG_WRITE(c, QSEED3_PHASE_INIT_Y_H + scaler_offset, + scaler3_cfg->init_phase_x[0] & 0x1FFFFF); + DPU_REG_WRITE(c, QSEED3_PHASE_INIT_Y_V + scaler_offset, + scaler3_cfg->init_phase_y[0] & 0x1FFFFF); + DPU_REG_WRITE(c, QSEED3_PHASE_INIT_UV_H + scaler_offset, + scaler3_cfg->init_phase_x[1] & 0x1FFFFF); + DPU_REG_WRITE(c, QSEED3_PHASE_INIT_UV_V + scaler_offset, + scaler3_cfg->init_phase_y[1] & 0x1FFFFF); + } + + DPU_REG_WRITE(c, QSEED3_PHASE_STEP_Y_H + scaler_offset, + scaler3_cfg->phase_step_x[0] & 0xFFFFFF); + + DPU_REG_WRITE(c, QSEED3_PHASE_STEP_Y_V + scaler_offset, + scaler3_cfg->phase_step_y[0] & 0xFFFFFF); + + DPU_REG_WRITE(c, QSEED3_PHASE_STEP_UV_H + scaler_offset, + scaler3_cfg->phase_step_x[1] & 0xFFFFFF); + + DPU_REG_WRITE(c, QSEED3_PHASE_STEP_UV_V + scaler_offset, + scaler3_cfg->phase_step_y[1] & 0xFFFFFF); + + DPU_REG_WRITE(c, QSEED3_PRELOAD + scaler_offset, preload); + + DPU_REG_WRITE(c, QSEED3_SRC_SIZE_Y_RGB_A + scaler_offset, src_y_rgb); + + DPU_REG_WRITE(c, QSEED3_SRC_SIZE_UV + scaler_offset, src_uv); + + DPU_REG_WRITE(c, QSEED3_DST_SIZE + scaler_offset, dst); + +end: + if (format && !DPU_FORMAT_IS_DX(format)) + op_mode |= BIT(14); + + if (format && format->alpha_enable) { + op_mode |= BIT(10); + if (scaler_version == 0x1002) + op_mode |= (scaler3_cfg->alpha_filter_cfg & 0x1) << 30; + else + op_mode |= (scaler3_cfg->alpha_filter_cfg & 0x3) << 29; + } + + DPU_REG_WRITE(c, QSEED3_OP_MODE + scaler_offset, op_mode); +} + +u32 dpu_hw_get_scaler3_ver(struct dpu_hw_blk_reg_map *c, + u32 scaler_offset) +{ + return DPU_REG_READ(c, QSEED3_HW_VERSION + scaler_offset); +} + +void dpu_hw_csc_setup(struct dpu_hw_blk_reg_map *c, + u32 csc_reg_off, + struct dpu_csc_cfg *data, bool csc10) +{ + static const u32 matrix_shift = 7; + u32 clamp_shift = csc10 ? 16 : 8; + u32 val; + + /* matrix coeff - convert S15.16 to S4.9 */ + val = ((data->csc_mv[0] >> matrix_shift) & 0x1FFF) | + (((data->csc_mv[1] >> matrix_shift) & 0x1FFF) << 16); + DPU_REG_WRITE(c, csc_reg_off, val); + val = ((data->csc_mv[2] >> matrix_shift) & 0x1FFF) | + (((data->csc_mv[3] >> matrix_shift) & 0x1FFF) << 16); + DPU_REG_WRITE(c, csc_reg_off + 0x4, val); + val = ((data->csc_mv[4] >> matrix_shift) & 0x1FFF) | + (((data->csc_mv[5] >> matrix_shift) & 0x1FFF) << 16); + DPU_REG_WRITE(c, csc_reg_off + 0x8, val); + val = ((data->csc_mv[6] >> matrix_shift) & 0x1FFF) | + (((data->csc_mv[7] >> matrix_shift) & 0x1FFF) << 16); + DPU_REG_WRITE(c, csc_reg_off + 0xc, val); + val = (data->csc_mv[8] >> matrix_shift) & 0x1FFF; + DPU_REG_WRITE(c, csc_reg_off + 0x10, val); + + /* Pre clamp */ + val = (data->csc_pre_lv[0] << clamp_shift) | data->csc_pre_lv[1]; + DPU_REG_WRITE(c, csc_reg_off + 0x14, val); + val = (data->csc_pre_lv[2] << clamp_shift) | data->csc_pre_lv[3]; + DPU_REG_WRITE(c, csc_reg_off + 0x18, val); + val = (data->csc_pre_lv[4] << clamp_shift) | data->csc_pre_lv[5]; + DPU_REG_WRITE(c, csc_reg_off + 0x1c, val); + + /* Post clamp */ + val = (data->csc_post_lv[0] << clamp_shift) | data->csc_post_lv[1]; + DPU_REG_WRITE(c, csc_reg_off + 0x20, val); + val = (data->csc_post_lv[2] << clamp_shift) | data->csc_post_lv[3]; + DPU_REG_WRITE(c, csc_reg_off + 0x24, val); + val = (data->csc_post_lv[4] << clamp_shift) | data->csc_post_lv[5]; + DPU_REG_WRITE(c, csc_reg_off + 0x28, val); + + /* Pre-Bias */ + DPU_REG_WRITE(c, csc_reg_off + 0x2c, data->csc_pre_bv[0]); + DPU_REG_WRITE(c, csc_reg_off + 0x30, data->csc_pre_bv[1]); + DPU_REG_WRITE(c, csc_reg_off + 0x34, data->csc_pre_bv[2]); + + /* Post-Bias */ + DPU_REG_WRITE(c, csc_reg_off + 0x38, data->csc_post_bv[0]); + DPU_REG_WRITE(c, csc_reg_off + 0x3c, data->csc_post_bv[1]); + DPU_REG_WRITE(c, csc_reg_off + 0x40, data->csc_post_bv[2]); +} + +/** + * _dpu_copy_formats - copy formats from src_list to dst_list + * @dst_list: pointer to destination list where to copy formats + * @dst_list_size: size of destination list + * @dst_list_pos: starting position on the list where to copy formats + * @src_list: pointer to source list where to copy formats from + * @src_list_size: size of source list + * Return: number of elements populated + */ +uint32_t dpu_copy_formats( + struct dpu_format_extended *dst_list, + uint32_t dst_list_size, + uint32_t dst_list_pos, + const struct dpu_format_extended *src_list, + uint32_t src_list_size) +{ + uint32_t cur_pos, i; + + if (!dst_list || !src_list || (dst_list_pos >= (dst_list_size - 1))) + return 0; + + for (i = 0, cur_pos = dst_list_pos; + (cur_pos < (dst_list_size - 1)) && (i < src_list_size) + && src_list[i].fourcc_format; ++i, ++cur_pos) + dst_list[cur_pos] = src_list[i]; + + dst_list[cur_pos].fourcc_format = 0; + + return i; +} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h new file mode 100644 index 0000000000000..42f1b228d342b --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h @@ -0,0 +1,358 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef _DPU_HW_UTIL_H +#define _DPU_HW_UTIL_H + +#include <linux/io.h> +#include <linux/slab.h> +#include "dpu_hw_mdss.h" + +#define REG_MASK(n) ((BIT(n)) - 1) +struct dpu_format_extended; + +/* + * This is the common struct maintained by each sub block + * for mapping the register offsets in this block to the + * absoulute IO address + * @base_off: mdp register mapped offset + * @blk_off: pipe offset relative to mdss offset + * @length length of register block offset + * @xin_id xin id + * @hwversion mdss hw version number + */ +struct dpu_hw_blk_reg_map { + void __iomem *base_off; + u32 blk_off; + u32 length; + u32 xin_id; + u32 hwversion; + u32 log_mask; +}; + +/** + * struct dpu_hw_scaler3_de_cfg : QSEEDv3 detail enhancer configuration + * @enable: detail enhancer enable/disable + * @sharpen_level1: sharpening strength for noise + * @sharpen_level2: sharpening strength for signal + * @ clip: clip shift + * @ limit: limit value + * @ thr_quiet: quiet threshold + * @ thr_dieout: dieout threshold + * @ thr_high: low threshold + * @ thr_high: high threshold + * @ prec_shift: precision shift + * @ adjust_a: A-coefficients for mapping curve + * @ adjust_b: B-coefficients for mapping curve + * @ adjust_c: C-coefficients for mapping curve + */ +struct dpu_hw_scaler3_de_cfg { + u32 enable; + int16_t sharpen_level1; + int16_t sharpen_level2; + uint16_t clip; + uint16_t limit; + uint16_t thr_quiet; + uint16_t thr_dieout; + uint16_t thr_low; + uint16_t thr_high; + uint16_t prec_shift; + int16_t adjust_a[DPU_MAX_DE_CURVES]; + int16_t adjust_b[DPU_MAX_DE_CURVES]; + int16_t adjust_c[DPU_MAX_DE_CURVES]; +}; + + +/** + * struct dpu_hw_scaler3_cfg : QSEEDv3 configuration + * @enable: scaler enable + * @dir_en: direction detection block enable + * @ init_phase_x: horizontal initial phase + * @ phase_step_x: horizontal phase step + * @ init_phase_y: vertical initial phase + * @ phase_step_y: vertical phase step + * @ preload_x: horizontal preload value + * @ preload_y: vertical preload value + * @ src_width: source width + * @ src_height: source height + * @ dst_width: destination width + * @ dst_height: destination height + * @ y_rgb_filter_cfg: y/rgb plane filter configuration + * @ uv_filter_cfg: uv plane filter configuration + * @ alpha_filter_cfg: alpha filter configuration + * @ blend_cfg: blend coefficients configuration + * @ lut_flag: scaler LUT update flags + * 0x1 swap LUT bank + * 0x2 update 2D filter LUT + * 0x4 update y circular filter LUT + * 0x8 update uv circular filter LUT + * 0x10 update y separable filter LUT + * 0x20 update uv separable filter LUT + * @ dir_lut_idx: 2D filter LUT index + * @ y_rgb_cir_lut_idx: y circular filter LUT index + * @ uv_cir_lut_idx: uv circular filter LUT index + * @ y_rgb_sep_lut_idx: y circular filter LUT index + * @ uv_sep_lut_idx: uv separable filter LUT index + * @ dir_lut: pointer to 2D LUT + * @ cir_lut: pointer to circular filter LUT + * @ sep_lut: pointer to separable filter LUT + * @ de: detail enhancer configuration + */ +struct dpu_hw_scaler3_cfg { + u32 enable; + u32 dir_en; + int32_t init_phase_x[DPU_MAX_PLANES]; + int32_t phase_step_x[DPU_MAX_PLANES]; + int32_t init_phase_y[DPU_MAX_PLANES]; + int32_t phase_step_y[DPU_MAX_PLANES]; + + u32 preload_x[DPU_MAX_PLANES]; + u32 preload_y[DPU_MAX_PLANES]; + u32 src_width[DPU_MAX_PLANES]; + u32 src_height[DPU_MAX_PLANES]; + + u32 dst_width; + u32 dst_height; + + u32 y_rgb_filter_cfg; + u32 uv_filter_cfg; + u32 alpha_filter_cfg; + u32 blend_cfg; + + u32 lut_flag; + u32 dir_lut_idx; + + u32 y_rgb_cir_lut_idx; + u32 uv_cir_lut_idx; + u32 y_rgb_sep_lut_idx; + u32 uv_sep_lut_idx; + u32 *dir_lut; + size_t dir_len; + u32 *cir_lut; + size_t cir_len; + u32 *sep_lut; + size_t sep_len; + + /* + * Detail enhancer settings + */ + struct dpu_hw_scaler3_de_cfg de; +}; + +struct dpu_hw_scaler3_lut_cfg { + bool is_configured; + u32 *dir_lut; + size_t dir_len; + u32 *cir_lut; + size_t cir_len; + u32 *sep_lut; + size_t sep_len; +}; + +/** + * struct dpu_drm_pix_ext_v1 - version 1 of pixel ext structure + * @num_ext_pxls_lr: Number of total horizontal pixels + * @num_ext_pxls_tb: Number of total vertical lines + * @left_ftch: Number of extra pixels to overfetch from left + * @right_ftch: Number of extra pixels to overfetch from right + * @top_ftch: Number of extra lines to overfetch from top + * @btm_ftch: Number of extra lines to overfetch from bottom + * @left_rpt: Number of extra pixels to repeat from left + * @right_rpt: Number of extra pixels to repeat from right + * @top_rpt: Number of extra lines to repeat from top + * @btm_rpt: Number of extra lines to repeat from bottom + */ +struct dpu_drm_pix_ext_v1 { + /* + * Number of pixels ext in left, right, top and bottom direction + * for all color components. + */ + int32_t num_ext_pxls_lr[DPU_MAX_PLANES]; + int32_t num_ext_pxls_tb[DPU_MAX_PLANES]; + + /* + * Number of pixels needs to be overfetched in left, right, top + * and bottom directions from source image for scaling. + */ + int32_t left_ftch[DPU_MAX_PLANES]; + int32_t right_ftch[DPU_MAX_PLANES]; + int32_t top_ftch[DPU_MAX_PLANES]; + int32_t btm_ftch[DPU_MAX_PLANES]; + /* + * Number of pixels needs to be repeated in left, right, top and + * bottom directions for scaling. + */ + int32_t left_rpt[DPU_MAX_PLANES]; + int32_t right_rpt[DPU_MAX_PLANES]; + int32_t top_rpt[DPU_MAX_PLANES]; + int32_t btm_rpt[DPU_MAX_PLANES]; + +}; + +/** + * struct dpu_drm_de_v1 - version 1 of detail enhancer structure + * @enable: Enables/disables detail enhancer + * @sharpen_level1: Sharpening strength for noise + * @sharpen_level2: Sharpening strength for context + * @clip: Clip coefficient + * @limit: Detail enhancer limit factor + * @thr_quiet: Quite zone threshold + * @thr_dieout: Die-out zone threshold + * @thr_low: Linear zone left threshold + * @thr_high: Linear zone right threshold + * @prec_shift: Detail enhancer precision + * @adjust_a: Mapping curves A coefficients + * @adjust_b: Mapping curves B coefficients + * @adjust_c: Mapping curves C coefficients + */ +struct dpu_drm_de_v1 { + uint32_t enable; + int16_t sharpen_level1; + int16_t sharpen_level2; + uint16_t clip; + uint16_t limit; + uint16_t thr_quiet; + uint16_t thr_dieout; + uint16_t thr_low; + uint16_t thr_high; + uint16_t prec_shift; + int16_t adjust_a[DPU_MAX_DE_CURVES]; + int16_t adjust_b[DPU_MAX_DE_CURVES]; + int16_t adjust_c[DPU_MAX_DE_CURVES]; +}; + +/** + * struct dpu_drm_scaler_v2 - version 2 of struct dpu_drm_scaler + * @enable: Scaler enable + * @dir_en: Detail enhancer enable + * @pe: Pixel extension settings + * @horz_decimate: Horizontal decimation factor + * @vert_decimate: Vertical decimation factor + * @init_phase_x: Initial scaler phase values for x + * @phase_step_x: Phase step values for x + * @init_phase_y: Initial scaler phase values for y + * @phase_step_y: Phase step values for y + * @preload_x: Horizontal preload value + * @preload_y: Vertical preload value + * @src_width: Source width + * @src_height: Source height + * @dst_width: Destination width + * @dst_height: Destination height + * @y_rgb_filter_cfg: Y/RGB plane filter configuration + * @uv_filter_cfg: UV plane filter configuration + * @alpha_filter_cfg: Alpha filter configuration + * @blend_cfg: Selection of blend coefficients + * @lut_flag: LUT configuration flags + * @dir_lut_idx: 2d 4x4 LUT index + * @y_rgb_cir_lut_idx: Y/RGB circular LUT index + * @uv_cir_lut_idx: UV circular LUT index + * @y_rgb_sep_lut_idx: Y/RGB separable LUT index + * @uv_sep_lut_idx: UV separable LUT index + * @de: Detail enhancer settings + */ +struct dpu_drm_scaler_v2 { + /* + * General definitions + */ + uint32_t enable; + uint32_t dir_en; + + /* + * Pix ext settings + */ + struct dpu_drm_pix_ext_v1 pe; + + /* + * Decimation settings + */ + uint32_t horz_decimate; + uint32_t vert_decimate; + + /* + * Phase settings + */ + int32_t init_phase_x[DPU_MAX_PLANES]; + int32_t phase_step_x[DPU_MAX_PLANES]; + int32_t init_phase_y[DPU_MAX_PLANES]; + int32_t phase_step_y[DPU_MAX_PLANES]; + + uint32_t preload_x[DPU_MAX_PLANES]; + uint32_t preload_y[DPU_MAX_PLANES]; + uint32_t src_width[DPU_MAX_PLANES]; + uint32_t src_height[DPU_MAX_PLANES]; + + uint32_t dst_width; + uint32_t dst_height; + + uint32_t y_rgb_filter_cfg; + uint32_t uv_filter_cfg; + uint32_t alpha_filter_cfg; + uint32_t blend_cfg; + + uint32_t lut_flag; + uint32_t dir_lut_idx; + + /* for Y(RGB) and UV planes*/ + uint32_t y_rgb_cir_lut_idx; + uint32_t uv_cir_lut_idx; + uint32_t y_rgb_sep_lut_idx; + uint32_t uv_sep_lut_idx; + + /* + * Detail enhancer settings + */ + struct dpu_drm_de_v1 de; +}; + + +u32 *dpu_hw_util_get_log_mask_ptr(void); + +void dpu_reg_write(struct dpu_hw_blk_reg_map *c, + u32 reg_off, + u32 val, + const char *name); +int dpu_reg_read(struct dpu_hw_blk_reg_map *c, u32 reg_off); + +#define DPU_REG_WRITE(c, off, val) dpu_reg_write(c, off, val, #off) +#define DPU_REG_READ(c, off) dpu_reg_read(c, off) + +#define MISR_FRAME_COUNT_MASK 0xFF +#define MISR_CTRL_ENABLE BIT(8) +#define MISR_CTRL_STATUS BIT(9) +#define MISR_CTRL_STATUS_CLEAR BIT(10) +#define INTF_MISR_CTRL_FREE_RUN_MASK BIT(31) + +void *dpu_hw_util_get_dir(void); + +void dpu_set_scaler_v2(struct dpu_hw_scaler3_cfg *cfg, + const struct dpu_drm_scaler_v2 *scale_v2); + +void dpu_hw_setup_scaler3(struct dpu_hw_blk_reg_map *c, + struct dpu_hw_scaler3_cfg *scaler3_cfg, + u32 scaler_offset, u32 scaler_version, + const struct dpu_format *format); + +u32 dpu_hw_get_scaler3_ver(struct dpu_hw_blk_reg_map *c, + u32 scaler_offset); + +void dpu_hw_csc_setup(struct dpu_hw_blk_reg_map *c, + u32 csc_reg_off, + struct dpu_csc_cfg *data, bool csc10); + +uint32_t dpu_copy_formats( + struct dpu_format_extended *dst_list, + uint32_t dst_list_size, + uint32_t dst_list_pos, + const struct dpu_format_extended *src_list, + uint32_t src_list_size); + +#endif /* _DPU_HW_UTIL_H */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.c new file mode 100644 index 0000000000000..d43905525f926 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.c @@ -0,0 +1,275 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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 "dpu_hwio.h" +#include "dpu_hw_catalog.h" +#include "dpu_hw_vbif.h" +#include "dpu_dbg.h" + +#define VBIF_VERSION 0x0000 +#define VBIF_CLK_FORCE_CTRL0 0x0008 +#define VBIF_CLK_FORCE_CTRL1 0x000C +#define VBIF_QOS_REMAP_00 0x0020 +#define VBIF_QOS_REMAP_01 0x0024 +#define VBIF_QOS_REMAP_10 0x0028 +#define VBIF_QOS_REMAP_11 0x002C +#define VBIF_WRITE_GATHER_EN 0x00AC +#define VBIF_IN_RD_LIM_CONF0 0x00B0 +#define VBIF_IN_RD_LIM_CONF1 0x00B4 +#define VBIF_IN_RD_LIM_CONF2 0x00B8 +#define VBIF_IN_WR_LIM_CONF0 0x00C0 +#define VBIF_IN_WR_LIM_CONF1 0x00C4 +#define VBIF_IN_WR_LIM_CONF2 0x00C8 +#define VBIF_OUT_RD_LIM_CONF0 0x00D0 +#define VBIF_OUT_WR_LIM_CONF0 0x00D4 +#define VBIF_OUT_AXI_AMEMTYPE_CONF0 0x0160 +#define VBIF_OUT_AXI_AMEMTYPE_CONF1 0x0164 +#define VBIF_XIN_PND_ERR 0x0190 +#define VBIF_XIN_SRC_ERR 0x0194 +#define VBIF_XIN_CLR_ERR 0x019C +#define VBIF_XIN_HALT_CTRL0 0x0200 +#define VBIF_XIN_HALT_CTRL1 0x0204 +#define VBIF_XINL_QOS_RP_REMAP_000 0x0550 +#define VBIF_XINL_QOS_LVL_REMAP_000 0x0590 + +static void dpu_hw_clear_errors(struct dpu_hw_vbif *vbif, + u32 *pnd_errors, u32 *src_errors) +{ + struct dpu_hw_blk_reg_map *c; + u32 pnd, src; + + if (!vbif) + return; + c = &vbif->hw; + pnd = DPU_REG_READ(c, VBIF_XIN_PND_ERR); + src = DPU_REG_READ(c, VBIF_XIN_SRC_ERR); + + if (pnd_errors) + *pnd_errors = pnd; + if (src_errors) + *src_errors = src; + + DPU_REG_WRITE(c, VBIF_XIN_CLR_ERR, pnd | src); +} + +static void dpu_hw_set_mem_type(struct dpu_hw_vbif *vbif, + u32 xin_id, u32 value) +{ + struct dpu_hw_blk_reg_map *c; + u32 reg_off; + u32 bit_off; + u32 reg_val; + + /* + * Assume 4 bits per bit field, 8 fields per 32-bit register so + * 16 bit fields maximum across two registers + */ + if (!vbif || xin_id >= MAX_XIN_COUNT || xin_id >= 16) + return; + + c = &vbif->hw; + + if (xin_id >= 8) { + xin_id -= 8; + reg_off = VBIF_OUT_AXI_AMEMTYPE_CONF1; + } else { + reg_off = VBIF_OUT_AXI_AMEMTYPE_CONF0; + } + bit_off = (xin_id & 0x7) * 4; + reg_val = DPU_REG_READ(c, reg_off); + reg_val &= ~(0x7 << bit_off); + reg_val |= (value & 0x7) << bit_off; + DPU_REG_WRITE(c, reg_off, reg_val); +} + +static void dpu_hw_set_limit_conf(struct dpu_hw_vbif *vbif, + u32 xin_id, bool rd, u32 limit) +{ + struct dpu_hw_blk_reg_map *c = &vbif->hw; + u32 reg_val; + u32 reg_off; + u32 bit_off; + + if (rd) + reg_off = VBIF_IN_RD_LIM_CONF0; + else + reg_off = VBIF_IN_WR_LIM_CONF0; + + reg_off += (xin_id / 4) * 4; + bit_off = (xin_id % 4) * 8; + reg_val = DPU_REG_READ(c, reg_off); + reg_val &= ~(0xFF << bit_off); + reg_val |= (limit) << bit_off; + DPU_REG_WRITE(c, reg_off, reg_val); +} + +static u32 dpu_hw_get_limit_conf(struct dpu_hw_vbif *vbif, + u32 xin_id, bool rd) +{ + struct dpu_hw_blk_reg_map *c = &vbif->hw; + u32 reg_val; + u32 reg_off; + u32 bit_off; + u32 limit; + + if (rd) + reg_off = VBIF_IN_RD_LIM_CONF0; + else + reg_off = VBIF_IN_WR_LIM_CONF0; + + reg_off += (xin_id / 4) * 4; + bit_off = (xin_id % 4) * 8; + reg_val = DPU_REG_READ(c, reg_off); + limit = (reg_val >> bit_off) & 0xFF; + + return limit; +} + +static void dpu_hw_set_halt_ctrl(struct dpu_hw_vbif *vbif, + u32 xin_id, bool enable) +{ + struct dpu_hw_blk_reg_map *c = &vbif->hw; + u32 reg_val; + + reg_val = DPU_REG_READ(c, VBIF_XIN_HALT_CTRL0); + + if (enable) + reg_val |= BIT(xin_id); + else + reg_val &= ~BIT(xin_id); + + DPU_REG_WRITE(c, VBIF_XIN_HALT_CTRL0, reg_val); +} + +static bool dpu_hw_get_halt_ctrl(struct dpu_hw_vbif *vbif, + u32 xin_id) +{ + struct dpu_hw_blk_reg_map *c = &vbif->hw; + u32 reg_val; + + reg_val = DPU_REG_READ(c, VBIF_XIN_HALT_CTRL1); + + return (reg_val & BIT(xin_id)) ? true : false; +} + +static void dpu_hw_set_qos_remap(struct dpu_hw_vbif *vbif, + u32 xin_id, u32 level, u32 remap_level) +{ + struct dpu_hw_blk_reg_map *c; + u32 reg_val, reg_val_lvl, mask, reg_high, reg_shift; + + if (!vbif) + return; + + c = &vbif->hw; + + reg_high = ((xin_id & 0x8) >> 3) * 4 + (level * 8); + reg_shift = (xin_id & 0x7) * 4; + + reg_val = DPU_REG_READ(c, VBIF_XINL_QOS_RP_REMAP_000 + reg_high); + reg_val_lvl = DPU_REG_READ(c, VBIF_XINL_QOS_LVL_REMAP_000 + reg_high); + + mask = 0x7 << reg_shift; + + reg_val &= ~mask; + reg_val |= (remap_level << reg_shift) & mask; + + reg_val_lvl &= ~mask; + reg_val_lvl |= (remap_level << reg_shift) & mask; + + DPU_REG_WRITE(c, VBIF_XINL_QOS_RP_REMAP_000 + reg_high, reg_val); + DPU_REG_WRITE(c, VBIF_XINL_QOS_LVL_REMAP_000 + reg_high, reg_val_lvl); +} + +static void dpu_hw_set_write_gather_en(struct dpu_hw_vbif *vbif, u32 xin_id) +{ + struct dpu_hw_blk_reg_map *c; + u32 reg_val; + + if (!vbif || xin_id >= MAX_XIN_COUNT) + return; + + c = &vbif->hw; + + reg_val = DPU_REG_READ(c, VBIF_WRITE_GATHER_EN); + reg_val |= BIT(xin_id); + DPU_REG_WRITE(c, VBIF_WRITE_GATHER_EN, reg_val); +} + +static void _setup_vbif_ops(struct dpu_hw_vbif_ops *ops, + unsigned long cap) +{ + ops->set_limit_conf = dpu_hw_set_limit_conf; + ops->get_limit_conf = dpu_hw_get_limit_conf; + ops->set_halt_ctrl = dpu_hw_set_halt_ctrl; + ops->get_halt_ctrl = dpu_hw_get_halt_ctrl; + if (test_bit(DPU_VBIF_QOS_REMAP, &cap)) + ops->set_qos_remap = dpu_hw_set_qos_remap; + ops->set_mem_type = dpu_hw_set_mem_type; + ops->clear_errors = dpu_hw_clear_errors; + ops->set_write_gather_en = dpu_hw_set_write_gather_en; +} + +static const struct dpu_vbif_cfg *_top_offset(enum dpu_vbif vbif, + const struct dpu_mdss_cfg *m, + void __iomem *addr, + struct dpu_hw_blk_reg_map *b) +{ + int i; + + for (i = 0; i < m->vbif_count; i++) { + if (vbif == m->vbif[i].id) { + b->base_off = addr; + b->blk_off = m->vbif[i].base; + b->length = m->vbif[i].len; + b->hwversion = m->hwversion; + b->log_mask = DPU_DBG_MASK_VBIF; + return &m->vbif[i]; + } + } + + return ERR_PTR(-EINVAL); +} + +struct dpu_hw_vbif *dpu_hw_vbif_init(enum dpu_vbif idx, + void __iomem *addr, + const struct dpu_mdss_cfg *m) +{ + struct dpu_hw_vbif *c; + const struct dpu_vbif_cfg *cfg; + + c = kzalloc(sizeof(*c), GFP_KERNEL); + if (!c) + return ERR_PTR(-ENOMEM); + + cfg = _top_offset(idx, m, addr, &c->hw); + if (IS_ERR_OR_NULL(cfg)) { + kfree(c); + return ERR_PTR(-EINVAL); + } + + /* + * Assign ops + */ + c->idx = idx; + c->cap = cfg; + _setup_vbif_ops(&c->ops, c->cap->features); + + /* no need to register sub-range in dpu dbg, dump entire vbif io base */ + + return c; +} + +void dpu_hw_vbif_destroy(struct dpu_hw_vbif *vbif) +{ + kfree(vbif); +} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h new file mode 100644 index 0000000000000..471ff673c0452 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h @@ -0,0 +1,128 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef _DPU_HW_VBIF_H +#define _DPU_HW_VBIF_H + +#include "dpu_hw_catalog.h" +#include "dpu_hw_mdss.h" +#include "dpu_hw_util.h" + +struct dpu_hw_vbif; + +/** + * struct dpu_hw_vbif_ops : Interface to the VBIF hardware driver functions + * Assumption is these functions will be called after clocks are enabled + */ +struct dpu_hw_vbif_ops { + /** + * set_limit_conf - set transaction limit config + * @vbif: vbif context driver + * @xin_id: client interface identifier + * @rd: true for read limit; false for write limit + * @limit: outstanding transaction limit + */ + void (*set_limit_conf)(struct dpu_hw_vbif *vbif, + u32 xin_id, bool rd, u32 limit); + + /** + * get_limit_conf - get transaction limit config + * @vbif: vbif context driver + * @xin_id: client interface identifier + * @rd: true for read limit; false for write limit + * @return: outstanding transaction limit + */ + u32 (*get_limit_conf)(struct dpu_hw_vbif *vbif, + u32 xin_id, bool rd); + + /** + * set_halt_ctrl - set halt control + * @vbif: vbif context driver + * @xin_id: client interface identifier + * @enable: halt control enable + */ + void (*set_halt_ctrl)(struct dpu_hw_vbif *vbif, + u32 xin_id, bool enable); + + /** + * get_halt_ctrl - get halt control + * @vbif: vbif context driver + * @xin_id: client interface identifier + * @return: halt control enable + */ + bool (*get_halt_ctrl)(struct dpu_hw_vbif *vbif, + u32 xin_id); + + /** + * set_qos_remap - set QoS priority remap + * @vbif: vbif context driver + * @xin_id: client interface identifier + * @level: priority level + * @remap_level: remapped level + */ + void (*set_qos_remap)(struct dpu_hw_vbif *vbif, + u32 xin_id, u32 level, u32 remap_level); + + /** + * set_mem_type - set memory type + * @vbif: vbif context driver + * @xin_id: client interface identifier + * @value: memory type value + */ + void (*set_mem_type)(struct dpu_hw_vbif *vbif, + u32 xin_id, u32 value); + + /** + * clear_errors - clear any vbif errors + * This function clears any detected pending/source errors + * on the VBIF interface, and optionally returns the detected + * error mask(s). + * @vbif: vbif context driver + * @pnd_errors: pointer to pending error reporting variable + * @src_errors: pointer to source error reporting variable + */ + void (*clear_errors)(struct dpu_hw_vbif *vbif, + u32 *pnd_errors, u32 *src_errors); + + /** + * set_write_gather_en - set write_gather enable + * @vbif: vbif context driver + * @xin_id: client interface identifier + */ + void (*set_write_gather_en)(struct dpu_hw_vbif *vbif, u32 xin_id); +}; + +struct dpu_hw_vbif { + /* base */ + struct dpu_hw_blk_reg_map hw; + + /* vbif */ + enum dpu_vbif idx; + const struct dpu_vbif_cfg *cap; + + /* ops */ + struct dpu_hw_vbif_ops ops; +}; + +/** + * dpu_hw_vbif_init - initializes the vbif driver for the passed interface idx + * @idx: Interface index for which driver object is required + * @addr: Mapped register io address of MDSS + * @m: Pointer to mdss catalog data + */ +struct dpu_hw_vbif *dpu_hw_vbif_init(enum dpu_vbif idx, + void __iomem *addr, + const struct dpu_mdss_cfg *m); + +void dpu_hw_vbif_destroy(struct dpu_hw_vbif *vbif); + +#endif /*_DPU_HW_VBIF_H */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hwio.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hwio.h new file mode 100644 index 0000000000000..5b2bc9b65b150 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hwio.h @@ -0,0 +1,56 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef _DPU_HWIO_H +#define _DPU_HWIO_H + +#include "dpu_hw_util.h" + +/** + * MDP TOP block Register and bit fields and defines + */ +#define DISP_INTF_SEL 0x004 +#define INTR_EN 0x010 +#define INTR_STATUS 0x014 +#define INTR_CLEAR 0x018 +#define INTR2_EN 0x008 +#define INTR2_STATUS 0x00c +#define INTR2_CLEAR 0x02c +#define HIST_INTR_EN 0x01c +#define HIST_INTR_STATUS 0x020 +#define HIST_INTR_CLEAR 0x024 +#define INTF_INTR_EN 0x1C0 +#define INTF_INTR_STATUS 0x1C4 +#define INTF_INTR_CLEAR 0x1C8 +#define SPLIT_DISPLAY_EN 0x2F4 +#define SPLIT_DISPLAY_UPPER_PIPE_CTRL 0x2F8 +#define DSPP_IGC_COLOR0_RAM_LUTN 0x300 +#define DSPP_IGC_COLOR1_RAM_LUTN 0x304 +#define DSPP_IGC_COLOR2_RAM_LUTN 0x308 +#define HW_EVENTS_CTL 0x37C +#define CLK_CTRL3 0x3A8 +#define CLK_STATUS3 0x3AC +#define CLK_CTRL4 0x3B0 +#define CLK_STATUS4 0x3B4 +#define CLK_CTRL5 0x3B8 +#define CLK_STATUS5 0x3BC +#define CLK_CTRL7 0x3D0 +#define CLK_STATUS7 0x3D4 +#define SPLIT_DISPLAY_LOWER_PIPE_CTRL 0x3F0 +#define SPLIT_DISPLAY_TE_LINE_INTERVAL 0x3F4 +#define INTF_SW_RESET_MASK 0x3FC +#define HDMI_DP_CORE_SELECT 0x408 +#define MDP_OUT_CTL_0 0x410 +#define MDP_VSYNC_SEL 0x414 +#define DCE_SEL 0x450 + +#endif /*_DPU_HWIO_H */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c new file mode 100644 index 0000000000000..8d907faa7496a --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c @@ -0,0 +1,204 @@ +/* Copyright (c) 2012-2015, 2017-2018, The Linux Foundation. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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 <linux/clk.h> +#include <linux/clk/clk-conf.h> +#include <linux/err.h> +#include <linux/delay.h> + +#include "dpu_io_util.h" + +void msm_dss_put_clk(struct dss_clk *clk_arry, int num_clk) +{ + int i; + + for (i = num_clk - 1; i >= 0; i--) { + if (clk_arry[i].clk) + clk_put(clk_arry[i].clk); + clk_arry[i].clk = NULL; + } +} + +int msm_dss_get_clk(struct device *dev, struct dss_clk *clk_arry, int num_clk) +{ + int i, rc = 0; + + for (i = 0; i < num_clk; i++) { + clk_arry[i].clk = clk_get(dev, clk_arry[i].clk_name); + rc = PTR_RET(clk_arry[i].clk); + if (rc) { + DEV_ERR("%pS->%s: '%s' get failed. rc=%d\n", + __builtin_return_address(0), __func__, + clk_arry[i].clk_name, rc); + goto error; + } + } + + return rc; + +error: + for (i--; i >= 0; i--) { + if (clk_arry[i].clk) + clk_put(clk_arry[i].clk); + clk_arry[i].clk = NULL; + } + + return rc; +} + +int msm_dss_clk_set_rate(struct dss_clk *clk_arry, int num_clk) +{ + int i, rc = 0; + + for (i = 0; i < num_clk; i++) { + if (clk_arry[i].clk) { + if (clk_arry[i].type != DSS_CLK_AHB) { + DEV_DBG("%pS->%s: '%s' rate %ld\n", + __builtin_return_address(0), __func__, + clk_arry[i].clk_name, + clk_arry[i].rate); + rc = clk_set_rate(clk_arry[i].clk, + clk_arry[i].rate); + if (rc) { + DEV_ERR("%pS->%s: %s failed. rc=%d\n", + __builtin_return_address(0), + __func__, + clk_arry[i].clk_name, rc); + break; + } + } + } else { + DEV_ERR("%pS->%s: '%s' is not available\n", + __builtin_return_address(0), __func__, + clk_arry[i].clk_name); + rc = -EPERM; + break; + } + } + + return rc; +} + +int msm_dss_enable_clk(struct dss_clk *clk_arry, int num_clk, int enable) +{ + int i, rc = 0; + + if (enable) { + for (i = 0; i < num_clk; i++) { + DEV_DBG("%pS->%s: enable '%s'\n", + __builtin_return_address(0), __func__, + clk_arry[i].clk_name); + if (clk_arry[i].clk) { + rc = clk_prepare_enable(clk_arry[i].clk); + if (rc) + DEV_ERR("%pS->%s: %s en fail. rc=%d\n", + __builtin_return_address(0), + __func__, + clk_arry[i].clk_name, rc); + } else { + DEV_ERR("%pS->%s: '%s' is not available\n", + __builtin_return_address(0), __func__, + clk_arry[i].clk_name); + rc = -EPERM; + } + + if (rc) { + msm_dss_enable_clk(&clk_arry[i], + i, false); + break; + } + } + } else { + for (i = num_clk - 1; i >= 0; i--) { + DEV_DBG("%pS->%s: disable '%s'\n", + __builtin_return_address(0), __func__, + clk_arry[i].clk_name); + + if (clk_arry[i].clk) + clk_disable_unprepare(clk_arry[i].clk); + else + DEV_ERR("%pS->%s: '%s' is not available\n", + __builtin_return_address(0), __func__, + clk_arry[i].clk_name); + } + } + + return rc; +} + +int msm_dss_parse_clock(struct platform_device *pdev, + struct dss_module_power *mp) +{ + u32 i, rc = 0; + const char *clock_name; + int num_clk = 0; + + if (!pdev || !mp) + return -EINVAL; + + mp->num_clk = 0; + num_clk = of_property_count_strings(pdev->dev.of_node, + "assigned-clock-names"); + if (num_clk <= 0) { + pr_debug("clocks are not defined\n"); + return 0; + } + + mp->clk_config = devm_kzalloc(&pdev->dev, + sizeof(struct dss_clk) * num_clk, + GFP_KERNEL); + if (!mp->clk_config) + return -ENOMEM; + + for (i = 0; i < num_clk; i++) { + rc = of_property_read_string_index(pdev->dev.of_node, + "assigned-clock-names", i, + &clock_name); + if (rc) { + dev_err(&pdev->dev, "Failed to get clock name for %d\n", + i); + break; + } + strlcpy(mp->clk_config[i].clk_name, clock_name, + sizeof(mp->clk_config[i].clk_name)); + + mp->clk_config[i].type = DSS_CLK_AHB; + } + + rc = msm_dss_get_clk(&pdev->dev, mp->clk_config, num_clk); + if (rc) { + dev_err(&pdev->dev, "Failed to get clock refs %d\n", rc); + goto err; + } + + rc = of_clk_set_defaults(pdev->dev.of_node, false); + if (rc) { + dev_err(&pdev->dev, "Failed to set clock defaults %d\n", rc); + goto err; + } + + for (i = 0; i < num_clk; i++) { + u32 rate = clk_get_rate(mp->clk_config[i].clk); + if (!rate) + continue; + mp->clk_config[i].rate = rate; + mp->clk_config[i].type = DSS_CLK_PCLK; + } + + mp->num_clk = num_clk; + return 0; + +err: + msm_dss_put_clk(mp->clk_config, num_clk); + return rc; +} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.h new file mode 100644 index 0000000000000..bc07381d74291 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.h @@ -0,0 +1,57 @@ +/* Copyright (c) 2012, 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef __DPU_IO_UTIL_H__ +#define __DPU_IO_UTIL_H__ + +#include <linux/gpio.h> +#include <linux/platform_device.h> +#include <linux/types.h> + +#define DEV_DBG(fmt, args...) pr_debug(fmt, ##args) +#define DEV_INFO(fmt, args...) pr_info(fmt, ##args) +#define DEV_WARN(fmt, args...) pr_warn(fmt, ##args) +#define DEV_ERR(fmt, args...) pr_err(fmt, ##args) + +struct dss_gpio { + unsigned int gpio; + unsigned int value; + char gpio_name[32]; +}; + +enum dss_clk_type { + DSS_CLK_AHB, /* no set rate. rate controlled through rpm */ + DSS_CLK_PCLK, +}; + +struct dss_clk { + struct clk *clk; /* clk handle */ + char clk_name[32]; + enum dss_clk_type type; + unsigned long rate; + unsigned long max_rate; +}; + +struct dss_module_power { + unsigned int num_gpio; + struct dss_gpio *gpio_config; + unsigned int num_clk; + struct dss_clk *clk_config; +}; + +int msm_dss_get_clk(struct device *dev, struct dss_clk *clk_arry, int num_clk); +void msm_dss_put_clk(struct dss_clk *clk_arry, int num_clk); +int msm_dss_clk_set_rate(struct dss_clk *clk_arry, int num_clk); +int msm_dss_enable_clk(struct dss_clk *clk_arry, int num_clk, int enable); +int msm_dss_parse_clock(struct platform_device *pdev, + struct dss_module_power *mp); +#endif /* __DPU_IO_UTIL_H__ */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_irq.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_irq.c new file mode 100644 index 0000000000000..d5e6ce0140cf9 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_irq.c @@ -0,0 +1,66 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ + +#include <linux/irqdomain.h> +#include <linux/irq.h> +#include <linux/kthread.h> + +#include "dpu_irq.h" +#include "dpu_core_irq.h" + +irqreturn_t dpu_irq(struct msm_kms *kms) +{ + struct dpu_kms *dpu_kms = to_dpu_kms(kms); + + return dpu_core_irq(dpu_kms); +} + +void dpu_irq_preinstall(struct msm_kms *kms) +{ + struct dpu_kms *dpu_kms = to_dpu_kms(kms); + + if (!dpu_kms->dev || !dpu_kms->dev->dev) { + pr_err("invalid device handles\n"); + return; + } + + dpu_core_irq_preinstall(dpu_kms); +} + +int dpu_irq_postinstall(struct msm_kms *kms) +{ + struct dpu_kms *dpu_kms = to_dpu_kms(kms); + int rc; + + if (!kms) { + DPU_ERROR("invalid parameters\n"); + return -EINVAL; + } + + rc = dpu_core_irq_postinstall(dpu_kms); + + return rc; +} + +void dpu_irq_uninstall(struct msm_kms *kms) +{ + struct dpu_kms *dpu_kms = to_dpu_kms(kms); + + if (!kms) { + DPU_ERROR("invalid parameters\n"); + return; + } + + dpu_core_irq_uninstall(dpu_kms); +} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_irq.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_irq.h new file mode 100644 index 0000000000000..3e147f7176e22 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_irq.h @@ -0,0 +1,59 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef __DPU_IRQ_H__ +#define __DPU_IRQ_H__ + +#include <linux/kernel.h> +#include <linux/irqdomain.h> + +#include "msm_kms.h" + +/** + * dpu_irq_controller - define MDSS level interrupt controller context + * @enabled_mask: enable status of MDSS level interrupt + * @domain: interrupt domain of this controller + */ +struct dpu_irq_controller { + unsigned long enabled_mask; + struct irq_domain *domain; +}; + +/** + * dpu_irq_preinstall - perform pre-installation of MDSS IRQ handler + * @kms: pointer to kms context + * @return: none + */ +void dpu_irq_preinstall(struct msm_kms *kms); + +/** + * dpu_irq_postinstall - perform post-installation of MDSS IRQ handler + * @kms: pointer to kms context + * @return: 0 if success; error code otherwise + */ +int dpu_irq_postinstall(struct msm_kms *kms); + +/** + * dpu_irq_uninstall - uninstall MDSS IRQ handler + * @drm_dev: pointer to kms context + * @return: none + */ +void dpu_irq_uninstall(struct msm_kms *kms); + +/** + * dpu_irq - MDSS level IRQ handler + * @kms: pointer to kms context + * @return: interrupt handling status + */ +irqreturn_t dpu_irq(struct msm_kms *kms); + +#endif /* __DPU_IRQ_H__ */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c new file mode 100644 index 0000000000000..8d4678d29cc73 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -0,0 +1,1345 @@ +/* + * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.com> + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ + +#include <drm/drm_crtc.h> +#include <linux/debugfs.h> +#include <linux/of_irq.h> +#include <linux/dma-buf.h> + +#include "msm_drv.h" +#include "msm_mmu.h" +#include "msm_gem.h" + +#include "dpu_kms.h" +#include "dpu_core_irq.h" +#include "dpu_formats.h" +#include "dpu_hw_vbif.h" +#include "dpu_vbif.h" +#include "dpu_encoder.h" +#include "dpu_plane.h" +#include "dpu_crtc.h" + +#define CREATE_TRACE_POINTS +#include "dpu_trace.h" + +static const char * const iommu_ports[] = { + "mdp_0", +}; + +/* + * To enable overall DRM driver logging + * # echo 0x2 > /sys/module/drm/parameters/debug + * + * To enable DRM driver h/w logging + * # echo <mask> > /sys/kernel/debug/dri/0/debug/hw_log_mask + * + * See dpu_hw_mdss.h for h/w logging mask definitions (search for DPU_DBG_MASK_) + */ +#define DPU_DEBUGFS_DIR "msm_dpu" +#define DPU_DEBUGFS_HWMASKNAME "hw_log_mask" + +static int dpu_kms_hw_init(struct msm_kms *kms); +static int _dpu_kms_mmu_destroy(struct dpu_kms *dpu_kms); + +static unsigned long dpu_iomap_size(struct platform_device *pdev, + const char *name) +{ + struct resource *res; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); + if (!res) { + DRM_ERROR("failed to get memory resource: %s\n", name); + return 0; + } + + return resource_size(res); +} + +#ifdef CONFIG_DEBUG_FS +static int _dpu_danger_signal_status(struct seq_file *s, + bool danger_status) +{ + struct dpu_kms *kms = (struct dpu_kms *)s->private; + struct msm_drm_private *priv; + struct dpu_danger_safe_status status; + int i; + + if (!kms || !kms->dev || !kms->dev->dev_private || !kms->hw_mdp) { + DPU_ERROR("invalid arg(s)\n"); + return 0; + } + + priv = kms->dev->dev_private; + memset(&status, 0, sizeof(struct dpu_danger_safe_status)); + + pm_runtime_get_sync(&kms->pdev->dev); + if (danger_status) { + seq_puts(s, "\nDanger signal status:\n"); + if (kms->hw_mdp->ops.get_danger_status) + kms->hw_mdp->ops.get_danger_status(kms->hw_mdp, + &status); + } else { + seq_puts(s, "\nSafe signal status:\n"); + if (kms->hw_mdp->ops.get_danger_status) + kms->hw_mdp->ops.get_danger_status(kms->hw_mdp, + &status); + } + pm_runtime_put_sync(&kms->pdev->dev); + + seq_printf(s, "MDP : 0x%x\n", status.mdp); + + for (i = SSPP_VIG0; i < SSPP_MAX; i++) + seq_printf(s, "SSPP%d : 0x%x \t", i - SSPP_VIG0, + status.sspp[i]); + seq_puts(s, "\n"); + + return 0; +} + +#define DEFINE_DPU_DEBUGFS_SEQ_FOPS(__prefix) \ +static int __prefix ## _open(struct inode *inode, struct file *file) \ +{ \ + return single_open(file, __prefix ## _show, inode->i_private); \ +} \ +static const struct file_operations __prefix ## _fops = { \ + .owner = THIS_MODULE, \ + .open = __prefix ## _open, \ + .release = single_release, \ + .read = seq_read, \ + .llseek = seq_lseek, \ +} + +static int dpu_debugfs_danger_stats_show(struct seq_file *s, void *v) +{ + return _dpu_danger_signal_status(s, true); +} +DEFINE_DPU_DEBUGFS_SEQ_FOPS(dpu_debugfs_danger_stats); + +static int dpu_debugfs_safe_stats_show(struct seq_file *s, void *v) +{ + return _dpu_danger_signal_status(s, false); +} +DEFINE_DPU_DEBUGFS_SEQ_FOPS(dpu_debugfs_safe_stats); + +static void dpu_debugfs_danger_destroy(struct dpu_kms *dpu_kms) +{ + debugfs_remove_recursive(dpu_kms->debugfs_danger); + dpu_kms->debugfs_danger = NULL; +} + +static int dpu_debugfs_danger_init(struct dpu_kms *dpu_kms, + struct dentry *parent) +{ + dpu_kms->debugfs_danger = debugfs_create_dir("danger", + parent); + if (!dpu_kms->debugfs_danger) { + DPU_ERROR("failed to create danger debugfs\n"); + return -EINVAL; + } + + debugfs_create_file("danger_status", 0600, dpu_kms->debugfs_danger, + dpu_kms, &dpu_debugfs_danger_stats_fops); + debugfs_create_file("safe_status", 0600, dpu_kms->debugfs_danger, + dpu_kms, &dpu_debugfs_safe_stats_fops); + + return 0; +} + +static int _dpu_debugfs_show_regset32(struct seq_file *s, void *data) +{ + struct dpu_debugfs_regset32 *regset; + struct dpu_kms *dpu_kms; + struct drm_device *dev; + struct msm_drm_private *priv; + void __iomem *base; + uint32_t i, addr; + + if (!s || !s->private) + return 0; + + regset = s->private; + + dpu_kms = regset->dpu_kms; + if (!dpu_kms || !dpu_kms->mmio) + return 0; + + dev = dpu_kms->dev; + if (!dev) + return 0; + + priv = dev->dev_private; + if (!priv) + return 0; + + base = dpu_kms->mmio + regset->offset; + + /* insert padding spaces, if needed */ + if (regset->offset & 0xF) { + seq_printf(s, "[%x]", regset->offset & ~0xF); + for (i = 0; i < (regset->offset & 0xF); i += 4) + seq_puts(s, " "); + } + + pm_runtime_get_sync(&dpu_kms->pdev->dev); + + /* main register output */ + for (i = 0; i < regset->blk_len; i += 4) { + addr = regset->offset + i; + if ((addr & 0xF) == 0x0) + seq_printf(s, i ? "\n[%x]" : "[%x]", addr); + seq_printf(s, " %08x", readl_relaxed(base + i)); + } + seq_puts(s, "\n"); + pm_runtime_put_sync(&dpu_kms->pdev->dev); + + return 0; +} + +static int dpu_debugfs_open_regset32(struct inode *inode, + struct file *file) +{ + return single_open(file, _dpu_debugfs_show_regset32, inode->i_private); +} + +static const struct file_operations dpu_fops_regset32 = { + .open = dpu_debugfs_open_regset32, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +void dpu_debugfs_setup_regset32(struct dpu_debugfs_regset32 *regset, + uint32_t offset, uint32_t length, struct dpu_kms *dpu_kms) +{ + if (regset) { + regset->offset = offset; + regset->blk_len = length; + regset->dpu_kms = dpu_kms; + } +} + +void *dpu_debugfs_create_regset32(const char *name, umode_t mode, + void *parent, struct dpu_debugfs_regset32 *regset) +{ + if (!name || !regset || !regset->dpu_kms || !regset->blk_len) + return NULL; + + /* make sure offset is a multiple of 4 */ + regset->offset = round_down(regset->offset, 4); + + return debugfs_create_file(name, mode, parent, + regset, &dpu_fops_regset32); +} + +static int _dpu_debugfs_init(struct dpu_kms *dpu_kms) +{ + void *p; + int rc; + + p = dpu_hw_util_get_log_mask_ptr(); + + if (!dpu_kms || !p) + return -EINVAL; + + dpu_kms->debugfs_root = debugfs_create_dir("debug", + dpu_kms->dev->primary->debugfs_root); + if (IS_ERR_OR_NULL(dpu_kms->debugfs_root)) { + DRM_ERROR("debugfs create_dir failed %ld\n", + PTR_ERR(dpu_kms->debugfs_root)); + return PTR_ERR(dpu_kms->debugfs_root); + } + + rc = dpu_dbg_debugfs_register(dpu_kms->debugfs_root); + if (rc) { + DRM_ERROR("failed to reg dpu dbg debugfs: %d\n", rc); + return rc; + } + + /* allow root to be NULL */ + debugfs_create_x32(DPU_DEBUGFS_HWMASKNAME, 0600, dpu_kms->debugfs_root, p); + + (void) dpu_debugfs_danger_init(dpu_kms, dpu_kms->debugfs_root); + (void) dpu_debugfs_vbif_init(dpu_kms, dpu_kms->debugfs_root); + (void) dpu_debugfs_core_irq_init(dpu_kms, dpu_kms->debugfs_root); + + rc = dpu_core_perf_debugfs_init(&dpu_kms->perf, dpu_kms->debugfs_root); + if (rc) { + DPU_ERROR("failed to init perf %d\n", rc); + return rc; + } + + return 0; +} + +static void _dpu_debugfs_destroy(struct dpu_kms *dpu_kms) +{ + /* don't need to NULL check debugfs_root */ + if (dpu_kms) { + dpu_debugfs_vbif_destroy(dpu_kms); + dpu_debugfs_danger_destroy(dpu_kms); + dpu_debugfs_core_irq_destroy(dpu_kms); + debugfs_remove_recursive(dpu_kms->debugfs_root); + } +} +#else +static void _dpu_debugfs_destroy(struct dpu_kms *dpu_kms) +{ +} +#endif + +static int dpu_kms_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc) +{ + return dpu_crtc_vblank(crtc, true); +} + +static void dpu_kms_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc) +{ + dpu_crtc_vblank(crtc, false); +} + +static void dpu_kms_prepare_commit(struct msm_kms *kms, + struct drm_atomic_state *state) +{ + struct dpu_kms *dpu_kms; + struct msm_drm_private *priv; + struct drm_device *dev; + struct drm_encoder *encoder; + + if (!kms) + return; + dpu_kms = to_dpu_kms(kms); + dev = dpu_kms->dev; + + if (!dev || !dev->dev_private) + return; + priv = dev->dev_private; + pm_runtime_get_sync(&dpu_kms->pdev->dev); + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) + if (encoder->crtc != NULL) + dpu_encoder_prepare_commit(encoder); +} + +/* + * Override the encoder enable since we need to setup the inline rotator and do + * some crtc magic before enabling any bridge that might be present. + */ +void dpu_kms_encoder_enable(struct drm_encoder *encoder) +{ + const struct drm_encoder_helper_funcs *funcs = encoder->helper_private; + struct drm_crtc *crtc = encoder->crtc; + + /* Forward this enable call to the commit hook */ + if (funcs && funcs->commit) + funcs->commit(encoder); + + if (crtc && crtc->state->active) { + trace_dpu_kms_enc_enable(DRMID(crtc)); + dpu_crtc_commit_kickoff(crtc); + } +} + +static void dpu_kms_commit(struct msm_kms *kms, struct drm_atomic_state *state) +{ + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + int i; + + for_each_new_crtc_in_state(state, crtc, crtc_state, i) { + /* If modeset is required, kickoff is run in encoder_enable */ + if (drm_atomic_crtc_needs_modeset(crtc_state)) + continue; + + if (crtc->state->active) { + trace_dpu_kms_commit(DRMID(crtc)); + dpu_crtc_commit_kickoff(crtc); + } + } +} + +static void dpu_kms_complete_commit(struct msm_kms *kms, + struct drm_atomic_state *old_state) +{ + struct dpu_kms *dpu_kms; + struct msm_drm_private *priv; + struct drm_crtc *crtc; + struct drm_crtc_state *old_crtc_state; + int i; + + if (!kms || !old_state) + return; + dpu_kms = to_dpu_kms(kms); + + if (!dpu_kms->dev || !dpu_kms->dev->dev_private) + return; + priv = dpu_kms->dev->dev_private; + + DPU_ATRACE_BEGIN("kms_complete_commit"); + + for_each_old_crtc_in_state(old_state, crtc, old_crtc_state, i) + dpu_crtc_complete_commit(crtc, old_crtc_state); + + pm_runtime_put_sync(&dpu_kms->pdev->dev); + + DPU_ATRACE_END("kms_complete_commit"); +} + +static void dpu_kms_wait_for_commit_done(struct msm_kms *kms, + struct drm_crtc *crtc) +{ + struct drm_encoder *encoder; + struct drm_device *dev; + int ret; + + if (!kms || !crtc || !crtc->state) { + DPU_ERROR("invalid params\n"); + return; + } + + dev = crtc->dev; + + if (!crtc->state->enable) { + DPU_DEBUG("[crtc:%d] not enable\n", crtc->base.id); + return; + } + + if (!crtc->state->active) { + DPU_DEBUG("[crtc:%d] not active\n", crtc->base.id); + return; + } + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->crtc != crtc) + continue; + /* + * Wait for post-flush if necessary to delay before + * plane_cleanup. For example, wait for vsync in case of video + * mode panels. This may be a no-op for command mode panels. + */ + trace_dpu_kms_wait_for_commit_done(DRMID(crtc)); + ret = dpu_encoder_wait_for_event(encoder, MSM_ENC_COMMIT_DONE); + if (ret && ret != -EWOULDBLOCK) { + DPU_ERROR("wait for commit done returned %d\n", ret); + break; + } + } +} + +static void _dpu_kms_initialize_dsi(struct drm_device *dev, + struct msm_drm_private *priv, + struct dpu_kms *dpu_kms) +{ + struct drm_encoder *encoder = NULL; + int i, rc; + + /*TODO: Support two independent DSI connectors */ + encoder = dpu_encoder_init(dev, DRM_MODE_CONNECTOR_DSI); + if (IS_ERR_OR_NULL(encoder)) { + DPU_ERROR("encoder init failed for dsi display\n"); + return; + } + + priv->encoders[priv->num_encoders++] = encoder; + + for (i = 0; i < ARRAY_SIZE(priv->dsi); i++) { + if (!priv->dsi[i]) { + DPU_DEBUG("invalid msm_dsi for ctrl %d\n", i); + return; + } + + rc = msm_dsi_modeset_init(priv->dsi[i], dev, encoder); + if (rc) { + DPU_ERROR("modeset_init failed for dsi[%d], rc = %d\n", + i, rc); + continue; + } + } +} + +/** + * _dpu_kms_setup_displays - create encoders, bridges and connectors + * for underlying displays + * @dev: Pointer to drm device structure + * @priv: Pointer to private drm device data + * @dpu_kms: Pointer to dpu kms structure + * Returns: Zero on success + */ +static void _dpu_kms_setup_displays(struct drm_device *dev, + struct msm_drm_private *priv, + struct dpu_kms *dpu_kms) +{ + _dpu_kms_initialize_dsi(dev, priv, dpu_kms); + + /** + * Extend this function to initialize other + * types of displays + */ +} + +static void _dpu_kms_drm_obj_destroy(struct dpu_kms *dpu_kms) +{ + struct msm_drm_private *priv; + int i; + + if (!dpu_kms) { + DPU_ERROR("invalid dpu_kms\n"); + return; + } else if (!dpu_kms->dev) { + DPU_ERROR("invalid dev\n"); + return; + } else if (!dpu_kms->dev->dev_private) { + DPU_ERROR("invalid dev_private\n"); + return; + } + priv = dpu_kms->dev->dev_private; + + for (i = 0; i < priv->num_crtcs; i++) + priv->crtcs[i]->funcs->destroy(priv->crtcs[i]); + priv->num_crtcs = 0; + + for (i = 0; i < priv->num_planes; i++) + priv->planes[i]->funcs->destroy(priv->planes[i]); + priv->num_planes = 0; + + for (i = 0; i < priv->num_connectors; i++) + priv->connectors[i]->funcs->destroy(priv->connectors[i]); + priv->num_connectors = 0; + + for (i = 0; i < priv->num_encoders; i++) + priv->encoders[i]->funcs->destroy(priv->encoders[i]); + priv->num_encoders = 0; +} + +static int _dpu_kms_drm_obj_init(struct dpu_kms *dpu_kms) +{ + struct drm_device *dev; + struct drm_plane *primary_planes[MAX_PLANES], *plane; + struct drm_crtc *crtc; + + struct msm_drm_private *priv; + struct dpu_mdss_cfg *catalog; + + int primary_planes_idx = 0, i, ret; + int max_crtc_count; + + if (!dpu_kms || !dpu_kms->dev || !dpu_kms->dev->dev) { + DPU_ERROR("invalid dpu_kms\n"); + return -EINVAL; + } + + dev = dpu_kms->dev; + priv = dev->dev_private; + catalog = dpu_kms->catalog; + + /* + * Create encoder and query display drivers to create + * bridges and connectors + */ + _dpu_kms_setup_displays(dev, priv, dpu_kms); + + max_crtc_count = min(catalog->mixer_count, priv->num_encoders); + + /* Create the planes */ + for (i = 0; i < catalog->sspp_count; i++) { + bool primary = true; + + if (catalog->sspp[i].features & BIT(DPU_SSPP_CURSOR) + || primary_planes_idx >= max_crtc_count) + primary = false; + + plane = dpu_plane_init(dev, catalog->sspp[i].id, primary, + (1UL << max_crtc_count) - 1, 0); + if (IS_ERR(plane)) { + DPU_ERROR("dpu_plane_init failed\n"); + ret = PTR_ERR(plane); + goto fail; + } + priv->planes[priv->num_planes++] = plane; + + if (primary) + primary_planes[primary_planes_idx++] = plane; + } + + max_crtc_count = min(max_crtc_count, primary_planes_idx); + + /* Create one CRTC per encoder */ + for (i = 0; i < max_crtc_count; i++) { + crtc = dpu_crtc_init(dev, primary_planes[i]); + if (IS_ERR(crtc)) { + ret = PTR_ERR(crtc); + goto fail; + } + priv->crtcs[priv->num_crtcs++] = crtc; + } + + /* All CRTCs are compatible with all encoders */ + for (i = 0; i < priv->num_encoders; i++) + priv->encoders[i]->possible_crtcs = (1 << priv->num_crtcs) - 1; + + return 0; +fail: + _dpu_kms_drm_obj_destroy(dpu_kms); + return ret; +} + +#ifdef CONFIG_DEBUG_FS +static int dpu_kms_debugfs_init(struct msm_kms *kms, struct drm_minor *minor) +{ + struct dpu_kms *dpu_kms = to_dpu_kms(kms); + struct drm_device *dev; + int rc; + + if (!dpu_kms || !dpu_kms->dev || !dpu_kms->dev->dev) { + DPU_ERROR("invalid dpu_kms\n"); + return -EINVAL; + } + + dev = dpu_kms->dev; + + rc = _dpu_debugfs_init(dpu_kms); + if (rc) + DPU_ERROR("dpu_debugfs init failed: %d\n", rc); + + return rc; +} +#endif + +static long dpu_kms_round_pixclk(struct msm_kms *kms, unsigned long rate, + struct drm_encoder *encoder) +{ + return rate; +} + +static void _dpu_kms_hw_destroy(struct dpu_kms *dpu_kms) +{ + struct drm_device *dev; + int i; + + dev = dpu_kms->dev; + if (!dev) + return; + + if (dpu_kms->hw_intr) + dpu_hw_intr_destroy(dpu_kms->hw_intr); + dpu_kms->hw_intr = NULL; + + if (dpu_kms->power_event) + dpu_power_handle_unregister_event( + &dpu_kms->phandle, dpu_kms->power_event); + + /* safe to call these more than once during shutdown */ + _dpu_debugfs_destroy(dpu_kms); + _dpu_kms_mmu_destroy(dpu_kms); + + if (dpu_kms->catalog) { + for (i = 0; i < dpu_kms->catalog->vbif_count; i++) { + u32 vbif_idx = dpu_kms->catalog->vbif[i].id; + + if ((vbif_idx < VBIF_MAX) && dpu_kms->hw_vbif[vbif_idx]) + dpu_hw_vbif_destroy(dpu_kms->hw_vbif[vbif_idx]); + } + } + + if (dpu_kms->rm_init) + dpu_rm_destroy(&dpu_kms->rm); + dpu_kms->rm_init = false; + + if (dpu_kms->catalog) + dpu_hw_catalog_deinit(dpu_kms->catalog); + dpu_kms->catalog = NULL; + + if (dpu_kms->core_client) + dpu_power_client_destroy(&dpu_kms->phandle, + dpu_kms->core_client); + dpu_kms->core_client = NULL; + + if (dpu_kms->vbif[VBIF_NRT]) + devm_iounmap(&dpu_kms->pdev->dev, dpu_kms->vbif[VBIF_NRT]); + dpu_kms->vbif[VBIF_NRT] = NULL; + + if (dpu_kms->vbif[VBIF_RT]) + devm_iounmap(&dpu_kms->pdev->dev, dpu_kms->vbif[VBIF_RT]); + dpu_kms->vbif[VBIF_RT] = NULL; + + if (dpu_kms->mmio) + devm_iounmap(&dpu_kms->pdev->dev, dpu_kms->mmio); + dpu_kms->mmio = NULL; +} + +static void dpu_kms_destroy(struct msm_kms *kms) +{ + struct dpu_kms *dpu_kms; + + if (!kms) { + DPU_ERROR("invalid kms\n"); + return; + } + + dpu_kms = to_dpu_kms(kms); + + dpu_dbg_destroy(); + _dpu_kms_hw_destroy(dpu_kms); +} + +static int dpu_kms_pm_suspend(struct device *dev) +{ + struct drm_device *ddev; + struct drm_modeset_acquire_ctx ctx; + struct drm_atomic_state *state; + struct dpu_kms *dpu_kms; + int ret = 0, num_crtcs = 0; + + if (!dev) + return -EINVAL; + + ddev = dev_get_drvdata(dev); + if (!ddev || !ddev_to_msm_kms(ddev)) + return -EINVAL; + + dpu_kms = to_dpu_kms(ddev_to_msm_kms(ddev)); + + /* disable hot-plug polling */ + drm_kms_helper_poll_disable(ddev); + + /* acquire modeset lock(s) */ + drm_modeset_acquire_init(&ctx, 0); + +retry: + DPU_ATRACE_BEGIN("kms_pm_suspend"); + + ret = drm_modeset_lock_all_ctx(ddev, &ctx); + if (ret) + goto unlock; + + /* save current state for resume */ + if (dpu_kms->suspend_state) + drm_atomic_state_put(dpu_kms->suspend_state); + dpu_kms->suspend_state = drm_atomic_helper_duplicate_state(ddev, &ctx); + if (IS_ERR_OR_NULL(dpu_kms->suspend_state)) { + DRM_ERROR("failed to back up suspend state\n"); + dpu_kms->suspend_state = NULL; + goto unlock; + } + + /* create atomic state to disable all CRTCs */ + state = drm_atomic_state_alloc(ddev); + if (IS_ERR_OR_NULL(state)) { + DRM_ERROR("failed to allocate crtc disable state\n"); + goto unlock; + } + + state->acquire_ctx = &ctx; + + /* check for nothing to do */ + if (num_crtcs == 0) { + DRM_DEBUG("all crtcs are already in the off state\n"); + drm_atomic_state_put(state); + goto suspended; + } + + /* commit the "disable all" state */ + ret = drm_atomic_commit(state); + if (ret < 0) { + DRM_ERROR("failed to disable crtcs, %d\n", ret); + drm_atomic_state_put(state); + goto unlock; + } + +suspended: + dpu_kms->suspend_block = true; + +unlock: + if (ret == -EDEADLK) { + drm_modeset_backoff(&ctx); + goto retry; + } + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + + DPU_ATRACE_END("kms_pm_suspend"); + return 0; +} + +static int dpu_kms_pm_resume(struct device *dev) +{ + struct drm_device *ddev; + struct dpu_kms *dpu_kms; + int ret; + + if (!dev) + return -EINVAL; + + ddev = dev_get_drvdata(dev); + if (!ddev || !ddev_to_msm_kms(ddev)) + return -EINVAL; + + dpu_kms = to_dpu_kms(ddev_to_msm_kms(ddev)); + + DPU_ATRACE_BEGIN("kms_pm_resume"); + + drm_mode_config_reset(ddev); + + drm_modeset_lock_all(ddev); + + dpu_kms->suspend_block = false; + + if (dpu_kms->suspend_state) { + dpu_kms->suspend_state->acquire_ctx = + ddev->mode_config.acquire_ctx; + ret = drm_atomic_commit(dpu_kms->suspend_state); + if (ret < 0) { + DRM_ERROR("failed to restore state, %d\n", ret); + drm_atomic_state_put(dpu_kms->suspend_state); + } + dpu_kms->suspend_state = NULL; + } + drm_modeset_unlock_all(ddev); + + /* enable hot-plug polling */ + drm_kms_helper_poll_enable(ddev); + + DPU_ATRACE_END("kms_pm_resume"); + return 0; +} + +void _dpu_kms_set_encoder_mode(struct msm_kms *kms, + struct drm_encoder *encoder, + bool cmd_mode) +{ + struct msm_display_info info; + struct msm_drm_private *priv = encoder->dev->dev_private; + int i, rc = 0; + + memset(&info, 0, sizeof(info)); + + info.intf_type = encoder->encoder_type; + info.capabilities = cmd_mode ? MSM_DISPLAY_CAP_CMD_MODE : + MSM_DISPLAY_CAP_VID_MODE; + + /* TODO: No support for DSI swap */ + for (i = 0; i < ARRAY_SIZE(priv->dsi); i++) { + if (priv->dsi[i]) { + info.h_tile_instance[info.num_of_h_tiles] = i; + info.num_of_h_tiles++; + } + } + + rc = dpu_encoder_setup(encoder->dev, encoder, &info); + if (rc) + DPU_ERROR("failed to setup DPU encoder %d: rc:%d\n", + encoder->base.id, rc); +} + +static const struct msm_kms_funcs kms_funcs = { + .hw_init = dpu_kms_hw_init, + .irq_preinstall = dpu_irq_preinstall, + .irq_postinstall = dpu_irq_postinstall, + .irq_uninstall = dpu_irq_uninstall, + .irq = dpu_irq, + .prepare_commit = dpu_kms_prepare_commit, + .commit = dpu_kms_commit, + .complete_commit = dpu_kms_complete_commit, + .wait_for_crtc_commit_done = dpu_kms_wait_for_commit_done, + .enable_vblank = dpu_kms_enable_vblank, + .disable_vblank = dpu_kms_disable_vblank, + .check_modified_format = dpu_format_check_modified_format, + .get_format = dpu_get_msm_format, + .round_pixclk = dpu_kms_round_pixclk, + .pm_suspend = dpu_kms_pm_suspend, + .pm_resume = dpu_kms_pm_resume, + .destroy = dpu_kms_destroy, + .set_encoder_mode = _dpu_kms_set_encoder_mode, +#ifdef CONFIG_DEBUG_FS + .debugfs_init = dpu_kms_debugfs_init, +#endif +}; + +/* the caller api needs to turn on clock before calling it */ +static inline void _dpu_kms_core_hw_rev_init(struct dpu_kms *dpu_kms) +{ + dpu_kms->core_rev = readl_relaxed(dpu_kms->mmio + 0x0); +} + +static int _dpu_kms_mmu_destroy(struct dpu_kms *dpu_kms) +{ + struct msm_mmu *mmu; + + mmu = dpu_kms->base.aspace->mmu; + + mmu->funcs->detach(mmu, (const char **)iommu_ports, + ARRAY_SIZE(iommu_ports)); + msm_gem_address_space_put(dpu_kms->base.aspace); + + return 0; +} + +static int _dpu_kms_mmu_init(struct dpu_kms *dpu_kms) +{ + struct iommu_domain *domain; + struct msm_gem_address_space *aspace; + int ret; + + domain = iommu_domain_alloc(&platform_bus_type); + if (!domain) + return 0; + + aspace = msm_gem_address_space_create(dpu_kms->dev->dev, + domain, "dpu1"); + if (IS_ERR(aspace)) { + ret = PTR_ERR(aspace); + goto fail; + } + + dpu_kms->base.aspace = aspace; + + ret = aspace->mmu->funcs->attach(aspace->mmu, iommu_ports, + ARRAY_SIZE(iommu_ports)); + if (ret) { + DPU_ERROR("failed to attach iommu %d\n", ret); + msm_gem_address_space_put(aspace); + goto fail; + } + + return 0; +fail: + _dpu_kms_mmu_destroy(dpu_kms); + + return ret; +} + +static struct dss_clk *_dpu_kms_get_clk(struct dpu_kms *dpu_kms, + char *clock_name) +{ + struct dss_module_power *mp = &dpu_kms->mp; + int i; + + for (i = 0; i < mp->num_clk; i++) { + if (!strcmp(mp->clk_config[i].clk_name, clock_name)) + return &mp->clk_config[i]; + } + + return NULL; +} + +u64 dpu_kms_get_clk_rate(struct dpu_kms *dpu_kms, char *clock_name) +{ + struct dss_clk *clk; + + clk = _dpu_kms_get_clk(dpu_kms, clock_name); + if (!clk) + return -EINVAL; + + return clk_get_rate(clk->clk); +} + +static void dpu_kms_handle_power_event(u32 event_type, void *usr) +{ + struct dpu_kms *dpu_kms = usr; + + if (!dpu_kms) + return; + + if (event_type == DPU_POWER_EVENT_POST_ENABLE) + dpu_vbif_init_memtypes(dpu_kms); +} + +static int dpu_kms_hw_init(struct msm_kms *kms) +{ + struct dpu_kms *dpu_kms; + struct drm_device *dev; + struct msm_drm_private *priv; + int i, rc = -EINVAL; + + if (!kms) { + DPU_ERROR("invalid kms\n"); + goto end; + } + + dpu_kms = to_dpu_kms(kms); + dev = dpu_kms->dev; + if (!dev) { + DPU_ERROR("invalid device\n"); + goto end; + } + + rc = dpu_dbg_init(&dpu_kms->pdev->dev); + if (rc) { + DRM_ERROR("failed to init dpu dbg: %d\n", rc); + goto end; + } + + priv = dev->dev_private; + if (!priv) { + DPU_ERROR("invalid private data\n"); + goto dbg_destroy; + } + + dpu_kms->mmio = msm_ioremap(dpu_kms->pdev, "mdp", "mdp"); + if (IS_ERR(dpu_kms->mmio)) { + rc = PTR_ERR(dpu_kms->mmio); + DPU_ERROR("mdp register memory map failed: %d\n", rc); + dpu_kms->mmio = NULL; + goto error; + } + DRM_DEBUG("mapped dpu address space @%pK\n", dpu_kms->mmio); + dpu_kms->mmio_len = dpu_iomap_size(dpu_kms->pdev, "mdp"); + + dpu_kms->vbif[VBIF_RT] = msm_ioremap(dpu_kms->pdev, "vbif", "vbif"); + if (IS_ERR(dpu_kms->vbif[VBIF_RT])) { + rc = PTR_ERR(dpu_kms->vbif[VBIF_RT]); + DPU_ERROR("vbif register memory map failed: %d\n", rc); + dpu_kms->vbif[VBIF_RT] = NULL; + goto error; + } + dpu_kms->vbif_len[VBIF_RT] = dpu_iomap_size(dpu_kms->pdev, "vbif"); + dpu_kms->vbif[VBIF_NRT] = msm_ioremap(dpu_kms->pdev, "vbif_nrt", "vbif_nrt"); + if (IS_ERR(dpu_kms->vbif[VBIF_NRT])) { + dpu_kms->vbif[VBIF_NRT] = NULL; + DPU_DEBUG("VBIF NRT is not defined"); + } else { + dpu_kms->vbif_len[VBIF_NRT] = dpu_iomap_size(dpu_kms->pdev, + "vbif_nrt"); + } + + dpu_kms->reg_dma = msm_ioremap(dpu_kms->pdev, "regdma", "regdma"); + if (IS_ERR(dpu_kms->reg_dma)) { + dpu_kms->reg_dma = NULL; + DPU_DEBUG("REG_DMA is not defined"); + } else { + dpu_kms->reg_dma_len = dpu_iomap_size(dpu_kms->pdev, "regdma"); + } + + dpu_kms->core_client = dpu_power_client_create(&dpu_kms->phandle, + "core"); + if (IS_ERR_OR_NULL(dpu_kms->core_client)) { + rc = PTR_ERR(dpu_kms->core_client); + if (!dpu_kms->core_client) + rc = -EINVAL; + DPU_ERROR("dpu power client create failed: %d\n", rc); + dpu_kms->core_client = NULL; + goto error; + } + + pm_runtime_get_sync(&dpu_kms->pdev->dev); + + _dpu_kms_core_hw_rev_init(dpu_kms); + + pr_info("dpu hardware revision:0x%x\n", dpu_kms->core_rev); + + dpu_kms->catalog = dpu_hw_catalog_init(dpu_kms->core_rev); + if (IS_ERR_OR_NULL(dpu_kms->catalog)) { + rc = PTR_ERR(dpu_kms->catalog); + if (!dpu_kms->catalog) + rc = -EINVAL; + DPU_ERROR("catalog init failed: %d\n", rc); + dpu_kms->catalog = NULL; + goto power_error; + } + + dpu_dbg_init_dbg_buses(dpu_kms->core_rev); + + /* + * Now we need to read the HW catalog and initialize resources such as + * clocks, regulators, GDSC/MMAGIC, ioremap the register ranges etc + */ + rc = _dpu_kms_mmu_init(dpu_kms); + if (rc) { + DPU_ERROR("dpu_kms_mmu_init failed: %d\n", rc); + goto power_error; + } + + rc = dpu_rm_init(&dpu_kms->rm, dpu_kms->catalog, dpu_kms->mmio, + dpu_kms->dev); + if (rc) { + DPU_ERROR("rm init failed: %d\n", rc); + goto power_error; + } + + dpu_kms->rm_init = true; + + dpu_kms->hw_mdp = dpu_rm_get_mdp(&dpu_kms->rm); + if (IS_ERR_OR_NULL(dpu_kms->hw_mdp)) { + rc = PTR_ERR(dpu_kms->hw_mdp); + if (!dpu_kms->hw_mdp) + rc = -EINVAL; + DPU_ERROR("failed to get hw_mdp: %d\n", rc); + dpu_kms->hw_mdp = NULL; + goto power_error; + } + + for (i = 0; i < dpu_kms->catalog->vbif_count; i++) { + u32 vbif_idx = dpu_kms->catalog->vbif[i].id; + + dpu_kms->hw_vbif[i] = dpu_hw_vbif_init(vbif_idx, + dpu_kms->vbif[vbif_idx], dpu_kms->catalog); + if (IS_ERR_OR_NULL(dpu_kms->hw_vbif[vbif_idx])) { + rc = PTR_ERR(dpu_kms->hw_vbif[vbif_idx]); + if (!dpu_kms->hw_vbif[vbif_idx]) + rc = -EINVAL; + DPU_ERROR("failed to init vbif %d: %d\n", vbif_idx, rc); + dpu_kms->hw_vbif[vbif_idx] = NULL; + goto power_error; + } + } + + rc = dpu_core_perf_init(&dpu_kms->perf, dev, dpu_kms->catalog, + &dpu_kms->phandle, + _dpu_kms_get_clk(dpu_kms, "core")); + if (rc) { + DPU_ERROR("failed to init perf %d\n", rc); + goto perf_err; + } + + dpu_kms->hw_intr = dpu_hw_intr_init(dpu_kms->mmio, dpu_kms->catalog); + if (IS_ERR_OR_NULL(dpu_kms->hw_intr)) { + rc = PTR_ERR(dpu_kms->hw_intr); + DPU_ERROR("hw_intr init failed: %d\n", rc); + dpu_kms->hw_intr = NULL; + goto hw_intr_init_err; + } + + /* + * _dpu_kms_drm_obj_init should create the DRM related objects + * i.e. CRTCs, planes, encoders, connectors and so forth + */ + rc = _dpu_kms_drm_obj_init(dpu_kms); + if (rc) { + DPU_ERROR("modeset init failed: %d\n", rc); + goto drm_obj_init_err; + } + + dev->mode_config.min_width = 0; + dev->mode_config.min_height = 0; + + /* + * max crtc width is equal to the max mixer width * 2 and max height is + * is 4K + */ + dev->mode_config.max_width = + dpu_kms->catalog->caps->max_mixer_width * 2; + dev->mode_config.max_height = 4096; + + /* + * Support format modifiers for compression etc. + */ + dev->mode_config.allow_fb_modifiers = true; + + /* + * Handle (re)initializations during power enable + */ + dpu_kms_handle_power_event(DPU_POWER_EVENT_POST_ENABLE, dpu_kms); + dpu_kms->power_event = dpu_power_handle_register_event( + &dpu_kms->phandle, + DPU_POWER_EVENT_POST_ENABLE, + dpu_kms_handle_power_event, dpu_kms, "kms"); + + pm_runtime_put_sync(&dpu_kms->pdev->dev); + + return 0; + +drm_obj_init_err: + dpu_core_perf_destroy(&dpu_kms->perf); +hw_intr_init_err: +perf_err: +power_error: + pm_runtime_put_sync(&dpu_kms->pdev->dev); +error: + _dpu_kms_hw_destroy(dpu_kms); +dbg_destroy: + dpu_dbg_destroy(); +end: + return rc; +} + +struct msm_kms *dpu_kms_init(struct drm_device *dev) +{ + struct msm_drm_private *priv; + struct dpu_kms *dpu_kms; + int irq; + + if (!dev || !dev->dev_private) { + DPU_ERROR("drm device node invalid\n"); + return ERR_PTR(-EINVAL); + } + + priv = dev->dev_private; + dpu_kms = to_dpu_kms(priv->kms); + + irq = irq_of_parse_and_map(dpu_kms->pdev->dev.of_node, 0); + if (irq < 0) { + DPU_ERROR("failed to get irq: %d\n", irq); + return ERR_PTR(irq); + } + dpu_kms->base.irq = irq; + + return &dpu_kms->base; +} + +static int dpu_bind(struct device *dev, struct device *master, void *data) +{ + struct drm_device *ddev = dev_get_drvdata(master); + struct platform_device *pdev = to_platform_device(dev); + struct msm_drm_private *priv = ddev->dev_private; + struct dpu_kms *dpu_kms; + struct dss_module_power *mp; + int ret = 0; + + dpu_kms = devm_kzalloc(&pdev->dev, sizeof(*dpu_kms), GFP_KERNEL); + if (!dpu_kms) + return -ENOMEM; + + mp = &dpu_kms->mp; + ret = msm_dss_parse_clock(pdev, mp); + if (ret) { + DPU_ERROR("failed to parse clocks, ret=%d\n", ret); + return ret; + } + + dpu_power_resource_init(pdev, &dpu_kms->phandle); + + platform_set_drvdata(pdev, dpu_kms); + + msm_kms_init(&dpu_kms->base, &kms_funcs); + dpu_kms->dev = ddev; + dpu_kms->pdev = pdev; + + pm_runtime_enable(&pdev->dev); + dpu_kms->rpm_enabled = true; + + priv->kms = &dpu_kms->base; + return ret; +} + +static void dpu_unbind(struct device *dev, struct device *master, void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + struct dpu_kms *dpu_kms = platform_get_drvdata(pdev); + struct dss_module_power *mp = &dpu_kms->mp; + + dpu_power_resource_deinit(pdev, &dpu_kms->phandle); + msm_dss_put_clk(mp->clk_config, mp->num_clk); + devm_kfree(&pdev->dev, mp->clk_config); + mp->num_clk = 0; + + if (dpu_kms->rpm_enabled) + pm_runtime_disable(&pdev->dev); +} + +static const struct component_ops dpu_ops = { + .bind = dpu_bind, + .unbind = dpu_unbind, +}; + +static int dpu_dev_probe(struct platform_device *pdev) +{ + return component_add(&pdev->dev, &dpu_ops); +} + +static int dpu_dev_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &dpu_ops); + return 0; +} + +static int dpu_runtime_suspend(struct device *dev) +{ + int rc = -1; + struct platform_device *pdev = to_platform_device(dev); + struct dpu_kms *dpu_kms = platform_get_drvdata(pdev); + struct drm_device *ddev; + struct dss_module_power *mp = &dpu_kms->mp; + + ddev = dpu_kms->dev; + if (!ddev) { + DPU_ERROR("invalid drm_device\n"); + goto exit; + } + + rc = dpu_power_resource_enable(&dpu_kms->phandle, + dpu_kms->core_client, false); + if (rc) + DPU_ERROR("resource disable failed: %d\n", rc); + + rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, false); + if (rc) + DPU_ERROR("clock disable failed rc:%d\n", rc); + +exit: + return rc; +} + +static int dpu_runtime_resume(struct device *dev) +{ + int rc = -1; + struct platform_device *pdev = to_platform_device(dev); + struct dpu_kms *dpu_kms = platform_get_drvdata(pdev); + struct drm_device *ddev; + struct dss_module_power *mp = &dpu_kms->mp; + + ddev = dpu_kms->dev; + if (!ddev) { + DPU_ERROR("invalid drm_device\n"); + goto exit; + } + + rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, true); + if (rc) { + DPU_ERROR("clock enable failed rc:%d\n", rc); + goto exit; + } + + rc = dpu_power_resource_enable(&dpu_kms->phandle, + dpu_kms->core_client, true); + if (rc) + DPU_ERROR("resource enable failed: %d\n", rc); + +exit: + return rc; +} + +static const struct dev_pm_ops dpu_pm_ops = { + SET_RUNTIME_PM_OPS(dpu_runtime_suspend, dpu_runtime_resume, NULL) +}; + +static const struct of_device_id dpu_dt_match[] = { + { .compatible = "qcom,sdm845-dpu", }, + {} +}; +MODULE_DEVICE_TABLE(of, dpu_dt_match); + +static struct platform_driver dpu_driver = { + .probe = dpu_dev_probe, + .remove = dpu_dev_remove, + .driver = { + .name = "msm_dpu", + .of_match_table = dpu_dt_match, + .pm = &dpu_pm_ops, + }, +}; + +void __init msm_dpu_register(void) +{ + platform_driver_register(&dpu_driver); +} + +void __exit msm_dpu_unregister(void) +{ + platform_driver_unregister(&dpu_driver); +} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h new file mode 100644 index 0000000000000..407c1ed27fe63 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h @@ -0,0 +1,402 @@ +/* + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.com> + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __DPU_KMS_H__ +#define __DPU_KMS_H__ + +#include "msm_drv.h" +#include "msm_kms.h" +#include "msm_mmu.h" +#include "msm_gem.h" +#include "dpu_dbg.h" +#include "dpu_hw_catalog.h" +#include "dpu_hw_ctl.h" +#include "dpu_hw_lm.h" +#include "dpu_hw_interrupts.h" +#include "dpu_hw_top.h" +#include "dpu_rm.h" +#include "dpu_power_handle.h" +#include "dpu_irq.h" +#include "dpu_core_perf.h" + +#define DRMID(x) ((x) ? (x)->base.id : -1) + +/** + * DPU_DEBUG - macro for kms/plane/crtc/encoder/connector logs + * @fmt: Pointer to format string + */ +#define DPU_DEBUG(fmt, ...) \ + do { \ + if (unlikely(drm_debug & DRM_UT_KMS)) \ + DRM_DEBUG(fmt, ##__VA_ARGS__); \ + else \ + pr_debug(fmt, ##__VA_ARGS__); \ + } while (0) + +/** + * DPU_DEBUG_DRIVER - macro for hardware driver logging + * @fmt: Pointer to format string + */ +#define DPU_DEBUG_DRIVER(fmt, ...) \ + do { \ + if (unlikely(drm_debug & DRM_UT_DRIVER)) \ + DRM_ERROR(fmt, ##__VA_ARGS__); \ + else \ + pr_debug(fmt, ##__VA_ARGS__); \ + } while (0) + +#define DPU_ERROR(fmt, ...) pr_err("[dpu error]" fmt, ##__VA_ARGS__) + +/** + * ktime_compare_safe - compare two ktime structures + * This macro is similar to the standard ktime_compare() function, but + * attempts to also handle ktime overflows. + * @A: First ktime value + * @B: Second ktime value + * Returns: -1 if A < B, 0 if A == B, 1 if A > B + */ +#define ktime_compare_safe(A, B) \ + ktime_compare(ktime_sub((A), (B)), ktime_set(0, 0)) + +#define DPU_NAME_SIZE 12 + +/* timeout in frames waiting for frame done */ +#define DPU_FRAME_DONE_TIMEOUT 60 + +/* + * struct dpu_irq_callback - IRQ callback handlers + * @list: list to callback + * @func: intr handler + * @arg: argument for the handler + */ +struct dpu_irq_callback { + struct list_head list; + void (*func)(void *arg, int irq_idx); + void *arg; +}; + +/** + * struct dpu_irq: IRQ structure contains callback registration info + * @total_irq: total number of irq_idx obtained from HW interrupts mapping + * @irq_cb_tbl: array of IRQ callbacks setting + * @enable_counts array of IRQ enable counts + * @cb_lock: callback lock + * @debugfs_file: debugfs file for irq statistics + */ +struct dpu_irq { + u32 total_irqs; + struct list_head *irq_cb_tbl; + atomic_t *enable_counts; + atomic_t *irq_counts; + spinlock_t cb_lock; + struct dentry *debugfs_file; +}; + +struct dpu_kms { + struct msm_kms base; + struct drm_device *dev; + int core_rev; + struct dpu_mdss_cfg *catalog; + + struct dpu_power_handle phandle; + struct dpu_power_client *core_client; + struct dpu_power_event *power_event; + + /* directory entry for debugfs */ + struct dentry *debugfs_root; + struct dentry *debugfs_danger; + struct dentry *debugfs_vbif; + + /* io/register spaces: */ + void __iomem *mmio, *vbif[VBIF_MAX], *reg_dma; + unsigned long mmio_len, vbif_len[VBIF_MAX], reg_dma_len; + + struct regulator *vdd; + struct regulator *mmagic; + struct regulator *venus; + + struct dpu_hw_intr *hw_intr; + struct dpu_irq irq_obj; + + struct dpu_core_perf perf; + + /* saved atomic state during system suspend */ + struct drm_atomic_state *suspend_state; + bool suspend_block; + + struct dpu_rm rm; + bool rm_init; + + struct dpu_hw_vbif *hw_vbif[VBIF_MAX]; + struct dpu_hw_mdp *hw_mdp; + + bool has_danger_ctrl; + + struct platform_device *pdev; + bool rpm_enabled; + struct dss_module_power mp; +}; + +struct vsync_info { + u32 frame_count; + u32 line_count; +}; + +#define to_dpu_kms(x) container_of(x, struct dpu_kms, base) + +/* get struct msm_kms * from drm_device * */ +#define ddev_to_msm_kms(D) ((D) && (D)->dev_private ? \ + ((struct msm_drm_private *)((D)->dev_private))->kms : NULL) + +/** + * dpu_kms_is_suspend_state - whether or not the system is pm suspended + * @dev: Pointer to drm device + * Return: Suspend status + */ +static inline bool dpu_kms_is_suspend_state(struct drm_device *dev) +{ + if (!ddev_to_msm_kms(dev)) + return false; + + return to_dpu_kms(ddev_to_msm_kms(dev))->suspend_state != NULL; +} + +/** + * dpu_kms_is_suspend_blocked - whether or not commits are blocked due to pm + * suspend status + * @dev: Pointer to drm device + * Return: True if commits should be rejected due to pm suspend + */ +static inline bool dpu_kms_is_suspend_blocked(struct drm_device *dev) +{ + if (!dpu_kms_is_suspend_state(dev)) + return false; + + return to_dpu_kms(ddev_to_msm_kms(dev))->suspend_block; +} + +/** + * Debugfs functions - extra helper functions for debugfs support + * + * Main debugfs documentation is located at, + * + * Documentation/filesystems/debugfs.txt + * + * @dpu_debugfs_setup_regset32: Initialize data for dpu_debugfs_create_regset32 + * @dpu_debugfs_create_regset32: Create 32-bit register dump file + * @dpu_debugfs_get_root: Get root dentry for DPU_KMS's debugfs node + */ + +/** + * Companion structure for dpu_debugfs_create_regset32. Do not initialize the + * members of this structure explicitly; use dpu_debugfs_setup_regset32 instead. + */ +struct dpu_debugfs_regset32 { + uint32_t offset; + uint32_t blk_len; + struct dpu_kms *dpu_kms; +}; + +/** + * dpu_debugfs_setup_regset32 - Initialize register block definition for debugfs + * This function is meant to initialize dpu_debugfs_regset32 structures for use + * with dpu_debugfs_create_regset32. + * @regset: opaque register definition structure + * @offset: sub-block offset + * @length: sub-block length, in bytes + * @dpu_kms: pointer to dpu kms structure + */ +void dpu_debugfs_setup_regset32(struct dpu_debugfs_regset32 *regset, + uint32_t offset, uint32_t length, struct dpu_kms *dpu_kms); + +/** + * dpu_debugfs_create_regset32 - Create register read back file for debugfs + * + * This function is almost identical to the standard debugfs_create_regset32() + * function, with the main difference being that a list of register + * names/offsets do not need to be provided. The 'read' function simply outputs + * sequential register values over a specified range. + * + * Similar to the related debugfs_create_regset32 API, the structure pointed to + * by regset needs to persist for the lifetime of the created file. The calling + * code is responsible for initialization/management of this structure. + * + * The structure pointed to by regset is meant to be opaque. Please use + * dpu_debugfs_setup_regset32 to initialize it. + * + * @name: File name within debugfs + * @mode: File mode within debugfs + * @parent: Parent directory entry within debugfs, can be NULL + * @regset: Pointer to persistent register block definition + * + * Return: dentry pointer for newly created file, use either debugfs_remove() + * or debugfs_remove_recursive() (on a parent directory) to remove the + * file + */ +void *dpu_debugfs_create_regset32(const char *name, umode_t mode, + void *parent, struct dpu_debugfs_regset32 *regset); + +/** + * dpu_debugfs_get_root - Return root directory entry for KMS's debugfs + * + * The return value should be passed as the 'parent' argument to subsequent + * debugfs create calls. + * + * @dpu_kms: Pointer to DPU's KMS structure + * + * Return: dentry pointer for DPU's debugfs location + */ +void *dpu_debugfs_get_root(struct dpu_kms *dpu_kms); + +/** + * DPU info management functions + * These functions/definitions allow for building up a 'dpu_info' structure + * containing one or more "key=value\n" entries. + */ +#define DPU_KMS_INFO_MAX_SIZE 4096 + +/** + * struct dpu_kms_info - connector information structure container + * @data: Array of information character data + * @len: Current length of information data + * @staged_len: Temporary data buffer length, commit to + * len using dpu_kms_info_stop + * @start: Whether or not a partial data entry was just started + */ +struct dpu_kms_info { + char data[DPU_KMS_INFO_MAX_SIZE]; + uint32_t len; + uint32_t staged_len; + bool start; +}; + +/** + * DPU_KMS_INFO_DATA - Macro for accessing dpu_kms_info data bytes + * @S: Pointer to dpu_kms_info structure + * Returns: Pointer to byte data + */ +#define DPU_KMS_INFO_DATA(S) ((S) ? ((struct dpu_kms_info *)(S))->data : 0) + +/** + * DPU_KMS_INFO_DATALEN - Macro for accessing dpu_kms_info data length + * it adds an extra character length to count null. + * @S: Pointer to dpu_kms_info structure + * Returns: Size of available byte data + */ +#define DPU_KMS_INFO_DATALEN(S) ((S) ? ((struct dpu_kms_info *)(S))->len + 1 \ + : 0) + +/** + * dpu_kms_info_reset - reset dpu_kms_info structure + * @info: Pointer to dpu_kms_info structure + */ +void dpu_kms_info_reset(struct dpu_kms_info *info); + +/** + * dpu_kms_info_add_keyint - add integer value to 'dpu_kms_info' + * @info: Pointer to dpu_kms_info structure + * @key: Pointer to key string + * @value: Signed 64-bit integer value + */ +void dpu_kms_info_add_keyint(struct dpu_kms_info *info, + const char *key, + int64_t value); + +/** + * dpu_kms_info_add_keystr - add string value to 'dpu_kms_info' + * @info: Pointer to dpu_kms_info structure + * @key: Pointer to key string + * @value: Pointer to string value + */ +void dpu_kms_info_add_keystr(struct dpu_kms_info *info, + const char *key, + const char *value); + +/** + * dpu_kms_info_start - begin adding key to 'dpu_kms_info' + * Usage: + * dpu_kms_info_start(key) + * dpu_kms_info_append(val_1) + * ... + * dpu_kms_info_append(val_n) + * dpu_kms_info_stop + * @info: Pointer to dpu_kms_info structure + * @key: Pointer to key string + */ +void dpu_kms_info_start(struct dpu_kms_info *info, + const char *key); + +/** + * dpu_kms_info_append - append value string to 'dpu_kms_info' + * Usage: + * dpu_kms_info_start(key) + * dpu_kms_info_append(val_1) + * ... + * dpu_kms_info_append(val_n) + * dpu_kms_info_stop + * @info: Pointer to dpu_kms_info structure + * @str: Pointer to partial value string + */ +void dpu_kms_info_append(struct dpu_kms_info *info, + const char *str); + +/** + * dpu_kms_info_append_format - append format code string to 'dpu_kms_info' + * Usage: + * dpu_kms_info_start(key) + * dpu_kms_info_append_format(fourcc, modifier) + * ... + * dpu_kms_info_stop + * @info: Pointer to dpu_kms_info structure + * @pixel_format: FOURCC format code + * @modifier: 64-bit drm format modifier + */ +void dpu_kms_info_append_format(struct dpu_kms_info *info, + uint32_t pixel_format, + uint64_t modifier); + +/** + * dpu_kms_info_stop - finish adding key to 'dpu_kms_info' + * Usage: + * dpu_kms_info_start(key) + * dpu_kms_info_append(val_1) + * ... + * dpu_kms_info_append(val_n) + * dpu_kms_info_stop + * @info: Pointer to dpu_kms_info structure + */ +void dpu_kms_info_stop(struct dpu_kms_info *info); + +/** + * Vblank enable/disable functions + */ +int dpu_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc); +void dpu_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc); + +void dpu_kms_encoder_enable(struct drm_encoder *encoder); + +/** + * dpu_kms_get_clk_rate() - get the clock rate + * @dpu_kms: poiner to dpu_kms structure + * @clock_name: clock name to get the rate + * + * Return: current clock rate + */ +u64 dpu_kms_get_clk_rate(struct dpu_kms *dpu_kms, char *clock_name); + +#endif /* __dpu_kms_H__ */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms_utils.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms_utils.c new file mode 100644 index 0000000000000..a80b3da5a9feb --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms_utils.c @@ -0,0 +1,153 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#define pr_fmt(fmt) "dpu-kms_utils:[%s] " fmt, __func__ + +#include "dpu_kms.h" + +void dpu_kms_info_reset(struct dpu_kms_info *info) +{ + if (info) { + info->len = 0; + info->staged_len = 0; + } +} + +void dpu_kms_info_add_keyint(struct dpu_kms_info *info, + const char *key, + int64_t value) +{ + uint32_t len; + + if (info && key) { + len = snprintf(info->data + info->len, + DPU_KMS_INFO_MAX_SIZE - info->len, + "%s=%lld\n", + key, + value); + + /* check if snprintf truncated the string */ + if ((info->len + len) < DPU_KMS_INFO_MAX_SIZE) + info->len += len; + } +} + +void dpu_kms_info_add_keystr(struct dpu_kms_info *info, + const char *key, + const char *value) +{ + uint32_t len; + + if (info && key && value) { + len = snprintf(info->data + info->len, + DPU_KMS_INFO_MAX_SIZE - info->len, + "%s=%s\n", + key, + value); + + /* check if snprintf truncated the string */ + if ((info->len + len) < DPU_KMS_INFO_MAX_SIZE) + info->len += len; + } +} + +void dpu_kms_info_start(struct dpu_kms_info *info, + const char *key) +{ + uint32_t len; + + if (info && key) { + len = snprintf(info->data + info->len, + DPU_KMS_INFO_MAX_SIZE - info->len, + "%s=", + key); + + info->start = true; + + /* check if snprintf truncated the string */ + if ((info->len + len) < DPU_KMS_INFO_MAX_SIZE) + info->staged_len = info->len + len; + } +} + +void dpu_kms_info_append(struct dpu_kms_info *info, + const char *str) +{ + uint32_t len; + + if (info) { + len = snprintf(info->data + info->staged_len, + DPU_KMS_INFO_MAX_SIZE - info->staged_len, + "%s", + str); + + /* check if snprintf truncated the string */ + if ((info->staged_len + len) < DPU_KMS_INFO_MAX_SIZE) { + info->staged_len += len; + info->start = false; + } + } +} + +void dpu_kms_info_append_format(struct dpu_kms_info *info, + uint32_t pixel_format, + uint64_t modifier) +{ + uint32_t len; + + if (!info) + return; + + if (modifier) { + len = snprintf(info->data + info->staged_len, + DPU_KMS_INFO_MAX_SIZE - info->staged_len, + info->start ? + "%c%c%c%c/%llX/%llX" : " %c%c%c%c/%llX/%llX", + (pixel_format >> 0) & 0xFF, + (pixel_format >> 8) & 0xFF, + (pixel_format >> 16) & 0xFF, + (pixel_format >> 24) & 0xFF, + (modifier >> 56) & 0xFF, + modifier & ((1ULL << 56) - 1)); + } else { + len = snprintf(info->data + info->staged_len, + DPU_KMS_INFO_MAX_SIZE - info->staged_len, + info->start ? + "%c%c%c%c" : " %c%c%c%c", + (pixel_format >> 0) & 0xFF, + (pixel_format >> 8) & 0xFF, + (pixel_format >> 16) & 0xFF, + (pixel_format >> 24) & 0xFF); + } + + /* check if snprintf truncated the string */ + if ((info->staged_len + len) < DPU_KMS_INFO_MAX_SIZE) { + info->staged_len += len; + info->start = false; + } +} + +void dpu_kms_info_stop(struct dpu_kms_info *info) +{ + uint32_t len; + + if (info) { + /* insert final delimiter */ + len = snprintf(info->data + info->staged_len, + DPU_KMS_INFO_MAX_SIZE - info->staged_len, + "\n"); + + /* check if snprintf truncated the string */ + if ((info->staged_len + len) < DPU_KMS_INFO_MAX_SIZE) + info->len = info->staged_len + len; + } +} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c new file mode 100644 index 0000000000000..6dfc26698a09b --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c @@ -0,0 +1,245 @@ +/* + * SPDX-License-Identifier: GPL-2.0 + * Copyright (c) 2018, The Linux Foundation + */ + +#include "dpu_kms.h" + +#define to_dpu_mdss(x) container_of(x, struct dpu_mdss, base) + +#define HW_INTR_STATUS 0x0010 + +struct dpu_mdss { + struct msm_mdss base; + void __iomem *mmio; + unsigned long mmio_len; + u32 hwversion; + struct dss_module_power mp; + struct dpu_irq_controller irq_controller; +}; + +static irqreturn_t dpu_mdss_irq(int irq, void *arg) +{ + struct dpu_mdss *dpu_mdss = arg; + u32 interrupts; + + interrupts = readl_relaxed(dpu_mdss->mmio + HW_INTR_STATUS); + + while (interrupts) { + irq_hw_number_t hwirq = fls(interrupts) - 1; + unsigned int mapping; + int rc; + + mapping = irq_find_mapping(dpu_mdss->irq_controller.domain, + hwirq); + if (mapping == 0) { + DRM_ERROR("couldn't find irq mapping for %lu\n", hwirq); + return IRQ_NONE; + } + + rc = generic_handle_irq(mapping); + if (rc < 0) { + DRM_ERROR("handle irq fail: irq=%lu mapping=%u rc=%d\n", + hwirq, mapping, rc); + return IRQ_NONE; + } + + interrupts &= ~(1 << hwirq); + } + + return IRQ_HANDLED; +} + +static void dpu_mdss_irq_mask(struct irq_data *irqd) +{ + struct dpu_mdss *dpu_mdss = irq_data_get_irq_chip_data(irqd); + + /* memory barrier */ + smp_mb__before_atomic(); + clear_bit(irqd->hwirq, &dpu_mdss->irq_controller.enabled_mask); + /* memory barrier */ + smp_mb__after_atomic(); +} + +static void dpu_mdss_irq_unmask(struct irq_data *irqd) +{ + struct dpu_mdss *dpu_mdss = irq_data_get_irq_chip_data(irqd); + + /* memory barrier */ + smp_mb__before_atomic(); + set_bit(irqd->hwirq, &dpu_mdss->irq_controller.enabled_mask); + /* memory barrier */ + smp_mb__after_atomic(); +} + +static struct irq_chip dpu_mdss_irq_chip = { + .name = "dpu_mdss", + .irq_mask = dpu_mdss_irq_mask, + .irq_unmask = dpu_mdss_irq_unmask, +}; + +static int dpu_mdss_irqdomain_map(struct irq_domain *domain, + unsigned int irq, irq_hw_number_t hwirq) +{ + struct dpu_mdss *dpu_mdss = domain->host_data; + int ret; + + irq_set_chip_and_handler(irq, &dpu_mdss_irq_chip, handle_level_irq); + ret = irq_set_chip_data(irq, dpu_mdss); + + return ret; +} + +static const struct irq_domain_ops dpu_mdss_irqdomain_ops = { + .map = dpu_mdss_irqdomain_map, + .xlate = irq_domain_xlate_onecell, +}; + +static int _dpu_mdss_irq_domain_add(struct dpu_mdss *dpu_mdss) +{ + struct device *dev; + struct irq_domain *domain; + + dev = dpu_mdss->base.dev->dev; + + domain = irq_domain_add_linear(dev->of_node, 32, + &dpu_mdss_irqdomain_ops, dpu_mdss); + if (!domain) { + DPU_ERROR("failed to add irq_domain\n"); + return -EINVAL; + } + + dpu_mdss->irq_controller.enabled_mask = 0; + dpu_mdss->irq_controller.domain = domain; + + return 0; +} + +int _dpu_mdss_irq_domain_fini(struct dpu_mdss *dpu_mdss) +{ + if (dpu_mdss->irq_controller.domain) { + irq_domain_remove(dpu_mdss->irq_controller.domain); + dpu_mdss->irq_controller.domain = NULL; + } + return 0; +} +static int dpu_mdss_enable(struct msm_mdss *mdss) +{ + struct dpu_mdss *dpu_mdss = to_dpu_mdss(mdss); + struct dss_module_power *mp = &dpu_mdss->mp; + int ret; + + ret = msm_dss_enable_clk(mp->clk_config, mp->num_clk, true); + if (ret) + DPU_ERROR("clock enable failed, ret:%d\n", ret); + + return ret; +} + +static int dpu_mdss_disable(struct msm_mdss *mdss) +{ + struct dpu_mdss *dpu_mdss = to_dpu_mdss(mdss); + struct dss_module_power *mp = &dpu_mdss->mp; + int ret; + + ret = msm_dss_enable_clk(mp->clk_config, mp->num_clk, false); + if (ret) + DPU_ERROR("clock disable failed, ret:%d\n", ret); + + return ret; +} + +static void dpu_mdss_destroy(struct drm_device *dev) +{ + struct platform_device *pdev = to_platform_device(dev->dev); + struct msm_drm_private *priv = dev->dev_private; + struct dpu_mdss *dpu_mdss = to_dpu_mdss(priv->mdss); + struct dss_module_power *mp = &dpu_mdss->mp; + + _dpu_mdss_irq_domain_fini(dpu_mdss); + + msm_dss_put_clk(mp->clk_config, mp->num_clk); + devm_kfree(&pdev->dev, mp->clk_config); + + if (dpu_mdss->mmio) + devm_iounmap(&pdev->dev, dpu_mdss->mmio); + dpu_mdss->mmio = NULL; + + pm_runtime_disable(dev->dev); + priv->mdss = NULL; +} + +static const struct msm_mdss_funcs mdss_funcs = { + .enable = dpu_mdss_enable, + .disable = dpu_mdss_disable, + .destroy = dpu_mdss_destroy, +}; + +int dpu_mdss_init(struct drm_device *dev) +{ + struct platform_device *pdev = to_platform_device(dev->dev); + struct msm_drm_private *priv = dev->dev_private; + struct resource *res; + struct dpu_mdss *dpu_mdss; + struct dss_module_power *mp; + int ret = 0; + + dpu_mdss = devm_kzalloc(dev->dev, sizeof(*dpu_mdss), GFP_KERNEL); + if (!dpu_mdss) + return -ENOMEM; + + dpu_mdss->mmio = msm_ioremap(pdev, "mdss", "mdss"); + if (IS_ERR(dpu_mdss->mmio)) + return PTR_ERR(dpu_mdss->mmio); + + DRM_DEBUG("mapped mdss address space @%pK\n", dpu_mdss->mmio); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mdss"); + if (!res) { + DRM_ERROR("failed to get memory resource for mdss\n"); + return -ENOMEM; + } + dpu_mdss->mmio_len = resource_size(res); + + mp = &dpu_mdss->mp; + ret = msm_dss_parse_clock(pdev, mp); + if (ret) { + DPU_ERROR("failed to parse clocks, ret=%d\n", ret); + goto clk_parse_err; + } + + dpu_mdss->base.dev = dev; + dpu_mdss->base.funcs = &mdss_funcs; + + ret = _dpu_mdss_irq_domain_add(dpu_mdss); + if (ret) + goto irq_domain_error; + + ret = devm_request_irq(dev->dev, platform_get_irq(pdev, 0), + dpu_mdss_irq, 0, "dpu_mdss_isr", dpu_mdss); + if (ret) { + DPU_ERROR("failed to init irq: %d\n", ret); + goto irq_error; + } + + pm_runtime_enable(dev->dev); + + pm_runtime_get_sync(dev->dev); + dpu_mdss->hwversion = readl_relaxed(dpu_mdss->mmio); + pm_runtime_put_sync(dev->dev); + + priv->mdss = &dpu_mdss->base; + + return ret; + +irq_error: + _dpu_mdss_irq_domain_fini(dpu_mdss); +irq_domain_error: + msm_dss_put_clk(mp->clk_config, mp->num_clk); +clk_parse_err: + devm_kfree(&pdev->dev, mp->clk_config); + if (dpu_mdss->mmio) + devm_iounmap(&pdev->dev, dpu_mdss->mmio); + dpu_mdss->mmio = NULL; + return ret; +} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c new file mode 100644 index 0000000000000..b640e39ebaca2 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c @@ -0,0 +1,1963 @@ +/* + * Copyright (C) 2014-2018 The Linux Foundation. All rights reserved. + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.com> + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ + +#include <linux/debugfs.h> +#include <linux/dma-buf.h> + +#include "msm_drv.h" +#include "dpu_kms.h" +#include "dpu_formats.h" +#include "dpu_hw_sspp.h" +#include "dpu_hw_catalog_format.h" +#include "dpu_trace.h" +#include "dpu_crtc.h" +#include "dpu_vbif.h" +#include "dpu_plane.h" + +#define DPU_DEBUG_PLANE(pl, fmt, ...) DPU_DEBUG("plane%d " fmt,\ + (pl) ? (pl)->base.base.id : -1, ##__VA_ARGS__) + +#define DPU_ERROR_PLANE(pl, fmt, ...) DPU_ERROR("plane%d " fmt,\ + (pl) ? (pl)->base.base.id : -1, ##__VA_ARGS__) + +#define DECIMATED_DIMENSION(dim, deci) (((dim) + ((1 << (deci)) - 1)) >> (deci)) +#define PHASE_STEP_SHIFT 21 +#define PHASE_STEP_UNIT_SCALE ((int) (1 << PHASE_STEP_SHIFT)) +#define PHASE_RESIDUAL 15 + +#define SHARP_STRENGTH_DEFAULT 32 +#define SHARP_EDGE_THR_DEFAULT 112 +#define SHARP_SMOOTH_THR_DEFAULT 8 +#define SHARP_NOISE_THR_DEFAULT 2 + +#define DPU_NAME_SIZE 12 + +#define DPU_PLANE_COLOR_FILL_FLAG BIT(31) +#define DPU_ZPOS_MAX 255 + +/* multirect rect index */ +enum { + R0, + R1, + R_MAX +}; + +#define DPU_QSEED3_DEFAULT_PRELOAD_H 0x4 +#define DPU_QSEED3_DEFAULT_PRELOAD_V 0x3 + +#define DEFAULT_REFRESH_RATE 60 + +/** + * enum dpu_plane_qos - Different qos configurations for each pipe + * + * @DPU_PLANE_QOS_VBLANK_CTRL: Setup VBLANK qos for the pipe. + * @DPU_PLANE_QOS_VBLANK_AMORTIZE: Enables Amortization within pipe. + * this configuration is mutually exclusive from VBLANK_CTRL. + * @DPU_PLANE_QOS_PANIC_CTRL: Setup panic for the pipe. + */ +enum dpu_plane_qos { + DPU_PLANE_QOS_VBLANK_CTRL = BIT(0), + DPU_PLANE_QOS_VBLANK_AMORTIZE = BIT(1), + DPU_PLANE_QOS_PANIC_CTRL = BIT(2), +}; + +/* + * struct dpu_plane - local dpu plane structure + * @aspace: address space pointer + * @csc_ptr: Points to dpu_csc_cfg structure to use for current + * @mplane_list: List of multirect planes of the same pipe + * @catalog: Points to dpu catalog structure + * @revalidate: force revalidation of all the plane properties + */ +struct dpu_plane { + struct drm_plane base; + + struct mutex lock; + + enum dpu_sspp pipe; + uint32_t features; /* capabilities from catalog */ + uint32_t nformats; + uint32_t formats[64]; + + struct dpu_hw_pipe *pipe_hw; + struct dpu_hw_pipe_cfg pipe_cfg; + struct dpu_hw_pipe_qos_cfg pipe_qos_cfg; + uint32_t color_fill; + bool is_error; + bool is_rt_pipe; + bool is_virtual; + struct list_head mplane_list; + struct dpu_mdss_cfg *catalog; + + struct dpu_csc_cfg *csc_ptr; + + const struct dpu_sspp_sub_blks *pipe_sblk; + char pipe_name[DPU_NAME_SIZE]; + + /* debugfs related stuff */ + struct dentry *debugfs_root; + struct dpu_debugfs_regset32 debugfs_src; + struct dpu_debugfs_regset32 debugfs_scaler; + struct dpu_debugfs_regset32 debugfs_csc; + bool debugfs_default_scale; +}; + +#define to_dpu_plane(x) container_of(x, struct dpu_plane, base) + +static struct dpu_kms *_dpu_plane_get_kms(struct drm_plane *plane) +{ + struct msm_drm_private *priv; + + if (!plane || !plane->dev) + return NULL; + priv = plane->dev->dev_private; + if (!priv) + return NULL; + return to_dpu_kms(priv->kms); +} + +static bool dpu_plane_enabled(struct drm_plane_state *state) +{ + return state && state->fb && state->crtc; +} + +static bool dpu_plane_sspp_enabled(struct drm_plane_state *state) +{ + return state && state->crtc; +} + +/** + * _dpu_plane_calc_fill_level - calculate fill level of the given source format + * @plane: Pointer to drm plane + * @fmt: Pointer to source buffer format + * @src_wdith: width of source buffer + * Return: fill level corresponding to the source buffer/format or 0 if error + */ +static inline int _dpu_plane_calc_fill_level(struct drm_plane *plane, + const struct dpu_format *fmt, u32 src_width) +{ + struct dpu_plane *pdpu, *tmp; + struct dpu_plane_state *pstate; + u32 fixed_buff_size; + u32 total_fl; + + if (!plane || !fmt || !plane->state || !src_width || !fmt->bpp) { + DPU_ERROR("invalid arguments\n"); + return 0; + } + + pdpu = to_dpu_plane(plane); + pstate = to_dpu_plane_state(plane->state); + fixed_buff_size = pdpu->pipe_sblk->common->pixel_ram_size; + + list_for_each_entry(tmp, &pdpu->mplane_list, mplane_list) { + if (!dpu_plane_enabled(tmp->base.state)) + continue; + DPU_DEBUG("plane%d/%d src_width:%d/%d\n", + pdpu->base.base.id, tmp->base.base.id, + src_width, + drm_rect_width(&tmp->pipe_cfg.src_rect)); + src_width = max_t(u32, src_width, + drm_rect_width(&tmp->pipe_cfg.src_rect)); + } + + if (fmt->fetch_planes == DPU_PLANE_PSEUDO_PLANAR) { + if (fmt->chroma_sample == DPU_CHROMA_420) { + /* NV12 */ + total_fl = (fixed_buff_size / 2) / + ((src_width + 32) * fmt->bpp); + } else { + /* non NV12 */ + total_fl = (fixed_buff_size / 2) * 2 / + ((src_width + 32) * fmt->bpp); + } + } else { + if (pstate->multirect_mode == DPU_SSPP_MULTIRECT_PARALLEL) { + total_fl = (fixed_buff_size / 2) * 2 / + ((src_width + 32) * fmt->bpp); + } else { + total_fl = (fixed_buff_size) * 2 / + ((src_width + 32) * fmt->bpp); + } + } + + DPU_DEBUG("plane%u: pnum:%d fmt: %4.4s w:%u fl:%u\n", + plane->base.id, pdpu->pipe - SSPP_VIG0, + (char *)&fmt->base.pixel_format, + src_width, total_fl); + + return total_fl; +} + +/** + * _dpu_plane_get_qos_lut - get LUT mapping based on fill level + * @tbl: Pointer to LUT table + * @total_fl: fill level + * Return: LUT setting corresponding to the fill level + */ +static u64 _dpu_plane_get_qos_lut(const struct dpu_qos_lut_tbl *tbl, + u32 total_fl) +{ + int i; + + if (!tbl || !tbl->nentry || !tbl->entries) + return 0; + + for (i = 0; i < tbl->nentry; i++) + if (total_fl <= tbl->entries[i].fl) + return tbl->entries[i].lut; + + /* if last fl is zero, use as default */ + if (!tbl->entries[i-1].fl) + return tbl->entries[i-1].lut; + + return 0; +} + +/** + * _dpu_plane_set_qos_lut - set QoS LUT of the given plane + * @plane: Pointer to drm plane + * @fb: Pointer to framebuffer associated with the given plane + */ +static void _dpu_plane_set_qos_lut(struct drm_plane *plane, + struct drm_framebuffer *fb) +{ + struct dpu_plane *pdpu; + const struct dpu_format *fmt = NULL; + u64 qos_lut; + u32 total_fl = 0, lut_usage; + + if (!plane || !fb) { + DPU_ERROR("invalid arguments plane %d fb %d\n", + plane != 0, fb != 0); + return; + } + + pdpu = to_dpu_plane(plane); + + if (!pdpu->pipe_hw || !pdpu->pipe_sblk || !pdpu->catalog) { + DPU_ERROR("invalid arguments\n"); + return; + } else if (!pdpu->pipe_hw->ops.setup_creq_lut) { + return; + } + + if (!pdpu->is_rt_pipe) { + lut_usage = DPU_QOS_LUT_USAGE_NRT; + } else { + fmt = dpu_get_dpu_format_ext( + fb->format->format, + fb->modifier); + total_fl = _dpu_plane_calc_fill_level(plane, fmt, + drm_rect_width(&pdpu->pipe_cfg.src_rect)); + + if (fmt && DPU_FORMAT_IS_LINEAR(fmt)) + lut_usage = DPU_QOS_LUT_USAGE_LINEAR; + else + lut_usage = DPU_QOS_LUT_USAGE_MACROTILE; + } + + qos_lut = _dpu_plane_get_qos_lut( + &pdpu->catalog->perf.qos_lut_tbl[lut_usage], total_fl); + + pdpu->pipe_qos_cfg.creq_lut = qos_lut; + + trace_dpu_perf_set_qos_luts(pdpu->pipe - SSPP_VIG0, + (fmt) ? fmt->base.pixel_format : 0, + pdpu->is_rt_pipe, total_fl, qos_lut, lut_usage); + + DPU_DEBUG("plane%u: pnum:%d fmt: %4.4s rt:%d fl:%u lut:0x%llx\n", + plane->base.id, + pdpu->pipe - SSPP_VIG0, + fmt ? (char *)&fmt->base.pixel_format : NULL, + pdpu->is_rt_pipe, total_fl, qos_lut); + + pdpu->pipe_hw->ops.setup_creq_lut(pdpu->pipe_hw, &pdpu->pipe_qos_cfg); +} + +/** + * _dpu_plane_set_panic_lut - set danger/safe LUT of the given plane + * @plane: Pointer to drm plane + * @fb: Pointer to framebuffer associated with the given plane + */ +static void _dpu_plane_set_danger_lut(struct drm_plane *plane, + struct drm_framebuffer *fb) +{ + struct dpu_plane *pdpu; + const struct dpu_format *fmt = NULL; + u32 danger_lut, safe_lut; + + if (!plane || !fb) { + DPU_ERROR("invalid arguments\n"); + return; + } + + pdpu = to_dpu_plane(plane); + + if (!pdpu->pipe_hw || !pdpu->pipe_sblk || !pdpu->catalog) { + DPU_ERROR("invalid arguments\n"); + return; + } else if (!pdpu->pipe_hw->ops.setup_danger_safe_lut) { + return; + } + + if (!pdpu->is_rt_pipe) { + danger_lut = pdpu->catalog->perf.danger_lut_tbl + [DPU_QOS_LUT_USAGE_NRT]; + safe_lut = pdpu->catalog->perf.safe_lut_tbl + [DPU_QOS_LUT_USAGE_NRT]; + } else { + fmt = dpu_get_dpu_format_ext( + fb->format->format, + fb->modifier); + + if (fmt && DPU_FORMAT_IS_LINEAR(fmt)) { + danger_lut = pdpu->catalog->perf.danger_lut_tbl + [DPU_QOS_LUT_USAGE_LINEAR]; + safe_lut = pdpu->catalog->perf.safe_lut_tbl + [DPU_QOS_LUT_USAGE_LINEAR]; + } else { + danger_lut = pdpu->catalog->perf.danger_lut_tbl + [DPU_QOS_LUT_USAGE_MACROTILE]; + safe_lut = pdpu->catalog->perf.safe_lut_tbl + [DPU_QOS_LUT_USAGE_MACROTILE]; + } + } + + pdpu->pipe_qos_cfg.danger_lut = danger_lut; + pdpu->pipe_qos_cfg.safe_lut = safe_lut; + + trace_dpu_perf_set_danger_luts(pdpu->pipe - SSPP_VIG0, + (fmt) ? fmt->base.pixel_format : 0, + (fmt) ? fmt->fetch_mode : 0, + pdpu->pipe_qos_cfg.danger_lut, + pdpu->pipe_qos_cfg.safe_lut); + + DPU_DEBUG("plane%u: pnum:%d fmt: %4.4s mode:%d luts[0x%x, 0x%x]\n", + plane->base.id, + pdpu->pipe - SSPP_VIG0, + fmt ? (char *)&fmt->base.pixel_format : NULL, + fmt ? fmt->fetch_mode : -1, + pdpu->pipe_qos_cfg.danger_lut, + pdpu->pipe_qos_cfg.safe_lut); + + pdpu->pipe_hw->ops.setup_danger_safe_lut(pdpu->pipe_hw, + &pdpu->pipe_qos_cfg); +} + +/** + * _dpu_plane_set_qos_ctrl - set QoS control of the given plane + * @plane: Pointer to drm plane + * @enable: true to enable QoS control + * @flags: QoS control mode (enum dpu_plane_qos) + */ +static void _dpu_plane_set_qos_ctrl(struct drm_plane *plane, + bool enable, u32 flags) +{ + struct dpu_plane *pdpu; + + if (!plane) { + DPU_ERROR("invalid arguments\n"); + return; + } + + pdpu = to_dpu_plane(plane); + + if (!pdpu->pipe_hw || !pdpu->pipe_sblk) { + DPU_ERROR("invalid arguments\n"); + return; + } else if (!pdpu->pipe_hw->ops.setup_qos_ctrl) { + return; + } + + if (flags & DPU_PLANE_QOS_VBLANK_CTRL) { + pdpu->pipe_qos_cfg.creq_vblank = pdpu->pipe_sblk->creq_vblank; + pdpu->pipe_qos_cfg.danger_vblank = + pdpu->pipe_sblk->danger_vblank; + pdpu->pipe_qos_cfg.vblank_en = enable; + } + + if (flags & DPU_PLANE_QOS_VBLANK_AMORTIZE) { + /* this feature overrules previous VBLANK_CTRL */ + pdpu->pipe_qos_cfg.vblank_en = false; + pdpu->pipe_qos_cfg.creq_vblank = 0; /* clear vblank bits */ + } + + if (flags & DPU_PLANE_QOS_PANIC_CTRL) + pdpu->pipe_qos_cfg.danger_safe_en = enable; + + if (!pdpu->is_rt_pipe) { + pdpu->pipe_qos_cfg.vblank_en = false; + pdpu->pipe_qos_cfg.danger_safe_en = false; + } + + DPU_DEBUG("plane%u: pnum:%d ds:%d vb:%d pri[0x%x, 0x%x] is_rt:%d\n", + plane->base.id, + pdpu->pipe - SSPP_VIG0, + pdpu->pipe_qos_cfg.danger_safe_en, + pdpu->pipe_qos_cfg.vblank_en, + pdpu->pipe_qos_cfg.creq_vblank, + pdpu->pipe_qos_cfg.danger_vblank, + pdpu->is_rt_pipe); + + pdpu->pipe_hw->ops.setup_qos_ctrl(pdpu->pipe_hw, + &pdpu->pipe_qos_cfg); +} + +int dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable) +{ + struct dpu_plane *pdpu; + struct msm_drm_private *priv; + struct dpu_kms *dpu_kms; + + if (!plane || !plane->dev) { + DPU_ERROR("invalid arguments\n"); + return -EINVAL; + } + + priv = plane->dev->dev_private; + if (!priv || !priv->kms) { + DPU_ERROR("invalid KMS reference\n"); + return -EINVAL; + } + + dpu_kms = to_dpu_kms(priv->kms); + pdpu = to_dpu_plane(plane); + + if (!pdpu->is_rt_pipe) + goto end; + + pm_runtime_get_sync(&dpu_kms->pdev->dev); + _dpu_plane_set_qos_ctrl(plane, enable, DPU_PLANE_QOS_PANIC_CTRL); + pm_runtime_put_sync(&dpu_kms->pdev->dev); + +end: + return 0; +} + +/** + * _dpu_plane_set_ot_limit - set OT limit for the given plane + * @plane: Pointer to drm plane + * @crtc: Pointer to drm crtc + */ +static void _dpu_plane_set_ot_limit(struct drm_plane *plane, + struct drm_crtc *crtc) +{ + struct dpu_plane *pdpu; + struct dpu_vbif_set_ot_params ot_params; + struct msm_drm_private *priv; + struct dpu_kms *dpu_kms; + + if (!plane || !plane->dev || !crtc) { + DPU_ERROR("invalid arguments plane %d crtc %d\n", + plane != 0, crtc != 0); + return; + } + + priv = plane->dev->dev_private; + if (!priv || !priv->kms) { + DPU_ERROR("invalid KMS reference\n"); + return; + } + + dpu_kms = to_dpu_kms(priv->kms); + pdpu = to_dpu_plane(plane); + if (!pdpu->pipe_hw) { + DPU_ERROR("invalid pipe reference\n"); + return; + } + + memset(&ot_params, 0, sizeof(ot_params)); + ot_params.xin_id = pdpu->pipe_hw->cap->xin_id; + ot_params.num = pdpu->pipe_hw->idx - SSPP_NONE; + ot_params.width = drm_rect_width(&pdpu->pipe_cfg.src_rect); + ot_params.height = drm_rect_height(&pdpu->pipe_cfg.src_rect); + ot_params.is_wfd = !pdpu->is_rt_pipe; + ot_params.frame_rate = crtc->mode.vrefresh; + ot_params.vbif_idx = VBIF_RT; + ot_params.clk_ctrl = pdpu->pipe_hw->cap->clk_ctrl; + ot_params.rd = true; + + dpu_vbif_set_ot_limit(dpu_kms, &ot_params); +} + +/** + * _dpu_plane_set_vbif_qos - set vbif QoS for the given plane + * @plane: Pointer to drm plane + */ +static void _dpu_plane_set_qos_remap(struct drm_plane *plane) +{ + struct dpu_plane *pdpu; + struct dpu_vbif_set_qos_params qos_params; + struct msm_drm_private *priv; + struct dpu_kms *dpu_kms; + + if (!plane || !plane->dev) { + DPU_ERROR("invalid arguments\n"); + return; + } + + priv = plane->dev->dev_private; + if (!priv || !priv->kms) { + DPU_ERROR("invalid KMS reference\n"); + return; + } + + dpu_kms = to_dpu_kms(priv->kms); + pdpu = to_dpu_plane(plane); + if (!pdpu->pipe_hw) { + DPU_ERROR("invalid pipe reference\n"); + return; + } + + memset(&qos_params, 0, sizeof(qos_params)); + qos_params.vbif_idx = VBIF_RT; + qos_params.clk_ctrl = pdpu->pipe_hw->cap->clk_ctrl; + qos_params.xin_id = pdpu->pipe_hw->cap->xin_id; + qos_params.num = pdpu->pipe_hw->idx - SSPP_VIG0; + qos_params.is_rt = pdpu->is_rt_pipe; + + DPU_DEBUG("plane%d pipe:%d vbif:%d xin:%d rt:%d, clk_ctrl:%d\n", + plane->base.id, qos_params.num, + qos_params.vbif_idx, + qos_params.xin_id, qos_params.is_rt, + qos_params.clk_ctrl); + + dpu_vbif_set_qos_remap(dpu_kms, &qos_params); +} + +/** + * _dpu_plane_get_aspace: gets the address space + */ +static int _dpu_plane_get_aspace( + struct dpu_plane *pdpu, + struct dpu_plane_state *pstate, + struct msm_gem_address_space **aspace) +{ + struct dpu_kms *kms; + + if (!pdpu || !pstate || !aspace) { + DPU_ERROR("invalid parameters\n"); + return -EINVAL; + } + + kms = _dpu_plane_get_kms(&pdpu->base); + if (!kms) { + DPU_ERROR("invalid kms\n"); + return -EINVAL; + } + + *aspace = kms->base.aspace; + + return 0; +} + +static inline void _dpu_plane_set_scanout(struct drm_plane *plane, + struct dpu_plane_state *pstate, + struct dpu_hw_pipe_cfg *pipe_cfg, + struct drm_framebuffer *fb) +{ + struct dpu_plane *pdpu; + struct msm_gem_address_space *aspace = NULL; + int ret; + + if (!plane || !pstate || !pipe_cfg || !fb) { + DPU_ERROR( + "invalid arg(s), plane %d state %d cfg %d fb %d\n", + plane != 0, pstate != 0, pipe_cfg != 0, fb != 0); + return; + } + + pdpu = to_dpu_plane(plane); + if (!pdpu->pipe_hw) { + DPU_ERROR_PLANE(pdpu, "invalid pipe_hw\n"); + return; + } + + ret = _dpu_plane_get_aspace(pdpu, pstate, &aspace); + if (ret) { + DPU_ERROR_PLANE(pdpu, "Failed to get aspace %d\n", ret); + return; + } + + ret = dpu_format_populate_layout(aspace, fb, &pipe_cfg->layout); + if (ret == -EAGAIN) + DPU_DEBUG_PLANE(pdpu, "not updating same src addrs\n"); + else if (ret) + DPU_ERROR_PLANE(pdpu, "failed to get format layout, %d\n", ret); + else if (pdpu->pipe_hw->ops.setup_sourceaddress) { + trace_dpu_plane_set_scanout(pdpu->pipe_hw->idx, + &pipe_cfg->layout, + pstate->multirect_index); + pdpu->pipe_hw->ops.setup_sourceaddress(pdpu->pipe_hw, pipe_cfg, + pstate->multirect_index); + } +} + +static void _dpu_plane_setup_scaler3(struct dpu_plane *pdpu, + struct dpu_plane_state *pstate, + uint32_t src_w, uint32_t src_h, uint32_t dst_w, uint32_t dst_h, + struct dpu_hw_scaler3_cfg *scale_cfg, + const struct dpu_format *fmt, + uint32_t chroma_subsmpl_h, uint32_t chroma_subsmpl_v) +{ + uint32_t i; + + if (!pdpu || !pstate || !scale_cfg || !fmt || !chroma_subsmpl_h || + !chroma_subsmpl_v) { + DPU_ERROR( + "pdpu %d pstate %d scale_cfg %d fmt %d smp_h %d smp_v %d\n", + !!pdpu, !!pstate, !!scale_cfg, !!fmt, chroma_subsmpl_h, + chroma_subsmpl_v); + return; + } + + memset(scale_cfg, 0, sizeof(*scale_cfg)); + memset(&pstate->pixel_ext, 0, sizeof(struct dpu_hw_pixel_ext)); + + scale_cfg->phase_step_x[DPU_SSPP_COMP_0] = + mult_frac((1 << PHASE_STEP_SHIFT), src_w, dst_w); + scale_cfg->phase_step_y[DPU_SSPP_COMP_0] = + mult_frac((1 << PHASE_STEP_SHIFT), src_h, dst_h); + + + scale_cfg->phase_step_y[DPU_SSPP_COMP_1_2] = + scale_cfg->phase_step_y[DPU_SSPP_COMP_0] / chroma_subsmpl_v; + scale_cfg->phase_step_x[DPU_SSPP_COMP_1_2] = + scale_cfg->phase_step_x[DPU_SSPP_COMP_0] / chroma_subsmpl_h; + + scale_cfg->phase_step_x[DPU_SSPP_COMP_2] = + scale_cfg->phase_step_x[DPU_SSPP_COMP_1_2]; + scale_cfg->phase_step_y[DPU_SSPP_COMP_2] = + scale_cfg->phase_step_y[DPU_SSPP_COMP_1_2]; + + scale_cfg->phase_step_x[DPU_SSPP_COMP_3] = + scale_cfg->phase_step_x[DPU_SSPP_COMP_0]; + scale_cfg->phase_step_y[DPU_SSPP_COMP_3] = + scale_cfg->phase_step_y[DPU_SSPP_COMP_0]; + + for (i = 0; i < DPU_MAX_PLANES; i++) { + scale_cfg->src_width[i] = src_w; + scale_cfg->src_height[i] = src_h; + if (i == DPU_SSPP_COMP_1_2 || i == DPU_SSPP_COMP_2) { + scale_cfg->src_width[i] /= chroma_subsmpl_h; + scale_cfg->src_height[i] /= chroma_subsmpl_v; + } + scale_cfg->preload_x[i] = DPU_QSEED3_DEFAULT_PRELOAD_H; + scale_cfg->preload_y[i] = DPU_QSEED3_DEFAULT_PRELOAD_V; + pstate->pixel_ext.num_ext_pxls_top[i] = + scale_cfg->src_height[i]; + pstate->pixel_ext.num_ext_pxls_left[i] = + scale_cfg->src_width[i]; + } + if (!(DPU_FORMAT_IS_YUV(fmt)) && (src_h == dst_h) + && (src_w == dst_w)) + return; + + scale_cfg->dst_width = dst_w; + scale_cfg->dst_height = dst_h; + scale_cfg->y_rgb_filter_cfg = DPU_SCALE_BIL; + scale_cfg->uv_filter_cfg = DPU_SCALE_BIL; + scale_cfg->alpha_filter_cfg = DPU_SCALE_ALPHA_BIL; + scale_cfg->lut_flag = 0; + scale_cfg->blend_cfg = 1; + scale_cfg->enable = 1; +} + +static inline void _dpu_plane_setup_csc(struct dpu_plane *pdpu) +{ + static const struct dpu_csc_cfg dpu_csc_YUV2RGB_601L = { + { + /* S15.16 format */ + 0x00012A00, 0x00000000, 0x00019880, + 0x00012A00, 0xFFFF9B80, 0xFFFF3000, + 0x00012A00, 0x00020480, 0x00000000, + }, + /* signed bias */ + { 0xfff0, 0xff80, 0xff80,}, + { 0x0, 0x0, 0x0,}, + /* unsigned clamp */ + { 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0,}, + { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,}, + }; + static const struct dpu_csc_cfg dpu_csc10_YUV2RGB_601L = { + { + /* S15.16 format */ + 0x00012A00, 0x00000000, 0x00019880, + 0x00012A00, 0xFFFF9B80, 0xFFFF3000, + 0x00012A00, 0x00020480, 0x00000000, + }, + /* signed bias */ + { 0xffc0, 0xfe00, 0xfe00,}, + { 0x0, 0x0, 0x0,}, + /* unsigned clamp */ + { 0x40, 0x3ac, 0x40, 0x3c0, 0x40, 0x3c0,}, + { 0x00, 0x3ff, 0x00, 0x3ff, 0x00, 0x3ff,}, + }; + + if (!pdpu) { + DPU_ERROR("invalid plane\n"); + return; + } + + if (BIT(DPU_SSPP_CSC_10BIT) & pdpu->features) + pdpu->csc_ptr = (struct dpu_csc_cfg *)&dpu_csc10_YUV2RGB_601L; + else + pdpu->csc_ptr = (struct dpu_csc_cfg *)&dpu_csc_YUV2RGB_601L; + + DPU_DEBUG_PLANE(pdpu, "using 0x%X 0x%X 0x%X...\n", + pdpu->csc_ptr->csc_mv[0], + pdpu->csc_ptr->csc_mv[1], + pdpu->csc_ptr->csc_mv[2]); +} + +static void _dpu_plane_setup_scaler(struct dpu_plane *pdpu, + struct dpu_plane_state *pstate, + const struct dpu_format *fmt, bool color_fill) +{ + struct dpu_hw_pixel_ext *pe; + uint32_t chroma_subsmpl_h, chroma_subsmpl_v; + + if (!pdpu || !fmt || !pstate) { + DPU_ERROR("invalid arg(s), plane %d fmt %d state %d\n", + pdpu != 0, fmt != 0, pstate != 0); + return; + } + + pe = &pstate->pixel_ext; + + /* don't chroma subsample if decimating */ + chroma_subsmpl_h = + drm_format_horz_chroma_subsampling(fmt->base.pixel_format); + chroma_subsmpl_v = + drm_format_vert_chroma_subsampling(fmt->base.pixel_format); + + /* update scaler. calculate default config for QSEED3 */ + _dpu_plane_setup_scaler3(pdpu, pstate, + drm_rect_width(&pdpu->pipe_cfg.src_rect), + drm_rect_height(&pdpu->pipe_cfg.src_rect), + drm_rect_width(&pdpu->pipe_cfg.dst_rect), + drm_rect_height(&pdpu->pipe_cfg.dst_rect), + &pstate->scaler3_cfg, fmt, + chroma_subsmpl_h, chroma_subsmpl_v); +} + +/** + * _dpu_plane_color_fill - enables color fill on plane + * @pdpu: Pointer to DPU plane object + * @color: RGB fill color value, [23..16] Blue, [15..8] Green, [7..0] Red + * @alpha: 8-bit fill alpha value, 255 selects 100% alpha + * Returns: 0 on success + */ +static int _dpu_plane_color_fill(struct dpu_plane *pdpu, + uint32_t color, uint32_t alpha) +{ + const struct dpu_format *fmt; + const struct drm_plane *plane; + struct dpu_plane_state *pstate; + + if (!pdpu || !pdpu->base.state) { + DPU_ERROR("invalid plane\n"); + return -EINVAL; + } + + if (!pdpu->pipe_hw) { + DPU_ERROR_PLANE(pdpu, "invalid plane h/w pointer\n"); + return -EINVAL; + } + + plane = &pdpu->base; + pstate = to_dpu_plane_state(plane->state); + + DPU_DEBUG_PLANE(pdpu, "\n"); + + /* + * select fill format to match user property expectation, + * h/w only supports RGB variants + */ + fmt = dpu_get_dpu_format(DRM_FORMAT_ABGR8888); + + /* update sspp */ + if (fmt && pdpu->pipe_hw->ops.setup_solidfill) { + pdpu->pipe_hw->ops.setup_solidfill(pdpu->pipe_hw, + (color & 0xFFFFFF) | ((alpha & 0xFF) << 24), + pstate->multirect_index); + + /* override scaler/decimation if solid fill */ + pdpu->pipe_cfg.src_rect.x1 = 0; + pdpu->pipe_cfg.src_rect.y1 = 0; + pdpu->pipe_cfg.src_rect.x2 = + drm_rect_width(&pdpu->pipe_cfg.dst_rect); + pdpu->pipe_cfg.src_rect.y2 = + drm_rect_height(&pdpu->pipe_cfg.dst_rect); + _dpu_plane_setup_scaler(pdpu, pstate, fmt, true); + + if (pdpu->pipe_hw->ops.setup_format) + pdpu->pipe_hw->ops.setup_format(pdpu->pipe_hw, + fmt, DPU_SSPP_SOLID_FILL, + pstate->multirect_index); + + if (pdpu->pipe_hw->ops.setup_rects) + pdpu->pipe_hw->ops.setup_rects(pdpu->pipe_hw, + &pdpu->pipe_cfg, + pstate->multirect_index); + + if (pdpu->pipe_hw->ops.setup_pe) + pdpu->pipe_hw->ops.setup_pe(pdpu->pipe_hw, + &pstate->pixel_ext); + + if (pdpu->pipe_hw->ops.setup_scaler && + pstate->multirect_index != DPU_SSPP_RECT_1) + pdpu->pipe_hw->ops.setup_scaler(pdpu->pipe_hw, + &pdpu->pipe_cfg, &pstate->pixel_ext, + &pstate->scaler3_cfg); + } + + return 0; +} + +void dpu_plane_clear_multirect(const struct drm_plane_state *drm_state) +{ + struct dpu_plane_state *pstate; + + if (!drm_state) + return; + + pstate = to_dpu_plane_state(drm_state); + + pstate->multirect_index = DPU_SSPP_RECT_SOLO; + pstate->multirect_mode = DPU_SSPP_MULTIRECT_NONE; +} + +int dpu_plane_validate_multirect_v2(struct dpu_multirect_plane_states *plane) +{ + struct dpu_plane_state *pstate[R_MAX]; + const struct drm_plane_state *drm_state[R_MAX]; + struct drm_rect src[R_MAX], dst[R_MAX]; + struct dpu_plane *dpu_plane[R_MAX]; + const struct dpu_format *fmt[R_MAX]; + int i, buffer_lines; + unsigned int max_tile_height = 1; + bool parallel_fetch_qualified = true; + bool has_tiled_rect = false; + + for (i = 0; i < R_MAX; i++) { + const struct msm_format *msm_fmt; + + drm_state[i] = i ? plane->r1 : plane->r0; + msm_fmt = msm_framebuffer_format(drm_state[i]->fb); + fmt[i] = to_dpu_format(msm_fmt); + + if (DPU_FORMAT_IS_UBWC(fmt[i])) { + has_tiled_rect = true; + if (fmt[i]->tile_height > max_tile_height) + max_tile_height = fmt[i]->tile_height; + } + } + + for (i = 0; i < R_MAX; i++) { + int width_threshold; + + pstate[i] = to_dpu_plane_state(drm_state[i]); + dpu_plane[i] = to_dpu_plane(drm_state[i]->plane); + + if (pstate[i] == NULL) { + DPU_ERROR("DPU plane state of plane id %d is NULL\n", + drm_state[i]->plane->base.id); + return -EINVAL; + } + + src[i].x1 = drm_state[i]->src_x >> 16; + src[i].y1 = drm_state[i]->src_y >> 16; + src[i].x2 = src[i].x1 + (drm_state[i]->src_w >> 16); + src[i].y2 = src[i].y1 + (drm_state[i]->src_h >> 16); + + dst[i] = drm_plane_state_dest(drm_state[i]); + + if (drm_rect_calc_hscale(&src[i], &dst[i], 1, 1) != 1 || + drm_rect_calc_vscale(&src[i], &dst[i], 1, 1) != 1) { + DPU_ERROR_PLANE(dpu_plane[i], + "scaling is not supported in multirect mode\n"); + return -EINVAL; + } + + if (DPU_FORMAT_IS_YUV(fmt[i])) { + DPU_ERROR_PLANE(dpu_plane[i], + "Unsupported format for multirect mode\n"); + return -EINVAL; + } + + /** + * SSPP PD_MEM is split half - one for each RECT. + * Tiled formats need 5 lines of buffering while fetching + * whereas linear formats need only 2 lines. + * So we cannot support more than half of the supported SSPP + * width for tiled formats. + */ + width_threshold = dpu_plane[i]->pipe_sblk->common->maxlinewidth; + if (has_tiled_rect) + width_threshold /= 2; + + if (parallel_fetch_qualified && + drm_rect_width(&src[i]) > width_threshold) + parallel_fetch_qualified = false; + + } + + /* Validate RECT's and set the mode */ + + /* Prefer PARALLEL FETCH Mode over TIME_MX Mode */ + if (parallel_fetch_qualified) { + pstate[R0]->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL; + pstate[R1]->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL; + + goto done; + } + + /* TIME_MX Mode */ + buffer_lines = 2 * max_tile_height; + + if (dst[R1].y1 >= dst[R0].y2 + buffer_lines || + dst[R0].y1 >= dst[R1].y2 + buffer_lines) { + pstate[R0]->multirect_mode = DPU_SSPP_MULTIRECT_TIME_MX; + pstate[R1]->multirect_mode = DPU_SSPP_MULTIRECT_TIME_MX; + } else { + DPU_ERROR( + "No multirect mode possible for the planes (%d - %d)\n", + drm_state[R0]->plane->base.id, + drm_state[R1]->plane->base.id); + return -EINVAL; + } + +done: + if (dpu_plane[R0]->is_virtual) { + pstate[R0]->multirect_index = DPU_SSPP_RECT_1; + pstate[R1]->multirect_index = DPU_SSPP_RECT_0; + } else { + pstate[R0]->multirect_index = DPU_SSPP_RECT_0; + pstate[R1]->multirect_index = DPU_SSPP_RECT_1; + }; + + DPU_DEBUG_PLANE(dpu_plane[R0], "R0: %d - %d\n", + pstate[R0]->multirect_mode, pstate[R0]->multirect_index); + DPU_DEBUG_PLANE(dpu_plane[R1], "R1: %d - %d\n", + pstate[R1]->multirect_mode, pstate[R1]->multirect_index); + return 0; +} + +/** + * dpu_plane_get_ctl_flush - get control flush for the given plane + * @plane: Pointer to drm plane structure + * @ctl: Pointer to hardware control driver + * @flush_sspp: Pointer to sspp flush control word + */ +void dpu_plane_get_ctl_flush(struct drm_plane *plane, struct dpu_hw_ctl *ctl, + u32 *flush_sspp) +{ + struct dpu_plane_state *pstate; + + if (!plane || !flush_sspp) { + DPU_ERROR("invalid parameters\n"); + return; + } + + pstate = to_dpu_plane_state(plane->state); + + *flush_sspp = ctl->ops.get_bitmask_sspp(ctl, dpu_plane_pipe(plane)); +} + +static int dpu_plane_prepare_fb(struct drm_plane *plane, + struct drm_plane_state *new_state) +{ + struct drm_framebuffer *fb = new_state->fb; + struct dpu_plane *pdpu = to_dpu_plane(plane); + struct dpu_plane_state *pstate = to_dpu_plane_state(new_state); + struct dpu_hw_fmt_layout layout; + struct drm_gem_object *obj; + struct msm_gem_object *msm_obj; + struct dma_fence *fence; + struct msm_gem_address_space *aspace; + int ret; + + if (!new_state->fb) + return 0; + + DPU_DEBUG_PLANE(pdpu, "FB[%u]\n", fb->base.id); + + ret = _dpu_plane_get_aspace(pdpu, pstate, &aspace); + if (ret) { + DPU_ERROR_PLANE(pdpu, "Failed to get aspace\n"); + return ret; + } + + /* cache aspace */ + pstate->aspace = aspace; + + /* + * TODO: Need to sort out the msm_framebuffer_prepare() call below so + * we can use msm_atomic_prepare_fb() instead of doing the + * implicit fence and fb prepare by hand here. + */ + obj = msm_framebuffer_bo(new_state->fb, 0); + msm_obj = to_msm_bo(obj); + fence = reservation_object_get_excl_rcu(msm_obj->resv); + if (fence) + drm_atomic_set_fence_for_plane(new_state, fence); + + if (pstate->aspace) { + ret = msm_framebuffer_prepare(new_state->fb, + pstate->aspace); + if (ret) { + DPU_ERROR("failed to prepare framebuffer\n"); + return ret; + } + } + + /* validate framebuffer layout before commit */ + ret = dpu_format_populate_layout(pstate->aspace, + new_state->fb, &layout); + if (ret) { + DPU_ERROR_PLANE(pdpu, "failed to get format layout, %d\n", ret); + return ret; + } + + return 0; +} + +static void dpu_plane_cleanup_fb(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + struct dpu_plane *pdpu = to_dpu_plane(plane); + struct dpu_plane_state *old_pstate; + + if (!old_state || !old_state->fb) + return; + + old_pstate = to_dpu_plane_state(old_state); + + DPU_DEBUG_PLANE(pdpu, "FB[%u]\n", old_state->fb->base.id); + + msm_framebuffer_cleanup(old_state->fb, old_pstate->aspace); +} + +static bool dpu_plane_validate_src(struct drm_rect *src, + struct drm_rect *fb_rect, + uint32_t min_src_size) +{ + /* Ensure fb size is supported */ + if (drm_rect_width(fb_rect) > MAX_IMG_WIDTH || + drm_rect_height(fb_rect) > MAX_IMG_HEIGHT) + return false; + + /* Ensure src rect is above the minimum size */ + if (drm_rect_width(src) < min_src_size || + drm_rect_height(src) < min_src_size) + return false; + + /* Ensure src is fully encapsulated in fb */ + return drm_rect_intersect(fb_rect, src) && + drm_rect_equals(fb_rect, src); +} + +static int dpu_plane_sspp_atomic_check(struct drm_plane *plane, + struct drm_plane_state *state) +{ + int ret = 0; + struct dpu_plane *pdpu; + struct dpu_plane_state *pstate; + const struct dpu_format *fmt; + struct drm_rect src, dst, fb_rect = { 0 }; + uint32_t max_upscale = 1, max_downscale = 1; + uint32_t min_src_size, max_linewidth; + int hscale = 1, vscale = 1; + + if (!plane || !state) { + DPU_ERROR("invalid arg(s), plane %d state %d\n", + plane != 0, state != 0); + ret = -EINVAL; + goto exit; + } + + pdpu = to_dpu_plane(plane); + pstate = to_dpu_plane_state(state); + + if (!pdpu->pipe_sblk) { + DPU_ERROR_PLANE(pdpu, "invalid catalog\n"); + ret = -EINVAL; + goto exit; + } + + src.x1 = state->src_x >> 16; + src.y1 = state->src_y >> 16; + src.x2 = src.x1 + (state->src_w >> 16); + src.y2 = src.y1 + (state->src_h >> 16); + + dst = drm_plane_state_dest(state); + + fb_rect.x2 = state->fb->width; + fb_rect.y2 = state->fb->height; + + max_linewidth = pdpu->pipe_sblk->common->maxlinewidth; + + if (pdpu->features & DPU_SSPP_SCALER) { + max_downscale = pdpu->pipe_sblk->maxdwnscale; + max_upscale = pdpu->pipe_sblk->maxupscale; + } + if (drm_rect_width(&src) < drm_rect_width(&dst)) + hscale = drm_rect_calc_hscale(&src, &dst, 1, max_upscale); + else + hscale = drm_rect_calc_hscale(&dst, &src, 1, max_downscale); + if (drm_rect_height(&src) < drm_rect_height(&dst)) + vscale = drm_rect_calc_vscale(&src, &dst, 1, max_upscale); + else + vscale = drm_rect_calc_vscale(&dst, &src, 1, max_downscale); + + DPU_DEBUG_PLANE(pdpu, "check %d -> %d\n", + dpu_plane_enabled(plane->state), dpu_plane_enabled(state)); + + if (!dpu_plane_enabled(state)) + goto exit; + + fmt = to_dpu_format(msm_framebuffer_format(state->fb)); + + min_src_size = DPU_FORMAT_IS_YUV(fmt) ? 2 : 1; + + if (DPU_FORMAT_IS_YUV(fmt) && + (!(pdpu->features & DPU_SSPP_SCALER) || + !(pdpu->features & (BIT(DPU_SSPP_CSC) + | BIT(DPU_SSPP_CSC_10BIT))))) { + DPU_ERROR_PLANE(pdpu, + "plane doesn't have scaler/csc for yuv\n"); + ret = -EINVAL; + + /* check src bounds */ + } else if (!dpu_plane_validate_src(&src, &fb_rect, min_src_size)) { + DPU_ERROR_PLANE(pdpu, "invalid source " DRM_RECT_FMT "\n", + DRM_RECT_ARG(&src)); + ret = -E2BIG; + + /* valid yuv image */ + } else if (DPU_FORMAT_IS_YUV(fmt) && + (src.x1 & 0x1 || src.y1 & 0x1 || + drm_rect_width(&src) & 0x1 || + drm_rect_height(&src) & 0x1)) { + DPU_ERROR_PLANE(pdpu, "invalid yuv source " DRM_RECT_FMT "\n", + DRM_RECT_ARG(&src)); + ret = -EINVAL; + + /* min dst support */ + } else if (drm_rect_width(&dst) < 0x1 || drm_rect_height(&dst) < 0x1) { + DPU_ERROR_PLANE(pdpu, "invalid dest rect " DRM_RECT_FMT "\n", + DRM_RECT_ARG(&dst)); + ret = -EINVAL; + + /* check decimated source width */ + } else if (drm_rect_width(&src) > max_linewidth) { + DPU_ERROR_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u\n", + DRM_RECT_ARG(&src), max_linewidth); + ret = -E2BIG; + + /* check scaler capability */ + } else if (hscale < 0 || vscale < 0) { + DPU_ERROR_PLANE(pdpu, "invalid scaling requested src=" + DRM_RECT_FMT " dst=" DRM_RECT_FMT "\n", + DRM_RECT_ARG(&src), DRM_RECT_ARG(&dst)); + ret = -E2BIG; + } + +exit: + return ret; +} + +static int dpu_plane_atomic_check(struct drm_plane *plane, + struct drm_plane_state *state) +{ + if (!state->fb) + return 0; + + DPU_DEBUG_PLANE(to_dpu_plane(plane), "\n"); + + return dpu_plane_sspp_atomic_check(plane, state); +} + +void dpu_plane_flush(struct drm_plane *plane) +{ + struct dpu_plane *pdpu; + struct dpu_plane_state *pstate; + + if (!plane || !plane->state) { + DPU_ERROR("invalid plane\n"); + return; + } + + pdpu = to_dpu_plane(plane); + pstate = to_dpu_plane_state(plane->state); + + /* + * These updates have to be done immediately before the plane flush + * timing, and may not be moved to the atomic_update/mode_set functions. + */ + if (pdpu->is_error) + /* force white frame with 100% alpha pipe output on error */ + _dpu_plane_color_fill(pdpu, 0xFFFFFF, 0xFF); + else if (pdpu->color_fill & DPU_PLANE_COLOR_FILL_FLAG) + /* force 100% alpha */ + _dpu_plane_color_fill(pdpu, pdpu->color_fill, 0xFF); + else if (pdpu->pipe_hw && pdpu->csc_ptr && pdpu->pipe_hw->ops.setup_csc) + pdpu->pipe_hw->ops.setup_csc(pdpu->pipe_hw, pdpu->csc_ptr); + + /* flag h/w flush complete */ + if (plane->state) + pstate->pending = false; +} + +/** + * dpu_plane_set_error: enable/disable error condition + * @plane: pointer to drm_plane structure + */ +void dpu_plane_set_error(struct drm_plane *plane, bool error) +{ + struct dpu_plane *pdpu; + + if (!plane) + return; + + pdpu = to_dpu_plane(plane); + pdpu->is_error = error; +} + +static int dpu_plane_sspp_atomic_update(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + uint32_t nplanes, src_flags; + struct dpu_plane *pdpu; + struct drm_plane_state *state; + struct dpu_plane_state *pstate; + struct dpu_plane_state *old_pstate; + const struct dpu_format *fmt; + struct drm_crtc *crtc; + struct drm_framebuffer *fb; + struct drm_rect src, dst; + + if (!plane) { + DPU_ERROR("invalid plane\n"); + return -EINVAL; + } else if (!plane->state) { + DPU_ERROR("invalid plane state\n"); + return -EINVAL; + } else if (!old_state) { + DPU_ERROR("invalid old state\n"); + return -EINVAL; + } + + pdpu = to_dpu_plane(plane); + state = plane->state; + + pstate = to_dpu_plane_state(state); + + old_pstate = to_dpu_plane_state(old_state); + + crtc = state->crtc; + fb = state->fb; + if (!crtc || !fb) { + DPU_ERROR_PLANE(pdpu, "invalid crtc %d or fb %d\n", + crtc != 0, fb != 0); + return -EINVAL; + } + fmt = to_dpu_format(msm_framebuffer_format(fb)); + nplanes = fmt->num_planes; + + memset(&(pdpu->pipe_cfg), 0, sizeof(struct dpu_hw_pipe_cfg)); + + _dpu_plane_set_scanout(plane, pstate, &pdpu->pipe_cfg, fb); + + pstate->pending = true; + + pdpu->is_rt_pipe = (dpu_crtc_get_client_type(crtc) != NRT_CLIENT); + _dpu_plane_set_qos_ctrl(plane, false, DPU_PLANE_QOS_PANIC_CTRL); + + src.x1 = state->src_x >> 16; + src.y1 = state->src_y >> 16; + src.x2 = src.x1 + (state->src_w >> 16); + src.y2 = src.y1 + (state->src_h >> 16); + + dst = drm_plane_state_dest(state); + + DPU_DEBUG_PLANE(pdpu, "FB[%u] " DRM_RECT_FMT "->crtc%u " DRM_RECT_FMT + ", %4.4s ubwc %d\n", fb->base.id, DRM_RECT_ARG(&src), + crtc->base.id, DRM_RECT_ARG(&dst), + (char *)&fmt->base.pixel_format, + DPU_FORMAT_IS_UBWC(fmt)); + + pdpu->pipe_cfg.src_rect = src; + pdpu->pipe_cfg.dst_rect = dst; + + _dpu_plane_setup_scaler(pdpu, pstate, fmt, false); + + /* override for color fill */ + if (pdpu->color_fill & DPU_PLANE_COLOR_FILL_FLAG) { + /* skip remaining processing on color fill */ + return 0; + } + + if (pdpu->pipe_hw->ops.setup_rects) { + pdpu->pipe_hw->ops.setup_rects(pdpu->pipe_hw, + &pdpu->pipe_cfg, + pstate->multirect_index); + } + + if (pdpu->pipe_hw->ops.setup_pe && + (pstate->multirect_index != DPU_SSPP_RECT_1)) + pdpu->pipe_hw->ops.setup_pe(pdpu->pipe_hw, + &pstate->pixel_ext); + + /** + * when programmed in multirect mode, scalar block will be + * bypassed. Still we need to update alpha and bitwidth + * ONLY for RECT0 + */ + if (pdpu->pipe_hw->ops.setup_scaler && + pstate->multirect_index != DPU_SSPP_RECT_1) + pdpu->pipe_hw->ops.setup_scaler(pdpu->pipe_hw, + &pdpu->pipe_cfg, &pstate->pixel_ext, + &pstate->scaler3_cfg); + + if (pdpu->pipe_hw->ops.setup_multirect) + pdpu->pipe_hw->ops.setup_multirect( + pdpu->pipe_hw, + pstate->multirect_index, + pstate->multirect_mode); + + if (pdpu->pipe_hw->ops.setup_format) { + src_flags = 0x0; + + /* update format */ + pdpu->pipe_hw->ops.setup_format(pdpu->pipe_hw, fmt, src_flags, + pstate->multirect_index); + + if (pdpu->pipe_hw->ops.setup_cdp) { + struct dpu_hw_pipe_cdp_cfg *cdp_cfg = &pstate->cdp_cfg; + + memset(cdp_cfg, 0, sizeof(struct dpu_hw_pipe_cdp_cfg)); + + cdp_cfg->enable = pdpu->catalog->perf.cdp_cfg + [DPU_PERF_CDP_USAGE_RT].rd_enable; + cdp_cfg->ubwc_meta_enable = + DPU_FORMAT_IS_UBWC(fmt); + cdp_cfg->tile_amortize_enable = + DPU_FORMAT_IS_UBWC(fmt) || + DPU_FORMAT_IS_TILE(fmt); + cdp_cfg->preload_ahead = DPU_SSPP_CDP_PRELOAD_AHEAD_64; + + pdpu->pipe_hw->ops.setup_cdp(pdpu->pipe_hw, cdp_cfg); + } + + /* update csc */ + if (DPU_FORMAT_IS_YUV(fmt)) + _dpu_plane_setup_csc(pdpu); + else + pdpu->csc_ptr = 0; + } + + _dpu_plane_set_qos_lut(plane, fb); + _dpu_plane_set_danger_lut(plane, fb); + + if (plane->type != DRM_PLANE_TYPE_CURSOR) { + _dpu_plane_set_qos_ctrl(plane, true, DPU_PLANE_QOS_PANIC_CTRL); + _dpu_plane_set_ot_limit(plane, crtc); + } + + _dpu_plane_set_qos_remap(plane); + return 0; +} + +static void _dpu_plane_atomic_disable(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + struct dpu_plane *pdpu; + struct drm_plane_state *state; + struct dpu_plane_state *pstate; + + if (!plane) { + DPU_ERROR("invalid plane\n"); + return; + } else if (!plane->state) { + DPU_ERROR("invalid plane state\n"); + return; + } else if (!old_state) { + DPU_ERROR("invalid old state\n"); + return; + } + + pdpu = to_dpu_plane(plane); + state = plane->state; + pstate = to_dpu_plane_state(state); + + trace_dpu_plane_disable(DRMID(plane), is_dpu_plane_virtual(plane), + pstate->multirect_mode); + + pstate->pending = true; + + if (is_dpu_plane_virtual(plane) && + pdpu->pipe_hw && pdpu->pipe_hw->ops.setup_multirect) + pdpu->pipe_hw->ops.setup_multirect(pdpu->pipe_hw, + DPU_SSPP_RECT_SOLO, DPU_SSPP_MULTIRECT_NONE); +} + +static void dpu_plane_atomic_update(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + struct dpu_plane *pdpu; + struct drm_plane_state *state; + + if (!plane) { + DPU_ERROR("invalid plane\n"); + return; + } else if (!plane->state) { + DPU_ERROR("invalid plane state\n"); + return; + } + + pdpu = to_dpu_plane(plane); + pdpu->is_error = false; + state = plane->state; + + DPU_DEBUG_PLANE(pdpu, "\n"); + + if (!dpu_plane_sspp_enabled(state)) { + _dpu_plane_atomic_disable(plane, old_state); + } else { + int ret; + + ret = dpu_plane_sspp_atomic_update(plane, old_state); + /* atomic_check should have ensured that this doesn't fail */ + WARN_ON(ret < 0); + } +} + +void dpu_plane_restore(struct drm_plane *plane) +{ + struct dpu_plane *pdpu; + + if (!plane || !plane->state) { + DPU_ERROR("invalid plane\n"); + return; + } + + pdpu = to_dpu_plane(plane); + + DPU_DEBUG_PLANE(pdpu, "\n"); + + /* last plane state is same as current state */ + dpu_plane_atomic_update(plane, plane->state); +} + +static void dpu_plane_destroy(struct drm_plane *plane) +{ + struct dpu_plane *pdpu = plane ? to_dpu_plane(plane) : NULL; + + DPU_DEBUG_PLANE(pdpu, "\n"); + + if (pdpu) { + _dpu_plane_set_qos_ctrl(plane, false, DPU_PLANE_QOS_PANIC_CTRL); + + mutex_destroy(&pdpu->lock); + + drm_plane_helper_disable(plane, NULL); + + /* this will destroy the states as well */ + drm_plane_cleanup(plane); + + if (pdpu->pipe_hw) + dpu_hw_sspp_destroy(pdpu->pipe_hw); + + kfree(pdpu); + } +} + +static void dpu_plane_destroy_state(struct drm_plane *plane, + struct drm_plane_state *state) +{ + struct dpu_plane_state *pstate; + + if (!plane || !state) { + DPU_ERROR("invalid arg(s), plane %d state %d\n", + plane != 0, state != 0); + return; + } + + pstate = to_dpu_plane_state(state); + + /* remove ref count for frame buffers */ + if (state->fb) + drm_framebuffer_put(state->fb); + + kfree(pstate); +} + +static struct drm_plane_state * +dpu_plane_duplicate_state(struct drm_plane *plane) +{ + struct dpu_plane *pdpu; + struct dpu_plane_state *pstate; + struct dpu_plane_state *old_state; + + if (!plane) { + DPU_ERROR("invalid plane\n"); + return NULL; + } else if (!plane->state) { + DPU_ERROR("invalid plane state\n"); + return NULL; + } + + old_state = to_dpu_plane_state(plane->state); + pdpu = to_dpu_plane(plane); + pstate = kmemdup(old_state, sizeof(*old_state), GFP_KERNEL); + if (!pstate) { + DPU_ERROR_PLANE(pdpu, "failed to allocate state\n"); + return NULL; + } + + DPU_DEBUG_PLANE(pdpu, "\n"); + + pstate->pending = false; + + __drm_atomic_helper_plane_duplicate_state(plane, &pstate->base); + + return &pstate->base; +} + +static void dpu_plane_reset(struct drm_plane *plane) +{ + struct dpu_plane *pdpu; + struct dpu_plane_state *pstate; + + if (!plane) { + DPU_ERROR("invalid plane\n"); + return; + } + + pdpu = to_dpu_plane(plane); + DPU_DEBUG_PLANE(pdpu, "\n"); + + /* remove previous state, if present */ + if (plane->state) { + dpu_plane_destroy_state(plane, plane->state); + plane->state = 0; + } + + pstate = kzalloc(sizeof(*pstate), GFP_KERNEL); + if (!pstate) { + DPU_ERROR_PLANE(pdpu, "failed to allocate state\n"); + return; + } + + pstate->base.plane = plane; + + plane->state = &pstate->base; +} + +#ifdef CONFIG_DEBUG_FS +static ssize_t _dpu_plane_danger_read(struct file *file, + char __user *buff, size_t count, loff_t *ppos) +{ + struct dpu_kms *kms = file->private_data; + struct dpu_mdss_cfg *cfg = kms->catalog; + int len = 0; + char buf[40] = {'\0'}; + + if (!cfg) + return -ENODEV; + + if (*ppos) + return 0; /* the end */ + + len = snprintf(buf, sizeof(buf), "%d\n", !kms->has_danger_ctrl); + if (len < 0 || len >= sizeof(buf)) + return 0; + + if ((count < sizeof(buf)) || copy_to_user(buff, buf, len)) + return -EFAULT; + + *ppos += len; /* increase offset */ + + return len; +} + +static void _dpu_plane_set_danger_state(struct dpu_kms *kms, bool enable) +{ + struct drm_plane *plane; + + drm_for_each_plane(plane, kms->dev) { + if (plane->fb && plane->state) { + dpu_plane_danger_signal_ctrl(plane, enable); + DPU_DEBUG("plane:%d img:%dx%d ", + plane->base.id, plane->fb->width, + plane->fb->height); + DPU_DEBUG("src[%d,%d,%d,%d] dst[%d,%d,%d,%d]\n", + plane->state->src_x >> 16, + plane->state->src_y >> 16, + plane->state->src_w >> 16, + plane->state->src_h >> 16, + plane->state->crtc_x, plane->state->crtc_y, + plane->state->crtc_w, plane->state->crtc_h); + } else { + DPU_DEBUG("Inactive plane:%d\n", plane->base.id); + } + } +} + +static ssize_t _dpu_plane_danger_write(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + struct dpu_kms *kms = file->private_data; + struct dpu_mdss_cfg *cfg = kms->catalog; + int disable_panic; + char buf[10]; + + if (!cfg) + return -EFAULT; + + if (count >= sizeof(buf)) + return -EFAULT; + + if (copy_from_user(buf, user_buf, count)) + return -EFAULT; + + buf[count] = 0; /* end of string */ + + if (kstrtoint(buf, 0, &disable_panic)) + return -EFAULT; + + if (disable_panic) { + /* Disable panic signal for all active pipes */ + DPU_DEBUG("Disabling danger:\n"); + _dpu_plane_set_danger_state(kms, false); + kms->has_danger_ctrl = false; + } else { + /* Enable panic signal for all active pipes */ + DPU_DEBUG("Enabling danger:\n"); + kms->has_danger_ctrl = true; + _dpu_plane_set_danger_state(kms, true); + } + + return count; +} + +static const struct file_operations dpu_plane_danger_enable = { + .open = simple_open, + .read = _dpu_plane_danger_read, + .write = _dpu_plane_danger_write, +}; + +static int _dpu_plane_init_debugfs(struct drm_plane *plane) +{ + struct dpu_plane *pdpu; + struct dpu_kms *kms; + struct msm_drm_private *priv; + const struct dpu_sspp_sub_blks *sblk = 0; + const struct dpu_sspp_cfg *cfg = 0; + + if (!plane || !plane->dev) { + DPU_ERROR("invalid arguments\n"); + return -EINVAL; + } + + priv = plane->dev->dev_private; + if (!priv || !priv->kms) { + DPU_ERROR("invalid KMS reference\n"); + return -EINVAL; + } + + kms = to_dpu_kms(priv->kms); + pdpu = to_dpu_plane(plane); + + if (pdpu && pdpu->pipe_hw) + cfg = pdpu->pipe_hw->cap; + if (cfg) + sblk = cfg->sblk; + + if (!sblk) + return 0; + + /* create overall sub-directory for the pipe */ + pdpu->debugfs_root = + debugfs_create_dir(pdpu->pipe_name, + plane->dev->primary->debugfs_root); + + if (!pdpu->debugfs_root) + return -ENOMEM; + + /* don't error check these */ + debugfs_create_x32("features", 0600, + pdpu->debugfs_root, &pdpu->features); + + /* add register dump support */ + dpu_debugfs_setup_regset32(&pdpu->debugfs_src, + sblk->src_blk.base + cfg->base, + sblk->src_blk.len, + kms); + dpu_debugfs_create_regset32("src_blk", 0400, + pdpu->debugfs_root, &pdpu->debugfs_src); + + if (cfg->features & BIT(DPU_SSPP_SCALER_QSEED3) || + cfg->features & BIT(DPU_SSPP_SCALER_QSEED2)) { + dpu_debugfs_setup_regset32(&pdpu->debugfs_scaler, + sblk->scaler_blk.base + cfg->base, + sblk->scaler_blk.len, + kms); + dpu_debugfs_create_regset32("scaler_blk", 0400, + pdpu->debugfs_root, + &pdpu->debugfs_scaler); + debugfs_create_bool("default_scaling", + 0600, + pdpu->debugfs_root, + &pdpu->debugfs_default_scale); + } + + if (cfg->features & BIT(DPU_SSPP_CSC) || + cfg->features & BIT(DPU_SSPP_CSC_10BIT)) { + dpu_debugfs_setup_regset32(&pdpu->debugfs_csc, + sblk->csc_blk.base + cfg->base, + sblk->csc_blk.len, + kms); + dpu_debugfs_create_regset32("csc_blk", 0400, + pdpu->debugfs_root, &pdpu->debugfs_csc); + } + + debugfs_create_u32("xin_id", + 0400, + pdpu->debugfs_root, + (u32 *) &cfg->xin_id); + debugfs_create_u32("clk_ctrl", + 0400, + pdpu->debugfs_root, + (u32 *) &cfg->clk_ctrl); + debugfs_create_x32("creq_vblank", + 0600, + pdpu->debugfs_root, + (u32 *) &sblk->creq_vblank); + debugfs_create_x32("danger_vblank", + 0600, + pdpu->debugfs_root, + (u32 *) &sblk->danger_vblank); + + debugfs_create_file("disable_danger", + 0600, + pdpu->debugfs_root, + kms, &dpu_plane_danger_enable); + + return 0; +} + +static void _dpu_plane_destroy_debugfs(struct drm_plane *plane) +{ + struct dpu_plane *pdpu; + + if (!plane) + return; + pdpu = to_dpu_plane(plane); + + debugfs_remove_recursive(pdpu->debugfs_root); +} +#else +static int _dpu_plane_init_debugfs(struct drm_plane *plane) +{ + return 0; +} +static void _dpu_plane_destroy_debugfs(struct drm_plane *plane) +{ +} +#endif + +static int dpu_plane_late_register(struct drm_plane *plane) +{ + return _dpu_plane_init_debugfs(plane); +} + +static void dpu_plane_early_unregister(struct drm_plane *plane) +{ + _dpu_plane_destroy_debugfs(plane); +} + +static const struct drm_plane_funcs dpu_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = dpu_plane_destroy, + .reset = dpu_plane_reset, + .atomic_duplicate_state = dpu_plane_duplicate_state, + .atomic_destroy_state = dpu_plane_destroy_state, + .late_register = dpu_plane_late_register, + .early_unregister = dpu_plane_early_unregister, +}; + +static const struct drm_plane_helper_funcs dpu_plane_helper_funcs = { + .prepare_fb = dpu_plane_prepare_fb, + .cleanup_fb = dpu_plane_cleanup_fb, + .atomic_check = dpu_plane_atomic_check, + .atomic_update = dpu_plane_atomic_update, +}; + +enum dpu_sspp dpu_plane_pipe(struct drm_plane *plane) +{ + return plane ? to_dpu_plane(plane)->pipe : SSPP_NONE; +} + +bool is_dpu_plane_virtual(struct drm_plane *plane) +{ + return plane ? to_dpu_plane(plane)->is_virtual : false; +} + +/* initialize plane */ +struct drm_plane *dpu_plane_init(struct drm_device *dev, + uint32_t pipe, bool primary_plane, + unsigned long possible_crtcs, u32 master_plane_id) +{ + struct drm_plane *plane = NULL, *master_plane = NULL; + const struct dpu_format_extended *format_list; + struct dpu_plane *pdpu; + struct msm_drm_private *priv; + struct dpu_kms *kms; + enum drm_plane_type type; + int zpos_max = DPU_ZPOS_MAX; + int ret = -EINVAL; + + if (!dev) { + DPU_ERROR("[%u]device is NULL\n", pipe); + goto exit; + } + + priv = dev->dev_private; + if (!priv) { + DPU_ERROR("[%u]private data is NULL\n", pipe); + goto exit; + } + + if (!priv->kms) { + DPU_ERROR("[%u]invalid KMS reference\n", pipe); + goto exit; + } + kms = to_dpu_kms(priv->kms); + + if (!kms->catalog) { + DPU_ERROR("[%u]invalid catalog reference\n", pipe); + goto exit; + } + + /* create and zero local structure */ + pdpu = kzalloc(sizeof(*pdpu), GFP_KERNEL); + if (!pdpu) { + DPU_ERROR("[%u]failed to allocate local plane struct\n", pipe); + ret = -ENOMEM; + goto exit; + } + + /* cache local stuff for later */ + plane = &pdpu->base; + pdpu->pipe = pipe; + pdpu->is_virtual = (master_plane_id != 0); + INIT_LIST_HEAD(&pdpu->mplane_list); + master_plane = drm_plane_find(dev, NULL, master_plane_id); + if (master_plane) { + struct dpu_plane *mpdpu = to_dpu_plane(master_plane); + + list_add_tail(&pdpu->mplane_list, &mpdpu->mplane_list); + } + + /* initialize underlying h/w driver */ + pdpu->pipe_hw = dpu_hw_sspp_init(pipe, kms->mmio, kms->catalog, + master_plane_id != 0); + if (IS_ERR(pdpu->pipe_hw)) { + DPU_ERROR("[%u]SSPP init failed\n", pipe); + ret = PTR_ERR(pdpu->pipe_hw); + goto clean_plane; + } else if (!pdpu->pipe_hw->cap || !pdpu->pipe_hw->cap->sblk) { + DPU_ERROR("[%u]SSPP init returned invalid cfg\n", pipe); + goto clean_sspp; + } + + /* cache features mask for later */ + pdpu->features = pdpu->pipe_hw->cap->features; + pdpu->pipe_sblk = pdpu->pipe_hw->cap->sblk; + if (!pdpu->pipe_sblk) { + DPU_ERROR("[%u]invalid sblk\n", pipe); + goto clean_sspp; + } + + if (!master_plane_id) + format_list = pdpu->pipe_sblk->format_list; + else + format_list = pdpu->pipe_sblk->virt_format_list; + + pdpu->nformats = dpu_populate_formats(format_list, + pdpu->formats, + 0, + ARRAY_SIZE(pdpu->formats)); + + if (!pdpu->nformats) { + DPU_ERROR("[%u]no valid formats for plane\n", pipe); + goto clean_sspp; + } + + if (pdpu->features & BIT(DPU_SSPP_CURSOR)) + type = DRM_PLANE_TYPE_CURSOR; + else if (primary_plane) + type = DRM_PLANE_TYPE_PRIMARY; + else + type = DRM_PLANE_TYPE_OVERLAY; + ret = drm_universal_plane_init(dev, plane, 0xff, &dpu_plane_funcs, + pdpu->formats, pdpu->nformats, + NULL, type, NULL); + if (ret) + goto clean_sspp; + + pdpu->catalog = kms->catalog; + + if (kms->catalog->mixer_count && + kms->catalog->mixer[0].sblk->maxblendstages) { + zpos_max = kms->catalog->mixer[0].sblk->maxblendstages - 1; + if (zpos_max > DPU_STAGE_MAX - DPU_STAGE_0 - 1) + zpos_max = DPU_STAGE_MAX - DPU_STAGE_0 - 1; + } + + ret = drm_plane_create_zpos_property(plane, 0, 0, zpos_max); + if (ret) + DPU_ERROR("failed to install zpos property, rc = %d\n", ret); + + /* success! finalize initialization */ + drm_plane_helper_add(plane, &dpu_plane_helper_funcs); + + /* save user friendly pipe name for later */ + snprintf(pdpu->pipe_name, DPU_NAME_SIZE, "plane%u", plane->base.id); + + mutex_init(&pdpu->lock); + + DPU_DEBUG("%s created for pipe:%u id:%u virtual:%u\n", pdpu->pipe_name, + pipe, plane->base.id, master_plane_id); + return plane; + +clean_sspp: + if (pdpu && pdpu->pipe_hw) + dpu_hw_sspp_destroy(pdpu->pipe_hw); +clean_plane: + kfree(pdpu); +exit: + return ERR_PTR(ret); +} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h new file mode 100644 index 0000000000000..f6fe6ddc7a3ac --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.com> + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _DPU_PLANE_H_ +#define _DPU_PLANE_H_ + +#include <drm/drm_crtc.h> + +#include "dpu_kms.h" +#include "dpu_hw_mdss.h" +#include "dpu_hw_sspp.h" + +/** + * struct dpu_plane_state: Define dpu extension of drm plane state object + * @base: base drm plane state object + * @property_state: Local storage for msm_prop properties + * @property_values: cached plane property values + * @aspace: pointer to address space for input/output buffers + * @input_fence: dereferenced input fence pointer + * @stage: assigned by crtc blender + * @multirect_index: index of the rectangle of SSPP + * @multirect_mode: parallel or time multiplex multirect mode + * @pending: whether the current update is still pending + * @scaler3_cfg: configuration data for scaler3 + * @pixel_ext: configuration data for pixel extensions + * @scaler_check_state: indicates status of user provided pixel extension data + * @cdp_cfg: CDP configuration + */ +struct dpu_plane_state { + struct drm_plane_state base; + struct msm_gem_address_space *aspace; + void *input_fence; + enum dpu_stage stage; + uint32_t multirect_index; + uint32_t multirect_mode; + bool pending; + + /* scaler configuration */ + struct dpu_hw_scaler3_cfg scaler3_cfg; + struct dpu_hw_pixel_ext pixel_ext; + + struct dpu_hw_pipe_cdp_cfg cdp_cfg; +}; + +/** + * struct dpu_multirect_plane_states: Defines multirect pair of drm plane states + * @r0: drm plane configured on rect 0 + * @r1: drm plane configured on rect 1 + */ +struct dpu_multirect_plane_states { + const struct drm_plane_state *r0; + const struct drm_plane_state *r1; +}; + +#define to_dpu_plane_state(x) \ + container_of(x, struct dpu_plane_state, base) + +/** + * dpu_plane_pipe - return sspp identifier for the given plane + * @plane: Pointer to DRM plane object + * Returns: sspp identifier of the given plane + */ +enum dpu_sspp dpu_plane_pipe(struct drm_plane *plane); + +/** + * is_dpu_plane_virtual - check for virtual plane + * @plane: Pointer to DRM plane object + * returns: true - if the plane is virtual + * false - if the plane is primary + */ +bool is_dpu_plane_virtual(struct drm_plane *plane); + +/** + * dpu_plane_get_ctl_flush - get control flush mask + * @plane: Pointer to DRM plane object + * @ctl: Pointer to control hardware + * @flush_sspp: Pointer to sspp flush control word + */ +void dpu_plane_get_ctl_flush(struct drm_plane *plane, struct dpu_hw_ctl *ctl, + u32 *flush_sspp); + +/** + * dpu_plane_restore - restore hw state if previously power collapsed + * @plane: Pointer to drm plane structure + */ +void dpu_plane_restore(struct drm_plane *plane); + +/** + * dpu_plane_flush - final plane operations before commit flush + * @plane: Pointer to drm plane structure + */ +void dpu_plane_flush(struct drm_plane *plane); + +/** + * dpu_plane_kickoff - final plane operations before commit kickoff + * @plane: Pointer to drm plane structure + */ +void dpu_plane_kickoff(struct drm_plane *plane); + +/** + * dpu_plane_set_error: enable/disable error condition + * @plane: pointer to drm_plane structure + */ +void dpu_plane_set_error(struct drm_plane *plane, bool error); + +/** + * dpu_plane_init - create new dpu plane for the given pipe + * @dev: Pointer to DRM device + * @pipe: dpu hardware pipe identifier + * @primary_plane: true if this pipe is primary plane for crtc + * @possible_crtcs: bitmask of crtc that can be attached to the given pipe + * @master_plane_id: primary plane id of a multirect pipe. 0 value passed for + * a regular plane initialization. A non-zero primary plane + * id will be passed for a virtual pipe initialization. + * + */ +struct drm_plane *dpu_plane_init(struct drm_device *dev, + uint32_t pipe, bool primary_plane, + unsigned long possible_crtcs, u32 master_plane_id); + +/** + * dpu_plane_validate_multirecti_v2 - validate the multirect planes + * against hw limitations + * @plane: drm plate states of the multirect pair + */ +int dpu_plane_validate_multirect_v2(struct dpu_multirect_plane_states *plane); + +/** + * dpu_plane_clear_multirect - clear multirect bits for the given pipe + * @drm_state: Pointer to DRM plane state + */ +void dpu_plane_clear_multirect(const struct drm_plane_state *drm_state); + +/** + * dpu_plane_wait_input_fence - wait for input fence object + * @plane: Pointer to DRM plane object + * @wait_ms: Wait timeout value + * Returns: Zero on success + */ +int dpu_plane_wait_input_fence(struct drm_plane *plane, uint32_t wait_ms); + +/** + * dpu_plane_color_fill - enables color fill on plane + * @plane: Pointer to DRM plane object + * @color: RGB fill color value, [23..16] Blue, [15..8] Green, [7..0] Red + * @alpha: 8-bit fill alpha value, 255 selects 100% alpha + * Returns: 0 on success + */ +int dpu_plane_color_fill(struct drm_plane *plane, + uint32_t color, uint32_t alpha); + +/** + * dpu_plane_set_revalidate - sets revalidate flag which forces a full + * validation of the plane properties in the next atomic check + * @plane: Pointer to DRM plane object + * @enable: Boolean to set/unset the flag + */ +void dpu_plane_set_revalidate(struct drm_plane *plane, bool enable); + +#endif /* _DPU_PLANE_H_ */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.c new file mode 100644 index 0000000000000..a68f1249388c4 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.c @@ -0,0 +1,249 @@ +/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#define pr_fmt(fmt) "[drm:%s:%d]: " fmt, __func__, __LINE__ + +#include <linux/kernel.h> +#include <linux/of.h> +#include <linux/string.h> +#include <linux/of_address.h> +#include <linux/slab.h> +#include <linux/mutex.h> +#include <linux/of_platform.h> + +#include "dpu_power_handle.h" +#include "dpu_trace.h" + +static const char *data_bus_name[DPU_POWER_HANDLE_DBUS_ID_MAX] = { + [DPU_POWER_HANDLE_DBUS_ID_MNOC] = "qcom,dpu-data-bus", + [DPU_POWER_HANDLE_DBUS_ID_LLCC] = "qcom,dpu-llcc-bus", + [DPU_POWER_HANDLE_DBUS_ID_EBI] = "qcom,dpu-ebi-bus", +}; + +const char *dpu_power_handle_get_dbus_name(u32 bus_id) +{ + if (bus_id < DPU_POWER_HANDLE_DBUS_ID_MAX) + return data_bus_name[bus_id]; + + return NULL; +} + +static void dpu_power_event_trigger_locked(struct dpu_power_handle *phandle, + u32 event_type) +{ + struct dpu_power_event *event; + + list_for_each_entry(event, &phandle->event_list, list) { + if (event->event_type & event_type) + event->cb_fnc(event_type, event->usr); + } +} + +struct dpu_power_client *dpu_power_client_create( + struct dpu_power_handle *phandle, char *client_name) +{ + struct dpu_power_client *client; + static u32 id; + + if (!client_name || !phandle) { + pr_err("client name is null or invalid power data\n"); + return ERR_PTR(-EINVAL); + } + + client = kzalloc(sizeof(struct dpu_power_client), GFP_KERNEL); + if (!client) + return ERR_PTR(-ENOMEM); + + mutex_lock(&phandle->phandle_lock); + strlcpy(client->name, client_name, MAX_CLIENT_NAME_LEN); + client->usecase_ndx = VOTE_INDEX_DISABLE; + client->id = id; + client->active = true; + pr_debug("client %s created:%pK id :%d\n", client_name, + client, id); + id++; + list_add(&client->list, &phandle->power_client_clist); + mutex_unlock(&phandle->phandle_lock); + + return client; +} + +void dpu_power_client_destroy(struct dpu_power_handle *phandle, + struct dpu_power_client *client) +{ + if (!client || !phandle) { + pr_err("reg bus vote: invalid client handle\n"); + } else if (!client->active) { + pr_err("dpu power deinit already done\n"); + kfree(client); + } else { + pr_debug("bus vote client %s destroyed:%pK id:%u\n", + client->name, client, client->id); + mutex_lock(&phandle->phandle_lock); + list_del_init(&client->list); + mutex_unlock(&phandle->phandle_lock); + kfree(client); + } +} + +void dpu_power_resource_init(struct platform_device *pdev, + struct dpu_power_handle *phandle) +{ + phandle->dev = &pdev->dev; + + INIT_LIST_HEAD(&phandle->power_client_clist); + INIT_LIST_HEAD(&phandle->event_list); + + mutex_init(&phandle->phandle_lock); +} + +void dpu_power_resource_deinit(struct platform_device *pdev, + struct dpu_power_handle *phandle) +{ + struct dpu_power_client *curr_client, *next_client; + struct dpu_power_event *curr_event, *next_event; + + if (!phandle || !pdev) { + pr_err("invalid input param\n"); + return; + } + + mutex_lock(&phandle->phandle_lock); + list_for_each_entry_safe(curr_client, next_client, + &phandle->power_client_clist, list) { + pr_err("cliend:%s-%d still registered with refcount:%d\n", + curr_client->name, curr_client->id, + curr_client->refcount); + curr_client->active = false; + list_del(&curr_client->list); + } + + list_for_each_entry_safe(curr_event, next_event, + &phandle->event_list, list) { + pr_err("event:%d, client:%s still registered\n", + curr_event->event_type, + curr_event->client_name); + curr_event->active = false; + list_del(&curr_event->list); + } + mutex_unlock(&phandle->phandle_lock); +} + +int dpu_power_resource_enable(struct dpu_power_handle *phandle, + struct dpu_power_client *pclient, bool enable) +{ + bool changed = false; + u32 max_usecase_ndx = VOTE_INDEX_DISABLE, prev_usecase_ndx; + struct dpu_power_client *client; + + if (!phandle || !pclient) { + pr_err("invalid input argument\n"); + return -EINVAL; + } + + mutex_lock(&phandle->phandle_lock); + if (enable) + pclient->refcount++; + else if (pclient->refcount) + pclient->refcount--; + + if (pclient->refcount) + pclient->usecase_ndx = VOTE_INDEX_LOW; + else + pclient->usecase_ndx = VOTE_INDEX_DISABLE; + + list_for_each_entry(client, &phandle->power_client_clist, list) { + if (client->usecase_ndx < VOTE_INDEX_MAX && + client->usecase_ndx > max_usecase_ndx) + max_usecase_ndx = client->usecase_ndx; + } + + if (phandle->current_usecase_ndx != max_usecase_ndx) { + changed = true; + prev_usecase_ndx = phandle->current_usecase_ndx; + phandle->current_usecase_ndx = max_usecase_ndx; + } + + pr_debug("%pS: changed=%d current idx=%d request client %s id:%u enable:%d refcount:%d\n", + __builtin_return_address(0), changed, max_usecase_ndx, + pclient->name, pclient->id, enable, pclient->refcount); + + if (!changed) + goto end; + + if (enable) { + dpu_power_event_trigger_locked(phandle, + DPU_POWER_EVENT_PRE_ENABLE); + dpu_power_event_trigger_locked(phandle, + DPU_POWER_EVENT_POST_ENABLE); + + } else { + dpu_power_event_trigger_locked(phandle, + DPU_POWER_EVENT_PRE_DISABLE); + dpu_power_event_trigger_locked(phandle, + DPU_POWER_EVENT_POST_DISABLE); + } + +end: + mutex_unlock(&phandle->phandle_lock); + return 0; +} + +struct dpu_power_event *dpu_power_handle_register_event( + struct dpu_power_handle *phandle, + u32 event_type, void (*cb_fnc)(u32 event_type, void *usr), + void *usr, char *client_name) +{ + struct dpu_power_event *event; + + if (!phandle) { + pr_err("invalid power handle\n"); + return ERR_PTR(-EINVAL); + } else if (!cb_fnc || !event_type) { + pr_err("no callback fnc or event type\n"); + return ERR_PTR(-EINVAL); + } + + event = kzalloc(sizeof(struct dpu_power_event), GFP_KERNEL); + if (!event) + return ERR_PTR(-ENOMEM); + + event->event_type = event_type; + event->cb_fnc = cb_fnc; + event->usr = usr; + strlcpy(event->client_name, client_name, MAX_CLIENT_NAME_LEN); + event->active = true; + + mutex_lock(&phandle->phandle_lock); + list_add(&event->list, &phandle->event_list); + mutex_unlock(&phandle->phandle_lock); + + return event; +} + +void dpu_power_handle_unregister_event( + struct dpu_power_handle *phandle, + struct dpu_power_event *event) +{ + if (!phandle || !event) { + pr_err("invalid phandle or event\n"); + } else if (!event->active) { + pr_err("power handle deinit already done\n"); + kfree(event); + } else { + mutex_lock(&phandle->phandle_lock); + list_del_init(&event->list); + mutex_unlock(&phandle->phandle_lock); + kfree(event); + } +} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.h new file mode 100644 index 0000000000000..344f74464ecab --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_power_handle.h @@ -0,0 +1,225 @@ +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#ifndef _DPU_POWER_HANDLE_H_ +#define _DPU_POWER_HANDLE_H_ + +#define MAX_CLIENT_NAME_LEN 128 + +#define DPU_POWER_HANDLE_ENABLE_BUS_AB_QUOTA 0 +#define DPU_POWER_HANDLE_DISABLE_BUS_AB_QUOTA 0 +#define DPU_POWER_HANDLE_ENABLE_BUS_IB_QUOTA 1600000000 +#define DPU_POWER_HANDLE_DISABLE_BUS_IB_QUOTA 0 + +#include "dpu_io_util.h" + +/* event will be triggered before power handler disable */ +#define DPU_POWER_EVENT_PRE_DISABLE 0x1 + +/* event will be triggered after power handler disable */ +#define DPU_POWER_EVENT_POST_DISABLE 0x2 + +/* event will be triggered before power handler enable */ +#define DPU_POWER_EVENT_PRE_ENABLE 0x4 + +/* event will be triggered after power handler enable */ +#define DPU_POWER_EVENT_POST_ENABLE 0x8 + +/** + * mdss_bus_vote_type: register bus vote type + * VOTE_INDEX_DISABLE: removes the client vote + * VOTE_INDEX_LOW: keeps the lowest vote for register bus + * VOTE_INDEX_MAX: invalid + */ +enum mdss_bus_vote_type { + VOTE_INDEX_DISABLE, + VOTE_INDEX_LOW, + VOTE_INDEX_MAX, +}; + +/** + * enum dpu_power_handle_data_bus_client - type of axi bus clients + * @DPU_POWER_HANDLE_DATA_BUS_CLIENT_RT: core real-time bus client + * @DPU_POWER_HANDLE_DATA_BUS_CLIENT_NRT: core non-real-time bus client + * @DPU_POWER_HANDLE_DATA_BUS_CLIENT_MAX: maximum number of bus client type + */ +enum dpu_power_handle_data_bus_client { + DPU_POWER_HANDLE_DATA_BUS_CLIENT_RT, + DPU_POWER_HANDLE_DATA_BUS_CLIENT_NRT, + DPU_POWER_HANDLE_DATA_BUS_CLIENT_MAX +}; + +/** + * enum DPU_POWER_HANDLE_DBUS_ID - data bus identifier + * @DPU_POWER_HANDLE_DBUS_ID_MNOC: DPU/MNOC data bus + * @DPU_POWER_HANDLE_DBUS_ID_LLCC: MNOC/LLCC data bus + * @DPU_POWER_HANDLE_DBUS_ID_EBI: LLCC/EBI data bus + */ +enum DPU_POWER_HANDLE_DBUS_ID { + DPU_POWER_HANDLE_DBUS_ID_MNOC, + DPU_POWER_HANDLE_DBUS_ID_LLCC, + DPU_POWER_HANDLE_DBUS_ID_EBI, + DPU_POWER_HANDLE_DBUS_ID_MAX, +}; + +/** + * struct dpu_power_client: stores the power client for dpu driver + * @name: name of the client + * @usecase_ndx: current regs bus vote type + * @refcount: current refcount if multiple modules are using same + * same client for enable/disable. Power module will + * aggregate the refcount and vote accordingly for this + * client. + * @id: assigned during create. helps for debugging. + * @list: list to attach power handle master list + * @ab: arbitrated bandwidth for each bus client + * @ib: instantaneous bandwidth for each bus client + * @active: inidcates the state of dpu power handle + */ +struct dpu_power_client { + char name[MAX_CLIENT_NAME_LEN]; + short usecase_ndx; + short refcount; + u32 id; + struct list_head list; + u64 ab[DPU_POWER_HANDLE_DATA_BUS_CLIENT_MAX]; + u64 ib[DPU_POWER_HANDLE_DATA_BUS_CLIENT_MAX]; + bool active; +}; + +/* + * struct dpu_power_event - local event registration structure + * @client_name: name of the client registering + * @cb_fnc: pointer to desired callback function + * @usr: user pointer to pass to callback event trigger + * @event: refer to DPU_POWER_HANDLE_EVENT_* + * @list: list to attach event master list + * @active: indicates the state of dpu power handle + */ +struct dpu_power_event { + char client_name[MAX_CLIENT_NAME_LEN]; + void (*cb_fnc)(u32 event_type, void *usr); + void *usr; + u32 event_type; + struct list_head list; + bool active; +}; + +/** + * struct dpu_power_handle: power handle main struct + * @client_clist: master list to store all clients + * @phandle_lock: lock to synchronize the enable/disable + * @dev: pointer to device structure + * @usecase_ndx: current usecase index + * @event_list: current power handle event list + */ +struct dpu_power_handle { + struct list_head power_client_clist; + struct mutex phandle_lock; + struct device *dev; + u32 current_usecase_ndx; + struct list_head event_list; +}; + +/** + * dpu_power_resource_init() - initializes the dpu power handle + * @pdev: platform device to search the power resources + * @pdata: power handle to store the power resources + */ +void dpu_power_resource_init(struct platform_device *pdev, + struct dpu_power_handle *pdata); + +/** + * dpu_power_resource_deinit() - release the dpu power handle + * @pdev: platform device for power resources + * @pdata: power handle containing the resources + * + * Return: error code. + */ +void dpu_power_resource_deinit(struct platform_device *pdev, + struct dpu_power_handle *pdata); + +/** + * dpu_power_client_create() - create the client on power handle + * @pdata: power handle containing the resources + * @client_name: new client name for registration + * + * Return: error code. + */ +struct dpu_power_client *dpu_power_client_create(struct dpu_power_handle *pdata, + char *client_name); + +/** + * dpu_power_client_destroy() - destroy the client on power handle + * @pdata: power handle containing the resources + * @client_name: new client name for registration + * + * Return: none + */ +void dpu_power_client_destroy(struct dpu_power_handle *phandle, + struct dpu_power_client *client); + +/** + * dpu_power_resource_enable() - enable/disable the power resources + * @pdata: power handle containing the resources + * @client: client information to enable/disable its vote + * @enable: boolean request for enable/disable + * + * Return: error code. + */ +int dpu_power_resource_enable(struct dpu_power_handle *pdata, + struct dpu_power_client *pclient, bool enable); + +/** + * dpu_power_data_bus_bandwidth_ctrl() - control data bus bandwidth enable + * @phandle: power handle containing the resources + * @client: client information to bandwidth control + * @enable: true to enable bandwidth for data base + * + * Return: none + */ +void dpu_power_data_bus_bandwidth_ctrl(struct dpu_power_handle *phandle, + struct dpu_power_client *pclient, int enable); + +/** + * dpu_power_handle_register_event - register a callback function for an event. + * Clients can register for multiple events with a single register. + * Any block with access to phandle can register for the event + * notification. + * @phandle: power handle containing the resources + * @event_type: event type to register; refer DPU_POWER_HANDLE_EVENT_* + * @cb_fnc: pointer to desired callback function + * @usr: user pointer to pass to callback on event trigger + * + * Return: event pointer if success, or error code otherwise + */ +struct dpu_power_event *dpu_power_handle_register_event( + struct dpu_power_handle *phandle, + u32 event_type, void (*cb_fnc)(u32 event_type, void *usr), + void *usr, char *client_name); +/** + * dpu_power_handle_unregister_event - unregister callback for event(s) + * @phandle: power handle containing the resources + * @event: event pointer returned after power handle register + */ +void dpu_power_handle_unregister_event(struct dpu_power_handle *phandle, + struct dpu_power_event *event); + +/** + * dpu_power_handle_get_dbus_name - get name of given data bus identifier + * @bus_id: data bus identifier + * Return: Pointer to name string if success; NULL otherwise + */ +const char *dpu_power_handle_get_dbus_name(u32 bus_id); + +#endif /* _DPU_POWER_HANDLE_H_ */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c new file mode 100644 index 0000000000000..13c0a36d4ef95 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c @@ -0,0 +1,1079 @@ +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#define pr_fmt(fmt) "[drm:%s] " fmt, __func__ +#include "dpu_kms.h" +#include "dpu_hw_lm.h" +#include "dpu_hw_ctl.h" +#include "dpu_hw_cdm.h" +#include "dpu_hw_pingpong.h" +#include "dpu_hw_intf.h" +#include "dpu_encoder.h" +#include "dpu_trace.h" + +#define RESERVED_BY_OTHER(h, r) \ + ((h)->rsvp && ((h)->rsvp->enc_id != (r)->enc_id)) + +#define RM_RQ_LOCK(r) ((r)->top_ctrl & BIT(DPU_RM_TOPCTL_RESERVE_LOCK)) +#define RM_RQ_CLEAR(r) ((r)->top_ctrl & BIT(DPU_RM_TOPCTL_RESERVE_CLEAR)) +#define RM_RQ_DS(r) ((r)->top_ctrl & BIT(DPU_RM_TOPCTL_DS)) +#define RM_IS_TOPOLOGY_MATCH(t, r) ((t).num_lm == (r).num_lm && \ + (t).num_comp_enc == (r).num_enc && \ + (t).num_intf == (r).num_intf) + +struct dpu_rm_topology_def { + enum dpu_rm_topology_name top_name; + int num_lm; + int num_comp_enc; + int num_intf; + int num_ctl; + int needs_split_display; +}; + +static const struct dpu_rm_topology_def g_top_table[] = { + { DPU_RM_TOPOLOGY_NONE, 0, 0, 0, 0, false }, + { DPU_RM_TOPOLOGY_SINGLEPIPE, 1, 0, 1, 1, false }, + { DPU_RM_TOPOLOGY_DUALPIPE, 2, 0, 2, 2, true }, + { DPU_RM_TOPOLOGY_DUALPIPE_3DMERGE, 2, 0, 1, 1, false }, +}; + +/** + * struct dpu_rm_requirements - Reservation requirements parameter bundle + * @top_ctrl: topology control preference from kernel client + * @top: selected topology for the display + * @hw_res: Hardware resources required as reported by the encoders + */ +struct dpu_rm_requirements { + uint64_t top_ctrl; + const struct dpu_rm_topology_def *topology; + struct dpu_encoder_hw_resources hw_res; +}; + +/** + * struct dpu_rm_rsvp - Use Case Reservation tagging structure + * Used to tag HW blocks as reserved by a CRTC->Encoder->Connector chain + * By using as a tag, rather than lists of pointers to HW blocks used + * we can avoid some list management since we don't know how many blocks + * of each type a given use case may require. + * @list: List head for list of all reservations + * @seq: Global RSVP sequence number for debugging, especially for + * differentiating differenct allocations for same encoder. + * @enc_id: Reservations are tracked by Encoder DRM object ID. + * CRTCs may be connected to multiple Encoders. + * An encoder or connector id identifies the display path. + * @topology DRM<->HW topology use case + */ +struct dpu_rm_rsvp { + struct list_head list; + uint32_t seq; + uint32_t enc_id; + enum dpu_rm_topology_name topology; +}; + +/** + * struct dpu_rm_hw_blk - hardware block tracking list member + * @list: List head for list of all hardware blocks tracking items + * @rsvp: Pointer to use case reservation if reserved by a client + * @rsvp_nxt: Temporary pointer used during reservation to the incoming + * request. Will be swapped into rsvp if proposal is accepted + * @type: Type of hardware block this structure tracks + * @id: Hardware ID number, within it's own space, ie. LM_X + * @catalog: Pointer to the hardware catalog entry for this block + * @hw: Pointer to the hardware register access object for this block + */ +struct dpu_rm_hw_blk { + struct list_head list; + struct dpu_rm_rsvp *rsvp; + struct dpu_rm_rsvp *rsvp_nxt; + enum dpu_hw_blk_type type; + uint32_t id; + struct dpu_hw_blk *hw; +}; + +/** + * dpu_rm_dbg_rsvp_stage - enum of steps in making reservation for event logging + */ +enum dpu_rm_dbg_rsvp_stage { + DPU_RM_STAGE_BEGIN, + DPU_RM_STAGE_AFTER_CLEAR, + DPU_RM_STAGE_AFTER_RSVPNEXT, + DPU_RM_STAGE_FINAL +}; + +static void _dpu_rm_print_rsvps( + struct dpu_rm *rm, + enum dpu_rm_dbg_rsvp_stage stage) +{ + struct dpu_rm_rsvp *rsvp; + struct dpu_rm_hw_blk *blk; + enum dpu_hw_blk_type type; + + DPU_DEBUG("%d\n", stage); + + list_for_each_entry(rsvp, &rm->rsvps, list) { + DRM_DEBUG_KMS("%d rsvp[s%ue%u] topology %d\n", stage, rsvp->seq, + rsvp->enc_id, rsvp->topology); + } + + for (type = 0; type < DPU_HW_BLK_MAX; type++) { + list_for_each_entry(blk, &rm->hw_blks[type], list) { + if (!blk->rsvp && !blk->rsvp_nxt) + continue; + + DRM_DEBUG_KMS("%d rsvp[s%ue%u->s%ue%u] %d %d\n", stage, + (blk->rsvp) ? blk->rsvp->seq : 0, + (blk->rsvp) ? blk->rsvp->enc_id : 0, + (blk->rsvp_nxt) ? blk->rsvp_nxt->seq : 0, + (blk->rsvp_nxt) ? blk->rsvp_nxt->enc_id : 0, + blk->type, blk->id); + } + } +} + +struct dpu_hw_mdp *dpu_rm_get_mdp(struct dpu_rm *rm) +{ + return rm->hw_mdp; +} + +enum dpu_rm_topology_name +dpu_rm_get_topology_name(struct msm_display_topology topology) +{ + int i; + + for (i = 0; i < DPU_RM_TOPOLOGY_MAX; i++) + if (RM_IS_TOPOLOGY_MATCH(g_top_table[i], topology)) + return g_top_table[i].top_name; + + return DPU_RM_TOPOLOGY_NONE; +} + +void dpu_rm_init_hw_iter( + struct dpu_rm_hw_iter *iter, + uint32_t enc_id, + enum dpu_hw_blk_type type) +{ + memset(iter, 0, sizeof(*iter)); + iter->enc_id = enc_id; + iter->type = type; +} + +static bool _dpu_rm_get_hw_locked(struct dpu_rm *rm, struct dpu_rm_hw_iter *i) +{ + struct list_head *blk_list; + + if (!rm || !i || i->type >= DPU_HW_BLK_MAX) { + DPU_ERROR("invalid rm\n"); + return false; + } + + i->hw = NULL; + blk_list = &rm->hw_blks[i->type]; + + if (i->blk && (&i->blk->list == blk_list)) { + DPU_DEBUG("attempt resume iteration past last\n"); + return false; + } + + i->blk = list_prepare_entry(i->blk, blk_list, list); + + list_for_each_entry_continue(i->blk, blk_list, list) { + struct dpu_rm_rsvp *rsvp = i->blk->rsvp; + + if (i->blk->type != i->type) { + DPU_ERROR("found incorrect block type %d on %d list\n", + i->blk->type, i->type); + return false; + } + + if ((i->enc_id == 0) || (rsvp && rsvp->enc_id == i->enc_id)) { + i->hw = i->blk->hw; + DPU_DEBUG("found type %d id %d for enc %d\n", + i->type, i->blk->id, i->enc_id); + return true; + } + } + + DPU_DEBUG("no match, type %d for enc %d\n", i->type, i->enc_id); + + return false; +} + +bool dpu_rm_get_hw(struct dpu_rm *rm, struct dpu_rm_hw_iter *i) +{ + bool ret; + + mutex_lock(&rm->rm_lock); + ret = _dpu_rm_get_hw_locked(rm, i); + mutex_unlock(&rm->rm_lock); + + return ret; +} + +static void _dpu_rm_hw_destroy(enum dpu_hw_blk_type type, void *hw) +{ + switch (type) { + case DPU_HW_BLK_LM: + dpu_hw_lm_destroy(hw); + break; + case DPU_HW_BLK_CTL: + dpu_hw_ctl_destroy(hw); + break; + case DPU_HW_BLK_CDM: + dpu_hw_cdm_destroy(hw); + break; + case DPU_HW_BLK_PINGPONG: + dpu_hw_pingpong_destroy(hw); + break; + case DPU_HW_BLK_INTF: + dpu_hw_intf_destroy(hw); + break; + case DPU_HW_BLK_SSPP: + /* SSPPs are not managed by the resource manager */ + case DPU_HW_BLK_TOP: + /* Top is a singleton, not managed in hw_blks list */ + case DPU_HW_BLK_MAX: + default: + DPU_ERROR("unsupported block type %d\n", type); + break; + } +} + +int dpu_rm_destroy(struct dpu_rm *rm) +{ + + struct dpu_rm_rsvp *rsvp_cur, *rsvp_nxt; + struct dpu_rm_hw_blk *hw_cur, *hw_nxt; + enum dpu_hw_blk_type type; + + if (!rm) { + DPU_ERROR("invalid rm\n"); + return -EINVAL; + } + + list_for_each_entry_safe(rsvp_cur, rsvp_nxt, &rm->rsvps, list) { + list_del(&rsvp_cur->list); + kfree(rsvp_cur); + } + + + for (type = 0; type < DPU_HW_BLK_MAX; type++) { + list_for_each_entry_safe(hw_cur, hw_nxt, &rm->hw_blks[type], + list) { + list_del(&hw_cur->list); + _dpu_rm_hw_destroy(hw_cur->type, hw_cur->hw); + kfree(hw_cur); + } + } + + dpu_hw_mdp_destroy(rm->hw_mdp); + rm->hw_mdp = NULL; + + mutex_destroy(&rm->rm_lock); + + return 0; +} + +static int _dpu_rm_hw_blk_create( + struct dpu_rm *rm, + struct dpu_mdss_cfg *cat, + void __iomem *mmio, + enum dpu_hw_blk_type type, + uint32_t id, + void *hw_catalog_info) +{ + struct dpu_rm_hw_blk *blk; + struct dpu_hw_mdp *hw_mdp; + void *hw; + + hw_mdp = rm->hw_mdp; + + switch (type) { + case DPU_HW_BLK_LM: + hw = dpu_hw_lm_init(id, mmio, cat); + break; + case DPU_HW_BLK_CTL: + hw = dpu_hw_ctl_init(id, mmio, cat); + break; + case DPU_HW_BLK_CDM: + hw = dpu_hw_cdm_init(id, mmio, cat, hw_mdp); + break; + case DPU_HW_BLK_PINGPONG: + hw = dpu_hw_pingpong_init(id, mmio, cat); + break; + case DPU_HW_BLK_INTF: + hw = dpu_hw_intf_init(id, mmio, cat); + break; + case DPU_HW_BLK_SSPP: + /* SSPPs are not managed by the resource manager */ + case DPU_HW_BLK_TOP: + /* Top is a singleton, not managed in hw_blks list */ + case DPU_HW_BLK_MAX: + default: + DPU_ERROR("unsupported block type %d\n", type); + return -EINVAL; + } + + if (IS_ERR_OR_NULL(hw)) { + DPU_ERROR("failed hw object creation: type %d, err %ld\n", + type, PTR_ERR(hw)); + return -EFAULT; + } + + blk = kzalloc(sizeof(*blk), GFP_KERNEL); + if (!blk) { + _dpu_rm_hw_destroy(type, hw); + return -ENOMEM; + } + + blk->type = type; + blk->id = id; + blk->hw = hw; + list_add_tail(&blk->list, &rm->hw_blks[type]); + + return 0; +} + +int dpu_rm_init(struct dpu_rm *rm, + struct dpu_mdss_cfg *cat, + void __iomem *mmio, + struct drm_device *dev) +{ + int rc, i; + enum dpu_hw_blk_type type; + + if (!rm || !cat || !mmio || !dev) { + DPU_ERROR("invalid kms\n"); + return -EINVAL; + } + + /* Clear, setup lists */ + memset(rm, 0, sizeof(*rm)); + + mutex_init(&rm->rm_lock); + + INIT_LIST_HEAD(&rm->rsvps); + for (type = 0; type < DPU_HW_BLK_MAX; type++) + INIT_LIST_HEAD(&rm->hw_blks[type]); + + rm->dev = dev; + + /* Some of the sub-blocks require an mdptop to be created */ + rm->hw_mdp = dpu_hw_mdptop_init(MDP_TOP, mmio, cat); + if (IS_ERR_OR_NULL(rm->hw_mdp)) { + rc = PTR_ERR(rm->hw_mdp); + rm->hw_mdp = NULL; + DPU_ERROR("failed: mdp hw not available\n"); + goto fail; + } + + /* Interrogate HW catalog and create tracking items for hw blocks */ + for (i = 0; i < cat->mixer_count; i++) { + struct dpu_lm_cfg *lm = &cat->mixer[i]; + + if (lm->pingpong == PINGPONG_MAX) { + DPU_DEBUG("skip mixer %d without pingpong\n", lm->id); + continue; + } + + rc = _dpu_rm_hw_blk_create(rm, cat, mmio, DPU_HW_BLK_LM, + cat->mixer[i].id, &cat->mixer[i]); + if (rc) { + DPU_ERROR("failed: lm hw not available\n"); + goto fail; + } + + if (!rm->lm_max_width) { + rm->lm_max_width = lm->sblk->maxwidth; + } else if (rm->lm_max_width != lm->sblk->maxwidth) { + /* + * Don't expect to have hw where lm max widths differ. + * If found, take the min. + */ + DPU_ERROR("unsupported: lm maxwidth differs\n"); + if (rm->lm_max_width > lm->sblk->maxwidth) + rm->lm_max_width = lm->sblk->maxwidth; + } + } + + for (i = 0; i < cat->pingpong_count; i++) { + rc = _dpu_rm_hw_blk_create(rm, cat, mmio, DPU_HW_BLK_PINGPONG, + cat->pingpong[i].id, &cat->pingpong[i]); + if (rc) { + DPU_ERROR("failed: pp hw not available\n"); + goto fail; + } + } + + for (i = 0; i < cat->intf_count; i++) { + if (cat->intf[i].type == INTF_NONE) { + DPU_DEBUG("skip intf %d with type none\n", i); + continue; + } + + rc = _dpu_rm_hw_blk_create(rm, cat, mmio, DPU_HW_BLK_INTF, + cat->intf[i].id, &cat->intf[i]); + if (rc) { + DPU_ERROR("failed: intf hw not available\n"); + goto fail; + } + } + + for (i = 0; i < cat->ctl_count; i++) { + rc = _dpu_rm_hw_blk_create(rm, cat, mmio, DPU_HW_BLK_CTL, + cat->ctl[i].id, &cat->ctl[i]); + if (rc) { + DPU_ERROR("failed: ctl hw not available\n"); + goto fail; + } + } + + for (i = 0; i < cat->cdm_count; i++) { + rc = _dpu_rm_hw_blk_create(rm, cat, mmio, DPU_HW_BLK_CDM, + cat->cdm[i].id, &cat->cdm[i]); + if (rc) { + DPU_ERROR("failed: cdm hw not available\n"); + goto fail; + } + } + + return 0; + +fail: + dpu_rm_destroy(rm); + + return rc; +} + +/** + * _dpu_rm_check_lm_and_get_connected_blks - check if proposed layer mixer meets + * proposed use case requirements, incl. hardwired dependent blocks like + * pingpong + * @rm: dpu resource manager handle + * @rsvp: reservation currently being created + * @reqs: proposed use case requirements + * @lm: proposed layer mixer, function checks if lm, and all other hardwired + * blocks connected to the lm (pp) is available and appropriate + * @pp: output parameter, pingpong block attached to the layer mixer. + * NULL if pp was not available, or not matching requirements. + * @primary_lm: if non-null, this function check if lm is compatible primary_lm + * as well as satisfying all other requirements + * @Return: true if lm matches all requirements, false otherwise + */ +static bool _dpu_rm_check_lm_and_get_connected_blks( + struct dpu_rm *rm, + struct dpu_rm_rsvp *rsvp, + struct dpu_rm_requirements *reqs, + struct dpu_rm_hw_blk *lm, + struct dpu_rm_hw_blk **pp, + struct dpu_rm_hw_blk *primary_lm) +{ + const struct dpu_lm_cfg *lm_cfg = to_dpu_hw_mixer(lm->hw)->cap; + struct dpu_rm_hw_iter iter; + + *pp = NULL; + + DPU_DEBUG("check lm %d pp %d\n", + lm_cfg->id, lm_cfg->pingpong); + + /* Check if this layer mixer is a peer of the proposed primary LM */ + if (primary_lm) { + const struct dpu_lm_cfg *prim_lm_cfg = + to_dpu_hw_mixer(primary_lm->hw)->cap; + + if (!test_bit(lm_cfg->id, &prim_lm_cfg->lm_pair_mask)) { + DPU_DEBUG("lm %d not peer of lm %d\n", lm_cfg->id, + prim_lm_cfg->id); + return false; + } + } + + /* Already reserved? */ + if (RESERVED_BY_OTHER(lm, rsvp)) { + DPU_DEBUG("lm %d already reserved\n", lm_cfg->id); + return false; + } + + dpu_rm_init_hw_iter(&iter, 0, DPU_HW_BLK_PINGPONG); + while (_dpu_rm_get_hw_locked(rm, &iter)) { + if (iter.blk->id == lm_cfg->pingpong) { + *pp = iter.blk; + break; + } + } + + if (!*pp) { + DPU_ERROR("failed to get pp on lm %d\n", lm_cfg->pingpong); + return false; + } + + if (RESERVED_BY_OTHER(*pp, rsvp)) { + DPU_DEBUG("lm %d pp %d already reserved\n", lm->id, + (*pp)->id); + return false; + } + + return true; +} + +static int _dpu_rm_reserve_lms( + struct dpu_rm *rm, + struct dpu_rm_rsvp *rsvp, + struct dpu_rm_requirements *reqs) + +{ + struct dpu_rm_hw_blk *lm[MAX_BLOCKS]; + struct dpu_rm_hw_blk *pp[MAX_BLOCKS]; + struct dpu_rm_hw_iter iter_i, iter_j; + int lm_count = 0; + int i, rc = 0; + + if (!reqs->topology->num_lm) { + DPU_ERROR("invalid number of lm: %d\n", reqs->topology->num_lm); + return -EINVAL; + } + + /* Find a primary mixer */ + dpu_rm_init_hw_iter(&iter_i, 0, DPU_HW_BLK_LM); + while (lm_count != reqs->topology->num_lm && + _dpu_rm_get_hw_locked(rm, &iter_i)) { + memset(&lm, 0, sizeof(lm)); + memset(&pp, 0, sizeof(pp)); + + lm_count = 0; + lm[lm_count] = iter_i.blk; + + if (!_dpu_rm_check_lm_and_get_connected_blks( + rm, rsvp, reqs, lm[lm_count], + &pp[lm_count], NULL)) + continue; + + ++lm_count; + + /* Valid primary mixer found, find matching peers */ + dpu_rm_init_hw_iter(&iter_j, 0, DPU_HW_BLK_LM); + + while (lm_count != reqs->topology->num_lm && + _dpu_rm_get_hw_locked(rm, &iter_j)) { + if (iter_i.blk == iter_j.blk) + continue; + + if (!_dpu_rm_check_lm_and_get_connected_blks( + rm, rsvp, reqs, iter_j.blk, + &pp[lm_count], iter_i.blk)) + continue; + + lm[lm_count] = iter_j.blk; + ++lm_count; + } + } + + if (lm_count != reqs->topology->num_lm) { + DPU_DEBUG("unable to find appropriate mixers\n"); + return -ENAVAIL; + } + + for (i = 0; i < ARRAY_SIZE(lm); i++) { + if (!lm[i]) + break; + + lm[i]->rsvp_nxt = rsvp; + pp[i]->rsvp_nxt = rsvp; + + trace_dpu_rm_reserve_lms(lm[i]->id, lm[i]->type, rsvp->enc_id, + pp[i]->id); + } + + return rc; +} + +static int _dpu_rm_reserve_ctls( + struct dpu_rm *rm, + struct dpu_rm_rsvp *rsvp, + const struct dpu_rm_topology_def *top) +{ + struct dpu_rm_hw_blk *ctls[MAX_BLOCKS]; + struct dpu_rm_hw_iter iter; + int i = 0; + + memset(&ctls, 0, sizeof(ctls)); + + dpu_rm_init_hw_iter(&iter, 0, DPU_HW_BLK_CTL); + while (_dpu_rm_get_hw_locked(rm, &iter)) { + const struct dpu_hw_ctl *ctl = to_dpu_hw_ctl(iter.blk->hw); + unsigned long features = ctl->caps->features; + bool has_split_display; + + if (RESERVED_BY_OTHER(iter.blk, rsvp)) + continue; + + has_split_display = BIT(DPU_CTL_SPLIT_DISPLAY) & features; + + DPU_DEBUG("ctl %d caps 0x%lX\n", iter.blk->id, features); + + if (top->needs_split_display != has_split_display) + continue; + + ctls[i] = iter.blk; + DPU_DEBUG("ctl %d match\n", iter.blk->id); + + if (++i == top->num_ctl) + break; + } + + if (i != top->num_ctl) + return -ENAVAIL; + + for (i = 0; i < ARRAY_SIZE(ctls) && i < top->num_ctl; i++) { + ctls[i]->rsvp_nxt = rsvp; + trace_dpu_rm_reserve_ctls(ctls[i]->id, ctls[i]->type, + rsvp->enc_id); + } + + return 0; +} + +static int _dpu_rm_reserve_cdm( + struct dpu_rm *rm, + struct dpu_rm_rsvp *rsvp, + uint32_t id, + enum dpu_hw_blk_type type) +{ + struct dpu_rm_hw_iter iter; + + DRM_DEBUG_KMS("type %d id %d\n", type, id); + + dpu_rm_init_hw_iter(&iter, 0, DPU_HW_BLK_CDM); + while (_dpu_rm_get_hw_locked(rm, &iter)) { + const struct dpu_hw_cdm *cdm = to_dpu_hw_cdm(iter.blk->hw); + const struct dpu_cdm_cfg *caps = cdm->caps; + bool match = false; + + if (RESERVED_BY_OTHER(iter.blk, rsvp)) + continue; + + if (type == DPU_HW_BLK_INTF && id != INTF_MAX) + match = test_bit(id, &caps->intf_connect); + + DRM_DEBUG_KMS("iter: type:%d id:%d enc:%d cdm:%lu match:%d\n", + iter.blk->type, iter.blk->id, rsvp->enc_id, + caps->intf_connect, match); + + if (!match) + continue; + + trace_dpu_rm_reserve_cdm(iter.blk->id, iter.blk->type, + rsvp->enc_id); + iter.blk->rsvp_nxt = rsvp; + break; + } + + if (!iter.hw) { + DPU_ERROR("couldn't reserve cdm for type %d id %d\n", type, id); + return -ENAVAIL; + } + + return 0; +} + +static int _dpu_rm_reserve_intf( + struct dpu_rm *rm, + struct dpu_rm_rsvp *rsvp, + uint32_t id, + enum dpu_hw_blk_type type, + bool needs_cdm) +{ + struct dpu_rm_hw_iter iter; + int ret = 0; + + /* Find the block entry in the rm, and note the reservation */ + dpu_rm_init_hw_iter(&iter, 0, type); + while (_dpu_rm_get_hw_locked(rm, &iter)) { + if (iter.blk->id != id) + continue; + + if (RESERVED_BY_OTHER(iter.blk, rsvp)) { + DPU_ERROR("type %d id %d already reserved\n", type, id); + return -ENAVAIL; + } + + iter.blk->rsvp_nxt = rsvp; + trace_dpu_rm_reserve_intf(iter.blk->id, iter.blk->type, + rsvp->enc_id); + break; + } + + /* Shouldn't happen since intfs are fixed at probe */ + if (!iter.hw) { + DPU_ERROR("couldn't find type %d id %d\n", type, id); + return -EINVAL; + } + + if (needs_cdm) + ret = _dpu_rm_reserve_cdm(rm, rsvp, id, type); + + return ret; +} + +static int _dpu_rm_reserve_intf_related_hw( + struct dpu_rm *rm, + struct dpu_rm_rsvp *rsvp, + struct dpu_encoder_hw_resources *hw_res) +{ + int i, ret = 0; + u32 id; + + for (i = 0; i < ARRAY_SIZE(hw_res->intfs); i++) { + if (hw_res->intfs[i] == INTF_MODE_NONE) + continue; + id = i + INTF_0; + ret = _dpu_rm_reserve_intf(rm, rsvp, id, + DPU_HW_BLK_INTF, hw_res->needs_cdm); + if (ret) + return ret; + } + + return ret; +} + +static int _dpu_rm_make_next_rsvp( + struct dpu_rm *rm, + struct drm_encoder *enc, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + struct dpu_rm_rsvp *rsvp, + struct dpu_rm_requirements *reqs) +{ + int ret; + struct dpu_rm_topology_def topology; + + /* Create reservation info, tag reserved blocks with it as we go */ + rsvp->seq = ++rm->rsvp_next_seq; + rsvp->enc_id = enc->base.id; + rsvp->topology = reqs->topology->top_name; + list_add_tail(&rsvp->list, &rm->rsvps); + + ret = _dpu_rm_reserve_lms(rm, rsvp, reqs); + if (ret) { + DPU_ERROR("unable to find appropriate mixers\n"); + return ret; + } + + /* + * Do assignment preferring to give away low-resource CTLs first: + * - Check mixers without Split Display + * - Only then allow to grab from CTLs with split display capability + */ + _dpu_rm_reserve_ctls(rm, rsvp, reqs->topology); + if (ret && !reqs->topology->needs_split_display) { + memcpy(&topology, reqs->topology, sizeof(topology)); + topology.needs_split_display = true; + _dpu_rm_reserve_ctls(rm, rsvp, &topology); + } + if (ret) { + DPU_ERROR("unable to find appropriate CTL\n"); + return ret; + } + + /* Assign INTFs and blks whose usage is tied to them: CTL & CDM */ + ret = _dpu_rm_reserve_intf_related_hw(rm, rsvp, &reqs->hw_res); + if (ret) + return ret; + + return ret; +} + +static int _dpu_rm_populate_requirements( + struct dpu_rm *rm, + struct drm_encoder *enc, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + struct dpu_rm_requirements *reqs, + struct msm_display_topology req_topology) +{ + int i; + + memset(reqs, 0, sizeof(*reqs)); + + dpu_encoder_get_hw_resources(enc, &reqs->hw_res, conn_state); + + for (i = 0; i < DPU_RM_TOPOLOGY_MAX; i++) { + if (RM_IS_TOPOLOGY_MATCH(g_top_table[i], + req_topology)) { + reqs->topology = &g_top_table[i]; + break; + } + } + + if (!reqs->topology) { + DPU_ERROR("invalid topology for the display\n"); + return -EINVAL; + } + + /** + * Set the requirement based on caps if not set from user space + * This will ensure to select LM tied with DS blocks + * Currently, DS blocks are tied with LM 0 and LM 1 (primary display) + */ + if (!RM_RQ_DS(reqs) && rm->hw_mdp->caps->has_dest_scaler && + conn_state->connector->connector_type == DRM_MODE_CONNECTOR_DSI) + reqs->top_ctrl |= BIT(DPU_RM_TOPCTL_DS); + + DRM_DEBUG_KMS("top_ctrl: 0x%llX num_h_tiles: %d\n", reqs->top_ctrl, + reqs->hw_res.display_num_of_h_tiles); + DRM_DEBUG_KMS("num_lm: %d num_ctl: %d topology: %d split_display: %d\n", + reqs->topology->num_lm, reqs->topology->num_ctl, + reqs->topology->top_name, + reqs->topology->needs_split_display); + + return 0; +} + +static struct dpu_rm_rsvp *_dpu_rm_get_rsvp( + struct dpu_rm *rm, + struct drm_encoder *enc) +{ + struct dpu_rm_rsvp *i; + + if (!rm || !enc) { + DPU_ERROR("invalid params\n"); + return NULL; + } + + if (list_empty(&rm->rsvps)) + return NULL; + + list_for_each_entry(i, &rm->rsvps, list) + if (i->enc_id == enc->base.id) + return i; + + return NULL; +} + +static struct drm_connector *_dpu_rm_get_connector( + struct drm_encoder *enc) +{ + struct drm_connector *conn = NULL; + struct list_head *connector_list = + &enc->dev->mode_config.connector_list; + + list_for_each_entry(conn, connector_list, head) + if (conn->encoder == enc) + return conn; + + return NULL; +} + +/** + * _dpu_rm_release_rsvp - release resources and release a reservation + * @rm: KMS handle + * @rsvp: RSVP pointer to release and release resources for + */ +static void _dpu_rm_release_rsvp( + struct dpu_rm *rm, + struct dpu_rm_rsvp *rsvp, + struct drm_connector *conn) +{ + struct dpu_rm_rsvp *rsvp_c, *rsvp_n; + struct dpu_rm_hw_blk *blk; + enum dpu_hw_blk_type type; + + if (!rsvp) + return; + + DPU_DEBUG("rel rsvp %d enc %d\n", rsvp->seq, rsvp->enc_id); + + list_for_each_entry_safe(rsvp_c, rsvp_n, &rm->rsvps, list) { + if (rsvp == rsvp_c) { + list_del(&rsvp_c->list); + break; + } + } + + for (type = 0; type < DPU_HW_BLK_MAX; type++) { + list_for_each_entry(blk, &rm->hw_blks[type], list) { + if (blk->rsvp == rsvp) { + blk->rsvp = NULL; + DPU_DEBUG("rel rsvp %d enc %d %d %d\n", + rsvp->seq, rsvp->enc_id, + blk->type, blk->id); + } + if (blk->rsvp_nxt == rsvp) { + blk->rsvp_nxt = NULL; + DPU_DEBUG("rel rsvp_nxt %d enc %d %d %d\n", + rsvp->seq, rsvp->enc_id, + blk->type, blk->id); + } + } + } + + kfree(rsvp); +} + +void dpu_rm_release(struct dpu_rm *rm, struct drm_encoder *enc) +{ + struct dpu_rm_rsvp *rsvp; + struct drm_connector *conn; + + if (!rm || !enc) { + DPU_ERROR("invalid params\n"); + return; + } + + mutex_lock(&rm->rm_lock); + + rsvp = _dpu_rm_get_rsvp(rm, enc); + if (!rsvp) { + DPU_ERROR("failed to find rsvp for enc %d\n", enc->base.id); + goto end; + } + + conn = _dpu_rm_get_connector(enc); + if (!conn) { + DPU_ERROR("failed to get connector for enc %d\n", enc->base.id); + goto end; + } + + _dpu_rm_release_rsvp(rm, rsvp, conn); +end: + mutex_unlock(&rm->rm_lock); +} + +static int _dpu_rm_commit_rsvp( + struct dpu_rm *rm, + struct dpu_rm_rsvp *rsvp, + struct drm_connector_state *conn_state) +{ + struct dpu_rm_hw_blk *blk; + enum dpu_hw_blk_type type; + int ret = 0; + + /* Swap next rsvp to be the active */ + for (type = 0; type < DPU_HW_BLK_MAX; type++) { + list_for_each_entry(blk, &rm->hw_blks[type], list) { + if (blk->rsvp_nxt) { + blk->rsvp = blk->rsvp_nxt; + blk->rsvp_nxt = NULL; + } + } + } + + if (!ret) + DRM_DEBUG_KMS("rsrv enc %d topology %d\n", rsvp->enc_id, + rsvp->topology); + + return ret; +} + +int dpu_rm_reserve( + struct dpu_rm *rm, + struct drm_encoder *enc, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + struct msm_display_topology topology, + bool test_only) +{ + struct dpu_rm_rsvp *rsvp_cur, *rsvp_nxt; + struct dpu_rm_requirements reqs; + int ret; + + if (!rm || !enc || !crtc_state || !conn_state) { + DPU_ERROR("invalid arguments\n"); + return -EINVAL; + } + + /* Check if this is just a page-flip */ + if (!drm_atomic_crtc_needs_modeset(crtc_state)) + return 0; + + DRM_DEBUG_KMS("reserving hw for conn %d enc %d crtc %d test_only %d\n", + conn_state->connector->base.id, enc->base.id, + crtc_state->crtc->base.id, test_only); + + mutex_lock(&rm->rm_lock); + + _dpu_rm_print_rsvps(rm, DPU_RM_STAGE_BEGIN); + + ret = _dpu_rm_populate_requirements(rm, enc, crtc_state, + conn_state, &reqs, topology); + if (ret) { + DPU_ERROR("failed to populate hw requirements\n"); + goto end; + } + + /* + * We only support one active reservation per-hw-block. But to implement + * transactional semantics for test-only, and for allowing failure while + * modifying your existing reservation, over the course of this + * function we can have two reservations: + * Current: Existing reservation + * Next: Proposed reservation. The proposed reservation may fail, or may + * be discarded if in test-only mode. + * If reservation is successful, and we're not in test-only, then we + * replace the current with the next. + */ + rsvp_nxt = kzalloc(sizeof(*rsvp_nxt), GFP_KERNEL); + if (!rsvp_nxt) { + ret = -ENOMEM; + goto end; + } + + rsvp_cur = _dpu_rm_get_rsvp(rm, enc); + + /* + * User can request that we clear out any reservation during the + * atomic_check phase by using this CLEAR bit + */ + if (rsvp_cur && test_only && RM_RQ_CLEAR(&reqs)) { + DPU_DEBUG("test_only & CLEAR: clear rsvp[s%de%d]\n", + rsvp_cur->seq, rsvp_cur->enc_id); + _dpu_rm_release_rsvp(rm, rsvp_cur, conn_state->connector); + rsvp_cur = NULL; + _dpu_rm_print_rsvps(rm, DPU_RM_STAGE_AFTER_CLEAR); + } + + /* Check the proposed reservation, store it in hw's "next" field */ + ret = _dpu_rm_make_next_rsvp(rm, enc, crtc_state, conn_state, + rsvp_nxt, &reqs); + + _dpu_rm_print_rsvps(rm, DPU_RM_STAGE_AFTER_RSVPNEXT); + + if (ret) { + DPU_ERROR("failed to reserve hw resources: %d\n", ret); + _dpu_rm_release_rsvp(rm, rsvp_nxt, conn_state->connector); + } else if (test_only && !RM_RQ_LOCK(&reqs)) { + /* + * Normally, if test_only, test the reservation and then undo + * However, if the user requests LOCK, then keep the reservation + * made during the atomic_check phase. + */ + DPU_DEBUG("test_only: discard test rsvp[s%de%d]\n", + rsvp_nxt->seq, rsvp_nxt->enc_id); + _dpu_rm_release_rsvp(rm, rsvp_nxt, conn_state->connector); + } else { + if (test_only && RM_RQ_LOCK(&reqs)) + DPU_DEBUG("test_only & LOCK: lock rsvp[s%de%d]\n", + rsvp_nxt->seq, rsvp_nxt->enc_id); + + _dpu_rm_release_rsvp(rm, rsvp_cur, conn_state->connector); + + ret = _dpu_rm_commit_rsvp(rm, rsvp_nxt, conn_state); + } + + _dpu_rm_print_rsvps(rm, DPU_RM_STAGE_FINAL); + +end: + mutex_unlock(&rm->rm_lock); + + return ret; +} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h new file mode 100644 index 0000000000000..ef3f67bedaa00 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#ifndef __DPU_RM_H__ +#define __DPU_RM_H__ + +#include <linux/list.h> + +#include "msm_kms.h" +#include "dpu_hw_top.h" + +/** + * enum dpu_rm_topology_name - HW resource use case in use by connector + * @DPU_RM_TOPOLOGY_NONE: No topology in use currently + * @DPU_RM_TOPOLOGY_SINGLEPIPE: 1 LM, 1 PP, 1 INTF/WB + * @DPU_RM_TOPOLOGY_DUALPIPE: 2 LM, 2 PP, 2 INTF/WB + * @DPU_RM_TOPOLOGY_DUALPIPE_3DMERGE: 2 LM, 2 PP, 3DMux, 1 INTF/WB + */ +enum dpu_rm_topology_name { + DPU_RM_TOPOLOGY_NONE = 0, + DPU_RM_TOPOLOGY_SINGLEPIPE, + DPU_RM_TOPOLOGY_DUALPIPE, + DPU_RM_TOPOLOGY_DUALPIPE_3DMERGE, + DPU_RM_TOPOLOGY_MAX, +}; + +/** + * enum dpu_rm_topology_control - HW resource use case in use by connector + * @DPU_RM_TOPCTL_RESERVE_LOCK: If set, in AtomicTest phase, after a successful + * test, reserve the resources for this display. + * Normal behavior would not impact the reservation + * list during the AtomicTest phase. + * @DPU_RM_TOPCTL_RESERVE_CLEAR: If set, in AtomicTest phase, before testing, + * release any reservation held by this display. + * Normal behavior would not impact the + * reservation list during the AtomicTest phase. + * @DPU_RM_TOPCTL_DS : Require layer mixers with DS capabilities + */ +enum dpu_rm_topology_control { + DPU_RM_TOPCTL_RESERVE_LOCK, + DPU_RM_TOPCTL_RESERVE_CLEAR, + DPU_RM_TOPCTL_DS, +}; + +/** + * struct dpu_rm - DPU dynamic hardware resource manager + * @dev: device handle for event logging purposes + * @rsvps: list of hardware reservations by each crtc->encoder->connector + * @hw_blks: array of lists of hardware resources present in the system, one + * list per type of hardware block + * @hw_mdp: hardware object for mdp_top + * @lm_max_width: cached layer mixer maximum width + * @rsvp_next_seq: sequence number for next reservation for debugging purposes + * @rm_lock: resource manager mutex + */ +struct dpu_rm { + struct drm_device *dev; + struct list_head rsvps; + struct list_head hw_blks[DPU_HW_BLK_MAX]; + struct dpu_hw_mdp *hw_mdp; + uint32_t lm_max_width; + uint32_t rsvp_next_seq; + struct mutex rm_lock; +}; + +/** + * struct dpu_rm_hw_blk - resource manager internal structure + * forward declaration for single iterator definition without void pointer + */ +struct dpu_rm_hw_blk; + +/** + * struct dpu_rm_hw_iter - iterator for use with dpu_rm + * @hw: dpu_hw object requested, or NULL on failure + * @blk: dpu_rm internal block representation. Clients ignore. Used as iterator. + * @enc_id: DRM ID of Encoder client wishes to search for, or 0 for Any Encoder + * @type: Hardware Block Type client wishes to search for. + */ +struct dpu_rm_hw_iter { + void *hw; + struct dpu_rm_hw_blk *blk; + uint32_t enc_id; + enum dpu_hw_blk_type type; +}; + +/** + * dpu_rm_init - Read hardware catalog and create reservation tracking objects + * for all HW blocks. + * @rm: DPU Resource Manager handle + * @cat: Pointer to hardware catalog + * @mmio: mapped register io address of MDP + * @dev: device handle for event logging purposes + * @Return: 0 on Success otherwise -ERROR + */ +int dpu_rm_init(struct dpu_rm *rm, + struct dpu_mdss_cfg *cat, + void *mmio, + struct drm_device *dev); + +/** + * dpu_rm_destroy - Free all memory allocated by dpu_rm_init + * @rm: DPU Resource Manager handle + * @Return: 0 on Success otherwise -ERROR + */ +int dpu_rm_destroy(struct dpu_rm *rm); + +/** + * dpu_rm_reserve - Given a CRTC->Encoder->Connector display chain, analyze + * the use connections and user requirements, specified through related + * topology control properties, and reserve hardware blocks to that + * display chain. + * HW blocks can then be accessed through dpu_rm_get_* functions. + * HW Reservations should be released via dpu_rm_release_hw. + * @rm: DPU Resource Manager handle + * @drm_enc: DRM Encoder handle + * @crtc_state: Proposed Atomic DRM CRTC State handle + * @conn_state: Proposed Atomic DRM Connector State handle + * @topology: Pointer to topology info for the display + * @test_only: Atomic-Test phase, discard results (unless property overrides) + * @Return: 0 on Success otherwise -ERROR + */ +int dpu_rm_reserve(struct dpu_rm *rm, + struct drm_encoder *drm_enc, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + struct msm_display_topology topology, + bool test_only); + +/** + * dpu_rm_reserve - Given the encoder for the display chain, release any + * HW blocks previously reserved for that use case. + * @rm: DPU Resource Manager handle + * @enc: DRM Encoder handle + * @Return: 0 on Success otherwise -ERROR + */ +void dpu_rm_release(struct dpu_rm *rm, struct drm_encoder *enc); + +/** + * dpu_rm_get_mdp - Retrieve HW block for MDP TOP. + * This is never reserved, and is usable by any display. + * @rm: DPU Resource Manager handle + * @Return: Pointer to hw block or NULL + */ +struct dpu_hw_mdp *dpu_rm_get_mdp(struct dpu_rm *rm); + +/** + * dpu_rm_init_hw_iter - setup given iterator for new iteration over hw list + * using dpu_rm_get_hw + * @iter: iter object to initialize + * @enc_id: DRM ID of Encoder client wishes to search for, or 0 for Any Encoder + * @type: Hardware Block Type client wishes to search for. + */ +void dpu_rm_init_hw_iter( + struct dpu_rm_hw_iter *iter, + uint32_t enc_id, + enum dpu_hw_blk_type type); +/** + * dpu_rm_get_hw - retrieve reserved hw object given encoder and hw type + * Meant to do a single pass through the hardware list to iteratively + * retrieve hardware blocks of a given type for a given encoder. + * Initialize an iterator object. + * Set hw block type of interest. Set encoder id of interest, 0 for any. + * Function returns first hw of type for that encoder. + * Subsequent calls will return the next reserved hw of that type in-order. + * Iterator HW pointer will be null on failure to find hw. + * @rm: DPU Resource Manager handle + * @iter: iterator object + * @Return: true on match found, false on no match found + */ +bool dpu_rm_get_hw(struct dpu_rm *rm, struct dpu_rm_hw_iter *iter); + +/** + * dpu_rm_check_property_topctl - validate property bitmask before it is set + * @val: user's proposed topology control bitmask + * @Return: 0 on success or error + */ +int dpu_rm_check_property_topctl(uint64_t val); + +/** + * dpu_rm_get_topology_name - returns the name of the the given topology + * definition + * @topology: topology definition + * @Return: name of the topology + */ +enum dpu_rm_topology_name +dpu_rm_get_topology_name(struct msm_display_topology topology); + +#endif /* __DPU_RM_H__ */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h new file mode 100644 index 0000000000000..ae0ca50762383 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h @@ -0,0 +1,1007 @@ +/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#if !defined(_DPU_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ) +#define _DPU_TRACE_H_ + +#include <linux/stringify.h> +#include <linux/types.h> +#include <linux/tracepoint.h> + +#include <drm/drm_rect.h> +#include "dpu_crtc.h" +#include "dpu_encoder_phys.h" +#include "dpu_hw_mdss.h" +#include "dpu_hw_vbif.h" +#include "dpu_plane.h" + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM dpu +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE dpu_trace + +TRACE_EVENT(dpu_perf_set_qos_luts, + TP_PROTO(u32 pnum, u32 fmt, bool rt, u32 fl, + u32 lut, u32 lut_usage), + TP_ARGS(pnum, fmt, rt, fl, lut, lut_usage), + TP_STRUCT__entry( + __field(u32, pnum) + __field(u32, fmt) + __field(bool, rt) + __field(u32, fl) + __field(u64, lut) + __field(u32, lut_usage) + ), + TP_fast_assign( + __entry->pnum = pnum; + __entry->fmt = fmt; + __entry->rt = rt; + __entry->fl = fl; + __entry->lut = lut; + __entry->lut_usage = lut_usage; + ), + TP_printk("pnum=%d fmt=%x rt=%d fl=%d lut=0x%llx lut_usage=%d", + __entry->pnum, __entry->fmt, + __entry->rt, __entry->fl, + __entry->lut, __entry->lut_usage) +); + +TRACE_EVENT(dpu_perf_set_danger_luts, + TP_PROTO(u32 pnum, u32 fmt, u32 mode, u32 danger_lut, + u32 safe_lut), + TP_ARGS(pnum, fmt, mode, danger_lut, safe_lut), + TP_STRUCT__entry( + __field(u32, pnum) + __field(u32, fmt) + __field(u32, mode) + __field(u32, danger_lut) + __field(u32, safe_lut) + ), + TP_fast_assign( + __entry->pnum = pnum; + __entry->fmt = fmt; + __entry->mode = mode; + __entry->danger_lut = danger_lut; + __entry->safe_lut = safe_lut; + ), + TP_printk("pnum=%d fmt=%x mode=%d luts[0x%x, 0x%x]", + __entry->pnum, __entry->fmt, + __entry->mode, __entry->danger_lut, + __entry->safe_lut) +); + +TRACE_EVENT(dpu_perf_set_ot, + TP_PROTO(u32 pnum, u32 xin_id, u32 rd_lim, u32 vbif_idx), + TP_ARGS(pnum, xin_id, rd_lim, vbif_idx), + TP_STRUCT__entry( + __field(u32, pnum) + __field(u32, xin_id) + __field(u32, rd_lim) + __field(u32, vbif_idx) + ), + TP_fast_assign( + __entry->pnum = pnum; + __entry->xin_id = xin_id; + __entry->rd_lim = rd_lim; + __entry->vbif_idx = vbif_idx; + ), + TP_printk("pnum:%d xin_id:%d ot:%d vbif:%d", + __entry->pnum, __entry->xin_id, __entry->rd_lim, + __entry->vbif_idx) +) + +TRACE_EVENT(dpu_perf_update_bus, + TP_PROTO(int client, unsigned long long ab_quota, + unsigned long long ib_quota), + TP_ARGS(client, ab_quota, ib_quota), + TP_STRUCT__entry( + __field(int, client) + __field(u64, ab_quota) + __field(u64, ib_quota) + ), + TP_fast_assign( + __entry->client = client; + __entry->ab_quota = ab_quota; + __entry->ib_quota = ib_quota; + ), + TP_printk("Request client:%d ab=%llu ib=%llu", + __entry->client, + __entry->ab_quota, + __entry->ib_quota) +) + + +TRACE_EVENT(dpu_cmd_release_bw, + TP_PROTO(u32 crtc_id), + TP_ARGS(crtc_id), + TP_STRUCT__entry( + __field(u32, crtc_id) + ), + TP_fast_assign( + __entry->crtc_id = crtc_id; + ), + TP_printk("crtc:%d", __entry->crtc_id) +); + +TRACE_EVENT(tracing_mark_write, + TP_PROTO(int pid, const char *name, bool trace_begin), + TP_ARGS(pid, name, trace_begin), + TP_STRUCT__entry( + __field(int, pid) + __string(trace_name, name) + __field(bool, trace_begin) + ), + TP_fast_assign( + __entry->pid = pid; + __assign_str(trace_name, name); + __entry->trace_begin = trace_begin; + ), + TP_printk("%s|%d|%s", __entry->trace_begin ? "B" : "E", + __entry->pid, __get_str(trace_name)) +) + +TRACE_EVENT(dpu_trace_counter, + TP_PROTO(int pid, char *name, int value), + TP_ARGS(pid, name, value), + TP_STRUCT__entry( + __field(int, pid) + __string(counter_name, name) + __field(int, value) + ), + TP_fast_assign( + __entry->pid = current->tgid; + __assign_str(counter_name, name); + __entry->value = value; + ), + TP_printk("%d|%s|%d", __entry->pid, + __get_str(counter_name), __entry->value) +) + +TRACE_EVENT(dpu_perf_crtc_update, + TP_PROTO(u32 crtc, u64 bw_ctl_mnoc, u64 bw_ctl_llcc, + u64 bw_ctl_ebi, u32 core_clk_rate, + bool stop_req, u32 update_bus, u32 update_clk), + TP_ARGS(crtc, bw_ctl_mnoc, bw_ctl_llcc, bw_ctl_ebi, core_clk_rate, + stop_req, update_bus, update_clk), + TP_STRUCT__entry( + __field(u32, crtc) + __field(u64, bw_ctl_mnoc) + __field(u64, bw_ctl_llcc) + __field(u64, bw_ctl_ebi) + __field(u32, core_clk_rate) + __field(bool, stop_req) + __field(u32, update_bus) + __field(u32, update_clk) + ), + TP_fast_assign( + __entry->crtc = crtc; + __entry->bw_ctl_mnoc = bw_ctl_mnoc; + __entry->bw_ctl_llcc = bw_ctl_llcc; + __entry->bw_ctl_ebi = bw_ctl_ebi; + __entry->core_clk_rate = core_clk_rate; + __entry->stop_req = stop_req; + __entry->update_bus = update_bus; + __entry->update_clk = update_clk; + ), + TP_printk( + "crtc=%d bw_mnoc=%llu bw_llcc=%llu bw_ebi=%llu clk_rate=%u stop_req=%d u_bus=%d u_clk=%d", + __entry->crtc, + __entry->bw_ctl_mnoc, + __entry->bw_ctl_llcc, + __entry->bw_ctl_ebi, + __entry->core_clk_rate, + __entry->stop_req, + __entry->update_bus, + __entry->update_clk) +); + +DECLARE_EVENT_CLASS(dpu_enc_irq_template, + TP_PROTO(uint32_t drm_id, enum dpu_intr_idx intr_idx, int hw_idx, + int irq_idx), + TP_ARGS(drm_id, intr_idx, hw_idx, irq_idx), + TP_STRUCT__entry( + __field( uint32_t, drm_id ) + __field( enum dpu_intr_idx, intr_idx ) + __field( int, hw_idx ) + __field( int, irq_idx ) + ), + TP_fast_assign( + __entry->drm_id = drm_id; + __entry->intr_idx = intr_idx; + __entry->hw_idx = hw_idx; + __entry->irq_idx = irq_idx; + ), + TP_printk("id=%u, intr=%d, hw=%d, irq=%d", + __entry->drm_id, __entry->intr_idx, __entry->hw_idx, + __entry->irq_idx) +); +DEFINE_EVENT(dpu_enc_irq_template, dpu_enc_irq_register_success, + TP_PROTO(uint32_t drm_id, enum dpu_intr_idx intr_idx, int hw_idx, + int irq_idx), + TP_ARGS(drm_id, intr_idx, hw_idx, irq_idx) +); +DEFINE_EVENT(dpu_enc_irq_template, dpu_enc_irq_unregister_success, + TP_PROTO(uint32_t drm_id, enum dpu_intr_idx intr_idx, int hw_idx, + int irq_idx), + TP_ARGS(drm_id, intr_idx, hw_idx, irq_idx) +); + +TRACE_EVENT(dpu_enc_irq_wait_success, + TP_PROTO(uint32_t drm_id, enum dpu_intr_idx intr_idx, int hw_idx, + int irq_idx, enum dpu_pingpong pp_idx, int atomic_cnt), + TP_ARGS(drm_id, intr_idx, hw_idx, irq_idx, pp_idx, atomic_cnt), + TP_STRUCT__entry( + __field( uint32_t, drm_id ) + __field( enum dpu_intr_idx, intr_idx ) + __field( int, hw_idx ) + __field( int, irq_idx ) + __field( enum dpu_pingpong, pp_idx ) + __field( int, atomic_cnt ) + ), + TP_fast_assign( + __entry->drm_id = drm_id; + __entry->intr_idx = intr_idx; + __entry->hw_idx = hw_idx; + __entry->irq_idx = irq_idx; + __entry->pp_idx = pp_idx; + __entry->atomic_cnt = atomic_cnt; + ), + TP_printk("id=%u, intr=%d, hw=%d, irq=%d, pp=%d, atomic_cnt=%d", + __entry->drm_id, __entry->intr_idx, __entry->hw_idx, + __entry->irq_idx, __entry->pp_idx, __entry->atomic_cnt) +); + +DECLARE_EVENT_CLASS(dpu_drm_obj_template, + TP_PROTO(uint32_t drm_id), + TP_ARGS(drm_id), + TP_STRUCT__entry( + __field( uint32_t, drm_id ) + ), + TP_fast_assign( + __entry->drm_id = drm_id; + ), + TP_printk("id=%u", __entry->drm_id) +); +DEFINE_EVENT(dpu_drm_obj_template, dpu_enc_atomic_check, + TP_PROTO(uint32_t drm_id), + TP_ARGS(drm_id) +); +DEFINE_EVENT(dpu_drm_obj_template, dpu_enc_mode_set, + TP_PROTO(uint32_t drm_id), + TP_ARGS(drm_id) +); +DEFINE_EVENT(dpu_drm_obj_template, dpu_enc_disable, + TP_PROTO(uint32_t drm_id), + TP_ARGS(drm_id) +); +DEFINE_EVENT(dpu_drm_obj_template, dpu_enc_kickoff, + TP_PROTO(uint32_t drm_id), + TP_ARGS(drm_id) +); +DEFINE_EVENT(dpu_drm_obj_template, dpu_enc_prepare_kickoff, + TP_PROTO(uint32_t drm_id), + TP_ARGS(drm_id) +); +DEFINE_EVENT(dpu_drm_obj_template, dpu_enc_prepare_kickoff_reset, + TP_PROTO(uint32_t drm_id), + TP_ARGS(drm_id) +); +DEFINE_EVENT(dpu_drm_obj_template, dpu_crtc_complete_flip, + TP_PROTO(uint32_t drm_id), + TP_ARGS(drm_id) +); +DEFINE_EVENT(dpu_drm_obj_template, dpu_crtc_vblank_cb, + TP_PROTO(uint32_t drm_id), + TP_ARGS(drm_id) +); +DEFINE_EVENT(dpu_drm_obj_template, dpu_crtc_complete_commit, + TP_PROTO(uint32_t drm_id), + TP_ARGS(drm_id) +); +DEFINE_EVENT(dpu_drm_obj_template, dpu_kms_enc_enable, + TP_PROTO(uint32_t drm_id), + TP_ARGS(drm_id) +); +DEFINE_EVENT(dpu_drm_obj_template, dpu_kms_commit, + TP_PROTO(uint32_t drm_id), + TP_ARGS(drm_id) +); +DEFINE_EVENT(dpu_drm_obj_template, dpu_kms_wait_for_commit_done, + TP_PROTO(uint32_t drm_id), + TP_ARGS(drm_id) +); + +TRACE_EVENT(dpu_enc_enable, + TP_PROTO(uint32_t drm_id, int hdisplay, int vdisplay), + TP_ARGS(drm_id, hdisplay, vdisplay), + TP_STRUCT__entry( + __field( uint32_t, drm_id ) + __field( int, hdisplay ) + __field( int, vdisplay ) + ), + TP_fast_assign( + __entry->drm_id = drm_id; + __entry->hdisplay = hdisplay; + __entry->vdisplay = vdisplay; + ), + TP_printk("id=%u, mode=%dx%d", + __entry->drm_id, __entry->hdisplay, __entry->vdisplay) +); + +DECLARE_EVENT_CLASS(dpu_enc_keyval_template, + TP_PROTO(uint32_t drm_id, int val), + TP_ARGS(drm_id, val), + TP_STRUCT__entry( + __field( uint32_t, drm_id ) + __field( int, val ) + ), + TP_fast_assign( + __entry->drm_id = drm_id; + __entry->val = val; + ), + TP_printk("id=%u, val=%d", __entry->drm_id, __entry->val) +); +DEFINE_EVENT(dpu_enc_keyval_template, dpu_enc_underrun_cb, + TP_PROTO(uint32_t drm_id, int count), + TP_ARGS(drm_id, count) +); +DEFINE_EVENT(dpu_enc_keyval_template, dpu_enc_trigger_start, + TP_PROTO(uint32_t drm_id, int ctl_idx), + TP_ARGS(drm_id, ctl_idx) +); + +TRACE_EVENT(dpu_enc_atomic_check_flags, + TP_PROTO(uint32_t drm_id, unsigned int flags, int private_flags), + TP_ARGS(drm_id, flags, private_flags), + TP_STRUCT__entry( + __field( uint32_t, drm_id ) + __field( unsigned int, flags ) + __field( int, private_flags ) + ), + TP_fast_assign( + __entry->drm_id = drm_id; + __entry->flags = flags; + __entry->private_flags = private_flags; + ), + TP_printk("id=%u, flags=%u, private_flags=%d", + __entry->drm_id, __entry->flags, __entry->private_flags) +); + +DECLARE_EVENT_CLASS(dpu_enc_id_enable_template, + TP_PROTO(uint32_t drm_id, bool enable), + TP_ARGS(drm_id, enable), + TP_STRUCT__entry( + __field( uint32_t, drm_id ) + __field( bool, enable ) + ), + TP_fast_assign( + __entry->drm_id = drm_id; + __entry->enable = enable; + ), + TP_printk("id=%u, enable=%s", + __entry->drm_id, __entry->enable ? "true" : "false") +); +DEFINE_EVENT(dpu_enc_id_enable_template, dpu_enc_rc_helper, + TP_PROTO(uint32_t drm_id, bool enable), + TP_ARGS(drm_id, enable) +); +DEFINE_EVENT(dpu_enc_id_enable_template, dpu_enc_vblank_cb, + TP_PROTO(uint32_t drm_id, bool enable), + TP_ARGS(drm_id, enable) +); +DEFINE_EVENT(dpu_enc_id_enable_template, dpu_enc_frame_event_cb, + TP_PROTO(uint32_t drm_id, bool enable), + TP_ARGS(drm_id, enable) +); +DEFINE_EVENT(dpu_enc_id_enable_template, dpu_enc_phys_cmd_connect_te, + TP_PROTO(uint32_t drm_id, bool enable), + TP_ARGS(drm_id, enable) +); + +TRACE_EVENT(dpu_enc_rc, + TP_PROTO(uint32_t drm_id, u32 sw_event, bool idle_pc_supported, + int rc_state, const char *stage), + TP_ARGS(drm_id, sw_event, idle_pc_supported, rc_state, stage), + TP_STRUCT__entry( + __field( uint32_t, drm_id ) + __field( u32, sw_event ) + __field( bool, idle_pc_supported ) + __field( int, rc_state ) + __string( stage_str, stage ) + ), + TP_fast_assign( + __entry->drm_id = drm_id; + __entry->sw_event = sw_event; + __entry->idle_pc_supported = idle_pc_supported; + __entry->rc_state = rc_state; + __assign_str(stage_str, stage); + ), + TP_printk("%s: id:%u, sw_event:%d, idle_pc_supported:%s, rc_state:%d\n", + __get_str(stage_str), __entry->drm_id, __entry->sw_event, + __entry->idle_pc_supported ? "true" : "false", + __entry->rc_state) +); + +TRACE_EVENT(dpu_enc_frame_done_cb_not_busy, + TP_PROTO(uint32_t drm_id, u32 event, enum dpu_intf intf_idx), + TP_ARGS(drm_id, event, intf_idx), + TP_STRUCT__entry( + __field( uint32_t, drm_id ) + __field( u32, event ) + __field( enum dpu_intf, intf_idx ) + ), + TP_fast_assign( + __entry->drm_id = drm_id; + __entry->event = event; + __entry->intf_idx = intf_idx; + ), + TP_printk("id=%u, event=%u, intf=%d", __entry->drm_id, __entry->event, + __entry->intf_idx) +); + +TRACE_EVENT(dpu_enc_frame_done_cb, + TP_PROTO(uint32_t drm_id, unsigned int idx, + unsigned long frame_busy_mask), + TP_ARGS(drm_id, idx, frame_busy_mask), + TP_STRUCT__entry( + __field( uint32_t, drm_id ) + __field( unsigned int, idx ) + __field( unsigned long, frame_busy_mask ) + ), + TP_fast_assign( + __entry->drm_id = drm_id; + __entry->idx = idx; + __entry->frame_busy_mask = frame_busy_mask; + ), + TP_printk("id=%u, idx=%u, frame_busy_mask=%lx", __entry->drm_id, + __entry->idx, __entry->frame_busy_mask) +); + +TRACE_EVENT(dpu_enc_trigger_flush, + TP_PROTO(uint32_t drm_id, enum dpu_intf intf_idx, + int pending_kickoff_cnt, int ctl_idx, u32 pending_flush_ret), + TP_ARGS(drm_id, intf_idx, pending_kickoff_cnt, ctl_idx, + pending_flush_ret), + TP_STRUCT__entry( + __field( uint32_t, drm_id ) + __field( enum dpu_intf, intf_idx ) + __field( int, pending_kickoff_cnt ) + __field( int, ctl_idx ) + __field( u32, pending_flush_ret ) + ), + TP_fast_assign( + __entry->drm_id = drm_id; + __entry->intf_idx = intf_idx; + __entry->pending_kickoff_cnt = pending_kickoff_cnt; + __entry->ctl_idx = ctl_idx; + __entry->pending_flush_ret = pending_flush_ret; + ), + TP_printk("id=%u, intf_idx=%d, pending_kickoff_cnt=%d ctl_idx=%d " + "pending_flush_ret=%u", __entry->drm_id, + __entry->intf_idx, __entry->pending_kickoff_cnt, + __entry->ctl_idx, __entry->pending_flush_ret) +); + +DECLARE_EVENT_CLASS(dpu_enc_ktime_template, + TP_PROTO(uint32_t drm_id, ktime_t time), + TP_ARGS(drm_id, time), + TP_STRUCT__entry( + __field( uint32_t, drm_id ) + __field( ktime_t, time ) + ), + TP_fast_assign( + __entry->drm_id = drm_id; + __entry->time = time; + ), + TP_printk("id=%u, time=%lld", __entry->drm_id, + ktime_to_ms(__entry->time)) +); +DEFINE_EVENT(dpu_enc_ktime_template, dpu_enc_vsync_event_work, + TP_PROTO(uint32_t drm_id, ktime_t time), + TP_ARGS(drm_id, time) +); +DEFINE_EVENT(dpu_enc_ktime_template, dpu_enc_early_kickoff, + TP_PROTO(uint32_t drm_id, ktime_t time), + TP_ARGS(drm_id, time) +); + +DECLARE_EVENT_CLASS(dpu_id_event_template, + TP_PROTO(uint32_t drm_id, u32 event), + TP_ARGS(drm_id, event), + TP_STRUCT__entry( + __field( uint32_t, drm_id ) + __field( u32, event ) + ), + TP_fast_assign( + __entry->drm_id = drm_id; + __entry->event = event; + ), + TP_printk("id=%u, event=%u", __entry->drm_id, __entry->event) +); +DEFINE_EVENT(dpu_id_event_template, dpu_enc_frame_done_timeout, + TP_PROTO(uint32_t drm_id, u32 event), + TP_ARGS(drm_id, event) +); +DEFINE_EVENT(dpu_id_event_template, dpu_crtc_frame_event_cb, + TP_PROTO(uint32_t drm_id, u32 event), + TP_ARGS(drm_id, event) +); +DEFINE_EVENT(dpu_id_event_template, dpu_crtc_handle_power_event, + TP_PROTO(uint32_t drm_id, u32 event), + TP_ARGS(drm_id, event) +); +DEFINE_EVENT(dpu_id_event_template, dpu_crtc_frame_event_done, + TP_PROTO(uint32_t drm_id, u32 event), + TP_ARGS(drm_id, event) +); +DEFINE_EVENT(dpu_id_event_template, dpu_crtc_frame_event_more_pending, + TP_PROTO(uint32_t drm_id, u32 event), + TP_ARGS(drm_id, event) +); + +TRACE_EVENT(dpu_enc_wait_event_timeout, + TP_PROTO(uint32_t drm_id, int32_t hw_id, int rc, s64 time, + s64 expected_time, int atomic_cnt), + TP_ARGS(drm_id, hw_id, rc, time, expected_time, atomic_cnt), + TP_STRUCT__entry( + __field( uint32_t, drm_id ) + __field( int32_t, hw_id ) + __field( int, rc ) + __field( s64, time ) + __field( s64, expected_time ) + __field( int, atomic_cnt ) + ), + TP_fast_assign( + __entry->drm_id = drm_id; + __entry->hw_id = hw_id; + __entry->rc = rc; + __entry->time = time; + __entry->expected_time = expected_time; + __entry->atomic_cnt = atomic_cnt; + ), + TP_printk("id=%u, hw_id=%d, rc=%d, time=%lld, expected=%lld cnt=%d", + __entry->drm_id, __entry->hw_id, __entry->rc, __entry->time, + __entry->expected_time, __entry->atomic_cnt) +); + +TRACE_EVENT(dpu_enc_phys_cmd_irq_ctrl, + TP_PROTO(uint32_t drm_id, enum dpu_pingpong pp, bool enable, + int refcnt), + TP_ARGS(drm_id, pp, enable, refcnt), + TP_STRUCT__entry( + __field( uint32_t, drm_id ) + __field( enum dpu_pingpong, pp ) + __field( bool, enable ) + __field( int, refcnt ) + ), + TP_fast_assign( + __entry->drm_id = drm_id; + __entry->pp = pp; + __entry->enable = enable; + __entry->refcnt = refcnt; + ), + TP_printk("id=%u, pp=%d, enable=%s, refcnt=%d", __entry->drm_id, + __entry->pp, __entry->enable ? "true" : "false", + __entry->refcnt) +); + +TRACE_EVENT(dpu_enc_phys_cmd_pp_tx_done, + TP_PROTO(uint32_t drm_id, enum dpu_pingpong pp, int new_count, + u32 event), + TP_ARGS(drm_id, pp, new_count, event), + TP_STRUCT__entry( + __field( uint32_t, drm_id ) + __field( enum dpu_pingpong, pp ) + __field( int, new_count ) + __field( u32, event ) + ), + TP_fast_assign( + __entry->drm_id = drm_id; + __entry->pp = pp; + __entry->new_count = new_count; + __entry->event = event; + ), + TP_printk("id=%u, pp=%d, new_count=%d, event=%u", __entry->drm_id, + __entry->pp, __entry->new_count, __entry->event) +); + +TRACE_EVENT(dpu_enc_phys_cmd_pdone_timeout, + TP_PROTO(uint32_t drm_id, enum dpu_pingpong pp, int timeout_count, + int kickoff_count, u32 event), + TP_ARGS(drm_id, pp, timeout_count, kickoff_count, event), + TP_STRUCT__entry( + __field( uint32_t, drm_id ) + __field( enum dpu_pingpong, pp ) + __field( int, timeout_count ) + __field( int, kickoff_count ) + __field( u32, event ) + ), + TP_fast_assign( + __entry->drm_id = drm_id; + __entry->pp = pp; + __entry->timeout_count = timeout_count; + __entry->kickoff_count = kickoff_count; + __entry->event = event; + ), + TP_printk("id=%u, pp=%d, timeout_count=%d, kickoff_count=%d, event=%u", + __entry->drm_id, __entry->pp, __entry->timeout_count, + __entry->kickoff_count, __entry->event) +); + +TRACE_EVENT(dpu_enc_phys_vid_post_kickoff, + TP_PROTO(uint32_t drm_id, enum dpu_intf intf_idx), + TP_ARGS(drm_id, intf_idx), + TP_STRUCT__entry( + __field( uint32_t, drm_id ) + __field( enum dpu_intf, intf_idx ) + ), + TP_fast_assign( + __entry->drm_id = drm_id; + __entry->intf_idx = intf_idx; + ), + TP_printk("id=%u, intf_idx=%d", __entry->drm_id, __entry->intf_idx) +); + +TRACE_EVENT(dpu_enc_phys_vid_irq_ctrl, + TP_PROTO(uint32_t drm_id, enum dpu_intf intf_idx, bool enable, + int refcnt), + TP_ARGS(drm_id, intf_idx, enable, refcnt), + TP_STRUCT__entry( + __field( uint32_t, drm_id ) + __field( enum dpu_intf, intf_idx ) + __field( bool, enable ) + __field( int, refcnt ) + ), + TP_fast_assign( + __entry->drm_id = drm_id; + __entry->intf_idx = intf_idx; + __entry->enable = enable; + __entry->refcnt = refcnt; + ), + TP_printk("id=%u, intf_idx=%d enable=%s refcnt=%d", __entry->drm_id, + __entry->intf_idx, __entry->enable ? "true" : "false", + __entry->drm_id) +); + +TRACE_EVENT(dpu_crtc_setup_mixer, + TP_PROTO(uint32_t crtc_id, uint32_t plane_id, + struct drm_plane_state *state, struct dpu_plane_state *pstate, + uint32_t stage_idx, enum dpu_sspp sspp, uint32_t pixel_format, + uint64_t modifier), + TP_ARGS(crtc_id, plane_id, state, pstate, stage_idx, sspp, + pixel_format, modifier), + TP_STRUCT__entry( + __field( uint32_t, crtc_id ) + __field( uint32_t, plane_id ) + __field( struct drm_plane_state*,state ) + __field( struct dpu_plane_state*,pstate ) + __field( uint32_t, stage_idx ) + __field( enum dpu_sspp, sspp ) + __field( uint32_t, pixel_format ) + __field( uint64_t, modifier ) + ), + TP_fast_assign( + __entry->crtc_id = crtc_id; + __entry->plane_id = plane_id; + __entry->state = state; + __entry->pstate = pstate; + __entry->stage_idx = stage_idx; + __entry->sspp = sspp; + __entry->pixel_format = pixel_format; + __entry->modifier = modifier; + ), + TP_printk("crtc_id:%u plane_id:%u fb_id:%u src:{%ux%u+%ux%u} " + "dst:{%ux%u+%ux%u} stage_idx:%u stage:%d, sspp:%d " + "multirect_index:%d multirect_mode:%u pix_format:%u " + "modifier:%llu", + __entry->crtc_id, __entry->plane_id, + __entry->state->fb ? __entry->state->fb->base.id : -1, + __entry->state->src_w >> 16, __entry->state->src_h >> 16, + __entry->state->src_x >> 16, __entry->state->src_y >> 16, + __entry->state->crtc_w, __entry->state->crtc_h, + __entry->state->crtc_x, __entry->state->crtc_y, + __entry->stage_idx, __entry->pstate->stage, __entry->sspp, + __entry->pstate->multirect_index, + __entry->pstate->multirect_mode, __entry->pixel_format, + __entry->modifier) +); + +TRACE_EVENT(dpu_crtc_setup_lm_bounds, + TP_PROTO(uint32_t drm_id, int mixer, struct drm_rect *bounds), + TP_ARGS(drm_id, mixer, bounds), + TP_STRUCT__entry( + __field( uint32_t, drm_id ) + __field( int, mixer ) + __field( struct drm_rect *, bounds ) + ), + TP_fast_assign( + __entry->drm_id = drm_id; + __entry->mixer = mixer; + __entry->bounds = bounds; + ), + TP_printk("id:%u mixer:%d bounds:" DRM_RECT_FMT, __entry->drm_id, + __entry->mixer, DRM_RECT_ARG(__entry->bounds)) +); + +TRACE_EVENT(dpu_crtc_vblank_enable, + TP_PROTO(uint32_t drm_id, uint32_t enc_id, bool enable, + struct dpu_crtc *crtc), + TP_ARGS(drm_id, enc_id, enable, crtc), + TP_STRUCT__entry( + __field( uint32_t, drm_id ) + __field( uint32_t, enc_id ) + __field( bool, enable ) + __field( struct dpu_crtc *, crtc ) + ), + TP_fast_assign( + __entry->drm_id = drm_id; + __entry->enc_id = enc_id; + __entry->enable = enable; + __entry->crtc = crtc; + ), + TP_printk("id:%u encoder:%u enable:%s state{enabled:%s suspend:%s " + "vblank_req:%s}", + __entry->drm_id, __entry->enc_id, + __entry->enable ? "true" : "false", + __entry->crtc->enabled ? "true" : "false", + __entry->crtc->suspend ? "true" : "false", + __entry->crtc->vblank_requested ? "true" : "false") +); + +DECLARE_EVENT_CLASS(dpu_crtc_enable_template, + TP_PROTO(uint32_t drm_id, bool enable, struct dpu_crtc *crtc), + TP_ARGS(drm_id, enable, crtc), + TP_STRUCT__entry( + __field( uint32_t, drm_id ) + __field( bool, enable ) + __field( struct dpu_crtc *, crtc ) + ), + TP_fast_assign( + __entry->drm_id = drm_id; + __entry->enable = enable; + __entry->crtc = crtc; + ), + TP_printk("id:%u enable:%s state{enabled:%s suspend:%s vblank_req:%s}", + __entry->drm_id, __entry->enable ? "true" : "false", + __entry->crtc->enabled ? "true" : "false", + __entry->crtc->suspend ? "true" : "false", + __entry->crtc->vblank_requested ? "true" : "false") +); +DEFINE_EVENT(dpu_crtc_enable_template, dpu_crtc_set_suspend, + TP_PROTO(uint32_t drm_id, bool enable, struct dpu_crtc *crtc), + TP_ARGS(drm_id, enable, crtc) +); +DEFINE_EVENT(dpu_crtc_enable_template, dpu_crtc_enable, + TP_PROTO(uint32_t drm_id, bool enable, struct dpu_crtc *crtc), + TP_ARGS(drm_id, enable, crtc) +); +DEFINE_EVENT(dpu_crtc_enable_template, dpu_crtc_disable, + TP_PROTO(uint32_t drm_id, bool enable, struct dpu_crtc *crtc), + TP_ARGS(drm_id, enable, crtc) +); +DEFINE_EVENT(dpu_crtc_enable_template, dpu_crtc_vblank, + TP_PROTO(uint32_t drm_id, bool enable, struct dpu_crtc *crtc), + TP_ARGS(drm_id, enable, crtc) +); + +TRACE_EVENT(dpu_crtc_disable_frame_pending, + TP_PROTO(uint32_t drm_id, int frame_pending), + TP_ARGS(drm_id, frame_pending), + TP_STRUCT__entry( + __field( uint32_t, drm_id ) + __field( int, frame_pending ) + ), + TP_fast_assign( + __entry->drm_id = drm_id; + __entry->frame_pending = frame_pending; + ), + TP_printk("id:%u frame_pending:%d", __entry->drm_id, + __entry->frame_pending) +); + +TRACE_EVENT(dpu_plane_set_scanout, + TP_PROTO(enum dpu_sspp index, struct dpu_hw_fmt_layout *layout, + enum dpu_sspp_multirect_index multirect_index), + TP_ARGS(index, layout, multirect_index), + TP_STRUCT__entry( + __field( enum dpu_sspp, index ) + __field( struct dpu_hw_fmt_layout*, layout ) + __field( enum dpu_sspp_multirect_index, multirect_index) + ), + TP_fast_assign( + __entry->index = index; + __entry->layout = layout; + __entry->multirect_index = multirect_index; + ), + TP_printk("index:%d layout:{%ux%u @ [%u/%u, %u/%u, %u/%u, %u/%u]} " + "multirect_index:%d", __entry->index, __entry->layout->width, + __entry->layout->height, __entry->layout->plane_addr[0], + __entry->layout->plane_size[0], + __entry->layout->plane_addr[1], + __entry->layout->plane_size[1], + __entry->layout->plane_addr[2], + __entry->layout->plane_size[2], + __entry->layout->plane_addr[3], + __entry->layout->plane_size[3], __entry->multirect_index) +); + +TRACE_EVENT(dpu_plane_disable, + TP_PROTO(uint32_t drm_id, bool is_virtual, uint32_t multirect_mode), + TP_ARGS(drm_id, is_virtual, multirect_mode), + TP_STRUCT__entry( + __field( uint32_t, drm_id ) + __field( bool, is_virtual ) + __field( uint32_t, multirect_mode ) + ), + TP_fast_assign( + __entry->drm_id = drm_id; + __entry->is_virtual = is_virtual; + __entry->multirect_mode = multirect_mode; + ), + TP_printk("id:%u is_virtual:%s multirect_mode:%u", __entry->drm_id, + __entry->is_virtual ? "true" : "false", + __entry->multirect_mode) +); + +DECLARE_EVENT_CLASS(dpu_rm_iter_template, + TP_PROTO(uint32_t id, enum dpu_hw_blk_type type, uint32_t enc_id), + TP_ARGS(id, type, enc_id), + TP_STRUCT__entry( + __field( uint32_t, id ) + __field( enum dpu_hw_blk_type, type ) + __field( uint32_t, enc_id ) + ), + TP_fast_assign( + __entry->id = id; + __entry->type = type; + __entry->enc_id = enc_id; + ), + TP_printk("id:%d type:%d enc_id:%u", __entry->id, __entry->type, + __entry->enc_id) +); +DEFINE_EVENT(dpu_rm_iter_template, dpu_rm_reserve_cdm, + TP_PROTO(uint32_t id, enum dpu_hw_blk_type type, uint32_t enc_id), + TP_ARGS(id, type, enc_id) +); +DEFINE_EVENT(dpu_rm_iter_template, dpu_rm_reserve_intf, + TP_PROTO(uint32_t id, enum dpu_hw_blk_type type, uint32_t enc_id), + TP_ARGS(id, type, enc_id) +); +DEFINE_EVENT(dpu_rm_iter_template, dpu_rm_reserve_ctls, + TP_PROTO(uint32_t id, enum dpu_hw_blk_type type, uint32_t enc_id), + TP_ARGS(id, type, enc_id) +); + +TRACE_EVENT(dpu_rm_reserve_lms, + TP_PROTO(uint32_t id, enum dpu_hw_blk_type type, uint32_t enc_id, + uint32_t pp_id), + TP_ARGS(id, type, enc_id, pp_id), + TP_STRUCT__entry( + __field( uint32_t, id ) + __field( enum dpu_hw_blk_type, type ) + __field( uint32_t, enc_id ) + __field( uint32_t, pp_id ) + ), + TP_fast_assign( + __entry->id = id; + __entry->type = type; + __entry->enc_id = enc_id; + __entry->pp_id = pp_id; + ), + TP_printk("id:%d type:%d enc_id:%u pp_id:%u", __entry->id, + __entry->type, __entry->enc_id, __entry->pp_id) +); + +TRACE_EVENT(dpu_vbif_wait_xin_halt_fail, + TP_PROTO(enum dpu_vbif index, u32 xin_id), + TP_ARGS(index, xin_id), + TP_STRUCT__entry( + __field( enum dpu_vbif, index ) + __field( u32, xin_id ) + ), + TP_fast_assign( + __entry->index = index; + __entry->xin_id = xin_id; + ), + TP_printk("index:%d xin_id:%u", __entry->index, __entry->xin_id) +); + +TRACE_EVENT(dpu_pp_connect_ext_te, + TP_PROTO(enum dpu_pingpong pp, u32 cfg), + TP_ARGS(pp, cfg), + TP_STRUCT__entry( + __field( enum dpu_pingpong, pp ) + __field( u32, cfg ) + ), + TP_fast_assign( + __entry->pp = pp; + __entry->cfg = cfg; + ), + TP_printk("pp:%d cfg:%u", __entry->pp, __entry->cfg) +); + +DECLARE_EVENT_CLASS(dpu_core_irq_idx_cnt_template, + TP_PROTO(int irq_idx, int enable_count), + TP_ARGS(irq_idx, enable_count), + TP_STRUCT__entry( + __field( int, irq_idx ) + __field( int, enable_count ) + ), + TP_fast_assign( + __entry->irq_idx = irq_idx; + __entry->enable_count = enable_count; + ), + TP_printk("irq_idx:%d enable_count:%u", __entry->irq_idx, + __entry->enable_count) +); +DEFINE_EVENT(dpu_core_irq_idx_cnt_template, dpu_core_irq_enable_idx, + TP_PROTO(int irq_idx, int enable_count), + TP_ARGS(irq_idx, enable_count) +); +DEFINE_EVENT(dpu_core_irq_idx_cnt_template, dpu_core_irq_disable_idx, + TP_PROTO(int irq_idx, int enable_count), + TP_ARGS(irq_idx, enable_count) +); + +DECLARE_EVENT_CLASS(dpu_core_irq_callback_template, + TP_PROTO(int irq_idx, struct dpu_irq_callback *callback), + TP_ARGS(irq_idx, callback), + TP_STRUCT__entry( + __field( int, irq_idx ) + __field( struct dpu_irq_callback *, callback) + ), + TP_fast_assign( + __entry->irq_idx = irq_idx; + __entry->callback = callback; + ), + TP_printk("irq_idx:%d callback:%pK", __entry->irq_idx, + __entry->callback) +); +DEFINE_EVENT(dpu_core_irq_callback_template, dpu_core_irq_register_callback, + TP_PROTO(int irq_idx, struct dpu_irq_callback *callback), + TP_ARGS(irq_idx, callback) +); +DEFINE_EVENT(dpu_core_irq_callback_template, dpu_core_irq_unregister_callback, + TP_PROTO(int irq_idx, struct dpu_irq_callback *callback), + TP_ARGS(irq_idx, callback) +); + +TRACE_EVENT(dpu_core_perf_update_clk, + TP_PROTO(struct drm_device *dev, bool stop_req, u64 clk_rate), + TP_ARGS(dev, stop_req, clk_rate), + TP_STRUCT__entry( + __field( struct drm_device *, dev ) + __field( bool, stop_req ) + __field( u64, clk_rate ) + ), + TP_fast_assign( + __entry->dev = dev; + __entry->stop_req = stop_req; + __entry->clk_rate = clk_rate; + ), + TP_printk("dev:%s stop_req:%s clk_rate:%llu", __entry->dev->unique, + __entry->stop_req ? "true" : "false", __entry->clk_rate) +); + +#define DPU_ATRACE_END(name) trace_tracing_mark_write(current->tgid, name, 0) +#define DPU_ATRACE_BEGIN(name) trace_tracing_mark_write(current->tgid, name, 1) +#define DPU_ATRACE_FUNC() DPU_ATRACE_BEGIN(__func__) + +#define DPU_ATRACE_INT(name, value) \ + trace_dpu_trace_counter(current->tgid, name, value) + +#endif /* _DPU_TRACE_H_ */ + +/* This part must be outside protection */ +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#include <trace/define_trace.h> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.c new file mode 100644 index 0000000000000..2955282922964 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.c @@ -0,0 +1,384 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ + +#include <linux/debugfs.h> + +#include "dpu_vbif.h" +#include "dpu_hw_vbif.h" +#include "dpu_trace.h" + +/** + * _dpu_vbif_wait_for_xin_halt - wait for the xin to halt + * @vbif: Pointer to hardware vbif driver + * @xin_id: Client interface identifier + * @return: 0 if success; error code otherwise + */ +static int _dpu_vbif_wait_for_xin_halt(struct dpu_hw_vbif *vbif, u32 xin_id) +{ + ktime_t timeout; + bool status; + int rc; + + if (!vbif || !vbif->cap || !vbif->ops.get_halt_ctrl) { + DPU_ERROR("invalid arguments vbif %d\n", vbif != 0); + return -EINVAL; + } + + timeout = ktime_add_us(ktime_get(), vbif->cap->xin_halt_timeout); + for (;;) { + status = vbif->ops.get_halt_ctrl(vbif, xin_id); + if (status) + break; + if (ktime_compare_safe(ktime_get(), timeout) > 0) { + status = vbif->ops.get_halt_ctrl(vbif, xin_id); + break; + } + usleep_range(501, 1000); + } + + if (!status) { + rc = -ETIMEDOUT; + DPU_ERROR("VBIF %d client %d not halting. TIMEDOUT.\n", + vbif->idx - VBIF_0, xin_id); + } else { + rc = 0; + DPU_DEBUG("VBIF %d client %d is halted\n", + vbif->idx - VBIF_0, xin_id); + } + + return rc; +} + +/** + * _dpu_vbif_apply_dynamic_ot_limit - determine OT based on usecase parameters + * @vbif: Pointer to hardware vbif driver + * @ot_lim: Pointer to OT limit to be modified + * @params: Pointer to usecase parameters + */ +static void _dpu_vbif_apply_dynamic_ot_limit(struct dpu_hw_vbif *vbif, + u32 *ot_lim, struct dpu_vbif_set_ot_params *params) +{ + u64 pps; + const struct dpu_vbif_dynamic_ot_tbl *tbl; + u32 i; + + if (!vbif || !(vbif->cap->features & BIT(DPU_VBIF_QOS_OTLIM))) + return; + + /* Dynamic OT setting done only for WFD */ + if (!params->is_wfd) + return; + + pps = params->frame_rate; + pps *= params->width; + pps *= params->height; + + tbl = params->rd ? &vbif->cap->dynamic_ot_rd_tbl : + &vbif->cap->dynamic_ot_wr_tbl; + + for (i = 0; i < tbl->count; i++) { + if (pps <= tbl->cfg[i].pps) { + *ot_lim = tbl->cfg[i].ot_limit; + break; + } + } + + DPU_DEBUG("vbif:%d xin:%d w:%d h:%d fps:%d pps:%llu ot:%u\n", + vbif->idx - VBIF_0, params->xin_id, + params->width, params->height, params->frame_rate, + pps, *ot_lim); +} + +/** + * _dpu_vbif_get_ot_limit - get OT based on usecase & configuration parameters + * @vbif: Pointer to hardware vbif driver + * @params: Pointer to usecase parameters + * @return: OT limit + */ +static u32 _dpu_vbif_get_ot_limit(struct dpu_hw_vbif *vbif, + struct dpu_vbif_set_ot_params *params) +{ + u32 ot_lim = 0; + u32 val; + + if (!vbif || !vbif->cap) { + DPU_ERROR("invalid arguments vbif %d\n", vbif != 0); + return -EINVAL; + } + + if (vbif->cap->default_ot_wr_limit && !params->rd) + ot_lim = vbif->cap->default_ot_wr_limit; + else if (vbif->cap->default_ot_rd_limit && params->rd) + ot_lim = vbif->cap->default_ot_rd_limit; + + /* + * If default ot is not set from dt/catalog, + * then do not configure it. + */ + if (ot_lim == 0) + goto exit; + + /* Modify the limits if the target and the use case requires it */ + _dpu_vbif_apply_dynamic_ot_limit(vbif, &ot_lim, params); + + if (vbif && vbif->ops.get_limit_conf) { + val = vbif->ops.get_limit_conf(vbif, + params->xin_id, params->rd); + if (val == ot_lim) + ot_lim = 0; + } + +exit: + DPU_DEBUG("vbif:%d xin:%d ot_lim:%d\n", + vbif->idx - VBIF_0, params->xin_id, ot_lim); + return ot_lim; +} + +/** + * dpu_vbif_set_ot_limit - set OT based on usecase & configuration parameters + * @vbif: Pointer to hardware vbif driver + * @params: Pointer to usecase parameters + * + * Note this function would block waiting for bus halt. + */ +void dpu_vbif_set_ot_limit(struct dpu_kms *dpu_kms, + struct dpu_vbif_set_ot_params *params) +{ + struct dpu_hw_vbif *vbif = NULL; + struct dpu_hw_mdp *mdp; + bool forced_on = false; + u32 ot_lim; + int ret, i; + + if (!dpu_kms) { + DPU_ERROR("invalid arguments\n"); + return; + } + mdp = dpu_kms->hw_mdp; + + for (i = 0; i < ARRAY_SIZE(dpu_kms->hw_vbif); i++) { + if (dpu_kms->hw_vbif[i] && + dpu_kms->hw_vbif[i]->idx == params->vbif_idx) + vbif = dpu_kms->hw_vbif[i]; + } + + if (!vbif || !mdp) { + DPU_DEBUG("invalid arguments vbif %d mdp %d\n", + vbif != 0, mdp != 0); + return; + } + + if (!mdp->ops.setup_clk_force_ctrl || + !vbif->ops.set_limit_conf || + !vbif->ops.set_halt_ctrl) + return; + + /* set write_gather_en for all write clients */ + if (vbif->ops.set_write_gather_en && !params->rd) + vbif->ops.set_write_gather_en(vbif, params->xin_id); + + ot_lim = _dpu_vbif_get_ot_limit(vbif, params) & 0xFF; + + if (ot_lim == 0) + goto exit; + + trace_dpu_perf_set_ot(params->num, params->xin_id, ot_lim, + params->vbif_idx); + + forced_on = mdp->ops.setup_clk_force_ctrl(mdp, params->clk_ctrl, true); + + vbif->ops.set_limit_conf(vbif, params->xin_id, params->rd, ot_lim); + + vbif->ops.set_halt_ctrl(vbif, params->xin_id, true); + + ret = _dpu_vbif_wait_for_xin_halt(vbif, params->xin_id); + if (ret) + trace_dpu_vbif_wait_xin_halt_fail(vbif->idx, params->xin_id); + + vbif->ops.set_halt_ctrl(vbif, params->xin_id, false); + + if (forced_on) + mdp->ops.setup_clk_force_ctrl(mdp, params->clk_ctrl, false); +exit: + return; +} + +void dpu_vbif_set_qos_remap(struct dpu_kms *dpu_kms, + struct dpu_vbif_set_qos_params *params) +{ + struct dpu_hw_vbif *vbif = NULL; + struct dpu_hw_mdp *mdp; + bool forced_on = false; + const struct dpu_vbif_qos_tbl *qos_tbl; + int i; + + if (!dpu_kms || !params || !dpu_kms->hw_mdp) { + DPU_ERROR("invalid arguments\n"); + return; + } + mdp = dpu_kms->hw_mdp; + + for (i = 0; i < ARRAY_SIZE(dpu_kms->hw_vbif); i++) { + if (dpu_kms->hw_vbif[i] && + dpu_kms->hw_vbif[i]->idx == params->vbif_idx) { + vbif = dpu_kms->hw_vbif[i]; + break; + } + } + + if (!vbif || !vbif->cap) { + DPU_ERROR("invalid vbif %d\n", params->vbif_idx); + return; + } + + if (!vbif->ops.set_qos_remap || !mdp->ops.setup_clk_force_ctrl) { + DPU_DEBUG("qos remap not supported\n"); + return; + } + + qos_tbl = params->is_rt ? &vbif->cap->qos_rt_tbl : + &vbif->cap->qos_nrt_tbl; + + if (!qos_tbl->npriority_lvl || !qos_tbl->priority_lvl) { + DPU_DEBUG("qos tbl not defined\n"); + return; + } + + forced_on = mdp->ops.setup_clk_force_ctrl(mdp, params->clk_ctrl, true); + + for (i = 0; i < qos_tbl->npriority_lvl; i++) { + DPU_DEBUG("vbif:%d xin:%d lvl:%d/%d\n", + params->vbif_idx, params->xin_id, i, + qos_tbl->priority_lvl[i]); + vbif->ops.set_qos_remap(vbif, params->xin_id, i, + qos_tbl->priority_lvl[i]); + } + + if (forced_on) + mdp->ops.setup_clk_force_ctrl(mdp, params->clk_ctrl, false); +} + +void dpu_vbif_clear_errors(struct dpu_kms *dpu_kms) +{ + struct dpu_hw_vbif *vbif; + u32 i, pnd, src; + + if (!dpu_kms) { + DPU_ERROR("invalid argument\n"); + return; + } + + for (i = 0; i < ARRAY_SIZE(dpu_kms->hw_vbif); i++) { + vbif = dpu_kms->hw_vbif[i]; + if (vbif && vbif->ops.clear_errors) { + vbif->ops.clear_errors(vbif, &pnd, &src); + if (pnd || src) { + DRM_DEBUG_KMS("VBIF %d: pnd 0x%X, src 0x%X\n", + vbif->idx - VBIF_0, pnd, src); + } + } + } +} + +void dpu_vbif_init_memtypes(struct dpu_kms *dpu_kms) +{ + struct dpu_hw_vbif *vbif; + int i, j; + + if (!dpu_kms) { + DPU_ERROR("invalid argument\n"); + return; + } + + for (i = 0; i < ARRAY_SIZE(dpu_kms->hw_vbif); i++) { + vbif = dpu_kms->hw_vbif[i]; + if (vbif && vbif->cap && vbif->ops.set_mem_type) { + for (j = 0; j < vbif->cap->memtype_count; j++) + vbif->ops.set_mem_type( + vbif, j, vbif->cap->memtype[j]); + } + } +} + +#ifdef CONFIG_DEBUG_FS +void dpu_debugfs_vbif_destroy(struct dpu_kms *dpu_kms) +{ + debugfs_remove_recursive(dpu_kms->debugfs_vbif); + dpu_kms->debugfs_vbif = NULL; +} + +int dpu_debugfs_vbif_init(struct dpu_kms *dpu_kms, struct dentry *debugfs_root) +{ + char vbif_name[32]; + struct dentry *debugfs_vbif; + int i, j; + + dpu_kms->debugfs_vbif = debugfs_create_dir("vbif", debugfs_root); + if (!dpu_kms->debugfs_vbif) { + DPU_ERROR("failed to create vbif debugfs\n"); + return -EINVAL; + } + + for (i = 0; i < dpu_kms->catalog->vbif_count; i++) { + struct dpu_vbif_cfg *vbif = &dpu_kms->catalog->vbif[i]; + + snprintf(vbif_name, sizeof(vbif_name), "%d", vbif->id); + + debugfs_vbif = debugfs_create_dir(vbif_name, + dpu_kms->debugfs_vbif); + + debugfs_create_u32("features", 0600, debugfs_vbif, + (u32 *)&vbif->features); + + debugfs_create_u32("xin_halt_timeout", 0400, debugfs_vbif, + (u32 *)&vbif->xin_halt_timeout); + + debugfs_create_u32("default_rd_ot_limit", 0400, debugfs_vbif, + (u32 *)&vbif->default_ot_rd_limit); + + debugfs_create_u32("default_wr_ot_limit", 0400, debugfs_vbif, + (u32 *)&vbif->default_ot_wr_limit); + + for (j = 0; j < vbif->dynamic_ot_rd_tbl.count; j++) { + struct dpu_vbif_dynamic_ot_cfg *cfg = + &vbif->dynamic_ot_rd_tbl.cfg[j]; + + snprintf(vbif_name, sizeof(vbif_name), + "dynamic_ot_rd_%d_pps", j); + debugfs_create_u64(vbif_name, 0400, debugfs_vbif, + (u64 *)&cfg->pps); + snprintf(vbif_name, sizeof(vbif_name), + "dynamic_ot_rd_%d_ot_limit", j); + debugfs_create_u32(vbif_name, 0400, debugfs_vbif, + (u32 *)&cfg->ot_limit); + } + + for (j = 0; j < vbif->dynamic_ot_wr_tbl.count; j++) { + struct dpu_vbif_dynamic_ot_cfg *cfg = + &vbif->dynamic_ot_wr_tbl.cfg[j]; + + snprintf(vbif_name, sizeof(vbif_name), + "dynamic_ot_wr_%d_pps", j); + debugfs_create_u64(vbif_name, 0400, debugfs_vbif, + (u64 *)&cfg->pps); + snprintf(vbif_name, sizeof(vbif_name), + "dynamic_ot_wr_%d_ot_limit", j); + debugfs_create_u32(vbif_name, 0400, debugfs_vbif, + (u32 *)&cfg->ot_limit); + } + } + + return 0; +} +#endif diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.h new file mode 100644 index 0000000000000..f17af52dbbd58 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.h @@ -0,0 +1,94 @@ +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef __DPU_VBIF_H__ +#define __DPU_VBIF_H__ + +#include "dpu_kms.h" + +struct dpu_vbif_set_ot_params { + u32 xin_id; + u32 num; + u32 width; + u32 height; + u32 frame_rate; + bool rd; + bool is_wfd; + u32 vbif_idx; + u32 clk_ctrl; +}; + +struct dpu_vbif_set_memtype_params { + u32 xin_id; + u32 vbif_idx; + u32 clk_ctrl; + bool is_cacheable; +}; + +/** + * struct dpu_vbif_set_qos_params - QoS remapper parameter + * @vbif_idx: vbif identifier + * @xin_id: client interface identifier + * @clk_ctrl: clock control identifier of the xin + * @num: pipe identifier (debug only) + * @is_rt: true if pipe is used in real-time use case + */ +struct dpu_vbif_set_qos_params { + u32 vbif_idx; + u32 xin_id; + u32 clk_ctrl; + u32 num; + bool is_rt; +}; + +/** + * dpu_vbif_set_ot_limit - set OT limit for vbif client + * @dpu_kms: DPU handler + * @params: Pointer to OT configuration parameters + */ +void dpu_vbif_set_ot_limit(struct dpu_kms *dpu_kms, + struct dpu_vbif_set_ot_params *params); + +/** + * dpu_vbif_set_qos_remap - set QoS priority level remap + * @dpu_kms: DPU handler + * @params: Pointer to QoS configuration parameters + */ +void dpu_vbif_set_qos_remap(struct dpu_kms *dpu_kms, + struct dpu_vbif_set_qos_params *params); + +/** + * dpu_vbif_clear_errors - clear any vbif errors + * @dpu_kms: DPU handler + */ +void dpu_vbif_clear_errors(struct dpu_kms *dpu_kms); + +/** + * dpu_vbif_init_memtypes - initialize xin memory types for vbif + * @dpu_kms: DPU handler + */ +void dpu_vbif_init_memtypes(struct dpu_kms *dpu_kms); + +#ifdef CONFIG_DEBUG_FS +int dpu_debugfs_vbif_init(struct dpu_kms *dpu_kms, struct dentry *debugfs_root); +void dpu_debugfs_vbif_destroy(struct dpu_kms *dpu_kms); +#else +static inline int dpu_debugfs_vbif_init(struct dpu_kms *dpu_kms, + struct dentry *debugfs_root) +{ + return 0; +} +static inline void dpu_debugfs_vbif_destroy(struct dpu_kms *dpu_kms) +{ +} +#endif +#endif /* __DPU_VBIF_H__ */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/msm_media_info.h b/drivers/gpu/drm/msm/disp/dpu1/msm_media_info.h new file mode 100644 index 0000000000000..4f12e5c534c8c --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/msm_media_info.h @@ -0,0 +1,1376 @@ +#ifndef __MEDIA_INFO_H__ +#define __MEDIA_INFO_H__ + +#ifndef MSM_MEDIA_ALIGN +#define MSM_MEDIA_ALIGN(__sz, __align) (((__align) & ((__align) - 1)) ?\ + ((((__sz) + (__align) - 1) / (__align)) * (__align)) :\ + (((__sz) + (__align) - 1) & (~((__align) - 1)))) +#endif + +#ifndef MSM_MEDIA_ROUNDUP +#define MSM_MEDIA_ROUNDUP(__sz, __r) (((__sz) + ((__r) - 1)) / (__r)) +#endif + +#ifndef MSM_MEDIA_MAX +#define MSM_MEDIA_MAX(__a, __b) ((__a) > (__b)?(__a):(__b)) +#endif + +enum color_fmts { + /* Venus NV12: + * YUV 4:2:0 image with a plane of 8 bit Y samples followed + * by an interleaved U/V plane containing 8 bit 2x2 subsampled + * colour difference samples. + * + * <-------- Y/UV_Stride --------> + * <------- Width -------> + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . ^ ^ + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . Height | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | Y_Scanlines + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . V | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . V + * U V U V U V U V U V U V . . . . ^ + * U V U V U V U V U V U V . . . . | + * U V U V U V U V U V U V . . . . | + * U V U V U V U V U V U V . . . . UV_Scanlines + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . V + * . . . . . . . . . . . . . . . . --> Buffer size alignment + * + * Y_Stride : Width aligned to 128 + * UV_Stride : Width aligned to 128 + * Y_Scanlines: Height aligned to 32 + * UV_Scanlines: Height/2 aligned to 16 + * Extradata: Arbitrary (software-imposed) padding + * Total size = align((Y_Stride * Y_Scanlines + * + UV_Stride * UV_Scanlines + * + max(Extradata, Y_Stride * 8), 4096) + */ + COLOR_FMT_NV12, + + /* Venus NV21: + * YUV 4:2:0 image with a plane of 8 bit Y samples followed + * by an interleaved V/U plane containing 8 bit 2x2 subsampled + * colour difference samples. + * + * <-------- Y/UV_Stride --------> + * <------- Width -------> + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . ^ ^ + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . Height | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | Y_Scanlines + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . V | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . V + * V U V U V U V U V U V U . . . . ^ + * V U V U V U V U V U V U . . . . | + * V U V U V U V U V U V U . . . . | + * V U V U V U V U V U V U . . . . UV_Scanlines + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . V + * . . . . . . . . . . . . . . . . --> Padding & Buffer size alignment + * + * Y_Stride : Width aligned to 128 + * UV_Stride : Width aligned to 128 + * Y_Scanlines: Height aligned to 32 + * UV_Scanlines: Height/2 aligned to 16 + * Extradata: Arbitrary (software-imposed) padding + * Total size = align((Y_Stride * Y_Scanlines + * + UV_Stride * UV_Scanlines + * + max(Extradata, Y_Stride * 8), 4096) + */ + COLOR_FMT_NV21, + /* Venus NV12_MVTB: + * Two YUV 4:2:0 images/views one after the other + * in a top-bottom layout, same as NV12 + * with a plane of 8 bit Y samples followed + * by an interleaved U/V plane containing 8 bit 2x2 subsampled + * colour difference samples. + * + * + * <-------- Y/UV_Stride --------> + * <------- Width -------> + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . ^ ^ ^ + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . Height | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | Y_Scanlines | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . V | | + * . . . . . . . . . . . . . . . . | View_1 + * . . . . . . . . . . . . . . . . | | + * . . . . . . . . . . . . . . . . | | + * . . . . . . . . . . . . . . . . V | + * U V U V U V U V U V U V . . . . ^ | + * U V U V U V U V U V U V . . . . | | + * U V U V U V U V U V U V . . . . | | + * U V U V U V U V U V U V . . . . UV_Scanlines | + * . . . . . . . . . . . . . . . . | | + * . . . . . . . . . . . . . . . . V V + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . ^ ^ ^ + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . Height | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | Y_Scanlines | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . V | | + * . . . . . . . . . . . . . . . . | View_2 + * . . . . . . . . . . . . . . . . | | + * . . . . . . . . . . . . . . . . | | + * . . . . . . . . . . . . . . . . V | + * U V U V U V U V U V U V . . . . ^ | + * U V U V U V U V U V U V . . . . | | + * U V U V U V U V U V U V . . . . | | + * U V U V U V U V U V U V . . . . UV_Scanlines | + * . . . . . . . . . . . . . . . . | | + * . . . . . . . . . . . . . . . . V V + * . . . . . . . . . . . . . . . . --> Buffer size alignment + * + * Y_Stride : Width aligned to 128 + * UV_Stride : Width aligned to 128 + * Y_Scanlines: Height aligned to 32 + * UV_Scanlines: Height/2 aligned to 16 + * View_1 begin at: 0 (zero) + * View_2 begin at: Y_Stride * Y_Scanlines + UV_Stride * UV_Scanlines + * Extradata: Arbitrary (software-imposed) padding + * Total size = align((2*(Y_Stride * Y_Scanlines) + * + 2*(UV_Stride * UV_Scanlines) + Extradata), 4096) + */ + COLOR_FMT_NV12_MVTB, + /* + * The buffer can be of 2 types: + * (1) Venus NV12 UBWC Progressive + * (2) Venus NV12 UBWC Interlaced + * + * (1) Venus NV12 UBWC Progressive Buffer Format: + * Compressed Macro-tile format for NV12. + * Contains 4 planes in the following order - + * (A) Y_Meta_Plane + * (B) Y_UBWC_Plane + * (C) UV_Meta_Plane + * (D) UV_UBWC_Plane + * + * Y_Meta_Plane consists of meta information to decode compressed + * tile data in Y_UBWC_Plane. + * Y_UBWC_Plane consists of Y data in compressed macro-tile format. + * UBWC decoder block will use the Y_Meta_Plane data together with + * Y_UBWC_Plane data to produce loss-less uncompressed 8 bit Y samples. + * + * UV_Meta_Plane consists of meta information to decode compressed + * tile data in UV_UBWC_Plane. + * UV_UBWC_Plane consists of UV data in compressed macro-tile format. + * UBWC decoder block will use UV_Meta_Plane data together with + * UV_UBWC_Plane data to produce loss-less uncompressed 8 bit 2x2 + * subsampled color difference samples. + * + * Each tile in Y_UBWC_Plane/UV_UBWC_Plane is independently decodable + * and randomly accessible. There is no dependency between tiles. + * + * <----- Y_Meta_Stride ----> + * <-------- Width ------> + * M M M M M M M M M M M M . . ^ ^ + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . Height | + * M M M M M M M M M M M M . . | Meta_Y_Scanlines + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . V | + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * . . . . . . . . . . . . . . V + * <--Compressed tile Y Stride---> + * <------- Width -------> + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . ^ ^ + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . Height | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | Macro_tile_Y_Scanlines + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . V | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * . . . . . . . . . . . . . . . . V + * <----- UV_Meta_Stride ----> + * M M M M M M M M M M M M . . ^ + * M M M M M M M M M M M M . . | + * M M M M M M M M M M M M . . | + * M M M M M M M M M M M M . . M_UV_Scanlines + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . V + * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * <--Compressed tile UV Stride---> + * U* V* U* V* U* V* U* V* . . . . ^ + * U* V* U* V* U* V* U* V* . . . . | + * U* V* U* V* U* V* U* V* . . . . | + * U* V* U* V* U* V* U* V* . . . . UV_Scanlines + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . V + * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * + * Y_Stride = align(Width, 128) + * UV_Stride = align(Width, 128) + * Y_Scanlines = align(Height, 32) + * UV_Scanlines = align(Height/2, 16) + * Y_UBWC_Plane_size = align(Y_Stride * Y_Scanlines, 4096) + * UV_UBWC_Plane_size = align(UV_Stride * UV_Scanlines, 4096) + * Y_Meta_Stride = align(roundup(Width, Y_TileWidth), 64) + * Y_Meta_Scanlines = align(roundup(Height, Y_TileHeight), 16) + * Y_Meta_Plane_size = align(Y_Meta_Stride * Y_Meta_Scanlines, 4096) + * UV_Meta_Stride = align(roundup(Width, UV_TileWidth), 64) + * UV_Meta_Scanlines = align(roundup(Height, UV_TileHeight), 16) + * UV_Meta_Plane_size = align(UV_Meta_Stride * UV_Meta_Scanlines, 4096) + * Extradata = 8k + * + * Total size = align( Y_UBWC_Plane_size + UV_UBWC_Plane_size + + * Y_Meta_Plane_size + UV_Meta_Plane_size + * + max(Extradata, Y_Stride * 48), 4096) + * + * + * (2) Venus NV12 UBWC Interlaced Buffer Format: + * Compressed Macro-tile format for NV12 interlaced. + * Contains 8 planes in the following order - + * (A) Y_Meta_Top_Field_Plane + * (B) Y_UBWC_Top_Field_Plane + * (C) UV_Meta_Top_Field_Plane + * (D) UV_UBWC_Top_Field_Plane + * (E) Y_Meta_Bottom_Field_Plane + * (F) Y_UBWC_Bottom_Field_Plane + * (G) UV_Meta_Bottom_Field_Plane + * (H) UV_UBWC_Bottom_Field_Plane + * Y_Meta_Top_Field_Plane consists of meta information to decode + * compressed tile data for Y_UBWC_Top_Field_Plane. + * Y_UBWC_Top_Field_Plane consists of Y data in compressed macro-tile + * format for top field of an interlaced frame. + * UBWC decoder block will use the Y_Meta_Top_Field_Plane data together + * with Y_UBWC_Top_Field_Plane data to produce loss-less uncompressed + * 8 bit Y samples for top field of an interlaced frame. + * + * UV_Meta_Top_Field_Plane consists of meta information to decode + * compressed tile data in UV_UBWC_Top_Field_Plane. + * UV_UBWC_Top_Field_Plane consists of UV data in compressed macro-tile + * format for top field of an interlaced frame. + * UBWC decoder block will use UV_Meta_Top_Field_Plane data together + * with UV_UBWC_Top_Field_Plane data to produce loss-less uncompressed + * 8 bit subsampled color difference samples for top field of an + * interlaced frame. + * + * Each tile in Y_UBWC_Top_Field_Plane/UV_UBWC_Top_Field_Plane is + * independently decodable and randomly accessible. There is no + * dependency between tiles. + * + * Y_Meta_Bottom_Field_Plane consists of meta information to decode + * compressed tile data for Y_UBWC_Bottom_Field_Plane. + * Y_UBWC_Bottom_Field_Plane consists of Y data in compressed macro-tile + * format for bottom field of an interlaced frame. + * UBWC decoder block will use the Y_Meta_Bottom_Field_Plane data + * together with Y_UBWC_Bottom_Field_Plane data to produce loss-less + * uncompressed 8 bit Y samples for bottom field of an interlaced frame. + * + * UV_Meta_Bottom_Field_Plane consists of meta information to decode + * compressed tile data in UV_UBWC_Bottom_Field_Plane. + * UV_UBWC_Bottom_Field_Plane consists of UV data in compressed + * macro-tile format for bottom field of an interlaced frame. + * UBWC decoder block will use UV_Meta_Bottom_Field_Plane data together + * with UV_UBWC_Bottom_Field_Plane data to produce loss-less + * uncompressed 8 bit subsampled color difference samples for bottom + * field of an interlaced frame. + * + * Each tile in Y_UBWC_Bottom_Field_Plane/UV_UBWC_Bottom_Field_Plane is + * independently decodable and randomly accessible. There is no + * dependency between tiles. + * + * <-----Y_TF_Meta_Stride----> + * <-------- Width ------> + * M M M M M M M M M M M M . . ^ ^ + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . Half_height | + * M M M M M M M M M M M M . . | Meta_Y_TF_Scanlines + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . V | + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * . . . . . . . . . . . . . . V + * <-Compressed tile Y_TF Stride-> + * <------- Width -------> + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . ^ ^ + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . Half_height | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | Macro_tile_Y_TF_Scanlines + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . V | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * . . . . . . . . . . . . . . . . V + * <----UV_TF_Meta_Stride----> + * M M M M M M M M M M M M . . ^ + * M M M M M M M M M M M M . . | + * M M M M M M M M M M M M . . | + * M M M M M M M M M M M M . . M_UV_TF_Scanlines + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . V + * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * <-Compressed tile UV_TF Stride-> + * U* V* U* V* U* V* U* V* . . . . ^ + * U* V* U* V* U* V* U* V* . . . . | + * U* V* U* V* U* V* U* V* . . . . | + * U* V* U* V* U* V* U* V* . . . . UV_TF_Scanlines + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . V + * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * <-----Y_BF_Meta_Stride----> + * <-------- Width ------> + * M M M M M M M M M M M M . . ^ ^ + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . Half_height | + * M M M M M M M M M M M M . . | Meta_Y_BF_Scanlines + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . V | + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * . . . . . . . . . . . . . . V + * <-Compressed tile Y_BF Stride-> + * <------- Width -------> + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . ^ ^ + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . Half_height | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | Macro_tile_Y_BF_Scanlines + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . V | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * . . . . . . . . . . . . . . . . V + * <----UV_BF_Meta_Stride----> + * M M M M M M M M M M M M . . ^ + * M M M M M M M M M M M M . . | + * M M M M M M M M M M M M . . | + * M M M M M M M M M M M M . . M_UV_BF_Scanlines + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . V + * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * <-Compressed tile UV_BF Stride-> + * U* V* U* V* U* V* U* V* . . . . ^ + * U* V* U* V* U* V* U* V* . . . . | + * U* V* U* V* U* V* U* V* . . . . | + * U* V* U* V* U* V* U* V* . . . . UV_BF_Scanlines + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . V + * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * + * Half_height = (Height+1)>>1 + * Y_TF_Stride = align(Width, 128) + * UV_TF_Stride = align(Width, 128) + * Y_TF_Scanlines = align(Half_height, 32) + * UV_TF_Scanlines = align((Half_height+1)/2, 32) + * Y_UBWC_TF_Plane_size = align(Y_TF_Stride * Y_TF_Scanlines, 4096) + * UV_UBWC_TF_Plane_size = align(UV_TF_Stride * UV_TF_Scanlines, 4096) + * Y_TF_Meta_Stride = align(roundup(Width, Y_TileWidth), 64) + * Y_TF_Meta_Scanlines = align(roundup(Half_height, Y_TileHeight), 16) + * Y_TF_Meta_Plane_size = + * align(Y_TF_Meta_Stride * Y_TF_Meta_Scanlines, 4096) + * UV_TF_Meta_Stride = align(roundup(Width, UV_TileWidth), 64) + * UV_TF_Meta_Scanlines = align(roundup(Half_height, UV_TileHeight), 16) + * UV_TF_Meta_Plane_size = + * align(UV_TF_Meta_Stride * UV_TF_Meta_Scanlines, 4096) + * Y_BF_Stride = align(Width, 128) + * UV_BF_Stride = align(Width, 128) + * Y_BF_Scanlines = align(Half_height, 32) + * UV_BF_Scanlines = align((Half_height+1)/2, 32) + * Y_UBWC_BF_Plane_size = align(Y_BF_Stride * Y_BF_Scanlines, 4096) + * UV_UBWC_BF_Plane_size = align(UV_BF_Stride * UV_BF_Scanlines, 4096) + * Y_BF_Meta_Stride = align(roundup(Width, Y_TileWidth), 64) + * Y_BF_Meta_Scanlines = align(roundup(Half_height, Y_TileHeight), 16) + * Y_BF_Meta_Plane_size = + * align(Y_BF_Meta_Stride * Y_BF_Meta_Scanlines, 4096) + * UV_BF_Meta_Stride = align(roundup(Width, UV_TileWidth), 64) + * UV_BF_Meta_Scanlines = align(roundup(Half_height, UV_TileHeight), 16) + * UV_BF_Meta_Plane_size = + * align(UV_BF_Meta_Stride * UV_BF_Meta_Scanlines, 4096) + * Extradata = 8k + * + * Total size = align( Y_UBWC_TF_Plane_size + UV_UBWC_TF_Plane_size + + * Y_TF_Meta_Plane_size + UV_TF_Meta_Plane_size + + * Y_UBWC_BF_Plane_size + UV_UBWC_BF_Plane_size + + * Y_BF_Meta_Plane_size + UV_BF_Meta_Plane_size + + * + max(Extradata, Y_TF_Stride * 48), 4096) + */ + COLOR_FMT_NV12_UBWC, + /* Venus NV12 10-bit UBWC: + * Compressed Macro-tile format for NV12. + * Contains 4 planes in the following order - + * (A) Y_Meta_Plane + * (B) Y_UBWC_Plane + * (C) UV_Meta_Plane + * (D) UV_UBWC_Plane + * + * Y_Meta_Plane consists of meta information to decode compressed + * tile data in Y_UBWC_Plane. + * Y_UBWC_Plane consists of Y data in compressed macro-tile format. + * UBWC decoder block will use the Y_Meta_Plane data together with + * Y_UBWC_Plane data to produce loss-less uncompressed 10 bit Y samples. + * + * UV_Meta_Plane consists of meta information to decode compressed + * tile data in UV_UBWC_Plane. + * UV_UBWC_Plane consists of UV data in compressed macro-tile format. + * UBWC decoder block will use UV_Meta_Plane data together with + * UV_UBWC_Plane data to produce loss-less uncompressed 10 bit 2x2 + * subsampled color difference samples. + * + * Each tile in Y_UBWC_Plane/UV_UBWC_Plane is independently decodable + * and randomly accessible. There is no dependency between tiles. + * + * <----- Y_Meta_Stride -----> + * <-------- Width ------> + * M M M M M M M M M M M M . . ^ ^ + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . Height | + * M M M M M M M M M M M M . . | Meta_Y_Scanlines + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . V | + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * . . . . . . . . . . . . . . V + * <--Compressed tile Y Stride---> + * <------- Width -------> + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . ^ ^ + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . Height | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | Macro_tile_Y_Scanlines + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . V | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * . . . . . . . . . . . . . . . . V + * <----- UV_Meta_Stride ----> + * M M M M M M M M M M M M . . ^ + * M M M M M M M M M M M M . . | + * M M M M M M M M M M M M . . | + * M M M M M M M M M M M M . . M_UV_Scanlines + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . V + * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * <--Compressed tile UV Stride---> + * U* V* U* V* U* V* U* V* . . . . ^ + * U* V* U* V* U* V* U* V* . . . . | + * U* V* U* V* U* V* U* V* . . . . | + * U* V* U* V* U* V* U* V* . . . . UV_Scanlines + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . V + * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * + * + * Y_Stride = align(Width * 4/3, 128) + * UV_Stride = align(Width * 4/3, 128) + * Y_Scanlines = align(Height, 32) + * UV_Scanlines = align(Height/2, 16) + * Y_UBWC_Plane_Size = align(Y_Stride * Y_Scanlines, 4096) + * UV_UBWC_Plane_Size = align(UV_Stride * UV_Scanlines, 4096) + * Y_Meta_Stride = align(roundup(Width, Y_TileWidth), 64) + * Y_Meta_Scanlines = align(roundup(Height, Y_TileHeight), 16) + * Y_Meta_Plane_size = align(Y_Meta_Stride * Y_Meta_Scanlines, 4096) + * UV_Meta_Stride = align(roundup(Width, UV_TileWidth), 64) + * UV_Meta_Scanlines = align(roundup(Height, UV_TileHeight), 16) + * UV_Meta_Plane_size = align(UV_Meta_Stride * UV_Meta_Scanlines, 4096) + * Extradata = 8k + * + * Total size = align(Y_UBWC_Plane_size + UV_UBWC_Plane_size + + * Y_Meta_Plane_size + UV_Meta_Plane_size + * + max(Extradata, Y_Stride * 48), 4096) + */ + COLOR_FMT_NV12_BPP10_UBWC, + /* Venus RGBA8888 format: + * Contains 1 plane in the following order - + * (A) RGBA plane + * + * <-------- RGB_Stride --------> + * <------- Width -------> + * R R R R R R R R R R R R . . . . ^ ^ + * R R R R R R R R R R R R . . . . | | + * R R R R R R R R R R R R . . . . Height | + * R R R R R R R R R R R R . . . . | RGB_Scanlines + * R R R R R R R R R R R R . . . . | | + * R R R R R R R R R R R R . . . . | | + * R R R R R R R R R R R R . . . . | | + * R R R R R R R R R R R R . . . . V | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . V + * + * RGB_Stride = align(Width * 4, 128) + * RGB_Scanlines = align(Height, 32) + * RGB_Plane_size = align(RGB_Stride * RGB_Scanlines, 4096) + * Extradata = 8k + * + * Total size = align(RGB_Plane_size + Extradata, 4096) + */ + COLOR_FMT_RGBA8888, + /* Venus RGBA8888 UBWC format: + * Contains 2 planes in the following order - + * (A) Meta plane + * (B) RGBA plane + * + * <--- RGB_Meta_Stride ----> + * <-------- Width ------> + * M M M M M M M M M M M M . . ^ ^ + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . Height | + * M M M M M M M M M M M M . . | Meta_RGB_Scanlines + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . V | + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * . . . . . . . . . . . . . . V + * <-------- RGB_Stride --------> + * <------- Width -------> + * R R R R R R R R R R R R . . . . ^ ^ + * R R R R R R R R R R R R . . . . | | + * R R R R R R R R R R R R . . . . Height | + * R R R R R R R R R R R R . . . . | RGB_Scanlines + * R R R R R R R R R R R R . . . . | | + * R R R R R R R R R R R R . . . . | | + * R R R R R R R R R R R R . . . . | | + * R R R R R R R R R R R R . . . . V | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * . . . . . . . . . . . . . . . . V + * + * RGB_Stride = align(Width * 4, 128) + * RGB_Scanlines = align(Height, 32) + * RGB_Plane_size = align(RGB_Stride * RGB_Scanlines, 4096) + * RGB_Meta_Stride = align(roundup(Width, RGB_TileWidth), 64) + * RGB_Meta_Scanline = align(roundup(Height, RGB_TileHeight), 16) + * RGB_Meta_Plane_size = align(RGB_Meta_Stride * + * RGB_Meta_Scanlines, 4096) + * Extradata = 8k + * + * Total size = align(RGB_Meta_Plane_size + RGB_Plane_size + + * Extradata, 4096) + */ + COLOR_FMT_RGBA8888_UBWC, + /* Venus RGBA1010102 UBWC format: + * Contains 2 planes in the following order - + * (A) Meta plane + * (B) RGBA plane + * + * <--- RGB_Meta_Stride ----> + * <-------- Width ------> + * M M M M M M M M M M M M . . ^ ^ + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . Height | + * M M M M M M M M M M M M . . | Meta_RGB_Scanlines + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . V | + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * . . . . . . . . . . . . . . V + * <-------- RGB_Stride --------> + * <------- Width -------> + * R R R R R R R R R R R R . . . . ^ ^ + * R R R R R R R R R R R R . . . . | | + * R R R R R R R R R R R R . . . . Height | + * R R R R R R R R R R R R . . . . | RGB_Scanlines + * R R R R R R R R R R R R . . . . | | + * R R R R R R R R R R R R . . . . | | + * R R R R R R R R R R R R . . . . | | + * R R R R R R R R R R R R . . . . V | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * . . . . . . . . . . . . . . . . V + * + * RGB_Stride = align(Width * 4, 256) + * RGB_Scanlines = align(Height, 16) + * RGB_Plane_size = align(RGB_Stride * RGB_Scanlines, 4096) + * RGB_Meta_Stride = align(roundup(Width, RGB_TileWidth), 64) + * RGB_Meta_Scanline = align(roundup(Height, RGB_TileHeight), 16) + * RGB_Meta_Plane_size = align(RGB_Meta_Stride * + * RGB_Meta_Scanlines, 4096) + * Extradata = 8k + * + * Total size = align(RGB_Meta_Plane_size + RGB_Plane_size + + * Extradata, 4096) + */ + COLOR_FMT_RGBA1010102_UBWC, + /* Venus RGB565 UBWC format: + * Contains 2 planes in the following order - + * (A) Meta plane + * (B) RGB plane + * + * <--- RGB_Meta_Stride ----> + * <-------- Width ------> + * M M M M M M M M M M M M . . ^ ^ + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . Height | + * M M M M M M M M M M M M . . | Meta_RGB_Scanlines + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . V | + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * . . . . . . . . . . . . . . V + * <-------- RGB_Stride --------> + * <------- Width -------> + * R R R R R R R R R R R R . . . . ^ ^ + * R R R R R R R R R R R R . . . . | | + * R R R R R R R R R R R R . . . . Height | + * R R R R R R R R R R R R . . . . | RGB_Scanlines + * R R R R R R R R R R R R . . . . | | + * R R R R R R R R R R R R . . . . | | + * R R R R R R R R R R R R . . . . | | + * R R R R R R R R R R R R . . . . V | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * . . . . . . . . . . . . . . . . V + * + * RGB_Stride = align(Width * 2, 128) + * RGB_Scanlines = align(Height, 16) + * RGB_Plane_size = align(RGB_Stride * RGB_Scanlines, 4096) + * RGB_Meta_Stride = align(roundup(Width, RGB_TileWidth), 64) + * RGB_Meta_Scanline = align(roundup(Height, RGB_TileHeight), 16) + * RGB_Meta_Plane_size = align(RGB_Meta_Stride * + * RGB_Meta_Scanlines, 4096) + * Extradata = 8k + * + * Total size = align(RGB_Meta_Plane_size + RGB_Plane_size + + * Extradata, 4096) + */ + COLOR_FMT_RGB565_UBWC, + /* P010 UBWC: + * Compressed Macro-tile format for NV12. + * Contains 4 planes in the following order - + * (A) Y_Meta_Plane + * (B) Y_UBWC_Plane + * (C) UV_Meta_Plane + * (D) UV_UBWC_Plane + * + * Y_Meta_Plane consists of meta information to decode compressed + * tile data in Y_UBWC_Plane. + * Y_UBWC_Plane consists of Y data in compressed macro-tile format. + * UBWC decoder block will use the Y_Meta_Plane data together with + * Y_UBWC_Plane data to produce loss-less uncompressed 10 bit Y samples. + * + * UV_Meta_Plane consists of meta information to decode compressed + * tile data in UV_UBWC_Plane. + * UV_UBWC_Plane consists of UV data in compressed macro-tile format. + * UBWC decoder block will use UV_Meta_Plane data together with + * UV_UBWC_Plane data to produce loss-less uncompressed 10 bit 2x2 + * subsampled color difference samples. + * + * Each tile in Y_UBWC_Plane/UV_UBWC_Plane is independently decodable + * and randomly accessible. There is no dependency between tiles. + * + * <----- Y_Meta_Stride -----> + * <-------- Width ------> + * M M M M M M M M M M M M . . ^ ^ + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . Height | + * M M M M M M M M M M M M . . | Meta_Y_Scanlines + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . V | + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * . . . . . . . . . . . . . . V + * <--Compressed tile Y Stride---> + * <------- Width -------> + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . ^ ^ + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . Height | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | Macro_tile_Y_Scanlines + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . V | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * . . . . . . . . . . . . . . . . V + * <----- UV_Meta_Stride ----> + * M M M M M M M M M M M M . . ^ + * M M M M M M M M M M M M . . | + * M M M M M M M M M M M M . . | + * M M M M M M M M M M M M . . M_UV_Scanlines + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . V + * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * <--Compressed tile UV Stride---> + * U* V* U* V* U* V* U* V* . . . . ^ + * U* V* U* V* U* V* U* V* . . . . | + * U* V* U* V* U* V* U* V* . . . . | + * U* V* U* V* U* V* U* V* . . . . UV_Scanlines + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . V + * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * + * + * Y_Stride = align(Width * 2, 256) + * UV_Stride = align(Width * 2, 256) + * Y_Scanlines = align(Height, 16) + * UV_Scanlines = align(Height/2, 16) + * Y_UBWC_Plane_Size = align(Y_Stride * Y_Scanlines, 4096) + * UV_UBWC_Plane_Size = align(UV_Stride * UV_Scanlines, 4096) + * Y_Meta_Stride = align(roundup(Width, Y_TileWidth), 64) + * Y_Meta_Scanlines = align(roundup(Height, Y_TileHeight), 16) + * Y_Meta_Plane_size = align(Y_Meta_Stride * Y_Meta_Scanlines, 4096) + * UV_Meta_Stride = align(roundup(Width, UV_TileWidth), 64) + * UV_Meta_Scanlines = align(roundup(Height, UV_TileHeight), 16) + * UV_Meta_Plane_size = align(UV_Meta_Stride * UV_Meta_Scanlines, 4096) + * Extradata = 8k + * + * Total size = align(Y_UBWC_Plane_size + UV_UBWC_Plane_size + + * Y_Meta_Plane_size + UV_Meta_Plane_size + * + max(Extradata, Y_Stride * 48), 4096) + */ + COLOR_FMT_P010_UBWC, + /* Venus P010: + * YUV 4:2:0 image with a plane of 10 bit Y samples followed + * by an interleaved U/V plane containing 10 bit 2x2 subsampled + * colour difference samples. + * + * <-------- Y/UV_Stride --------> + * <------- Width -------> + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . ^ ^ + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . Height | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | Y_Scanlines + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . V | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . V + * U V U V U V U V U V U V . . . . ^ + * U V U V U V U V U V U V . . . . | + * U V U V U V U V U V U V . . . . | + * U V U V U V U V U V U V . . . . UV_Scanlines + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . V + * . . . . . . . . . . . . . . . . --> Buffer size alignment + * + * Y_Stride : Width * 2 aligned to 128 + * UV_Stride : Width * 2 aligned to 128 + * Y_Scanlines: Height aligned to 32 + * UV_Scanlines: Height/2 aligned to 16 + * Extradata: Arbitrary (software-imposed) padding + * Total size = align((Y_Stride * Y_Scanlines + * + UV_Stride * UV_Scanlines + * + max(Extradata, Y_Stride * 8), 4096) + */ + COLOR_FMT_P010, +}; + +#define COLOR_FMT_RGBA1010102_UBWC COLOR_FMT_RGBA1010102_UBWC +#define COLOR_FMT_RGB565_UBWC COLOR_FMT_RGB565_UBWC +#define COLOR_FMT_P010_UBWC COLOR_FMT_P010_UBWC +#define COLOR_FMT_P010 COLOR_FMT_P010 + +static inline unsigned int VENUS_EXTRADATA_SIZE(int width, int height) +{ + (void)height; + (void)width; + + /* + * In the future, calculate the size based on the w/h but just + * hardcode it for now since 16K satisfies all current usecases. + */ + return 16 * 1024; +} + +/* + * Function arguments: + * @color_fmt + * @width + * Progressive: width + * Interlaced: width + */ +static inline unsigned int VENUS_Y_STRIDE(int color_fmt, int width) +{ + unsigned int alignment, stride = 0; + + if (!width) + goto invalid_input; + + switch (color_fmt) { + case COLOR_FMT_NV21: + case COLOR_FMT_NV12: + case COLOR_FMT_NV12_MVTB: + case COLOR_FMT_NV12_UBWC: + alignment = 128; + stride = MSM_MEDIA_ALIGN(width, alignment); + break; + case COLOR_FMT_NV12_BPP10_UBWC: + alignment = 256; + stride = MSM_MEDIA_ALIGN(width, 192); + stride = MSM_MEDIA_ALIGN(stride * 4/3, alignment); + break; + case COLOR_FMT_P010_UBWC: + alignment = 256; + stride = MSM_MEDIA_ALIGN(width * 2, alignment); + break; + case COLOR_FMT_P010: + alignment = 128; + stride = MSM_MEDIA_ALIGN(width*2, alignment); + break; + default: + break; + } +invalid_input: + return stride; +} + +/* + * Function arguments: + * @color_fmt + * @width + * Progressive: width + * Interlaced: width + */ +static inline unsigned int VENUS_UV_STRIDE(int color_fmt, int width) +{ + unsigned int alignment, stride = 0; + + if (!width) + goto invalid_input; + + switch (color_fmt) { + case COLOR_FMT_NV21: + case COLOR_FMT_NV12: + case COLOR_FMT_NV12_MVTB: + case COLOR_FMT_NV12_UBWC: + alignment = 128; + stride = MSM_MEDIA_ALIGN(width, alignment); + break; + case COLOR_FMT_NV12_BPP10_UBWC: + alignment = 256; + stride = MSM_MEDIA_ALIGN(width, 192); + stride = MSM_MEDIA_ALIGN(stride * 4/3, alignment); + break; + case COLOR_FMT_P010_UBWC: + alignment = 256; + stride = MSM_MEDIA_ALIGN(width * 2, alignment); + break; + case COLOR_FMT_P010: + alignment = 128; + stride = MSM_MEDIA_ALIGN(width*2, alignment); + break; + default: + break; + } +invalid_input: + return stride; +} + +/* + * Function arguments: + * @color_fmt + * @height + * Progressive: height + * Interlaced: (height+1)>>1 + */ +static inline unsigned int VENUS_Y_SCANLINES(int color_fmt, int height) +{ + unsigned int alignment, sclines = 0; + + if (!height) + goto invalid_input; + + switch (color_fmt) { + case COLOR_FMT_NV21: + case COLOR_FMT_NV12: + case COLOR_FMT_NV12_MVTB: + case COLOR_FMT_NV12_UBWC: + case COLOR_FMT_P010: + alignment = 32; + break; + case COLOR_FMT_NV12_BPP10_UBWC: + case COLOR_FMT_P010_UBWC: + alignment = 16; + break; + default: + return 0; + } + sclines = MSM_MEDIA_ALIGN(height, alignment); +invalid_input: + return sclines; +} + +/* + * Function arguments: + * @color_fmt + * @height + * Progressive: height + * Interlaced: (height+1)>>1 + */ +static inline unsigned int VENUS_UV_SCANLINES(int color_fmt, int height) +{ + unsigned int alignment, sclines = 0; + + if (!height) + goto invalid_input; + + switch (color_fmt) { + case COLOR_FMT_NV21: + case COLOR_FMT_NV12: + case COLOR_FMT_NV12_MVTB: + case COLOR_FMT_NV12_BPP10_UBWC: + case COLOR_FMT_P010_UBWC: + case COLOR_FMT_P010: + alignment = 16; + break; + case COLOR_FMT_NV12_UBWC: + alignment = 32; + break; + default: + goto invalid_input; + } + + sclines = MSM_MEDIA_ALIGN((height+1)>>1, alignment); + +invalid_input: + return sclines; +} + +/* + * Function arguments: + * @color_fmt + * @width + * Progressive: width + * Interlaced: width + */ +static inline unsigned int VENUS_Y_META_STRIDE(int color_fmt, int width) +{ + int y_tile_width = 0, y_meta_stride = 0; + + if (!width) + goto invalid_input; + + switch (color_fmt) { + case COLOR_FMT_NV12_UBWC: + case COLOR_FMT_P010_UBWC: + y_tile_width = 32; + break; + case COLOR_FMT_NV12_BPP10_UBWC: + y_tile_width = 48; + break; + default: + goto invalid_input; + } + + y_meta_stride = MSM_MEDIA_ROUNDUP(width, y_tile_width); + y_meta_stride = MSM_MEDIA_ALIGN(y_meta_stride, 64); + +invalid_input: + return y_meta_stride; +} + +/* + * Function arguments: + * @color_fmt + * @height + * Progressive: height + * Interlaced: (height+1)>>1 + */ +static inline unsigned int VENUS_Y_META_SCANLINES(int color_fmt, int height) +{ + int y_tile_height = 0, y_meta_scanlines = 0; + + if (!height) + goto invalid_input; + + switch (color_fmt) { + case COLOR_FMT_NV12_UBWC: + y_tile_height = 8; + break; + case COLOR_FMT_NV12_BPP10_UBWC: + case COLOR_FMT_P010_UBWC: + y_tile_height = 4; + break; + default: + goto invalid_input; + } + + y_meta_scanlines = MSM_MEDIA_ROUNDUP(height, y_tile_height); + y_meta_scanlines = MSM_MEDIA_ALIGN(y_meta_scanlines, 16); + +invalid_input: + return y_meta_scanlines; +} + +/* + * Function arguments: + * @color_fmt + * @width + * Progressive: width + * Interlaced: width + */ +static inline unsigned int VENUS_UV_META_STRIDE(int color_fmt, int width) +{ + int uv_tile_width = 0, uv_meta_stride = 0; + + if (!width) + goto invalid_input; + + switch (color_fmt) { + case COLOR_FMT_NV12_UBWC: + case COLOR_FMT_P010_UBWC: + uv_tile_width = 16; + break; + case COLOR_FMT_NV12_BPP10_UBWC: + uv_tile_width = 24; + break; + default: + goto invalid_input; + } + + uv_meta_stride = MSM_MEDIA_ROUNDUP((width+1)>>1, uv_tile_width); + uv_meta_stride = MSM_MEDIA_ALIGN(uv_meta_stride, 64); + +invalid_input: + return uv_meta_stride; +} + +/* + * Function arguments: + * @color_fmt + * @height + * Progressive: height + * Interlaced: (height+1)>>1 + */ +static inline unsigned int VENUS_UV_META_SCANLINES(int color_fmt, int height) +{ + int uv_tile_height = 0, uv_meta_scanlines = 0; + + if (!height) + goto invalid_input; + + switch (color_fmt) { + case COLOR_FMT_NV12_UBWC: + uv_tile_height = 8; + break; + case COLOR_FMT_NV12_BPP10_UBWC: + case COLOR_FMT_P010_UBWC: + uv_tile_height = 4; + break; + default: + goto invalid_input; + } + + uv_meta_scanlines = MSM_MEDIA_ROUNDUP((height+1)>>1, uv_tile_height); + uv_meta_scanlines = MSM_MEDIA_ALIGN(uv_meta_scanlines, 16); + +invalid_input: + return uv_meta_scanlines; +} + +static inline unsigned int VENUS_RGB_STRIDE(int color_fmt, int width) +{ + unsigned int alignment = 0, stride = 0, bpp = 4; + + if (!width) + goto invalid_input; + + switch (color_fmt) { + case COLOR_FMT_RGBA8888: + alignment = 128; + break; + case COLOR_FMT_RGB565_UBWC: + alignment = 256; + bpp = 2; + break; + case COLOR_FMT_RGBA8888_UBWC: + case COLOR_FMT_RGBA1010102_UBWC: + alignment = 256; + break; + default: + goto invalid_input; + } + + stride = MSM_MEDIA_ALIGN(width * bpp, alignment); + +invalid_input: + return stride; +} + +static inline unsigned int VENUS_RGB_SCANLINES(int color_fmt, int height) +{ + unsigned int alignment = 0, scanlines = 0; + + if (!height) + goto invalid_input; + + switch (color_fmt) { + case COLOR_FMT_RGBA8888: + alignment = 32; + break; + case COLOR_FMT_RGBA8888_UBWC: + case COLOR_FMT_RGBA1010102_UBWC: + case COLOR_FMT_RGB565_UBWC: + alignment = 16; + break; + default: + goto invalid_input; + } + + scanlines = MSM_MEDIA_ALIGN(height, alignment); + +invalid_input: + return scanlines; +} + +static inline unsigned int VENUS_RGB_META_STRIDE(int color_fmt, int width) +{ + int rgb_tile_width = 0, rgb_meta_stride = 0; + + if (!width) + goto invalid_input; + + switch (color_fmt) { + case COLOR_FMT_RGBA8888_UBWC: + case COLOR_FMT_RGBA1010102_UBWC: + case COLOR_FMT_RGB565_UBWC: + rgb_tile_width = 16; + break; + default: + goto invalid_input; + } + + rgb_meta_stride = MSM_MEDIA_ROUNDUP(width, rgb_tile_width); + rgb_meta_stride = MSM_MEDIA_ALIGN(rgb_meta_stride, 64); + +invalid_input: + return rgb_meta_stride; +} + +static inline unsigned int VENUS_RGB_META_SCANLINES(int color_fmt, int height) +{ + int rgb_tile_height = 0, rgb_meta_scanlines = 0; + + if (!height) + goto invalid_input; + + switch (color_fmt) { + case COLOR_FMT_RGBA8888_UBWC: + case COLOR_FMT_RGBA1010102_UBWC: + case COLOR_FMT_RGB565_UBWC: + rgb_tile_height = 4; + break; + default: + goto invalid_input; + } + + rgb_meta_scanlines = MSM_MEDIA_ROUNDUP(height, rgb_tile_height); + rgb_meta_scanlines = MSM_MEDIA_ALIGN(rgb_meta_scanlines, 16); + +invalid_input: + return rgb_meta_scanlines; +} + +/* + * Function arguments: + * @color_fmt + * @width + * Progressive: width + * Interlaced: width + * @height + * Progressive: height + * Interlaced: height + */ +static inline unsigned int VENUS_BUFFER_SIZE( + int color_fmt, int width, int height) +{ + const unsigned int extra_size = VENUS_EXTRADATA_SIZE(width, height); + unsigned int uv_alignment = 0, size = 0; + unsigned int y_plane, uv_plane, y_stride, + uv_stride, y_sclines, uv_sclines; + unsigned int y_ubwc_plane = 0, uv_ubwc_plane = 0; + unsigned int y_meta_stride = 0, y_meta_scanlines = 0; + unsigned int uv_meta_stride = 0, uv_meta_scanlines = 0; + unsigned int y_meta_plane = 0, uv_meta_plane = 0; + unsigned int rgb_stride = 0, rgb_scanlines = 0; + unsigned int rgb_plane = 0, rgb_ubwc_plane = 0, rgb_meta_plane = 0; + unsigned int rgb_meta_stride = 0, rgb_meta_scanlines = 0; + + if (!width || !height) + goto invalid_input; + + y_stride = VENUS_Y_STRIDE(color_fmt, width); + uv_stride = VENUS_UV_STRIDE(color_fmt, width); + y_sclines = VENUS_Y_SCANLINES(color_fmt, height); + uv_sclines = VENUS_UV_SCANLINES(color_fmt, height); + rgb_stride = VENUS_RGB_STRIDE(color_fmt, width); + rgb_scanlines = VENUS_RGB_SCANLINES(color_fmt, height); + + switch (color_fmt) { + case COLOR_FMT_NV21: + case COLOR_FMT_NV12: + case COLOR_FMT_P010: + uv_alignment = 4096; + y_plane = y_stride * y_sclines; + uv_plane = uv_stride * uv_sclines + uv_alignment; + size = y_plane + uv_plane + + MSM_MEDIA_MAX(extra_size, 8 * y_stride); + size = MSM_MEDIA_ALIGN(size, 4096); + break; + case COLOR_FMT_NV12_MVTB: + uv_alignment = 4096; + y_plane = y_stride * y_sclines; + uv_plane = uv_stride * uv_sclines + uv_alignment; + size = y_plane + uv_plane; + size = 2 * size + extra_size; + size = MSM_MEDIA_ALIGN(size, 4096); + break; + case COLOR_FMT_NV12_UBWC: + y_sclines = VENUS_Y_SCANLINES(color_fmt, (height+1)>>1); + y_ubwc_plane = MSM_MEDIA_ALIGN(y_stride * y_sclines, 4096); + uv_sclines = VENUS_UV_SCANLINES(color_fmt, (height+1)>>1); + uv_ubwc_plane = MSM_MEDIA_ALIGN(uv_stride * uv_sclines, 4096); + y_meta_stride = VENUS_Y_META_STRIDE(color_fmt, width); + y_meta_scanlines = + VENUS_Y_META_SCANLINES(color_fmt, (height+1)>>1); + y_meta_plane = MSM_MEDIA_ALIGN( + y_meta_stride * y_meta_scanlines, 4096); + uv_meta_stride = VENUS_UV_META_STRIDE(color_fmt, width); + uv_meta_scanlines = + VENUS_UV_META_SCANLINES(color_fmt, (height+1)>>1); + uv_meta_plane = MSM_MEDIA_ALIGN(uv_meta_stride * + uv_meta_scanlines, 4096); + + size = (y_ubwc_plane + uv_ubwc_plane + y_meta_plane + + uv_meta_plane)*2 + + MSM_MEDIA_MAX(extra_size + 8192, 48 * y_stride); + size = MSM_MEDIA_ALIGN(size, 4096); + break; + case COLOR_FMT_NV12_BPP10_UBWC: + y_ubwc_plane = MSM_MEDIA_ALIGN(y_stride * y_sclines, 4096); + uv_ubwc_plane = MSM_MEDIA_ALIGN(uv_stride * uv_sclines, 4096); + y_meta_stride = VENUS_Y_META_STRIDE(color_fmt, width); + y_meta_scanlines = VENUS_Y_META_SCANLINES(color_fmt, height); + y_meta_plane = MSM_MEDIA_ALIGN( + y_meta_stride * y_meta_scanlines, 4096); + uv_meta_stride = VENUS_UV_META_STRIDE(color_fmt, width); + uv_meta_scanlines = VENUS_UV_META_SCANLINES(color_fmt, height); + uv_meta_plane = MSM_MEDIA_ALIGN(uv_meta_stride * + uv_meta_scanlines, 4096); + + size = y_ubwc_plane + uv_ubwc_plane + y_meta_plane + + uv_meta_plane + + MSM_MEDIA_MAX(extra_size + 8192, 48 * y_stride); + size = MSM_MEDIA_ALIGN(size, 4096); + break; + case COLOR_FMT_P010_UBWC: + y_ubwc_plane = MSM_MEDIA_ALIGN(y_stride * y_sclines, 4096); + uv_ubwc_plane = MSM_MEDIA_ALIGN(uv_stride * uv_sclines, 4096); + y_meta_stride = VENUS_Y_META_STRIDE(color_fmt, width); + y_meta_scanlines = VENUS_Y_META_SCANLINES(color_fmt, height); + y_meta_plane = MSM_MEDIA_ALIGN( + y_meta_stride * y_meta_scanlines, 4096); + uv_meta_stride = VENUS_UV_META_STRIDE(color_fmt, width); + uv_meta_scanlines = VENUS_UV_META_SCANLINES(color_fmt, height); + uv_meta_plane = MSM_MEDIA_ALIGN(uv_meta_stride * + uv_meta_scanlines, 4096); + + size = y_ubwc_plane + uv_ubwc_plane + y_meta_plane + + uv_meta_plane; + size = MSM_MEDIA_ALIGN(size, 4096); + break; + case COLOR_FMT_RGBA8888: + rgb_plane = MSM_MEDIA_ALIGN(rgb_stride * rgb_scanlines, 4096); + size = rgb_plane; + size = MSM_MEDIA_ALIGN(size, 4096); + break; + case COLOR_FMT_RGBA8888_UBWC: + case COLOR_FMT_RGBA1010102_UBWC: + case COLOR_FMT_RGB565_UBWC: + rgb_ubwc_plane = MSM_MEDIA_ALIGN(rgb_stride * rgb_scanlines, + 4096); + rgb_meta_stride = VENUS_RGB_META_STRIDE(color_fmt, width); + rgb_meta_scanlines = VENUS_RGB_META_SCANLINES(color_fmt, + height); + rgb_meta_plane = MSM_MEDIA_ALIGN(rgb_meta_stride * + rgb_meta_scanlines, 4096); + size = rgb_ubwc_plane + rgb_meta_plane; + size = MSM_MEDIA_ALIGN(size, 4096); + break; + default: + break; + } +invalid_input: + return size; +} + +static inline unsigned int VENUS_VIEW2_OFFSET( + int color_fmt, int width, int height) +{ + unsigned int offset = 0; + unsigned int y_plane, uv_plane, y_stride, + uv_stride, y_sclines, uv_sclines; + if (!width || !height) + goto invalid_input; + + y_stride = VENUS_Y_STRIDE(color_fmt, width); + uv_stride = VENUS_UV_STRIDE(color_fmt, width); + y_sclines = VENUS_Y_SCANLINES(color_fmt, height); + uv_sclines = VENUS_UV_SCANLINES(color_fmt, height); + switch (color_fmt) { + case COLOR_FMT_NV12_MVTB: + y_plane = y_stride * y_sclines; + uv_plane = uv_stride * uv_sclines; + offset = y_plane + uv_plane; + break; + default: + break; + } +invalid_input: + return offset; +} + +#endif diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index e79ad74ca98c2..46876bc8b7077 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> * @@ -15,6 +16,8 @@ * this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <linux/kthread.h> +#include <uapi/linux/sched/types.h> #include <drm/drm_of.h> #include "msm_drv.h" @@ -149,7 +152,7 @@ struct vblank_event { bool enable; }; -static void vblank_ctrl_worker(struct work_struct *work) +static void vblank_ctrl_worker(struct kthread_work *work) { struct msm_vblank_ctrl *vbl_ctrl = container_of(work, struct msm_vblank_ctrl, work); @@ -197,7 +200,8 @@ static int vblank_ctrl_queue_work(struct msm_drm_private *priv, list_add_tail(&vbl_ev->node, &vbl_ctrl->event_list); spin_unlock_irqrestore(&vbl_ctrl->lock, flags); - queue_work(priv->wq, &vbl_ctrl->work); + kthread_queue_work(&priv->disp_thread[crtc_id].worker, + &vbl_ctrl->work); return 0; } @@ -211,17 +215,33 @@ static int msm_drm_uninit(struct device *dev) struct msm_mdss *mdss = priv->mdss; struct msm_vblank_ctrl *vbl_ctrl = &priv->vblank_ctrl; struct vblank_event *vbl_ev, *tmp; + int i; /* We must cancel and cleanup any pending vblank enable/disable * work before drm_irq_uninstall() to avoid work re-enabling an * irq after uninstall has disabled it. */ - cancel_work_sync(&vbl_ctrl->work); + kthread_flush_work(&vbl_ctrl->work); list_for_each_entry_safe(vbl_ev, tmp, &vbl_ctrl->event_list, node) { list_del(&vbl_ev->node); kfree(vbl_ev); } + /* clean up display commit/event worker threads */ + for (i = 0; i < priv->num_crtcs; i++) { + if (priv->disp_thread[i].thread) { + kthread_flush_worker(&priv->disp_thread[i].worker); + kthread_stop(priv->disp_thread[i].thread); + priv->disp_thread[i].thread = NULL; + } + + if (priv->event_thread[i].thread) { + kthread_flush_worker(&priv->event_thread[i].worker); + kthread_stop(priv->event_thread[i].thread); + priv->event_thread[i].thread = NULL; + } + } + msm_gem_shrinker_cleanup(ddev); drm_kms_helper_poll_fini(ddev); @@ -269,6 +289,7 @@ static int msm_drm_uninit(struct device *dev) #define KMS_MDP4 4 #define KMS_MDP5 5 +#define KMS_DPU 3 static int get_mdp_ver(struct platform_device *pdev) { @@ -360,7 +381,8 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) struct msm_drm_private *priv; struct msm_kms *kms; struct msm_mdss *mdss; - int ret; + int ret, i; + struct sched_param param; ddev = drm_dev_alloc(drv, dev); if (IS_ERR(ddev)) { @@ -379,7 +401,17 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) ddev->dev_private = priv; priv->dev = ddev; - ret = mdp5_mdss_init(ddev); + switch (get_mdp_ver(pdev)) { + case KMS_MDP5: + ret = mdp5_mdss_init(ddev); + break; + case KMS_DPU: + ret = dpu_mdss_init(ddev); + break; + default: + ret = 0; + break; + } if (ret) goto err_free_priv; @@ -389,7 +421,7 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) INIT_LIST_HEAD(&priv->inactive_list); INIT_LIST_HEAD(&priv->vblank_ctrl.event_list); - INIT_WORK(&priv->vblank_ctrl.work, vblank_ctrl_worker); + kthread_init_work(&priv->vblank_ctrl.work, vblank_ctrl_worker); spin_lock_init(&priv->vblank_ctrl.lock); drm_mode_config_init(ddev); @@ -413,6 +445,10 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) case KMS_MDP5: kms = mdp5_kms_init(ddev); break; + case KMS_DPU: + kms = dpu_kms_init(ddev); + priv->kms = kms; + break; default: kms = ERR_PTR(-ENODEV); break; @@ -444,6 +480,79 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) ddev->mode_config.funcs = &mode_config_funcs; ddev->mode_config.helper_private = &mode_config_helper_funcs; + /** + * this priority was found during empiric testing to have appropriate + * realtime scheduling to process display updates and interact with + * other real time and normal priority task + */ + param.sched_priority = 16; + for (i = 0; i < priv->num_crtcs; i++) { + + /* initialize display thread */ + priv->disp_thread[i].crtc_id = priv->crtcs[i]->base.id; + kthread_init_worker(&priv->disp_thread[i].worker); + priv->disp_thread[i].dev = ddev; + priv->disp_thread[i].thread = + kthread_run(kthread_worker_fn, + &priv->disp_thread[i].worker, + "crtc_commit:%d", priv->disp_thread[i].crtc_id); + ret = sched_setscheduler(priv->disp_thread[i].thread, + SCHED_FIFO, ¶m); + if (ret) + pr_warn("display thread priority update failed: %d\n", + ret); + + if (IS_ERR(priv->disp_thread[i].thread)) { + dev_err(dev, "failed to create crtc_commit kthread\n"); + priv->disp_thread[i].thread = NULL; + } + + /* initialize event thread */ + priv->event_thread[i].crtc_id = priv->crtcs[i]->base.id; + kthread_init_worker(&priv->event_thread[i].worker); + priv->event_thread[i].dev = ddev; + priv->event_thread[i].thread = + kthread_run(kthread_worker_fn, + &priv->event_thread[i].worker, + "crtc_event:%d", priv->event_thread[i].crtc_id); + /** + * event thread should also run at same priority as disp_thread + * because it is handling frame_done events. A lower priority + * event thread and higher priority disp_thread can causes + * frame_pending counters beyond 2. This can lead to commit + * failure at crtc commit level. + */ + ret = sched_setscheduler(priv->event_thread[i].thread, + SCHED_FIFO, ¶m); + if (ret) + pr_warn("display event thread priority update failed: %d\n", + ret); + + if (IS_ERR(priv->event_thread[i].thread)) { + dev_err(dev, "failed to create crtc_event kthread\n"); + priv->event_thread[i].thread = NULL; + } + + if ((!priv->disp_thread[i].thread) || + !priv->event_thread[i].thread) { + /* clean up previously created threads if any */ + for ( ; i >= 0; i--) { + if (priv->disp_thread[i].thread) { + kthread_stop( + priv->disp_thread[i].thread); + priv->disp_thread[i].thread = NULL; + } + + if (priv->event_thread[i].thread) { + kthread_stop( + priv->event_thread[i].thread); + priv->event_thread[i].thread = NULL; + } + } + goto err_msm_uninit; + } + } + ret = drm_vblank_init(ddev, priv->num_crtcs); if (ret < 0) { dev_err(dev, "failed to initialize vblank\n"); @@ -1060,12 +1169,13 @@ static int add_display_components(struct device *dev, int ret; /* - * MDP5 based devices don't have a flat hierarchy. There is a top level - * parent: MDSS, and children: MDP5, DSI, HDMI, eDP etc. Populate the - * children devices, find the MDP5 node, and then add the interfaces - * to our components list. + * MDP5/DPU based devices don't have a flat hierarchy. There is a top + * level parent: MDSS, and children: MDP5/DPU, DSI, HDMI, eDP etc. + * Populate the children devices, find the MDP5/DPU node, and then add + * the interfaces to our components list. */ - if (of_device_is_compatible(dev->of_node, "qcom,mdss")) { + if (of_device_is_compatible(dev->of_node, "qcom,mdss") || + of_device_is_compatible(dev->of_node, "qcom,sdm845-mdss")) { ret = of_platform_populate(dev->of_node, NULL, NULL, dev); if (ret) { dev_err(dev, "failed to populate children devices\n"); @@ -1177,6 +1287,7 @@ static int msm_pdev_remove(struct platform_device *pdev) static const struct of_device_id dt_match[] = { { .compatible = "qcom,mdp4", .data = (void *)KMS_MDP4 }, { .compatible = "qcom,mdss", .data = (void *)KMS_MDP5 }, + { .compatible = "qcom,sdm845-mdss", .data = (void *)KMS_DPU }, {} }; MODULE_DEVICE_TABLE(of, dt_match); @@ -1198,6 +1309,7 @@ static int __init msm_drm_register(void) DBG("init"); msm_mdp_register(); + msm_dpu_register(); msm_dsi_register(); msm_edp_register(); msm_hdmi_register(); @@ -1214,6 +1326,7 @@ static void __exit msm_drm_unregister(void) msm_edp_unregister(); msm_dsi_unregister(); msm_mdp_unregister(); + msm_dpu_unregister(); } module_init(msm_drm_register); diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 3b206ae6423ff..0cba86ed3f54c 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -1,4 +1,5 @@ /* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> * @@ -33,6 +34,7 @@ #include <linux/of_graph.h> #include <linux/of_device.h> #include <asm/sizes.h> +#include <linux/kthread.h> #include <drm/drmP.h> #include <drm/drm_atomic.h> @@ -55,7 +57,7 @@ struct msm_gem_address_space; struct msm_gem_vma; #define MAX_CRTCS 8 -#define MAX_PLANES 16 +#define MAX_PLANES 20 #define MAX_ENCODERS 8 #define MAX_BRIDGES 8 #define MAX_CONNECTORS 8 @@ -74,12 +76,77 @@ enum msm_mdp_plane_property { }; struct msm_vblank_ctrl { - struct work_struct work; + struct kthread_work work; struct list_head event_list; spinlock_t lock; }; #define MSM_GPU_MAX_RINGS 4 +#define MAX_H_TILES_PER_DISPLAY 2 + +/** + * enum msm_display_caps - features/capabilities supported by displays + * @MSM_DISPLAY_CAP_VID_MODE: Video or "active" mode supported + * @MSM_DISPLAY_CAP_CMD_MODE: Command mode supported + * @MSM_DISPLAY_CAP_HOT_PLUG: Hot plug detection supported + * @MSM_DISPLAY_CAP_EDID: EDID supported + */ +enum msm_display_caps { + MSM_DISPLAY_CAP_VID_MODE = BIT(0), + MSM_DISPLAY_CAP_CMD_MODE = BIT(1), + MSM_DISPLAY_CAP_HOT_PLUG = BIT(2), + MSM_DISPLAY_CAP_EDID = BIT(3), +}; + +/** + * enum msm_event_wait - type of HW events to wait for + * @MSM_ENC_COMMIT_DONE - wait for the driver to flush the registers to HW + * @MSM_ENC_TX_COMPLETE - wait for the HW to transfer the frame to panel + * @MSM_ENC_VBLANK - wait for the HW VBLANK event (for driver-internal waiters) + */ +enum msm_event_wait { + MSM_ENC_COMMIT_DONE = 0, + MSM_ENC_TX_COMPLETE, + MSM_ENC_VBLANK, +}; + +/** + * struct msm_display_topology - defines a display topology pipeline + * @num_lm: number of layer mixers used + * @num_enc: number of compression encoder blocks used + * @num_intf: number of interfaces the panel is mounted on + */ +struct msm_display_topology { + u32 num_lm; + u32 num_enc; + u32 num_intf; +}; + +/** + * struct msm_display_info - defines display properties + * @intf_type: DRM_MODE_CONNECTOR_ display type + * @capabilities: Bitmask of display flags + * @num_of_h_tiles: Number of horizontal tiles in case of split interface + * @h_tile_instance: Controller instance used per tile. Number of elements is + * based on num_of_h_tiles + * @is_te_using_watchdog_timer: Boolean to indicate watchdog TE is + * used instead of panel TE in cmd mode panels + */ +struct msm_display_info { + int intf_type; + uint32_t capabilities; + uint32_t num_of_h_tiles; + uint32_t h_tile_instance[MAX_H_TILES_PER_DISPLAY]; + bool is_te_using_watchdog_timer; +}; + +/* Commit/Event thread specific structure */ +struct msm_drm_thread { + struct drm_device *dev; + struct task_struct *thread; + unsigned int crtc_id; + struct kthread_worker worker; +}; struct msm_drm_private { @@ -90,7 +157,7 @@ struct msm_drm_private { /* subordinate devices, if present: */ struct platform_device *gpu_pdev; - /* top level MDSS wrapper device (for MDP5 only) */ + /* top level MDSS wrapper device (for MDP5/DPU only) */ struct msm_mdss *mdss; /* possibly this should be in the kms component, but it is @@ -128,6 +195,9 @@ struct msm_drm_private { unsigned int num_crtcs; struct drm_crtc *crtcs[MAX_CRTCS]; + struct msm_drm_thread disp_thread[MAX_CRTCS]; + struct msm_drm_thread event_thread[MAX_CRTCS]; + unsigned int num_encoders; struct drm_encoder *encoders[MAX_ENCODERS]; @@ -180,6 +250,9 @@ struct msm_gem_address_space * msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain, const char *name); +int msm_register_mmu(struct drm_device *dev, struct msm_mmu *mmu); +void msm_unregister_mmu(struct drm_device *dev, struct msm_mmu *mmu); + void msm_gem_submit_free(struct msm_gem_submit *submit); int msm_ioctl_gem_submit(struct drm_device *dev, void *data, struct drm_file *file); @@ -291,6 +364,8 @@ static inline int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, void __init msm_mdp_register(void); void __exit msm_mdp_unregister(void); +void __init msm_dpu_register(void); +void __exit msm_dpu_unregister(void); #ifdef CONFIG_DEBUG_FS void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m); diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h index c15de28ae2ddf..fd88cebb6adb3 100644 --- a/drivers/gpu/drm/msm/msm_kms.h +++ b/drivers/gpu/drm/msm/msm_kms.h @@ -1,4 +1,5 @@ /* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> * @@ -51,6 +52,11 @@ struct msm_kms_funcs { const struct msm_format *(*get_format)(struct msm_kms *kms, const uint32_t format, const uint64_t modifiers); + /* do format checking on format modified through fb_cmd2 modifiers */ + int (*check_modified_format)(const struct msm_kms *kms, + const struct msm_format *msm_fmt, + const struct drm_mode_fb_cmd2 *cmd, + struct drm_gem_object **bos); /* misc: */ long (*round_pixclk)(struct msm_kms *kms, unsigned long rate, struct drm_encoder *encoder); @@ -90,6 +96,7 @@ static inline void msm_kms_init(struct msm_kms *kms, struct msm_kms *mdp4_kms_init(struct drm_device *dev); struct msm_kms *mdp5_kms_init(struct drm_device *dev); +struct msm_kms *dpu_kms_init(struct drm_device *dev); struct msm_mdss_funcs { int (*enable)(struct msm_mdss *mdss); @@ -103,5 +110,6 @@ struct msm_mdss { }; int mdp5_mdss_init(struct drm_device *dev); +int dpu_mdss_init(struct drm_device *dev); #endif /* __MSM_KMS_H__ */ -- GitLab From 2f2eb723b50b4da887a34570ff15a3c23d966b85 Mon Sep 17 00:00:00 2001 From: Rajesh Yadav <ryadav@codeaurora.org> Date: Fri, 13 Jul 2018 18:27:23 +0530 Subject: [PATCH 1343/1506] drm/msm: rework vblank event handling in dpu_crtc The vblank on/off calls were missing in dpu_crtc leading to "driver forgot to call drm_crtc_vblank_off()" warning while entering suspend state. Also handle the state update completion event for a crtc being disabled in current atomic commit. This patch depends on https://www.spinics.net/lists/dri-devel/msg182402.html Signed-off-by: Rajesh Yadav <ryadav@codeaurora.org> Signed-off-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index bcc4796cb5da8..7ac0e0dda8664 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -1606,6 +1606,7 @@ static void dpu_crtc_disable(struct drm_crtc *crtc) struct drm_encoder *encoder; struct msm_drm_private *priv; int ret; + unsigned long flags; if (!crtc || !crtc->dev || !crtc->dev->dev_private || !crtc->state) { DPU_ERROR("invalid crtc\n"); @@ -1621,6 +1622,9 @@ static void dpu_crtc_disable(struct drm_crtc *crtc) if (dpu_kms_is_suspend_state(crtc->dev)) _dpu_crtc_set_suspend(crtc, true); + /* Disable/save vblank irq handling */ + drm_crtc_vblank_off(crtc); + mutex_lock(&dpu_crtc->crtc_lock); /* wait for frame_event_done completion */ @@ -1658,7 +1662,6 @@ static void dpu_crtc_disable(struct drm_crtc *crtc) dpu_power_handle_unregister_event(dpu_crtc->phandle, dpu_crtc->power_event); - memset(dpu_crtc->mixers, 0, sizeof(dpu_crtc->mixers)); dpu_crtc->num_mixers = 0; dpu_crtc->mixers_swapped = false; @@ -1668,6 +1671,13 @@ static void dpu_crtc_disable(struct drm_crtc *crtc) cstate->bw_split_vote = false; mutex_unlock(&dpu_crtc->crtc_lock); + + if (crtc->state->event && !crtc->state->active) { + spin_lock_irqsave(&crtc->dev->event_lock, flags); + drm_crtc_send_vblank_event(crtc, crtc->state->event); + crtc->state->event = NULL; + spin_unlock_irqrestore(&crtc->dev->event_lock, flags); + } } static void dpu_crtc_enable(struct drm_crtc *crtc, @@ -1707,6 +1717,9 @@ static void dpu_crtc_enable(struct drm_crtc *crtc, mutex_unlock(&dpu_crtc->crtc_lock); + /* Enable/restore vblank irq handling */ + drm_crtc_vblank_on(crtc); + dpu_crtc->power_event = dpu_power_handle_register_event( dpu_crtc->phandle, DPU_POWER_EVENT_POST_ENABLE | DPU_POWER_EVENT_POST_DISABLE | -- GitLab From 9d248517d4bd807c7690d55d0b6f54618fc60942 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Mon, 23 Jul 2018 16:01:39 +0200 Subject: [PATCH 1344/1506] drm/amdgpu: add support for inplace IB patching for MM engines v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are going to need that for the second UVD instance on Vega20. v2: rename to patch_cs_in_place Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-and-tested-by: James Zhu <James.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 1 + drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 22 +++++++++++++++------- drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h | 1 + 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 0283e2b3c851a..1f6345dda6ead 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1748,6 +1748,7 @@ amdgpu_get_sdma_instance(struct amdgpu_ring *ring) #define amdgpu_vm_write_pte(adev, ib, pe, value, count, incr) ((adev)->vm_manager.vm_pte_funcs->write_pte((ib), (pe), (value), (count), (incr))) #define amdgpu_vm_set_pte_pde(adev, ib, pe, addr, count, incr, flags) ((adev)->vm_manager.vm_pte_funcs->set_pte_pde((ib), (pe), (addr), (count), (incr), (flags))) #define amdgpu_ring_parse_cs(r, p, ib) ((r)->funcs->parse_cs((p), (ib))) +#define amdgpu_ring_patch_cs_in_place(r, p, ib) ((r)->funcs->patch_cs_in_place((p), (ib))) #define amdgpu_ring_test_ring(r) (r)->funcs->test_ring((r)) #define amdgpu_ring_test_ib(r, t) (r)->funcs->test_ib((r), (t)) #define amdgpu_ring_get_rptr(r) (r)->funcs->get_rptr((r)) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 178d9ce4eba1f..533b2e7656c05 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -916,7 +916,7 @@ static int amdgpu_cs_ib_vm_chunk(struct amdgpu_device *adev, int r; /* Only for UVD/VCE VM emulation */ - if (p->ring->funcs->parse_cs) { + if (p->ring->funcs->parse_cs || p->ring->funcs->patch_cs_in_place) { unsigned i, j; for (i = 0, j = 0; i < p->nchunks && j < p->job->num_ibs; i++) { @@ -957,12 +957,20 @@ static int amdgpu_cs_ib_vm_chunk(struct amdgpu_device *adev, offset = m->start * AMDGPU_GPU_PAGE_SIZE; kptr += va_start - offset; - memcpy(ib->ptr, kptr, chunk_ib->ib_bytes); - amdgpu_bo_kunmap(aobj); - - r = amdgpu_ring_parse_cs(ring, p, j); - if (r) - return r; + if (p->ring->funcs->parse_cs) { + memcpy(ib->ptr, kptr, chunk_ib->ib_bytes); + amdgpu_bo_kunmap(aobj); + + r = amdgpu_ring_parse_cs(ring, p, j); + if (r) + return r; + } else { + ib->ptr = (uint32_t *)kptr; + r = amdgpu_ring_patch_cs_in_place(ring, p, j); + amdgpu_bo_kunmap(aobj); + if (r) + return r; + } j++; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h index 5018c0b6bf1a4..d242b9a51e90f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h @@ -123,6 +123,7 @@ struct amdgpu_ring_funcs { void (*set_wptr)(struct amdgpu_ring *ring); /* validating and patching of IBs */ int (*parse_cs)(struct amdgpu_cs_parser *p, uint32_t ib_idx); + int (*patch_cs_in_place)(struct amdgpu_cs_parser *p, uint32_t ib_idx); /* constants to calculate how many DW are needed for an emit */ unsigned emit_frame_size; unsigned emit_ib_size; -- GitLab From 66c28d6df2d8292098839d365b82a1e30b567211 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Wed, 18 Jul 2018 14:52:42 +0200 Subject: [PATCH 1345/1506] drm/amdgpu: patch the IBs for the second UVD instance v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Patch the IBs for the second UVD instance so that userspace don't need to care about the instance they submit to. v2: use direct IB patching Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Reviewed-and-tested-by: James Zhu <James.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c | 29 +++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c index db5f3d78ab12a..d74c1b2426676 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c @@ -1205,6 +1205,34 @@ static int uvd_v7_0_ring_test_ring(struct amdgpu_ring *ring) return r; } +/** + * uvd_v7_0_ring_patch_cs_in_place - Patch the IB for command submission. + * + * @p: the CS parser with the IBs + * @ib_idx: which IB to patch + * + */ +static int uvd_v7_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p, + uint32_t ib_idx) +{ + struct amdgpu_ib *ib = &p->job->ibs[ib_idx]; + unsigned i; + + /* No patching necessary for the first instance */ + if (!p->ring->me) + return 0; + + for (i = 0; i < ib->length_dw; i += 2) { + uint32_t reg = amdgpu_get_ib_value(p, ib_idx, i); + + reg -= p->adev->reg_offset[UVD_HWIP][0][1]; + reg += p->adev->reg_offset[UVD_HWIP][1][1]; + + amdgpu_set_ib_value(p, ib_idx, i, reg); + } + return 0; +} + /** * uvd_v7_0_ring_emit_ib - execute indirect buffer * @@ -1697,6 +1725,7 @@ static const struct amdgpu_ring_funcs uvd_v7_0_ring_vm_funcs = { .get_rptr = uvd_v7_0_ring_get_rptr, .get_wptr = uvd_v7_0_ring_get_wptr, .set_wptr = uvd_v7_0_ring_set_wptr, + .patch_cs_in_place = uvd_v7_0_ring_patch_cs_in_place, .emit_frame_size = 6 + /* hdp invalidate */ SOC15_FLUSH_GPU_TLB_NUM_WREG * 6 + -- GitLab From 824474ba38e27ccacc9d2dd066f780e9b3c2ad78 Mon Sep 17 00:00:00 2001 From: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com> Date: Fri, 13 Jul 2018 18:00:06 -0400 Subject: [PATCH 1346/1506] drm/amd/display: Retry link training again [Why] Some receivers seem to fail the first link training but are good on subsequent tries. We want to retry link training again. This fixes HTC vive pro not lighting up after being disabled. [How] Check if the link training passed without fall back if this is not the case then we retry link training. Signed-off-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com> Reviewed-by: Harry Wentland <Harry.Wentland@amd.com> Acked-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 20 +++++++++++++++++-- .../gpu/drm/amd/display/dc/core/dc_link_dp.c | 5 ++++- .../gpu/drm/amd/display/dc/inc/dc_link_dp.h | 3 ++- 3 files changed, 24 insertions(+), 4 deletions(-) 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 388a0635c38d5..966d2f9c8c995 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -60,7 +60,14 @@ enum { LINK_RATE_REF_FREQ_IN_MHZ = 27, - PEAK_FACTOR_X1000 = 1006 + PEAK_FACTOR_X1000 = 1006, + /* + * Some receivers fail to train on first try and are good + * on subsequent tries. 2 retries should be plenty. If we + * don't have a successful training then we don't expect to + * ever get one. + */ + LINK_TRAINING_MAX_VERIFY_RETRY = 2 }; /******************************************************************************* @@ -760,7 +767,16 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) */ /* deal with non-mst cases */ - dp_verify_link_cap(link, &link->reported_link_cap); + for (i = 0; i < LINK_TRAINING_MAX_VERIFY_RETRY; i++) { + int fail_count = 0; + + dp_verify_link_cap(link, + &link->reported_link_cap, + &fail_count); + + if (fail_count == 0) + break; + } } /* HDMI-DVI Dongle */ 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 9d901ca705883..58ee9aad13fb6 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 @@ -1088,7 +1088,8 @@ static struct dc_link_settings get_max_link_cap(struct dc_link *link) bool dp_verify_link_cap( struct dc_link *link, - struct dc_link_settings *known_limit_link_setting) + struct dc_link_settings *known_limit_link_setting, + int *fail_count) { struct dc_link_settings max_link_cap = {0}; struct dc_link_settings cur_link_setting = {0}; @@ -1160,6 +1161,8 @@ bool dp_verify_link_cap( skip_video_pattern); if (status == LINK_TRAINING_SUCCESS) success = true; + else + (*fail_count)++; } if (success) diff --git a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h index 697b5ee738451..a37255c757e0c 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h @@ -35,7 +35,8 @@ struct dc_link_settings; bool dp_verify_link_cap( struct dc_link *link, - struct dc_link_settings *known_limit_link_setting); + struct dc_link_settings *known_limit_link_setting, + int *fail_count); bool dp_validate_mode_timing( struct dc_link *link, -- GitLab From 65c78961b30005447a0d9b285de93354d8308f34 Mon Sep 17 00:00:00 2001 From: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com> Date: Thu, 28 Jun 2018 17:50:05 -0400 Subject: [PATCH 1347/1506] drm/amd/display: flatten aux_engine and engine [Why] engine and aux_engine are unnecessary layers we want to remove this layer. [How] flatten engine and aux engine structs into one struct called aux_engine and remove all references to the engine struct. Signed-off-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com> Reviewed-by: Harry Wentland <Harry.Wentland@amd.com> Acked-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../gpu/drm/amd/display/dc/core/dc_link_ddc.c | 8 +- drivers/gpu/drm/amd/display/dc/dce/dce_aux.c | 55 ++++---- drivers/gpu/drm/amd/display/dc/dce/dce_aux.h | 4 +- .../amd/display/dc/dce100/dce100_resource.c | 4 +- .../amd/display/dc/dce110/dce110_resource.c | 4 +- .../amd/display/dc/dce112/dce112_resource.c | 4 +- .../amd/display/dc/dce120/dce120_resource.c | 4 +- .../drm/amd/display/dc/dce80/dce80_resource.c | 4 +- .../drm/amd/display/dc/dcn10/dcn10_resource.c | 4 +- .../gpu/drm/amd/display/dc/inc/core_types.h | 2 +- .../drm/amd/display/dc/inc/hw/aux_engine.h | 127 +++++++++++++----- .../gpu/drm/amd/display/dc/inc/hw/engine.h | 106 --------------- 12 files changed, 140 insertions(+), 186 deletions(-) delete mode 100644 drivers/gpu/drm/amd/display/dc/inc/hw/engine.h diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c index 4019fe07d291e..8def0d9fa0ff0 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c @@ -33,7 +33,6 @@ #include "include/vector.h" #include "core_types.h" #include "dc_link_ddc.h" -#include "engine.h" #include "aux_engine.h" #define AUX_POWER_UP_WA_DELAY 500 @@ -640,7 +639,6 @@ int dc_link_aux_transfer(struct ddc_service *ddc, enum i2caux_transaction_action action) { struct ddc *ddc_pin = ddc->ddc_pin; - struct engine *engine; struct aux_engine *aux_engine; enum aux_channel_operation_result operation_result; struct aux_request_transaction_data aux_req; @@ -652,8 +650,8 @@ int dc_link_aux_transfer(struct ddc_service *ddc, memset(&aux_req, 0, sizeof(aux_req)); memset(&aux_rep, 0, sizeof(aux_rep)); - engine = ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]; - aux_engine = engine->funcs->acquire(engine, ddc_pin); + aux_engine = ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]; + aux_engine->funcs->acquire(aux_engine, ddc_pin); aux_req.type = type; aux_req.action = action; @@ -685,7 +683,7 @@ int dc_link_aux_transfer(struct ddc_service *ddc, res = -1; break; } - aux_engine->base.funcs->release_engine(&aux_engine->base); + aux_engine->funcs->release_engine(aux_engine); return res; } diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c index b28e2120767e2..3f5b2e6f7553f 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c @@ -28,12 +28,12 @@ #include "dce/dce_11_0_sh_mask.h" #define CTX \ - aux110->base.base.ctx + aux110->base.ctx #define REG(reg_name)\ (aux110->regs->reg_name) #define DC_LOGGER \ - engine->base.ctx->logger + engine->ctx->logger #include "reg_helper.h" @@ -51,9 +51,9 @@ enum { AUX_DEFER_RETRY_COUNTER = 6 }; static void release_engine( - struct engine *engine) + struct aux_engine *engine) { - struct aux_engine_dce110 *aux110 = FROM_ENGINE(engine); + struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine); dal_ddc_close(engine->ddc); @@ -827,22 +827,21 @@ static bool end_of_transaction_command( /* according Syed, it does not need now DoDummyMOT */ } -bool submit_request( - struct engine *engine, +static bool submit_request( + struct aux_engine *engine, struct i2caux_transaction_request *request, bool middle_of_transaction) { - struct aux_engine *aux_engine = FROM_AUX_ENGINE_ENGINE(engine); bool result; bool mot_used = true; switch (request->operation) { case I2CAUX_TRANSACTION_READ: - result = read_command(aux_engine, request, mot_used); + result = read_command(engine, request, mot_used); break; case I2CAUX_TRANSACTION_WRITE: - result = write_command(aux_engine, request, mot_used); + result = write_command(engine, request, mot_used); break; default: result = false; @@ -854,45 +853,45 @@ bool submit_request( */ if (!middle_of_transaction || !result) - end_of_transaction_command(aux_engine, request); + end_of_transaction_command(engine, request); /* mask AUX interrupt */ return result; } enum i2caux_engine_type get_engine_type( - const struct engine *engine) + const struct aux_engine *engine) { return I2CAUX_ENGINE_TYPE_AUX; } -static struct aux_engine *acquire( - struct engine *engine, +static bool acquire( + struct aux_engine *engine, struct ddc *ddc) { - struct aux_engine *aux_engine = FROM_AUX_ENGINE_ENGINE(engine); + enum gpio_result result; - if (aux_engine->funcs->is_engine_available) { + if (engine->funcs->is_engine_available) { /*check whether SW could use the engine*/ - if (!aux_engine->funcs->is_engine_available(aux_engine)) - return NULL; + if (!engine->funcs->is_engine_available(engine)) + return false; } result = dal_ddc_open(ddc, GPIO_MODE_HARDWARE, GPIO_DDC_CONFIG_TYPE_MODE_AUX); if (result != GPIO_RESULT_OK) - return NULL; + return false; - if (!aux_engine->funcs->acquire_engine(aux_engine)) { + if (!engine->funcs->acquire_engine(engine)) { dal_ddc_close(ddc); - return NULL; + return false; } engine->ddc = ddc; - return aux_engine; + return true; } static const struct aux_engine_funcs aux_engine_funcs = { @@ -902,9 +901,6 @@ static const struct aux_engine_funcs aux_engine_funcs = { .read_channel_reply = read_channel_reply, .get_channel_status = get_channel_status, .is_engine_available = is_engine_available, -}; - -static const struct engine_funcs engine_funcs = { .release_engine = release_engine, .destroy_engine = dce110_engine_destroy, .submit_request = submit_request, @@ -912,10 +908,10 @@ static const struct engine_funcs engine_funcs = { .acquire = acquire, }; -void dce110_engine_destroy(struct engine **engine) +void dce110_engine_destroy(struct aux_engine **engine) { - struct aux_engine_dce110 *engine110 = FROM_ENGINE(*engine); + struct aux_engine_dce110 *engine110 = FROM_AUX_ENGINE(*engine); kfree(engine110); *engine = NULL; @@ -927,13 +923,12 @@ struct aux_engine *dce110_aux_engine_construct(struct aux_engine_dce110 *aux_eng uint32_t timeout_period, const struct dce110_aux_registers *regs) { - aux_engine110->base.base.ddc = NULL; - aux_engine110->base.base.ctx = ctx; + aux_engine110->base.ddc = NULL; + aux_engine110->base.ctx = ctx; aux_engine110->base.delay = 0; aux_engine110->base.max_defer_write_retry = 0; - aux_engine110->base.base.funcs = &engine_funcs; aux_engine110->base.funcs = &aux_engine_funcs; - aux_engine110->base.base.inst = inst; + aux_engine110->base.inst = inst; aux_engine110->timeout_period = timeout_period; aux_engine110->regs = regs; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h index c6b2aec2e367e..f7caab85dc801 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h @@ -103,9 +103,9 @@ struct aux_engine *dce110_aux_engine_construct( uint32_t timeout_period, const struct dce110_aux_registers *regs); -void dce110_engine_destroy(struct engine **engine); +void dce110_engine_destroy(struct aux_engine **engine); bool dce110_aux_engine_acquire( - struct engine *aux_engine, + struct aux_engine *aux_engine, struct ddc *ddc); #endif diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c index c34c9531915ef..fd2bdae4dcec7 100644 --- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c @@ -586,7 +586,7 @@ struct output_pixel_processor *dce100_opp_create( return &opp->base; } -struct engine *dce100_aux_engine_create( +struct aux_engine *dce100_aux_engine_create( struct dc_context *ctx, uint32_t inst) { @@ -600,7 +600,7 @@ struct engine *dce100_aux_engine_create( SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, &aux_engine_regs[inst]); - return &aux_engine->base.base; + return &aux_engine->base; } struct clock_source *dce100_clock_source_create( diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c index 4a665a29191bc..e5e9e92521e91 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c @@ -604,7 +604,7 @@ static struct output_pixel_processor *dce110_opp_create( return &opp->base; } -struct engine *dce110_aux_engine_create( +struct aux_engine *dce110_aux_engine_create( struct dc_context *ctx, uint32_t inst) { @@ -618,7 +618,7 @@ struct engine *dce110_aux_engine_create( SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, &aux_engine_regs[inst]); - return &aux_engine->base.base; + return &aux_engine->base; } struct clock_source *dce110_clock_source_create( diff --git a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c index caf90ae2cbb04..84a05ff2d6748 100644 --- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c @@ -604,7 +604,7 @@ struct output_pixel_processor *dce112_opp_create( return &opp->base; } -struct engine *dce112_aux_engine_create( +struct aux_engine *dce112_aux_engine_create( struct dc_context *ctx, uint32_t inst) { @@ -618,7 +618,7 @@ struct engine *dce112_aux_engine_create( SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, &aux_engine_regs[inst]); - return &aux_engine->base.base; + return &aux_engine->base; } struct clock_source *dce112_clock_source_create( diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c index f7d02f2190d3e..61d8e22d23c95 100644 --- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c @@ -376,7 +376,7 @@ struct output_pixel_processor *dce120_opp_create( ctx, inst, &opp_regs[inst], &opp_shift, &opp_mask); return &opp->base; } -struct engine *dce120_aux_engine_create( +struct aux_engine *dce120_aux_engine_create( struct dc_context *ctx, uint32_t inst) { @@ -390,7 +390,7 @@ struct engine *dce120_aux_engine_create( SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, &aux_engine_regs[inst]); - return &aux_engine->base.base; + return &aux_engine->base; } static const struct bios_registers bios_regs = { diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c index 6fb33ad2d3c80..dc9f3e9afc338 100644 --- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c @@ -464,7 +464,7 @@ static struct output_pixel_processor *dce80_opp_create( return &opp->base; } -struct engine *dce80_aux_engine_create( +struct aux_engine *dce80_aux_engine_create( struct dc_context *ctx, uint32_t inst) { @@ -478,7 +478,7 @@ struct engine *dce80_aux_engine_create( SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, &aux_engine_regs[inst]); - return &aux_engine->base.base; + return &aux_engine->base; } static struct stream_encoder *dce80_stream_encoder_create( diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c index cd8c22839227a..5d169f07d745f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c @@ -594,7 +594,7 @@ static struct output_pixel_processor *dcn10_opp_create( return &opp->base; } -struct engine *dcn10_aux_engine_create( +struct aux_engine *dcn10_aux_engine_create( struct dc_context *ctx, uint32_t inst) { @@ -608,7 +608,7 @@ struct engine *dcn10_aux_engine_create( SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, &aux_engine_regs[inst]); - return &aux_engine->base.base; + return &aux_engine->base; } static struct mpc *dcn10_mpc_create(struct dc_context *ctx) diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h index 0fa385872ed33..9f33306f9014f 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h @@ -138,7 +138,7 @@ struct resource_pool { struct output_pixel_processor *opps[MAX_PIPES]; struct timing_generator *timing_generators[MAX_PIPES]; struct stream_encoder *stream_enc[MAX_PIPES * 2]; - struct engine *engines[MAX_PIPES]; + struct aux_engine *engines[MAX_PIPES]; struct hubbub *hubbub; struct mpc *mpc; struct pp_smu_funcs_rv *pp_smu; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/aux_engine.h b/drivers/gpu/drm/amd/display/dc/inc/hw/aux_engine.h index 06d7e5d4cf21d..e79cd4e929194 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/aux_engine.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/aux_engine.h @@ -26,46 +26,72 @@ #ifndef __DAL_AUX_ENGINE_H__ #define __DAL_AUX_ENGINE_H__ -#include "engine.h" +#include "dc_ddc_types.h" #include "include/i2caux_interface.h" -struct aux_engine; -union aux_config; -struct aux_engine_funcs { - void (*destroy)( - struct aux_engine **ptr); - bool (*acquire_engine)( - struct aux_engine *engine); - void (*configure)( - struct aux_engine *engine, - union aux_config cfg); - void (*submit_channel_request)( - struct aux_engine *engine, - struct aux_request_transaction_data *request); - void (*process_channel_reply)( - struct aux_engine *engine, - struct aux_reply_transaction_data *reply); - int (*read_channel_reply)( - struct aux_engine *engine, - uint32_t size, - uint8_t *buffer, - uint8_t *reply_result, - uint32_t *sw_status); - enum aux_channel_operation_result (*get_channel_status)( - struct aux_engine *engine, - uint8_t *returned_bytes); - bool (*is_engine_available)(struct aux_engine *engine); +enum i2caux_transaction_operation { + I2CAUX_TRANSACTION_READ, + I2CAUX_TRANSACTION_WRITE +}; + +enum i2caux_transaction_address_space { + I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C = 1, + I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD +}; + +struct i2caux_transaction_payload { + enum i2caux_transaction_address_space address_space; + uint32_t address; + uint32_t length; + uint8_t *data; +}; + +enum i2caux_transaction_status { + I2CAUX_TRANSACTION_STATUS_UNKNOWN = (-1L), + I2CAUX_TRANSACTION_STATUS_SUCCEEDED, + I2CAUX_TRANSACTION_STATUS_FAILED_CHANNEL_BUSY, + I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT, + I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR, + I2CAUX_TRANSACTION_STATUS_FAILED_NACK, + I2CAUX_TRANSACTION_STATUS_FAILED_INCOMPLETE, + I2CAUX_TRANSACTION_STATUS_FAILED_OPERATION, + I2CAUX_TRANSACTION_STATUS_FAILED_INVALID_OPERATION, + I2CAUX_TRANSACTION_STATUS_FAILED_BUFFER_OVERFLOW, + I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON +}; + +struct i2caux_transaction_request { + enum i2caux_transaction_operation operation; + struct i2caux_transaction_payload payload; + enum i2caux_transaction_status status; +}; + +enum i2caux_engine_type { + I2CAUX_ENGINE_TYPE_UNKNOWN = (-1L), + I2CAUX_ENGINE_TYPE_AUX, + I2CAUX_ENGINE_TYPE_I2C_DDC_HW, + I2CAUX_ENGINE_TYPE_I2C_GENERIC_HW, + I2CAUX_ENGINE_TYPE_I2C_SW +}; + +enum i2c_default_speed { + I2CAUX_DEFAULT_I2C_HW_SPEED = 50, + I2CAUX_DEFAULT_I2C_SW_SPEED = 50 }; -struct engine; + +union aux_config; + struct aux_engine { - struct engine base; + uint32_t inst; + struct ddc *ddc; + struct dc_context *ctx; const struct aux_engine_funcs *funcs; /* following values are expressed in milliseconds */ uint32_t delay; uint32_t max_defer_write_retry; - bool acquire_reset; }; + struct read_command_context { uint8_t *buffer; uint32_t current_read_length; @@ -86,6 +112,7 @@ struct read_command_context { bool transaction_complete; bool operation_succeeded; }; + struct write_command_context { bool mot; @@ -110,4 +137,44 @@ struct write_command_context { bool transaction_complete; bool operation_succeeded; }; + + +struct aux_engine_funcs { + void (*destroy)( + struct aux_engine **ptr); + bool (*acquire_engine)( + struct aux_engine *engine); + void (*configure)( + struct aux_engine *engine, + union aux_config cfg); + void (*submit_channel_request)( + struct aux_engine *engine, + struct aux_request_transaction_data *request); + void (*process_channel_reply)( + struct aux_engine *engine, + struct aux_reply_transaction_data *reply); + int (*read_channel_reply)( + struct aux_engine *engine, + uint32_t size, + uint8_t *buffer, + uint8_t *reply_result, + uint32_t *sw_status); + enum aux_channel_operation_result (*get_channel_status)( + struct aux_engine *engine, + uint8_t *returned_bytes); + bool (*is_engine_available)(struct aux_engine *engine); + enum i2caux_engine_type (*get_engine_type)( + const struct aux_engine *engine); + bool (*acquire)( + struct aux_engine *engine, + struct ddc *ddc); + bool (*submit_request)( + struct aux_engine *engine, + struct i2caux_transaction_request *request, + bool middle_of_transaction); + void (*release_engine)( + struct aux_engine *engine); + void (*destroy_engine)( + struct aux_engine **engine); +}; #endif diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/engine.h b/drivers/gpu/drm/amd/display/dc/inc/hw/engine.h deleted file mode 100644 index 1f5476f412363..0000000000000 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/engine.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __DAL_ENGINE_H__ -#define __DAL_ENGINE_H__ - -#include "dc_ddc_types.h" - -enum i2caux_transaction_operation { - I2CAUX_TRANSACTION_READ, - I2CAUX_TRANSACTION_WRITE -}; - -enum i2caux_transaction_address_space { - I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C = 1, - I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD -}; - -struct i2caux_transaction_payload { - enum i2caux_transaction_address_space address_space; - uint32_t address; - uint32_t length; - uint8_t *data; -}; - -enum i2caux_transaction_status { - I2CAUX_TRANSACTION_STATUS_UNKNOWN = (-1L), - I2CAUX_TRANSACTION_STATUS_SUCCEEDED, - I2CAUX_TRANSACTION_STATUS_FAILED_CHANNEL_BUSY, - I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT, - I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR, - I2CAUX_TRANSACTION_STATUS_FAILED_NACK, - I2CAUX_TRANSACTION_STATUS_FAILED_INCOMPLETE, - I2CAUX_TRANSACTION_STATUS_FAILED_OPERATION, - I2CAUX_TRANSACTION_STATUS_FAILED_INVALID_OPERATION, - I2CAUX_TRANSACTION_STATUS_FAILED_BUFFER_OVERFLOW, - I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON -}; - -struct i2caux_transaction_request { - enum i2caux_transaction_operation operation; - struct i2caux_transaction_payload payload; - enum i2caux_transaction_status status; -}; - -enum i2caux_engine_type { - I2CAUX_ENGINE_TYPE_UNKNOWN = (-1L), - I2CAUX_ENGINE_TYPE_AUX, - I2CAUX_ENGINE_TYPE_I2C_DDC_HW, - I2CAUX_ENGINE_TYPE_I2C_GENERIC_HW, - I2CAUX_ENGINE_TYPE_I2C_SW -}; - -enum i2c_default_speed { - I2CAUX_DEFAULT_I2C_HW_SPEED = 50, - I2CAUX_DEFAULT_I2C_SW_SPEED = 50 -}; - -struct engine; - -struct engine_funcs { - enum i2caux_engine_type (*get_engine_type)( - const struct engine *engine); - struct aux_engine* (*acquire)( - struct engine *engine, - struct ddc *ddc); - bool (*submit_request)( - struct engine *engine, - struct i2caux_transaction_request *request, - bool middle_of_transaction); - void (*release_engine)( - struct engine *engine); - void (*destroy_engine)( - struct engine **engine); -}; - -struct engine { - const struct engine_funcs *funcs; - uint32_t inst; - struct ddc *ddc; - struct dc_context *ctx; -}; - -#endif -- GitLab From f358b39d187500717b4bc8633cef45d87eff0a3e Mon Sep 17 00:00:00 2001 From: "Jerry (Fangzhi) Zuo" <Jerry.Zuo@amd.com> Date: Tue, 17 Jul 2018 11:53:54 -0400 Subject: [PATCH 1348/1506] drm/amd/display: Fix Vega10 black screen after mode change [Why] The sequence is slightly changed when bring .set_bandwidth out from the end of programming backend to the end of programming surface. Vega10 doesn't like to get clocks updated if stream_count is zero in the current context (Atomic Reset). [How] Do not update clocks if no stream is showing up in the context. Fixes 1b2b130192 "dc: Remove 300Mhz minimum disp clk limit." Signed-off-by: Jerry (Fangzhi) Zuo <Jerry.Zuo@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../drm/amd/display/dc/dce110/dce110_hw_sequencer.c | 2 +- .../drm/amd/display/dc/dce110/dce110_hw_sequencer.h | 5 +++++ .../drm/amd/display/dc/dce120/dce120_hw_sequencer.c | 10 ++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) 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 33a14e163f880..1149c413f6d23 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 @@ -2552,7 +2552,7 @@ static void pplib_apply_display_requirements( dc->prev_display_config = *pp_display_cfg; } -static void dce110_set_bandwidth( +void dce110_set_bandwidth( struct dc *dc, struct dc_state *context, bool decrease_allowed) diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h index d6db3dbd90153..e4c5db75c4c65 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h @@ -68,6 +68,11 @@ void dce110_fill_display_configs( const struct dc_state *context, struct dm_pp_display_configuration *pp_display_cfg); +void dce110_set_bandwidth( + struct dc *dc, + struct dc_state *context, + bool decrease_allowed); + uint32_t dce110_get_min_vblank_time_us(const struct dc_state *context); void dp_receiver_power_ctrl(struct dc_link *link, bool on); diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.c index e96ff86d2fc3b..5853522a61829 100644 --- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.c @@ -244,7 +244,16 @@ static void dce120_update_dchub( dh_data->dchub_info_valid = false; } +static void dce120_set_bandwidth( + struct dc *dc, + struct dc_state *context, + bool decrease_allowed) +{ + if (context->stream_count <= 0) + return; + dce110_set_bandwidth(dc, context, decrease_allowed); +} void dce120_hw_sequencer_construct(struct dc *dc) { @@ -254,5 +263,6 @@ void dce120_hw_sequencer_construct(struct dc *dc) dce110_hw_sequencer_construct(dc); dc->hwss.enable_display_power_gating = dce120_enable_display_power_gating; dc->hwss.update_dchub = dce120_update_dchub; + dc->hwss.set_bandwidth = dce120_set_bandwidth; } -- GitLab From 9907704174e0ad4ed02766fac4049971e583323d Mon Sep 17 00:00:00 2001 From: Anthony Koo <Anthony.Koo@amd.com> Date: Tue, 17 Jul 2018 09:43:44 -0400 Subject: [PATCH 1349/1506] drm/amd/display: Prevent PSR from being enabled if initialization fails [Why] PSR_SET command is sent to the microcontroller in order to initialize parameters needed for PSR feature, such as telling the microcontroller which pipe is driving the PSR supported panel. When this command is skipped or fails, the microcontroller may program the wrong thing if driver tries to enable PSR. [How] If PSR_SET fails, do not set psr_enable flag to indicate the feature is not yet initialized. Signed-off-by: Anthony Koo <Anthony.Koo@amd.com> Reviewed-by: Aric Cyr <Aric.Cyr@amd.com> Acked-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c | 38 +++++++++++-------- drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h | 2 +- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c index 062a46543887a..ca7989e4932bd 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c @@ -150,7 +150,7 @@ static void dce_dmcu_set_psr_enable(struct dmcu *dmcu, bool enable, bool wait) } } -static void dce_dmcu_setup_psr(struct dmcu *dmcu, +static bool dce_dmcu_setup_psr(struct dmcu *dmcu, struct dc_link *link, struct psr_context *psr_context) { @@ -261,6 +261,8 @@ static void dce_dmcu_setup_psr(struct dmcu *dmcu, /* notifyDMCUMsg */ REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1); + + return true; } static bool dce_is_dmcu_initialized(struct dmcu *dmcu) @@ -545,24 +547,25 @@ static void dcn10_dmcu_set_psr_enable(struct dmcu *dmcu, bool enable, bool wait) * least a few frames. Should never hit the max retry assert below. */ if (wait == true) { - for (retryCount = 0; retryCount <= 1000; retryCount++) { - dcn10_get_dmcu_psr_state(dmcu, &psr_state); - if (enable) { - if (psr_state != 0) - break; - } else { - if (psr_state == 0) - break; + for (retryCount = 0; retryCount <= 1000; retryCount++) { + dcn10_get_dmcu_psr_state(dmcu, &psr_state); + if (enable) { + if (psr_state != 0) + break; + } else { + if (psr_state == 0) + break; + } + udelay(500); } - udelay(500); - } - /* assert if max retry hit */ - ASSERT(retryCount <= 1000); + /* assert if max retry hit */ + if (retryCount >= 1000) + ASSERT(0); } } -static void dcn10_dmcu_setup_psr(struct dmcu *dmcu, +static bool dcn10_dmcu_setup_psr(struct dmcu *dmcu, struct dc_link *link, struct psr_context *psr_context) { @@ -577,7 +580,7 @@ static void dcn10_dmcu_setup_psr(struct dmcu *dmcu, /* If microcontroller is not running, do nothing */ if (dmcu->dmcu_state != DMCU_RUNNING) - return; + return false; link->link_enc->funcs->psr_program_dp_dphy_fast_training(link->link_enc, psr_context->psrExitLinkTrainingRequired); @@ -677,6 +680,11 @@ static void dcn10_dmcu_setup_psr(struct dmcu *dmcu, /* notifyDMCUMsg */ REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1); + + /* waitDMCUReadyForCmd */ + REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 1, 10000); + + return true; } static void dcn10_psr_wait_loop( diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h index de60f940030da..4550747fb61c2 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h @@ -48,7 +48,7 @@ struct dmcu_funcs { const char *src, unsigned int bytes); void (*set_psr_enable)(struct dmcu *dmcu, bool enable, bool wait); - void (*setup_psr)(struct dmcu *dmcu, + bool (*setup_psr)(struct dmcu *dmcu, struct dc_link *link, struct psr_context *psr_context); void (*get_psr_state)(struct dmcu *dmcu, uint32_t *psr_state); -- GitLab From 116f451c90a94de6203757c117278b99a837d3b5 Mon Sep 17 00:00:00 2001 From: Harry Wentland <harry.wentland@amd.com> Date: Mon, 9 Jul 2018 17:26:34 -0400 Subject: [PATCH 1350/1506] drm/amd/display: DC 3.1.59 Signed-off-by: Harry Wentland <harry.wentland@amd.com> Reviewed-by: Aric Cyr <Aric.Cyr@amd.com> Acked-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 7515c0dcbdd24..c2d390fba0bf0 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.1.58" +#define DC_VER "3.1.59" #define MAX_SURFACES 3 #define MAX_STREAMS 6 -- GitLab From d04cc604a66b07eff8fce824fb6c0fdc0875d2e3 Mon Sep 17 00:00:00 2001 From: Harry Wentland <harry.wentland@amd.com> Date: Wed, 25 Jul 2018 09:45:47 -0400 Subject: [PATCH 1351/1506] drm/amd: Add missing fields in atom_integrated_system_info_v1_11 This structure needs to align with structure in atomfirmware table. Update it. Signed-off-by: Harry Wentland <harry.wentland@amd.com> Acked-by: Alex Deucher <alexander.deucher@amd.com> Reviewed-by: Dmytro Laktyushkin <dmytro.laktyushkin@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/include/atomfirmware.h | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/include/atomfirmware.h b/drivers/gpu/drm/amd/include/atomfirmware.h index 33b4de4ad66eb..4bc118df3bc48 100644 --- a/drivers/gpu/drm/amd/include/atomfirmware.h +++ b/drivers/gpu/drm/amd/include/atomfirmware.h @@ -1074,7 +1074,7 @@ struct atom_integrated_system_info_v1_11 uint16_t dpphy_override; // bit vector, enum of atom_sysinfo_dpphy_override_def uint16_t lvds_misc; // enum of atom_sys_info_lvds_misc_def uint16_t backlight_pwm_hz; // pwm frequency in hz - uint8_t memorytype; // enum of atom_sys_mem_type + uint8_t memorytype; // enum of atom_dmi_t17_mem_type_def, APU memory type indication. uint8_t umachannelnumber; // number of memory channels uint8_t pwr_on_digon_to_de; /* all pwr sequence numbers below are in uint of 4ms */ uint8_t pwr_on_de_to_vary_bl; @@ -1084,18 +1084,25 @@ struct atom_integrated_system_info_v1_11 uint8_t pwr_on_vary_bl_to_blon; uint8_t pwr_down_bloff_to_vary_bloff; uint8_t min_allowed_bl_level; + uint8_t htc_hyst_limit; + uint8_t htc_tmp_limit; + uint8_t reserved1; + uint8_t reserved2; struct atom_external_display_connection_info extdispconninfo; struct atom_14nm_dpphy_dvihdmi_tuningset dvi_tuningset; struct atom_14nm_dpphy_dvihdmi_tuningset hdmi_tuningset; struct atom_14nm_dpphy_dvihdmi_tuningset hdmi6g_tuningset; - struct atom_14nm_dpphy_dp_tuningset dp_tuningset; - struct atom_14nm_dpphy_dp_tuningset dp_hbr3_tuningset; + struct atom_14nm_dpphy_dp_tuningset dp_tuningset; // rbr 1.62G dp tuning set + struct atom_14nm_dpphy_dp_tuningset dp_hbr3_tuningset; // HBR3 dp tuning set struct atom_camera_data camera_info; struct atom_hdmi_retimer_redriver_set dp0_retimer_set; //for DP0 struct atom_hdmi_retimer_redriver_set dp1_retimer_set; //for DP1 struct atom_hdmi_retimer_redriver_set dp2_retimer_set; //for DP2 struct atom_hdmi_retimer_redriver_set dp3_retimer_set; //for DP3 - uint32_t reserved[108]; + struct atom_14nm_dpphy_dp_tuningset dp_hbr_tuningset; //hbr 2.7G dp tuning set + struct atom_14nm_dpphy_dp_tuningset dp_hbr2_tuningset; //hbr2 5.4G dp turnig set + struct atom_14nm_dpphy_dp_tuningset edp_tuningset; //edp tuning set + uint32_t reserved[66]; }; -- GitLab From f1e582ebfd703ea01dc4caf4d339b7c84ec3ff29 Mon Sep 17 00:00:00 2001 From: Alex Deucher <alexander.deucher@amd.com> Date: Wed, 25 Jul 2018 15:11:34 -0500 Subject: [PATCH 1352/1506] drm/amdgpu: implement harvesting support for UVD 7.2 (v3) Properly handle cases where one or more instance of the IP block may be harvested. v2: make sure ip_num_rings is initialized amdgpu_queue_mgr.c v3: rebase on Christian's UVD changes, drop unused var Reviewed-by: James Zhu <James.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 17 ++++-- drivers/gpu/drm/amd/amdgpu/amdgpu_queue_mgr.c | 13 ++++- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 11 +++- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.h | 4 ++ drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c | 56 ++++++++++++++++++- 5 files changed, 89 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index c7dce14fd47d5..dd2132fa2b896 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -286,7 +286,7 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file struct drm_crtc *crtc; uint32_t ui32 = 0; uint64_t ui64 = 0; - int i, found; + int i, j, found; int ui32_size = sizeof(ui32); if (!info->return_size || !info->return_pointer) @@ -348,7 +348,11 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file break; case AMDGPU_HW_IP_UVD: type = AMD_IP_BLOCK_TYPE_UVD; - ring_mask |= adev->uvd.inst[0].ring.ready; + for (i = 0; i < adev->uvd.num_uvd_inst; i++) { + if (adev->uvd.harvest_config & (1 << i)) + continue; + ring_mask |= adev->uvd.inst[i].ring.ready; + } ib_start_alignment = 64; ib_size_alignment = 64; break; @@ -361,9 +365,12 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file break; case AMDGPU_HW_IP_UVD_ENC: type = AMD_IP_BLOCK_TYPE_UVD; - for (i = 0; i < adev->uvd.num_enc_rings; i++) - ring_mask |= - adev->uvd.inst[0].ring_enc[i].ready << i; + for (i = 0; i < adev->uvd.num_uvd_inst; i++) { + if (adev->uvd.harvest_config & (1 << i)) + continue; + for (j = 0; j < adev->uvd.num_enc_rings; j++) + ring_mask |= adev->uvd.inst[i].ring_enc[j].ready << j; + } ib_start_alignment = 64; ib_size_alignment = 64; break; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_queue_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_queue_mgr.c index d8357290ad099..a172bba32b45c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_queue_mgr.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_queue_mgr.c @@ -214,7 +214,7 @@ int amdgpu_queue_mgr_map(struct amdgpu_device *adev, u32 hw_ip, u32 instance, u32 ring, struct amdgpu_ring **out_ring) { - int r, ip_num_rings; + int i, r, ip_num_rings = 0; struct amdgpu_queue_mapper *mapper = &mgr->mapper[hw_ip]; if (!adev || !mgr || !out_ring) @@ -243,14 +243,21 @@ int amdgpu_queue_mgr_map(struct amdgpu_device *adev, ip_num_rings = adev->sdma.num_instances; break; case AMDGPU_HW_IP_UVD: - ip_num_rings = adev->uvd.num_uvd_inst; + for (i = 0; i < adev->uvd.num_uvd_inst; i++) { + if (!(adev->uvd.harvest_config & (1 << i))) + ip_num_rings++; + } break; case AMDGPU_HW_IP_VCE: ip_num_rings = adev->vce.num_rings; break; case AMDGPU_HW_IP_UVD_ENC: + for (i = 0; i < adev->uvd.num_uvd_inst; i++) { + if (!(adev->uvd.harvest_config & (1 << i))) + ip_num_rings++; + } ip_num_rings = - adev->uvd.num_enc_rings * adev->uvd.num_uvd_inst; + adev->uvd.num_enc_rings * ip_num_rings; break; case AMDGPU_HW_IP_VCN_DEC: ip_num_rings = 1; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c index fca86d71fafce..632fa5980ff44 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c @@ -255,7 +255,8 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev) bo_size += AMDGPU_GPU_PAGE_ALIGN(le32_to_cpu(hdr->ucode_size_bytes) + 8); for (j = 0; j < adev->uvd.num_uvd_inst; j++) { - + if (adev->uvd.harvest_config & (1 << j)) + continue; r = amdgpu_bo_create_kernel(adev, bo_size, PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM, &adev->uvd.inst[j].vcpu_bo, &adev->uvd.inst[j].gpu_addr, &adev->uvd.inst[j].cpu_addr); @@ -308,6 +309,8 @@ int amdgpu_uvd_sw_fini(struct amdgpu_device *adev) drm_sched_entity_destroy(&adev->uvd.entity); for (j = 0; j < adev->uvd.num_uvd_inst; ++j) { + if (adev->uvd.harvest_config & (1 << j)) + continue; kfree(adev->uvd.inst[j].saved_bo); amdgpu_bo_free_kernel(&adev->uvd.inst[j].vcpu_bo, @@ -343,6 +346,8 @@ int amdgpu_uvd_suspend(struct amdgpu_device *adev) } for (j = 0; j < adev->uvd.num_uvd_inst; ++j) { + if (adev->uvd.harvest_config & (1 << j)) + continue; if (adev->uvd.inst[j].vcpu_bo == NULL) continue; @@ -365,6 +370,8 @@ int amdgpu_uvd_resume(struct amdgpu_device *adev) int i; for (i = 0; i < adev->uvd.num_uvd_inst; i++) { + if (adev->uvd.harvest_config & (1 << i)) + continue; if (adev->uvd.inst[i].vcpu_bo == NULL) return -EINVAL; @@ -1159,6 +1166,8 @@ static void amdgpu_uvd_idle_work_handler(struct work_struct *work) unsigned fences = 0, i, j; for (i = 0; i < adev->uvd.num_uvd_inst; ++i) { + if (adev->uvd.harvest_config & (1 << i)) + continue; fences += amdgpu_fence_count_emitted(&adev->uvd.inst[i].ring); for (j = 0; j < adev->uvd.num_enc_rings; ++j) { fences += amdgpu_fence_count_emitted(&adev->uvd.inst[i].ring_enc[j]); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.h index 66872286ab123..33c5f806f9256 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.h @@ -48,6 +48,9 @@ struct amdgpu_uvd_inst { uint32_t srbm_soft_reset; }; +#define AMDGPU_UVD_HARVEST_UVD0 (1 << 0) +#define AMDGPU_UVD_HARVEST_UVD1 (1 << 1) + struct amdgpu_uvd { const struct firmware *fw; /* UVD firmware */ unsigned fw_version; @@ -61,6 +64,7 @@ struct amdgpu_uvd { atomic_t handles[AMDGPU_MAX_UVD_HANDLES]; struct drm_sched_entity entity; struct delayed_work idle_work; + unsigned harvest_config; }; int amdgpu_uvd_sw_init(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c index d74c1b2426676..5fab3560a71db 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c @@ -41,6 +41,12 @@ #include "mmhub/mmhub_1_0_sh_mask.h" #include "ivsrcid/uvd/irqsrcs_uvd_7_0.h" +#define mmUVD_PG0_CC_UVD_HARVESTING 0x00c7 +#define mmUVD_PG0_CC_UVD_HARVESTING_BASE_IDX 1 +//UVD_PG0_CC_UVD_HARVESTING +#define UVD_PG0_CC_UVD_HARVESTING__UVD_DISABLE__SHIFT 0x1 +#define UVD_PG0_CC_UVD_HARVESTING__UVD_DISABLE_MASK 0x00000002L + #define UVD7_MAX_HW_INSTANCES_VEGA20 2 static void uvd_v7_0_set_ring_funcs(struct amdgpu_device *adev); @@ -370,10 +376,25 @@ static int uvd_v7_0_enc_ring_test_ib(struct amdgpu_ring *ring, long timeout) static int uvd_v7_0_early_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - if (adev->asic_type == CHIP_VEGA20) + + if (adev->asic_type == CHIP_VEGA20) { + u32 harvest; + int i; + adev->uvd.num_uvd_inst = UVD7_MAX_HW_INSTANCES_VEGA20; - else + for (i = 0; i < adev->uvd.num_uvd_inst; i++) { + harvest = RREG32_SOC15(UVD, i, mmUVD_PG0_CC_UVD_HARVESTING); + if (harvest & UVD_PG0_CC_UVD_HARVESTING__UVD_DISABLE_MASK) { + adev->uvd.harvest_config |= 1 << i; + } + } + if (adev->uvd.harvest_config == (AMDGPU_UVD_HARVEST_UVD0 | + AMDGPU_UVD_HARVEST_UVD1)) + /* both instances are harvested, disable the block */ + return -ENOENT; + } else { adev->uvd.num_uvd_inst = 1; + } if (amdgpu_sriov_vf(adev)) adev->uvd.num_enc_rings = 1; @@ -393,6 +414,8 @@ static int uvd_v7_0_sw_init(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; for (j = 0; j < adev->uvd.num_uvd_inst; j++) { + if (adev->uvd.harvest_config & (1 << j)) + continue; /* UVD TRAP */ r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_uvds[j], UVD_7_0__SRCID__UVD_SYSTEM_MESSAGE_INTERRUPT, &adev->uvd.inst[j].irq); if (r) @@ -425,6 +448,8 @@ static int uvd_v7_0_sw_init(void *handle) return r; for (j = 0; j < adev->uvd.num_uvd_inst; j++) { + if (adev->uvd.harvest_config & (1 << j)) + continue; if (!amdgpu_sriov_vf(adev)) { ring = &adev->uvd.inst[j].ring; sprintf(ring->name, "uvd<%d>", j); @@ -472,6 +497,8 @@ static int uvd_v7_0_sw_fini(void *handle) return r; for (j = 0; j < adev->uvd.num_uvd_inst; ++j) { + if (adev->uvd.harvest_config & (1 << j)) + continue; for (i = 0; i < adev->uvd.num_enc_rings; ++i) amdgpu_ring_fini(&adev->uvd.inst[j].ring_enc[i]); } @@ -500,6 +527,8 @@ static int uvd_v7_0_hw_init(void *handle) goto done; for (j = 0; j < adev->uvd.num_uvd_inst; ++j) { + if (adev->uvd.harvest_config & (1 << j)) + continue; ring = &adev->uvd.inst[j].ring; if (!amdgpu_sriov_vf(adev)) { @@ -579,8 +608,11 @@ static int uvd_v7_0_hw_fini(void *handle) DRM_DEBUG("For SRIOV client, shouldn't do anything.\n"); } - for (i = 0; i < adev->uvd.num_uvd_inst; ++i) + for (i = 0; i < adev->uvd.num_uvd_inst; ++i) { + if (adev->uvd.harvest_config & (1 << i)) + continue; adev->uvd.inst[i].ring.ready = false; + } return 0; } @@ -623,6 +655,8 @@ static void uvd_v7_0_mc_resume(struct amdgpu_device *adev) int i; for (i = 0; i < adev->uvd.num_uvd_inst; ++i) { + if (adev->uvd.harvest_config & (1 << i)) + continue; if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { WREG32_SOC15(UVD, i, mmUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW, lower_32_bits(adev->firmware.ucode[AMDGPU_UCODE_ID_UVD].mc_addr)); @@ -695,6 +729,8 @@ static int uvd_v7_0_mmsch_start(struct amdgpu_device *adev, WREG32_SOC15(VCE, 0, mmVCE_MMSCH_VF_MAILBOX_RESP, 0); for (i = 0; i < adev->uvd.num_uvd_inst; ++i) { + if (adev->uvd.harvest_config & (1 << i)) + continue; WDOORBELL32(adev->uvd.inst[i].ring_enc[0].doorbell_index, 0); adev->wb.wb[adev->uvd.inst[i].ring_enc[0].wptr_offs] = 0; adev->uvd.inst[i].ring_enc[0].wptr = 0; @@ -751,6 +787,8 @@ static int uvd_v7_0_sriov_start(struct amdgpu_device *adev) init_table += header->uvd_table_offset; for (i = 0; i < adev->uvd.num_uvd_inst; ++i) { + if (adev->uvd.harvest_config & (1 << i)) + continue; ring = &adev->uvd.inst[i].ring; ring->wptr = 0; size = AMDGPU_GPU_PAGE_ALIGN(adev->uvd.fw->size + 4); @@ -890,6 +928,8 @@ static int uvd_v7_0_start(struct amdgpu_device *adev) int i, j, k, r; for (k = 0; k < adev->uvd.num_uvd_inst; ++k) { + if (adev->uvd.harvest_config & (1 << k)) + continue; /* disable DPG */ WREG32_P(SOC15_REG_OFFSET(UVD, k, mmUVD_POWER_STATUS), 0, ~UVD_POWER_STATUS__UVD_PG_MODE_MASK); @@ -902,6 +942,8 @@ static int uvd_v7_0_start(struct amdgpu_device *adev) uvd_v7_0_mc_resume(adev); for (k = 0; k < adev->uvd.num_uvd_inst; ++k) { + if (adev->uvd.harvest_config & (1 << k)) + continue; ring = &adev->uvd.inst[k].ring; /* disable clock gating */ WREG32_P(SOC15_REG_OFFSET(UVD, k, mmUVD_CGC_CTRL), 0, @@ -1069,6 +1111,8 @@ static void uvd_v7_0_stop(struct amdgpu_device *adev) uint8_t i = 0; for (i = 0; i < adev->uvd.num_uvd_inst; ++i) { + if (adev->uvd.harvest_config & (1 << i)) + continue; /* force RBC into idle state */ WREG32_SOC15(UVD, i, mmUVD_RBC_RB_CNTL, 0x11010101); @@ -1785,6 +1829,8 @@ static void uvd_v7_0_set_ring_funcs(struct amdgpu_device *adev) int i; for (i = 0; i < adev->uvd.num_uvd_inst; i++) { + if (adev->uvd.harvest_config & (1 << i)) + continue; adev->uvd.inst[i].ring.funcs = &uvd_v7_0_ring_vm_funcs; adev->uvd.inst[i].ring.me = i; DRM_INFO("UVD(%d) is enabled in VM mode\n", i); @@ -1796,6 +1842,8 @@ static void uvd_v7_0_set_enc_ring_funcs(struct amdgpu_device *adev) int i, j; for (j = 0; j < adev->uvd.num_uvd_inst; j++) { + if (adev->uvd.harvest_config & (1 << j)) + continue; for (i = 0; i < adev->uvd.num_enc_rings; ++i) { adev->uvd.inst[j].ring_enc[i].funcs = &uvd_v7_0_enc_ring_vm_funcs; adev->uvd.inst[j].ring_enc[i].me = j; @@ -1815,6 +1863,8 @@ static void uvd_v7_0_set_irq_funcs(struct amdgpu_device *adev) int i; for (i = 0; i < adev->uvd.num_uvd_inst; i++) { + if (adev->uvd.harvest_config & (1 << i)) + continue; adev->uvd.inst[i].irq.num_types = adev->uvd.num_enc_rings + 1; adev->uvd.inst[i].irq.funcs = &uvd_v7_0_irq_funcs; } -- GitLab From 2ac305b7c8d7f93a6ef0018391e9865ea4ac0d65 Mon Sep 17 00:00:00 2001 From: Huang Rui <ray.huang@amd.com> Date: Thu, 26 Jul 2018 16:32:08 +0800 Subject: [PATCH 1353/1506] drm/ttm: add ttm_set_memory header (v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch moves all non-x86 abstraction to the ttm_set_memory header. It is to make function calling more clearly. (v2): add ttm_ prefix. Suggested-by: Christian König <christian.koenig@amd.com> Signed-off-by: Huang Rui <ray.huang@amd.com> Reviewed-by: Bas Nieuwenhuizen <basni@chromium.org> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- include/drm/ttm/ttm_set_memory.h | 128 +++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 include/drm/ttm/ttm_set_memory.h diff --git a/include/drm/ttm/ttm_set_memory.h b/include/drm/ttm/ttm_set_memory.h new file mode 100644 index 0000000000000..a70723cf208b2 --- /dev/null +++ b/include/drm/ttm/ttm_set_memory.h @@ -0,0 +1,128 @@ +/************************************************************************** + * + * Copyright (c) 2018 Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ +/* + * Authors: Huang Rui <ray.huang@amd.com> + */ + +#ifndef TTM_SET_MEMORY +#define TTM_SET_MEMORY + +#include <linux/mm.h> + +#ifdef CONFIG_X86 + +#include <asm/set_memory.h> + +static inline int ttm_set_pages_array_wb(struct page **pages, int addrinarray) +{ + return set_pages_array_wb(pages, addrinarray); +} + +static inline int ttm_set_pages_array_wc(struct page **pages, int addrinarray) +{ + return set_pages_array_wc(pages, addrinarray); +} + +static inline int ttm_set_pages_array_uc(struct page **pages, int addrinarray) +{ + return set_pages_array_uc(pages, addrinarray); +} + +static inline int ttm_set_pages_wb(struct page *page, int numpages) +{ + return set_pages_wb(page, numpages); +} + +#else /* for CONFIG_X86 */ + +#if IS_ENABLED(CONFIG_AGP) + +#include <asm/agp.h> + +static inline int ttm_set_pages_array_wb(struct page **pages, int addrinarray) +{ + int i; + + for (i = 0; i < addrinarray; i++) + unmap_page_from_agp(pages[i]); + return 0; +} + +static inline int ttm_set_pages_array_wc(struct page **pages, int addrinarray) +{ + int i; + + for (i = 0; i < addrinarray; i++) + map_page_into_agp(pages[i]); + return 0; +} + +static inline int ttm_set_pages_array_uc(struct page **pages, int addrinarray) +{ + int i; + + for (i = 0; i < addrinarray; i++) + map_page_into_agp(pages[i]); + return 0; +} + +static inline int ttm_set_pages_wb(struct page *page, int numpages) +{ + int i; + + for (i = 0; i < numpages; i++) + unmap_page_from_agp(page++); + return 0; +} + +#else /* for CONFIG_AGP */ + +static inline int ttm_set_pages_array_wb(struct page **pages, int addrinarray) +{ + return 0; +} + +static inline int ttm_set_pages_array_wc(struct page **pages, int addrinarray) +{ + return 0; +} + +static inline int ttm_set_pages_array_uc(struct page **pages, int addrinarray) +{ + return 0; +} + +static inline int ttm_set_pages_wb(struct page *page, int numpages) +{ + return 0; +} + +#endif /* for CONFIG_AGP */ + +#endif /* for CONFIG_X86 */ + +#endif -- GitLab From c7bb1e57e20a7f43b52df183d1a5a1aa936acc2d Mon Sep 17 00:00:00 2001 From: Huang Rui <ray.huang@amd.com> Date: Thu, 26 Jul 2018 16:48:54 +0800 Subject: [PATCH 1354/1506] drm/ttm: clean up non-x86 definitions on ttm_page_alloc_dma MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All non-x86 definitions are moved to ttm_set_memory header, so remove it from ttm_page_alloc_dma.c. Suggested-by: Christian König <christian.koenig@amd.com> Signed-off-by: Huang Rui <ray.huang@amd.com> Reviewed-by: Bas Nieuwenhuizen <basni@chromium.org> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/ttm/ttm_page_alloc_dma.c | 48 ++---------------------- 1 file changed, 4 insertions(+), 44 deletions(-) diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c b/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c index 3f14c1cc07891..f31148ad981c4 100644 --- a/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c +++ b/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c @@ -50,12 +50,7 @@ #include <linux/kthread.h> #include <drm/ttm/ttm_bo_driver.h> #include <drm/ttm/ttm_page_alloc.h> -#if IS_ENABLED(CONFIG_AGP) -#include <asm/agp.h> -#endif -#ifdef CONFIG_X86 -#include <asm/set_memory.h> -#endif +#include <drm/ttm/ttm_set_memory.h> #define NUM_PAGES_TO_ALLOC (PAGE_SIZE/sizeof(struct page *)) #define SMALL_ALLOCATION 4 @@ -268,41 +263,6 @@ static struct kobj_type ttm_pool_kobj_type = { .default_attrs = ttm_pool_attrs, }; -#ifndef CONFIG_X86 -static int set_pages_array_wb(struct page **pages, int addrinarray) -{ -#if IS_ENABLED(CONFIG_AGP) - int i; - - for (i = 0; i < addrinarray; i++) - unmap_page_from_agp(pages[i]); -#endif - return 0; -} - -static int set_pages_array_wc(struct page **pages, int addrinarray) -{ -#if IS_ENABLED(CONFIG_AGP) - int i; - - for (i = 0; i < addrinarray; i++) - map_page_into_agp(pages[i]); -#endif - return 0; -} - -static int set_pages_array_uc(struct page **pages, int addrinarray) -{ -#if IS_ENABLED(CONFIG_AGP) - int i; - - for (i = 0; i < addrinarray; i++) - map_page_into_agp(pages[i]); -#endif - return 0; -} -#endif /* for !CONFIG_X86 */ - static int ttm_set_pages_caching(struct dma_pool *pool, struct page **pages, unsigned cpages) { @@ -315,7 +275,7 @@ static int ttm_set_pages_caching(struct dma_pool *pool, pool->dev_name, cpages); } if (pool->type & IS_WC) { - r = set_pages_array_wc(pages, cpages); + r = ttm_set_pages_array_wc(pages, cpages); if (r) pr_err("%s: Failed to set %d pages to wc!\n", pool->dev_name, cpages); @@ -395,7 +355,7 @@ static void ttm_dma_page_put(struct dma_pool *pool, struct dma_page *d_page) if (!(pool->type & IS_CACHED)) { num_pages = pool->size / PAGE_SIZE; for (i = 0; i < num_pages; ++i, ++page) { - if (set_pages_array_wb(&page, 1)) { + if (ttm_set_pages_array_wb(&page, 1)) { pr_err("%s: Failed to set %d pages to wb!\n", pool->dev_name, 1); } @@ -420,7 +380,7 @@ static void ttm_dma_pages_put(struct dma_pool *pool, struct list_head *d_pages, /* Don't set WB on WB page pool. */ if (npages && !(pool->type & IS_CACHED) && - set_pages_array_wb(pages, npages)) + ttm_set_pages_array_wb(pages, npages)) pr_err("%s: Failed to set %d pages to wb!\n", pool->dev_name, npages); -- GitLab From d55f9b87428f4732472ec7e9ccb7b4135751996c Mon Sep 17 00:00:00 2001 From: Huang Rui <ray.huang@amd.com> Date: Thu, 26 Jul 2018 16:49:36 +0800 Subject: [PATCH 1355/1506] drm/ttm: clean up non-x86 definitions on ttm_page_alloc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All non-x86 definitions are moved to ttm_set_memory header, so remove it from ttm_page_alloc.c. Suggested-by: Christian König <christian.koenig@amd.com> Signed-off-by: Huang Rui <ray.huang@amd.com> Reviewed-by: Bas Nieuwenhuizen <basni@chromium.org> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/ttm/ttm_page_alloc.c | 62 +++------------------------- 1 file changed, 5 insertions(+), 57 deletions(-) diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc.c b/drivers/gpu/drm/ttm/ttm_page_alloc.c index 6e2d1300b457b..f841accc2c006 100644 --- a/drivers/gpu/drm/ttm/ttm_page_alloc.c +++ b/drivers/gpu/drm/ttm/ttm_page_alloc.c @@ -47,13 +47,7 @@ #include <drm/ttm/ttm_bo_driver.h> #include <drm/ttm/ttm_page_alloc.h> - -#if IS_ENABLED(CONFIG_AGP) -#include <asm/agp.h> -#endif -#ifdef CONFIG_X86 -#include <asm/set_memory.h> -#endif +#include <drm/ttm/ttm_set_memory.h> #define NUM_PAGES_TO_ALLOC (PAGE_SIZE/sizeof(struct page *)) #define SMALL_ALLOCATION 16 @@ -222,52 +216,6 @@ static struct kobj_type ttm_pool_kobj_type = { static struct ttm_pool_manager *_manager; -#ifndef CONFIG_X86 -static int set_pages_wb(struct page *page, int numpages) -{ -#if IS_ENABLED(CONFIG_AGP) - int i; - - for (i = 0; i < numpages; i++) - unmap_page_from_agp(page++); -#endif - return 0; -} - -static int set_pages_array_wb(struct page **pages, int addrinarray) -{ -#if IS_ENABLED(CONFIG_AGP) - int i; - - for (i = 0; i < addrinarray; i++) - unmap_page_from_agp(pages[i]); -#endif - return 0; -} - -static int set_pages_array_wc(struct page **pages, int addrinarray) -{ -#if IS_ENABLED(CONFIG_AGP) - int i; - - for (i = 0; i < addrinarray; i++) - map_page_into_agp(pages[i]); -#endif - return 0; -} - -static int set_pages_array_uc(struct page **pages, int addrinarray) -{ -#if IS_ENABLED(CONFIG_AGP) - int i; - - for (i = 0; i < addrinarray; i++) - map_page_into_agp(pages[i]); -#endif - return 0; -} -#endif - /** * Select the right pool or requested caching state and ttm flags. */ static struct ttm_page_pool *ttm_get_pool(int flags, bool huge, @@ -302,13 +250,13 @@ static void ttm_pages_put(struct page *pages[], unsigned npages, unsigned int i, pages_nr = (1 << order); if (order == 0) { - if (set_pages_array_wb(pages, npages)) + if (ttm_set_pages_array_wb(pages, npages)) pr_err("Failed to set %d pages to wb!\n", npages); } for (i = 0; i < npages; ++i) { if (order > 0) { - if (set_pages_wb(pages[i], pages_nr)) + if (ttm_set_pages_wb(pages[i], pages_nr)) pr_err("Failed to set %d pages to wb!\n", pages_nr); } __free_pages(pages[i], order); @@ -498,12 +446,12 @@ static int ttm_set_pages_caching(struct page **pages, /* Set page caching */ switch (cstate) { case tt_uncached: - r = set_pages_array_uc(pages, cpages); + r = ttm_set_pages_array_uc(pages, cpages); if (r) pr_err("Failed to set %d pages to uc!\n", cpages); break; case tt_wc: - r = set_pages_array_wc(pages, cpages); + r = ttm_set_pages_array_wc(pages, cpages); if (r) pr_err("Failed to set %d pages to wc!\n", cpages); break; -- GitLab From 610b399f1ff269e4b9ec85cfdffb06f9befd0c41 Mon Sep 17 00:00:00 2001 From: Bas Nieuwenhuizen <basni@chromium.org> Date: Wed, 25 Jul 2018 22:29:50 +0200 Subject: [PATCH 1356/1506] drm/ttm: Merge hugepage attr changes in ttm_dma_page_put. (v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every set_pages_array_wb call resulted in cross-core interrupts and TLB flushes. Merge more of them for less overhead. This reduces the time needed to free a 1.6 GiB GTT WC buffer as part of Vulkan CTS from ~2 sec to < 0.25 sec. (Allocation still takes more than 2 sec though) (v2): use set_pages_wb instead of set_memory_wb. Signed-off-by: Bas Nieuwenhuizen <basni@chromium.org> Signed-off-by: Huang Rui <ray.huang@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Reviewed-by: Huang Rui <ray.huang@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/ttm/ttm_page_alloc_dma.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c b/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c index f31148ad981c4..8304917294a2e 100644 --- a/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c +++ b/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c @@ -349,17 +349,14 @@ static void ttm_pool_update_free_locked(struct dma_pool *pool, static void ttm_dma_page_put(struct dma_pool *pool, struct dma_page *d_page) { struct page *page = d_page->p; - unsigned i, num_pages; + unsigned num_pages; /* Don't set WB on WB page pool. */ if (!(pool->type & IS_CACHED)) { num_pages = pool->size / PAGE_SIZE; - for (i = 0; i < num_pages; ++i, ++page) { - if (ttm_set_pages_array_wb(&page, 1)) { - pr_err("%s: Failed to set %d pages to wb!\n", - pool->dev_name, 1); - } - } + if (ttm_set_pages_wb(page, num_pages)) + pr_err("%s: Failed to set %d pages to wb!\n", + pool->dev_name, num_pages); } list_del(&d_page->page_list); -- GitLab From 204029e1979959ea6150c2a5c3e961800f52d0d4 Mon Sep 17 00:00:00 2001 From: Junwei Zhang <Jerry.Zhang@amd.com> Date: Thu, 26 Jul 2018 18:00:13 +0800 Subject: [PATCH 1357/1506] drm/amdgpu: correct evict flag for bo move MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pass the evict flag instead of hard code Signed-off-by: Junwei Zhang <Jerry.Zhang@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 8c4358e36c871..c1ae528c7b0ed 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -580,7 +580,7 @@ static int amdgpu_move_vram_ram(struct ttm_buffer_object *bo, bool evict, } /* blit VRAM to GTT */ - r = amdgpu_move_blit(bo, true, ctx->no_wait_gpu, &tmp_mem, old_mem); + r = amdgpu_move_blit(bo, evict, ctx->no_wait_gpu, &tmp_mem, old_mem); if (unlikely(r)) { goto out_cleanup; } @@ -632,7 +632,7 @@ static int amdgpu_move_ram_vram(struct ttm_buffer_object *bo, bool evict, } /* copy to VRAM */ - r = amdgpu_move_blit(bo, true, ctx->no_wait_gpu, new_mem, old_mem); + r = amdgpu_move_blit(bo, evict, ctx->no_wait_gpu, new_mem, old_mem); if (unlikely(r)) { goto out_cleanup; } -- GitLab From 2e603d0429a4e7cba93a4bc4fcdbdf830adaa472 Mon Sep 17 00:00:00 2001 From: Huang Rui <ray.huang@amd.com> Date: Thu, 26 Jul 2018 14:08:03 +0800 Subject: [PATCH 1358/1506] drm/amdgpu: clean up the superfluous space and align the comment text for amdgpu_ttm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch cleans up spaces and align the text to refine the comment for amdgpu_ttm. Signed-off-by: Huang Rui <ray.huang@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 107 +++++++++++------------- 1 file changed, 51 insertions(+), 56 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index c1ae528c7b0ed..fcf421263fd96 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -92,11 +92,9 @@ static void amdgpu_ttm_mem_global_release(struct drm_global_reference *ref) } /** - * amdgpu_ttm_global_init - Initialize global TTM memory reference - * structures. + * amdgpu_ttm_global_init - Initialize global TTM memory reference structures. * - * @adev: AMDGPU device for which the global structures need to be - * registered. + * @adev: AMDGPU device for which the global structures need to be registered. * * This is called as part of the AMDGPU ttm init from amdgpu_ttm_init() * during bring up. @@ -162,13 +160,12 @@ static int amdgpu_invalidate_caches(struct ttm_bo_device *bdev, uint32_t flags) } /** - * amdgpu_init_mem_type - Initialize a memory manager for a specific - * type of memory request. + * amdgpu_init_mem_type - Initialize a memory manager for a specific type of + * memory request. * - * @bdev: The TTM BO device object (contains a reference to - * amdgpu_device) - * @type: The type of memory requested - * @man: + * @bdev: The TTM BO device object (contains a reference to amdgpu_device) + * @type: The type of memory requested + * @man: The memory type manager for each domain * * This is called by ttm_bo_init_mm() when a buffer object is being * initialized. @@ -292,8 +289,8 @@ static void amdgpu_evict_flags(struct ttm_buffer_object *bo, /** * amdgpu_verify_access - Verify access for a mmap call * - * @bo: The buffer object to map - * @filp: The file pointer from the process performing the mmap + * @bo: The buffer object to map + * @filp: The file pointer from the process performing the mmap * * This is called by ttm_bo_mmap() to verify whether a process * has the right to mmap a BO to their process space. @@ -318,11 +315,10 @@ static int amdgpu_verify_access(struct ttm_buffer_object *bo, struct file *filp) /** * amdgpu_move_null - Register memory for a buffer object * - * @bo: The bo to assign the memory to - * @new_mem: The memory to be assigned. + * @bo: The bo to assign the memory to + * @new_mem: The memory to be assigned. * - * Assign the memory from new_mem to the memory of the buffer object - * bo. + * Assign the memory from new_mem to the memory of the buffer object bo. */ static void amdgpu_move_null(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_mem) @@ -335,8 +331,12 @@ static void amdgpu_move_null(struct ttm_buffer_object *bo, } /** - * amdgpu_mm_node_addr - Compute the GPU relative offset of a GTT - * buffer. + * amdgpu_mm_node_addr - Compute the GPU relative offset of a GTT buffer. + * + * @bo: The bo to assign the memory to. + * @mm_node: Memory manager node for drm allocator. + * @mem: The region where the bo resides. + * */ static uint64_t amdgpu_mm_node_addr(struct ttm_buffer_object *bo, struct drm_mm_node *mm_node, @@ -352,10 +352,12 @@ static uint64_t amdgpu_mm_node_addr(struct ttm_buffer_object *bo, } /** - * amdgpu_find_mm_node - Helper function finds the drm_mm_node - * corresponding to @offset. It also modifies - * the offset to be within the drm_mm_node - * returned + * amdgpu_find_mm_node - Helper function finds the drm_mm_node corresponding to + * @offset. It also modifies the offset to be within the drm_mm_node returned + * + * @mem: The region where the bo resides. + * @offset: The offset that drm_mm_node is used for finding. + * */ static struct drm_mm_node *amdgpu_find_mm_node(struct ttm_mem_reg *mem, unsigned long *offset) @@ -497,8 +499,8 @@ int amdgpu_ttm_copy_mem_to_mem(struct amdgpu_device *adev, /** * amdgpu_move_blit - Copy an entire buffer to another buffer * - * This is a helper called by amdgpu_bo_move() and - * amdgpu_move_vram_ram() to help move buffers to and from VRAM. + * This is a helper called by amdgpu_bo_move() and amdgpu_move_vram_ram() to + * help move buffers to and from VRAM. */ static int amdgpu_move_blit(struct ttm_buffer_object *bo, bool evict, bool no_wait_gpu, @@ -794,8 +796,8 @@ struct amdgpu_ttm_tt { }; /** - * amdgpu_ttm_tt_get_user_pages - Pin pages of memory pointed to - * by a USERPTR pointer to memory + * amdgpu_ttm_tt_get_user_pages - Pin pages of memory pointed to by a USERPTR + * pointer to memory * * Called by amdgpu_gem_userptr_ioctl() and amdgpu_cs_parser_bos(). * This provides a wrapper around the get_user_pages() call to provide @@ -818,8 +820,10 @@ int amdgpu_ttm_tt_get_user_pages(struct ttm_tt *ttm, struct page **pages) down_read(&mm->mmap_sem); if (gtt->userflags & AMDGPU_GEM_USERPTR_ANONONLY) { - /* check that we only use anonymous memory - to prevent problems with writeback */ + /* + * check that we only use anonymous memory to prevent problems + * with writeback + */ unsigned long end = gtt->userptr + ttm->num_pages * PAGE_SIZE; struct vm_area_struct *vma; @@ -870,10 +874,9 @@ int amdgpu_ttm_tt_get_user_pages(struct ttm_tt *ttm, struct page **pages) } /** - * amdgpu_ttm_tt_set_user_pages - Copy pages in, putting old pages - * as necessary. + * amdgpu_ttm_tt_set_user_pages - Copy pages in, putting old pages as necessary. * - * Called by amdgpu_cs_list_validate(). This creates the page list + * Called by amdgpu_cs_list_validate(). This creates the page list * that backs user memory and will ultimately be mapped into the device * address space. */ @@ -915,8 +918,7 @@ void amdgpu_ttm_tt_mark_user_pages(struct ttm_tt *ttm) } /** - * amdgpu_ttm_tt_pin_userptr - prepare the sg table with the - * user pages + * amdgpu_ttm_tt_pin_userptr - prepare the sg table with the user pages * * Called by amdgpu_ttm_backend_bind() **/ @@ -1295,8 +1297,8 @@ static void amdgpu_ttm_tt_unpopulate(struct ttm_tt *ttm) } /** - * amdgpu_ttm_tt_set_userptr - Initialize userptr GTT ttm_tt - * for the current task + * amdgpu_ttm_tt_set_userptr - Initialize userptr GTT ttm_tt for the current + * task * * @ttm: The ttm_tt object to bind this userptr object to * @addr: The address in the current tasks VM space to use @@ -1346,9 +1348,8 @@ struct mm_struct *amdgpu_ttm_tt_get_usermm(struct ttm_tt *ttm) } /** - * amdgpu_ttm_tt_affect_userptr - Determine if a ttm_tt object lays - * inside an address range for the - * current task. + * amdgpu_ttm_tt_affect_userptr - Determine if a ttm_tt object lays inside an + * address range for the current task. * */ bool amdgpu_ttm_tt_affect_userptr(struct ttm_tt *ttm, unsigned long start, @@ -1386,8 +1387,7 @@ bool amdgpu_ttm_tt_affect_userptr(struct ttm_tt *ttm, unsigned long start, } /** - * amdgpu_ttm_tt_userptr_invalidated - Has the ttm_tt object been - * invalidated? + * amdgpu_ttm_tt_userptr_invalidated - Has the ttm_tt object been invalidated? */ bool amdgpu_ttm_tt_userptr_invalidated(struct ttm_tt *ttm, int *last_invalidated) @@ -1400,10 +1400,8 @@ bool amdgpu_ttm_tt_userptr_invalidated(struct ttm_tt *ttm, } /** - * amdgpu_ttm_tt_userptr_needs_pages - Have the pages backing this - * ttm_tt object been invalidated - * since the last time they've - * been set? + * amdgpu_ttm_tt_userptr_needs_pages - Have the pages backing this ttm_tt object + * been invalidated since the last time they've been set? */ bool amdgpu_ttm_tt_userptr_needs_pages(struct ttm_tt *ttm) { @@ -1459,13 +1457,12 @@ uint64_t amdgpu_ttm_tt_pte_flags(struct amdgpu_device *adev, struct ttm_tt *ttm, } /** - * amdgpu_ttm_bo_eviction_valuable - Check to see if we can evict - * a buffer object. + * amdgpu_ttm_bo_eviction_valuable - Check to see if we can evict a buffer + * object. * - * Return true if eviction is sensible. Called by - * ttm_mem_evict_first() on behalf of ttm_bo_mem_force_space() - * which tries to evict buffer objects until it can find space - * for a new object and by ttm_bo_force_list_clean() which is + * Return true if eviction is sensible. Called by ttm_mem_evict_first() on + * behalf of ttm_bo_mem_force_space() which tries to evict buffer objects until + * it can find space for a new object and by ttm_bo_force_list_clean() which is * used to clean out a memory space. */ static bool amdgpu_ttm_bo_eviction_valuable(struct ttm_buffer_object *bo, @@ -1515,8 +1512,7 @@ static bool amdgpu_ttm_bo_eviction_valuable(struct ttm_buffer_object *bo, } /** - * amdgpu_ttm_access_memory - Read or Write memory that backs a - * buffer object. + * amdgpu_ttm_access_memory - Read or Write memory that backs a buffer object. * * @bo: The buffer object to read/write * @offset: Offset into buffer object @@ -1704,8 +1700,8 @@ static int amdgpu_ttm_fw_reserve_vram_init(struct amdgpu_device *adev) return r; } /** - * amdgpu_ttm_init - Init the memory management (ttm) as well as - * various gtt/vram related fields. + * amdgpu_ttm_init - Init the memory management (ttm) as well as various + * gtt/vram related fields. * * This initializes all of the memory space pools that the TTM layer * will need such as the GTT space (system memory mapped to the device), @@ -1856,8 +1852,7 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) } /** - * amdgpu_ttm_late_init - Handle any late initialization for - * amdgpu_ttm + * amdgpu_ttm_late_init - Handle any late initialization for amdgpu_ttm */ void amdgpu_ttm_late_init(struct amdgpu_device *adev) { -- GitLab From ea5569ecd6b81232eb536017b627c417befc1acb Mon Sep 17 00:00:00 2001 From: Hans Verkuil <hverkuil@xs4all.nl> Date: Tue, 24 Jul 2018 21:20:28 +0200 Subject: [PATCH 1359/1506] drm_dp_cec.c: fix formatting typo: %pdH -> %phD This caused a kernel oops since %pdH interpreted the pointer as a struct file. Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.com> Link: https://patchwork.freedesktop.org/patch/msgid/f3720ddf-ec0f-cd22-46b6-720a5e2098f2@xs4all.nl --- drivers/gpu/drm/drm_dp_cec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_dp_cec.c b/drivers/gpu/drm/drm_dp_cec.c index ddb1c5adebb96..988513346e9c4 100644 --- a/drivers/gpu/drm/drm_dp_cec.c +++ b/drivers/gpu/drm/drm_dp_cec.c @@ -157,7 +157,7 @@ static void drm_dp_cec_adap_status(struct cec_adapter *adap, if (drm_dp_read_desc(aux, &desc, true)) return; - seq_printf(file, "OUI: %*pdH\n", + seq_printf(file, "OUI: %*phD\n", (int)sizeof(id->oui), id->oui); seq_printf(file, "ID: %*pE\n", (int)strnlen(id->device_id, sizeof(id->device_id)), -- GitLab From 2ead1be54b22ccdc93d3030172993e363128f1b4 Mon Sep 17 00:00:00 2001 From: Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com> Date: Wed, 18 Jul 2018 21:40:45 -0300 Subject: [PATCH 1360/1506] drm/vkms: Fix connector leak at the module removal Currently, vkms shows an error message if the following steps occur: (1) load vkms, (2) perform any specific operation in the vkms (e.g., run an IGT test), and (3) unload the module. The following error message emerges: [drm:drm_mode_config_cleanup [drm]] *ERROR* connector Virtual-1 leaked! This commit fixes this error by calling drm_atomic_helper_shutdown() before drm_mode_config_cleanup, which turns off the whole display pipeline and remove a reference related to any connector. Signed-off-by: Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com> Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180719004045.hzepp565x5lfco3c@smtp.gmail.com --- drivers/gpu/drm/vkms/vkms_drv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c index 37aa2ef33b213..6e728b8252596 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.c +++ b/drivers/gpu/drm/vkms/vkms_drv.c @@ -44,6 +44,7 @@ static void vkms_release(struct drm_device *dev) struct vkms_device *vkms = container_of(dev, struct vkms_device, drm); platform_device_unregister(vkms->platform); + drm_atomic_helper_shutdown(&vkms->drm); drm_mode_config_cleanup(&vkms->drm); drm_dev_fini(&vkms->drm); } -- GitLab From 830aadceae20c08704562f0b83fdd0f0062d06c6 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann <tdz@users.sourceforge.net> Date: Mon, 30 Jul 2018 11:52:31 +0100 Subject: [PATCH 1361/1506] drm/armada: 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 <tdz@users.sourceforge.net> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/armada/armada_drv.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c index 4b11b6b52f1de..d1705d298a39f 100644 --- a/drivers/gpu/drm/armada/armada_drv.c +++ b/drivers/gpu/drm/armada/armada_drv.c @@ -109,7 +109,7 @@ static int armada_drm_bind(struct device *dev) /* * The drm_device structure must be at the start of - * armada_private for drm_dev_unref() to work correctly. + * armada_private for drm_dev_put() to work correctly. */ BUILD_BUG_ON(offsetof(struct armada_private, drm) != 0); @@ -180,7 +180,7 @@ static int armada_drm_bind(struct device *dev) drm_mode_config_cleanup(&priv->drm); drm_mm_takedown(&priv->linear); flush_work(&priv->fb_unref_work); - drm_dev_unref(&priv->drm); + drm_dev_put(&priv->drm); return ret; } @@ -200,7 +200,7 @@ static void armada_drm_unbind(struct device *dev) drm_mm_takedown(&priv->linear); flush_work(&priv->fb_unref_work); - drm_dev_unref(&priv->drm); + drm_dev_put(&priv->drm); } static int compare_of(struct device *dev, void *data) -- GitLab From 7794ec7774066eb12af67a0a756bddd66f2d50f8 Mon Sep 17 00:00:00 2001 From: Souptick Joarder <jrdr.linux@gmail.com> Date: Mon, 30 Jul 2018 11:52:31 +0100 Subject: [PATCH 1362/1506] drm/armada: Adding new typedef vm_fault_t Use new return type vm_fault_t for fault handler in struct vm_operations_struct. For now, this is just documenting that the function returns a VM_FAULT value rather than an errno. Once all instances are converted, vm_fault_t will become a distinct type. commit 1c8f422059ae ("mm: change return type to vm_fault_t") Previously vm_insert_pfn() returns err which driver mapped into VM_FAULT_* type. The new function vmf_insert_pfn() will replace this inefficiency by returning VM_FAULT_* type. Signed-off-by: Souptick Joarder <jrdr.linux@gmail.com> Reviewed-by: Matthew Wilcox <mawilcox@microsoft.com> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/armada/armada_gem.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_gem.c b/drivers/gpu/drm/armada/armada_gem.c index 3fb37c75c065d..892c1d9304bb7 100644 --- a/drivers/gpu/drm/armada/armada_gem.c +++ b/drivers/gpu/drm/armada/armada_gem.c @@ -13,25 +13,14 @@ #include <drm/armada_drm.h> #include "armada_ioctlP.h" -static int armada_gem_vm_fault(struct vm_fault *vmf) +static vm_fault_t armada_gem_vm_fault(struct vm_fault *vmf) { struct drm_gem_object *gobj = vmf->vma->vm_private_data; struct armada_gem_object *obj = drm_to_armada_gem(gobj); unsigned long pfn = obj->phys_addr >> PAGE_SHIFT; - int ret; pfn += (vmf->address - vmf->vma->vm_start) >> PAGE_SHIFT; - ret = vm_insert_pfn(vmf->vma, vmf->address, pfn); - - switch (ret) { - case 0: - case -EBUSY: - return VM_FAULT_NOPAGE; - case -ENOMEM: - return VM_FAULT_OOM; - default: - return VM_FAULT_SIGBUS; - } + return vmf_insert_pfn(vmf->vma, vmf->address, pfn); } const struct vm_operations_struct armada_gem_vm_ops = { -- GitLab From 1729f56010a960f182a36e09ce8d6504fa637d76 Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 1363/1506] drm/armada: clean up armada_drm_crtc_page_flip() drm_mode_page_flip_ioctl() already takes care of checking the framebuffer format, and also assigns primary->fb after a successful call to this handler. These are both redundant, and can be removed. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/armada/armada_crtc.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 42a40daff1326..78bb3d51417ba 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -1039,10 +1039,6 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc, unsigned i; int ret; - /* We don't support changing the pixel format */ - if (fb->format != crtc->primary->fb->format) - return -EINVAL; - work = armada_drm_crtc_alloc_plane_work(dcrtc->crtc.primary); if (!work) return -ENOMEM; @@ -1068,14 +1064,6 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc, return ret; } - /* - * Don't take a reference on the new framebuffer; - * drm_mode_page_flip_ioctl() has already grabbed a reference and - * will _not_ drop that reference on successful return from this - * function. Simply mark this new framebuffer as the current one. - */ - dcrtc->crtc.primary->fb = fb; - /* * Finally, if the display is blanked, we won't receive an * interrupt, so complete it now. -- GitLab From 0239520e0290e7d5f186f7fb7f7ce307c478a439 Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 1364/1506] drm/armada: add rectangle helpers Add helpers to convert rectangle width/height and x/y to register values. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/armada/armada_crtc.c | 8 +++----- drivers/gpu/drm/armada/armada_hw.h | 15 +++++++++++++++ drivers/gpu/drm/armada/armada_overlay.c | 7 +++---- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 78bb3d51417ba..205d5dc7ba81d 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -1158,11 +1158,9 @@ static void armada_drm_primary_update_state(struct drm_plane_state *state, 0, CFG_PDWN64x66, LCD_SPU_SRAM_PARA1); dplane->state.ctrl0 = val; - dplane->state.src_hw = (drm_rect_height(&state->src) & 0xffff0000) | - drm_rect_width(&state->src) >> 16; - dplane->state.dst_hw = drm_rect_height(&state->dst) << 16 | - drm_rect_width(&state->dst); - dplane->state.dst_yx = state->dst.y1 << 16 | state->dst.x1; + dplane->state.src_hw = armada_rect_hw_fp(&state->src); + dplane->state.dst_hw = armada_rect_hw(&state->dst); + dplane->state.dst_yx = armada_rect_yx(&state->dst); armada_drm_gra_plane_regs(regs + idx, &dfb->fb, &dplane->state, state->src.x1 >> 16, state->src.y1 >> 16, diff --git a/drivers/gpu/drm/armada/armada_hw.h b/drivers/gpu/drm/armada/armada_hw.h index 345dc4d0851ef..277580b367586 100644 --- a/drivers/gpu/drm/armada/armada_hw.h +++ b/drivers/gpu/drm/armada/armada_hw.h @@ -316,4 +316,19 @@ enum { PWRDN_IRQ_LEVEL = 1 << 0, }; +static inline u32 armada_rect_hw_fp(struct drm_rect *r) +{ + return (drm_rect_height(r) & 0xffff0000) | drm_rect_width(r) >> 16; +} + +static inline u32 armada_rect_hw(struct drm_rect *r) +{ + return drm_rect_height(r) << 16 | (drm_rect_width(r) & 0x0000ffff); +} + +static inline u32 armada_rect_yx(struct drm_rect *r) +{ + return (r)->y1 << 16 | ((r)->x1 & 0x0000ffff); +} + #endif diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index afa7ded3ae31d..2347811ccf1b5 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -146,22 +146,21 @@ static void armada_ovl_plane_update_state(struct drm_plane_state *state, LCD_SPU_DMA_PITCH_UV); } - val = (drm_rect_height(&state->src) & 0xffff0000) | - drm_rect_width(&state->src) >> 16; + val = armada_rect_hw_fp(&state->src); if (dplane->base.state.src_hw != val) { dplane->base.state.src_hw = val; armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_HPXL_VLN); } - val = drm_rect_height(&state->dst) << 16 | drm_rect_width(&state->dst); + val = armada_rect_hw(&state->dst); if (dplane->base.state.dst_hw != val) { dplane->base.state.dst_hw = val; armada_reg_queue_set(regs, idx, val, LCD_SPU_DZM_HPXL_VLN); } - val = state->dst.y1 << 16 | state->dst.x1; + val = armada_rect_yx(&state->dst); if (dplane->base.state.dst_yx != val) { dplane->base.state.dst_yx = val; armada_reg_queue_set(regs, idx, val, -- GitLab From f9a13bb3baf6009225e91f2b9748ed27f2db9c2c Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 1365/1506] drm/armada: move mode set vblank handling and disable/enable Move the mode set vblank handling and controller enable/disable to the prepare() and commit() callbacks. This will be needed when we move to mode_set_nofb() as we should not enable the controller without the plane coordinates and location having been properly updated. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/armada/armada_crtc.c | 41 ++++++++++++++-------------- drivers/gpu/drm/armada/armada_crtc.h | 1 + 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 205d5dc7ba81d..683b2cec3d554 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -399,6 +399,7 @@ static void armada_drm_crtc_prepare(struct drm_crtc *crtc) { struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); struct drm_plane *plane; + u32 val; /* * If we have an overlay plane associated with this CRTC, disable @@ -411,6 +412,18 @@ static void armada_drm_crtc_prepare(struct drm_crtc *crtc) WARN_ON(!armada_drm_plane_work_wait(drm_to_armada_plane(plane), HZ)); } + + /* Wait for pending flips to complete */ + armada_drm_plane_work_wait(drm_to_armada_plane(dcrtc->crtc.primary), + MAX_SCHEDULE_TIMEOUT); + + drm_crtc_vblank_off(crtc); + + val = dcrtc->dumb_ctrl & ~CFG_DUMB_ENA; + if (val != dcrtc->dumb_ctrl) { + dcrtc->dumb_ctrl = val; + writel_relaxed(val, dcrtc->base + LCD_SPU_DUMB_CTRL); + } } /* The mode_config.mutex will be held for this call */ @@ -418,10 +431,12 @@ static void armada_drm_crtc_commit(struct drm_crtc *crtc) { struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); - if (dcrtc->dpms != DRM_MODE_DPMS_ON) { - dcrtc->dpms = DRM_MODE_DPMS_ON; - armada_drm_crtc_update(dcrtc); - } + dcrtc->dpms = DRM_MODE_DPMS_ON; + armada_drm_crtc_update(dcrtc); + drm_crtc_vblank_on(crtc); + + if (dcrtc->old_modeset_fb) + armada_drm_crtc_finish_fb(dcrtc, dcrtc->old_modeset_fb, false); } /* The mode_config.mutex will be held for this call */ @@ -623,6 +638,7 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc, bool interlaced; drm_framebuffer_get(crtc->primary->fb); + dcrtc->old_modeset_fb = old_fb; interlaced = !!(adj->flags & DRM_MODE_FLAG_INTERLACE); @@ -656,18 +672,6 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc, adj->crtc_vsync_end, adj->crtc_vtotal, tm, bm); - /* Wait for pending flips to complete */ - armada_drm_plane_work_wait(drm_to_armada_plane(dcrtc->crtc.primary), - MAX_SCHEDULE_TIMEOUT); - - drm_crtc_vblank_off(crtc); - - val = dcrtc->dumb_ctrl & ~CFG_DUMB_ENA; - if (val != dcrtc->dumb_ctrl) { - dcrtc->dumb_ctrl = val; - writel_relaxed(val, dcrtc->base + LCD_SPU_DUMB_CTRL); - } - /* * If we are blanked, we would have disabled the clock. Re-enable * it so that compute_clock() does the right thing. @@ -739,11 +743,6 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc, armada_drm_primary_set(crtc, crtc->primary, x, y); spin_unlock_irqrestore(&dcrtc->irq_lock, flags); - armada_drm_crtc_update(dcrtc); - - drm_crtc_vblank_on(crtc); - armada_drm_crtc_finish_fb(dcrtc, old_fb, dpms_blanked(dcrtc->dpms)); - return 0; } diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h index 445829b8877af..8edcfd1fa75f0 100644 --- a/drivers/gpu/drm/armada/armada_crtc.h +++ b/drivers/gpu/drm/armada/armada_crtc.h @@ -93,6 +93,7 @@ struct armada_crtc { uint8_t csc_rgb_mode; struct drm_plane *plane; + struct drm_framebuffer *old_modeset_fb; struct armada_gem_object *cursor_obj; int cursor_x; -- GitLab From cfd1b63af78bfce8161e5f65a1d799a9c33b52c6 Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 1366/1506] drm/armada: use core of primary update_plane for mode set Use the core of the update_plane method to configure the primary plane within mode_set() rather than duplicating this code. This moves us closer to the same code structure that the atomic modeset transitional helpers will use. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/armada/armada_crtc.c | 137 ++++++++++++--------------- 1 file changed, 59 insertions(+), 78 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 683b2cec3d554..6dd54f1d3ac98 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -613,17 +613,8 @@ static void armada_drm_gra_plane_regs(struct armada_regs *regs, armada_reg_queue_end(regs, i); } -static void armada_drm_primary_set(struct drm_crtc *crtc, - struct drm_plane *plane, int x, int y) -{ - struct armada_plane_state *state = &drm_to_armada_plane(plane)->state; - struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); - struct armada_regs regs[8]; - bool interlaced = dcrtc->interlaced; - - armada_drm_gra_plane_regs(regs, plane->fb, state, x, y, interlaced); - armada_drm_crtc_update_regs(dcrtc, regs); -} +static int armada_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, + struct drm_framebuffer *old_fb); /* The mode_config.mutex will be held for this call */ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc, @@ -637,24 +628,13 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc, unsigned i; bool interlaced; - drm_framebuffer_get(crtc->primary->fb); + /* Take a reference on the old fb for armada_drm_crtc_commit() */ + if (old_fb) + drm_framebuffer_get(old_fb); dcrtc->old_modeset_fb = old_fb; interlaced = !!(adj->flags & DRM_MODE_FLAG_INTERLACE); - val = CFG_GRA_ENA; - val |= CFG_GRA_FMT(drm_fb_to_armada_fb(dcrtc->crtc.primary->fb)->fmt); - val |= CFG_GRA_MOD(drm_fb_to_armada_fb(dcrtc->crtc.primary->fb)->mod); - - if (drm_fb_to_armada_fb(dcrtc->crtc.primary->fb)->fmt > CFG_420) - val |= CFG_PALETTE_ENA; - - drm_to_armada_plane(crtc->primary)->state.ctrl0 = val; - drm_to_armada_plane(crtc->primary)->state.src_hw = - drm_to_armada_plane(crtc->primary)->state.dst_hw = - adj->crtc_vdisplay << 16 | adj->crtc_hdisplay; - drm_to_armada_plane(crtc->primary)->state.dst_yx = 0; - i = 0; rm = adj->crtc_hsync_start - adj->crtc_hdisplay; lm = adj->crtc_htotal - adj->crtc_hsync_end; @@ -694,9 +674,6 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc, spin_lock_irqsave(&dcrtc->irq_lock, flags); - /* Ensure graphic fifo is enabled */ - armada_reg_queue_mod(regs, i, 0, CFG_PDWN64x66, LCD_SPU_SRAM_PARA1); - /* Even interlaced/progressive frame */ dcrtc->v[1].spu_v_h_total = adj->crtc_vtotal << 16 | adj->crtc_htotal; @@ -739,37 +716,34 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc, armada_reg_queue_end(regs, i); armada_drm_crtc_update_regs(dcrtc, regs); - - armada_drm_primary_set(crtc, crtc->primary, x, y); spin_unlock_irqrestore(&dcrtc->irq_lock, flags); - return 0; + return armada_drm_crtc_mode_set_base(crtc, x, y, old_fb); } +static int armada_drm_do_primary_update(struct drm_plane *plane, + struct drm_plane_state *state, struct drm_framebuffer *old_fb); + /* The mode_config.mutex will be held for this call */ static int armada_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb) { - struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); - struct armada_regs regs[4]; - unsigned i; - - i = armada_drm_crtc_calc_fb(crtc->primary->fb, crtc->x, crtc->y, regs, - dcrtc->interlaced); - armada_reg_queue_end(regs, i); - - /* Wait for pending flips to complete */ - armada_drm_plane_work_wait(drm_to_armada_plane(dcrtc->crtc.primary), - MAX_SCHEDULE_TIMEOUT); - - /* Take a reference to the new fb as we're using it */ - drm_framebuffer_get(crtc->primary->fb); - - /* Update the base in the CRTC */ - armada_drm_crtc_update_regs(dcrtc, regs); + struct drm_plane_state state = { + .plane = crtc->primary, + .crtc = crtc, + .fb = crtc->primary->fb, + .crtc_x = 0, + .crtc_y = 0, + .crtc_w = crtc->mode.hdisplay, + .crtc_h = crtc->mode.vdisplay, + .src_x = x << 16, + .src_y = y << 16, + .src_w = crtc->mode.hdisplay << 16, + .src_h = crtc->mode.vdisplay << 16, + .rotation = DRM_MODE_ROTATE_0, + }; - /* Drop our previously held reference */ - armada_drm_crtc_finish_fb(dcrtc, old_fb, dpms_blanked(dcrtc->dpms)); + armada_drm_do_primary_update(crtc->primary, &state, old_fb); return 0; } @@ -1169,37 +1143,20 @@ static void armada_drm_primary_update_state(struct drm_plane_state *state, dplane->state.changed = true; } -static int armada_drm_primary_update(struct drm_plane *plane, - struct drm_crtc *crtc, struct drm_framebuffer *fb, - int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, - uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h, - struct drm_modeset_acquire_ctx *ctx) +static int armada_drm_do_primary_update(struct drm_plane *plane, + struct drm_plane_state *state, struct drm_framebuffer *old_fb) { struct armada_plane *dplane = drm_to_armada_plane(plane); - struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); + struct armada_crtc *dcrtc = drm_to_armada_crtc(state->crtc); struct armada_plane_work *work; - struct drm_plane_state state = { - .plane = plane, - .crtc = crtc, - .fb = fb, - .src_x = src_x, - .src_y = src_y, - .src_w = src_w, - .src_h = src_h, - .crtc_x = crtc_x, - .crtc_y = crtc_y, - .crtc_w = crtc_w, - .crtc_h = crtc_h, - .rotation = DRM_MODE_ROTATE_0, - }; struct drm_crtc_state crtc_state = { - .crtc = crtc, - .enable = crtc->enabled, - .mode = crtc->mode, + .crtc = state->crtc, + .enable = state->crtc->enabled, + .mode = state->crtc->mode, }; int ret; - ret = drm_atomic_helper_check_plane_state(&state, &crtc_state, 0, + ret = drm_atomic_helper_check_plane_state(state, &crtc_state, 0, INT_MAX, true, false); if (ret) return ret; @@ -1207,19 +1164,19 @@ static int armada_drm_primary_update(struct drm_plane *plane, work = &dplane->works[dplane->next_work]; work->fn = armada_drm_crtc_complete_frame_work; - if (plane->fb != fb) { + if (old_fb != state->fb) { /* * Take a reference on the new framebuffer - we want to * hold on to it while the hardware is displaying it. */ - drm_framebuffer_reference(fb); + drm_framebuffer_reference(state->fb); - work->old_fb = plane->fb; + work->old_fb = old_fb; } else { work->old_fb = NULL; } - armada_drm_primary_update_state(&state, work->regs); + armada_drm_primary_update_state(state, work->regs); if (!dplane->state.changed) return 0; @@ -1248,6 +1205,30 @@ static int armada_drm_primary_update(struct drm_plane *plane, return 0; } +static int armada_drm_primary_update(struct drm_plane *plane, + struct drm_crtc *crtc, struct drm_framebuffer *fb, + int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, + uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h, + struct drm_modeset_acquire_ctx *ctx) +{ + struct drm_plane_state state = { + .plane = plane, + .crtc = crtc, + .fb = fb, + .src_x = src_x, + .src_y = src_y, + .src_w = src_w, + .src_h = src_h, + .crtc_x = crtc_x, + .crtc_y = crtc_y, + .crtc_w = crtc_w, + .crtc_h = crtc_h, + .rotation = DRM_MODE_ROTATE_0, + }; + + return armada_drm_do_primary_update(plane, &state, plane->fb); +} + int armada_drm_plane_disable(struct drm_plane *plane, struct drm_modeset_acquire_ctx *ctx) { -- GitLab From ecf25d2380313139a2cc5f07e7ac2d910054b478 Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 1367/1506] drm/armada: merge armada_drm_gra_plane_regs() into only caller armada_drm_gra_plane_regs() is now only ever called from within armada_drm_primary_update_state(), so merge it into this function. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/armada/armada_crtc.c | 55 ++++++++++++---------------- 1 file changed, 24 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 6dd54f1d3ac98..735abdab9754f 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -588,31 +588,6 @@ static uint32_t armada_drm_crtc_calculate_csc(struct armada_crtc *dcrtc) return val; } -static void armada_drm_gra_plane_regs(struct armada_regs *regs, - struct drm_framebuffer *fb, struct armada_plane_state *state, - int x, int y, bool interlaced) -{ - unsigned int i; - u32 ctrl0; - - i = armada_drm_crtc_calc_fb(fb, x, y, regs, interlaced); - armada_reg_queue_set(regs, i, state->dst_yx, LCD_SPU_GRA_OVSA_HPXL_VLN); - armada_reg_queue_set(regs, i, state->src_hw, LCD_SPU_GRA_HPXL_VLN); - armada_reg_queue_set(regs, i, state->dst_hw, LCD_SPU_GZM_HPXL_VLN); - - ctrl0 = state->ctrl0; - if (interlaced) - ctrl0 |= CFG_GRA_FTOGGLE; - - armada_reg_queue_mod(regs, i, ctrl0, CFG_GRAFORMAT | - CFG_GRA_MOD(CFG_SWAPRB | CFG_SWAPUV | - CFG_SWAPYU | CFG_YUV2RGB) | - CFG_PALETTE_ENA | CFG_GRA_FTOGGLE | - CFG_GRA_HSMOOTH | CFG_GRA_ENA, - LCD_SPU_DMA_CTRL0); - armada_reg_queue_end(regs, i); -} - static int armada_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb); @@ -1107,8 +1082,8 @@ static const struct drm_crtc_funcs armada_crtc_funcs = { .disable_vblank = armada_drm_crtc_disable_vblank, }; -static void armada_drm_primary_update_state(struct drm_plane_state *state, - struct armada_regs *regs) +static unsigned int armada_drm_primary_update_state( + struct drm_plane_state *state, struct armada_regs *regs) { struct armada_plane *dplane = drm_to_armada_plane(state->plane); struct armada_crtc *dcrtc = drm_to_armada_crtc(state->crtc); @@ -1124,6 +1099,8 @@ static void armada_drm_primary_update_state(struct drm_plane_state *state, val |= CFG_GRA_ENA; if (drm_rect_width(&state->src) >> 16 != drm_rect_width(&state->dst)) val |= CFG_GRA_HSMOOTH; + if (dcrtc->interlaced) + val |= CFG_GRA_FTOGGLE; was_disabled = !(dplane->state.ctrl0 & CFG_GRA_ENA); if (was_disabled) @@ -1135,12 +1112,26 @@ static void armada_drm_primary_update_state(struct drm_plane_state *state, dplane->state.dst_hw = armada_rect_hw(&state->dst); dplane->state.dst_yx = armada_rect_yx(&state->dst); - armada_drm_gra_plane_regs(regs + idx, &dfb->fb, &dplane->state, - state->src.x1 >> 16, state->src.y1 >> 16, - dcrtc->interlaced); + idx += armada_drm_crtc_calc_fb(&dfb->fb, state->src.x1 >> 16, + state->src.y1 >> 16, regs + idx, + dcrtc->interlaced); + armada_reg_queue_set(regs, idx, dplane->state.dst_yx, + LCD_SPU_GRA_OVSA_HPXL_VLN); + armada_reg_queue_set(regs, idx, dplane->state.src_hw, + LCD_SPU_GRA_HPXL_VLN); + armada_reg_queue_set(regs, idx, dplane->state.dst_hw, + LCD_SPU_GZM_HPXL_VLN); + armada_reg_queue_mod(regs, idx, dplane->state.ctrl0, CFG_GRAFORMAT | + CFG_GRA_MOD(CFG_SWAPRB | CFG_SWAPUV | + CFG_SWAPYU | CFG_YUV2RGB) | + CFG_PALETTE_ENA | CFG_GRA_FTOGGLE | + CFG_GRA_HSMOOTH | CFG_GRA_ENA, + LCD_SPU_DMA_CTRL0); dplane->state.vsync_update = !was_disabled; dplane->state.changed = true; + + return idx; } static int armada_drm_do_primary_update(struct drm_plane *plane, @@ -1154,6 +1145,7 @@ static int armada_drm_do_primary_update(struct drm_plane *plane, .enable = state->crtc->enabled, .mode = state->crtc->mode, }; + unsigned int idx; int ret; ret = drm_atomic_helper_check_plane_state(state, &crtc_state, 0, @@ -1176,7 +1168,8 @@ static int armada_drm_do_primary_update(struct drm_plane *plane, work->old_fb = NULL; } - armada_drm_primary_update_state(state, work->regs); + idx = armada_drm_primary_update_state(state, work->regs); + armada_reg_queue_end(work->regs, idx); if (!dplane->state.changed) return 0; -- GitLab From 80c63aee8143d83743a9df6d09309d3d15b20680 Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 1368/1506] drm/armada: reset all atomic state during driver initialisation Reset the atomic state of any converted components during driver initialisation to ensure that we have the atomic state initialised for any component converted to atomic modeset. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/armada/armada_drv.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c index d1705d298a39f..e47b995b4ce63 100644 --- a/drivers/gpu/drm/armada/armada_drv.c +++ b/drivers/gpu/drm/armada/armada_drv.c @@ -155,6 +155,8 @@ static int armada_drm_bind(struct device *dev) priv->drm.irq_enabled = true; + drm_mode_config_reset(&priv->drm); + ret = armada_fbdev_init(&priv->drm); if (ret) goto err_comp; -- GitLab From c36045e17a0e9206078a3254385bf9258e32d5b8 Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 1369/1506] drm/armada: convert primary plane to atomic state Convert the primary plane as a whole to use its atomic state and the transitional helpers. The CRTC is also switched to use the transitional helpers for mode_set() and mode_set_base(). Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/armada/armada_crtc.c | 308 +++++++++++++-------------- drivers/gpu/drm/armada/armada_crtc.h | 8 +- 2 files changed, 157 insertions(+), 159 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 735abdab9754f..523e0e8c6962b 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -325,38 +325,6 @@ armada_drm_crtc_alloc_plane_work(struct drm_plane *plane) return work; } -static void armada_drm_crtc_finish_fb(struct armada_crtc *dcrtc, - struct drm_framebuffer *fb, bool force) -{ - struct armada_plane_work *work; - - if (!fb) - return; - - if (force) { - /* Display is disabled, so just drop the old fb */ - drm_framebuffer_put(fb); - return; - } - - work = armada_drm_crtc_alloc_plane_work(dcrtc->crtc.primary); - if (work) { - work->old_fb = fb; - - if (armada_drm_plane_work_queue(dcrtc, work) == 0) - return; - - kfree(work); - } - - /* - * Oops - just drop the reference immediately and hope for - * the best. The worst that will happen is the buffer gets - * reused before it has finished being displayed. - */ - drm_framebuffer_put(fb); -} - static void armada_drm_vblank_off(struct armada_crtc *dcrtc) { /* @@ -434,9 +402,6 @@ static void armada_drm_crtc_commit(struct drm_crtc *crtc) dcrtc->dpms = DRM_MODE_DPMS_ON; armada_drm_crtc_update(dcrtc); drm_crtc_vblank_on(crtc); - - if (dcrtc->old_modeset_fb) - armada_drm_crtc_finish_fb(dcrtc, dcrtc->old_modeset_fb, false); } /* The mode_config.mutex will be held for this call */ @@ -588,27 +553,16 @@ static uint32_t armada_drm_crtc_calculate_csc(struct armada_crtc *dcrtc) return val; } -static int armada_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, - struct drm_framebuffer *old_fb); - /* The mode_config.mutex will be held for this call */ -static int armada_drm_crtc_mode_set(struct drm_crtc *crtc, - struct drm_display_mode *mode, struct drm_display_mode *adj, - int x, int y, struct drm_framebuffer *old_fb) +static void armada_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) { + struct drm_display_mode *adj = &crtc->state->adjusted_mode; struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); struct armada_regs regs[17]; uint32_t lm, rm, tm, bm, val, sclk; unsigned long flags; unsigned i; - bool interlaced; - - /* Take a reference on the old fb for armada_drm_crtc_commit() */ - if (old_fb) - drm_framebuffer_get(old_fb); - dcrtc->old_modeset_fb = old_fb; - - interlaced = !!(adj->flags & DRM_MODE_FLAG_INTERLACE); + bool interlaced = !!(adj->flags & DRM_MODE_FLAG_INTERLACE); i = 0; rm = adj->crtc_hsync_start - adj->crtc_hdisplay; @@ -692,35 +646,6 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc, armada_drm_crtc_update_regs(dcrtc, regs); spin_unlock_irqrestore(&dcrtc->irq_lock, flags); - - return armada_drm_crtc_mode_set_base(crtc, x, y, old_fb); -} - -static int armada_drm_do_primary_update(struct drm_plane *plane, - struct drm_plane_state *state, struct drm_framebuffer *old_fb); - -/* The mode_config.mutex will be held for this call */ -static int armada_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, - struct drm_framebuffer *old_fb) -{ - struct drm_plane_state state = { - .plane = crtc->primary, - .crtc = crtc, - .fb = crtc->primary->fb, - .crtc_x = 0, - .crtc_y = 0, - .crtc_w = crtc->mode.hdisplay, - .crtc_h = crtc->mode.vdisplay, - .src_x = x << 16, - .src_y = y << 16, - .src_w = crtc->mode.hdisplay << 16, - .src_h = crtc->mode.vdisplay << 16, - .rotation = DRM_MODE_ROTATE_0, - }; - - armada_drm_do_primary_update(crtc->primary, &state, old_fb); - - return 0; } /* The mode_config.mutex will be held for this call */ @@ -732,14 +657,49 @@ static void armada_drm_crtc_disable(struct drm_crtc *crtc) crtc->primary->funcs->disable_plane(crtc->primary, NULL); } +static void armada_drm_crtc_atomic_begin(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) +{ + struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); + struct armada_plane *dplane; + + DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name); + + /* Wait 100ms for any plane works to complete */ + dplane = drm_to_armada_plane(crtc->primary); + if (WARN_ON(armada_drm_plane_work_wait(dplane, HZ / 10) == 0)) + armada_drm_plane_work_cancel(dcrtc, dplane); + + dcrtc->regs_idx = 0; + dcrtc->regs = dcrtc->atomic_regs; +} + +static void armada_drm_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) +{ + struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); + unsigned long flags; + + DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name); + + armada_reg_queue_end(dcrtc->regs, dcrtc->regs_idx); + + spin_lock_irqsave(&dcrtc->irq_lock, flags); + armada_drm_crtc_update_regs(dcrtc, dcrtc->regs); + spin_unlock_irqrestore(&dcrtc->irq_lock, flags); +} + static const struct drm_crtc_helper_funcs armada_crtc_helper_funcs = { .dpms = armada_drm_crtc_dpms, .prepare = armada_drm_crtc_prepare, .commit = armada_drm_crtc_commit, .mode_fixup = armada_drm_crtc_mode_fixup, - .mode_set = armada_drm_crtc_mode_set, - .mode_set_base = armada_drm_crtc_mode_set_base, + .mode_set = drm_helper_crtc_mode_set, + .mode_set_nofb = armada_drm_crtc_mode_set_nofb, + .mode_set_base = drm_helper_crtc_mode_set_base, .disable = armada_drm_crtc_disable, + .atomic_begin = armada_drm_crtc_atomic_begin, + .atomic_flush = armada_drm_crtc_atomic_flush, }; static void armada_load_cursor_argb(void __iomem *base, uint32_t *pix, @@ -1012,6 +972,12 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc, return ret; } + /* + * We are in transition to atomic modeset: update the atomic modeset + * state with the new framebuffer to keep the state consistent. + */ + drm_framebuffer_assign(&dcrtc->crtc.primary->state->fb, fb); + /* * Finally, if the display is blanked, we won't receive an * interrupt, so complete it now. @@ -1072,16 +1038,66 @@ static void armada_drm_crtc_disable_vblank(struct drm_crtc *crtc) } static const struct drm_crtc_funcs armada_crtc_funcs = { + .reset = drm_atomic_helper_crtc_reset, .cursor_set = armada_drm_crtc_cursor_set, .cursor_move = armada_drm_crtc_cursor_move, .destroy = armada_drm_crtc_destroy, .set_config = drm_crtc_helper_set_config, .page_flip = armada_drm_crtc_page_flip, .set_property = armada_drm_crtc_set_property, + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, .enable_vblank = armada_drm_crtc_enable_vblank, .disable_vblank = armada_drm_crtc_disable_vblank, }; +static int armada_drm_plane_prepare_fb(struct drm_plane *plane, + struct drm_plane_state *state) +{ + DRM_DEBUG_KMS("[PLANE:%d:%s] [FB:%d]\n", + plane->base.id, plane->name, + state->fb ? state->fb->base.id : 0); + + /* + * Take a reference on the new framebuffer - we want to + * hold on to it while the hardware is displaying it. + */ + if (state->fb) + drm_framebuffer_get(state->fb); + return 0; +} + +static void armada_drm_plane_cleanup_fb(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + DRM_DEBUG_KMS("[PLANE:%d:%s] [FB:%d]\n", + plane->base.id, plane->name, + old_state->fb ? old_state->fb->base.id : 0); + + if (old_state->fb) + drm_framebuffer_put(old_state->fb); +} + +static int armada_drm_plane_atomic_check(struct drm_plane *plane, + struct drm_plane_state *state) +{ + if (state->fb && !WARN_ON(!state->crtc)) { + struct drm_crtc *crtc = state->crtc; + struct drm_crtc_state crtc_state = { + .crtc = crtc, + .enable = crtc->enabled, + .mode = crtc->mode, + }; + + return drm_atomic_helper_check_plane_state(state, &crtc_state, + 0, INT_MAX, + true, false); + } else { + state->visible = false; + } + return 0; +} + static unsigned int armada_drm_primary_update_state( struct drm_plane_state *state, struct armada_regs *regs) { @@ -1134,94 +1150,70 @@ static unsigned int armada_drm_primary_update_state( return idx; } -static int armada_drm_do_primary_update(struct drm_plane *plane, - struct drm_plane_state *state, struct drm_framebuffer *old_fb) +static void armada_drm_primary_plane_atomic_update(struct drm_plane *plane, + struct drm_plane_state *old_state) { - struct armada_plane *dplane = drm_to_armada_plane(plane); - struct armada_crtc *dcrtc = drm_to_armada_crtc(state->crtc); - struct armada_plane_work *work; - struct drm_crtc_state crtc_state = { - .crtc = state->crtc, - .enable = state->crtc->enabled, - .mode = state->crtc->mode, - }; - unsigned int idx; - int ret; + struct drm_plane_state *state = plane->state; + struct armada_crtc *dcrtc; + struct armada_regs *regs; - ret = drm_atomic_helper_check_plane_state(state, &crtc_state, 0, - INT_MAX, true, false); - if (ret) - return ret; + DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name); - work = &dplane->works[dplane->next_work]; - work->fn = armada_drm_crtc_complete_frame_work; + if (!state->fb || WARN_ON(!state->crtc)) + return; - if (old_fb != state->fb) { - /* - * Take a reference on the new framebuffer - we want to - * hold on to it while the hardware is displaying it. - */ - drm_framebuffer_reference(state->fb); + DRM_DEBUG_KMS("[PLANE:%d:%s] is on [CRTC:%d:%s] with [FB:%d] visible %u->%u\n", + plane->base.id, plane->name, + state->crtc->base.id, state->crtc->name, + state->fb->base.id, + old_state->visible, state->visible); - work->old_fb = old_fb; - } else { - work->old_fb = NULL; - } + dcrtc = drm_to_armada_crtc(state->crtc); + regs = dcrtc->regs + dcrtc->regs_idx; - idx = armada_drm_primary_update_state(state, work->regs); - armada_reg_queue_end(work->regs, idx); + dcrtc->regs_idx += armada_drm_primary_update_state(state, regs); +} - if (!dplane->state.changed) - return 0; +static void armada_drm_primary_plane_atomic_disable(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + struct armada_plane *dplane = drm_to_armada_plane(plane); + struct armada_crtc *dcrtc; + struct armada_regs *regs; + unsigned int idx = 0; - /* Wait for pending work to complete */ - if (armada_drm_plane_work_wait(dplane, HZ / 10) == 0) - armada_drm_plane_work_cancel(dcrtc, dplane); + DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name); - if (!dplane->state.vsync_update) { - work->fn(dcrtc, work); - if (work->old_fb) - drm_framebuffer_unreference(work->old_fb); - return 0; - } + if (!old_state->crtc) + return; - /* Queue it for update on the next interrupt if we are enabled */ - ret = armada_drm_plane_work_queue(dcrtc, work); - if (ret) { - work->fn(dcrtc, work); - if (work->old_fb) - drm_framebuffer_unreference(work->old_fb); - } + DRM_DEBUG_KMS("[PLANE:%d:%s] was on [CRTC:%d:%s] with [FB:%d]\n", + plane->base.id, plane->name, + old_state->crtc->base.id, old_state->crtc->name, + old_state->fb->base.id); - dplane->next_work = !dplane->next_work; + dplane->state.ctrl0 &= ~CFG_GRA_ENA; - return 0; -} + dcrtc = drm_to_armada_crtc(old_state->crtc); + regs = dcrtc->regs + dcrtc->regs_idx; -static int armada_drm_primary_update(struct drm_plane *plane, - struct drm_crtc *crtc, struct drm_framebuffer *fb, - int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, - uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h, - struct drm_modeset_acquire_ctx *ctx) -{ - struct drm_plane_state state = { - .plane = plane, - .crtc = crtc, - .fb = fb, - .src_x = src_x, - .src_y = src_y, - .src_w = src_w, - .src_h = src_h, - .crtc_x = crtc_x, - .crtc_y = crtc_y, - .crtc_w = crtc_w, - .crtc_h = crtc_h, - .rotation = DRM_MODE_ROTATE_0, - }; - - return armada_drm_do_primary_update(plane, &state, plane->fb); + /* Disable plane and power down most RAMs and FIFOs */ + armada_reg_queue_mod(regs, idx, 0, CFG_GRA_ENA, LCD_SPU_DMA_CTRL0); + armada_reg_queue_mod(regs, idx, CFG_PDWN256x32 | CFG_PDWN256x24 | + CFG_PDWN256x8 | CFG_PDWN32x32 | CFG_PDWN64x66, + 0, LCD_SPU_SRAM_PARA1); + + dcrtc->regs_idx += idx; } +static const struct drm_plane_helper_funcs armada_primary_plane_helper_funcs = { + .prepare_fb = armada_drm_plane_prepare_fb, + .cleanup_fb = armada_drm_plane_cleanup_fb, + .atomic_check = armada_drm_plane_atomic_check, + .atomic_update = armada_drm_primary_plane_atomic_update, + .atomic_disable = armada_drm_primary_plane_atomic_disable, +}; + int armada_drm_plane_disable(struct drm_plane *plane, struct drm_modeset_acquire_ctx *ctx) { @@ -1283,9 +1275,12 @@ int armada_drm_plane_disable(struct drm_plane *plane, } static const struct drm_plane_funcs armada_primary_plane_funcs = { - .update_plane = armada_drm_primary_update, - .disable_plane = armada_drm_plane_disable, + .update_plane = drm_plane_helper_update, + .disable_plane = drm_plane_helper_disable, .destroy = drm_primary_helper_destroy, + .reset = drm_atomic_helper_plane_reset, + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, }; int armada_drm_plane_init(struct armada_plane *plane) @@ -1414,6 +1409,9 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev, goto err_crtc; } + drm_plane_helper_add(&primary->base, + &armada_primary_plane_helper_funcs); + ret = drm_universal_plane_init(drm, &primary->base, 0, &armada_primary_plane_funcs, armada_primary_formats, diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h index 8edcfd1fa75f0..3253947e0d41f 100644 --- a/drivers/gpu/drm/armada/armada_crtc.h +++ b/drivers/gpu/drm/armada/armada_crtc.h @@ -93,7 +93,6 @@ struct armada_crtc { uint8_t csc_rgb_mode; struct drm_plane *plane; - struct drm_framebuffer *old_modeset_fb; struct armada_gem_object *cursor_obj; int cursor_x; @@ -110,14 +109,15 @@ struct armada_crtc { spinlock_t irq_lock; uint32_t irq_ena; + + struct armada_regs atomic_regs[32]; + struct armada_regs *regs; + unsigned int regs_idx; }; #define drm_to_armada_crtc(c) container_of(c, struct armada_crtc, crtc) void armada_drm_crtc_update_regs(struct armada_crtc *, struct armada_regs *); -int armada_drm_plane_disable(struct drm_plane *plane, - struct drm_modeset_acquire_ctx *ctx); - extern struct platform_driver armada_lcd_platform_driver; #endif -- GitLab From de503ddff86ed31cde5ec5ea74ec7bf60d3fecc5 Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 1370/1506] drm/armada: convert page_flip to use primary plane atomic_update() page_flip requests happen asynchronously, so we can't wait on the vblank event before returning to userspace, as the transitional plane update helper would do. Craft our own implementation that keeps the asynchronous behaviour of this request, while making use of the atomic infrastructure for the primary plane update. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/armada/armada_crtc.c | 81 +++++++++++++++++++--------- 1 file changed, 55 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 523e0e8c6962b..50b34f5fc97b2 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -11,6 +11,7 @@ #include <linux/of_device.h> #include <linux/platform_device.h> #include <drm/drmP.h> +#include <drm/drm_atomic.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_plane_helper.h> #include <drm/drm_atomic_helper.h> @@ -939,53 +940,81 @@ static void armada_drm_crtc_destroy(struct drm_crtc *crtc) * and a mode_set. */ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc, - struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, uint32_t page_flip_flags, - struct drm_modeset_acquire_ctx *ctx) + struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, + uint32_t page_flip_flags, struct drm_modeset_acquire_ctx *ctx) { struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); + struct drm_plane *plane = crtc->primary; + const struct drm_plane_helper_funcs *plane_funcs; + struct drm_plane_state *state; struct armada_plane_work *work; - unsigned i; int ret; - work = armada_drm_crtc_alloc_plane_work(dcrtc->crtc.primary); - if (!work) + /* Construct new state for the primary plane */ + state = drm_atomic_helper_plane_duplicate_state(plane); + if (!state) return -ENOMEM; - work->event = event; - work->old_fb = dcrtc->crtc.primary->fb; + drm_atomic_set_fb_for_plane(state, fb); - i = armada_drm_crtc_calc_fb(fb, crtc->x, crtc->y, work->regs, - dcrtc->interlaced); - armada_reg_queue_end(work->regs, i); + work = armada_drm_crtc_alloc_plane_work(plane); + if (!work) { + ret = -ENOMEM; + goto put_state; + } + + /* Make sure we can get vblank interrupts */ + ret = drm_crtc_vblank_get(crtc); + if (ret) + goto put_work; /* - * Ensure that we hold a reference on the new framebuffer. - * This has to match the behaviour in mode_set. + * If we have another work pending, we can't process this flip. + * The modeset locks protect us from another user queuing a work + * while we're setting up. */ - drm_framebuffer_get(fb); - - ret = armada_drm_plane_work_queue(dcrtc, work); - if (ret) { - /* Undo our reference above */ - drm_framebuffer_put(fb); - kfree(work); - return ret; + if (drm_to_armada_plane(plane)->work) { + ret = -EBUSY; + goto put_vblank; } + work->event = event; + work->old_fb = plane->state->fb; + /* - * We are in transition to atomic modeset: update the atomic modeset - * state with the new framebuffer to keep the state consistent. + * Hold a ref on the new fb while it's being displayed by the + * hardware. The old fb refcount will be released in the worker. */ - drm_framebuffer_assign(&dcrtc->crtc.primary->state->fb, fb); + drm_framebuffer_get(state->fb); + + /* Point of no return */ + swap(plane->state, state); + + dcrtc->regs_idx = 0; + dcrtc->regs = work->regs; + + plane_funcs = plane->helper_private; + plane_funcs->atomic_update(plane, state); + armada_reg_queue_end(dcrtc->regs, dcrtc->regs_idx); + + /* Queue the work - this should never fail */ + WARN_ON(armada_drm_plane_work_queue(dcrtc, work)); + work = NULL; /* * Finally, if the display is blanked, we won't receive an * interrupt, so complete it now. */ if (dpms_blanked(dcrtc->dpms)) - armada_drm_plane_work_run(dcrtc, dcrtc->crtc.primary); - - return 0; + armada_drm_plane_work_run(dcrtc, plane); + +put_vblank: + drm_crtc_vblank_put(crtc); +put_work: + kfree(work); +put_state: + drm_atomic_helper_plane_destroy_state(plane, state); + return ret; } static int -- GitLab From 47dc413b0025e96eaa43bdd808233763e4080a10 Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 1371/1506] drm/armada: convert overlay plane to atomic state The overlay plane support updates asynchronously to the request, but the drm_plane_helper_update() transitional helper waits for a vblank event before releasing the framebuffer. Using the transitional helper would make the call block, which would introduce a performance regression. Convert the overlay plane update to use the atomic state structures and methods for the plane, but implement our own legacy update method rather than the transitional helper. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/armada/armada_crtc.c | 79 +---------- drivers/gpu/drm/armada/armada_crtc.h | 7 + drivers/gpu/drm/armada/armada_overlay.c | 179 ++++++++++++++++++------ 3 files changed, 145 insertions(+), 120 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 50b34f5fc97b2..5bb097b75b441 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -295,19 +295,6 @@ static void armada_drm_crtc_complete_frame_work(struct armada_crtc *dcrtc, spin_unlock_irqrestore(&dcrtc->irq_lock, flags); } -static void armada_drm_crtc_complete_disable_work(struct armada_crtc *dcrtc, - struct armada_plane_work *work) -{ - unsigned long flags; - - if (dcrtc->plane == work->plane) - dcrtc->plane = NULL; - - spin_lock_irqsave(&dcrtc->irq_lock, flags); - armada_drm_crtc_update_regs(dcrtc, work->regs); - spin_unlock_irqrestore(&dcrtc->irq_lock, flags); -} - static struct armada_plane_work * armada_drm_crtc_alloc_plane_work(struct drm_plane *plane) { @@ -1080,7 +1067,7 @@ static const struct drm_crtc_funcs armada_crtc_funcs = { .disable_vblank = armada_drm_crtc_disable_vblank, }; -static int armada_drm_plane_prepare_fb(struct drm_plane *plane, +int armada_drm_plane_prepare_fb(struct drm_plane *plane, struct drm_plane_state *state) { DRM_DEBUG_KMS("[PLANE:%d:%s] [FB:%d]\n", @@ -1096,7 +1083,7 @@ static int armada_drm_plane_prepare_fb(struct drm_plane *plane, return 0; } -static void armada_drm_plane_cleanup_fb(struct drm_plane *plane, +void armada_drm_plane_cleanup_fb(struct drm_plane *plane, struct drm_plane_state *old_state) { DRM_DEBUG_KMS("[PLANE:%d:%s] [FB:%d]\n", @@ -1107,7 +1094,7 @@ static void armada_drm_plane_cleanup_fb(struct drm_plane *plane, drm_framebuffer_put(old_state->fb); } -static int armada_drm_plane_atomic_check(struct drm_plane *plane, +int armada_drm_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *state) { if (state->fb && !WARN_ON(!state->crtc)) { @@ -1243,66 +1230,6 @@ static const struct drm_plane_helper_funcs armada_primary_plane_helper_funcs = { .atomic_disable = armada_drm_primary_plane_atomic_disable, }; -int armada_drm_plane_disable(struct drm_plane *plane, - struct drm_modeset_acquire_ctx *ctx) -{ - struct armada_plane *dplane = drm_to_armada_plane(plane); - struct armada_crtc *dcrtc; - struct armada_plane_work *work; - unsigned int idx = 0; - u32 sram_para1, enable_mask; - - if (!plane->crtc) - return 0; - - /* - * Arrange to power down most RAMs and FIFOs if this is the primary - * plane, otherwise just the YUV FIFOs for the overlay plane. - */ - if (plane->type == DRM_PLANE_TYPE_PRIMARY) { - sram_para1 = CFG_PDWN256x32 | CFG_PDWN256x24 | CFG_PDWN256x8 | - CFG_PDWN32x32 | CFG_PDWN64x66; - enable_mask = CFG_GRA_ENA; - } else { - sram_para1 = CFG_PDWN16x66 | CFG_PDWN32x66; - enable_mask = CFG_DMA_ENA; - } - - dplane->state.ctrl0 &= ~enable_mask; - - dcrtc = drm_to_armada_crtc(plane->crtc); - - /* - * Try to disable the plane and drop our ref on the framebuffer - * at the next frame update. If we fail for any reason, disable - * the plane immediately. - */ - work = &dplane->works[dplane->next_work]; - work->fn = armada_drm_crtc_complete_disable_work; - work->cancel = armada_drm_crtc_complete_disable_work; - work->old_fb = plane->fb; - - armada_reg_queue_mod(work->regs, idx, - 0, enable_mask, LCD_SPU_DMA_CTRL0); - armada_reg_queue_mod(work->regs, idx, - sram_para1, 0, LCD_SPU_SRAM_PARA1); - armada_reg_queue_end(work->regs, idx); - - /* Wait for any preceding work to complete, but don't wedge */ - if (WARN_ON(!armada_drm_plane_work_wait(dplane, HZ))) - armada_drm_plane_work_cancel(dcrtc, dplane); - - if (armada_drm_plane_work_queue(dcrtc, work)) { - work->fn(dcrtc, work); - if (work->old_fb) - drm_framebuffer_unreference(work->old_fb); - } - - dplane->next_work = !dplane->next_work; - - return 0; -} - static const struct drm_plane_funcs armada_primary_plane_funcs = { .update_plane = drm_plane_helper_update, .disable_plane = drm_plane_helper_disable, diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h index 3253947e0d41f..4da56a171b13e 100644 --- a/drivers/gpu/drm/armada/armada_crtc.h +++ b/drivers/gpu/drm/armada/armada_crtc.h @@ -75,6 +75,13 @@ void armada_drm_plane_work_cancel(struct armada_crtc *dcrtc, void armada_drm_plane_calc_addrs(u32 *addrs, struct drm_framebuffer *fb, int x, int y); +int armada_drm_plane_prepare_fb(struct drm_plane *plane, + struct drm_plane_state *state); +void armada_drm_plane_cleanup_fb(struct drm_plane *plane, + struct drm_plane_state *old_state); +int armada_drm_plane_atomic_check(struct drm_plane *plane, + struct drm_plane_state *state); + struct armada_crtc { struct drm_crtc crtc; const struct armada_variant *variant; diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index 2347811ccf1b5..be9de5d85f9f4 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -7,7 +7,9 @@ * published by the Free Software Foundation. */ #include <drm/drmP.h> +#include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_plane_helper.h> #include "armada_crtc.h" #include "armada_drm.h" #include "armada_fb.h" @@ -78,7 +80,7 @@ static void armada_ovl_plane_work(struct armada_crtc *dcrtc, spin_unlock_irqrestore(&dcrtc->irq_lock, flags); } -static void armada_ovl_plane_update_state(struct drm_plane_state *state, +static unsigned int armada_ovl_plane_update_state(struct drm_plane_state *state, struct armada_regs *regs) { struct armada_ovl_plane *dplane = drm_to_armada_ovl_plane(state->plane); @@ -180,67 +182,116 @@ static void armada_ovl_plane_update_state(struct drm_plane_state *state, dplane->base.state.changed = idx != 0; - armada_reg_queue_end(regs, idx); + return idx; } -static int -armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, - struct drm_framebuffer *fb, - int crtc_x, int crtc_y, unsigned crtc_w, unsigned crtc_h, - uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h, - struct drm_modeset_acquire_ctx *ctx) +static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + struct drm_plane_state *state = plane->state; + struct armada_crtc *dcrtc; + struct armada_regs *regs; + + DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name); + + if (!state->fb || WARN_ON(!state->crtc)) + return; + + DRM_DEBUG_KMS("[PLANE:%d:%s] is on [CRTC:%d:%s] with [FB:%d] visible %u->%u\n", + plane->base.id, plane->name, + state->crtc->base.id, state->crtc->name, + state->fb->base.id, + old_state->visible, state->visible); + + dcrtc = drm_to_armada_crtc(state->crtc); + regs = dcrtc->regs + dcrtc->regs_idx; + + dcrtc->regs_idx += armada_ovl_plane_update_state(state, regs); +} + +static void armada_drm_overlay_plane_atomic_disable(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + struct armada_plane *dplane = drm_to_armada_plane(plane); + struct armada_crtc *dcrtc; + struct armada_regs *regs; + unsigned int idx = 0; + + DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name); + + if (!old_state->crtc) + return; + + DRM_DEBUG_KMS("[PLANE:%d:%s] was on [CRTC:%d:%s] with [FB:%d]\n", + plane->base.id, plane->name, + old_state->crtc->base.id, old_state->crtc->name, + old_state->fb->base.id); + + dplane->state.ctrl0 &= ~CFG_DMA_ENA; + + dcrtc = drm_to_armada_crtc(old_state->crtc); + regs = dcrtc->regs + dcrtc->regs_idx; + + /* Disable plane and power down the YUV FIFOs */ + armada_reg_queue_mod(regs, idx, 0, CFG_DMA_ENA, LCD_SPU_DMA_CTRL0); + armada_reg_queue_mod(regs, idx, CFG_PDWN16x66 | CFG_PDWN32x66, 0, + LCD_SPU_SRAM_PARA1); + + dcrtc->regs_idx += idx; + + if (dcrtc->plane == plane) + dcrtc->plane = NULL; +} + +static const struct drm_plane_helper_funcs armada_overlay_plane_helper_funcs = { + .prepare_fb = armada_drm_plane_prepare_fb, + .cleanup_fb = armada_drm_plane_cleanup_fb, + .atomic_check = armada_drm_plane_atomic_check, + .atomic_update = armada_drm_overlay_plane_atomic_update, + .atomic_disable = armada_drm_overlay_plane_atomic_disable, +}; + +static int armada_overlay_commit(struct drm_plane *plane, + struct drm_plane_state *state) { struct armada_ovl_plane *dplane = drm_to_armada_ovl_plane(plane); - struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); + const struct drm_plane_helper_funcs *plane_funcs; + struct armada_crtc *dcrtc = drm_to_armada_crtc(state->crtc); struct armada_plane_work *work; - struct drm_plane_state state = { - .plane = plane, - .crtc = crtc, - .fb = fb, - .src_x = src_x, - .src_y = src_y, - .src_w = src_w, - .src_h = src_h, - .crtc_x = crtc_x, - .crtc_y = crtc_y, - .crtc_w = crtc_w, - .crtc_h = crtc_h, - .rotation = DRM_MODE_ROTATE_0, - }; - struct drm_crtc_state crtc_state = { - .crtc = crtc, - .enable = crtc->enabled, - .mode = crtc->mode, - }; int ret; - trace_armada_ovl_plane_update(plane, crtc, fb, - crtc_x, crtc_y, crtc_w, crtc_h, - src_x, src_y, src_w, src_h); - - ret = drm_atomic_helper_check_plane_state(&state, &crtc_state, 0, - INT_MAX, true, false); + plane_funcs = plane->helper_private; + ret = plane_funcs->atomic_check(plane, state); if (ret) - return ret; + goto put_state; work = &dplane->base.works[dplane->base.next_work]; - if (plane->fb != fb) { + if (plane->state->fb != state->fb) { /* * Take a reference on the new framebuffer - we want to * hold on to it while the hardware is displaying it. */ - drm_framebuffer_reference(fb); + drm_framebuffer_reference(state->fb); - work->old_fb = plane->fb; + work->old_fb = plane->state->fb; } else { work->old_fb = NULL; } - armada_ovl_plane_update_state(&state, work->regs); + /* Point of no return */ + swap(plane->state, state); + + dcrtc->regs_idx = 0; + dcrtc->regs = work->regs; + plane_funcs->atomic_update(plane, state); + + /* If nothing was updated, short-circuit */ if (!dplane->base.state.changed) - return 0; + goto put_state; + + armada_reg_queue_end(dcrtc->regs, dcrtc->regs_idx); /* Wait for pending work to complete */ if (armada_drm_plane_work_wait(&dplane->base, HZ / 25) == 0) @@ -249,7 +300,7 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, /* Just updating the position/size? */ if (!dplane->base.state.vsync_update) { armada_ovl_plane_work(dcrtc, work); - return 0; + goto put_state; } if (!dcrtc->plane) { @@ -259,12 +310,48 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, /* Queue it for update on the next interrupt if we are enabled */ ret = armada_drm_plane_work_queue(dcrtc, work); - if (ret) + if (ret) { DRM_ERROR("failed to queue plane work: %d\n", ret); + ret = 0; + } dplane->base.next_work = !dplane->base.next_work; - return 0; +put_state: + drm_atomic_helper_plane_destroy_state(plane, state); + return ret; +} + +static int +armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, + struct drm_framebuffer *fb, + int crtc_x, int crtc_y, unsigned crtc_w, unsigned crtc_h, + uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h, + struct drm_modeset_acquire_ctx *ctx) +{ + struct drm_plane_state *state; + + trace_armada_ovl_plane_update(plane, crtc, fb, + crtc_x, crtc_y, crtc_w, crtc_h, + src_x, src_y, src_w, src_h); + + /* Construct new state for the overlay plane */ + state = drm_atomic_helper_plane_duplicate_state(plane); + if (!state) + return -ENOMEM; + + state->crtc = crtc; + drm_atomic_set_fb_for_plane(state, fb); + state->crtc_x = crtc_x; + state->crtc_y = crtc_y; + state->crtc_h = crtc_h; + state->crtc_w = crtc_w; + state->src_x = src_x; + state->src_y = src_y; + state->src_h = src_h; + state->src_w = src_w; + + return armada_overlay_commit(plane, state); } static void armada_ovl_plane_destroy(struct drm_plane *plane) @@ -355,9 +442,10 @@ static int armada_ovl_plane_set_property(struct drm_plane *plane, static const struct drm_plane_funcs armada_ovl_plane_funcs = { .update_plane = armada_ovl_plane_update, - .disable_plane = armada_drm_plane_disable, + .disable_plane = drm_plane_helper_disable, .destroy = armada_ovl_plane_destroy, .set_property = armada_ovl_plane_set_property, + .reset = drm_atomic_helper_plane_reset, }; static const uint32_t armada_ovl_formats[] = { @@ -450,6 +538,9 @@ int armada_overlay_plane_create(struct drm_device *dev, unsigned long crtcs) dplane->base.works[0].fn = armada_ovl_plane_work; dplane->base.works[1].fn = armada_ovl_plane_work; + drm_plane_helper_add(&dplane->base.base, + &armada_overlay_plane_helper_funcs); + ret = drm_universal_plane_init(dev, &dplane->base.base, crtcs, &armada_ovl_plane_funcs, armada_ovl_formats, -- GitLab From 9c41467c9aa5b3916ff559b8c2b3725d6290e5ec Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 1372/1506] drm/armada: remove temporary crtc state Now that we have the CRTC using the atomic modeset transitional helper, there is no need to build a temporary crtc state anymore - we can use the CRTC atomic state directly. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/armada/armada_crtc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 5bb097b75b441..0566739118187 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -1099,13 +1099,13 @@ int armada_drm_plane_atomic_check(struct drm_plane *plane, { if (state->fb && !WARN_ON(!state->crtc)) { struct drm_crtc *crtc = state->crtc; - struct drm_crtc_state crtc_state = { - .crtc = crtc, - .enable = crtc->enabled, - .mode = crtc->mode, - }; + struct drm_crtc_state *crtc_state; - return drm_atomic_helper_check_plane_state(state, &crtc_state, + if (state->state) + crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc); + else + crtc_state = crtc->state; + return drm_atomic_helper_check_plane_state(state, crtc_state, 0, INT_MAX, true, false); } else { -- GitLab From 3acea7b9b62c282ea3d4d0cd156ca8e35dfa8a8c Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 1373/1506] drm/armada: use old_state for update tracking in atomic_update() Rather than tracking the register state, we can now check the previous state and decide which registers need updating from that since the old plane state indicates the previous state which was programmed into the hardware. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/armada/armada_crtc.c | 116 ++++++++------- drivers/gpu/drm/armada/armada_crtc.h | 12 -- drivers/gpu/drm/armada/armada_overlay.c | 189 +++++++++++------------- 3 files changed, 144 insertions(+), 173 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 0566739118187..14339d5bed149 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -1114,64 +1114,14 @@ int armada_drm_plane_atomic_check(struct drm_plane *plane, return 0; } -static unsigned int armada_drm_primary_update_state( - struct drm_plane_state *state, struct armada_regs *regs) -{ - struct armada_plane *dplane = drm_to_armada_plane(state->plane); - struct armada_crtc *dcrtc = drm_to_armada_crtc(state->crtc); - struct armada_framebuffer *dfb = drm_fb_to_armada_fb(state->fb); - bool was_disabled; - unsigned int idx = 0; - u32 val; - - val = CFG_GRA_FMT(dfb->fmt) | CFG_GRA_MOD(dfb->mod); - if (dfb->fmt > CFG_420) - val |= CFG_PALETTE_ENA; - if (state->visible) - val |= CFG_GRA_ENA; - if (drm_rect_width(&state->src) >> 16 != drm_rect_width(&state->dst)) - val |= CFG_GRA_HSMOOTH; - if (dcrtc->interlaced) - val |= CFG_GRA_FTOGGLE; - - was_disabled = !(dplane->state.ctrl0 & CFG_GRA_ENA); - if (was_disabled) - armada_reg_queue_mod(regs, idx, - 0, CFG_PDWN64x66, LCD_SPU_SRAM_PARA1); - - dplane->state.ctrl0 = val; - dplane->state.src_hw = armada_rect_hw_fp(&state->src); - dplane->state.dst_hw = armada_rect_hw(&state->dst); - dplane->state.dst_yx = armada_rect_yx(&state->dst); - - idx += armada_drm_crtc_calc_fb(&dfb->fb, state->src.x1 >> 16, - state->src.y1 >> 16, regs + idx, - dcrtc->interlaced); - armada_reg_queue_set(regs, idx, dplane->state.dst_yx, - LCD_SPU_GRA_OVSA_HPXL_VLN); - armada_reg_queue_set(regs, idx, dplane->state.src_hw, - LCD_SPU_GRA_HPXL_VLN); - armada_reg_queue_set(regs, idx, dplane->state.dst_hw, - LCD_SPU_GZM_HPXL_VLN); - armada_reg_queue_mod(regs, idx, dplane->state.ctrl0, CFG_GRAFORMAT | - CFG_GRA_MOD(CFG_SWAPRB | CFG_SWAPUV | - CFG_SWAPYU | CFG_YUV2RGB) | - CFG_PALETTE_ENA | CFG_GRA_FTOGGLE | - CFG_GRA_HSMOOTH | CFG_GRA_ENA, - LCD_SPU_DMA_CTRL0); - - dplane->state.vsync_update = !was_disabled; - dplane->state.changed = true; - - return idx; -} - static void armada_drm_primary_plane_atomic_update(struct drm_plane *plane, struct drm_plane_state *old_state) { struct drm_plane_state *state = plane->state; struct armada_crtc *dcrtc; struct armada_regs *regs; + u32 cfg, cfg_mask, val; + unsigned int idx; DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name); @@ -1187,13 +1137,69 @@ static void armada_drm_primary_plane_atomic_update(struct drm_plane *plane, dcrtc = drm_to_armada_crtc(state->crtc); regs = dcrtc->regs + dcrtc->regs_idx; - dcrtc->regs_idx += armada_drm_primary_update_state(state, regs); + idx = 0; + if (!old_state->visible && state->visible) { + val = CFG_PDWN64x66; + if (drm_fb_to_armada_fb(state->fb)->fmt > CFG_420) + val |= CFG_PDWN256x24; + armada_reg_queue_mod(regs, idx, 0, val, LCD_SPU_SRAM_PARA1); + } + val = armada_rect_hw_fp(&state->src); + if (armada_rect_hw_fp(&old_state->src) != val) + armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_HPXL_VLN); + val = armada_rect_yx(&state->dst); + if (armada_rect_yx(&old_state->dst) != val) + armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_OVSA_HPXL_VLN); + val = armada_rect_hw(&state->dst); + if (armada_rect_hw(&old_state->dst) != val) + armada_reg_queue_set(regs, idx, val, LCD_SPU_GZM_HPXL_VLN); + if (old_state->src.x1 != state->src.x1 || + old_state->src.y1 != state->src.y1 || + old_state->fb != state->fb) { + idx += armada_drm_crtc_calc_fb(state->fb, + state->src.x1 >> 16, + state->src.y1 >> 16, + regs + idx, + dcrtc->interlaced); + } + if (old_state->fb != state->fb) { + cfg = CFG_GRA_FMT(drm_fb_to_armada_fb(state->fb)->fmt) | + CFG_GRA_MOD(drm_fb_to_armada_fb(state->fb)->mod); + if (drm_fb_to_armada_fb(state->fb)->fmt > CFG_420) + cfg |= CFG_PALETTE_ENA; + if (state->visible) + cfg |= CFG_GRA_ENA; + if (dcrtc->interlaced) + cfg |= CFG_GRA_FTOGGLE; + cfg_mask = CFG_GRAFORMAT | + CFG_GRA_MOD(CFG_SWAPRB | CFG_SWAPUV | + CFG_SWAPYU | CFG_YUV2RGB) | + CFG_PALETTE_ENA | CFG_GRA_FTOGGLE | + CFG_GRA_ENA; + } else if (old_state->visible != state->visible) { + cfg = state->visible ? CFG_GRA_ENA : 0; + cfg_mask = CFG_GRA_ENA; + } else { + cfg = cfg_mask = 0; + } + if (drm_rect_width(&old_state->src) != drm_rect_width(&state->src) || + drm_rect_width(&old_state->dst) != drm_rect_width(&state->dst)) { + cfg_mask |= CFG_GRA_HSMOOTH; + if (drm_rect_width(&state->src) >> 16 != + drm_rect_width(&state->dst)) + cfg |= CFG_GRA_HSMOOTH; + } + + if (cfg_mask) + armada_reg_queue_mod(regs, idx, cfg, cfg_mask, + LCD_SPU_DMA_CTRL0); + + dcrtc->regs_idx += idx; } static void armada_drm_primary_plane_atomic_disable(struct drm_plane *plane, struct drm_plane_state *old_state) { - struct armada_plane *dplane = drm_to_armada_plane(plane); struct armada_crtc *dcrtc; struct armada_regs *regs; unsigned int idx = 0; @@ -1208,8 +1214,6 @@ static void armada_drm_primary_plane_atomic_disable(struct drm_plane *plane, old_state->crtc->base.id, old_state->crtc->name, old_state->fb->base.id); - dplane->state.ctrl0 &= ~CFG_GRA_ENA; - dcrtc = drm_to_armada_crtc(old_state->crtc); regs = dcrtc->regs + dcrtc->regs_idx; diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h index 4da56a171b13e..79ac0db047c9e 100644 --- a/drivers/gpu/drm/armada/armada_crtc.h +++ b/drivers/gpu/drm/armada/armada_crtc.h @@ -45,24 +45,12 @@ struct armada_plane_work { struct armada_regs regs[14]; }; -struct armada_plane_state { - u16 src_x; - u16 src_y; - u32 src_hw; - u32 dst_hw; - u32 dst_yx; - u32 ctrl0; - bool changed; - bool vsync_update; -}; - struct armada_plane { struct drm_plane base; wait_queue_head_t frame_wait; bool next_work; struct armada_plane_work works[2]; struct armada_plane_work *work; - struct armada_plane_state state; }; #define drm_to_armada_plane(p) container_of(p, struct armada_plane, base) diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index be9de5d85f9f4..aa2a12aec3cc5 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -35,6 +35,7 @@ struct armada_ovl_plane_properties { struct armada_ovl_plane { struct armada_plane base; + bool wait_vblank; struct armada_ovl_plane_properties prop; }; #define drm_to_armada_ovl_plane(p) \ @@ -80,52 +81,55 @@ static void armada_ovl_plane_work(struct armada_crtc *dcrtc, spin_unlock_irqrestore(&dcrtc->irq_lock, flags); } -static unsigned int armada_ovl_plane_update_state(struct drm_plane_state *state, - struct armada_regs *regs) +static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane, + struct drm_plane_state *old_state) { - struct armada_ovl_plane *dplane = drm_to_armada_ovl_plane(state->plane); - struct armada_framebuffer *dfb = drm_fb_to_armada_fb(state->fb); - const struct drm_format_info *format; - unsigned int idx = 0; - bool fb_changed; - u32 val, ctrl0; - u16 src_x, src_y; - - ctrl0 = CFG_DMA_FMT(dfb->fmt) | CFG_DMA_MOD(dfb->mod) | CFG_CBSH_ENA; - if (state->visible) - ctrl0 |= CFG_DMA_ENA; - if (drm_rect_width(&state->src) >> 16 != drm_rect_width(&state->dst)) - ctrl0 |= CFG_DMA_HSMOOTH; - - /* - * Shifting a YUV packed format image by one pixel causes the U/V - * planes to swap. Compensate for it by also toggling the UV swap. - */ - format = dfb->fb.format; - if (format->num_planes == 1 && state->src.x1 >> 16 & (format->hsub - 1)) - ctrl0 ^= CFG_DMA_MOD(CFG_SWAPUV); - - if (~dplane->base.state.ctrl0 & ctrl0 & CFG_DMA_ENA) { - /* Power up the Y/U/V FIFOs on ENA 0->1 transitions */ - armada_reg_queue_mod(regs, idx, - 0, CFG_PDWN16x66 | CFG_PDWN32x66, - LCD_SPU_SRAM_PARA1); - } + struct drm_plane_state *state = plane->state; + struct armada_crtc *dcrtc; + struct armada_regs *regs; + unsigned int idx; + u32 cfg, cfg_mask, val; - fb_changed = dplane->base.base.fb != &dfb->fb || - dplane->base.state.src_x != state->src.x1 >> 16 || - dplane->base.state.src_y != state->src.y1 >> 16; + DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name); - dplane->base.state.vsync_update = fb_changed; + if (!state->fb || WARN_ON(!state->crtc)) + return; + DRM_DEBUG_KMS("[PLANE:%d:%s] is on [CRTC:%d:%s] with [FB:%d] visible %u->%u\n", + plane->base.id, plane->name, + state->crtc->base.id, state->crtc->name, + state->fb->base.id, + old_state->visible, state->visible); + + dcrtc = drm_to_armada_crtc(state->crtc); + regs = dcrtc->regs + dcrtc->regs_idx; + + drm_to_armada_ovl_plane(plane)->wait_vblank = false; + + idx = 0; + if (!old_state->visible && state->visible) + armada_reg_queue_mod(regs, idx, + 0, CFG_PDWN16x66 | CFG_PDWN32x66, + LCD_SPU_SRAM_PARA1); + val = armada_rect_hw_fp(&state->src); + if (armada_rect_hw_fp(&old_state->src) != val) + armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_HPXL_VLN); + val = armada_rect_yx(&state->dst); + if (armada_rect_yx(&old_state->dst) != val) + armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_OVSA_HPXL_VLN); + val = armada_rect_hw(&state->dst); + if (armada_rect_hw(&old_state->dst) != val) + armada_reg_queue_set(regs, idx, val, LCD_SPU_DZM_HPXL_VLN); /* FIXME: overlay on an interlaced display */ - if (fb_changed) { + if (old_state->src.x1 != state->src.x1 || + old_state->src.y1 != state->src.y1 || + old_state->fb != state->fb) { + const struct drm_format_info *format; + u16 src_x = state->src.x1 >> 16; + u16 src_y = state->src.y1 >> 16; u32 addrs[3]; - dplane->base.state.src_y = src_y = state->src.y1 >> 16; - dplane->base.state.src_x = src_x = state->src.x1 >> 16; - - armada_drm_plane_calc_addrs(addrs, &dfb->fb, src_x, src_y); + armada_drm_plane_calc_addrs(addrs, state->fb, src_x, src_y); armada_reg_queue_set(regs, idx, addrs[0], LCD_SPU_DMA_START_ADDR_Y0); @@ -140,79 +144,56 @@ static unsigned int armada_ovl_plane_update_state(struct drm_plane_state *state, armada_reg_queue_set(regs, idx, addrs[2], LCD_SPU_DMA_START_ADDR_V1); - val = dfb->fb.pitches[0] << 16 | dfb->fb.pitches[0]; - armada_reg_queue_set(regs, idx, val, - LCD_SPU_DMA_PITCH_YC); - val = dfb->fb.pitches[1] << 16 | dfb->fb.pitches[2]; - armada_reg_queue_set(regs, idx, val, - LCD_SPU_DMA_PITCH_UV); - } - - val = armada_rect_hw_fp(&state->src); - if (dplane->base.state.src_hw != val) { - dplane->base.state.src_hw = val; - armada_reg_queue_set(regs, idx, val, - LCD_SPU_DMA_HPXL_VLN); - } + val = state->fb->pitches[0] << 16 | state->fb->pitches[0]; + armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_PITCH_YC); + val = state->fb->pitches[1] << 16 | state->fb->pitches[2]; + armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_PITCH_UV); - val = armada_rect_hw(&state->dst); - if (dplane->base.state.dst_hw != val) { - dplane->base.state.dst_hw = val; - armada_reg_queue_set(regs, idx, val, - LCD_SPU_DZM_HPXL_VLN); - } + cfg = CFG_DMA_FMT(drm_fb_to_armada_fb(state->fb)->fmt) | + CFG_DMA_MOD(drm_fb_to_armada_fb(state->fb)->mod) | + CFG_CBSH_ENA; + if (state->visible) + cfg |= CFG_DMA_ENA; - val = armada_rect_yx(&state->dst); - if (dplane->base.state.dst_yx != val) { - dplane->base.state.dst_yx = val; - armada_reg_queue_set(regs, idx, val, - LCD_SPU_DMA_OVSA_HPXL_VLN); + /* + * Shifting a YUV packed format image by one pixel causes the + * U/V planes to swap. Compensate for it by also toggling + * the UV swap. + */ + format = state->fb->format; + if (format->num_planes == 1 && src_x & (format->hsub - 1)) + cfg ^= CFG_DMA_MOD(CFG_SWAPUV); + cfg_mask = CFG_CBSH_ENA | CFG_DMAFORMAT | + CFG_DMA_MOD(CFG_SWAPRB | CFG_SWAPUV | + CFG_SWAPYU | CFG_YUV2RGB) | + CFG_DMA_FTOGGLE | CFG_DMA_TSTMODE | + CFG_DMA_ENA; + + drm_to_armada_ovl_plane(plane)->wait_vblank = true; + } else if (old_state->visible != state->visible) { + cfg = state->visible ? CFG_DMA_ENA : 0; + cfg_mask = CFG_DMA_ENA; + } else { + cfg = cfg_mask = 0; } - - if (dplane->base.state.ctrl0 != ctrl0) { - dplane->base.state.ctrl0 = ctrl0; - armada_reg_queue_mod(regs, idx, ctrl0, - CFG_CBSH_ENA | CFG_DMAFORMAT | CFG_DMA_FTOGGLE | - CFG_DMA_HSMOOTH | CFG_DMA_TSTMODE | - CFG_DMA_MOD(CFG_SWAPRB | CFG_SWAPUV | CFG_SWAPYU | - CFG_YUV2RGB) | CFG_DMA_ENA, - LCD_SPU_DMA_CTRL0); - dplane->base.state.vsync_update = true; + if (drm_rect_width(&old_state->src) != drm_rect_width(&state->src) || + drm_rect_width(&old_state->dst) != drm_rect_width(&state->dst)) { + cfg_mask |= CFG_DMA_HSMOOTH; + if (drm_rect_width(&state->src) >> 16 != + drm_rect_width(&state->dst)) + cfg |= CFG_DMA_HSMOOTH; } - dplane->base.state.changed = idx != 0; - - return idx; -} - -static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane, - struct drm_plane_state *old_state) -{ - struct drm_plane_state *state = plane->state; - struct armada_crtc *dcrtc; - struct armada_regs *regs; + if (cfg_mask) + armada_reg_queue_mod(regs, idx, cfg, cfg_mask, + LCD_SPU_DMA_CTRL0); - DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name); - - if (!state->fb || WARN_ON(!state->crtc)) - return; - - DRM_DEBUG_KMS("[PLANE:%d:%s] is on [CRTC:%d:%s] with [FB:%d] visible %u->%u\n", - plane->base.id, plane->name, - state->crtc->base.id, state->crtc->name, - state->fb->base.id, - old_state->visible, state->visible); - - dcrtc = drm_to_armada_crtc(state->crtc); - regs = dcrtc->regs + dcrtc->regs_idx; - - dcrtc->regs_idx += armada_ovl_plane_update_state(state, regs); + dcrtc->regs_idx += idx; } static void armada_drm_overlay_plane_atomic_disable(struct drm_plane *plane, struct drm_plane_state *old_state) { - struct armada_plane *dplane = drm_to_armada_plane(plane); struct armada_crtc *dcrtc; struct armada_regs *regs; unsigned int idx = 0; @@ -227,8 +208,6 @@ static void armada_drm_overlay_plane_atomic_disable(struct drm_plane *plane, old_state->crtc->base.id, old_state->crtc->name, old_state->fb->base.id); - dplane->state.ctrl0 &= ~CFG_DMA_ENA; - dcrtc = drm_to_armada_crtc(old_state->crtc); regs = dcrtc->regs + dcrtc->regs_idx; @@ -288,7 +267,7 @@ static int armada_overlay_commit(struct drm_plane *plane, plane_funcs->atomic_update(plane, state); /* If nothing was updated, short-circuit */ - if (!dplane->base.state.changed) + if (dcrtc->regs_idx == 0) goto put_state; armada_reg_queue_end(dcrtc->regs, dcrtc->regs_idx); @@ -298,7 +277,7 @@ static int armada_overlay_commit(struct drm_plane *plane, armada_drm_plane_work_cancel(dcrtc, &dplane->base); /* Just updating the position/size? */ - if (!dplane->base.state.vsync_update) { + if (!dplane->wait_vblank) { armada_ovl_plane_work(dcrtc, work); goto put_state; } -- GitLab From d40af7b1ae23da718ba916fcd07f5b064efff921 Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 1374/1506] drm/armada: move primary plane to separate file Split out the primary plane support; this is now entirely separate from the CRTC support. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/armada/Makefile | 2 +- drivers/gpu/drm/armada/armada_crtc.c | 273 +--------------------- drivers/gpu/drm/armada/armada_crtc.h | 10 - drivers/gpu/drm/armada/armada_overlay.c | 3 +- drivers/gpu/drm/armada/armada_plane.c | 297 ++++++++++++++++++++++++ drivers/gpu/drm/armada/armada_plane.h | 16 ++ 6 files changed, 318 insertions(+), 283 deletions(-) create mode 100644 drivers/gpu/drm/armada/armada_plane.c create mode 100644 drivers/gpu/drm/armada/armada_plane.h diff --git a/drivers/gpu/drm/armada/Makefile b/drivers/gpu/drm/armada/Makefile index ecf25cf9f9f59..9bc3c32137248 100644 --- a/drivers/gpu/drm/armada/Makefile +++ b/drivers/gpu/drm/armada/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 armada-y := armada_crtc.o armada_drv.o armada_fb.o armada_fbdev.o \ - armada_gem.o armada_overlay.o armada_trace.o + armada_gem.o armada_overlay.o armada_plane.o armada_trace.o armada-y += armada_510.o armada-$(CONFIG_DEBUG_FS) += armada_debugfs.o diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 14339d5bed149..b9b0a508793d3 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -20,6 +20,7 @@ #include "armada_fb.h" #include "armada_gem.h" #include "armada_hw.h" +#include "armada_plane.h" #include "armada_trace.h" enum csc_mode { @@ -30,23 +31,6 @@ enum csc_mode { CSC_RGB_STUDIO = 2, }; -static const uint32_t armada_primary_formats[] = { - DRM_FORMAT_UYVY, - DRM_FORMAT_YUYV, - DRM_FORMAT_VYUY, - DRM_FORMAT_YVYU, - DRM_FORMAT_ARGB8888, - DRM_FORMAT_ABGR8888, - DRM_FORMAT_XRGB8888, - DRM_FORMAT_XBGR8888, - DRM_FORMAT_RGB888, - DRM_FORMAT_BGR888, - DRM_FORMAT_ARGB1555, - DRM_FORMAT_ABGR1555, - DRM_FORMAT_RGB565, - DRM_FORMAT_BGR565, -}; - /* * A note about interlacing. Let's consider HDMI 1920x1080i. * The timing parameters we have from X are: @@ -160,57 +144,6 @@ static void armada_drm_crtc_update(struct armada_crtc *dcrtc) } } -void armada_drm_plane_calc_addrs(u32 *addrs, struct drm_framebuffer *fb, - int x, int y) -{ - const struct drm_format_info *format = fb->format; - unsigned int num_planes = format->num_planes; - u32 addr = drm_fb_obj(fb)->dev_addr; - int i; - - if (num_planes > 3) - num_planes = 3; - - addrs[0] = addr + fb->offsets[0] + y * fb->pitches[0] + - x * format->cpp[0]; - - y /= format->vsub; - x /= format->hsub; - - for (i = 1; i < num_planes; i++) - addrs[i] = addr + fb->offsets[i] + y * fb->pitches[i] + - x * format->cpp[i]; - for (; i < 3; i++) - addrs[i] = 0; -} - -static unsigned armada_drm_crtc_calc_fb(struct drm_framebuffer *fb, - int x, int y, struct armada_regs *regs, bool interlaced) -{ - unsigned pitch = fb->pitches[0]; - u32 addrs[3], addr_odd, addr_even; - unsigned i = 0; - - DRM_DEBUG_DRIVER("pitch %u x %d y %d bpp %d\n", - pitch, x, y, fb->format->cpp[0] * 8); - - armada_drm_plane_calc_addrs(addrs, fb, x, y); - - addr_odd = addr_even = addrs[0]; - - if (interlaced) { - addr_even += pitch; - pitch *= 2; - } - - /* write offset, base, and pitch */ - armada_reg_queue_set(regs, i, addr_odd, LCD_CFG_GRA_START_ADDR0); - armada_reg_queue_set(regs, i, addr_even, LCD_CFG_GRA_START_ADDR1); - armada_reg_queue_mod(regs, i, pitch, 0xffff, LCD_CFG_GRA_PITCH); - - return i; -} - static void armada_drm_plane_work_call(struct armada_crtc *dcrtc, struct armada_plane_work *work, void (*fn)(struct armada_crtc *, struct armada_plane_work *)) @@ -1067,194 +1000,6 @@ static const struct drm_crtc_funcs armada_crtc_funcs = { .disable_vblank = armada_drm_crtc_disable_vblank, }; -int armada_drm_plane_prepare_fb(struct drm_plane *plane, - struct drm_plane_state *state) -{ - DRM_DEBUG_KMS("[PLANE:%d:%s] [FB:%d]\n", - plane->base.id, plane->name, - state->fb ? state->fb->base.id : 0); - - /* - * Take a reference on the new framebuffer - we want to - * hold on to it while the hardware is displaying it. - */ - if (state->fb) - drm_framebuffer_get(state->fb); - return 0; -} - -void armada_drm_plane_cleanup_fb(struct drm_plane *plane, - struct drm_plane_state *old_state) -{ - DRM_DEBUG_KMS("[PLANE:%d:%s] [FB:%d]\n", - plane->base.id, plane->name, - old_state->fb ? old_state->fb->base.id : 0); - - if (old_state->fb) - drm_framebuffer_put(old_state->fb); -} - -int armada_drm_plane_atomic_check(struct drm_plane *plane, - struct drm_plane_state *state) -{ - if (state->fb && !WARN_ON(!state->crtc)) { - struct drm_crtc *crtc = state->crtc; - struct drm_crtc_state *crtc_state; - - if (state->state) - crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc); - else - crtc_state = crtc->state; - return drm_atomic_helper_check_plane_state(state, crtc_state, - 0, INT_MAX, - true, false); - } else { - state->visible = false; - } - return 0; -} - -static void armada_drm_primary_plane_atomic_update(struct drm_plane *plane, - struct drm_plane_state *old_state) -{ - struct drm_plane_state *state = plane->state; - struct armada_crtc *dcrtc; - struct armada_regs *regs; - u32 cfg, cfg_mask, val; - unsigned int idx; - - DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name); - - if (!state->fb || WARN_ON(!state->crtc)) - return; - - DRM_DEBUG_KMS("[PLANE:%d:%s] is on [CRTC:%d:%s] with [FB:%d] visible %u->%u\n", - plane->base.id, plane->name, - state->crtc->base.id, state->crtc->name, - state->fb->base.id, - old_state->visible, state->visible); - - dcrtc = drm_to_armada_crtc(state->crtc); - regs = dcrtc->regs + dcrtc->regs_idx; - - idx = 0; - if (!old_state->visible && state->visible) { - val = CFG_PDWN64x66; - if (drm_fb_to_armada_fb(state->fb)->fmt > CFG_420) - val |= CFG_PDWN256x24; - armada_reg_queue_mod(regs, idx, 0, val, LCD_SPU_SRAM_PARA1); - } - val = armada_rect_hw_fp(&state->src); - if (armada_rect_hw_fp(&old_state->src) != val) - armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_HPXL_VLN); - val = armada_rect_yx(&state->dst); - if (armada_rect_yx(&old_state->dst) != val) - armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_OVSA_HPXL_VLN); - val = armada_rect_hw(&state->dst); - if (armada_rect_hw(&old_state->dst) != val) - armada_reg_queue_set(regs, idx, val, LCD_SPU_GZM_HPXL_VLN); - if (old_state->src.x1 != state->src.x1 || - old_state->src.y1 != state->src.y1 || - old_state->fb != state->fb) { - idx += armada_drm_crtc_calc_fb(state->fb, - state->src.x1 >> 16, - state->src.y1 >> 16, - regs + idx, - dcrtc->interlaced); - } - if (old_state->fb != state->fb) { - cfg = CFG_GRA_FMT(drm_fb_to_armada_fb(state->fb)->fmt) | - CFG_GRA_MOD(drm_fb_to_armada_fb(state->fb)->mod); - if (drm_fb_to_armada_fb(state->fb)->fmt > CFG_420) - cfg |= CFG_PALETTE_ENA; - if (state->visible) - cfg |= CFG_GRA_ENA; - if (dcrtc->interlaced) - cfg |= CFG_GRA_FTOGGLE; - cfg_mask = CFG_GRAFORMAT | - CFG_GRA_MOD(CFG_SWAPRB | CFG_SWAPUV | - CFG_SWAPYU | CFG_YUV2RGB) | - CFG_PALETTE_ENA | CFG_GRA_FTOGGLE | - CFG_GRA_ENA; - } else if (old_state->visible != state->visible) { - cfg = state->visible ? CFG_GRA_ENA : 0; - cfg_mask = CFG_GRA_ENA; - } else { - cfg = cfg_mask = 0; - } - if (drm_rect_width(&old_state->src) != drm_rect_width(&state->src) || - drm_rect_width(&old_state->dst) != drm_rect_width(&state->dst)) { - cfg_mask |= CFG_GRA_HSMOOTH; - if (drm_rect_width(&state->src) >> 16 != - drm_rect_width(&state->dst)) - cfg |= CFG_GRA_HSMOOTH; - } - - if (cfg_mask) - armada_reg_queue_mod(regs, idx, cfg, cfg_mask, - LCD_SPU_DMA_CTRL0); - - dcrtc->regs_idx += idx; -} - -static void armada_drm_primary_plane_atomic_disable(struct drm_plane *plane, - struct drm_plane_state *old_state) -{ - struct armada_crtc *dcrtc; - struct armada_regs *regs; - unsigned int idx = 0; - - DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name); - - if (!old_state->crtc) - return; - - DRM_DEBUG_KMS("[PLANE:%d:%s] was on [CRTC:%d:%s] with [FB:%d]\n", - plane->base.id, plane->name, - old_state->crtc->base.id, old_state->crtc->name, - old_state->fb->base.id); - - dcrtc = drm_to_armada_crtc(old_state->crtc); - regs = dcrtc->regs + dcrtc->regs_idx; - - /* Disable plane and power down most RAMs and FIFOs */ - armada_reg_queue_mod(regs, idx, 0, CFG_GRA_ENA, LCD_SPU_DMA_CTRL0); - armada_reg_queue_mod(regs, idx, CFG_PDWN256x32 | CFG_PDWN256x24 | - CFG_PDWN256x8 | CFG_PDWN32x32 | CFG_PDWN64x66, - 0, LCD_SPU_SRAM_PARA1); - - dcrtc->regs_idx += idx; -} - -static const struct drm_plane_helper_funcs armada_primary_plane_helper_funcs = { - .prepare_fb = armada_drm_plane_prepare_fb, - .cleanup_fb = armada_drm_plane_cleanup_fb, - .atomic_check = armada_drm_plane_atomic_check, - .atomic_update = armada_drm_primary_plane_atomic_update, - .atomic_disable = armada_drm_primary_plane_atomic_disable, -}; - -static const struct drm_plane_funcs armada_primary_plane_funcs = { - .update_plane = drm_plane_helper_update, - .disable_plane = drm_plane_helper_disable, - .destroy = drm_primary_helper_destroy, - .reset = drm_atomic_helper_plane_reset, - .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, -}; - -int armada_drm_plane_init(struct armada_plane *plane) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(plane->works); i++) - plane->works[i].plane = &plane->base; - - init_waitqueue_head(&plane->frame_wait); - - return 0; -} - static const struct drm_prop_enum_list armada_drm_csc_yuv_enum_list[] = { { CSC_AUTO, "Auto" }, { CSC_YUV_CCIR601, "CCIR601" }, @@ -1363,21 +1108,7 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev, goto err_crtc; } - ret = armada_drm_plane_init(primary); - if (ret) { - kfree(primary); - goto err_crtc; - } - - drm_plane_helper_add(&primary->base, - &armada_primary_plane_helper_funcs); - - ret = drm_universal_plane_init(drm, &primary->base, 0, - &armada_primary_plane_funcs, - armada_primary_formats, - ARRAY_SIZE(armada_primary_formats), - NULL, - DRM_PLANE_TYPE_PRIMARY, NULL); + ret = armada_drm_primary_plane_init(drm, primary); if (ret) { kfree(primary); goto err_crtc; diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h index 79ac0db047c9e..2672c5cc0e455 100644 --- a/drivers/gpu/drm/armada/armada_crtc.h +++ b/drivers/gpu/drm/armada/armada_crtc.h @@ -54,21 +54,11 @@ struct armada_plane { }; #define drm_to_armada_plane(p) container_of(p, struct armada_plane, base) -int armada_drm_plane_init(struct armada_plane *plane); int armada_drm_plane_work_queue(struct armada_crtc *dcrtc, struct armada_plane_work *work); int armada_drm_plane_work_wait(struct armada_plane *plane, long timeout); void armada_drm_plane_work_cancel(struct armada_crtc *dcrtc, struct armada_plane *plane); -void armada_drm_plane_calc_addrs(u32 *addrs, struct drm_framebuffer *fb, - int x, int y); - -int armada_drm_plane_prepare_fb(struct drm_plane *plane, - struct drm_plane_state *state); -void armada_drm_plane_cleanup_fb(struct drm_plane *plane, - struct drm_plane_state *old_state); -int armada_drm_plane_atomic_check(struct drm_plane *plane, - struct drm_plane_state *state); struct armada_crtc { struct drm_crtc crtc; diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index aa2a12aec3cc5..214b2171a8f45 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -10,13 +10,14 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_plane_helper.h> +#include <drm/armada_drm.h> #include "armada_crtc.h" #include "armada_drm.h" #include "armada_fb.h" #include "armada_gem.h" #include "armada_hw.h" -#include <drm/armada_drm.h> #include "armada_ioctlP.h" +#include "armada_plane.h" #include "armada_trace.h" struct armada_ovl_plane_properties { diff --git a/drivers/gpu/drm/armada/armada_plane.c b/drivers/gpu/drm/armada/armada_plane.c new file mode 100644 index 0000000000000..9d1eec1dc720c --- /dev/null +++ b/drivers/gpu/drm/armada/armada_plane.c @@ -0,0 +1,297 @@ +/* + * Copyright (C) 2012 Russell King + * Rewritten from the dovefb driver, and Armada510 manuals. + * + * 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 <drm/drmP.h> +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_helper.h> +#include <drm/drm_plane_helper.h> +#include "armada_crtc.h" +#include "armada_drm.h" +#include "armada_fb.h" +#include "armada_gem.h" +#include "armada_hw.h" +#include "armada_plane.h" +#include "armada_trace.h" + +static const uint32_t armada_primary_formats[] = { + DRM_FORMAT_UYVY, + DRM_FORMAT_YUYV, + DRM_FORMAT_VYUY, + DRM_FORMAT_YVYU, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_RGB888, + DRM_FORMAT_BGR888, + DRM_FORMAT_ARGB1555, + DRM_FORMAT_ABGR1555, + DRM_FORMAT_RGB565, + DRM_FORMAT_BGR565, +}; + +void armada_drm_plane_calc_addrs(u32 *addrs, struct drm_framebuffer *fb, + int x, int y) +{ + const struct drm_format_info *format = fb->format; + unsigned int num_planes = format->num_planes; + u32 addr = drm_fb_obj(fb)->dev_addr; + int i; + + if (num_planes > 3) + num_planes = 3; + + addrs[0] = addr + fb->offsets[0] + y * fb->pitches[0] + + x * format->cpp[0]; + + y /= format->vsub; + x /= format->hsub; + + for (i = 1; i < num_planes; i++) + addrs[i] = addr + fb->offsets[i] + y * fb->pitches[i] + + x * format->cpp[i]; + for (; i < 3; i++) + addrs[i] = 0; +} + +static unsigned armada_drm_crtc_calc_fb(struct drm_framebuffer *fb, + int x, int y, struct armada_regs *regs, bool interlaced) +{ + unsigned pitch = fb->pitches[0]; + u32 addrs[3], addr_odd, addr_even; + unsigned i = 0; + + DRM_DEBUG_DRIVER("pitch %u x %d y %d bpp %d\n", + pitch, x, y, fb->format->cpp[0] * 8); + + armada_drm_plane_calc_addrs(addrs, fb, x, y); + + addr_odd = addr_even = addrs[0]; + + if (interlaced) { + addr_even += pitch; + pitch *= 2; + } + + /* write offset, base, and pitch */ + armada_reg_queue_set(regs, i, addr_odd, LCD_CFG_GRA_START_ADDR0); + armada_reg_queue_set(regs, i, addr_even, LCD_CFG_GRA_START_ADDR1); + armada_reg_queue_mod(regs, i, pitch, 0xffff, LCD_CFG_GRA_PITCH); + + return i; +} + +int armada_drm_plane_prepare_fb(struct drm_plane *plane, + struct drm_plane_state *state) +{ + DRM_DEBUG_KMS("[PLANE:%d:%s] [FB:%d]\n", + plane->base.id, plane->name, + state->fb ? state->fb->base.id : 0); + + /* + * Take a reference on the new framebuffer - we want to + * hold on to it while the hardware is displaying it. + */ + if (state->fb) + drm_framebuffer_get(state->fb); + return 0; +} + +void armada_drm_plane_cleanup_fb(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + DRM_DEBUG_KMS("[PLANE:%d:%s] [FB:%d]\n", + plane->base.id, plane->name, + old_state->fb ? old_state->fb->base.id : 0); + + if (old_state->fb) + drm_framebuffer_put(old_state->fb); +} + +int armada_drm_plane_atomic_check(struct drm_plane *plane, + struct drm_plane_state *state) +{ + if (state->fb && !WARN_ON(!state->crtc)) { + struct drm_crtc *crtc = state->crtc; + struct drm_crtc_state *crtc_state; + + if (state->state) + crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc); + else + crtc_state = crtc->state; + return drm_atomic_helper_check_plane_state(state, crtc_state, + 0, INT_MAX, + true, false); + } else { + state->visible = false; + } + return 0; +} + +static void armada_drm_primary_plane_atomic_update(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + struct drm_plane_state *state = plane->state; + struct armada_crtc *dcrtc; + struct armada_regs *regs; + u32 cfg, cfg_mask, val; + unsigned int idx; + + DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name); + + if (!state->fb || WARN_ON(!state->crtc)) + return; + + DRM_DEBUG_KMS("[PLANE:%d:%s] is on [CRTC:%d:%s] with [FB:%d] visible %u->%u\n", + plane->base.id, plane->name, + state->crtc->base.id, state->crtc->name, + state->fb->base.id, + old_state->visible, state->visible); + + dcrtc = drm_to_armada_crtc(state->crtc); + regs = dcrtc->regs + dcrtc->regs_idx; + + idx = 0; + if (!old_state->visible && state->visible) { + val = CFG_PDWN64x66; + if (drm_fb_to_armada_fb(state->fb)->fmt > CFG_420) + val |= CFG_PDWN256x24; + armada_reg_queue_mod(regs, idx, 0, val, LCD_SPU_SRAM_PARA1); + } + val = armada_rect_hw_fp(&state->src); + if (armada_rect_hw_fp(&old_state->src) != val) + armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_HPXL_VLN); + val = armada_rect_yx(&state->dst); + if (armada_rect_yx(&old_state->dst) != val) + armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_OVSA_HPXL_VLN); + val = armada_rect_hw(&state->dst); + if (armada_rect_hw(&old_state->dst) != val) + armada_reg_queue_set(regs, idx, val, LCD_SPU_GZM_HPXL_VLN); + if (old_state->src.x1 != state->src.x1 || + old_state->src.y1 != state->src.y1 || + old_state->fb != state->fb) { + idx += armada_drm_crtc_calc_fb(state->fb, + state->src.x1 >> 16, + state->src.y1 >> 16, + regs + idx, + dcrtc->interlaced); + } + if (old_state->fb != state->fb) { + cfg = CFG_GRA_FMT(drm_fb_to_armada_fb(state->fb)->fmt) | + CFG_GRA_MOD(drm_fb_to_armada_fb(state->fb)->mod); + if (drm_fb_to_armada_fb(state->fb)->fmt > CFG_420) + cfg |= CFG_PALETTE_ENA; + if (state->visible) + cfg |= CFG_GRA_ENA; + if (dcrtc->interlaced) + cfg |= CFG_GRA_FTOGGLE; + cfg_mask = CFG_GRAFORMAT | + CFG_GRA_MOD(CFG_SWAPRB | CFG_SWAPUV | + CFG_SWAPYU | CFG_YUV2RGB) | + CFG_PALETTE_ENA | CFG_GRA_FTOGGLE | + CFG_GRA_ENA; + } else if (old_state->visible != state->visible) { + cfg = state->visible ? CFG_GRA_ENA : 0; + cfg_mask = CFG_GRA_ENA; + } else { + cfg = cfg_mask = 0; + } + if (drm_rect_width(&old_state->src) != drm_rect_width(&state->src) || + drm_rect_width(&old_state->dst) != drm_rect_width(&state->dst)) { + cfg_mask |= CFG_GRA_HSMOOTH; + if (drm_rect_width(&state->src) >> 16 != + drm_rect_width(&state->dst)) + cfg |= CFG_GRA_HSMOOTH; + } + + if (cfg_mask) + armada_reg_queue_mod(regs, idx, cfg, cfg_mask, + LCD_SPU_DMA_CTRL0); + + dcrtc->regs_idx += idx; +} + +static void armada_drm_primary_plane_atomic_disable(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + struct armada_crtc *dcrtc; + struct armada_regs *regs; + unsigned int idx = 0; + + DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name); + + if (!old_state->crtc) + return; + + DRM_DEBUG_KMS("[PLANE:%d:%s] was on [CRTC:%d:%s] with [FB:%d]\n", + plane->base.id, plane->name, + old_state->crtc->base.id, old_state->crtc->name, + old_state->fb->base.id); + + dcrtc = drm_to_armada_crtc(old_state->crtc); + regs = dcrtc->regs + dcrtc->regs_idx; + + /* Disable plane and power down most RAMs and FIFOs */ + armada_reg_queue_mod(regs, idx, 0, CFG_GRA_ENA, LCD_SPU_DMA_CTRL0); + armada_reg_queue_mod(regs, idx, CFG_PDWN256x32 | CFG_PDWN256x24 | + CFG_PDWN256x8 | CFG_PDWN32x32 | CFG_PDWN64x66, + 0, LCD_SPU_SRAM_PARA1); + + dcrtc->regs_idx += idx; +} + +static const struct drm_plane_helper_funcs armada_primary_plane_helper_funcs = { + .prepare_fb = armada_drm_plane_prepare_fb, + .cleanup_fb = armada_drm_plane_cleanup_fb, + .atomic_check = armada_drm_plane_atomic_check, + .atomic_update = armada_drm_primary_plane_atomic_update, + .atomic_disable = armada_drm_primary_plane_atomic_disable, +}; + +static const struct drm_plane_funcs armada_primary_plane_funcs = { + .update_plane = drm_plane_helper_update, + .disable_plane = drm_plane_helper_disable, + .destroy = drm_primary_helper_destroy, + .reset = drm_atomic_helper_plane_reset, + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, +}; + +int armada_drm_plane_init(struct armada_plane *plane) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(plane->works); i++) + plane->works[i].plane = &plane->base; + + init_waitqueue_head(&plane->frame_wait); + + return 0; +} + +int armada_drm_primary_plane_init(struct drm_device *drm, + struct armada_plane *primary) +{ + int ret; + + ret = armada_drm_plane_init(primary); + if (ret) + return ret; + + drm_plane_helper_add(&primary->base, + &armada_primary_plane_helper_funcs); + + ret = drm_universal_plane_init(drm, &primary->base, 0, + &armada_primary_plane_funcs, + armada_primary_formats, + ARRAY_SIZE(armada_primary_formats), + NULL, + DRM_PLANE_TYPE_PRIMARY, NULL); + + return ret; +} diff --git a/drivers/gpu/drm/armada/armada_plane.h b/drivers/gpu/drm/armada/armada_plane.h new file mode 100644 index 0000000000000..3c83160039077 --- /dev/null +++ b/drivers/gpu/drm/armada/armada_plane.h @@ -0,0 +1,16 @@ +#ifndef ARMADA_PLANE_H +#define ARMADA_PLANE_H + +void armada_drm_plane_calc_addrs(u32 *addrs, struct drm_framebuffer *fb, + int x, int y); +int armada_drm_plane_prepare_fb(struct drm_plane *plane, + struct drm_plane_state *state); +void armada_drm_plane_cleanup_fb(struct drm_plane *plane, + struct drm_plane_state *old_state); +int armada_drm_plane_atomic_check(struct drm_plane *plane, + struct drm_plane_state *state); +int armada_drm_plane_init(struct armada_plane *plane); +int armada_drm_primary_plane_init(struct drm_device *drm, + struct armada_plane *primary); + +#endif -- GitLab From 63b93c0834a0cb7d537b30f8e815a9f63d0da37f Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 1375/1506] drm/armada: move plane works to overlay Only overlay makes use of these now, so move these to the overlay code. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/armada/armada_crtc.h | 2 -- drivers/gpu/drm/armada/armada_overlay.c | 12 ++++++++---- drivers/gpu/drm/armada/armada_plane.c | 6 ------ 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h index 2672c5cc0e455..73ddd7d61eb48 100644 --- a/drivers/gpu/drm/armada/armada_crtc.h +++ b/drivers/gpu/drm/armada/armada_crtc.h @@ -48,8 +48,6 @@ struct armada_plane_work { struct armada_plane { struct drm_plane base; wait_queue_head_t frame_wait; - bool next_work; - struct armada_plane_work works[2]; struct armada_plane_work *work; }; #define drm_to_armada_plane(p) container_of(p, struct armada_plane, base) diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index 214b2171a8f45..40868e485ae81 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -36,6 +36,8 @@ struct armada_ovl_plane_properties { struct armada_ovl_plane { struct armada_plane base; + struct armada_plane_work works[2]; + bool next_work; bool wait_vblank; struct armada_ovl_plane_properties prop; }; @@ -245,7 +247,7 @@ static int armada_overlay_commit(struct drm_plane *plane, if (ret) goto put_state; - work = &dplane->base.works[dplane->base.next_work]; + work = &dplane->works[dplane->next_work]; if (plane->state->fb != state->fb) { /* @@ -295,7 +297,7 @@ static int armada_overlay_commit(struct drm_plane *plane, ret = 0; } - dplane->base.next_work = !dplane->base.next_work; + dplane->next_work = !dplane->next_work; put_state: drm_atomic_helper_plane_destroy_state(plane, state); @@ -515,8 +517,10 @@ int armada_overlay_plane_create(struct drm_device *dev, unsigned long crtcs) return ret; } - dplane->base.works[0].fn = armada_ovl_plane_work; - dplane->base.works[1].fn = armada_ovl_plane_work; + dplane->works[0].plane = &dplane->base.base; + dplane->works[0].fn = armada_ovl_plane_work; + dplane->works[1].plane = &dplane->base.base; + dplane->works[1].fn = armada_ovl_plane_work; drm_plane_helper_add(&dplane->base.base, &armada_overlay_plane_helper_funcs); diff --git a/drivers/gpu/drm/armada/armada_plane.c b/drivers/gpu/drm/armada/armada_plane.c index 9d1eec1dc720c..1cb6a605bda9c 100644 --- a/drivers/gpu/drm/armada/armada_plane.c +++ b/drivers/gpu/drm/armada/armada_plane.c @@ -264,13 +264,7 @@ static const struct drm_plane_funcs armada_primary_plane_funcs = { int armada_drm_plane_init(struct armada_plane *plane) { - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(plane->works); i++) - plane->works[i].plane = &plane->base; - init_waitqueue_head(&plane->frame_wait); - return 0; } -- GitLab From 61ba252705a6d5b8dd71bd2ccc544d33cb2af623 Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 1376/1506] drm/armada: move CBSH properties into overlay plane state Move the contrast, brightness, and saturation properties to the overlay plane state structure, and call our overlay commit function to update the hardware via the planes atomic_update() method. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/armada/armada_crtc.h | 2 +- drivers/gpu/drm/armada/armada_overlay.c | 163 ++++++++++++++++++++---- 2 files changed, 136 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h index 73ddd7d61eb48..c27435a8776a8 100644 --- a/drivers/gpu/drm/armada/armada_crtc.h +++ b/drivers/gpu/drm/armada/armada_crtc.h @@ -42,7 +42,7 @@ struct armada_plane_work { struct drm_plane *plane; struct drm_framebuffer *old_fb; struct drm_pending_vblank_event *event; - struct armada_regs regs[14]; + struct armada_regs regs[24]; }; struct armada_plane { diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index 40868e485ae81..ec3ce28f162e3 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -20,6 +20,10 @@ #include "armada_plane.h" #include "armada_trace.h" +#define DEFAULT_BRIGHTNESS 0 +#define DEFAULT_CONTRAST 0x4000 +#define DEFAULT_SATURATION 0x4000 + struct armada_ovl_plane_properties { uint32_t colorkey_yr; uint32_t colorkey_ug; @@ -27,9 +31,6 @@ struct armada_ovl_plane_properties { #define K2R(val) (((val) >> 0) & 0xff) #define K2G(val) (((val) >> 8) & 0xff) #define K2B(val) (((val) >> 16) & 0xff) - int16_t brightness; - uint16_t contrast; - uint16_t saturation; uint32_t colorkey_mode; uint32_t colorkey_enable; }; @@ -44,6 +45,26 @@ struct armada_ovl_plane { #define drm_to_armada_ovl_plane(p) \ container_of(p, struct armada_ovl_plane, base.base) +struct armada_overlay_state { + struct drm_plane_state base; + s16 brightness; + u16 contrast; + u16 saturation; +}; +#define drm_to_overlay_state(s) \ + container_of(s, struct armada_overlay_state, base) + +static inline u32 armada_spu_contrast(struct drm_plane_state *state) +{ + return drm_to_overlay_state(state)->brightness << 16 | + drm_to_overlay_state(state)->contrast; +} + +static inline u32 armada_spu_saturation(struct drm_plane_state *state) +{ + /* Docs say 15:0, but it seems to actually be 31:16 on Armada 510 */ + return drm_to_overlay_state(state)->saturation << 16; +} static void armada_ovl_update_attr(struct armada_ovl_plane_properties *prop, @@ -53,13 +74,6 @@ armada_ovl_update_attr(struct armada_ovl_plane_properties *prop, writel_relaxed(prop->colorkey_ug, dcrtc->base + LCD_SPU_COLORKEY_U); writel_relaxed(prop->colorkey_vb, dcrtc->base + LCD_SPU_COLORKEY_V); - writel_relaxed(prop->brightness << 16 | prop->contrast, - dcrtc->base + LCD_SPU_CONTRAST); - /* Docs say 15:0, but it seems to actually be 31:16 on Armada 510 */ - writel_relaxed(prop->saturation << 16, - dcrtc->base + LCD_SPU_SATURATION); - writel_relaxed(0x00002000, dcrtc->base + LCD_SPU_CBSH_HUE); - spin_lock_irq(&dcrtc->irq_lock); armada_updatel(prop->colorkey_mode, CFG_CKMODE_MASK | CFG_ALPHAM_MASK | CFG_ALPHA_MASK, @@ -191,6 +205,17 @@ static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane, armada_reg_queue_mod(regs, idx, cfg, cfg_mask, LCD_SPU_DMA_CTRL0); + val = armada_spu_contrast(state); + if ((!old_state->visible && state->visible) || + armada_spu_contrast(old_state) != val) + armada_reg_queue_set(regs, idx, val, LCD_SPU_CONTRAST); + val = armada_spu_saturation(state); + if ((!old_state->visible && state->visible) || + armada_spu_saturation(old_state) != val) + armada_reg_queue_set(regs, idx, val, LCD_SPU_SATURATION); + if (!old_state->visible && state->visible) + armada_reg_queue_set(regs, idx, 0x00002000, LCD_SPU_CBSH_HUE); + dcrtc->regs_idx += idx; } @@ -264,6 +289,10 @@ static int armada_overlay_commit(struct drm_plane *plane, /* Point of no return */ swap(plane->state, state); + /* No CRTC, can't update */ + if (!plane->state->crtc) + goto put_state; + dcrtc->regs_idx = 0; dcrtc->regs = work->regs; @@ -300,7 +329,7 @@ static int armada_overlay_commit(struct drm_plane *plane, dplane->next_work = !dplane->next_work; put_state: - drm_atomic_helper_plane_destroy_state(plane, state); + plane->funcs->atomic_destroy_state(plane, state); return ret; } @@ -318,7 +347,7 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, src_x, src_y, src_w, src_h); /* Construct new state for the overlay plane */ - state = drm_atomic_helper_plane_duplicate_state(plane); + state = plane->funcs->atomic_duplicate_state(plane); if (!state) return -ENOMEM; @@ -404,15 +433,22 @@ static int armada_ovl_plane_set_property(struct drm_plane *plane, dplane->prop.colorkey_enable = ADV_GRACOLORKEY; } update_attr = true; - } else if (property == priv->brightness_prop) { - dplane->prop.brightness = val - 256; - update_attr = true; - } else if (property == priv->contrast_prop) { - dplane->prop.contrast = val; - update_attr = true; - } else if (property == priv->saturation_prop) { - dplane->prop.saturation = val; - update_attr = true; + } else { + struct drm_plane_state *state; + int ret; + + state = plane->funcs->atomic_duplicate_state(plane); + if (!state) + return -ENOMEM; + + ret = plane->funcs->atomic_set_property(plane, state, property, + val); + if (ret) { + plane->funcs->atomic_destroy_state(plane, state); + return ret; + } + + return armada_overlay_commit(plane, state); } if (update_attr && dplane->base.base.crtc) @@ -422,12 +458,85 @@ static int armada_ovl_plane_set_property(struct drm_plane *plane, return 0; } +static void armada_overlay_reset(struct drm_plane *plane) +{ + struct armada_overlay_state *state; + + if (plane->state) + __drm_atomic_helper_plane_destroy_state(plane->state); + kfree(plane->state); + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (state) { + state->base.plane = plane; + state->base.rotation = DRM_MODE_ROTATE_0; + state->brightness = DEFAULT_BRIGHTNESS; + state->contrast = DEFAULT_CONTRAST; + state->saturation = DEFAULT_SATURATION; + } + plane->state = &state->base; +} + +struct drm_plane_state * +armada_overlay_duplicate_state(struct drm_plane *plane) +{ + struct armada_overlay_state *state; + + if (WARN_ON(!plane->state)) + return NULL; + + state = kmemdup(plane->state, sizeof(*state), GFP_KERNEL); + if (state) + __drm_atomic_helper_plane_duplicate_state(plane, &state->base); + return &state->base; +} + +static int armada_overlay_set_property(struct drm_plane *plane, + struct drm_plane_state *state, struct drm_property *property, + uint64_t val) +{ + struct armada_private *priv = plane->dev->dev_private; + + if (property == priv->brightness_prop) { + drm_to_overlay_state(state)->brightness = val - 256; + } else if (property == priv->contrast_prop) { + drm_to_overlay_state(state)->contrast = val; + } else if (property == priv->saturation_prop) { + drm_to_overlay_state(state)->saturation = val; + } else { + return -EINVAL; + } + return 0; +} + +static int armada_overlay_get_property(struct drm_plane *plane, + const struct drm_plane_state *state, struct drm_property *property, + uint64_t *val) +{ + struct armada_private *priv = plane->dev->dev_private; + + if (property == priv->brightness_prop) { + *val = drm_to_overlay_state(state)->brightness + 256; + } else if (property == priv->contrast_prop) { + *val = drm_to_overlay_state(state)->contrast; + } else if (property == priv->saturation_prop) { + *val = drm_to_overlay_state(state)->saturation; + } else { + return -EINVAL; + } + return 0; +} + static const struct drm_plane_funcs armada_ovl_plane_funcs = { .update_plane = armada_ovl_plane_update, .disable_plane = drm_plane_helper_disable, .destroy = armada_ovl_plane_destroy, .set_property = armada_ovl_plane_set_property, - .reset = drm_atomic_helper_plane_reset, + .reset = armada_overlay_reset, + .atomic_duplicate_state = armada_overlay_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, + .atomic_set_property = armada_overlay_set_property, + .atomic_get_property = armada_overlay_get_property, }; static const uint32_t armada_ovl_formats[] = { @@ -542,9 +651,6 @@ int armada_overlay_plane_create(struct drm_device *dev, unsigned long crtcs) dplane->prop.colorkey_mode = CFG_CKMODE(CKMODE_RGB) | CFG_ALPHAM_GRA | CFG_ALPHA(0); dplane->prop.colorkey_enable = ADV_GRACOLORKEY; - dplane->prop.brightness = 0; - dplane->prop.contrast = 0x4000; - dplane->prop.saturation = 0x4000; mobj = &dplane->base.base.base; drm_object_attach_property(mobj, priv->colorkey_prop, @@ -559,11 +665,12 @@ int armada_overlay_plane_create(struct drm_device *dev, unsigned long crtcs) 0x000000); drm_object_attach_property(mobj, priv->colorkey_mode_prop, CKMODE_RGB); - drm_object_attach_property(mobj, priv->brightness_prop, 256); + drm_object_attach_property(mobj, priv->brightness_prop, + 256 + DEFAULT_BRIGHTNESS); drm_object_attach_property(mobj, priv->contrast_prop, - dplane->prop.contrast); + DEFAULT_CONTRAST); drm_object_attach_property(mobj, priv->saturation_prop, - dplane->prop.saturation); + DEFAULT_SATURATION); return 0; } -- GitLab From c96103b6c49ff9a8710e580da72c0f116d24a76c Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 1377/1506] drm/armada: move colorkey properties into overlay plane state Move the overlay plane colorkey properties into the plane state, keeping the existing driver behaviour to avoid breaking userspace. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/armada/armada_overlay.c | 251 +++++++++++++----------- 1 file changed, 132 insertions(+), 119 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index ec3ce28f162e3..7f75df4f83907 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -24,29 +24,22 @@ #define DEFAULT_CONTRAST 0x4000 #define DEFAULT_SATURATION 0x4000 -struct armada_ovl_plane_properties { - uint32_t colorkey_yr; - uint32_t colorkey_ug; - uint32_t colorkey_vb; -#define K2R(val) (((val) >> 0) & 0xff) -#define K2G(val) (((val) >> 8) & 0xff) -#define K2B(val) (((val) >> 16) & 0xff) - uint32_t colorkey_mode; - uint32_t colorkey_enable; -}; - struct armada_ovl_plane { struct armada_plane base; struct armada_plane_work works[2]; bool next_work; bool wait_vblank; - struct armada_ovl_plane_properties prop; }; #define drm_to_armada_ovl_plane(p) \ container_of(p, struct armada_ovl_plane, base.base) struct armada_overlay_state { struct drm_plane_state base; + u32 colorkey_yr; + u32 colorkey_ug; + u32 colorkey_vb; + u32 colorkey_mode; + u32 colorkey_enable; s16 brightness; u16 contrast; u16 saturation; @@ -66,25 +59,6 @@ static inline u32 armada_spu_saturation(struct drm_plane_state *state) return drm_to_overlay_state(state)->saturation << 16; } -static void -armada_ovl_update_attr(struct armada_ovl_plane_properties *prop, - struct armada_crtc *dcrtc) -{ - writel_relaxed(prop->colorkey_yr, dcrtc->base + LCD_SPU_COLORKEY_Y); - writel_relaxed(prop->colorkey_ug, dcrtc->base + LCD_SPU_COLORKEY_U); - writel_relaxed(prop->colorkey_vb, dcrtc->base + LCD_SPU_COLORKEY_V); - - spin_lock_irq(&dcrtc->irq_lock); - armada_updatel(prop->colorkey_mode, - CFG_CKMODE_MASK | CFG_ALPHAM_MASK | CFG_ALPHA_MASK, - dcrtc->base + LCD_SPU_DMA_CTRL1); - if (dcrtc->variant->has_spu_adv_reg) - armada_updatel(prop->colorkey_enable, - ADV_GRACOLORKEY | ADV_VIDCOLORKEY, - dcrtc->base + LCD_SPU_ADV_REG); - spin_unlock_irq(&dcrtc->irq_lock); -} - /* === Plane support === */ static void armada_ovl_plane_work(struct armada_crtc *dcrtc, struct armada_plane_work *work) @@ -215,6 +189,30 @@ static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane, armada_reg_queue_set(regs, idx, val, LCD_SPU_SATURATION); if (!old_state->visible && state->visible) armada_reg_queue_set(regs, idx, 0x00002000, LCD_SPU_CBSH_HUE); + val = drm_to_overlay_state(state)->colorkey_yr; + if ((!old_state->visible && state->visible) || + drm_to_overlay_state(old_state)->colorkey_yr != val) + armada_reg_queue_set(regs, idx, val, LCD_SPU_COLORKEY_Y); + val = drm_to_overlay_state(state)->colorkey_ug; + if ((!old_state->visible && state->visible) || + drm_to_overlay_state(old_state)->colorkey_ug != val) + armada_reg_queue_set(regs, idx, val, LCD_SPU_COLORKEY_U); + val = drm_to_overlay_state(state)->colorkey_vb; + if ((!old_state->visible && state->visible) || + drm_to_overlay_state(old_state)->colorkey_vb != val) + armada_reg_queue_set(regs, idx, val, LCD_SPU_COLORKEY_V); + val = drm_to_overlay_state(state)->colorkey_mode; + if ((!old_state->visible && state->visible) || + drm_to_overlay_state(old_state)->colorkey_mode != val) + armada_reg_queue_mod(regs, idx, val, CFG_CKMODE_MASK | + CFG_ALPHAM_MASK | CFG_ALPHA_MASK, + LCD_SPU_DMA_CTRL1); + val = drm_to_overlay_state(state)->colorkey_enable; + if (((!old_state->visible && state->visible) || + drm_to_overlay_state(old_state)->colorkey_enable != val) && + dcrtc->variant->has_spu_adv_reg) + armada_reg_queue_mod(regs, idx, val, ADV_GRACOLORKEY | + ADV_VIDCOLORKEY, LCD_SPU_ADV_REG); dcrtc->regs_idx += idx; } @@ -314,10 +312,7 @@ static int armada_overlay_commit(struct drm_plane *plane, goto put_state; } - if (!dcrtc->plane) { - dcrtc->plane = plane; - armada_ovl_update_attr(&dplane->prop, dcrtc); - } + dcrtc->plane = plane; /* Queue it for update on the next interrupt if we are enabled */ ret = armada_drm_plane_work_queue(dcrtc, work); @@ -377,85 +372,20 @@ static void armada_ovl_plane_destroy(struct drm_plane *plane) static int armada_ovl_plane_set_property(struct drm_plane *plane, struct drm_property *property, uint64_t val) { - struct armada_private *priv = plane->dev->dev_private; - struct armada_ovl_plane *dplane = drm_to_armada_ovl_plane(plane); - bool update_attr = false; + struct drm_plane_state *state; + int ret; - if (property == priv->colorkey_prop) { -#define CCC(v) ((v) << 24 | (v) << 16 | (v) << 8) - dplane->prop.colorkey_yr = CCC(K2R(val)); - dplane->prop.colorkey_ug = CCC(K2G(val)); - dplane->prop.colorkey_vb = CCC(K2B(val)); -#undef CCC - update_attr = true; - } else if (property == priv->colorkey_min_prop) { - dplane->prop.colorkey_yr &= ~0x00ff0000; - dplane->prop.colorkey_yr |= K2R(val) << 16; - dplane->prop.colorkey_ug &= ~0x00ff0000; - dplane->prop.colorkey_ug |= K2G(val) << 16; - dplane->prop.colorkey_vb &= ~0x00ff0000; - dplane->prop.colorkey_vb |= K2B(val) << 16; - update_attr = true; - } else if (property == priv->colorkey_max_prop) { - dplane->prop.colorkey_yr &= ~0xff000000; - dplane->prop.colorkey_yr |= K2R(val) << 24; - dplane->prop.colorkey_ug &= ~0xff000000; - dplane->prop.colorkey_ug |= K2G(val) << 24; - dplane->prop.colorkey_vb &= ~0xff000000; - dplane->prop.colorkey_vb |= K2B(val) << 24; - update_attr = true; - } else if (property == priv->colorkey_val_prop) { - dplane->prop.colorkey_yr &= ~0x0000ff00; - dplane->prop.colorkey_yr |= K2R(val) << 8; - dplane->prop.colorkey_ug &= ~0x0000ff00; - dplane->prop.colorkey_ug |= K2G(val) << 8; - dplane->prop.colorkey_vb &= ~0x0000ff00; - dplane->prop.colorkey_vb |= K2B(val) << 8; - update_attr = true; - } else if (property == priv->colorkey_alpha_prop) { - dplane->prop.colorkey_yr &= ~0x000000ff; - dplane->prop.colorkey_yr |= K2R(val); - dplane->prop.colorkey_ug &= ~0x000000ff; - dplane->prop.colorkey_ug |= K2G(val); - dplane->prop.colorkey_vb &= ~0x000000ff; - dplane->prop.colorkey_vb |= K2B(val); - update_attr = true; - } else if (property == priv->colorkey_mode_prop) { - if (val == CKMODE_DISABLE) { - dplane->prop.colorkey_mode = - CFG_CKMODE(CKMODE_DISABLE) | - CFG_ALPHAM_CFG | CFG_ALPHA(255); - dplane->prop.colorkey_enable = 0; - } else { - dplane->prop.colorkey_mode = - CFG_CKMODE(val) | - CFG_ALPHAM_GRA | CFG_ALPHA(0); - dplane->prop.colorkey_enable = ADV_GRACOLORKEY; - } - update_attr = true; - } else { - struct drm_plane_state *state; - int ret; - - state = plane->funcs->atomic_duplicate_state(plane); - if (!state) - return -ENOMEM; - - ret = plane->funcs->atomic_set_property(plane, state, property, - val); - if (ret) { - plane->funcs->atomic_destroy_state(plane, state); - return ret; - } + state = plane->funcs->atomic_duplicate_state(plane); + if (!state) + return -ENOMEM; - return armada_overlay_commit(plane, state); + ret = plane->funcs->atomic_set_property(plane, state, property, val); + if (ret) { + plane->funcs->atomic_destroy_state(plane, state); + return ret; } - if (update_attr && dplane->base.base.crtc) - armada_ovl_update_attr(&dplane->prop, - drm_to_armada_crtc(dplane->base.base.crtc)); - - return 0; + return armada_overlay_commit(plane, state); } static void armada_overlay_reset(struct drm_plane *plane) @@ -470,6 +400,12 @@ static void armada_overlay_reset(struct drm_plane *plane) if (state) { state->base.plane = plane; state->base.rotation = DRM_MODE_ROTATE_0; + state->colorkey_yr = 0xfefefe00; + state->colorkey_ug = 0x01010100; + state->colorkey_vb = 0x01010100; + state->colorkey_mode = CFG_CKMODE(CKMODE_RGB) | + CFG_ALPHAM_GRA | CFG_ALPHA(0); + state->colorkey_enable = ADV_GRACOLORKEY; state->brightness = DEFAULT_BRIGHTNESS; state->contrast = DEFAULT_CONTRAST; state->saturation = DEFAULT_SATURATION; @@ -497,7 +433,57 @@ static int armada_overlay_set_property(struct drm_plane *plane, { struct armada_private *priv = plane->dev->dev_private; - if (property == priv->brightness_prop) { +#define K2R(val) (((val) >> 0) & 0xff) +#define K2G(val) (((val) >> 8) & 0xff) +#define K2B(val) (((val) >> 16) & 0xff) + if (property == priv->colorkey_prop) { +#define CCC(v) ((v) << 24 | (v) << 16 | (v) << 8) + drm_to_overlay_state(state)->colorkey_yr = CCC(K2R(val)); + drm_to_overlay_state(state)->colorkey_ug = CCC(K2G(val)); + drm_to_overlay_state(state)->colorkey_vb = CCC(K2B(val)); +#undef CCC + } else if (property == priv->colorkey_min_prop) { + drm_to_overlay_state(state)->colorkey_yr &= ~0x00ff0000; + drm_to_overlay_state(state)->colorkey_yr |= K2R(val) << 16; + drm_to_overlay_state(state)->colorkey_ug &= ~0x00ff0000; + drm_to_overlay_state(state)->colorkey_ug |= K2G(val) << 16; + drm_to_overlay_state(state)->colorkey_vb &= ~0x00ff0000; + drm_to_overlay_state(state)->colorkey_vb |= K2B(val) << 16; + } else if (property == priv->colorkey_max_prop) { + drm_to_overlay_state(state)->colorkey_yr &= ~0xff000000; + drm_to_overlay_state(state)->colorkey_yr |= K2R(val) << 24; + drm_to_overlay_state(state)->colorkey_ug &= ~0xff000000; + drm_to_overlay_state(state)->colorkey_ug |= K2G(val) << 24; + drm_to_overlay_state(state)->colorkey_vb &= ~0xff000000; + drm_to_overlay_state(state)->colorkey_vb |= K2B(val) << 24; + } else if (property == priv->colorkey_val_prop) { + drm_to_overlay_state(state)->colorkey_yr &= ~0x0000ff00; + drm_to_overlay_state(state)->colorkey_yr |= K2R(val) << 8; + drm_to_overlay_state(state)->colorkey_ug &= ~0x0000ff00; + drm_to_overlay_state(state)->colorkey_ug |= K2G(val) << 8; + drm_to_overlay_state(state)->colorkey_vb &= ~0x0000ff00; + drm_to_overlay_state(state)->colorkey_vb |= K2B(val) << 8; + } else if (property == priv->colorkey_alpha_prop) { + drm_to_overlay_state(state)->colorkey_yr &= ~0x000000ff; + drm_to_overlay_state(state)->colorkey_yr |= K2R(val); + drm_to_overlay_state(state)->colorkey_ug &= ~0x000000ff; + drm_to_overlay_state(state)->colorkey_ug |= K2G(val); + drm_to_overlay_state(state)->colorkey_vb &= ~0x000000ff; + drm_to_overlay_state(state)->colorkey_vb |= K2B(val); + } else if (property == priv->colorkey_mode_prop) { + if (val == CKMODE_DISABLE) { + drm_to_overlay_state(state)->colorkey_mode = + CFG_CKMODE(CKMODE_DISABLE) | + CFG_ALPHAM_CFG | CFG_ALPHA(255); + drm_to_overlay_state(state)->colorkey_enable = 0; + } else { + drm_to_overlay_state(state)->colorkey_mode = + CFG_CKMODE(val) | + CFG_ALPHAM_GRA | CFG_ALPHA(0); + drm_to_overlay_state(state)->colorkey_enable = + ADV_GRACOLORKEY; + } + } else if (property == priv->brightness_prop) { drm_to_overlay_state(state)->brightness = val - 256; } else if (property == priv->contrast_prop) { drm_to_overlay_state(state)->contrast = val; @@ -515,7 +501,41 @@ static int armada_overlay_get_property(struct drm_plane *plane, { struct armada_private *priv = plane->dev->dev_private; - if (property == priv->brightness_prop) { +#define C2K(c,s) (((c) >> (s)) & 0xff) +#define R2BGR(r,g,b,s) (C2K(r,s) << 0 | C2K(g,s) << 8 | C2K(b,s) << 16) + if (property == priv->colorkey_prop) { + /* Do best-efforts here for this property */ + *val = R2BGR(drm_to_overlay_state(state)->colorkey_yr, + drm_to_overlay_state(state)->colorkey_ug, + drm_to_overlay_state(state)->colorkey_vb, 16); + /* If min != max, or min != val, error out */ + if (*val != R2BGR(drm_to_overlay_state(state)->colorkey_yr, + drm_to_overlay_state(state)->colorkey_ug, + drm_to_overlay_state(state)->colorkey_vb, 24) || + *val != R2BGR(drm_to_overlay_state(state)->colorkey_yr, + drm_to_overlay_state(state)->colorkey_ug, + drm_to_overlay_state(state)->colorkey_vb, 8)) + return -EINVAL; + } else if (property == priv->colorkey_min_prop) { + *val = R2BGR(drm_to_overlay_state(state)->colorkey_yr, + drm_to_overlay_state(state)->colorkey_ug, + drm_to_overlay_state(state)->colorkey_vb, 16); + } else if (property == priv->colorkey_max_prop) { + *val = R2BGR(drm_to_overlay_state(state)->colorkey_yr, + drm_to_overlay_state(state)->colorkey_ug, + drm_to_overlay_state(state)->colorkey_vb, 24); + } else if (property == priv->colorkey_val_prop) { + *val = R2BGR(drm_to_overlay_state(state)->colorkey_yr, + drm_to_overlay_state(state)->colorkey_ug, + drm_to_overlay_state(state)->colorkey_vb, 8); + } else if (property == priv->colorkey_alpha_prop) { + *val = R2BGR(drm_to_overlay_state(state)->colorkey_yr, + drm_to_overlay_state(state)->colorkey_ug, + drm_to_overlay_state(state)->colorkey_vb, 0); + } else if (property == priv->colorkey_mode_prop) { + *val = (drm_to_overlay_state(state)->colorkey_mode & + CFG_CKMODE_MASK) >> ffs(CFG_CKMODE_MASK); + } else if (property == priv->brightness_prop) { *val = drm_to_overlay_state(state)->brightness + 256; } else if (property == priv->contrast_prop) { *val = drm_to_overlay_state(state)->contrast; @@ -645,13 +665,6 @@ int armada_overlay_plane_create(struct drm_device *dev, unsigned long crtcs) return ret; } - dplane->prop.colorkey_yr = 0xfefefe00; - dplane->prop.colorkey_ug = 0x01010100; - dplane->prop.colorkey_vb = 0x01010100; - dplane->prop.colorkey_mode = CFG_CKMODE(CKMODE_RGB) | - CFG_ALPHAM_GRA | CFG_ALPHA(0); - dplane->prop.colorkey_enable = ADV_GRACOLORKEY; - mobj = &dplane->base.base.base; drm_object_attach_property(mobj, priv->colorkey_prop, 0x0101fe); -- GitLab From 240cf2b58eb0bdd3c59387ca0cfbd5657708b996 Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 1378/1506] drm/armada: remove crtc YUV colourspace properties Remove the unused CRTC colourspace properties - userspace does not make use of these. In any case, these are not a property of the CRTC, since they demonstrably only affect the video (overlay) plane, irrespective of the format of the graphics (primary) plane. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/armada/armada_crtc.c | 118 --------------------------- drivers/gpu/drm/armada/armada_crtc.h | 2 - drivers/gpu/drm/armada/armada_drm.h | 2 - 3 files changed, 122 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index b9b0a508793d3..35b2df0fc21c1 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -23,14 +23,6 @@ #include "armada_plane.h" #include "armada_trace.h" -enum csc_mode { - CSC_AUTO = 0, - CSC_YUV_CCIR601 = 1, - CSC_YUV_CCIR709 = 2, - CSC_RGB_COMPUTER = 1, - CSC_RGB_STUDIO = 2, -}; - /* * A note about interlacing. Let's consider HDMI 1920x1080i. * The timing parameters we have from X are: @@ -438,42 +430,6 @@ static irqreturn_t armada_drm_irq(int irq, void *arg) return IRQ_NONE; } -static uint32_t armada_drm_crtc_calculate_csc(struct armada_crtc *dcrtc) -{ - struct drm_display_mode *adj = &dcrtc->crtc.mode; - uint32_t val = 0; - - if (dcrtc->csc_yuv_mode == CSC_YUV_CCIR709) - val |= CFG_CSC_YUV_CCIR709; - if (dcrtc->csc_rgb_mode == CSC_RGB_STUDIO) - val |= CFG_CSC_RGB_STUDIO; - - /* - * In auto mode, set the colorimetry, based upon the HDMI spec. - * 1280x720p, 1920x1080p and 1920x1080i use ITU709, others use - * ITU601. It may be more appropriate to set this depending on - * the source - but what if the graphic frame is YUV and the - * video frame is RGB? - */ - if ((adj->hdisplay == 1280 && adj->vdisplay == 720 && - !(adj->flags & DRM_MODE_FLAG_INTERLACE)) || - (adj->hdisplay == 1920 && adj->vdisplay == 1080)) { - if (dcrtc->csc_yuv_mode == CSC_AUTO) - val |= CFG_CSC_YUV_CCIR709; - } - - /* - * We assume we're connected to a TV-like device, so the YUV->RGB - * conversion should produce a limited range. We should set this - * depending on the connectors attached to this CRTC, and what - * kind of device they report being connected. - */ - if (dcrtc->csc_rgb_mode == CSC_AUTO) - val |= CFG_CSC_RGB_STUDIO; - - return val; -} - /* The mode_config.mutex will be held for this call */ static void armada_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) { @@ -560,9 +516,6 @@ static void armada_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) val = adj->flags & DRM_MODE_FLAG_NVSYNC ? CFG_VSYNC_INV : 0; armada_reg_queue_mod(regs, i, val, CFG_VSYNC_INV, LCD_SPU_DMA_CTRL1); - - val = dcrtc->spu_iopad_ctrl | armada_drm_crtc_calculate_csc(dcrtc); - armada_reg_queue_set(regs, i, val, LCD_SPU_IOPAD_CONTROL); armada_reg_queue_end(regs, i); armada_drm_crtc_update_regs(dcrtc, regs); @@ -937,33 +890,6 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc, return ret; } -static int -armada_drm_crtc_set_property(struct drm_crtc *crtc, - struct drm_property *property, uint64_t val) -{ - struct armada_private *priv = crtc->dev->dev_private; - struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); - bool update_csc = false; - - if (property == priv->csc_yuv_prop) { - dcrtc->csc_yuv_mode = val; - update_csc = true; - } else if (property == priv->csc_rgb_prop) { - dcrtc->csc_rgb_mode = val; - update_csc = true; - } - - if (update_csc) { - uint32_t val; - - val = dcrtc->spu_iopad_ctrl | - armada_drm_crtc_calculate_csc(dcrtc); - writel_relaxed(val, dcrtc->base + LCD_SPU_IOPAD_CONTROL); - } - - return 0; -} - /* These are called under the vbl_lock. */ static int armada_drm_crtc_enable_vblank(struct drm_crtc *crtc) { @@ -993,45 +919,12 @@ static const struct drm_crtc_funcs armada_crtc_funcs = { .destroy = armada_drm_crtc_destroy, .set_config = drm_crtc_helper_set_config, .page_flip = armada_drm_crtc_page_flip, - .set_property = armada_drm_crtc_set_property, .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, .enable_vblank = armada_drm_crtc_enable_vblank, .disable_vblank = armada_drm_crtc_disable_vblank, }; -static const struct drm_prop_enum_list armada_drm_csc_yuv_enum_list[] = { - { CSC_AUTO, "Auto" }, - { CSC_YUV_CCIR601, "CCIR601" }, - { CSC_YUV_CCIR709, "CCIR709" }, -}; - -static const struct drm_prop_enum_list armada_drm_csc_rgb_enum_list[] = { - { CSC_AUTO, "Auto" }, - { CSC_RGB_COMPUTER, "Computer system" }, - { CSC_RGB_STUDIO, "Studio" }, -}; - -static int armada_drm_crtc_create_properties(struct drm_device *dev) -{ - struct armada_private *priv = dev->dev_private; - - if (priv->csc_yuv_prop) - return 0; - - priv->csc_yuv_prop = drm_property_create_enum(dev, 0, - "CSC_YUV", armada_drm_csc_yuv_enum_list, - ARRAY_SIZE(armada_drm_csc_yuv_enum_list)); - priv->csc_rgb_prop = drm_property_create_enum(dev, 0, - "CSC_RGB", armada_drm_csc_rgb_enum_list, - ARRAY_SIZE(armada_drm_csc_rgb_enum_list)); - - if (!priv->csc_yuv_prop || !priv->csc_rgb_prop) - return -ENOMEM; - - return 0; -} - static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev, struct resource *res, int irq, const struct armada_variant *variant, struct device_node *port) @@ -1042,10 +935,6 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev, void __iomem *base; int ret; - ret = armada_drm_crtc_create_properties(drm); - if (ret) - return ret; - base = devm_ioremap_resource(dev, res); if (IS_ERR(base)) return PTR_ERR(base); @@ -1063,8 +952,6 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev, dcrtc->base = base; dcrtc->num = drm->mode_config.num_crtc; dcrtc->clk = ERR_PTR(-EINVAL); - dcrtc->csc_yuv_mode = CSC_AUTO; - dcrtc->csc_rgb_mode = CSC_AUTO; dcrtc->cfg_dumb_ctrl = DUMB24_RGB888_0; dcrtc->spu_iopad_ctrl = CFG_VSCALE_LN_EN | CFG_IOPAD_DUMB24; spin_lock_init(&dcrtc->irq_lock); @@ -1121,11 +1008,6 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev, drm_crtc_helper_add(&dcrtc->crtc, &armada_crtc_helper_funcs); - drm_object_attach_property(&dcrtc->crtc.base, priv->csc_yuv_prop, - dcrtc->csc_yuv_mode); - drm_object_attach_property(&dcrtc->crtc.base, priv->csc_rgb_prop, - dcrtc->csc_rgb_mode); - return armada_overlay_plane_create(drm, 1 << dcrtc->num); err_crtc_init: diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h index c27435a8776a8..21338f7c3d7dd 100644 --- a/drivers/gpu/drm/armada/armada_crtc.h +++ b/drivers/gpu/drm/armada/armada_crtc.h @@ -72,8 +72,6 @@ struct armada_crtc { } v[2]; bool interlaced; bool cursor_update; - uint8_t csc_yuv_mode; - uint8_t csc_rgb_mode; struct drm_plane *plane; diff --git a/drivers/gpu/drm/armada/armada_drm.h b/drivers/gpu/drm/armada/armada_drm.h index cc4c557c9f664..28087e4b9b81d 100644 --- a/drivers/gpu/drm/armada/armada_drm.h +++ b/drivers/gpu/drm/armada/armada_drm.h @@ -60,8 +60,6 @@ struct armada_private { struct armada_crtc *dcrtc[2]; struct drm_mm linear; /* protected by linear_lock */ struct mutex linear_lock; - struct drm_property *csc_yuv_prop; - struct drm_property *csc_rgb_prop; struct drm_property *colorkey_prop; struct drm_property *colorkey_min_prop; struct drm_property *colorkey_max_prop; -- GitLab From c29277d4e56388e805acc3ba428c9cff7df99fa7 Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 1379/1506] drm/armada: add plane colorspace properties Use the DRM standard plane properties for specifying the YUV colour encoding parameter. Our colour range is fixed at limited range. Since we are transitioning to atomic modeset, we need to explicitly add handling of these properties to our atomic_set_property() method, but once the transition is complete, these will be removed. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/armada/armada_overlay.c | 33 ++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index 7f75df4f83907..bc1b5b860141d 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -23,6 +23,7 @@ #define DEFAULT_BRIGHTNESS 0 #define DEFAULT_CONTRAST 0x4000 #define DEFAULT_SATURATION 0x4000 +#define DEFAULT_ENCODING DRM_COLOR_YCBCR_BT601 struct armada_ovl_plane { struct armada_plane base; @@ -59,6 +60,19 @@ static inline u32 armada_spu_saturation(struct drm_plane_state *state) return drm_to_overlay_state(state)->saturation << 16; } +static inline u32 armada_csc(struct drm_plane_state *state) +{ + /* + * The CFG_CSC_RGB_* settings control the output of the colour space + * converter, setting the range of output values it produces. Since + * we will be blending with the full-range graphics, we need to + * produce full-range RGB output from the conversion. + */ + return CFG_CSC_RGB_COMPUTER | + (state->color_encoding == DRM_COLOR_YCBCR_BT709 ? + CFG_CSC_YUV_CCIR709 : CFG_CSC_YUV_CCIR601); +} + /* === Plane support === */ static void armada_ovl_plane_work(struct armada_crtc *dcrtc, struct armada_plane_work *work) @@ -189,6 +203,11 @@ static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane, armada_reg_queue_set(regs, idx, val, LCD_SPU_SATURATION); if (!old_state->visible && state->visible) armada_reg_queue_set(regs, idx, 0x00002000, LCD_SPU_CBSH_HUE); + val = armada_csc(state); + if ((!old_state->visible && state->visible) || + armada_csc(old_state) != val) + armada_reg_queue_mod(regs, idx, val, CFG_CSC_MASK, + LCD_SPU_IOPAD_CONTROL); val = drm_to_overlay_state(state)->colorkey_yr; if ((!old_state->visible && state->visible) || drm_to_overlay_state(old_state)->colorkey_yr != val) @@ -399,6 +418,8 @@ static void armada_overlay_reset(struct drm_plane *plane) state = kzalloc(sizeof(*state), GFP_KERNEL); if (state) { state->base.plane = plane; + state->base.color_encoding = DEFAULT_ENCODING; + state->base.color_range = DRM_COLOR_YCBCR_LIMITED_RANGE; state->base.rotation = DRM_MODE_ROTATE_0; state->colorkey_yr = 0xfefefe00; state->colorkey_ug = 0x01010100; @@ -489,6 +510,9 @@ static int armada_overlay_set_property(struct drm_plane *plane, drm_to_overlay_state(state)->contrast = val; } else if (property == priv->saturation_prop) { drm_to_overlay_state(state)->saturation = val; + } else if (property == plane->color_encoding_property) { + /* transitional only */ + state->color_encoding = val; } else { return -EINVAL; } @@ -685,5 +709,12 @@ int armada_overlay_plane_create(struct drm_device *dev, unsigned long crtcs) drm_object_attach_property(mobj, priv->saturation_prop, DEFAULT_SATURATION); - return 0; + ret = drm_plane_create_color_properties(&dplane->base.base, + BIT(DRM_COLOR_YCBCR_BT601) | + BIT(DRM_COLOR_YCBCR_BT709), + BIT(DRM_COLOR_YCBCR_LIMITED_RANGE), + DEFAULT_ENCODING, + DRM_COLOR_YCBCR_LIMITED_RANGE); + + return ret; } -- GitLab From 3382a6b999415d1f78cee3f483957651d7e1f8a4 Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 1380/1506] drm/armada: move armada_drm_mode_config_funcs to armada_drv.c Move the armada_drm_mode_config_funcs to armada_drv.c, since this now has less to do with FBs than it does with general mode configuration. In doing so, we need to make armada_fb_create() visible to armada_drv.c, which reveals a function name clash with armada_fbdev.c. Rename the version in armada_fbdev.c. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/armada/armada_drm.h | 2 -- drivers/gpu/drm/armada/armada_drv.c | 6 ++++++ drivers/gpu/drm/armada/armada_fb.c | 7 +------ drivers/gpu/drm/armada/armada_fb.h | 3 ++- drivers/gpu/drm/armada/armada_fbdev.c | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_drm.h b/drivers/gpu/drm/armada/armada_drm.h index 28087e4b9b81d..64f1c8836078c 100644 --- a/drivers/gpu/drm/armada/armada_drm.h +++ b/drivers/gpu/drm/armada/armada_drm.h @@ -79,8 +79,6 @@ void __armada_drm_queue_unref_work(struct drm_device *, void armada_drm_queue_unref_work(struct drm_device *, struct drm_framebuffer *); -extern const struct drm_mode_config_funcs armada_drm_mode_config_funcs; - int armada_fbdev_init(struct drm_device *); void armada_fbdev_fini(struct drm_device *); diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c index e47b995b4ce63..7517f23bb9cdb 100644 --- a/drivers/gpu/drm/armada/armada_drv.c +++ b/drivers/gpu/drm/armada/armada_drv.c @@ -15,6 +15,7 @@ #include "armada_crtc.h" #include "armada_drm.h" #include "armada_gem.h" +#include "armada_fb.h" #include "armada_hw.h" #include <drm/armada_drm.h> #include "armada_ioctlP.h" @@ -77,6 +78,11 @@ static struct drm_driver armada_drm_driver = { .fops = &armada_drm_fops, }; +static const struct drm_mode_config_funcs armada_drm_mode_config_funcs = { + .fb_create = armada_fb_create, + .output_poll_changed = drm_fb_helper_output_poll_changed, +}; + static int armada_drm_bind(struct device *dev) { struct armada_private *priv; diff --git a/drivers/gpu/drm/armada/armada_fb.c b/drivers/gpu/drm/armada/armada_fb.c index edd15126bde93..6bd638a54579f 100644 --- a/drivers/gpu/drm/armada/armada_fb.c +++ b/drivers/gpu/drm/armada/armada_fb.c @@ -84,7 +84,7 @@ struct armada_framebuffer *armada_framebuffer_create(struct drm_device *dev, return dfb; } -static struct drm_framebuffer *armada_fb_create(struct drm_device *dev, +struct drm_framebuffer *armada_fb_create(struct drm_device *dev, struct drm_file *dfile, const struct drm_mode_fb_cmd2 *mode) { struct armada_gem_object *obj; @@ -138,8 +138,3 @@ static struct drm_framebuffer *armada_fb_create(struct drm_device *dev, DRM_ERROR("failed to initialize framebuffer: %d\n", ret); return ERR_PTR(ret); } - -const struct drm_mode_config_funcs armada_drm_mode_config_funcs = { - .fb_create = armada_fb_create, - .output_poll_changed = drm_fb_helper_output_poll_changed, -}; diff --git a/drivers/gpu/drm/armada/armada_fb.h b/drivers/gpu/drm/armada/armada_fb.h index 5c130ff5da770..476daad0a36a2 100644 --- a/drivers/gpu/drm/armada/armada_fb.h +++ b/drivers/gpu/drm/armada/armada_fb.h @@ -19,5 +19,6 @@ struct armada_framebuffer { struct armada_framebuffer *armada_framebuffer_create(struct drm_device *, const struct drm_mode_fb_cmd2 *, struct armada_gem_object *); - +struct drm_framebuffer *armada_fb_create(struct drm_device *dev, + struct drm_file *dfile, const struct drm_mode_fb_cmd2 *mode); #endif diff --git a/drivers/gpu/drm/armada/armada_fbdev.c b/drivers/gpu/drm/armada/armada_fbdev.c index 2a59db0994b2e..8d23700848df7 100644 --- a/drivers/gpu/drm/armada/armada_fbdev.c +++ b/drivers/gpu/drm/armada/armada_fbdev.c @@ -24,7 +24,7 @@ static /*const*/ struct fb_ops armada_fb_ops = { .fb_imageblit = drm_fb_helper_cfb_imageblit, }; -static int armada_fb_create(struct drm_fb_helper *fbh, +static int armada_fbdev_create(struct drm_fb_helper *fbh, struct drm_fb_helper_surface_size *sizes) { struct drm_device *dev = fbh->dev; @@ -108,7 +108,7 @@ static int armada_fb_probe(struct drm_fb_helper *fbh, int ret = 0; if (!fbh->fb) { - ret = armada_fb_create(fbh, sizes); + ret = armada_fbdev_create(fbh, sizes); if (ret == 0) ret = 1; } -- GitLab From b4df3ba0d76823cb5e548505de104837d89aa5a9 Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 1381/1506] drm/armada: pass plane state into armada_drm_plane_calc_addrs() armada_drm_plane_calc_addrs() gets all its information from the plane state, so it makes sense to pass the plane state pointer down into this function, rather than extracting the information in identical ways, sometimes a couple of layers up. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/armada/armada_overlay.c | 6 +++--- drivers/gpu/drm/armada/armada_plane.c | 25 ++++++++++++------------- drivers/gpu/drm/armada/armada_plane.h | 3 +-- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index bc1b5b860141d..e8c3bcc09d5ca 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -130,11 +130,10 @@ static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane, old_state->src.y1 != state->src.y1 || old_state->fb != state->fb) { const struct drm_format_info *format; - u16 src_x = state->src.x1 >> 16; - u16 src_y = state->src.y1 >> 16; + u16 src_x; u32 addrs[3]; - armada_drm_plane_calc_addrs(addrs, state->fb, src_x, src_y); + armada_drm_plane_calc_addrs(state, addrs); armada_reg_queue_set(regs, idx, addrs[0], LCD_SPU_DMA_START_ADDR_Y0); @@ -166,6 +165,7 @@ static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane, * the UV swap. */ format = state->fb->format; + src_x = state->src.x1 >> 16; if (format->num_planes == 1 && src_x & (format->hsub - 1)) cfg ^= CFG_DMA_MOD(CFG_SWAPUV); cfg_mask = CFG_CBSH_ENA | CFG_DMAFORMAT | diff --git a/drivers/gpu/drm/armada/armada_plane.c b/drivers/gpu/drm/armada/armada_plane.c index 1cb6a605bda9c..c426c92c79d95 100644 --- a/drivers/gpu/drm/armada/armada_plane.c +++ b/drivers/gpu/drm/armada/armada_plane.c @@ -35,14 +35,19 @@ static const uint32_t armada_primary_formats[] = { DRM_FORMAT_BGR565, }; -void armada_drm_plane_calc_addrs(u32 *addrs, struct drm_framebuffer *fb, - int x, int y) +void armada_drm_plane_calc_addrs(struct drm_plane_state *state, u32 addrs[3]) { + struct drm_framebuffer *fb = state->fb; const struct drm_format_info *format = fb->format; unsigned int num_planes = format->num_planes; + unsigned int x = state->src.x1 >> 16; + unsigned int y = state->src.y1 >> 16; u32 addr = drm_fb_obj(fb)->dev_addr; int i; + DRM_DEBUG_KMS("pitch %u x %d y %d bpp %d\n", + fb->pitches[0], x, y, format->cpp[0] * 8); + if (num_planes > 3) num_planes = 3; @@ -59,17 +64,14 @@ void armada_drm_plane_calc_addrs(u32 *addrs, struct drm_framebuffer *fb, addrs[i] = 0; } -static unsigned armada_drm_crtc_calc_fb(struct drm_framebuffer *fb, - int x, int y, struct armada_regs *regs, bool interlaced) +static unsigned armada_drm_crtc_calc_fb(struct drm_plane_state *state, + struct armada_regs *regs, bool interlaced) { - unsigned pitch = fb->pitches[0]; + unsigned pitch = state->fb->pitches[0]; u32 addrs[3], addr_odd, addr_even; unsigned i = 0; - DRM_DEBUG_DRIVER("pitch %u x %d y %d bpp %d\n", - pitch, x, y, fb->format->cpp[0] * 8); - - armada_drm_plane_calc_addrs(addrs, fb, x, y); + armada_drm_plane_calc_addrs(state, addrs); addr_odd = addr_even = addrs[0]; @@ -175,10 +177,7 @@ static void armada_drm_primary_plane_atomic_update(struct drm_plane *plane, if (old_state->src.x1 != state->src.x1 || old_state->src.y1 != state->src.y1 || old_state->fb != state->fb) { - idx += armada_drm_crtc_calc_fb(state->fb, - state->src.x1 >> 16, - state->src.y1 >> 16, - regs + idx, + idx += armada_drm_crtc_calc_fb(state, regs + idx, dcrtc->interlaced); } if (old_state->fb != state->fb) { diff --git a/drivers/gpu/drm/armada/armada_plane.h b/drivers/gpu/drm/armada/armada_plane.h index 3c83160039077..999a0bd3e5124 100644 --- a/drivers/gpu/drm/armada/armada_plane.h +++ b/drivers/gpu/drm/armada/armada_plane.h @@ -1,8 +1,7 @@ #ifndef ARMADA_PLANE_H #define ARMADA_PLANE_H -void armada_drm_plane_calc_addrs(u32 *addrs, struct drm_framebuffer *fb, - int x, int y); +void armada_drm_plane_calc_addrs(struct drm_plane_state *state, u32 addrs[3]); int armada_drm_plane_prepare_fb(struct drm_plane *plane, struct drm_plane_state *state); void armada_drm_plane_cleanup_fb(struct drm_plane *plane, -- GitLab From 4aafe00e2f6bb43656d690b6241f80bb8c236168 Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 1382/1506] drm/armada: provide pitches from armada_drm_plane_calc_addrs() Provide the framebuffer pitches from armada_drm_plane_calc_addrs() as well as the base addresses for each plane. Since this is now about more than just addresses, rename to armada_drm_plane_calc(). Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/armada/armada_overlay.c | 8 ++++---- drivers/gpu/drm/armada/armada_plane.c | 22 ++++++++++++++-------- drivers/gpu/drm/armada/armada_plane.h | 3 ++- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index e8c3bcc09d5ca..f36f6fb919e7c 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -130,10 +130,10 @@ static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane, old_state->src.y1 != state->src.y1 || old_state->fb != state->fb) { const struct drm_format_info *format; - u16 src_x; + u16 src_x, pitches[3]; u32 addrs[3]; - armada_drm_plane_calc_addrs(state, addrs); + armada_drm_plane_calc(state, addrs, pitches); armada_reg_queue_set(regs, idx, addrs[0], LCD_SPU_DMA_START_ADDR_Y0); @@ -148,9 +148,9 @@ static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane, armada_reg_queue_set(regs, idx, addrs[2], LCD_SPU_DMA_START_ADDR_V1); - val = state->fb->pitches[0] << 16 | state->fb->pitches[0]; + val = pitches[0] << 16 | pitches[0]; armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_PITCH_YC); - val = state->fb->pitches[1] << 16 | state->fb->pitches[2]; + val = pitches[1] << 16 | pitches[2]; armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_PITCH_UV); cfg = CFG_DMA_FMT(drm_fb_to_armada_fb(state->fb)->fmt) | diff --git a/drivers/gpu/drm/armada/armada_plane.c b/drivers/gpu/drm/armada/armada_plane.c index c426c92c79d95..3c9414c56acac 100644 --- a/drivers/gpu/drm/armada/armada_plane.c +++ b/drivers/gpu/drm/armada/armada_plane.c @@ -35,7 +35,8 @@ static const uint32_t armada_primary_formats[] = { DRM_FORMAT_BGR565, }; -void armada_drm_plane_calc_addrs(struct drm_plane_state *state, u32 addrs[3]) +void armada_drm_plane_calc(struct drm_plane_state *state, u32 addrs[3], + u16 pitches[3]) { struct drm_framebuffer *fb = state->fb; const struct drm_format_info *format = fb->format; @@ -53,37 +54,42 @@ void armada_drm_plane_calc_addrs(struct drm_plane_state *state, u32 addrs[3]) addrs[0] = addr + fb->offsets[0] + y * fb->pitches[0] + x * format->cpp[0]; + pitches[0] = fb->pitches[0]; y /= format->vsub; x /= format->hsub; - for (i = 1; i < num_planes; i++) + for (i = 1; i < num_planes; i++) { addrs[i] = addr + fb->offsets[i] + y * fb->pitches[i] + x * format->cpp[i]; - for (; i < 3; i++) + pitches[i] = fb->pitches[i]; + } + for (; i < 3; i++) { addrs[i] = 0; + pitches[i] = 0; + } } static unsigned armada_drm_crtc_calc_fb(struct drm_plane_state *state, struct armada_regs *regs, bool interlaced) { - unsigned pitch = state->fb->pitches[0]; + u16 pitches[3]; u32 addrs[3], addr_odd, addr_even; unsigned i = 0; - armada_drm_plane_calc_addrs(state, addrs); + armada_drm_plane_calc(state, addrs, pitches); addr_odd = addr_even = addrs[0]; if (interlaced) { - addr_even += pitch; - pitch *= 2; + addr_even += pitches[0]; + pitches[0] *= 2; } /* write offset, base, and pitch */ armada_reg_queue_set(regs, i, addr_odd, LCD_CFG_GRA_START_ADDR0); armada_reg_queue_set(regs, i, addr_even, LCD_CFG_GRA_START_ADDR1); - armada_reg_queue_mod(regs, i, pitch, 0xffff, LCD_CFG_GRA_PITCH); + armada_reg_queue_mod(regs, i, pitches[0], 0xffff, LCD_CFG_GRA_PITCH); return i; } diff --git a/drivers/gpu/drm/armada/armada_plane.h b/drivers/gpu/drm/armada/armada_plane.h index 999a0bd3e5124..98280beaaa440 100644 --- a/drivers/gpu/drm/armada/armada_plane.h +++ b/drivers/gpu/drm/armada/armada_plane.h @@ -1,7 +1,8 @@ #ifndef ARMADA_PLANE_H #define ARMADA_PLANE_H -void armada_drm_plane_calc_addrs(struct drm_plane_state *state, u32 addrs[3]); +void armada_drm_plane_calc(struct drm_plane_state *state, u32 addrs[3], + u16 pitches[3]); int armada_drm_plane_prepare_fb(struct drm_plane *plane, struct drm_plane_state *state); void armada_drm_plane_cleanup_fb(struct drm_plane *plane, -- GitLab From b5bae71a79d712681bdf48ee029f1953697924f7 Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 1383/1506] drm/armada: push interlace calculation into armada_drm_plane_calc() Push the interlaced frame calculation down into armada_drm_plane_calc() which needs to apply the same correction for both the overlay and primary planes. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/armada/armada_overlay.c | 16 +++++------ drivers/gpu/drm/armada/armada_plane.c | 38 +++++++++++++------------ drivers/gpu/drm/armada/armada_plane.h | 4 +-- 3 files changed, 30 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index f36f6fb919e7c..7de8b6bd78473 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -131,21 +131,21 @@ static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane, old_state->fb != state->fb) { const struct drm_format_info *format; u16 src_x, pitches[3]; - u32 addrs[3]; + u32 addrs[2][3]; - armada_drm_plane_calc(state, addrs, pitches); + armada_drm_plane_calc(state, addrs, pitches, false); - armada_reg_queue_set(regs, idx, addrs[0], + armada_reg_queue_set(regs, idx, addrs[0][0], LCD_SPU_DMA_START_ADDR_Y0); - armada_reg_queue_set(regs, idx, addrs[1], + armada_reg_queue_set(regs, idx, addrs[0][1], LCD_SPU_DMA_START_ADDR_U0); - armada_reg_queue_set(regs, idx, addrs[2], + armada_reg_queue_set(regs, idx, addrs[0][2], LCD_SPU_DMA_START_ADDR_V0); - armada_reg_queue_set(regs, idx, addrs[0], + armada_reg_queue_set(regs, idx, addrs[1][0], LCD_SPU_DMA_START_ADDR_Y1); - armada_reg_queue_set(regs, idx, addrs[1], + armada_reg_queue_set(regs, idx, addrs[1][1], LCD_SPU_DMA_START_ADDR_U1); - armada_reg_queue_set(regs, idx, addrs[2], + armada_reg_queue_set(regs, idx, addrs[1][2], LCD_SPU_DMA_START_ADDR_V1); val = pitches[0] << 16 | pitches[0]; diff --git a/drivers/gpu/drm/armada/armada_plane.c b/drivers/gpu/drm/armada/armada_plane.c index 3c9414c56acac..1320fec4c386c 100644 --- a/drivers/gpu/drm/armada/armada_plane.c +++ b/drivers/gpu/drm/armada/armada_plane.c @@ -35,8 +35,8 @@ static const uint32_t armada_primary_formats[] = { DRM_FORMAT_BGR565, }; -void armada_drm_plane_calc(struct drm_plane_state *state, u32 addrs[3], - u16 pitches[3]) +void armada_drm_plane_calc(struct drm_plane_state *state, u32 addrs[2][3], + u16 pitches[3], bool interlaced) { struct drm_framebuffer *fb = state->fb; const struct drm_format_info *format = fb->format; @@ -52,43 +52,45 @@ void armada_drm_plane_calc(struct drm_plane_state *state, u32 addrs[3], if (num_planes > 3) num_planes = 3; - addrs[0] = addr + fb->offsets[0] + y * fb->pitches[0] + - x * format->cpp[0]; + addrs[0][0] = addr + fb->offsets[0] + y * fb->pitches[0] + + x * format->cpp[0]; pitches[0] = fb->pitches[0]; y /= format->vsub; x /= format->hsub; for (i = 1; i < num_planes; i++) { - addrs[i] = addr + fb->offsets[i] + y * fb->pitches[i] + - x * format->cpp[i]; + addrs[0][i] = addr + fb->offsets[i] + y * fb->pitches[i] + + x * format->cpp[i]; pitches[i] = fb->pitches[i]; } for (; i < 3; i++) { - addrs[i] = 0; + addrs[0][i] = 0; pitches[i] = 0; } + if (interlaced) { + for (i = 0; i < 3; i++) { + addrs[1][i] = addrs[0][i] + pitches[i]; + pitches[i] *= 2; + } + } else { + for (i = 0; i < 3; i++) + addrs[1][i] = addrs[0][i]; + } } static unsigned armada_drm_crtc_calc_fb(struct drm_plane_state *state, struct armada_regs *regs, bool interlaced) { u16 pitches[3]; - u32 addrs[3], addr_odd, addr_even; + u32 addrs[2][3]; unsigned i = 0; - armada_drm_plane_calc(state, addrs, pitches); - - addr_odd = addr_even = addrs[0]; - - if (interlaced) { - addr_even += pitches[0]; - pitches[0] *= 2; - } + armada_drm_plane_calc(state, addrs, pitches, interlaced); /* write offset, base, and pitch */ - armada_reg_queue_set(regs, i, addr_odd, LCD_CFG_GRA_START_ADDR0); - armada_reg_queue_set(regs, i, addr_even, LCD_CFG_GRA_START_ADDR1); + armada_reg_queue_set(regs, i, addrs[0][0], LCD_CFG_GRA_START_ADDR0); + armada_reg_queue_set(regs, i, addrs[1][0], LCD_CFG_GRA_START_ADDR1); armada_reg_queue_mod(regs, i, pitches[0], 0xffff, LCD_CFG_GRA_PITCH); return i; diff --git a/drivers/gpu/drm/armada/armada_plane.h b/drivers/gpu/drm/armada/armada_plane.h index 98280beaaa440..1bd8430992e09 100644 --- a/drivers/gpu/drm/armada/armada_plane.h +++ b/drivers/gpu/drm/armada/armada_plane.h @@ -1,8 +1,8 @@ #ifndef ARMADA_PLANE_H #define ARMADA_PLANE_H -void armada_drm_plane_calc(struct drm_plane_state *state, u32 addrs[3], - u16 pitches[3]); +void armada_drm_plane_calc(struct drm_plane_state *state, u32 addrs[2][3], + u16 pitches[3], bool interlaced); int armada_drm_plane_prepare_fb(struct drm_plane *plane, struct drm_plane_state *state); void armada_drm_plane_cleanup_fb(struct drm_plane *plane, -- GitLab From 155b8290f7635b31faa57ca38cb5ddfe78111c2d Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 1384/1506] drm/armada: move sync signal polarity to mode_set_nofb() method For atomic modeset, we need to set the sync signal polarities from the CRTC state structure rather than the legacy mode structure stored in CRTC. In any case, we should update this from our mode_set_nofb() method, rather than the commit() method. Move it there, and ensure that armada_drm_crtc_update() will not overwrite these bits. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/armada/armada_crtc.c | 47 +++++++++++++--------------- drivers/gpu/drm/armada/armada_crtc.h | 1 - 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 35b2df0fc21c1..3cae6587b0794 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -115,25 +115,9 @@ static void armada_drm_crtc_update(struct armada_crtc *dcrtc) dumb_ctrl |= DUMB_BLANK; } - /* - * The documentation doesn't indicate what the normal state of - * the sync signals are. Sebastian Hesselbart kindly probed - * these signals on his board to determine their state. - * - * The non-inverted state of the sync signals is active high. - * Setting these bits makes the appropriate signal active low. - */ - if (dcrtc->crtc.mode.flags & DRM_MODE_FLAG_NCSYNC) - dumb_ctrl |= CFG_INV_CSYNC; - if (dcrtc->crtc.mode.flags & DRM_MODE_FLAG_NHSYNC) - dumb_ctrl |= CFG_INV_HSYNC; - if (dcrtc->crtc.mode.flags & DRM_MODE_FLAG_NVSYNC) - dumb_ctrl |= CFG_INV_VSYNC; - - if (dcrtc->dumb_ctrl != dumb_ctrl) { - dcrtc->dumb_ctrl = dumb_ctrl; - writel_relaxed(dumb_ctrl, dcrtc->base + LCD_SPU_DUMB_CTRL); - } + armada_updatel(dumb_ctrl, + ~(CFG_INV_CSYNC | CFG_INV_HSYNC | CFG_INV_VSYNC), + dcrtc->base + LCD_SPU_DUMB_CTRL); } static void armada_drm_plane_work_call(struct armada_crtc *dcrtc, @@ -280,7 +264,6 @@ static void armada_drm_crtc_prepare(struct drm_crtc *crtc) { struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); struct drm_plane *plane; - u32 val; /* * If we have an overlay plane associated with this CRTC, disable @@ -300,11 +283,7 @@ static void armada_drm_crtc_prepare(struct drm_crtc *crtc) drm_crtc_vblank_off(crtc); - val = dcrtc->dumb_ctrl & ~CFG_DUMB_ENA; - if (val != dcrtc->dumb_ctrl) { - dcrtc->dumb_ctrl = val; - writel_relaxed(val, dcrtc->base + LCD_SPU_DUMB_CTRL); - } + armada_updatel(0, CFG_DUMB_ENA, dcrtc->base + LCD_SPU_DUMB_CTRL); } /* The mode_config.mutex will be held for this call */ @@ -516,6 +495,24 @@ static void armada_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) val = adj->flags & DRM_MODE_FLAG_NVSYNC ? CFG_VSYNC_INV : 0; armada_reg_queue_mod(regs, i, val, CFG_VSYNC_INV, LCD_SPU_DMA_CTRL1); + + /* + * The documentation doesn't indicate what the normal state of + * the sync signals are. Sebastian Hesselbart kindly probed + * these signals on his board to determine their state. + * + * The non-inverted state of the sync signals is active high. + * Setting these bits makes the appropriate signal active low. + */ + val = 0; + if (adj->flags & DRM_MODE_FLAG_NCSYNC) + val |= CFG_INV_CSYNC; + if (adj->flags & DRM_MODE_FLAG_NHSYNC) + val |= CFG_INV_HSYNC; + if (adj->flags & DRM_MODE_FLAG_NVSYNC) + val |= CFG_INV_VSYNC; + armada_reg_queue_mod(regs, i, val, CFG_INV_CSYNC | CFG_INV_HSYNC | + CFG_INV_VSYNC, LCD_SPU_DUMB_CTRL); armada_reg_queue_end(regs, i); armada_drm_crtc_update_regs(dcrtc, regs); diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h index 21338f7c3d7dd..775c01c529820 100644 --- a/drivers/gpu/drm/armada/armada_crtc.h +++ b/drivers/gpu/drm/armada/armada_crtc.h @@ -85,7 +85,6 @@ struct armada_crtc { int dpms; uint32_t cfg_dumb_ctrl; - uint32_t dumb_ctrl; uint32_t spu_iopad_ctrl; spinlock_t irq_lock; -- GitLab From a61c3922f6293ab5d58f64e2312981cc646c2fd8 Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 1385/1506] drm/armada: update debug in armada_drm_crtc_mode_set_nofb() Update debug to use KMS level, and print the mode using the standard format for mode lines, but print the adjusted CRTC parameters as that's what we will be programming for. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/armada/armada_crtc.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 3cae6587b0794..9ad966caf08cc 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -426,16 +426,15 @@ static void armada_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) bm = adj->crtc_vsync_start - adj->crtc_vdisplay; tm = adj->crtc_vtotal - adj->crtc_vsync_end; - DRM_DEBUG_DRIVER("H: %d %d %d %d lm %d rm %d\n", - adj->crtc_hdisplay, - adj->crtc_hsync_start, - adj->crtc_hsync_end, - adj->crtc_htotal, lm, rm); - DRM_DEBUG_DRIVER("V: %d %d %d %d tm %d bm %d\n", - adj->crtc_vdisplay, - adj->crtc_vsync_start, - adj->crtc_vsync_end, - adj->crtc_vtotal, tm, bm); + DRM_DEBUG_KMS("[CRTC:%d:%s] mode " DRM_MODE_FMT "\n", + crtc->base.id, crtc->name, + adj->base.id, adj->name, adj->vrefresh, adj->clock, + adj->crtc_hdisplay, adj->crtc_hsync_start, + adj->crtc_hsync_end, adj->crtc_htotal, + adj->crtc_vdisplay, adj->crtc_vsync_start, + adj->crtc_vsync_end, adj->crtc_vtotal, + adj->type, adj->flags); + DRM_DEBUG_KMS("lm %d rm %d tm %d bm %d\n", lm, rm, tm, bm); /* * If we are blanked, we would have disabled the clock. Re-enable -- GitLab From 4e4b3563ac006e47761341682de80528e2cf30ab Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 1386/1506] drm/armada: clean up SPU_ADV_REG Rather than writing all bits of SPU_ADV_REG on modeset, only write what we need to change, and initialise the register in the variant initialisation. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/armada/armada_510.c | 5 ++++- drivers/gpu/drm/armada/armada_crtc.c | 11 ++++------- drivers/gpu/drm/armada/armada_drm.h | 1 - 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_510.c b/drivers/gpu/drm/armada/armada_510.c index 41a784f5a5e64..9a4fbb6a24b8f 100644 --- a/drivers/gpu/drm/armada/armada_510.c +++ b/drivers/gpu/drm/armada/armada_510.c @@ -27,6 +27,10 @@ static int armada510_crtc_init(struct armada_crtc *dcrtc, struct device *dev) /* Lower the watermark so to eliminate jitter at higher bandwidths */ armada_updatel(0x20, (1 << 11) | 0xff, dcrtc->base + LCD_CFG_RDREG4F); + /* Initialise SPU register */ + writel_relaxed(ADV_HWC32ENABLE | ADV_HWC32ARGB | ADV_HWC32BLEND, + dcrtc->base + LCD_SPU_ADV_REG); + return 0; } @@ -77,7 +81,6 @@ static int armada510_crtc_compute_clock(struct armada_crtc *dcrtc, const struct armada_variant armada510_ops = { .has_spu_adv_reg = true, - .spu_adv_reg = ADV_HWC32ENABLE | ADV_HWC32ARGB | ADV_HWC32BLEND, .init = armada510_crtc_init, .compute_clock = armada510_crtc_compute_clock, }; diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 9ad966caf08cc..80d34a4b7d416 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -463,17 +463,15 @@ static void armada_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) adj->crtc_htotal; dcrtc->v[1].spu_v_porch = tm << 16 | bm; val = adj->crtc_hsync_start; - dcrtc->v[1].spu_adv_reg = val << 20 | val | ADV_VSYNCOFFEN | - dcrtc->variant->spu_adv_reg; + dcrtc->v[1].spu_adv_reg = val << 20 | val | ADV_VSYNCOFFEN; if (interlaced) { /* Odd interlaced frame */ + val -= adj->crtc_htotal / 2; + dcrtc->v[0].spu_adv_reg = val << 20 | val | ADV_VSYNCOFFEN; dcrtc->v[0].spu_v_h_total = dcrtc->v[1].spu_v_h_total + (1 << 16); dcrtc->v[0].spu_v_porch = dcrtc->v[1].spu_v_porch + 1; - val = adj->crtc_hsync_start - adj->crtc_htotal / 2; - dcrtc->v[0].spu_adv_reg = val << 20 | val | ADV_VSYNCOFFEN | - dcrtc->variant->spu_adv_reg; } else { dcrtc->v[0] = dcrtc->v[1]; } @@ -486,11 +484,10 @@ static void armada_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) armada_reg_queue_set(regs, i, dcrtc->v[0].spu_v_h_total, LCD_SPUT_V_H_TOTAL); - if (dcrtc->variant->has_spu_adv_reg) { + if (dcrtc->variant->has_spu_adv_reg) armada_reg_queue_mod(regs, i, dcrtc->v[0].spu_adv_reg, ADV_VSYNC_L_OFF | ADV_VSYNC_H_OFF | ADV_VSYNCOFFEN, LCD_SPU_ADV_REG); - } val = adj->flags & DRM_MODE_FLAG_NVSYNC ? CFG_VSYNC_INV : 0; armada_reg_queue_mod(regs, i, val, CFG_VSYNC_INV, LCD_SPU_DMA_CTRL1); diff --git a/drivers/gpu/drm/armada/armada_drm.h b/drivers/gpu/drm/armada/armada_drm.h index 64f1c8836078c..a6f919b0084c6 100644 --- a/drivers/gpu/drm/armada/armada_drm.h +++ b/drivers/gpu/drm/armada/armada_drm.h @@ -42,7 +42,6 @@ struct armada_private; struct armada_variant { bool has_spu_adv_reg; - uint32_t spu_adv_reg; int (*init)(struct armada_crtc *, struct device *); int (*compute_clock)(struct armada_crtc *, const struct drm_display_mode *, -- GitLab From dbb4ca8acae100b21946a9c6439af51bd606595e Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 1387/1506] drm/armada: handle atomic modeset crtc events Prepare handling for atomic modeset CRTC events. Currently, using the transition helpers, CRTC events do not exist, but once we switch to proper atomic modeset, they have to be handled. We queue an event for the next vblank in two places: - armada_drm_crtc_atomic_flush() provided we aren't doing an atomic modeset. - armada_drm_crtc_commit() if we are committing a modeset. This ensures that the event is sent at the correct time (after all updates have been written to the hardware and after the following vblank.) Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/armada/armada_crtc.c | 33 ++++++++++++++++++++++++++++ drivers/gpu/drm/armada/armada_crtc.h | 1 + 2 files changed, 34 insertions(+) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 80d34a4b7d416..a0c67ec892cf5 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -232,6 +232,19 @@ static void armada_drm_vblank_off(struct armada_crtc *dcrtc) armada_drm_plane_work_run(dcrtc, dcrtc->crtc.primary); } +static void armada_drm_crtc_queue_state_event(struct drm_crtc *crtc) +{ + struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); + struct drm_pending_vblank_event *event; + + /* If we have an event, we need vblank events enabled */ + event = xchg(&crtc->state->event, NULL); + if (event) { + WARN_ON(drm_crtc_vblank_get(crtc) != 0); + dcrtc->event = event; + } +} + /* The mode_config.mutex will be held for this call */ static void armada_drm_crtc_dpms(struct drm_crtc *crtc, int dpms) { @@ -294,6 +307,8 @@ static void armada_drm_crtc_commit(struct drm_crtc *crtc) dcrtc->dpms = DRM_MODE_DPMS_ON; armada_drm_crtc_update(dcrtc); drm_crtc_vblank_on(crtc); + + armada_drm_crtc_queue_state_event(crtc); } /* The mode_config.mutex will be held for this call */ @@ -337,6 +352,7 @@ static void armada_drm_crtc_enable_irq(struct armada_crtc *dcrtc, u32 mask) static void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat) { + struct drm_pending_vblank_event *event; void __iomem *base = dcrtc->base; struct drm_plane *ovl_plane; @@ -383,6 +399,16 @@ static void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat) if (stat & GRA_FRAME_IRQ) armada_drm_plane_work_run(dcrtc, dcrtc->crtc.primary); + + if (stat & VSYNC_IRQ) { + event = xchg(&dcrtc->event, NULL); + if (event) { + spin_lock(&dcrtc->crtc.dev->event_lock); + drm_crtc_send_vblank_event(&dcrtc->crtc, event); + spin_unlock(&dcrtc->crtc.dev->event_lock); + drm_crtc_vblank_put(&dcrtc->crtc); + } + } } static irqreturn_t armada_drm_irq(int irq, void *arg) @@ -554,6 +580,13 @@ static void armada_drm_crtc_atomic_flush(struct drm_crtc *crtc, spin_lock_irqsave(&dcrtc->irq_lock, flags); armada_drm_crtc_update_regs(dcrtc, dcrtc->regs); spin_unlock_irqrestore(&dcrtc->irq_lock, flags); + + /* + * If we aren't doing a full modeset, then we need to queue + * the event here. + */ + if (!drm_atomic_crtc_needs_modeset(crtc->state)) + armada_drm_crtc_queue_state_event(crtc); } static const struct drm_crtc_helper_funcs armada_crtc_helper_funcs = { diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h index 775c01c529820..8b1de877cb021 100644 --- a/drivers/gpu/drm/armada/armada_crtc.h +++ b/drivers/gpu/drm/armada/armada_crtc.h @@ -90,6 +90,7 @@ struct armada_crtc { spinlock_t irq_lock; uint32_t irq_ena; + struct drm_pending_vblank_event *event; struct armada_regs atomic_regs[32]; struct armada_regs *regs; unsigned int regs_idx; -- GitLab From a0fbb35ecde52aa5abf5975d117d29e3b30f7b91 Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 1388/1506] drm/armada: push responsibility for clock management to backend Push responsibility for managing the clock during DPMS down into the variant backend, rather than the CRTC layer having knowledge of its state. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/armada/armada_510.c | 19 +++++++++++++++++++ drivers/gpu/drm/armada/armada_crtc.c | 19 ++++++------------- drivers/gpu/drm/armada/armada_drm.h | 2 ++ 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_510.c b/drivers/gpu/drm/armada/armada_510.c index 9a4fbb6a24b8f..2f7c048c53613 100644 --- a/drivers/gpu/drm/armada/armada_510.c +++ b/drivers/gpu/drm/armada/armada_510.c @@ -79,8 +79,27 @@ static int armada510_crtc_compute_clock(struct armada_crtc *dcrtc, return 0; } +static void armada510_crtc_disable(struct armada_crtc *dcrtc) +{ + if (!IS_ERR(dcrtc->clk)) { + clk_disable_unprepare(dcrtc->clk); + dcrtc->clk = ERR_PTR(-EINVAL); + } +} + +static void armada510_crtc_enable(struct armada_crtc *dcrtc, + const struct drm_display_mode *mode) +{ + if (IS_ERR(dcrtc->clk)) { + dcrtc->clk = dcrtc->extclk[0]; + WARN_ON(clk_prepare_enable(dcrtc->clk)); + } +} + const struct armada_variant armada510_ops = { .has_spu_adv_reg = true, .init = armada510_crtc_init, .compute_clock = armada510_crtc_compute_clock, + .disable = armada510_crtc_disable, + .enable = armada510_crtc_enable, }; diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index a0c67ec892cf5..5d8fdcda27ee8 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -253,14 +253,14 @@ static void armada_drm_crtc_dpms(struct drm_crtc *crtc, int dpms) if (dpms_blanked(dcrtc->dpms) != dpms_blanked(dpms)) { if (dpms_blanked(dpms)) armada_drm_vblank_off(dcrtc); - else if (!IS_ERR(dcrtc->clk)) - WARN_ON(clk_prepare_enable(dcrtc->clk)); + else if (dcrtc->variant->enable) + dcrtc->variant->enable(dcrtc, &crtc->hwmode); dcrtc->dpms = dpms; armada_drm_crtc_update(dcrtc); if (!dpms_blanked(dpms)) drm_crtc_vblank_on(&dcrtc->crtc); - else if (!IS_ERR(dcrtc->clk)) - clk_disable_unprepare(dcrtc->clk); + else if (dcrtc->variant->disable) + dcrtc->variant->disable(dcrtc); } else if (dcrtc->dpms != dpms) { dcrtc->dpms = dpms; } @@ -462,13 +462,6 @@ static void armada_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) adj->type, adj->flags); DRM_DEBUG_KMS("lm %d rm %d tm %d bm %d\n", lm, rm, tm, bm); - /* - * If we are blanked, we would have disabled the clock. Re-enable - * it so that compute_clock() does the right thing. - */ - if (!IS_ERR(dcrtc->clk) && dpms_blanked(dcrtc->dpms)) - WARN_ON(clk_prepare_enable(dcrtc->clk)); - /* Now compute the divider for real */ dcrtc->variant->compute_clock(dcrtc, adj, &sclk); @@ -824,8 +817,8 @@ static void armada_drm_crtc_destroy(struct drm_crtc *crtc) priv->dcrtc[dcrtc->num] = NULL; drm_crtc_cleanup(&dcrtc->crtc); - if (!IS_ERR(dcrtc->clk)) - clk_disable_unprepare(dcrtc->clk); + if (dcrtc->variant->disable) + dcrtc->variant->disable(dcrtc); writel_relaxed(0, dcrtc->base + LCD_SPU_IRQ_ENA); diff --git a/drivers/gpu/drm/armada/armada_drm.h b/drivers/gpu/drm/armada/armada_drm.h index a6f919b0084c6..9658be917ea1e 100644 --- a/drivers/gpu/drm/armada/armada_drm.h +++ b/drivers/gpu/drm/armada/armada_drm.h @@ -46,6 +46,8 @@ struct armada_variant { int (*compute_clock)(struct armada_crtc *, const struct drm_display_mode *, uint32_t *); + void (*disable)(struct armada_crtc *); + void (*enable)(struct armada_crtc *, const struct drm_display_mode *); }; /* Variant ops */ -- GitLab From a0f75d2468fe4510bb8d0d6c4e1a5fd5e262e7b5 Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 1389/1506] drm/armada: unhook dpms state from armada_drm_crtc_update() Explicitly pass in the desired enable/disable state into armada_drm_crtc_update() rather than having it use the DPMS state stored in our crtc structure. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/armada/armada_crtc.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 5d8fdcda27ee8..554135062d931 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -94,13 +94,13 @@ armada_drm_crtc_update_regs(struct armada_crtc *dcrtc, struct armada_regs *regs) #define dpms_blanked(dpms) ((dpms) != DRM_MODE_DPMS_ON) -static void armada_drm_crtc_update(struct armada_crtc *dcrtc) +static void armada_drm_crtc_update(struct armada_crtc *dcrtc, bool enable) { uint32_t dumb_ctrl; dumb_ctrl = dcrtc->cfg_dumb_ctrl; - if (!dpms_blanked(dcrtc->dpms)) + if (enable) dumb_ctrl |= CFG_DUMB_ENA; /* @@ -109,8 +109,7 @@ static void armada_drm_crtc_update(struct armada_crtc *dcrtc) * force LCD_D[23:0] to output blank color, overriding the GPIO or * SPI usage. So leave it as-is unless in DUMB24_RGB888_0 mode. */ - if (dpms_blanked(dcrtc->dpms) && - (dumb_ctrl & DUMB_MASK) == DUMB24_RGB888_0) { + if (!enable && (dumb_ctrl & DUMB_MASK) == DUMB24_RGB888_0) { dumb_ctrl &= ~DUMB_MASK; dumb_ctrl |= DUMB_BLANK; } @@ -256,7 +255,7 @@ static void armada_drm_crtc_dpms(struct drm_crtc *crtc, int dpms) else if (dcrtc->variant->enable) dcrtc->variant->enable(dcrtc, &crtc->hwmode); dcrtc->dpms = dpms; - armada_drm_crtc_update(dcrtc); + armada_drm_crtc_update(dcrtc, !dpms_blanked(dcrtc->dpms)); if (!dpms_blanked(dpms)) drm_crtc_vblank_on(&dcrtc->crtc); else if (dcrtc->variant->disable) @@ -305,7 +304,7 @@ static void armada_drm_crtc_commit(struct drm_crtc *crtc) struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); dcrtc->dpms = DRM_MODE_DPMS_ON; - armada_drm_crtc_update(dcrtc); + armada_drm_crtc_update(dcrtc, true); drm_crtc_vblank_on(crtc); armada_drm_crtc_queue_state_event(crtc); -- GitLab From 34e25ed60ae2cdf91b953dd3772ae48a6bffbd4c Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 1390/1506] drm/armada: implement atomic_enable()/atomic_disable() methods Implement the atomic_enable()/atomic_disable() methods used by the atomic modeset helpers. atomic_disable() will need some transitional code during conversion to ensure proper ordering is maintained. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/armada/armada_crtc.c | 71 ++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 554135062d931..e93097d3aa068 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -581,6 +581,75 @@ static void armada_drm_crtc_atomic_flush(struct drm_crtc *crtc, armada_drm_crtc_queue_state_event(crtc); } +static void armada_drm_crtc_atomic_disable(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) +{ + struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); + struct drm_pending_vblank_event *event; + struct drm_plane *plane; + + DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name); + + /* + * For transition only - we must wait for completion of our + * untransitioned paths before changing anything. + */ + plane = dcrtc->plane; + if (plane) + WARN_ON(!armada_drm_plane_work_wait(drm_to_armada_plane(plane), + HZ)); + armada_drm_plane_work_wait(drm_to_armada_plane(dcrtc->crtc.primary), + MAX_SCHEDULE_TIMEOUT); + + dcrtc->dpms = DRM_MODE_DPMS_OFF; + drm_crtc_vblank_off(crtc); + armada_drm_crtc_update(dcrtc, false); + + if (!crtc->state->active) { + /* + * This modeset will be leaving the CRTC disabled, so + * call the backend to disable upstream clocks etc. + */ + if (dcrtc->variant->disable) + dcrtc->variant->disable(dcrtc); + + /* + * We will not receive any further vblank events. + * Send the flip_done event manually. + */ + event = crtc->state->event; + crtc->state->event = NULL; + if (event) { + spin_lock_irq(&crtc->dev->event_lock); + drm_crtc_send_vblank_event(crtc, event); + spin_unlock_irq(&crtc->dev->event_lock); + } + } +} + +static void armada_drm_crtc_atomic_enable(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) +{ + struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); + + DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name); + + dcrtc->dpms = DRM_MODE_DPMS_ON; + if (!old_state->active) { + /* + * This modeset is enabling the CRTC after it having + * been disabled. Reverse the call to ->disable in + * the atomic_disable(). + */ + if (dcrtc->variant->enable) + dcrtc->variant->enable(dcrtc, &crtc->state->adjusted_mode); + } + armada_drm_crtc_update(dcrtc, true); + drm_crtc_vblank_on(crtc); + + armada_drm_crtc_queue_state_event(crtc); +} + static const struct drm_crtc_helper_funcs armada_crtc_helper_funcs = { .dpms = armada_drm_crtc_dpms, .prepare = armada_drm_crtc_prepare, @@ -592,6 +661,8 @@ static const struct drm_crtc_helper_funcs armada_crtc_helper_funcs = { .disable = armada_drm_crtc_disable, .atomic_begin = armada_drm_crtc_atomic_begin, .atomic_flush = armada_drm_crtc_atomic_flush, + .atomic_disable = armada_drm_crtc_atomic_disable, + .atomic_enable = armada_drm_crtc_atomic_enable, }; static void armada_load_cursor_argb(void __iomem *base, uint32_t *pix, -- GitLab From 6bd02908836ed00aa7fcdc759d490029137c2b30 Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Mon, 30 Jul 2018 11:53:06 +0100 Subject: [PATCH 1391/1506] drm/armada: enable atomic modeset support Enable atomic modeset helpers, and internal DRM use of atomic modeset with armada-drm. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/armada/armada_crtc.c | 7 +++---- drivers/gpu/drm/armada/armada_drv.c | 5 ++++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index e93097d3aa068..375a20757561a 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -278,13 +278,12 @@ static void armada_drm_crtc_prepare(struct drm_crtc *crtc) struct drm_plane *plane; /* - * If we have an overlay plane associated with this CRTC, disable - * it before the modeset to avoid its coordinates being outside - * the new mode parameters. + * If we have an overlay plane associated with this CRTC, disable it + * before the modeset to avoid its coordinates being outside the new + * mode parameters. For transitional atomic modeset, we only wait. */ plane = dcrtc->plane; if (plane) { - drm_plane_force_disable(plane); WARN_ON(!armada_drm_plane_work_wait(drm_to_armada_plane(plane), HZ)); } diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c index 7517f23bb9cdb..20661bd9001e9 100644 --- a/drivers/gpu/drm/armada/armada_drv.c +++ b/drivers/gpu/drm/armada/armada_drv.c @@ -9,6 +9,7 @@ #include <linux/component.h> #include <linux/module.h> #include <linux/of_graph.h> +#include <drm/drm_atomic_helper.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_fb_helper.h> #include <drm/drm_of.h> @@ -73,7 +74,7 @@ static struct drm_driver armada_drm_driver = { .desc = "Armada SoC DRM", .date = "20120730", .driver_features = DRIVER_GEM | DRIVER_MODESET | - DRIVER_PRIME, + DRIVER_PRIME | DRIVER_ATOMIC, .ioctls = armada_ioctls, .fops = &armada_drm_fops, }; @@ -81,6 +82,8 @@ static struct drm_driver armada_drm_driver = { static const struct drm_mode_config_funcs armada_drm_mode_config_funcs = { .fb_create = armada_fb_create, .output_poll_changed = drm_fb_helper_output_poll_changed, + .atomic_check = drm_atomic_helper_check, + .atomic_commit = drm_atomic_helper_commit, }; static int armada_drm_bind(struct device *dev) -- GitLab From 6d2f864fdff5c73cb37069cd17b0f897d7995b62 Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Mon, 30 Jul 2018 11:53:06 +0100 Subject: [PATCH 1392/1506] drm/armada: switch legacy modeset to atomic modeset Switch the legacy set_config() method to use the atomic modeset helper, which allows us to get rid of the legacy dpms, prepare, commit, mode_set, mode_set_base and disable helper methods. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/armada/armada_crtc.c | 103 +-------------------------- drivers/gpu/drm/armada/armada_crtc.h | 1 - 2 files changed, 1 insertion(+), 103 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 375a20757561a..0cef40ad3a061 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -92,8 +92,6 @@ armada_drm_crtc_update_regs(struct armada_crtc *dcrtc, struct armada_regs *regs) } } -#define dpms_blanked(dpms) ((dpms) != DRM_MODE_DPMS_ON) - static void armada_drm_crtc_update(struct armada_crtc *dcrtc, bool enable) { uint32_t dumb_ctrl; @@ -221,16 +219,6 @@ armada_drm_crtc_alloc_plane_work(struct drm_plane *plane) return work; } -static void armada_drm_vblank_off(struct armada_crtc *dcrtc) -{ - /* - * Tell the DRM core that vblank IRQs aren't going to happen for - * a while. This cleans up any pending vblank events for us. - */ - drm_crtc_vblank_off(&dcrtc->crtc); - armada_drm_plane_work_run(dcrtc, dcrtc->crtc.primary); -} - static void armada_drm_crtc_queue_state_event(struct drm_crtc *crtc) { struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); @@ -244,71 +232,6 @@ static void armada_drm_crtc_queue_state_event(struct drm_crtc *crtc) } } -/* The mode_config.mutex will be held for this call */ -static void armada_drm_crtc_dpms(struct drm_crtc *crtc, int dpms) -{ - struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); - - if (dpms_blanked(dcrtc->dpms) != dpms_blanked(dpms)) { - if (dpms_blanked(dpms)) - armada_drm_vblank_off(dcrtc); - else if (dcrtc->variant->enable) - dcrtc->variant->enable(dcrtc, &crtc->hwmode); - dcrtc->dpms = dpms; - armada_drm_crtc_update(dcrtc, !dpms_blanked(dcrtc->dpms)); - if (!dpms_blanked(dpms)) - drm_crtc_vblank_on(&dcrtc->crtc); - else if (dcrtc->variant->disable) - dcrtc->variant->disable(dcrtc); - } else if (dcrtc->dpms != dpms) { - dcrtc->dpms = dpms; - } -} - -/* - * Prepare for a mode set. Turn off overlay to ensure that we don't end - * up with the overlay size being bigger than the active screen size. - * We rely upon X refreshing this state after the mode set has completed. - * - * The mode_config.mutex will be held for this call - */ -static void armada_drm_crtc_prepare(struct drm_crtc *crtc) -{ - struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); - struct drm_plane *plane; - - /* - * If we have an overlay plane associated with this CRTC, disable it - * before the modeset to avoid its coordinates being outside the new - * mode parameters. For transitional atomic modeset, we only wait. - */ - plane = dcrtc->plane; - if (plane) { - WARN_ON(!armada_drm_plane_work_wait(drm_to_armada_plane(plane), - HZ)); - } - - /* Wait for pending flips to complete */ - armada_drm_plane_work_wait(drm_to_armada_plane(dcrtc->crtc.primary), - MAX_SCHEDULE_TIMEOUT); - - drm_crtc_vblank_off(crtc); - - armada_updatel(0, CFG_DUMB_ENA, dcrtc->base + LCD_SPU_DUMB_CTRL); -} - -/* The mode_config.mutex will be held for this call */ -static void armada_drm_crtc_commit(struct drm_crtc *crtc) -{ - struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); - - dcrtc->dpms = DRM_MODE_DPMS_ON; - armada_drm_crtc_update(dcrtc, true); - drm_crtc_vblank_on(crtc); - - armada_drm_crtc_queue_state_event(crtc); -} - /* The mode_config.mutex will be held for this call */ static bool armada_drm_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode, struct drm_display_mode *adj) @@ -532,15 +455,6 @@ static void armada_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) spin_unlock_irqrestore(&dcrtc->irq_lock, flags); } -/* The mode_config.mutex will be held for this call */ -static void armada_drm_crtc_disable(struct drm_crtc *crtc) -{ - armada_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); - - /* Disable our primary plane when we disable the CRTC. */ - crtc->primary->funcs->disable_plane(crtc->primary, NULL); -} - static void armada_drm_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state) { @@ -600,7 +514,6 @@ static void armada_drm_crtc_atomic_disable(struct drm_crtc *crtc, armada_drm_plane_work_wait(drm_to_armada_plane(dcrtc->crtc.primary), MAX_SCHEDULE_TIMEOUT); - dcrtc->dpms = DRM_MODE_DPMS_OFF; drm_crtc_vblank_off(crtc); armada_drm_crtc_update(dcrtc, false); @@ -633,7 +546,6 @@ static void armada_drm_crtc_atomic_enable(struct drm_crtc *crtc, DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name); - dcrtc->dpms = DRM_MODE_DPMS_ON; if (!old_state->active) { /* * This modeset is enabling the CRTC after it having @@ -650,14 +562,8 @@ static void armada_drm_crtc_atomic_enable(struct drm_crtc *crtc, } static const struct drm_crtc_helper_funcs armada_crtc_helper_funcs = { - .dpms = armada_drm_crtc_dpms, - .prepare = armada_drm_crtc_prepare, - .commit = armada_drm_crtc_commit, .mode_fixup = armada_drm_crtc_mode_fixup, - .mode_set = drm_helper_crtc_mode_set, .mode_set_nofb = armada_drm_crtc_mode_set_nofb, - .mode_set_base = drm_helper_crtc_mode_set_base, - .disable = armada_drm_crtc_disable, .atomic_begin = armada_drm_crtc_atomic_begin, .atomic_flush = armada_drm_crtc_atomic_flush, .atomic_disable = armada_drm_crtc_atomic_disable, @@ -962,13 +868,6 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc, WARN_ON(armada_drm_plane_work_queue(dcrtc, work)); work = NULL; - /* - * Finally, if the display is blanked, we won't receive an - * interrupt, so complete it now. - */ - if (dpms_blanked(dcrtc->dpms)) - armada_drm_plane_work_run(dcrtc, plane); - put_vblank: drm_crtc_vblank_put(crtc); put_work: @@ -1005,7 +904,7 @@ static const struct drm_crtc_funcs armada_crtc_funcs = { .cursor_set = armada_drm_crtc_cursor_set, .cursor_move = armada_drm_crtc_cursor_move, .destroy = armada_drm_crtc_destroy, - .set_config = drm_crtc_helper_set_config, + .set_config = drm_atomic_helper_set_config, .page_flip = armada_drm_crtc_page_flip, .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h index 8b1de877cb021..afc9266bc1e20 100644 --- a/drivers/gpu/drm/armada/armada_crtc.h +++ b/drivers/gpu/drm/armada/armada_crtc.h @@ -83,7 +83,6 @@ struct armada_crtc { uint32_t cursor_w; uint32_t cursor_h; - int dpms; uint32_t cfg_dumb_ctrl; uint32_t spu_iopad_ctrl; -- GitLab From 13c94d5349c9c0756131e7bf2e703ab36ea55c73 Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Mon, 30 Jul 2018 11:53:06 +0100 Subject: [PATCH 1393/1506] drm/armada: switch primary plane to atomic modeset Switch the primary plane away from the transitional helpers, and use the atomic helpers instead to implement the legacy set_plane ioctl call for this plane. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/armada/armada_crtc.c | 116 +------------------------- drivers/gpu/drm/armada/armada_plane.c | 4 +- 2 files changed, 3 insertions(+), 117 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 0cef40ad3a061..a25094bbeb2cd 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -191,34 +191,6 @@ void armada_drm_plane_work_cancel(struct armada_crtc *dcrtc, armada_drm_plane_work_call(dcrtc, work, work->cancel); } -static void armada_drm_crtc_complete_frame_work(struct armada_crtc *dcrtc, - struct armada_plane_work *work) -{ - unsigned long flags; - - spin_lock_irqsave(&dcrtc->irq_lock, flags); - armada_drm_crtc_update_regs(dcrtc, work->regs); - spin_unlock_irqrestore(&dcrtc->irq_lock, flags); -} - -static struct armada_plane_work * -armada_drm_crtc_alloc_plane_work(struct drm_plane *plane) -{ - struct armada_plane_work *work; - int i = 0; - - work = kzalloc(sizeof(*work), GFP_KERNEL); - if (!work) - return NULL; - - work->plane = plane; - work->fn = armada_drm_crtc_complete_frame_work; - work->need_kfree = true; - armada_reg_queue_end(work->regs, i); - - return work; -} - static void armada_drm_crtc_queue_state_event(struct drm_crtc *crtc) { struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); @@ -318,9 +290,6 @@ static void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat) spin_unlock(&dcrtc->irq_lock); - if (stat & GRA_FRAME_IRQ) - armada_drm_plane_work_run(dcrtc, dcrtc->crtc.primary); - if (stat & VSYNC_IRQ) { event = xchg(&dcrtc->event, NULL); if (event) { @@ -459,15 +428,9 @@ static void armada_drm_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state) { struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); - struct armada_plane *dplane; DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name); - /* Wait 100ms for any plane works to complete */ - dplane = drm_to_armada_plane(crtc->primary); - if (WARN_ON(armada_drm_plane_work_wait(dplane, HZ / 10) == 0)) - armada_drm_plane_work_cancel(dcrtc, dplane); - dcrtc->regs_idx = 0; dcrtc->regs = dcrtc->atomic_regs; } @@ -511,8 +474,6 @@ static void armada_drm_crtc_atomic_disable(struct drm_crtc *crtc, if (plane) WARN_ON(!armada_drm_plane_work_wait(drm_to_armada_plane(plane), HZ)); - armada_drm_plane_work_wait(drm_to_armada_plane(dcrtc->crtc.primary), - MAX_SCHEDULE_TIMEOUT); drm_crtc_vblank_off(crtc); armada_drm_crtc_update(dcrtc, false); @@ -802,81 +763,6 @@ static void armada_drm_crtc_destroy(struct drm_crtc *crtc) kfree(dcrtc); } -/* - * The mode_config lock is held here, to prevent races between this - * and a mode_set. - */ -static int armada_drm_crtc_page_flip(struct drm_crtc *crtc, - struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, - uint32_t page_flip_flags, struct drm_modeset_acquire_ctx *ctx) -{ - struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); - struct drm_plane *plane = crtc->primary; - const struct drm_plane_helper_funcs *plane_funcs; - struct drm_plane_state *state; - struct armada_plane_work *work; - int ret; - - /* Construct new state for the primary plane */ - state = drm_atomic_helper_plane_duplicate_state(plane); - if (!state) - return -ENOMEM; - - drm_atomic_set_fb_for_plane(state, fb); - - work = armada_drm_crtc_alloc_plane_work(plane); - if (!work) { - ret = -ENOMEM; - goto put_state; - } - - /* Make sure we can get vblank interrupts */ - ret = drm_crtc_vblank_get(crtc); - if (ret) - goto put_work; - - /* - * If we have another work pending, we can't process this flip. - * The modeset locks protect us from another user queuing a work - * while we're setting up. - */ - if (drm_to_armada_plane(plane)->work) { - ret = -EBUSY; - goto put_vblank; - } - - work->event = event; - work->old_fb = plane->state->fb; - - /* - * Hold a ref on the new fb while it's being displayed by the - * hardware. The old fb refcount will be released in the worker. - */ - drm_framebuffer_get(state->fb); - - /* Point of no return */ - swap(plane->state, state); - - dcrtc->regs_idx = 0; - dcrtc->regs = work->regs; - - plane_funcs = plane->helper_private; - plane_funcs->atomic_update(plane, state); - armada_reg_queue_end(dcrtc->regs, dcrtc->regs_idx); - - /* Queue the work - this should never fail */ - WARN_ON(armada_drm_plane_work_queue(dcrtc, work)); - work = NULL; - -put_vblank: - drm_crtc_vblank_put(crtc); -put_work: - kfree(work); -put_state: - drm_atomic_helper_plane_destroy_state(plane, state); - return ret; -} - /* These are called under the vbl_lock. */ static int armada_drm_crtc_enable_vblank(struct drm_crtc *crtc) { @@ -905,7 +791,7 @@ static const struct drm_crtc_funcs armada_crtc_funcs = { .cursor_move = armada_drm_crtc_cursor_move, .destroy = armada_drm_crtc_destroy, .set_config = drm_atomic_helper_set_config, - .page_flip = armada_drm_crtc_page_flip, + .page_flip = drm_atomic_helper_page_flip, .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, .enable_vblank = armada_drm_crtc_enable_vblank, diff --git a/drivers/gpu/drm/armada/armada_plane.c b/drivers/gpu/drm/armada/armada_plane.c index 1320fec4c386c..39c9ba3ee57ee 100644 --- a/drivers/gpu/drm/armada/armada_plane.c +++ b/drivers/gpu/drm/armada/armada_plane.c @@ -261,8 +261,8 @@ static const struct drm_plane_helper_funcs armada_primary_plane_helper_funcs = { }; static const struct drm_plane_funcs armada_primary_plane_funcs = { - .update_plane = drm_plane_helper_update, - .disable_plane = drm_plane_helper_disable, + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, .destroy = drm_primary_helper_destroy, .reset = drm_atomic_helper_plane_reset, .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, -- GitLab From b1ec9ed6aa985be432f9ba29696029dc6779258e Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Mon, 30 Jul 2018 11:53:06 +0100 Subject: [PATCH 1394/1506] drm/armada: switch overlay plane to atomic modeset Switch the overlay plane away from the transitional helpers and legacy methods, and use atomic helpers instead to implement the legacy set_plane ioctl methods. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/armada/armada_crtc.c | 89 ------------ drivers/gpu/drm/armada/armada_crtc.h | 19 --- drivers/gpu/drm/armada/armada_overlay.c | 172 +++++------------------- 3 files changed, 32 insertions(+), 248 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index a25094bbeb2cd..ebcb99316c94a 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -117,80 +117,6 @@ static void armada_drm_crtc_update(struct armada_crtc *dcrtc, bool enable) dcrtc->base + LCD_SPU_DUMB_CTRL); } -static void armada_drm_plane_work_call(struct armada_crtc *dcrtc, - struct armada_plane_work *work, - void (*fn)(struct armada_crtc *, struct armada_plane_work *)) -{ - struct armada_plane *dplane = drm_to_armada_plane(work->plane); - struct drm_pending_vblank_event *event; - struct drm_framebuffer *fb; - - if (fn) - fn(dcrtc, work); - drm_crtc_vblank_put(&dcrtc->crtc); - - event = work->event; - fb = work->old_fb; - if (event || fb) { - struct drm_device *dev = dcrtc->crtc.dev; - unsigned long flags; - - spin_lock_irqsave(&dev->event_lock, flags); - if (event) - drm_crtc_send_vblank_event(&dcrtc->crtc, event); - if (fb) - __armada_drm_queue_unref_work(dev, fb); - spin_unlock_irqrestore(&dev->event_lock, flags); - } - - if (work->need_kfree) - kfree(work); - - wake_up(&dplane->frame_wait); -} - -static void armada_drm_plane_work_run(struct armada_crtc *dcrtc, - struct drm_plane *plane) -{ - struct armada_plane *dplane = drm_to_armada_plane(plane); - struct armada_plane_work *work = xchg(&dplane->work, NULL); - - /* Handle any pending frame work. */ - if (work) - armada_drm_plane_work_call(dcrtc, work, work->fn); -} - -int armada_drm_plane_work_queue(struct armada_crtc *dcrtc, - struct armada_plane_work *work) -{ - struct armada_plane *plane = drm_to_armada_plane(work->plane); - int ret; - - ret = drm_crtc_vblank_get(&dcrtc->crtc); - if (ret) - return ret; - - ret = cmpxchg(&plane->work, NULL, work) ? -EBUSY : 0; - if (ret) - drm_crtc_vblank_put(&dcrtc->crtc); - - return ret; -} - -int armada_drm_plane_work_wait(struct armada_plane *plane, long timeout) -{ - return wait_event_timeout(plane->frame_wait, !plane->work, timeout); -} - -void armada_drm_plane_work_cancel(struct armada_crtc *dcrtc, - struct armada_plane *dplane) -{ - struct armada_plane_work *work = xchg(&dplane->work, NULL); - - if (work) - armada_drm_plane_work_call(dcrtc, work, work->cancel); -} - static void armada_drm_crtc_queue_state_event(struct drm_crtc *crtc) { struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); @@ -247,7 +173,6 @@ static void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat) { struct drm_pending_vblank_event *event; void __iomem *base = dcrtc->base; - struct drm_plane *ovl_plane; if (stat & DMA_FF_UNDERFLOW) DRM_ERROR("video underflow on crtc %u\n", dcrtc->num); @@ -257,10 +182,6 @@ static void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat) if (stat & VSYNC_IRQ) drm_crtc_handle_vblank(&dcrtc->crtc); - ovl_plane = dcrtc->plane; - if (ovl_plane) - armada_drm_plane_work_run(dcrtc, ovl_plane); - spin_lock(&dcrtc->irq_lock); if (stat & GRA_FRAME_IRQ && dcrtc->interlaced) { int i = stat & GRA_FRAME_IRQ0 ? 0 : 1; @@ -462,19 +383,9 @@ static void armada_drm_crtc_atomic_disable(struct drm_crtc *crtc, { struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); struct drm_pending_vblank_event *event; - struct drm_plane *plane; DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name); - /* - * For transition only - we must wait for completion of our - * untransitioned paths before changing anything. - */ - plane = dcrtc->plane; - if (plane) - WARN_ON(!armada_drm_plane_work_wait(drm_to_armada_plane(plane), - HZ)); - drm_crtc_vblank_off(crtc); armada_drm_crtc_update(dcrtc, false); diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h index afc9266bc1e20..5b607d45f4693 100644 --- a/drivers/gpu/drm/armada/armada_crtc.h +++ b/drivers/gpu/drm/armada/armada_crtc.h @@ -35,29 +35,12 @@ struct armada_crtc; struct armada_plane; struct armada_variant; -struct armada_plane_work { - void (*fn)(struct armada_crtc *, struct armada_plane_work *); - void (*cancel)(struct armada_crtc *, struct armada_plane_work *); - bool need_kfree; - struct drm_plane *plane; - struct drm_framebuffer *old_fb; - struct drm_pending_vblank_event *event; - struct armada_regs regs[24]; -}; - struct armada_plane { struct drm_plane base; wait_queue_head_t frame_wait; - struct armada_plane_work *work; }; #define drm_to_armada_plane(p) container_of(p, struct armada_plane, base) -int armada_drm_plane_work_queue(struct armada_crtc *dcrtc, - struct armada_plane_work *work); -int armada_drm_plane_work_wait(struct armada_plane *plane, long timeout); -void armada_drm_plane_work_cancel(struct armada_crtc *dcrtc, - struct armada_plane *plane); - struct armada_crtc { struct drm_crtc crtc; const struct armada_variant *variant; @@ -73,8 +56,6 @@ struct armada_crtc { bool interlaced; bool cursor_update; - struct drm_plane *plane; - struct armada_gem_object *cursor_obj; int cursor_x; int cursor_y; diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index 7de8b6bd78473..ec2043b6f61f9 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -27,9 +27,6 @@ struct armada_ovl_plane { struct armada_plane base; - struct armada_plane_work works[2]; - bool next_work; - bool wait_vblank; }; #define drm_to_armada_ovl_plane(p) \ container_of(p, struct armada_ovl_plane, base.base) @@ -74,18 +71,6 @@ static inline u32 armada_csc(struct drm_plane_state *state) } /* === Plane support === */ -static void armada_ovl_plane_work(struct armada_crtc *dcrtc, - struct armada_plane_work *work) -{ - unsigned long flags; - - trace_armada_ovl_plane_work(&dcrtc->crtc, work->plane); - - spin_lock_irqsave(&dcrtc->irq_lock, flags); - armada_drm_crtc_update_regs(dcrtc, work->regs); - spin_unlock_irqrestore(&dcrtc->irq_lock, flags); -} - static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane, struct drm_plane_state *old_state) { @@ -109,8 +94,6 @@ static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane, dcrtc = drm_to_armada_crtc(state->crtc); regs = dcrtc->regs + dcrtc->regs_idx; - drm_to_armada_ovl_plane(plane)->wait_vblank = false; - idx = 0; if (!old_state->visible && state->visible) armada_reg_queue_mod(regs, idx, @@ -173,8 +156,6 @@ static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane, CFG_SWAPYU | CFG_YUV2RGB) | CFG_DMA_FTOGGLE | CFG_DMA_TSTMODE | CFG_DMA_ENA; - - drm_to_armada_ovl_plane(plane)->wait_vblank = true; } else if (old_state->visible != state->visible) { cfg = state->visible ? CFG_DMA_ENA : 0; cfg_mask = CFG_DMA_ENA; @@ -262,9 +243,6 @@ static void armada_drm_overlay_plane_atomic_disable(struct drm_plane *plane, LCD_SPU_SRAM_PARA1); dcrtc->regs_idx += idx; - - if (dcrtc->plane == plane) - dcrtc->plane = NULL; } static const struct drm_plane_helper_funcs armada_overlay_plane_helper_funcs = { @@ -275,108 +253,50 @@ static const struct drm_plane_helper_funcs armada_overlay_plane_helper_funcs = { .atomic_disable = armada_drm_overlay_plane_atomic_disable, }; -static int armada_overlay_commit(struct drm_plane *plane, - struct drm_plane_state *state) -{ - struct armada_ovl_plane *dplane = drm_to_armada_ovl_plane(plane); - const struct drm_plane_helper_funcs *plane_funcs; - struct armada_crtc *dcrtc = drm_to_armada_crtc(state->crtc); - struct armada_plane_work *work; - int ret; - - plane_funcs = plane->helper_private; - ret = plane_funcs->atomic_check(plane, state); - if (ret) - goto put_state; - - work = &dplane->works[dplane->next_work]; - - if (plane->state->fb != state->fb) { - /* - * Take a reference on the new framebuffer - we want to - * hold on to it while the hardware is displaying it. - */ - drm_framebuffer_reference(state->fb); - - work->old_fb = plane->state->fb; - } else { - work->old_fb = NULL; - } - - /* Point of no return */ - swap(plane->state, state); - - /* No CRTC, can't update */ - if (!plane->state->crtc) - goto put_state; - - dcrtc->regs_idx = 0; - dcrtc->regs = work->regs; - - plane_funcs->atomic_update(plane, state); - - /* If nothing was updated, short-circuit */ - if (dcrtc->regs_idx == 0) - goto put_state; - - armada_reg_queue_end(dcrtc->regs, dcrtc->regs_idx); - - /* Wait for pending work to complete */ - if (armada_drm_plane_work_wait(&dplane->base, HZ / 25) == 0) - armada_drm_plane_work_cancel(dcrtc, &dplane->base); - - /* Just updating the position/size? */ - if (!dplane->wait_vblank) { - armada_ovl_plane_work(dcrtc, work); - goto put_state; - } - - dcrtc->plane = plane; - - /* Queue it for update on the next interrupt if we are enabled */ - ret = armada_drm_plane_work_queue(dcrtc, work); - if (ret) { - DRM_ERROR("failed to queue plane work: %d\n", ret); - ret = 0; - } - - dplane->next_work = !dplane->next_work; - -put_state: - plane->funcs->atomic_destroy_state(plane, state); - return ret; -} - static int -armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, +armada_overlay_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, int crtc_x, int crtc_y, unsigned crtc_w, unsigned crtc_h, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h, struct drm_modeset_acquire_ctx *ctx) { - struct drm_plane_state *state; + struct drm_atomic_state *state; + struct drm_plane_state *plane_state; + int ret = 0; trace_armada_ovl_plane_update(plane, crtc, fb, crtc_x, crtc_y, crtc_w, crtc_h, src_x, src_y, src_w, src_h); - /* Construct new state for the overlay plane */ - state = plane->funcs->atomic_duplicate_state(plane); + state = drm_atomic_state_alloc(plane->dev); if (!state) return -ENOMEM; - state->crtc = crtc; - drm_atomic_set_fb_for_plane(state, fb); - state->crtc_x = crtc_x; - state->crtc_y = crtc_y; - state->crtc_h = crtc_h; - state->crtc_w = crtc_w; - state->src_x = src_x; - state->src_y = src_y; - state->src_h = src_h; - state->src_w = src_w; - - return armada_overlay_commit(plane, state); + state->acquire_ctx = ctx; + plane_state = drm_atomic_get_plane_state(state, plane); + if (IS_ERR(plane_state)) { + ret = PTR_ERR(plane_state); + goto fail; + } + + ret = drm_atomic_set_crtc_for_plane(plane_state, crtc); + if (ret != 0) + goto fail; + + drm_atomic_set_fb_for_plane(plane_state, fb); + plane_state->crtc_x = crtc_x; + plane_state->crtc_y = crtc_y; + plane_state->crtc_h = crtc_h; + plane_state->crtc_w = crtc_w; + plane_state->src_x = src_x; + plane_state->src_y = src_y; + plane_state->src_h = src_h; + plane_state->src_w = src_w; + + ret = drm_atomic_nonblocking_commit(state); +fail: + drm_atomic_state_put(state); + return ret; } static void armada_ovl_plane_destroy(struct drm_plane *plane) @@ -388,25 +308,6 @@ static void armada_ovl_plane_destroy(struct drm_plane *plane) kfree(dplane); } -static int armada_ovl_plane_set_property(struct drm_plane *plane, - struct drm_property *property, uint64_t val) -{ - struct drm_plane_state *state; - int ret; - - state = plane->funcs->atomic_duplicate_state(plane); - if (!state) - return -ENOMEM; - - ret = plane->funcs->atomic_set_property(plane, state, property, val); - if (ret) { - plane->funcs->atomic_destroy_state(plane, state); - return ret; - } - - return armada_overlay_commit(plane, state); -} - static void armada_overlay_reset(struct drm_plane *plane) { struct armada_overlay_state *state; @@ -510,9 +411,6 @@ static int armada_overlay_set_property(struct drm_plane *plane, drm_to_overlay_state(state)->contrast = val; } else if (property == priv->saturation_prop) { drm_to_overlay_state(state)->saturation = val; - } else if (property == plane->color_encoding_property) { - /* transitional only */ - state->color_encoding = val; } else { return -EINVAL; } @@ -572,10 +470,9 @@ static int armada_overlay_get_property(struct drm_plane *plane, } static const struct drm_plane_funcs armada_ovl_plane_funcs = { - .update_plane = armada_ovl_plane_update, - .disable_plane = drm_plane_helper_disable, + .update_plane = armada_overlay_plane_update, + .disable_plane = drm_atomic_helper_disable_plane, .destroy = armada_ovl_plane_destroy, - .set_property = armada_ovl_plane_set_property, .reset = armada_overlay_reset, .atomic_duplicate_state = armada_overlay_duplicate_state, .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, @@ -670,11 +567,6 @@ int armada_overlay_plane_create(struct drm_device *dev, unsigned long crtcs) return ret; } - dplane->works[0].plane = &dplane->base.base; - dplane->works[0].fn = armada_ovl_plane_work; - dplane->works[1].plane = &dplane->base.base; - dplane->works[1].fn = armada_ovl_plane_work; - drm_plane_helper_add(&dplane->base.base, &armada_overlay_plane_helper_funcs); -- GitLab From 3cb13ac97bdfda5b301609256e3e0b59bc94f10a Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Mon, 30 Jul 2018 11:53:06 +0100 Subject: [PATCH 1395/1506] drm/armada: update planes after the dumb frame is complete Write out the plane updates after the dumb frame has completed, but just before the blank period. This allows all the plane updates to be performed in a flicker-free non-tearing manner. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/armada/armada_crtc.c | 46 ++++++++++++++++------------ drivers/gpu/drm/armada/armada_crtc.h | 1 + 2 files changed, 28 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index ebcb99316c94a..bb1e13b4516b7 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -197,21 +197,27 @@ static void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat) writel_relaxed(val, base + LCD_SPU_ADV_REG); } - if (stat & DUMB_FRAMEDONE && dcrtc->cursor_update) { - writel_relaxed(dcrtc->cursor_hw_pos, - base + LCD_SPU_HWC_OVSA_HPXL_VLN); - writel_relaxed(dcrtc->cursor_hw_sz, - base + LCD_SPU_HWC_HPXL_VLN); - armada_updatel(CFG_HWC_ENA, - CFG_HWC_ENA | CFG_HWC_1BITMOD | CFG_HWC_1BITENA, - base + LCD_SPU_DMA_CTRL0); - dcrtc->cursor_update = false; + if (stat & dcrtc->irq_ena & DUMB_FRAMEDONE) { + if (dcrtc->update_pending) { + armada_drm_crtc_update_regs(dcrtc, dcrtc->regs); + dcrtc->update_pending = false; + } + if (dcrtc->cursor_update) { + writel_relaxed(dcrtc->cursor_hw_pos, + base + LCD_SPU_HWC_OVSA_HPXL_VLN); + writel_relaxed(dcrtc->cursor_hw_sz, + base + LCD_SPU_HWC_HPXL_VLN); + armada_updatel(CFG_HWC_ENA, + CFG_HWC_ENA | CFG_HWC_1BITMOD | + CFG_HWC_1BITENA, + base + LCD_SPU_DMA_CTRL0); + dcrtc->cursor_update = false; + } armada_drm_crtc_disable_irq(dcrtc, DUMB_FRAMEDONE_ENA); } - spin_unlock(&dcrtc->irq_lock); - if (stat & VSYNC_IRQ) { + if (stat & VSYNC_IRQ && !dcrtc->update_pending) { event = xchg(&dcrtc->event, NULL); if (event) { spin_lock(&dcrtc->crtc.dev->event_lock); @@ -360,22 +366,26 @@ static void armada_drm_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state) { struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); - unsigned long flags; DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name); armada_reg_queue_end(dcrtc->regs, dcrtc->regs_idx); - spin_lock_irqsave(&dcrtc->irq_lock, flags); - armada_drm_crtc_update_regs(dcrtc, dcrtc->regs); - spin_unlock_irqrestore(&dcrtc->irq_lock, flags); - /* * If we aren't doing a full modeset, then we need to queue * the event here. */ - if (!drm_atomic_crtc_needs_modeset(crtc->state)) + if (!drm_atomic_crtc_needs_modeset(crtc->state)) { + dcrtc->update_pending = true; armada_drm_crtc_queue_state_event(crtc); + spin_lock_irq(&dcrtc->irq_lock); + armada_drm_crtc_enable_irq(dcrtc, DUMB_FRAMEDONE_ENA); + spin_unlock_irq(&dcrtc->irq_lock); + } else { + spin_lock_irq(&dcrtc->irq_lock); + armada_drm_crtc_update_regs(dcrtc, dcrtc->regs); + spin_unlock_irq(&dcrtc->irq_lock); + } } static void armada_drm_crtc_atomic_disable(struct drm_crtc *crtc, @@ -532,7 +542,6 @@ static int armada_drm_crtc_cursor_update(struct armada_crtc *dcrtc, bool reload) if (!dcrtc->cursor_obj || !h || !w) { spin_lock_irq(&dcrtc->irq_lock); - armada_drm_crtc_disable_irq(dcrtc, DUMB_FRAMEDONE_ENA); dcrtc->cursor_update = false; armada_updatel(0, CFG_HWC_ENA, dcrtc->base + LCD_SPU_DMA_CTRL0); spin_unlock_irq(&dcrtc->irq_lock); @@ -556,7 +565,6 @@ static int armada_drm_crtc_cursor_update(struct armada_crtc *dcrtc, bool reload) if (dcrtc->cursor_hw_sz != (h << 16 | w)) { spin_lock_irq(&dcrtc->irq_lock); - armada_drm_crtc_disable_irq(dcrtc, DUMB_FRAMEDONE_ENA); dcrtc->cursor_update = false; armada_updatel(0, CFG_HWC_ENA, dcrtc->base + LCD_SPU_DMA_CTRL0); spin_unlock_irq(&dcrtc->irq_lock); diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h index 5b607d45f4693..b95ea13d0705d 100644 --- a/drivers/gpu/drm/armada/armada_crtc.h +++ b/drivers/gpu/drm/armada/armada_crtc.h @@ -70,6 +70,7 @@ struct armada_crtc { spinlock_t irq_lock; uint32_t irq_ena; + bool update_pending; struct drm_pending_vblank_event *event; struct armada_regs atomic_regs[32]; struct armada_regs *regs; -- GitLab From dae2155bb07bb2063ce604049e9aa4e862b6db0a Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Mon, 30 Jul 2018 11:53:06 +0100 Subject: [PATCH 1396/1506] drm/armada: update primary framebuffer parameters on mode change The framebuffer base address and toggling mode needs to be updated when the interlaced flag for mode changes is updated. Arrange to reprogram these parameters when only the mode has changed. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/armada/armada_plane.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_plane.c b/drivers/gpu/drm/armada/armada_plane.c index 39c9ba3ee57ee..bed2dca83a375 100644 --- a/drivers/gpu/drm/armada/armada_plane.c +++ b/drivers/gpu/drm/armada/armada_plane.c @@ -184,11 +184,13 @@ static void armada_drm_primary_plane_atomic_update(struct drm_plane *plane, armada_reg_queue_set(regs, idx, val, LCD_SPU_GZM_HPXL_VLN); if (old_state->src.x1 != state->src.x1 || old_state->src.y1 != state->src.y1 || - old_state->fb != state->fb) { + old_state->fb != state->fb || + state->crtc->state->mode_changed) { idx += armada_drm_crtc_calc_fb(state, regs + idx, dcrtc->interlaced); } - if (old_state->fb != state->fb) { + if (old_state->fb != state->fb || + state->crtc->state->mode_changed) { cfg = CFG_GRA_FMT(drm_fb_to_armada_fb(state->fb)->fmt) | CFG_GRA_MOD(drm_fb_to_armada_fb(state->fb)->mod); if (drm_fb_to_armada_fb(state->fb)->fmt > CFG_420) -- GitLab From d701278ada5115c40cd4d58ce0fb1169479c0bf6 Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Mon, 30 Jul 2018 11:53:06 +0100 Subject: [PATCH 1397/1506] drm/armada: remove unnecessary armada_ovl_plane structure We no longer need a private plane structure, so get rid of it. Use the drm_plane structure directly. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/armada/armada_overlay.c | 34 +++++++------------------ 1 file changed, 9 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index ec2043b6f61f9..eb7dfb65ef475 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -25,12 +25,6 @@ #define DEFAULT_SATURATION 0x4000 #define DEFAULT_ENCODING DRM_COLOR_YCBCR_BT601 -struct armada_ovl_plane { - struct armada_plane base; -}; -#define drm_to_armada_ovl_plane(p) \ - container_of(p, struct armada_ovl_plane, base.base) - struct armada_overlay_state { struct drm_plane_state base; u32 colorkey_yr; @@ -301,11 +295,8 @@ armada_overlay_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, static void armada_ovl_plane_destroy(struct drm_plane *plane) { - struct armada_ovl_plane *dplane = drm_to_armada_ovl_plane(plane); - drm_plane_cleanup(plane); - - kfree(dplane); + kfree(plane); } static void armada_overlay_reset(struct drm_plane *plane) @@ -550,38 +541,31 @@ int armada_overlay_plane_create(struct drm_device *dev, unsigned long crtcs) { struct armada_private *priv = dev->dev_private; struct drm_mode_object *mobj; - struct armada_ovl_plane *dplane; + struct drm_plane *overlay; int ret; ret = armada_overlay_create_properties(dev); if (ret) return ret; - dplane = kzalloc(sizeof(*dplane), GFP_KERNEL); - if (!dplane) + overlay = kzalloc(sizeof(*overlay), GFP_KERNEL); + if (!overlay) return -ENOMEM; - ret = armada_drm_plane_init(&dplane->base); - if (ret) { - kfree(dplane); - return ret; - } - - drm_plane_helper_add(&dplane->base.base, - &armada_overlay_plane_helper_funcs); + drm_plane_helper_add(overlay, &armada_overlay_plane_helper_funcs); - ret = drm_universal_plane_init(dev, &dplane->base.base, crtcs, + ret = drm_universal_plane_init(dev, overlay, crtcs, &armada_ovl_plane_funcs, armada_ovl_formats, ARRAY_SIZE(armada_ovl_formats), NULL, DRM_PLANE_TYPE_OVERLAY, NULL); if (ret) { - kfree(dplane); + kfree(overlay); return ret; } - mobj = &dplane->base.base.base; + mobj = &overlay->base; drm_object_attach_property(mobj, priv->colorkey_prop, 0x0101fe); drm_object_attach_property(mobj, priv->colorkey_min_prop, @@ -601,7 +585,7 @@ int armada_overlay_plane_create(struct drm_device *dev, unsigned long crtcs) drm_object_attach_property(mobj, priv->saturation_prop, DEFAULT_SATURATION); - ret = drm_plane_create_color_properties(&dplane->base.base, + ret = drm_plane_create_color_properties(overlay, BIT(DRM_COLOR_YCBCR_BT601) | BIT(DRM_COLOR_YCBCR_BT709), BIT(DRM_COLOR_YCBCR_LIMITED_RANGE), -- GitLab From 82c702cb0c041a9a1c69f489d1517235a633fc77 Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Mon, 30 Jul 2018 11:53:06 +0100 Subject: [PATCH 1398/1506] drm/armada: remove unnecessary armada_plane structure We no longer require a private armada_plane structure, so eliminate it, and use the drm_plane structure directly. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/armada/armada_crtc.c | 6 +++--- drivers/gpu/drm/armada/armada_crtc.h | 7 ------- drivers/gpu/drm/armada/armada_plane.c | 17 +++-------------- drivers/gpu/drm/armada/armada_plane.h | 3 +-- 4 files changed, 7 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index bb1e13b4516b7..da9360688b554 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -723,7 +723,7 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev, { struct armada_private *priv = drm->dev_private; struct armada_crtc *dcrtc; - struct armada_plane *primary; + struct drm_plane *primary; void __iomem *base; int ret; @@ -793,7 +793,7 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev, goto err_crtc; } - ret = drm_crtc_init_with_planes(drm, &dcrtc->crtc, &primary->base, NULL, + ret = drm_crtc_init_with_planes(drm, &dcrtc->crtc, primary, NULL, &armada_crtc_funcs, NULL); if (ret) goto err_crtc_init; @@ -803,7 +803,7 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev, return armada_overlay_plane_create(drm, 1 << dcrtc->num); err_crtc_init: - primary->base.funcs->destroy(&primary->base); + primary->funcs->destroy(primary); err_crtc: kfree(dcrtc); diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h index b95ea13d0705d..7ebd337b60af3 100644 --- a/drivers/gpu/drm/armada/armada_crtc.h +++ b/drivers/gpu/drm/armada/armada_crtc.h @@ -32,15 +32,8 @@ struct armada_regs { armada_reg_queue_mod(_r, _i, 0, 0, ~0) struct armada_crtc; -struct armada_plane; struct armada_variant; -struct armada_plane { - struct drm_plane base; - wait_queue_head_t frame_wait; -}; -#define drm_to_armada_plane(p) container_of(p, struct armada_plane, base) - struct armada_crtc { struct drm_crtc crtc; const struct armada_variant *variant; diff --git a/drivers/gpu/drm/armada/armada_plane.c b/drivers/gpu/drm/armada/armada_plane.c index bed2dca83a375..9f36423dd394b 100644 --- a/drivers/gpu/drm/armada/armada_plane.c +++ b/drivers/gpu/drm/armada/armada_plane.c @@ -271,25 +271,14 @@ static const struct drm_plane_funcs armada_primary_plane_funcs = { .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, }; -int armada_drm_plane_init(struct armada_plane *plane) -{ - init_waitqueue_head(&plane->frame_wait); - return 0; -} - int armada_drm_primary_plane_init(struct drm_device *drm, - struct armada_plane *primary) + struct drm_plane *primary) { int ret; - ret = armada_drm_plane_init(primary); - if (ret) - return ret; - - drm_plane_helper_add(&primary->base, - &armada_primary_plane_helper_funcs); + drm_plane_helper_add(primary, &armada_primary_plane_helper_funcs); - ret = drm_universal_plane_init(drm, &primary->base, 0, + ret = drm_universal_plane_init(drm, primary, 0, &armada_primary_plane_funcs, armada_primary_formats, ARRAY_SIZE(armada_primary_formats), diff --git a/drivers/gpu/drm/armada/armada_plane.h b/drivers/gpu/drm/armada/armada_plane.h index 1bd8430992e09..ff4281ba7fad4 100644 --- a/drivers/gpu/drm/armada/armada_plane.h +++ b/drivers/gpu/drm/armada/armada_plane.h @@ -9,8 +9,7 @@ void armada_drm_plane_cleanup_fb(struct drm_plane *plane, struct drm_plane_state *old_state); int armada_drm_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *state); -int armada_drm_plane_init(struct armada_plane *plane); int armada_drm_primary_plane_init(struct drm_device *drm, - struct armada_plane *primary); + struct drm_plane *primary); #endif -- GitLab From aa595c00bcf5b6f2f394a98217f82c9402952ea9 Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Mon, 30 Jul 2018 11:53:06 +0100 Subject: [PATCH 1399/1506] drm/armada: remove obsolete fb unreferencing kfifo and workqueue Remove the obsolete fb unreferencing system that is no longer used since we've transitioned to atomic modeset. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/armada/armada_drm.h | 7 ------ drivers/gpu/drm/armada/armada_drv.c | 35 ----------------------------- 2 files changed, 42 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_drm.h b/drivers/gpu/drm/armada/armada_drm.h index 9658be917ea1e..f09083ff15d3b 100644 --- a/drivers/gpu/drm/armada/armada_drm.h +++ b/drivers/gpu/drm/armada/armada_drm.h @@ -55,8 +55,6 @@ extern const struct armada_variant armada510_ops; struct armada_private { struct drm_device drm; - struct work_struct fb_unref_work; - DECLARE_KFIFO(fb_unref, struct drm_framebuffer *, 8); struct drm_fb_helper *fbdev; struct armada_crtc *dcrtc[2]; struct drm_mm linear; /* protected by linear_lock */ @@ -75,11 +73,6 @@ struct armada_private { #endif }; -void __armada_drm_queue_unref_work(struct drm_device *, - struct drm_framebuffer *); -void armada_drm_queue_unref_work(struct drm_device *, - struct drm_framebuffer *); - int armada_fbdev_init(struct drm_device *); void armada_fbdev_fini(struct drm_device *); diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c index 20661bd9001e9..fa31589b4fc09 100644 --- a/drivers/gpu/drm/armada/armada_drv.c +++ b/drivers/gpu/drm/armada/armada_drv.c @@ -21,36 +21,6 @@ #include <drm/armada_drm.h> #include "armada_ioctlP.h" -static void armada_drm_unref_work(struct work_struct *work) -{ - struct armada_private *priv = - container_of(work, struct armada_private, fb_unref_work); - struct drm_framebuffer *fb; - - while (kfifo_get(&priv->fb_unref, &fb)) - drm_framebuffer_put(fb); -} - -/* Must be called with dev->event_lock held */ -void __armada_drm_queue_unref_work(struct drm_device *dev, - struct drm_framebuffer *fb) -{ - struct armada_private *priv = dev->dev_private; - - WARN_ON(!kfifo_put(&priv->fb_unref, fb)); - schedule_work(&priv->fb_unref_work); -} - -void armada_drm_queue_unref_work(struct drm_device *dev, - struct drm_framebuffer *fb) -{ - unsigned long flags; - - spin_lock_irqsave(&dev->event_lock, flags); - __armada_drm_queue_unref_work(dev, fb); - spin_unlock_irqrestore(&dev->event_lock, flags); -} - static struct drm_ioctl_desc armada_ioctls[] = { DRM_IOCTL_DEF_DRV(ARMADA_GEM_CREATE, armada_gem_create_ioctl,0), DRM_IOCTL_DEF_DRV(ARMADA_GEM_MMAP, armada_gem_mmap_ioctl, 0), @@ -134,9 +104,6 @@ static int armada_drm_bind(struct device *dev) dev_set_drvdata(dev, &priv->drm); - INIT_WORK(&priv->fb_unref_work, armada_drm_unref_work); - INIT_KFIFO(priv->fb_unref); - /* Mode setting support */ drm_mode_config_init(&priv->drm); priv->drm.mode_config.min_width = 320; @@ -190,7 +157,6 @@ static int armada_drm_bind(struct device *dev) err_kms: drm_mode_config_cleanup(&priv->drm); drm_mm_takedown(&priv->linear); - flush_work(&priv->fb_unref_work); drm_dev_put(&priv->drm); return ret; } @@ -209,7 +175,6 @@ static void armada_drm_unbind(struct device *dev) drm_mode_config_cleanup(&priv->drm); drm_mm_takedown(&priv->linear); - flush_work(&priv->fb_unref_work); drm_dev_put(&priv->drm); } -- GitLab From 489cae632fc04927e8ef36ac8d8847193a41df3b Mon Sep 17 00:00:00 2001 From: Jordan Crouse <jcrouse@codeaurora.org> Date: Tue, 24 Jul 2018 10:33:19 -0600 Subject: [PATCH 1400/1506] include: Move ascii85 functions from i915 to linux/ascii85.h The i915 DRM driver very cleverly used ascii85 encoding for their GPU state file. Move the encode functions to a general header file to support other drivers that might be interested in the same functionality. v4: Make the return value const char * as suggested by Chris Wilson v3: Fix error_puts -> err_puts pointed out by the 01.org bot v2: Update API to be cleaner for the caller as suggested by Chris Wilson Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/i915/i915_gpu_error.c | 34 +++--------------------- include/linux/ascii85.h | 38 +++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 30 deletions(-) create mode 100644 include/linux/ascii85.h diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 8c81cf3aa182e..f7f2aa71d8d99 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -31,6 +31,7 @@ #include <linux/stop_machine.h> #include <linux/zlib.h> #include <drm/drm_print.h> +#include <linux/ascii85.h> #include "i915_gpu_error.h" #include "i915_drv.h" @@ -517,35 +518,12 @@ void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...) va_end(args); } -static int -ascii85_encode_len(int len) -{ - return DIV_ROUND_UP(len, 4); -} - -static bool -ascii85_encode(u32 in, char *out) -{ - int i; - - if (in == 0) - return false; - - out[5] = '\0'; - for (i = 5; i--; ) { - out[i] = '!' + in % 85; - in /= 85; - } - - return true; -} - static void print_error_obj(struct drm_i915_error_state_buf *m, struct intel_engine_cs *engine, const char *name, struct drm_i915_error_object *obj) { - char out[6]; + char out[ASCII85_BUFSZ]; int page; if (!obj) @@ -567,12 +545,8 @@ static void print_error_obj(struct drm_i915_error_state_buf *m, len -= obj->unused; len = ascii85_encode_len(len); - for (i = 0; i < len; i++) { - if (ascii85_encode(obj->pages[page][i], out)) - err_puts(m, out); - else - err_puts(m, "z"); - } + for (i = 0; i < len; i++) + err_puts(m, ascii85_encode(obj->pages[page][i], out)); } err_puts(m, "\n"); } diff --git a/include/linux/ascii85.h b/include/linux/ascii85.h new file mode 100644 index 0000000000000..4cc40201273ee --- /dev/null +++ b/include/linux/ascii85.h @@ -0,0 +1,38 @@ +/* + * SPDX-License-Identifier: GPL-2.0 + * + * Copyright (c) 2008 Intel Corporation + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + */ + +#ifndef _ASCII85_H_ +#define _ASCII85_H_ + +#include <linux/kernel.h> + +#define ASCII85_BUFSZ 6 + +static inline long +ascii85_encode_len(long len) +{ + return DIV_ROUND_UP(len, 4); +} + +static inline const char * +ascii85_encode(u32 in, char *out) +{ + int i; + + if (in == 0) + return "z"; + + out[5] = '\0'; + for (i = 5; i--; ) { + out[i] = '!' + in % 85; + in /= 85; + } + + return out; +} + +#endif -- GitLab From cfc57a18a3c5dc95d06db80bddd30015162c57d2 Mon Sep 17 00:00:00 2001 From: Jordan Crouse <jcrouse@codeaurora.org> Date: Tue, 24 Jul 2018 10:33:20 -0600 Subject: [PATCH 1401/1506] drm: drm_printer: Add printer for devcoredump Add a drm printer suitable for use with the read callback for devcoredump or other suitable buffer based output format that isn't otherwise covered by seq_file. v2: Add improved documentation per Daniel Vetter Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/drm_print.c | 74 +++++++++++++++++++++++++++++++++++++ include/drm/drm_print.h | 65 ++++++++++++++++++++++++++++++++ 2 files changed, 139 insertions(+) diff --git a/drivers/gpu/drm/drm_print.c b/drivers/gpu/drm/drm_print.c index b25f98f33f6cb..03d1f98e5ac7c 100644 --- a/drivers/gpu/drm/drm_print.c +++ b/drivers/gpu/drm/drm_print.c @@ -30,6 +30,80 @@ #include <drm/drmP.h> #include <drm/drm_print.h> +void __drm_printfn_coredump(struct drm_printer *p, struct va_format *vaf) +{ + struct drm_print_iterator *iterator = p->arg; + ssize_t len; + + if (!iterator->remain) + return; + + /* Figure out how big the string will be */ + len = snprintf(NULL, 0, "%pV", vaf); + + if (iterator->offset < iterator->start) { + char *buf; + ssize_t copy; + + if (iterator->offset + len <= iterator->start) { + iterator->offset += len; + return; + } + + /* Print the string into a temporary buffer */ + buf = kmalloc(len + 1, + GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY); + if (!buf) + return; + + snprintf(buf, len + 1, "%pV", vaf); + + copy = len - (iterator->start - iterator->offset); + + if (copy > iterator->remain) + copy = iterator->remain; + + /* Copy out the bit of the string that we need */ + memcpy(iterator->data, + buf + (iterator->start - iterator->offset), copy); + + iterator->offset = iterator->start + copy; + iterator->remain -= copy; + + kfree(buf); + } else { + char *buf; + ssize_t pos = iterator->offset - iterator->start; + + if (len < iterator->remain) { + snprintf(((char *) iterator->data) + pos, + iterator->remain, "%pV", vaf); + + iterator->offset += len; + iterator->remain -= len; + + return; + } + + /* Print the string into a temporary buffer */ + buf = kmalloc(len + 1, + GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY); + if (!buf) + return; + + snprintf(buf, len + 1, "%pV", vaf); + + /* Copy out the remaining bits */ + memcpy(iterator->data + pos, buf, iterator->remain); + + iterator->offset += iterator->remain; + iterator->remain = 0; + + kfree(buf); + } +} +EXPORT_SYMBOL(__drm_printfn_coredump); + void __drm_printfn_seq_file(struct drm_printer *p, struct va_format *vaf) { seq_printf(p->arg, "%pV", vaf); diff --git a/include/drm/drm_print.h b/include/drm/drm_print.h index 767c90b654c53..e7570f93a21f8 100644 --- a/include/drm/drm_print.h +++ b/include/drm/drm_print.h @@ -73,6 +73,7 @@ struct drm_printer { const char *prefix; }; +void __drm_printfn_coredump(struct drm_printer *p, struct va_format *vaf); void __drm_printfn_seq_file(struct drm_printer *p, struct va_format *vaf); void __drm_printfn_info(struct drm_printer *p, struct va_format *vaf); void __drm_printfn_debug(struct drm_printer *p, struct va_format *vaf); @@ -104,6 +105,70 @@ drm_vprintf(struct drm_printer *p, const char *fmt, va_list *va) #define drm_printf_indent(printer, indent, fmt, ...) \ drm_printf((printer), "%.*s" fmt, (indent), "\t\t\t\t\tX", ##__VA_ARGS__) +/** + * struct drm_print_iterator - local struct used with drm_printer_coredump + * @data: Pointer to the devcoredump output buffer + * @start: The offset within the buffer to start writing + * @remain: The number of bytes to write for this iteration + */ +struct drm_print_iterator { + void *data; + ssize_t start; + ssize_t remain; + /* private: */ + ssize_t offset; +}; + +/** + * drm_coredump_printer - construct a &drm_printer that can output to a buffer + * from the read function for devcoredump + * @iter: A pointer to a struct drm_print_iterator for the read instance + * + * This wrapper extends drm_printf() to work with a dev_coredumpm() callback + * function. The passed in drm_print_iterator struct contains the buffer + * pointer, size and offset as passed in from devcoredump. + * + * For example:: + * + * void coredump_read(char *buffer, loff_t offset, size_t count, + * void *data, size_t datalen) + * { + * struct drm_print_iterator iter; + * struct drm_printer p; + * + * iter.data = buffer; + * iter.start = offset; + * iter.remain = count; + * + * p = drm_coredump_printer(&iter); + * + * drm_printf(p, "foo=%d\n", foo); + * } + * + * void makecoredump(...) + * { + * ... + * dev_coredumpm(dev, THIS_MODULE, data, 0, GFP_KERNEL, + * coredump_read, ...) + * } + * + * RETURNS: + * The &drm_printer object + */ +static inline struct drm_printer +drm_coredump_printer(struct drm_print_iterator *iter) +{ + struct drm_printer p = { + .printfn = __drm_printfn_coredump, + .arg = iter, + }; + + /* Set the internal offset of the iterator to zero */ + iter->offset = 0; + + return p; +} + /** * drm_seq_file_printer - construct a &drm_printer that outputs to &seq_file * @f: the &struct seq_file to output to -- GitLab From 63f4cc015b66dd265c2fd6e7c94be1b9a3b72267 Mon Sep 17 00:00:00 2001 From: Jordan Crouse <jcrouse@codeaurora.org> Date: Tue, 24 Jul 2018 10:33:21 -0600 Subject: [PATCH 1402/1506] drm: Add drm_puts() to complement drm_printf() Add drm_puts() for a much faster path to print constant strings into a drm_printer object with memcpy and friends. This can have seconds off of really large outputs such as GPU dumps. If the drm_printer object supports a custom puts function then use that otherwise fall back to the slower legacy printf call. v2: Add documentation for drm_puts() per Daniel Vetter Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org> [robclark fix minor htmldocs warning] Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/drm_print.c | 17 +++++++++++++++++ include/drm/drm_print.h | 2 ++ 2 files changed, 19 insertions(+) diff --git a/drivers/gpu/drm/drm_print.c b/drivers/gpu/drm/drm_print.c index 03d1f98e5ac7c..01d4e5583b5d9 100644 --- a/drivers/gpu/drm/drm_print.c +++ b/drivers/gpu/drm/drm_print.c @@ -122,6 +122,23 @@ void __drm_printfn_debug(struct drm_printer *p, struct va_format *vaf) } EXPORT_SYMBOL(__drm_printfn_debug); +/** + * drm_puts - print a const string to a &drm_printer stream + * @p: the &drm printer + * @str: const string + * + * Allow &drm_printer types that have a constant string + * option to use it. + */ +void drm_puts(struct drm_printer *p, const char *str) +{ + if (p->puts) + p->puts(p, str); + else + drm_printf(p, "%s", str); +} +EXPORT_SYMBOL(drm_puts); + /** * drm_printf - print to a &drm_printer stream * @p: the &drm_printer diff --git a/include/drm/drm_print.h b/include/drm/drm_print.h index e7570f93a21f8..f2f42bb87ef25 100644 --- a/include/drm/drm_print.h +++ b/include/drm/drm_print.h @@ -69,6 +69,7 @@ struct drm_printer { /* private: */ void (*printfn)(struct drm_printer *p, struct va_format *vaf); + void (*puts)(struct drm_printer *p, const char *str); void *arg; const char *prefix; }; @@ -80,6 +81,7 @@ void __drm_printfn_debug(struct drm_printer *p, struct va_format *vaf); __printf(2, 3) void drm_printf(struct drm_printer *p, const char *f, ...); +void drm_puts(struct drm_printer *p, const char *str); __printf(2, 0) /** -- GitLab From 4538d7324507fed892a18b79ad72c8501b6e7027 Mon Sep 17 00:00:00 2001 From: Jordan Crouse <jcrouse@codeaurora.org> Date: Tue, 24 Jul 2018 10:33:22 -0600 Subject: [PATCH 1403/1506] drm: Add a -puts() function for the seq_file printer Add a puts() function to use seq_puts() to help speed up up print time for constant strings. Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/drm_print.c | 6 ++++++ include/drm/drm_print.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/drivers/gpu/drm/drm_print.c b/drivers/gpu/drm/drm_print.c index 01d4e5583b5d9..45d7876117239 100644 --- a/drivers/gpu/drm/drm_print.c +++ b/drivers/gpu/drm/drm_print.c @@ -104,6 +104,12 @@ void __drm_printfn_coredump(struct drm_printer *p, struct va_format *vaf) } EXPORT_SYMBOL(__drm_printfn_coredump); +void __drm_puts_seq_file(struct drm_printer *p, const char *str) +{ + seq_puts(p->arg, str); +} +EXPORT_SYMBOL(__drm_puts_seq_file); + void __drm_printfn_seq_file(struct drm_printer *p, struct va_format *vaf) { seq_printf(p->arg, "%pV", vaf); diff --git a/include/drm/drm_print.h b/include/drm/drm_print.h index f2f42bb87ef25..b1432969b627b 100644 --- a/include/drm/drm_print.h +++ b/include/drm/drm_print.h @@ -76,6 +76,7 @@ struct drm_printer { void __drm_printfn_coredump(struct drm_printer *p, struct va_format *vaf); void __drm_printfn_seq_file(struct drm_printer *p, struct va_format *vaf); +void __drm_puts_seq_file(struct drm_printer *p, const char *str); void __drm_printfn_info(struct drm_printer *p, struct va_format *vaf); void __drm_printfn_debug(struct drm_printer *p, struct va_format *vaf); @@ -182,6 +183,7 @@ static inline struct drm_printer drm_seq_file_printer(struct seq_file *f) { struct drm_printer p = { .printfn = __drm_printfn_seq_file, + .puts = __drm_puts_seq_file, .arg = f, }; return p; -- GitLab From 5dc634bdbfd6dd9bdf98bce0d6f64878e1d47b1f Mon Sep 17 00:00:00 2001 From: Jordan Crouse <jcrouse@codeaurora.org> Date: Tue, 24 Jul 2018 10:33:23 -0600 Subject: [PATCH 1404/1506] drm: Add puts callback for the coredump printer Add a puts function for the coredump printer to bypass printf() for constant strings for a speed boost. Reorganize the coredump printf callback to share as much code as possible. v2: Try to reuse code between print and puts as suggested by Chris Wilson Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/drm_print.c | 84 +++++++++++++++++++++---------------- include/drm/drm_print.h | 2 + 2 files changed, 51 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/drm_print.c b/drivers/gpu/drm/drm_print.c index 45d7876117239..0e7fc3e7dfb48 100644 --- a/drivers/gpu/drm/drm_print.c +++ b/drivers/gpu/drm/drm_print.c @@ -30,7 +30,7 @@ #include <drm/drmP.h> #include <drm/drm_print.h> -void __drm_printfn_coredump(struct drm_printer *p, struct va_format *vaf) +void __drm_puts_coredump(struct drm_printer *p, const char *str) { struct drm_print_iterator *iterator = p->arg; ssize_t len; @@ -38,26 +38,16 @@ void __drm_printfn_coredump(struct drm_printer *p, struct va_format *vaf) if (!iterator->remain) return; - /* Figure out how big the string will be */ - len = snprintf(NULL, 0, "%pV", vaf); - if (iterator->offset < iterator->start) { - char *buf; ssize_t copy; + len = strlen(str); + if (iterator->offset + len <= iterator->start) { iterator->offset += len; return; } - /* Print the string into a temporary buffer */ - buf = kmalloc(len + 1, - GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY); - if (!buf) - return; - - snprintf(buf, len + 1, "%pV", vaf); - copy = len - (iterator->start - iterator->offset); if (copy > iterator->remain) @@ -65,42 +55,66 @@ void __drm_printfn_coredump(struct drm_printer *p, struct va_format *vaf) /* Copy out the bit of the string that we need */ memcpy(iterator->data, - buf + (iterator->start - iterator->offset), copy); + str + (iterator->start - iterator->offset), copy); iterator->offset = iterator->start + copy; iterator->remain -= copy; - - kfree(buf); } else { - char *buf; ssize_t pos = iterator->offset - iterator->start; - if (len < iterator->remain) { - snprintf(((char *) iterator->data) + pos, - iterator->remain, "%pV", vaf); + len = min_t(ssize_t, strlen(str), iterator->remain); - iterator->offset += len; - iterator->remain -= len; + memcpy(iterator->data + pos, str, len); - return; - } + iterator->offset += len; + iterator->remain -= len; + } +} +EXPORT_SYMBOL(__drm_puts_coredump); - /* Print the string into a temporary buffer */ - buf = kmalloc(len + 1, - GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY); - if (!buf) - return; +void __drm_printfn_coredump(struct drm_printer *p, struct va_format *vaf) +{ + struct drm_print_iterator *iterator = p->arg; + size_t len; + char *buf; + + if (!iterator->remain) + return; + + /* Figure out how big the string will be */ + len = snprintf(NULL, 0, "%pV", vaf); + + /* This is the easiest path, we've already advanced beyond the offset */ + if (iterator->offset + len <= iterator->start) { + iterator->offset += len; + return; + } - snprintf(buf, len + 1, "%pV", vaf); + /* Then check if we can directly copy into the target buffer */ + if ((iterator->offset >= iterator->start) && (len < iterator->remain)) { + ssize_t pos = iterator->offset - iterator->start; - /* Copy out the remaining bits */ - memcpy(iterator->data + pos, buf, iterator->remain); + snprintf(((char *) iterator->data) + pos, + iterator->remain, "%pV", vaf); - iterator->offset += iterator->remain; - iterator->remain = 0; + iterator->offset += len; + iterator->remain -= len; - kfree(buf); + return; } + + /* + * Finally, hit the slow path and make a temporary string to copy over + * using _drm_puts_coredump + */ + buf = kmalloc(len + 1, GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY); + if (!buf) + return; + + snprintf(buf, len + 1, "%pV", vaf); + __drm_puts_coredump(p, (const char *) buf); + + kfree(buf); } EXPORT_SYMBOL(__drm_printfn_coredump); diff --git a/include/drm/drm_print.h b/include/drm/drm_print.h index b1432969b627b..f3e6eed3e79c6 100644 --- a/include/drm/drm_print.h +++ b/include/drm/drm_print.h @@ -75,6 +75,7 @@ struct drm_printer { }; void __drm_printfn_coredump(struct drm_printer *p, struct va_format *vaf); +void __drm_puts_coredump(struct drm_printer *p, const char *str); void __drm_printfn_seq_file(struct drm_printer *p, struct va_format *vaf); void __drm_puts_seq_file(struct drm_printer *p, const char *str); void __drm_printfn_info(struct drm_printer *p, struct va_format *vaf); @@ -163,6 +164,7 @@ drm_coredump_printer(struct drm_print_iterator *iter) { struct drm_printer p = { .printfn = __drm_printfn_coredump, + .puts = __drm_puts_coredump, .arg = iter, }; -- GitLab From e00e473d9817e03cddbaf181a491c42ae8373482 Mon Sep 17 00:00:00 2001 From: Jordan Crouse <jcrouse@codeaurora.org> Date: Tue, 24 Jul 2018 10:33:24 -0600 Subject: [PATCH 1405/1506] drm/msm/gpu: Capture the state of the GPU Add the infrastructure to capture the current state of the GPU and store it in memory so that it can be dumped later. For now grab the same basic ringbuffer information and registers that are provided by the debugfs 'gpu' node but obviously this should be extended to capture a much larger set of GPU information. Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/msm/adreno/a3xx_gpu.c | 15 +++++++ drivers/gpu/drm/msm/adreno/a4xx_gpu.c | 14 +++++++ drivers/gpu/drm/msm/adreno/a5xx_gpu.c | 22 ++++++++++ drivers/gpu/drm/msm/adreno/adreno_gpu.c | 55 +++++++++++++++++++++++++ drivers/gpu/drm/msm/adreno/adreno_gpu.h | 3 ++ drivers/gpu/drm/msm/msm_gpu.h | 20 +++++++++ 6 files changed, 129 insertions(+) diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c index 3ebbeb3a9b68f..b707b5bca9ab6 100644 --- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c @@ -427,6 +427,19 @@ static void a3xx_dump(struct msm_gpu *gpu) gpu_read(gpu, REG_A3XX_RBBM_STATUS)); adreno_dump(gpu); } + +static struct msm_gpu_state *a3xx_gpu_state_get(struct msm_gpu *gpu) +{ + struct msm_gpu_state *state = adreno_gpu_state_get(gpu); + + if (IS_ERR(state)) + return state; + + state->rbbm_status = gpu_read(gpu, REG_A3XX_RBBM_STATUS); + + return state; +} + /* Register offset defines for A3XX */ static const unsigned int a3xx_register_offsets[REG_ADRENO_REGISTER_MAX] = { REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_BASE, REG_AXXX_CP_RB_BASE), @@ -453,6 +466,8 @@ static const struct adreno_gpu_funcs funcs = { #ifdef CONFIG_DEBUG_FS .show = a3xx_show, #endif + .gpu_state_get = a3xx_gpu_state_get, + .gpu_state_put = adreno_gpu_state_put, }, }; diff --git a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c index 16d3d596638e2..17e97ebc10774 100644 --- a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c @@ -465,6 +465,18 @@ static void a4xx_show(struct msm_gpu *gpu, struct seq_file *m) } #endif +static struct msm_gpu_state *a4xx_gpu_state_get(struct msm_gpu *gpu) +{ + struct msm_gpu_state *state = adreno_gpu_state_get(gpu); + + if (IS_ERR(state)) + return state; + + state->rbbm_status = gpu_read(gpu, REG_A4XX_RBBM_STATUS); + + return state; +} + /* Register offset defines for A4XX, in order of enum adreno_regs */ static const unsigned int a4xx_register_offsets[REG_ADRENO_REGISTER_MAX] = { REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_BASE, REG_A4XX_CP_RB_BASE), @@ -541,6 +553,8 @@ static const struct adreno_gpu_funcs funcs = { #ifdef CONFIG_DEBUG_FS .show = a4xx_show, #endif + .gpu_state_get = a4xx_gpu_state_get, + .gpu_state_put = adreno_gpu_state_put, }, .get_timestamp = a4xx_get_timestamp, }; diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c index d39400e5bc429..9e85e4f7016d0 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c @@ -1195,6 +1195,26 @@ static int a5xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value) return 0; } +static struct msm_gpu_state *a5xx_gpu_state_get(struct msm_gpu *gpu) +{ + struct msm_gpu_state *state; + + /* + * Temporarily disable hardware clock gating before going into + * adreno_show to avoid issues while reading the registers + */ + a5xx_set_hwcg(gpu, false); + + state = adreno_gpu_state_get(gpu); + + if (!IS_ERR(state)) + state->rbbm_status = gpu_read(gpu, REG_A5XX_RBBM_STATUS); + + a5xx_set_hwcg(gpu, true); + + return state; +} + #ifdef CONFIG_DEBUG_FS static void a5xx_show(struct msm_gpu *gpu, struct seq_file *m) { @@ -1244,6 +1264,8 @@ static const struct adreno_gpu_funcs funcs = { .debugfs_init = a5xx_debugfs_init, #endif .gpu_busy = a5xx_gpu_busy, + .gpu_state_get = a5xx_gpu_state_get, + .gpu_state_put = adreno_gpu_state_put, }, .get_timestamp = a5xx_get_timestamp, }; diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index bcbf9f2a29f9c..4286a539f40aa 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -368,6 +368,61 @@ bool adreno_idle(struct msm_gpu *gpu, struct msm_ringbuffer *ring) return false; } +struct msm_gpu_state *adreno_gpu_state_get(struct msm_gpu *gpu) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct msm_gpu_state *state; + int i, count = 0; + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return ERR_PTR(-ENOMEM); + + do_gettimeofday(&state->time); + + for (i = 0; i < gpu->nr_rings; i++) { + state->ring[i].fence = gpu->rb[i]->memptrs->fence; + state->ring[i].iova = gpu->rb[i]->iova; + state->ring[i].seqno = gpu->rb[i]->seqno; + state->ring[i].rptr = get_rptr(adreno_gpu, gpu->rb[i]); + state->ring[i].wptr = get_wptr(gpu->rb[i]); + } + + /* Count the number of registers */ + for (i = 0; adreno_gpu->registers[i] != ~0; i += 2) + count += adreno_gpu->registers[i + 1] - + adreno_gpu->registers[i] + 1; + + state->registers = kcalloc(count * 2, sizeof(u32), GFP_KERNEL); + if (state->registers) { + int pos = 0; + + for (i = 0; adreno_gpu->registers[i] != ~0; i += 2) { + u32 start = adreno_gpu->registers[i]; + u32 end = adreno_gpu->registers[i + 1]; + u32 addr; + + for (addr = start; addr <= end; addr++) { + state->registers[pos++] = addr; + state->registers[pos++] = gpu_read(gpu, addr); + } + } + + state->nr_registers = count; + } + + return state; +} + +void adreno_gpu_state_put(struct msm_gpu_state *state) +{ + if (IS_ERR_OR_NULL(state)) + return; + + kfree(state->registers); + kfree(state); +} + #ifdef CONFIG_DEBUG_FS void adreno_show(struct msm_gpu *gpu, struct seq_file *m) { diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h index bc9ec27e9ed85..734e31a9631fc 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h @@ -229,6 +229,9 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, void adreno_gpu_cleanup(struct adreno_gpu *gpu); +struct msm_gpu_state *adreno_gpu_state_get(struct msm_gpu *gpu); +void adreno_gpu_state_put(struct msm_gpu_state *state); + /* ringbuffer helpers (the parts that are adreno specific) */ static inline void diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index b8241179175a2..de71cc04ecf34 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -27,6 +27,7 @@ struct msm_gem_submit; struct msm_gpu_perfcntr; +struct msm_gpu_state; struct msm_gpu_config { const char *ioname; @@ -69,6 +70,8 @@ struct msm_gpu_funcs { int (*debugfs_init)(struct msm_gpu *gpu, struct drm_minor *minor); #endif int (*gpu_busy)(struct msm_gpu *gpu, uint64_t *value); + struct msm_gpu_state *(*gpu_state_get)(struct msm_gpu *gpu); + void (*gpu_state_put)(struct msm_gpu_state *state); }; struct msm_gpu { @@ -175,6 +178,23 @@ struct msm_gpu_submitqueue { struct kref ref; }; +struct msm_gpu_state { + struct timeval time; + + struct { + u64 iova; + u32 fence; + u32 seqno; + u32 rptr; + u32 wptr; + } ring[MSM_GPU_MAX_RINGS]; + + int nr_registers; + u32 *registers; + + u32 rbbm_status; +}; + static inline void gpu_write(struct msm_gpu *gpu, u32 reg, u32 data) { msm_writel(data, gpu->mmio + (reg << 2)); -- GitLab From 4f776f4511c7f7b6576dfc38c609b168b9188d72 Mon Sep 17 00:00:00 2001 From: Jordan Crouse <jcrouse@codeaurora.org> Date: Tue, 24 Jul 2018 10:33:25 -0600 Subject: [PATCH 1406/1506] drm/msm/gpu: Convert the GPU show function to use the GPU state Convert the existing GPU show function to use the GPU state to dump the information rather than reading it directly from the hardware. This will require an additional step to capture the state before dumping it for the existing nodes but it will greatly facilitate reusing the same code for dumping a previously captured state from a GPU hang. Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/msm/adreno/a3xx_gpu.c | 11 +-- drivers/gpu/drm/msm/adreno/a4xx_gpu.c | 12 +--- drivers/gpu/drm/msm/adreno/a5xx_gpu.c | 18 +---- drivers/gpu/drm/msm/adreno/adreno_gpu.c | 30 ++++---- drivers/gpu/drm/msm/adreno/adreno_gpu.h | 3 +- drivers/gpu/drm/msm/msm_debugfs.c | 92 ++++++++++++++++++++++--- drivers/gpu/drm/msm/msm_gpu.h | 3 +- 7 files changed, 104 insertions(+), 65 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c index b707b5bca9ab6..4cffec2b6adcc 100644 --- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c @@ -411,15 +411,6 @@ static const unsigned int a3xx_registers[] = { ~0 /* sentinel */ }; -#ifdef CONFIG_DEBUG_FS -static void a3xx_show(struct msm_gpu *gpu, struct seq_file *m) -{ - seq_printf(m, "status: %08x\n", - gpu_read(gpu, REG_A3XX_RBBM_STATUS)); - adreno_show(gpu, m); -} -#endif - /* would be nice to not have to duplicate the _show() stuff with printk(): */ static void a3xx_dump(struct msm_gpu *gpu) { @@ -464,7 +455,7 @@ static const struct adreno_gpu_funcs funcs = { .irq = a3xx_irq, .destroy = a3xx_destroy, #ifdef CONFIG_DEBUG_FS - .show = a3xx_show, + .show = adreno_show, #endif .gpu_state_get = a3xx_gpu_state_get, .gpu_state_put = adreno_gpu_state_put, diff --git a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c index 17e97ebc10774..95f08c22e8d7c 100644 --- a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c @@ -455,16 +455,6 @@ static const unsigned int a4xx_registers[] = { ~0 /* sentinel */ }; -#ifdef CONFIG_DEBUG_FS -static void a4xx_show(struct msm_gpu *gpu, struct seq_file *m) -{ - seq_printf(m, "status: %08x\n", - gpu_read(gpu, REG_A4XX_RBBM_STATUS)); - adreno_show(gpu, m); - -} -#endif - static struct msm_gpu_state *a4xx_gpu_state_get(struct msm_gpu *gpu) { struct msm_gpu_state *state = adreno_gpu_state_get(gpu); @@ -551,7 +541,7 @@ static const struct adreno_gpu_funcs funcs = { .irq = a4xx_irq, .destroy = a4xx_destroy, #ifdef CONFIG_DEBUG_FS - .show = a4xx_show, + .show = adreno_show, #endif .gpu_state_get = a4xx_gpu_state_get, .gpu_state_put = adreno_gpu_state_put, diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c index 9e85e4f7016d0..5f1aab3c1cb11 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c @@ -1215,22 +1215,6 @@ static struct msm_gpu_state *a5xx_gpu_state_get(struct msm_gpu *gpu) return state; } -#ifdef CONFIG_DEBUG_FS -static void a5xx_show(struct msm_gpu *gpu, struct seq_file *m) -{ - seq_printf(m, "status: %08x\n", - gpu_read(gpu, REG_A5XX_RBBM_STATUS)); - - /* - * Temporarily disable hardware clock gating before going into - * adreno_show to avoid issues while reading the registers - */ - a5xx_set_hwcg(gpu, false); - adreno_show(gpu, m); - a5xx_set_hwcg(gpu, true); -} -#endif - static struct msm_ringbuffer *a5xx_active_ring(struct msm_gpu *gpu) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); @@ -1260,7 +1244,7 @@ static const struct adreno_gpu_funcs funcs = { .irq = a5xx_irq, .destroy = a5xx_destroy, #ifdef CONFIG_DEBUG_FS - .show = a5xx_show, + .show = adreno_show, .debugfs_init = a5xx_debugfs_init, #endif .gpu_busy = a5xx_gpu_busy, diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index 4286a539f40aa..42828253ede5a 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -424,38 +424,34 @@ void adreno_gpu_state_put(struct msm_gpu_state *state) } #ifdef CONFIG_DEBUG_FS -void adreno_show(struct msm_gpu *gpu, struct seq_file *m) +void adreno_show(struct msm_gpu *gpu, struct msm_gpu_state *state, + struct seq_file *m) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); int i; + if (IS_ERR_OR_NULL(state)) + return; + + seq_printf(m, "status: %08x\n", state->rbbm_status); seq_printf(m, "revision: %d (%d.%d.%d.%d)\n", adreno_gpu->info->revn, adreno_gpu->rev.core, adreno_gpu->rev.major, adreno_gpu->rev.minor, adreno_gpu->rev.patchid); for (i = 0; i < gpu->nr_rings; i++) { - struct msm_ringbuffer *ring = gpu->rb[i]; - seq_printf(m, "rb %d: fence: %d/%d\n", i, - ring->memptrs->fence, ring->seqno); + state->ring[i].fence, state->ring[i].seqno); - seq_printf(m, " rptr: %d\n", - get_rptr(adreno_gpu, ring)); - seq_printf(m, "rb wptr: %d\n", get_wptr(ring)); + seq_printf(m, " rptr: %d\n", state->ring[i].rptr); + seq_printf(m, "rb wptr: %d\n", state->ring[i].wptr); } - /* dump these out in a form that can be parsed by demsm: */ seq_printf(m, "IO:region %s 00000000 00020000\n", gpu->name); - for (i = 0; adreno_gpu->registers[i] != ~0; i += 2) { - uint32_t start = adreno_gpu->registers[i]; - uint32_t end = adreno_gpu->registers[i+1]; - uint32_t addr; - - for (addr = start; addr <= end; addr++) { - uint32_t val = gpu_read(gpu, addr); - seq_printf(m, "IO:R %08x %08x\n", addr<<2, val); - } + for (i = 0; i < state->nr_registers; i++) { + seq_printf(m, "IO:R %08x %08x\n", + state->registers[i * 2] << 2, + state->registers[(i * 2) + 1]); } } #endif diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h index 734e31a9631fc..90b6b59252afa 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h @@ -216,7 +216,8 @@ void adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, void adreno_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring); bool adreno_idle(struct msm_gpu *gpu, struct msm_ringbuffer *ring); #ifdef CONFIG_DEBUG_FS -void adreno_show(struct msm_gpu *gpu, struct seq_file *m); +void adreno_show(struct msm_gpu *gpu, struct msm_gpu_state *state, + struct seq_file *m); #endif void adreno_dump_info(struct msm_gpu *gpu); void adreno_dump(struct msm_gpu *gpu); diff --git a/drivers/gpu/drm/msm/msm_debugfs.c b/drivers/gpu/drm/msm/msm_debugfs.c index 1ff3fda245d18..c3da12179888a 100644 --- a/drivers/gpu/drm/msm/msm_debugfs.c +++ b/drivers/gpu/drm/msm/msm_debugfs.c @@ -16,26 +16,100 @@ */ #ifdef CONFIG_DEBUG_FS +#include <linux/debugfs.h> #include "msm_drv.h" #include "msm_gpu.h" #include "msm_kms.h" #include "msm_debugfs.h" -static int msm_gpu_show(struct drm_device *dev, struct seq_file *m) +struct msm_gpu_show_priv { + struct msm_gpu_state *state; + struct drm_device *dev; +}; + +static int msm_gpu_show(struct seq_file *m, void *arg) +{ + struct msm_gpu_show_priv *show_priv = m->private; + struct msm_drm_private *priv = show_priv->dev->dev_private; + struct msm_gpu *gpu = priv->gpu; + int ret; + + ret = mutex_lock_interruptible(&show_priv->dev->struct_mutex); + if (ret) + return ret; + + seq_printf(m, "%s Status:\n", gpu->name); + gpu->funcs->show(gpu, show_priv->state, m); + + mutex_unlock(&show_priv->dev->struct_mutex); + + return 0; +} + +static int msm_gpu_release(struct inode *inode, struct file *file) +{ + struct seq_file *m = file->private_data; + struct msm_gpu_show_priv *show_priv = m->private; + struct msm_drm_private *priv = show_priv->dev->dev_private; + struct msm_gpu *gpu = priv->gpu; + int ret; + + ret = mutex_lock_interruptible(&show_priv->dev->struct_mutex); + if (ret) + return ret; + + gpu->funcs->gpu_state_put(show_priv->state); + mutex_unlock(&show_priv->dev->struct_mutex); + + kfree(show_priv); + + return single_release(inode, file); +} + +static int msm_gpu_open(struct inode *inode, struct file *file) { + struct drm_device *dev = inode->i_private; struct msm_drm_private *priv = dev->dev_private; struct msm_gpu *gpu = priv->gpu; + struct msm_gpu_show_priv *show_priv; + int ret; - if (gpu) { - seq_printf(m, "%s Status:\n", gpu->name); - pm_runtime_get_sync(&gpu->pdev->dev); - gpu->funcs->show(gpu, m); - pm_runtime_put_sync(&gpu->pdev->dev); + if (!gpu) + return -ENODEV; + + show_priv = kmalloc(sizeof(*show_priv), GFP_KERNEL); + if (!show_priv) + return -ENOMEM; + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + + pm_runtime_get_sync(&gpu->pdev->dev); + show_priv->state = gpu->funcs->gpu_state_get(gpu); + pm_runtime_put_sync(&gpu->pdev->dev); + + mutex_unlock(&dev->struct_mutex); + + if (IS_ERR(show_priv->state)) { + ret = PTR_ERR(show_priv->state); + kfree(show_priv); + return ret; } - return 0; + show_priv->dev = dev; + + return single_open(file, msm_gpu_show, show_priv); } +static const struct file_operations msm_gpu_fops = { + .owner = THIS_MODULE, + .open = msm_gpu_open, + .read = seq_read, + .llseek = seq_lseek, + .release = msm_gpu_release, +}; + static int msm_gem_show(struct drm_device *dev, struct seq_file *m) { struct msm_drm_private *priv = dev->dev_private; @@ -105,7 +179,6 @@ static int show_locked(struct seq_file *m, void *arg) } static struct drm_info_list msm_debugfs_list[] = { - {"gpu", show_locked, 0, msm_gpu_show}, {"gem", show_locked, 0, msm_gem_show}, { "mm", show_locked, 0, msm_mm_show }, { "fb", show_locked, 0, msm_fb_show }, @@ -158,6 +231,9 @@ int msm_debugfs_init(struct drm_minor *minor) return ret; } + debugfs_create_file("gpu", S_IRUSR, minor->debugfs_root, + dev, &msm_gpu_fops); + if (priv->kms->funcs->debugfs_init) { ret = priv->kms->funcs->debugfs_init(priv->kms, minor); if (ret) diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index de71cc04ecf34..d204eca8518ec 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -65,7 +65,8 @@ struct msm_gpu_funcs { void (*destroy)(struct msm_gpu *gpu); #ifdef CONFIG_DEBUG_FS /* show GPU status in debugfs: */ - void (*show)(struct msm_gpu *gpu, struct seq_file *m); + void (*show)(struct msm_gpu *gpu, struct msm_gpu_state *state, + struct seq_file *m); /* for generation specific debugfs: */ int (*debugfs_init)(struct msm_gpu *gpu, struct drm_minor *minor); #endif -- GitLab From 65a3c2748e882da03102369edb6991e1dd88456e Mon Sep 17 00:00:00 2001 From: Jordan Crouse <jcrouse@codeaurora.org> Date: Tue, 24 Jul 2018 10:33:26 -0600 Subject: [PATCH 1407/1506] drm/msm/gpu: Rearrange the code that collects the task during a hang Do a bit of cleanup to prepare for upcoming changes to pass the hanging task comm and cmdline to the crash dump function. v2: Use GFP_ATOMIC while holding the rcu lock per Chris Wilson Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/msm/msm_gpu.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 1c09acfb4028d..03ba8872cc99b 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -314,6 +314,7 @@ static void recover_worker(struct work_struct *work) struct msm_drm_private *priv = dev->dev_private; struct msm_gem_submit *submit; struct msm_ringbuffer *cur_ring = gpu->funcs->active_ring(gpu); + char *comm = NULL, *cmd = NULL; int i; mutex_lock(&dev->struct_mutex); @@ -327,7 +328,7 @@ static void recover_worker(struct work_struct *work) rcu_read_lock(); task = pid_task(submit->pid, PIDTYPE_PID); if (task) { - char *cmd; + comm = kstrdup(task->comm, GFP_ATOMIC); /* * So slightly annoying, in other paths like @@ -340,22 +341,23 @@ static void recover_worker(struct work_struct *work) * about the submit going away. */ mutex_unlock(&dev->struct_mutex); - cmd = kstrdup_quotable_cmdline(task, GFP_KERNEL); + cmd = kstrdup_quotable_cmdline(task, GFP_ATOMIC); mutex_lock(&dev->struct_mutex); + } + rcu_read_unlock(); + if (comm && cmd) { dev_err(dev->dev, "%s: offending task: %s (%s)\n", - gpu->name, task->comm, cmd); + gpu->name, comm, cmd); msm_rd_dump_submit(priv->hangrd, submit, - "offending task: %s (%s)", task->comm, cmd); - - kfree(cmd); - } else { + "offending task: %s (%s)", comm, cmd); + } else msm_rd_dump_submit(priv->hangrd, submit, NULL); - } - rcu_read_unlock(); } + kfree(cmd); + kfree(comm); /* * Update all the rings with the latest and greatest fence.. this -- GitLab From c0fec7f562ec76404ef0f074a89113a703587f3d Mon Sep 17 00:00:00 2001 From: Jordan Crouse <jcrouse@codeaurora.org> Date: Tue, 24 Jul 2018 10:33:27 -0600 Subject: [PATCH 1408/1506] drm/msm/gpu: Capture the GPU state on a GPU hang Capture the GPU state on a GPU hang and store it for later playback via the devcoredump facility. Only one crash state is stored at a time on the assumption that the first hang is usually the most interesting. The existing crash state can be cleared after capturing it and then a new one will be captured on the next hang. Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/msm/Kconfig | 1 + drivers/gpu/drm/msm/adreno/a3xx_gpu.c | 2 +- drivers/gpu/drm/msm/adreno/a4xx_gpu.c | 2 +- drivers/gpu/drm/msm/adreno/a5xx_gpu.c | 4 +- drivers/gpu/drm/msm/adreno/adreno_gpu.c | 36 +++++++---- drivers/gpu/drm/msm/adreno/adreno_gpu.h | 6 +- drivers/gpu/drm/msm/msm_debugfs.c | 5 +- drivers/gpu/drm/msm/msm_gpu.c | 83 ++++++++++++++++++++++++- drivers/gpu/drm/msm/msm_gpu.h | 38 ++++++++++- 9 files changed, 154 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig index 38cbde971b48c..843a9d40c05e3 100644 --- a/drivers/gpu/drm/msm/Kconfig +++ b/drivers/gpu/drm/msm/Kconfig @@ -12,6 +12,7 @@ config DRM_MSM select SHMEM select TMPFS select QCOM_SCM + select WANT_DEV_COREDUMP select SND_SOC_HDMI_CODEC if SND_SOC select SYNC_FILE select PM_OPP diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c index 4cffec2b6adcc..fc502e4121328 100644 --- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c @@ -454,7 +454,7 @@ static const struct adreno_gpu_funcs funcs = { .active_ring = adreno_active_ring, .irq = a3xx_irq, .destroy = a3xx_destroy, -#ifdef CONFIG_DEBUG_FS +#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP) .show = adreno_show, #endif .gpu_state_get = a3xx_gpu_state_get, diff --git a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c index 95f08c22e8d7c..8129cf037db19 100644 --- a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c @@ -540,7 +540,7 @@ static const struct adreno_gpu_funcs funcs = { .active_ring = adreno_active_ring, .irq = a4xx_irq, .destroy = a4xx_destroy, -#ifdef CONFIG_DEBUG_FS +#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP) .show = adreno_show, #endif .gpu_state_get = a4xx_gpu_state_get, diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c index 5f1aab3c1cb11..16074fa6bf1ef 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c @@ -1243,8 +1243,10 @@ static const struct adreno_gpu_funcs funcs = { .active_ring = a5xx_active_ring, .irq = a5xx_irq, .destroy = a5xx_destroy, -#ifdef CONFIG_DEBUG_FS +#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP) .show = adreno_show, +#endif +#if defined(CONFIG_DEBUG_FS) .debugfs_init = a5xx_debugfs_init, #endif .gpu_busy = a5xx_gpu_busy, diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index 42828253ede5a..c72e3afc43a83 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -378,6 +378,8 @@ struct msm_gpu_state *adreno_gpu_state_get(struct msm_gpu *gpu) if (!state) return ERR_PTR(-ENOMEM); + kref_init(&state->ref); + do_gettimeofday(&state->time); for (i = 0; i < gpu->nr_rings; i++) { @@ -414,18 +416,28 @@ struct msm_gpu_state *adreno_gpu_state_get(struct msm_gpu *gpu) return state; } -void adreno_gpu_state_put(struct msm_gpu_state *state) +static void adreno_gpu_state_destroy(struct kref *kref) { - if (IS_ERR_OR_NULL(state)) - return; + struct msm_gpu_state *state = container_of(kref, + struct msm_gpu_state, ref); + kfree(state->comm); + kfree(state->cmd); kfree(state->registers); kfree(state); } -#ifdef CONFIG_DEBUG_FS +int adreno_gpu_state_put(struct msm_gpu_state *state) +{ + if (IS_ERR_OR_NULL(state)) + return 1; + + return kref_put(&state->ref, adreno_gpu_state_destroy); +} + +#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP) void adreno_show(struct msm_gpu *gpu, struct msm_gpu_state *state, - struct seq_file *m) + struct drm_printer *p) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); int i; @@ -433,23 +445,23 @@ void adreno_show(struct msm_gpu *gpu, struct msm_gpu_state *state, if (IS_ERR_OR_NULL(state)) return; - seq_printf(m, "status: %08x\n", state->rbbm_status); - seq_printf(m, "revision: %d (%d.%d.%d.%d)\n", + drm_printf(p, "status: %08x\n", state->rbbm_status); + drm_printf(p, "revision: %d (%d.%d.%d.%d)\n", adreno_gpu->info->revn, adreno_gpu->rev.core, adreno_gpu->rev.major, adreno_gpu->rev.minor, adreno_gpu->rev.patchid); for (i = 0; i < gpu->nr_rings; i++) { - seq_printf(m, "rb %d: fence: %d/%d\n", i, + drm_printf(p, "rb %d: fence: %d/%d\n", i, state->ring[i].fence, state->ring[i].seqno); - seq_printf(m, " rptr: %d\n", state->ring[i].rptr); - seq_printf(m, "rb wptr: %d\n", state->ring[i].wptr); + drm_printf(p, " rptr: %d\n", state->ring[i].rptr); + drm_printf(p, "rb wptr: %d\n", state->ring[i].wptr); } - seq_printf(m, "IO:region %s 00000000 00020000\n", gpu->name); + drm_printf(p, "IO:region %s 00000000 00020000\n", gpu->name); for (i = 0; i < state->nr_registers; i++) { - seq_printf(m, "IO:R %08x %08x\n", + drm_printf(p, "IO:R %08x %08x\n", state->registers[i * 2] << 2, state->registers[(i * 2) + 1]); } diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h index 90b6b59252afa..4a868aaf1a705 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h @@ -215,9 +215,9 @@ void adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, struct msm_file_private *ctx); void adreno_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring); bool adreno_idle(struct msm_gpu *gpu, struct msm_ringbuffer *ring); -#ifdef CONFIG_DEBUG_FS +#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP) void adreno_show(struct msm_gpu *gpu, struct msm_gpu_state *state, - struct seq_file *m); + struct drm_printer *p); #endif void adreno_dump_info(struct msm_gpu *gpu); void adreno_dump(struct msm_gpu *gpu); @@ -231,7 +231,7 @@ void adreno_gpu_cleanup(struct adreno_gpu *gpu); struct msm_gpu_state *adreno_gpu_state_get(struct msm_gpu *gpu); -void adreno_gpu_state_put(struct msm_gpu_state *state); +int adreno_gpu_state_put(struct msm_gpu_state *state); /* ringbuffer helpers (the parts that are adreno specific) */ diff --git a/drivers/gpu/drm/msm/msm_debugfs.c b/drivers/gpu/drm/msm/msm_debugfs.c index c3da12179888a..f0da0d3c8a80f 100644 --- a/drivers/gpu/drm/msm/msm_debugfs.c +++ b/drivers/gpu/drm/msm/msm_debugfs.c @@ -29,6 +29,7 @@ struct msm_gpu_show_priv { static int msm_gpu_show(struct seq_file *m, void *arg) { + struct drm_printer p = drm_seq_file_printer(m); struct msm_gpu_show_priv *show_priv = m->private; struct msm_drm_private *priv = show_priv->dev->dev_private; struct msm_gpu *gpu = priv->gpu; @@ -38,8 +39,8 @@ static int msm_gpu_show(struct seq_file *m, void *arg) if (ret) return ret; - seq_printf(m, "%s Status:\n", gpu->name); - gpu->funcs->show(gpu, show_priv->state, m); + drm_printf(&p, "%s Status:\n", gpu->name); + gpu->funcs->show(gpu, show_priv->state, &p); mutex_unlock(&show_priv->dev->struct_mutex); diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 03ba8872cc99b..5f39549d9a8b9 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -20,10 +20,11 @@ #include "msm_mmu.h" #include "msm_fence.h" +#include <generated/utsrelease.h> #include <linux/string_helpers.h> #include <linux/pm_opp.h> #include <linux/devfreq.h> - +#include <linux/devcoredump.h> /* * Power Management: @@ -273,6 +274,81 @@ int msm_gpu_hw_init(struct msm_gpu *gpu) return ret; } +#ifdef CONFIG_DEV_COREDUMP +static ssize_t msm_gpu_devcoredump_read(char *buffer, loff_t offset, + size_t count, void *data, size_t datalen) +{ + struct msm_gpu *gpu = data; + struct drm_print_iterator iter; + struct drm_printer p; + struct msm_gpu_state *state; + + state = msm_gpu_crashstate_get(gpu); + if (!state) + return 0; + + iter.data = buffer; + iter.offset = 0; + iter.start = offset; + iter.remain = count; + + p = drm_coredump_printer(&iter); + + drm_printf(&p, "---\n"); + drm_printf(&p, "kernel: " UTS_RELEASE "\n"); + drm_printf(&p, "module: " KBUILD_MODNAME "\n"); + drm_printf(&p, "time: %ld.%ld\n", + state->time.tv_sec, state->time.tv_usec); + if (state->comm) + drm_printf(&p, "comm: %s\n", state->comm); + if (state->cmd) + drm_printf(&p, "cmdline: %s\n", state->cmd); + + gpu->funcs->show(gpu, state, &p); + + msm_gpu_crashstate_put(gpu); + + return count - iter.remain; +} + +static void msm_gpu_devcoredump_free(void *data) +{ + struct msm_gpu *gpu = data; + + msm_gpu_crashstate_put(gpu); +} + +static void msm_gpu_crashstate_capture(struct msm_gpu *gpu, char *comm, + char *cmd) +{ + struct msm_gpu_state *state; + + /* Only save one crash state at a time */ + if (gpu->crashstate) + return; + + state = gpu->funcs->gpu_state_get(gpu); + if (IS_ERR_OR_NULL(state)) + return; + + /* Fill in the additional crash state information */ + state->comm = kstrdup(comm, GFP_KERNEL); + state->cmd = kstrdup(cmd, GFP_KERNEL); + + /* Set the active crash state to be dumped on failure */ + gpu->crashstate = state; + + /* FIXME: Release the crashstate if this errors out? */ + dev_coredumpm(gpu->dev->dev, THIS_MODULE, gpu, 0, GFP_KERNEL, + msm_gpu_devcoredump_read, msm_gpu_devcoredump_free); +} +#else +static void msm_gpu_crashstate_capture(struct msm_gpu *gpu, char *comm, + char *cmd) +{ +} +#endif + /* * Hangcheck detection for locked gpu: */ @@ -356,6 +432,11 @@ static void recover_worker(struct work_struct *work) msm_rd_dump_submit(priv->hangrd, submit, NULL); } + /* Record the crash state */ + pm_runtime_get_sync(&gpu->pdev->dev); + msm_gpu_crashstate_capture(gpu, comm, cmd); + pm_runtime_put_sync(&gpu->pdev->dev); + kfree(cmd); kfree(comm); diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index d204eca8518ec..b1cb44922441d 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -66,13 +66,13 @@ struct msm_gpu_funcs { #ifdef CONFIG_DEBUG_FS /* show GPU status in debugfs: */ void (*show)(struct msm_gpu *gpu, struct msm_gpu_state *state, - struct seq_file *m); + struct drm_printer *p); /* for generation specific debugfs: */ int (*debugfs_init)(struct msm_gpu *gpu, struct drm_minor *minor); #endif int (*gpu_busy)(struct msm_gpu *gpu, uint64_t *value); struct msm_gpu_state *(*gpu_state_get)(struct msm_gpu *gpu); - void (*gpu_state_put)(struct msm_gpu_state *state); + int (*gpu_state_put)(struct msm_gpu_state *state); }; struct msm_gpu { @@ -133,6 +133,8 @@ struct msm_gpu { u64 busy_cycles; ktime_t time; } devfreq; + + struct msm_gpu_state *crashstate; }; /* It turns out that all targets use the same ringbuffer size */ @@ -180,6 +182,7 @@ struct msm_gpu_submitqueue { }; struct msm_gpu_state { + struct kref ref; struct timeval time; struct { @@ -194,6 +197,9 @@ struct msm_gpu_state { u32 *registers; u32 rbbm_status; + + char *comm; + char *cmd; }; static inline void gpu_write(struct msm_gpu *gpu, u32 reg, u32 data) @@ -275,4 +281,32 @@ static inline void msm_submitqueue_put(struct msm_gpu_submitqueue *queue) kref_put(&queue->ref, msm_submitqueue_destroy); } +static inline struct msm_gpu_state *msm_gpu_crashstate_get(struct msm_gpu *gpu) +{ + struct msm_gpu_state *state = NULL; + + mutex_lock(&gpu->dev->struct_mutex); + + if (gpu->crashstate) { + kref_get(&gpu->crashstate->ref); + state = gpu->crashstate; + } + + mutex_unlock(&gpu->dev->struct_mutex); + + return state; +} + +static inline void msm_gpu_crashstate_put(struct msm_gpu *gpu) +{ + mutex_lock(&gpu->dev->struct_mutex); + + if (gpu->crashstate) { + if (gpu->funcs->gpu_state_put(gpu->crashstate)) + gpu->crashstate = NULL; + } + + mutex_unlock(&gpu->dev->struct_mutex); +} + #endif /* __MSM_GPU_H__ */ -- GitLab From bcf1d9fa5d03c1e86733411b5dc3a76ba7d75e6e Mon Sep 17 00:00:00 2001 From: Jordan Crouse <jcrouse@codeaurora.org> Date: Tue, 24 Jul 2018 10:33:28 -0600 Subject: [PATCH 1409/1506] drm/msm/adreno: Convert the show/crash file format Convert the format of the 'show' debugfs file and the crash dump to a format resembling YAML. This should be easier to parse and be more flexible for future changes and expansions. v2: Use a standard .rst for the msm crashdump documentation Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- Documentation/gpu/msm-crash-dump.rst | 71 +++++++++++++++++++++++++ drivers/gpu/drm/msm/adreno/adreno_gpu.c | 21 +++++--- 2 files changed, 84 insertions(+), 8 deletions(-) create mode 100644 Documentation/gpu/msm-crash-dump.rst diff --git a/Documentation/gpu/msm-crash-dump.rst b/Documentation/gpu/msm-crash-dump.rst new file mode 100644 index 0000000000000..75ab1d541c037 --- /dev/null +++ b/Documentation/gpu/msm-crash-dump.rst @@ -0,0 +1,71 @@ +===================== +MSM Crash Dump Format +===================== + +Following a GPU hang the MSM driver outputs debugging information via +/sys/kernel/dri/X/show or via devcoredump (/sys/class/devcoredump/dcdX/data). +This document describes how the output is formatted. + +Each entry is in the form key: value. Sections headers will not have a value +and all the contents of a section will be indented two spaces from the header. +Each section might have multiple array entries the start of which is designated +by a (-). + +Mappings +-------- + +kernel + The kernel version that generated the dump (UTS_RELEASE). + +module + The module that generated the crashdump. + +time + The kernel time at crash formated as seconds.microseconds. + +comm + Comm string for the binary that generated the fault. + +cmdline + Command line for the binary that generated the fault. + +revision + ID of the GPU that generated the crash formatted as + core.major.minor.patchlevel separated by dots. + +rbbm-status + The current value of RBBM_STATUS which shows what top level GPU + components are in use at the time of crash. + +ringbuffer + Section containing the contents of each ringbuffer. Each ringbuffer is + identified with an id number. + + id + Ringbuffer ID (0 based index). Each ringbuffer in the section + will have its own unique id. + iova + GPU address of the ringbuffer. + + last-fence + The last fence that was issued on the ringbuffer + + retired-fence + The last fence retired on the ringbuffer. + + rptr + The current read pointer (rptr) for the ringbuffer. + + wptr + The current write pointer (wptr) for the ringbuffer. + +registers + Set of registers values. Each entry is on its own line enclosed + by brackets { }. + + offset + Byte offset of the register from the start of the + GPU memory region. + + value + Hexadecimal value of the register. diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index c72e3afc43a83..c7a998d9dc855 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -445,23 +445,28 @@ void adreno_show(struct msm_gpu *gpu, struct msm_gpu_state *state, if (IS_ERR_OR_NULL(state)) return; - drm_printf(p, "status: %08x\n", state->rbbm_status); drm_printf(p, "revision: %d (%d.%d.%d.%d)\n", adreno_gpu->info->revn, adreno_gpu->rev.core, adreno_gpu->rev.major, adreno_gpu->rev.minor, adreno_gpu->rev.patchid); - for (i = 0; i < gpu->nr_rings; i++) { - drm_printf(p, "rb %d: fence: %d/%d\n", i, - state->ring[i].fence, state->ring[i].seqno); + drm_printf(p, "rbbm-status: 0x%08x\n", state->rbbm_status); + + drm_puts(p, "ringbuffer:\n"); - drm_printf(p, " rptr: %d\n", state->ring[i].rptr); - drm_printf(p, "rb wptr: %d\n", state->ring[i].wptr); + for (i = 0; i < gpu->nr_rings; i++) { + drm_printf(p, " - id: %d\n", i); + drm_printf(p, " iova: 0x%016llx\n", state->ring[i].iova); + drm_printf(p, " last-fence: %d\n", state->ring[i].seqno); + drm_printf(p, " retired-fence: %d\n", state->ring[i].fence); + drm_printf(p, " rptr: %d\n", state->ring[i].rptr); + drm_printf(p, " wptr: %d\n", state->ring[i].wptr); } - drm_printf(p, "IO:region %s 00000000 00020000\n", gpu->name); + drm_puts(p, "registers:\n"); + for (i = 0; i < state->nr_registers; i++) { - drm_printf(p, "IO:R %08x %08x\n", + drm_printf(p, " - { offset: 0x%04x, value: 0x%08x }\n", state->registers[i * 2] << 2, state->registers[(i * 2) + 1]); } -- GitLab From 43a56687d15db09f3cf7b9d53b182bdef86c17c0 Mon Sep 17 00:00:00 2001 From: Jordan Crouse <jcrouse@codeaurora.org> Date: Tue, 24 Jul 2018 10:33:29 -0600 Subject: [PATCH 1410/1506] drm/msm/adreno: Add ringbuffer data to the GPU state Add the contents of each ringbuffer to the GPU state and dump the data in the crash file encoded with ascii85. To save space only the used portions of the ringbuffer are dumped. Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- Documentation/gpu/msm-crash-dump.rst | 7 +++++ drivers/gpu/drm/msm/adreno/adreno_gpu.c | 39 +++++++++++++++++++++++++ drivers/gpu/drm/msm/msm_gpu.h | 2 ++ 3 files changed, 48 insertions(+) diff --git a/Documentation/gpu/msm-crash-dump.rst b/Documentation/gpu/msm-crash-dump.rst index 75ab1d541c037..35e87004e006e 100644 --- a/Documentation/gpu/msm-crash-dump.rst +++ b/Documentation/gpu/msm-crash-dump.rst @@ -59,6 +59,13 @@ ringbuffer wptr The current write pointer (wptr) for the ringbuffer. + size + Maximum size of the ringbuffer programmed in the hardware. + + data + The contents of the ring encoded as ascii85. Only the used + portions of the ring will be printed. + registers Set of registers values. Each entry is on its own line enclosed by brackets { }. diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index c7a998d9dc855..808d4fc9c4a15 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -17,6 +17,7 @@ * this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <linux/ascii85.h> #include <linux/pm_opp.h> #include "adreno_gpu.h" #include "msm_gem.h" @@ -383,11 +384,29 @@ struct msm_gpu_state *adreno_gpu_state_get(struct msm_gpu *gpu) do_gettimeofday(&state->time); for (i = 0; i < gpu->nr_rings; i++) { + int size = 0, j; + state->ring[i].fence = gpu->rb[i]->memptrs->fence; state->ring[i].iova = gpu->rb[i]->iova; state->ring[i].seqno = gpu->rb[i]->seqno; state->ring[i].rptr = get_rptr(adreno_gpu, gpu->rb[i]); state->ring[i].wptr = get_wptr(gpu->rb[i]); + + /* Copy at least 'wptr' dwords of the data */ + size = state->ring[i].wptr; + + /* After wptr find the last non zero dword to save space */ + for (j = state->ring[i].wptr; j < MSM_GPU_RINGBUFFER_SZ >> 2; j++) + if (gpu->rb[i]->start[j]) + size = j + 1; + + if (size) { + state->ring[i].data = kmalloc(size << 2, GFP_KERNEL); + if (state->ring[i].data) { + memcpy(state->ring[i].data, gpu->rb[i]->start, size << 2); + state->ring[i].data_size = size << 2; + } + } } /* Count the number of registers */ @@ -418,9 +437,13 @@ struct msm_gpu_state *adreno_gpu_state_get(struct msm_gpu *gpu) static void adreno_gpu_state_destroy(struct kref *kref) { + int i; struct msm_gpu_state *state = container_of(kref, struct msm_gpu_state, ref); + for (i = 0; i < ARRAY_SIZE(state->ring); i++) + kfree(state->ring[i].data); + kfree(state->comm); kfree(state->cmd); kfree(state->registers); @@ -461,6 +484,22 @@ void adreno_show(struct msm_gpu *gpu, struct msm_gpu_state *state, drm_printf(p, " retired-fence: %d\n", state->ring[i].fence); drm_printf(p, " rptr: %d\n", state->ring[i].rptr); drm_printf(p, " wptr: %d\n", state->ring[i].wptr); + drm_printf(p, " size: %d\n", MSM_GPU_RINGBUFFER_SZ); + + if (state->ring[i].data && state->ring[i].data_size) { + u32 *ptr = (u32 *) state->ring[i].data; + char out[ASCII85_BUFSZ]; + long len = ascii85_encode_len(state->ring[i].data_size); + int j; + + drm_printf(p, " data: !!ascii85 |\n"); + drm_printf(p, " "); + + for (j = 0; j < len; j++) + drm_printf(p, ascii85_encode(ptr[j], out)); + + drm_printf(p, "\n"); + } } drm_puts(p, "registers:\n"); diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index b1cb44922441d..878090b57e902 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -191,6 +191,8 @@ struct msm_gpu_state { u32 seqno; u32 rptr; u32 wptr; + void *data; + int data_size; } ring[MSM_GPU_MAX_RINGS]; int nr_registers; -- GitLab From 50f8d21863b9b774b198e631d2b14878f6a54b5b Mon Sep 17 00:00:00 2001 From: Jordan Crouse <jcrouse@codeaurora.org> Date: Tue, 24 Jul 2018 10:33:30 -0600 Subject: [PATCH 1411/1506] drm/msm/adreno: Add a5xx specific registers for the GPU state HLSQ, SP and TP registers are only accessible from a special aperture and to make matters worse the aperture is blocked from the CPU on targets that can support secure rendering. Luckily the GPU hardware has its own purpose built register dumper that can access the registers from the aperture. Add a5xx specific code to program the crashdumper and retrieve the wayward registers and dump them for the crash state. Also, remove a block of registers the regular CPU accessible list that aren't useful for debug which helps reduce the size of the crash state file by a goodly amount. Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- Documentation/gpu/msm-crash-dump.rst | 4 + drivers/gpu/drm/msm/adreno/a3xx_gpu.c | 8 +- drivers/gpu/drm/msm/adreno/a4xx_gpu.c | 8 +- drivers/gpu/drm/msm/adreno/a5xx_gpu.c | 236 ++++++++++++++++++++++-- drivers/gpu/drm/msm/adreno/adreno_gpu.c | 23 +-- drivers/gpu/drm/msm/adreno/adreno_gpu.h | 4 +- 6 files changed, 252 insertions(+), 31 deletions(-) diff --git a/Documentation/gpu/msm-crash-dump.rst b/Documentation/gpu/msm-crash-dump.rst index 35e87004e006e..7943f43f70d6c 100644 --- a/Documentation/gpu/msm-crash-dump.rst +++ b/Documentation/gpu/msm-crash-dump.rst @@ -76,3 +76,7 @@ registers value Hexadecimal value of the register. + +registers-hlsq + (5xx only) Register values from the HLSQ aperture. + Same format as the register section. diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c index fc502e4121328..669c2d4b070de 100644 --- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c @@ -421,10 +421,12 @@ static void a3xx_dump(struct msm_gpu *gpu) static struct msm_gpu_state *a3xx_gpu_state_get(struct msm_gpu *gpu) { - struct msm_gpu_state *state = adreno_gpu_state_get(gpu); + struct msm_gpu_state *state = kzalloc(sizeof(*state), GFP_KERNEL); - if (IS_ERR(state)) - return state; + if (!state) + return ERR_PTR(-ENOMEM); + + adreno_gpu_state_get(gpu, state); state->rbbm_status = gpu_read(gpu, REG_A3XX_RBBM_STATUS); diff --git a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c index 8129cf037db19..7c4e6dc1ed599 100644 --- a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c @@ -457,10 +457,12 @@ static const unsigned int a4xx_registers[] = { static struct msm_gpu_state *a4xx_gpu_state_get(struct msm_gpu *gpu) { - struct msm_gpu_state *state = adreno_gpu_state_get(gpu); + struct msm_gpu_state *state = kzalloc(sizeof(*state), GFP_KERNEL); - if (IS_ERR(state)) - return state; + if (!state) + return ERR_PTR(-ENOMEM); + + adreno_gpu_state_get(gpu, state); state->rbbm_status = gpu_read(gpu, REG_A4XX_RBBM_STATUS); diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c index 16074fa6bf1ef..bd84f71d27d85 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c @@ -19,6 +19,7 @@ #include <linux/soc/qcom/mdt_loader.h> #include <linux/pm_opp.h> #include <linux/nvmem-consumer.h> +#include <linux/iopoll.h> #include "msm_gem.h" #include "msm_mmu.h" #include "a5xx_gpu.h" @@ -1123,8 +1124,9 @@ static const u32 a5xx_registers[] = { 0xE800, 0xE806, 0xE810, 0xE89A, 0xE8A0, 0xE8A4, 0xE8AA, 0xE8EB, 0xE900, 0xE905, 0xEB80, 0xEB8F, 0xEBB0, 0xEBB0, 0xEC00, 0xEC05, 0xEC08, 0xECE9, 0xECF0, 0xECF0, 0xEA80, 0xEA80, 0xEA82, 0xEAA3, - 0xEAA5, 0xEAC2, 0xA800, 0xA8FF, 0xAC60, 0xAC60, 0xB000, 0xB97F, - 0xB9A0, 0xB9BF, ~0 + 0xEAA5, 0xEAC2, 0xA800, 0xA800, 0xA820, 0xA828, 0xA840, 0xA87D, + 0XA880, 0xA88D, 0xA890, 0xA8A3, 0xA8D0, 0xA8D8, 0xA8E0, 0xA8F5, + 0xAC60, 0xAC60, ~0, }; static void a5xx_dump(struct msm_gpu *gpu) @@ -1195,25 +1197,233 @@ static int a5xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value) return 0; } +struct a5xx_crashdumper { + void *ptr; + struct drm_gem_object *bo; + u64 iova; +}; + +struct a5xx_gpu_state { + struct msm_gpu_state base; + u32 *hlsqregs; +}; + +#define gpu_poll_timeout(gpu, addr, val, cond, interval, timeout) \ + readl_poll_timeout((gpu)->mmio + ((addr) << 2), val, cond, \ + interval, timeout) + +static int a5xx_crashdumper_init(struct msm_gpu *gpu, + struct a5xx_crashdumper *dumper) +{ + dumper->ptr = msm_gem_kernel_new_locked(gpu->dev, + SZ_1M, MSM_BO_UNCACHED, gpu->aspace, + &dumper->bo, &dumper->iova); + + if (IS_ERR(dumper->ptr)) + return PTR_ERR(dumper->ptr); + + return 0; +} + +static void a5xx_crashdumper_free(struct msm_gpu *gpu, + struct a5xx_crashdumper *dumper) +{ + msm_gem_put_iova(dumper->bo, gpu->aspace); + msm_gem_put_vaddr(dumper->bo); + + drm_gem_object_unreference(dumper->bo); +} + +static int a5xx_crashdumper_run(struct msm_gpu *gpu, + struct a5xx_crashdumper *dumper) +{ + u32 val; + + if (IS_ERR_OR_NULL(dumper->ptr)) + return -EINVAL; + + gpu_write64(gpu, REG_A5XX_CP_CRASH_SCRIPT_BASE_LO, + REG_A5XX_CP_CRASH_SCRIPT_BASE_HI, dumper->iova); + + gpu_write(gpu, REG_A5XX_CP_CRASH_DUMP_CNTL, 1); + + return gpu_poll_timeout(gpu, REG_A5XX_CP_CRASH_DUMP_CNTL, val, + val & 0x04, 100, 10000); +} + +/* + * These are a list of the registers that need to be read through the HLSQ + * aperture through the crashdumper. These are not nominally accessible from + * the CPU on a secure platform. + */ +static const struct { + u32 type; + u32 regoffset; + u32 count; +} a5xx_hlsq_aperture_regs[] = { + { 0x35, 0xe00, 0x32 }, /* HSLQ non-context */ + { 0x31, 0x2080, 0x1 }, /* HLSQ 2D context 0 */ + { 0x33, 0x2480, 0x1 }, /* HLSQ 2D context 1 */ + { 0x32, 0xe780, 0x62 }, /* HLSQ 3D context 0 */ + { 0x34, 0xef80, 0x62 }, /* HLSQ 3D context 1 */ + { 0x3f, 0x0ec0, 0x40 }, /* SP non-context */ + { 0x3d, 0x2040, 0x1 }, /* SP 2D context 0 */ + { 0x3b, 0x2440, 0x1 }, /* SP 2D context 1 */ + { 0x3e, 0xe580, 0x170 }, /* SP 3D context 0 */ + { 0x3c, 0xed80, 0x170 }, /* SP 3D context 1 */ + { 0x3a, 0x0f00, 0x1c }, /* TP non-context */ + { 0x38, 0x2000, 0xa }, /* TP 2D context 0 */ + { 0x36, 0x2400, 0xa }, /* TP 2D context 1 */ + { 0x39, 0xe700, 0x80 }, /* TP 3D context 0 */ + { 0x37, 0xef00, 0x80 }, /* TP 3D context 1 */ +}; + +static void a5xx_gpu_state_get_hlsq_regs(struct msm_gpu *gpu, + struct a5xx_gpu_state *a5xx_state) +{ + struct a5xx_crashdumper dumper = { 0 }; + u32 offset, count = 0; + u64 *ptr; + int i; + + if (a5xx_crashdumper_init(gpu, &dumper)) + return; + + /* The script will be written at offset 0 */ + ptr = dumper.ptr; + + /* Start writing the data at offset 256k */ + offset = dumper.iova + (256 * SZ_1K); + + /* Count how many additional registers to get from the HLSQ aperture */ + for (i = 0; i < ARRAY_SIZE(a5xx_hlsq_aperture_regs); i++) + count += a5xx_hlsq_aperture_regs[i].count; + + a5xx_state->hlsqregs = kcalloc(count, sizeof(u32), GFP_KERNEL); + if (!a5xx_state->hlsqregs) + return; + + /* Build the crashdump script */ + for (i = 0; i < ARRAY_SIZE(a5xx_hlsq_aperture_regs); i++) { + u32 type = a5xx_hlsq_aperture_regs[i].type; + u32 c = a5xx_hlsq_aperture_regs[i].count; + + /* Write the register to select the desired bank */ + *ptr++ = ((u64) type << 8); + *ptr++ = (((u64) REG_A5XX_HLSQ_DBG_READ_SEL) << 44) | + (1 << 21) | 1; + + *ptr++ = offset; + *ptr++ = (((u64) REG_A5XX_HLSQ_DBG_AHB_READ_APERTURE) << 44) + | c; + + offset += c * sizeof(u32); + } + + /* Write two zeros to close off the script */ + *ptr++ = 0; + *ptr++ = 0; + + if (a5xx_crashdumper_run(gpu, &dumper)) { + kfree(a5xx_state->hlsqregs); + a5xx_crashdumper_free(gpu, &dumper); + return; + } + + /* Copy the data from the crashdumper to the state */ + memcpy(a5xx_state->hlsqregs, dumper.ptr + (256 * SZ_1K), + count * sizeof(u32)); + + a5xx_crashdumper_free(gpu, &dumper); +} + static struct msm_gpu_state *a5xx_gpu_state_get(struct msm_gpu *gpu) { - struct msm_gpu_state *state; + struct a5xx_gpu_state *a5xx_state = kzalloc(sizeof(*a5xx_state), + GFP_KERNEL); - /* - * Temporarily disable hardware clock gating before going into - * adreno_show to avoid issues while reading the registers - */ + if (!a5xx_state) + return ERR_PTR(-ENOMEM); + + /* Temporarily disable hardware clock gating before reading the hw */ a5xx_set_hwcg(gpu, false); - state = adreno_gpu_state_get(gpu); + /* First get the generic state from the adreno core */ + adreno_gpu_state_get(gpu, &(a5xx_state->base)); + + a5xx_state->base.rbbm_status = gpu_read(gpu, REG_A5XX_RBBM_STATUS); - if (!IS_ERR(state)) - state->rbbm_status = gpu_read(gpu, REG_A5XX_RBBM_STATUS); + /* Get the HLSQ regs with the help of the crashdumper */ + a5xx_gpu_state_get_hlsq_regs(gpu, a5xx_state); a5xx_set_hwcg(gpu, true); - return state; + return &a5xx_state->base; +} + +static void a5xx_gpu_state_destroy(struct kref *kref) +{ + struct msm_gpu_state *state = container_of(kref, + struct msm_gpu_state, ref); + struct a5xx_gpu_state *a5xx_state = container_of(state, + struct a5xx_gpu_state, base); + + kfree(a5xx_state->hlsqregs); + + adreno_gpu_state_destroy(state); + kfree(a5xx_state); +} + +int a5xx_gpu_state_put(struct msm_gpu_state *state) +{ + if (IS_ERR_OR_NULL(state)) + return 1; + + return kref_put(&state->ref, a5xx_gpu_state_destroy); +} + + +#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP) +void a5xx_show(struct msm_gpu *gpu, struct msm_gpu_state *state, + struct drm_printer *p) +{ + int i, j; + u32 pos = 0; + struct a5xx_gpu_state *a5xx_state = container_of(state, + struct a5xx_gpu_state, base); + + if (IS_ERR_OR_NULL(state)) + return; + + adreno_show(gpu, state, p); + + /* Dump the additional a5xx HLSQ registers */ + if (!a5xx_state->hlsqregs) + return; + + drm_printf(p, "registers-hlsq:\n"); + + for (i = 0; i < ARRAY_SIZE(a5xx_hlsq_aperture_regs); i++) { + u32 o = a5xx_hlsq_aperture_regs[i].regoffset; + u32 c = a5xx_hlsq_aperture_regs[i].count; + + for (j = 0; j < c; j++, pos++, o++) { + /* + * To keep the crashdump simple we pull the entire range + * for each register type but not all of the registers + * in the range are valid. Fortunately invalid registers + * stick out like a sore thumb with a value of + * 0xdeadbeef + */ + if (a5xx_state->hlsqregs[pos] == 0xdeadbeef) + continue; + + drm_printf(p, " - { offset: 0x%04x, value: 0x%08x }\n", + o << 2, a5xx_state->hlsqregs[pos]); + } + } } +#endif static struct msm_ringbuffer *a5xx_active_ring(struct msm_gpu *gpu) { @@ -1244,14 +1454,14 @@ static const struct adreno_gpu_funcs funcs = { .irq = a5xx_irq, .destroy = a5xx_destroy, #if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP) - .show = adreno_show, + .show = a5xx_show, #endif #if defined(CONFIG_DEBUG_FS) .debugfs_init = a5xx_debugfs_init, #endif .gpu_busy = a5xx_gpu_busy, .gpu_state_get = a5xx_gpu_state_get, - .gpu_state_put = adreno_gpu_state_put, + .gpu_state_put = a5xx_gpu_state_put, }, .get_timestamp = a5xx_get_timestamp, }; diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index 808d4fc9c4a15..cd418dab7a623 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -369,16 +369,11 @@ bool adreno_idle(struct msm_gpu *gpu, struct msm_ringbuffer *ring) return false; } -struct msm_gpu_state *adreno_gpu_state_get(struct msm_gpu *gpu) +int adreno_gpu_state_get(struct msm_gpu *gpu, struct msm_gpu_state *state) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); - struct msm_gpu_state *state; int i, count = 0; - state = kzalloc(sizeof(*state), GFP_KERNEL); - if (!state) - return ERR_PTR(-ENOMEM); - kref_init(&state->ref); do_gettimeofday(&state->time); @@ -432,14 +427,12 @@ struct msm_gpu_state *adreno_gpu_state_get(struct msm_gpu *gpu) state->nr_registers = count; } - return state; + return 0; } -static void adreno_gpu_state_destroy(struct kref *kref) +void adreno_gpu_state_destroy(struct msm_gpu_state *state) { int i; - struct msm_gpu_state *state = container_of(kref, - struct msm_gpu_state, ref); for (i = 0; i < ARRAY_SIZE(state->ring); i++) kfree(state->ring[i].data); @@ -447,6 +440,14 @@ static void adreno_gpu_state_destroy(struct kref *kref) kfree(state->comm); kfree(state->cmd); kfree(state->registers); +} + +static void adreno_gpu_state_kref_destroy(struct kref *kref) +{ + struct msm_gpu_state *state = container_of(kref, + struct msm_gpu_state, ref); + + adreno_gpu_state_destroy(state); kfree(state); } @@ -455,7 +456,7 @@ int adreno_gpu_state_put(struct msm_gpu_state *state) if (IS_ERR_OR_NULL(state)) return 1; - return kref_put(&state->ref, adreno_gpu_state_destroy); + return kref_put(&state->ref, adreno_gpu_state_kref_destroy); } #if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP) diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h index 4a868aaf1a705..4406776597fdb 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h @@ -230,7 +230,9 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, void adreno_gpu_cleanup(struct adreno_gpu *gpu); -struct msm_gpu_state *adreno_gpu_state_get(struct msm_gpu *gpu); +void adreno_gpu_state_destroy(struct msm_gpu_state *state); + +int adreno_gpu_state_get(struct msm_gpu *gpu, struct msm_gpu_state *state); int adreno_gpu_state_put(struct msm_gpu_state *state); /* ringbuffer helpers (the parts that are adreno specific) */ -- GitLab From cdb95931dea32981545e34a3b1dfc9e172425d95 Mon Sep 17 00:00:00 2001 From: Jordan Crouse <jcrouse@codeaurora.org> Date: Tue, 24 Jul 2018 10:33:31 -0600 Subject: [PATCH 1412/1506] drm/msm/gpu: Add the buffer objects from the submit to the crash dump For hangs, dump copy out the contents of the buffer objects attached to the guilty submission and print them in the crash dump report. Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- Documentation/gpu/msm-crash-dump.rst | 14 ++++++ drivers/gpu/drm/msm/adreno/adreno_gpu.c | 58 ++++++++++++++++++++----- drivers/gpu/drm/msm/msm_gpu.c | 48 ++++++++++++++++++-- drivers/gpu/drm/msm/msm_gpu.h | 9 ++++ 4 files changed, 116 insertions(+), 13 deletions(-) diff --git a/Documentation/gpu/msm-crash-dump.rst b/Documentation/gpu/msm-crash-dump.rst index 7943f43f70d6c..757cd257e0d88 100644 --- a/Documentation/gpu/msm-crash-dump.rst +++ b/Documentation/gpu/msm-crash-dump.rst @@ -66,6 +66,20 @@ ringbuffer The contents of the ring encoded as ascii85. Only the used portions of the ring will be printed. +bo + List of buffers from the hanging submission if available. + Each buffer object will have a uinque iova. + + iova + GPU address of the buffer object. + + size + Allocated size of the buffer object. + + data + The contents of the buffer object encoded with ascii85. Only + Trailing zeros at the end of the buffer will be skipped. + registers Set of registers values. Each entry is on its own line enclosed by brackets { }. diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index cd418dab7a623..08d3c618b7de9 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -437,6 +437,10 @@ void adreno_gpu_state_destroy(struct msm_gpu_state *state) for (i = 0; i < ARRAY_SIZE(state->ring); i++) kfree(state->ring[i].data); + for (i = 0; state->bos && i < state->nr_bos; i++) + kvfree(state->bos[i].data); + + kfree(state->bos); kfree(state->comm); kfree(state->cmd); kfree(state->registers); @@ -460,6 +464,39 @@ int adreno_gpu_state_put(struct msm_gpu_state *state) } #if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP) + +static void adreno_show_object(struct drm_printer *p, u32 *ptr, int len) +{ + char out[ASCII85_BUFSZ]; + long l, datalen, i; + + if (!ptr || !len) + return; + + /* + * Only dump the non-zero part of the buffer - rarely will any data + * completely fill the entire allocated size of the buffer + */ + for (datalen = 0, i = 0; i < len >> 2; i++) { + if (ptr[i]) + datalen = (i << 2) + 1; + } + + /* Skip printing the object if it is empty */ + if (datalen == 0) + return; + + l = ascii85_encode_len(datalen); + + drm_puts(p, " data: !!ascii85 |\n"); + drm_puts(p, " "); + + for (i = 0; i < l; i++) + drm_puts(p, ascii85_encode(ptr[i], out)); + + drm_puts(p, "\n"); +} + void adreno_show(struct msm_gpu *gpu, struct msm_gpu_state *state, struct drm_printer *p) { @@ -487,19 +524,20 @@ void adreno_show(struct msm_gpu *gpu, struct msm_gpu_state *state, drm_printf(p, " wptr: %d\n", state->ring[i].wptr); drm_printf(p, " size: %d\n", MSM_GPU_RINGBUFFER_SZ); - if (state->ring[i].data && state->ring[i].data_size) { - u32 *ptr = (u32 *) state->ring[i].data; - char out[ASCII85_BUFSZ]; - long len = ascii85_encode_len(state->ring[i].data_size); - int j; + adreno_show_object(p, state->ring[i].data, + state->ring[i].data_size); + } - drm_printf(p, " data: !!ascii85 |\n"); - drm_printf(p, " "); + if (state->bos) { + drm_puts(p, "bos:\n"); - for (j = 0; j < len; j++) - drm_printf(p, ascii85_encode(ptr[j], out)); + for (i = 0; i < state->nr_bos; i++) { + drm_printf(p, " - iova: 0x%016llx\n", + state->bos[i].iova); + drm_printf(p, " size: %zd\n", state->bos[i].size); - drm_printf(p, "\n"); + adreno_show_object(p, state->bos[i].data, + state->bos[i].size); } } diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 5f39549d9a8b9..3cf8e8d29812c 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -318,8 +318,39 @@ static void msm_gpu_devcoredump_free(void *data) msm_gpu_crashstate_put(gpu); } -static void msm_gpu_crashstate_capture(struct msm_gpu *gpu, char *comm, - char *cmd) +static void msm_gpu_crashstate_get_bo(struct msm_gpu_state *state, + struct msm_gem_object *obj, u64 iova, u32 flags) +{ + struct msm_gpu_state_bo *state_bo = &state->bos[state->nr_bos]; + + /* Don't record write only objects */ + + state_bo->size = obj->base.size; + state_bo->iova = iova; + + /* Only store the data for buffer objects marked for read */ + if ((flags & MSM_SUBMIT_BO_READ)) { + void *ptr; + + state_bo->data = kvmalloc(obj->base.size, GFP_KERNEL); + if (!state_bo->data) + return; + + ptr = msm_gem_get_vaddr_active(&obj->base); + if (IS_ERR(ptr)) { + kvfree(state_bo->data); + return; + } + + memcpy(state_bo->data, ptr, obj->base.size); + msm_gem_put_vaddr(&obj->base); + } + + state->nr_bos++; +} + +static void msm_gpu_crashstate_capture(struct msm_gpu *gpu, + struct msm_gem_submit *submit, char *comm, char *cmd) { struct msm_gpu_state *state; @@ -335,6 +366,17 @@ static void msm_gpu_crashstate_capture(struct msm_gpu *gpu, char *comm, state->comm = kstrdup(comm, GFP_KERNEL); state->cmd = kstrdup(cmd, GFP_KERNEL); + if (submit) { + int i; + + state->bos = kcalloc(submit->nr_bos, + sizeof(struct msm_gpu_state_bo), GFP_KERNEL); + + for (i = 0; state->bos && i < submit->nr_bos; i++) + msm_gpu_crashstate_get_bo(state, submit->bos[i].obj, + submit->bos[i].iova, submit->bos[i].flags); + } + /* Set the active crash state to be dumped on failure */ gpu->crashstate = state; @@ -434,7 +476,7 @@ static void recover_worker(struct work_struct *work) /* Record the crash state */ pm_runtime_get_sync(&gpu->pdev->dev); - msm_gpu_crashstate_capture(gpu, comm, cmd); + msm_gpu_crashstate_capture(gpu, submit, comm, cmd); pm_runtime_put_sync(&gpu->pdev->dev); kfree(cmd); diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index 878090b57e902..57380ef8d1f7c 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -181,6 +181,12 @@ struct msm_gpu_submitqueue { struct kref ref; }; +struct msm_gpu_state_bo { + u64 iova; + size_t size; + void *data; +}; + struct msm_gpu_state { struct kref ref; struct timeval time; @@ -202,6 +208,9 @@ struct msm_gpu_state { char *comm; char *cmd; + + int nr_bos; + struct msm_gpu_state_bo *bos; }; static inline void gpu_write(struct msm_gpu *gpu, u32 reg, u32 data) -- GitLab From 2c1f748d00e0617799c5bdbe9daf3a6a887b1b84 Mon Sep 17 00:00:00 2001 From: Sean Paul <seanpaul@chromium.org> Date: Wed, 25 Jul 2018 16:34:43 -0400 Subject: [PATCH 1413/1506] drm/msm: dpu: Use 'vsync' instead of 'vsync_clk' in cmdmode encoder Should work with the legacy handling in of, but we shouldn't rely on that. Signed-off-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c index 035a5fbe1435a..e6d02c6947b4f 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c @@ -424,7 +424,7 @@ static void dpu_encoder_phys_cmd_tearcheck_config( * vsync_count is ratio of MDP VSYNC clock frequency to LCD panel * frequency divided by the no. of rows (lines) in the LCDpanel. */ - vsync_hz = dpu_kms_get_clk_rate(dpu_kms, "vsync_clk"); + vsync_hz = dpu_kms_get_clk_rate(dpu_kms, "vsync"); if (vsync_hz <= 0) { DPU_DEBUG_CMDENC(cmd_enc, "invalid - vsync_hz %u\n", vsync_hz); -- GitLab From 41a8e8865a82b4fd4ff62b43b7c6d3bc5831f93d Mon Sep 17 00:00:00 2001 From: Sean Paul <seanpaul@chromium.org> Date: Wed, 25 Jul 2018 16:34:44 -0400 Subject: [PATCH 1414/1506] drm/msm: dpu: Use clock-names instead of assigned-clock-names In these cases, we want to enumerate _all_ clocks, not just the ones that are assigned a rate. Signed-off-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c index 8d907faa7496a..c1d7eac4fa258 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c @@ -147,8 +147,7 @@ int msm_dss_parse_clock(struct platform_device *pdev, return -EINVAL; mp->num_clk = 0; - num_clk = of_property_count_strings(pdev->dev.of_node, - "assigned-clock-names"); + num_clk = of_property_count_strings(pdev->dev.of_node, "clock-names"); if (num_clk <= 0) { pr_debug("clocks are not defined\n"); return 0; @@ -162,7 +161,7 @@ int msm_dss_parse_clock(struct platform_device *pdev, for (i = 0; i < num_clk; i++) { rc = of_property_read_string_index(pdev->dev.of_node, - "assigned-clock-names", i, + "clock-names", i, &clock_name); if (rc) { dev_err(&pdev->dev, "Failed to get clock name for %d\n", -- GitLab From a6bcddbc2ee1b2797fce016775b9e3faf17a4d0e Mon Sep 17 00:00:00 2001 From: Sean Paul <seanpaul@chromium.org> Date: Wed, 25 Jul 2018 16:34:45 -0400 Subject: [PATCH 1415/1506] drm/msm: dsi: Handle dual-channel for 6G as well This fixes up a collision between introducing dual-channel support and the dsi refactors. This patch applies the same dual-channel considerations and pclk calculations to both v2 and 6G, with a bit of abstracting for good measure. Signed-off-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/msm/dsi/dsi_host.c | 72 +++++++++++++++--------------- 1 file changed, 35 insertions(+), 37 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index 319501dcc0833..96fb5f6353148 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -664,11 +664,9 @@ void dsi_link_clk_disable_v2(struct msm_dsi_host *msm_host) clk_disable_unprepare(msm_host->byte_clk); } -int dsi_calc_clk_rate_6g(struct msm_dsi_host *msm_host, bool is_dual_dsi) +static u32 dsi_get_pclk_rate(struct msm_dsi_host *msm_host, bool is_dual_dsi) { struct drm_display_mode *mode = msm_host->mode; - u8 lanes = msm_host->lanes; - u32 bpp = dsi_get_bpp(msm_host->format); u32 pclk_rate; pclk_rate = mode->clock * 1000; @@ -676,61 +674,61 @@ int dsi_calc_clk_rate_6g(struct msm_dsi_host *msm_host, bool is_dual_dsi) /* * For dual DSI mode, the current DRM mode has the complete width of the * panel. Since, the complete panel is driven by two DSI controllers, - * theclock rates have to be split between the two dsi controllers. + * the clock rates have to be split between the two dsi controllers. * Adjust the byte and pixel clock rates for each dsi host accordingly. */ if (is_dual_dsi) pclk_rate /= 2; - if (lanes > 0) { - msm_host->byte_clk_rate = (pclk_rate * bpp) / (8 * lanes); - } else { + return pclk_rate; +} + +static void dsi_calc_pclk(struct msm_dsi_host *msm_host, bool is_dual_dsi) +{ + u8 lanes = msm_host->lanes; + u32 bpp = dsi_get_bpp(msm_host->format); + u32 pclk_rate = dsi_get_pclk_rate(msm_host, is_dual_dsi); + u64 pclk_bpp = (u64)pclk_rate * bpp; + + if (lanes == 0) { pr_err("%s: forcing mdss_dsi lanes to 1\n", __func__); - msm_host->byte_clk_rate = (pclk_rate * bpp) / 8; + lanes = 1; } - DBG("pclk=%d, bclk=%d", pclk_rate, msm_host->byte_clk_rate); + do_div(pclk_bpp, (8 * lanes)); - msm_host->esc_clk_rate = clk_get_rate(msm_host->esc_clk); + msm_host->pixel_clk_rate = pclk_rate; + msm_host->byte_clk_rate = pclk_bpp; + + DBG("pclk=%d, bclk=%d", msm_host->pixel_clk_rate, + msm_host->byte_clk_rate); + +} + +int dsi_calc_clk_rate_6g(struct msm_dsi_host *msm_host, bool is_dual_dsi) +{ + if (!msm_host->mode) { + pr_err("%s: mode not set\n", __func__); + return -EINVAL; + } + dsi_calc_pclk(msm_host, is_dual_dsi); + msm_host->esc_clk_rate = clk_get_rate(msm_host->esc_clk); return 0; } int dsi_calc_clk_rate_v2(struct msm_dsi_host *msm_host, bool is_dual_dsi) { - struct drm_display_mode *mode = msm_host->mode; - u8 lanes = msm_host->lanes; u32 bpp = dsi_get_bpp(msm_host->format); - u32 pclk_rate; u64 pclk_bpp; unsigned int esc_mhz, esc_div; unsigned long byte_mhz; - pclk_rate = mode->clock * 1000; - - /* - * For dual DSI mode, the current DRM mode has the complete width of the - * panel. Since, the complete panel is driven by two DSI controllers, - * theclock rates have to be split between the two dsi controllers. - * Adjust the byte and pixel clock rates for each dsi host accordingly. - */ - if (is_dual_dsi) - pclk_rate /= 2; - - pclk_bpp = pclk_rate * bpp; - if (lanes > 0) { - do_div(pclk_bpp, (8 * lanes)); - } else { - pr_err("%s: forcing mdss_dsi lanes to 1\n", __func__); - do_div(pclk_bpp, 8); - } - msm_host->pixel_clk_rate = pclk_rate; - msm_host->byte_clk_rate = pclk_bpp; - - DBG("pclk=%d, bclk=%d", msm_host->pixel_clk_rate, - msm_host->byte_clk_rate); + dsi_calc_pclk(msm_host, is_dual_dsi); - msm_host->src_clk_rate = (pclk_rate * bpp) / 8; + pclk_bpp = (u64)dsi_get_pclk_rate(msm_host, is_dual_dsi) * bpp; + do_div(pclk_bpp, 8); + msm_host->src_clk_rate = pclk_bpp; /* * esc clock is byte clock followed by a 4 bit divider, -- GitLab From 3530a17f4dc8f1f667fee14c16f229162daa79bb Mon Sep 17 00:00:00 2001 From: Arnd Bergmann <arnd@arndb.de> Date: Thu, 26 Jul 2018 14:39:25 +0200 Subject: [PATCH 1416/1506] drm/msm/gpu: avoid deprecated do_gettimeofday All users of do_gettimeofday() have been removed, but this one recently crept in, along with an incorrect printing of the microseconds portion. This converts it to using ktime_get_real_timespec64() as a direct replacement, and adds the leading zeroes. I considered using monotonic times (ktime_get()) instead, but as this timestamp appears to only be used for humans rather than compared with other timestamps, the real time domain is probably good enough. Fixes: e43b045e2c82 ("drm/msm/gpu: Capture the state of the GPU") Signed-off-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/msm/adreno/adreno_gpu.c | 2 +- drivers/gpu/drm/msm/msm_gpu.c | 4 ++-- drivers/gpu/drm/msm/msm_gpu.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index 08d3c618b7de9..38ac50b738295 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -376,7 +376,7 @@ int adreno_gpu_state_get(struct msm_gpu *gpu, struct msm_gpu_state *state) kref_init(&state->ref); - do_gettimeofday(&state->time); + ktime_get_real_ts64(&state->time); for (i = 0; i < gpu->nr_rings; i++) { int size = 0, j; diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 3cf8e8d29812c..f388944c93e27 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -297,8 +297,8 @@ static ssize_t msm_gpu_devcoredump_read(char *buffer, loff_t offset, drm_printf(&p, "---\n"); drm_printf(&p, "kernel: " UTS_RELEASE "\n"); drm_printf(&p, "module: " KBUILD_MODNAME "\n"); - drm_printf(&p, "time: %ld.%ld\n", - state->time.tv_sec, state->time.tv_usec); + drm_printf(&p, "time: %lld.%09ld\n", + state->time.tv_sec, state->time.tv_nsec); if (state->comm) drm_printf(&p, "comm: %s\n", state->comm); if (state->cmd) diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index 57380ef8d1f7c..1c6105bc55c76 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -189,7 +189,7 @@ struct msm_gpu_state_bo { struct msm_gpu_state { struct kref ref; - struct timeval time; + struct timespec64 time; struct { u64 iova; -- GitLab From f4b0f66daf77ac79807711310597e4c102f72bd8 Mon Sep 17 00:00:00 2001 From: zhong jiang <zhongjiang@huawei.com> Date: Tue, 24 Jul 2018 19:51:59 +0800 Subject: [PATCH 1417/1506] drm/msm/dpu: fix mismatch in function argument. Fix the sparse error. the dpu_rm_init declaration is not consistent with the implement. Signed-off-by: zhong jiang <zhongjiang@huawei.com> [robclark un-typo'd subject line] Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h index ef3f67bedaa00..ffd1841a6067c 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h @@ -105,7 +105,7 @@ struct dpu_rm_hw_iter { */ int dpu_rm_init(struct dpu_rm *rm, struct dpu_mdss_cfg *cat, - void *mmio, + void __iomem *mmio, struct drm_device *dev); /** -- GitLab From 78918cd0eee346c43e2d9dc553fadfacad6cb488 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann <arnd@arndb.de> Date: Tue, 24 Jul 2018 17:35:37 +0200 Subject: [PATCH 1418/1506] drm/msm: mark PM functions as __maybe_unused The suspend/resume functions are not referenced when power management is disabled: drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c:1288:12: error: 'dpu_runtime_resume' defined but not used [-Werror=unused-function] drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c:1261:12: error: 'dpu_runtime_suspend' defined but not used [-Werror=unused-function] This marks them as __maybe_unused to let the compiler drop the functions without complaining. Fixes: 591225291ca2 ("drm/msm: Add SDM845 DPU support") Signed-off-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index 8d4678d29cc73..1c0838801e784 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -1258,7 +1258,7 @@ static int dpu_dev_remove(struct platform_device *pdev) return 0; } -static int dpu_runtime_suspend(struct device *dev) +static int __maybe_unused dpu_runtime_suspend(struct device *dev) { int rc = -1; struct platform_device *pdev = to_platform_device(dev); @@ -1285,7 +1285,7 @@ static int dpu_runtime_suspend(struct device *dev) return rc; } -static int dpu_runtime_resume(struct device *dev) +static int __maybe_unused dpu_runtime_resume(struct device *dev) { int rc = -1; struct platform_device *pdev = to_platform_device(dev); -- GitLab From aff24cd1f531b0dd55e46f6a8f76cf44117f0a24 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" <gustavo@embeddedor.com> Date: Mon, 23 Jul 2018 13:46:55 -0500 Subject: [PATCH 1419/1506] drm/msm: Replace PTR_RET with PTR_ERR_OR_ZERO PTR_RET is deprecated, use PTR_ERR_OR_ZERO instead. Signed-off-by: Gustavo A. R. Silva <gustavo@embeddedor.com> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c index c1d7eac4fa258..790d39f816dc0 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c @@ -35,7 +35,7 @@ int msm_dss_get_clk(struct device *dev, struct dss_clk *clk_arry, int num_clk) for (i = 0; i < num_clk; i++) { clk_arry[i].clk = clk_get(dev, clk_arry[i].clk_name); - rc = PTR_RET(clk_arry[i].clk); + rc = PTR_ERR_OR_ZERO(clk_arry[i].clk); if (rc) { DEV_ERR("%pS->%s: '%s' get failed. rc=%d\n", __builtin_return_address(0), __func__, -- GitLab From 2c7b48e7267adb0b79a0785563eaa69a35632155 Mon Sep 17 00:00:00 2001 From: Jordan Crouse <jcrouse@codeaurora.org> Date: Thu, 26 Jul 2018 14:30:10 -0600 Subject: [PATCH 1420/1506] drm/msm/disp/dpu: Remove unused code from drm_encoder.c Remove dpu_encoder_check_mode and dpu_encoder_helper_hw_release frmo drm_encoder.c as they appear to be unused. Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 80 ------------------- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h | 8 -- .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h | 9 --- 3 files changed, 97 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 27775feed32be..5c0051af5e986 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -1627,22 +1627,6 @@ static void _dpu_encoder_kickoff_phys(struct dpu_encoder_virt *dpu_enc) spin_unlock_irqrestore(&dpu_enc->enc_spinlock, lock_flags); } -bool dpu_encoder_check_mode(struct drm_encoder *drm_enc, u32 mode) -{ - struct dpu_encoder_virt *dpu_enc; - struct msm_display_info *disp_info; - - if (!drm_enc) { - DPU_ERROR("invalid encoder\n"); - return false; - } - - dpu_enc = to_dpu_encoder_virt(drm_enc); - disp_info = &dpu_enc->disp_info; - - return (disp_info->capabilities & mode); -} - void dpu_encoder_trigger_kickoff_pending(struct drm_encoder *drm_enc) { struct dpu_encoder_virt *dpu_enc; @@ -1903,70 +1887,6 @@ void dpu_encoder_kickoff(struct drm_encoder *drm_enc) DPU_ATRACE_END("encoder_kickoff"); } -int dpu_encoder_helper_hw_release(struct dpu_encoder_phys *phys_enc, - struct drm_framebuffer *fb) -{ - struct drm_encoder *drm_enc; - struct dpu_hw_mixer_cfg mixer; - struct dpu_rm_hw_iter lm_iter; - bool lm_valid = false; - - if (!phys_enc || !phys_enc->parent) { - DPU_ERROR("invalid encoder\n"); - return -EINVAL; - } - - drm_enc = phys_enc->parent; - memset(&mixer, 0, sizeof(mixer)); - - /* reset associated CTL/LMs */ - if (phys_enc->hw_ctl->ops.clear_pending_flush) - phys_enc->hw_ctl->ops.clear_pending_flush(phys_enc->hw_ctl); - if (phys_enc->hw_ctl->ops.clear_all_blendstages) - phys_enc->hw_ctl->ops.clear_all_blendstages(phys_enc->hw_ctl); - - dpu_rm_init_hw_iter(&lm_iter, drm_enc->base.id, DPU_HW_BLK_LM); - while (dpu_rm_get_hw(&phys_enc->dpu_kms->rm, &lm_iter)) { - struct dpu_hw_mixer *hw_lm = (struct dpu_hw_mixer *)lm_iter.hw; - - if (!hw_lm) - continue; - - /* need to flush LM to remove it */ - if (phys_enc->hw_ctl->ops.get_bitmask_mixer && - phys_enc->hw_ctl->ops.update_pending_flush) - phys_enc->hw_ctl->ops.update_pending_flush( - phys_enc->hw_ctl, - phys_enc->hw_ctl->ops.get_bitmask_mixer( - phys_enc->hw_ctl, hw_lm->idx)); - - if (fb) { - /* assume a single LM if targeting a frame buffer */ - if (lm_valid) - continue; - - mixer.out_height = fb->height; - mixer.out_width = fb->width; - - if (hw_lm->ops.setup_mixer_out) - hw_lm->ops.setup_mixer_out(hw_lm, &mixer); - } - - lm_valid = true; - - /* only enable border color on LM */ - if (phys_enc->hw_ctl->ops.setup_blendstage) - phys_enc->hw_ctl->ops.setup_blendstage( - phys_enc->hw_ctl, hw_lm->idx, NULL); - } - - if (!lm_valid) { - DPU_DEBUG_ENC(to_dpu_encoder_virt(drm_enc), "lm not found\n"); - return -EFAULT; - } - return 0; -} - void dpu_encoder_prepare_commit(struct drm_encoder *drm_enc) { struct dpu_encoder_virt *dpu_enc; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h index ce92901ed2273..204e538b0b745 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h @@ -139,14 +139,6 @@ enum dpu_intf_mode dpu_encoder_get_intf_mode(struct drm_encoder *encoder); */ void dpu_encoder_virt_restore(struct drm_encoder *encoder); -/** - * dpu_encoder_check_mode - check if given mode is supported or not - * @drm_enc: Pointer to drm encoder object - * @mode: Mode to be checked - * @Return: true if it is cmd mode - */ -bool dpu_encoder_check_mode(struct drm_encoder *drm_enc, u32 mode); - /** * dpu_encoder_init - initialize virtual encoder object * @dev: Pointer to drm device structure diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h index 8505edddcc813..dacec1c8eeebb 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h @@ -402,15 +402,6 @@ void dpu_encoder_helper_split_config( struct dpu_encoder_phys *phys_enc, enum dpu_intf interface); -/** - * dpu_encoder_helper_hw_release - prepare for h/w reset during disable - * @phys_enc: Pointer to physical encoder structure - * @fb: Optional fb for specifying new mixer output resolution, may be NULL - * Return: Zero on success - */ -int dpu_encoder_helper_hw_release(struct dpu_encoder_phys *phys_enc, - struct drm_framebuffer *fb); - /** * dpu_encoder_helper_report_irq_timeout - utility to report error that irq has * timed out, including reporting frame error event to crtc and debug dump -- GitLab From c17aeda0b01cbcb8e334665fefa64a5148ecd18f Mon Sep 17 00:00:00 2001 From: Jordan Crouse <jcrouse@codeaurora.org> Date: Thu, 26 Jul 2018 14:30:11 -0600 Subject: [PATCH 1421/1506] drm/msm/disp/dpu: Remove unused code from drm_crtc.c Remove a chunk of unused code from drm_crtc.c, namely dpu_crtc_res_add, dpu_crtc_res_get, dpu_crtc_res_put and associated static functions. Also zap dpu_crtc_event_queue(), helper functions and members. Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 383 +---------------------- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h | 61 ---- 2 files changed, 2 insertions(+), 442 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index 7ac0e0dda8664..80cbf75bc2ff2 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -280,289 +280,6 @@ static void _dpu_crtc_rp_reset(struct dpu_crtc_respool *rp, mutex_unlock(rp_lock); } -/** - * _dpu_crtc_rp_add_no_lock - add given resource to resource pool without lock - * @rp: Pointer to original resource pool - * @type: Resource type - * @tag: Search tag for given resource - * @val: Resource handle - * @ops: Resource callback operations - * return: 0 if success; error code otherwise - */ -static int _dpu_crtc_rp_add_no_lock(struct dpu_crtc_respool *rp, u32 type, - u64 tag, void *val, struct dpu_crtc_res_ops *ops) -{ - struct dpu_crtc_res *res; - struct drm_crtc *crtc; - - if (!rp || !ops) { - DPU_ERROR("invalid resource pool/ops\n"); - return -EINVAL; - } - - crtc = _dpu_crtc_rp_to_crtc(rp); - if (!crtc) { - DPU_ERROR("invalid crtc\n"); - return -EINVAL; - } - - list_for_each_entry(res, &rp->res_list, list) { - if (res->type != type || res->tag != tag) - continue; - DPU_ERROR("crtc%d.%u already exist res:0x%x/0x%llx/%pK/%d\n", - crtc->base.id, rp->sequence_id, - res->type, res->tag, res->val, - atomic_read(&res->refcount)); - return -EEXIST; - } - res = kzalloc(sizeof(struct dpu_crtc_res), GFP_KERNEL); - if (!res) - return -ENOMEM; - INIT_LIST_HEAD(&res->list); - atomic_set(&res->refcount, 1); - res->type = type; - res->tag = tag; - res->val = val; - res->ops = *ops; - list_add_tail(&res->list, &rp->res_list); - DPU_DEBUG("crtc%d.%u added res:0x%x/0x%llx\n", - crtc->base.id, rp->sequence_id, type, tag); - return 0; -} - -/** - * _dpu_crtc_rp_add - add given resource to resource pool - * @rp: Pointer to original resource pool - * @type: Resource type - * @tag: Search tag for given resource - * @val: Resource handle - * @ops: Resource callback operations - * return: 0 if success; error code otherwise - */ -static int _dpu_crtc_rp_add(struct dpu_crtc_respool *rp, u32 type, u64 tag, - void *val, struct dpu_crtc_res_ops *ops) -{ - int rc; - - if (!rp) { - DPU_ERROR("invalid resource pool\n"); - return -EINVAL; - } - - mutex_lock(rp->rp_lock); - rc = _dpu_crtc_rp_add_no_lock(rp, type, tag, val, ops); - mutex_unlock(rp->rp_lock); - return rc; -} - -/** - * _dpu_crtc_rp_get - lookup the resource from given resource pool and obtain - * if available; otherwise, obtain resource from global pool - * @rp: Pointer to original resource pool - * @type: Resource type - * @tag: Search tag for given resource - * return: Resource handle if success; pointer error or null otherwise - */ -static void *_dpu_crtc_rp_get(struct dpu_crtc_respool *rp, u32 type, u64 tag) -{ - struct dpu_crtc_respool *old_rp; - struct dpu_crtc_res *res; - void *val = NULL; - int rc; - struct drm_crtc *crtc; - - if (!rp) { - DPU_ERROR("invalid resource pool\n"); - return NULL; - } - - crtc = _dpu_crtc_rp_to_crtc(rp); - if (!crtc) { - DPU_ERROR("invalid crtc\n"); - return NULL; - } - - mutex_lock(rp->rp_lock); - list_for_each_entry(res, &rp->res_list, list) { - if (res->type != type || res->tag != tag) - continue; - DPU_DEBUG("crtc%d.%u found res:0x%x/0x%llx/%pK/%d\n", - crtc->base.id, rp->sequence_id, - res->type, res->tag, res->val, - atomic_read(&res->refcount)); - atomic_inc(&res->refcount); - res->flags &= ~DPU_CRTC_RES_FLAG_FREE; - mutex_unlock(rp->rp_lock); - return res->val; - } - list_for_each_entry(res, &rp->res_list, list) { - if (res->type != type || !(res->flags & DPU_CRTC_RES_FLAG_FREE)) - continue; - DPU_DEBUG("crtc%d.%u retag res:0x%x/0x%llx/%pK/%d\n", - crtc->base.id, rp->sequence_id, - res->type, res->tag, res->val, - atomic_read(&res->refcount)); - atomic_inc(&res->refcount); - res->tag = tag; - res->flags &= ~DPU_CRTC_RES_FLAG_FREE; - mutex_unlock(rp->rp_lock); - return res->val; - } - /* not in this rp, try to grab from global pool */ - if (rp->ops.get) - val = rp->ops.get(NULL, type, -1); - if (!IS_ERR_OR_NULL(val)) - goto add_res; - /* - * Search older resource pools for hw blk with matching type, - * necessary when resource is being used by this object, - * but in previous states not yet cleaned up. - * - * This enables searching of all resources currently owned - * by this crtc even though the resource might not be used - * in the current atomic state. This allows those resources - * to be re-acquired by the new atomic state immediately - * without waiting for the resources to be fully released. - */ - else if (IS_ERR_OR_NULL(val) && (type < DPU_HW_BLK_MAX)) { - list_for_each_entry(old_rp, rp->rp_head, rp_list) { - if (old_rp == rp) - continue; - - list_for_each_entry(res, &old_rp->res_list, list) { - if (res->type != type) - continue; - DRM_DEBUG_KMS("crtc%d.%u found res:0x%x//%pK/ " - "in crtc%d.%d\n", - crtc->base.id, rp->sequence_id, - res->type, res->val, - crtc->base.id, - old_rp->sequence_id); - if (res->ops.get) - res->ops.get(res->val, 0, -1); - val = res->val; - break; - } - - if (!IS_ERR_OR_NULL(val)) - break; - } - } - if (IS_ERR_OR_NULL(val)) { - DPU_DEBUG("crtc%d.%u failed to get res:0x%x//\n", - crtc->base.id, rp->sequence_id, type); - mutex_unlock(rp->rp_lock); - return NULL; - } -add_res: - rc = _dpu_crtc_rp_add_no_lock(rp, type, tag, val, &rp->ops); - if (rc) { - DPU_ERROR("crtc%d.%u failed to add res:0x%x/0x%llx\n", - crtc->base.id, rp->sequence_id, type, tag); - if (rp->ops.put) - rp->ops.put(val); - val = NULL; - } - mutex_unlock(rp->rp_lock); - return val; -} - -/** - * _dpu_crtc_rp_put - return given resource to resource pool - * @rp: Pointer to original resource pool - * @type: Resource type - * @tag: Search tag for given resource - * return: None - */ -static void _dpu_crtc_rp_put(struct dpu_crtc_respool *rp, u32 type, u64 tag) -{ - struct dpu_crtc_res *res, *next; - struct drm_crtc *crtc; - - if (!rp) { - DPU_ERROR("invalid resource pool\n"); - return; - } - - crtc = _dpu_crtc_rp_to_crtc(rp); - if (!crtc) { - DPU_ERROR("invalid crtc\n"); - return; - } - - mutex_lock(rp->rp_lock); - list_for_each_entry_safe(res, next, &rp->res_list, list) { - if (res->type != type || res->tag != tag) - continue; - DPU_DEBUG("crtc%d.%u found res:0x%x/0x%llx/%pK/%d\n", - crtc->base.id, rp->sequence_id, - res->type, res->tag, res->val, - atomic_read(&res->refcount)); - if (res->flags & DPU_CRTC_RES_FLAG_FREE) - DPU_ERROR( - "crtc%d.%u already free res:0x%x/0x%llx/%pK/%d\n", - crtc->base.id, rp->sequence_id, - res->type, res->tag, res->val, - atomic_read(&res->refcount)); - else if (atomic_dec_return(&res->refcount) == 0) - res->flags |= DPU_CRTC_RES_FLAG_FREE; - - mutex_unlock(rp->rp_lock); - return; - } - DPU_ERROR("crtc%d.%u not found res:0x%x/0x%llx\n", - crtc->base.id, rp->sequence_id, type, tag); - mutex_unlock(rp->rp_lock); -} - -int dpu_crtc_res_add(struct drm_crtc_state *state, u32 type, u64 tag, - void *val, struct dpu_crtc_res_ops *ops) -{ - struct dpu_crtc_respool *rp; - - if (!state) { - DPU_ERROR("invalid parameters\n"); - return -EINVAL; - } - - rp = &to_dpu_crtc_state(state)->rp; - return _dpu_crtc_rp_add(rp, type, tag, val, ops); -} - -void *dpu_crtc_res_get(struct drm_crtc_state *state, u32 type, u64 tag) -{ - struct dpu_crtc_respool *rp; - void *val; - - if (!state) { - DPU_ERROR("invalid parameters\n"); - return NULL; - } - - rp = &to_dpu_crtc_state(state)->rp; - val = _dpu_crtc_rp_get(rp, type, tag); - if (IS_ERR(val)) { - DPU_ERROR("failed to get res type:0x%x:0x%llx\n", - type, tag); - return NULL; - } - - return val; -} - -void dpu_crtc_res_put(struct drm_crtc_state *state, u32 type, u64 tag) -{ - struct dpu_crtc_respool *rp; - - if (!state) { - DPU_ERROR("invalid parameters\n"); - return; - } - - rp = &to_dpu_crtc_state(state)->rp; - _dpu_crtc_rp_put(rp, type, tag); -} - static void dpu_crtc_destroy(struct drm_crtc *crtc) { struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); @@ -2364,97 +2081,6 @@ static const struct drm_crtc_helper_funcs dpu_crtc_helper_funcs = { .atomic_flush = dpu_crtc_atomic_flush, }; -static void _dpu_crtc_event_cb(struct kthread_work *work) -{ - struct dpu_crtc_event *event; - struct dpu_crtc *dpu_crtc; - unsigned long irq_flags; - - if (!work) { - DPU_ERROR("invalid work item\n"); - return; - } - - event = container_of(work, struct dpu_crtc_event, kt_work); - - /* set dpu_crtc to NULL for static work structures */ - dpu_crtc = event->dpu_crtc; - if (!dpu_crtc) - return; - - if (event->cb_func) - event->cb_func(&dpu_crtc->base, event->usr); - - spin_lock_irqsave(&dpu_crtc->event_lock, irq_flags); - list_add_tail(&event->list, &dpu_crtc->event_free_list); - spin_unlock_irqrestore(&dpu_crtc->event_lock, irq_flags); -} - -int dpu_crtc_event_queue(struct drm_crtc *crtc, - void (*func)(struct drm_crtc *crtc, void *usr), void *usr) -{ - unsigned long irq_flags; - struct dpu_crtc *dpu_crtc; - struct msm_drm_private *priv; - struct dpu_crtc_event *event = NULL; - u32 crtc_id; - - if (!crtc || !crtc->dev || !crtc->dev->dev_private || !func) { - DPU_ERROR("invalid parameters\n"); - return -EINVAL; - } - dpu_crtc = to_dpu_crtc(crtc); - priv = crtc->dev->dev_private; - crtc_id = drm_crtc_index(crtc); - - /* - * Obtain an event struct from the private cache. This event - * queue may be called from ISR contexts, so use a private - * cache to avoid calling any memory allocation functions. - */ - spin_lock_irqsave(&dpu_crtc->event_lock, irq_flags); - if (!list_empty(&dpu_crtc->event_free_list)) { - event = list_first_entry(&dpu_crtc->event_free_list, - struct dpu_crtc_event, list); - list_del_init(&event->list); - } - spin_unlock_irqrestore(&dpu_crtc->event_lock, irq_flags); - - if (!event) - return -ENOMEM; - - /* populate event node */ - event->dpu_crtc = dpu_crtc; - event->cb_func = func; - event->usr = usr; - - /* queue new event request */ - kthread_init_work(&event->kt_work, _dpu_crtc_event_cb); - kthread_queue_work(&priv->event_thread[crtc_id].worker, - &event->kt_work); - - return 0; -} - -static int _dpu_crtc_init_events(struct dpu_crtc *dpu_crtc) -{ - int i, rc = 0; - - if (!dpu_crtc) { - DPU_ERROR("invalid crtc\n"); - return -EINVAL; - } - - spin_lock_init(&dpu_crtc->event_lock); - - INIT_LIST_HEAD(&dpu_crtc->event_free_list); - for (i = 0; i < DPU_CRTC_MAX_EVENT_COUNT; ++i) - list_add_tail(&dpu_crtc->event_cache[i].list, - &dpu_crtc->event_free_list); - - return rc; -} - /* initialize crtc */ struct drm_crtc *dpu_crtc_init(struct drm_device *dev, struct drm_plane *plane) { @@ -2462,7 +2088,7 @@ struct drm_crtc *dpu_crtc_init(struct drm_device *dev, struct drm_plane *plane) struct dpu_crtc *dpu_crtc = NULL; struct msm_drm_private *priv = NULL; struct dpu_kms *kms = NULL; - int i, rc; + int i; priv = dev->dev_private; kms = to_dpu_kms(priv->kms); @@ -2503,12 +2129,7 @@ struct drm_crtc *dpu_crtc_init(struct drm_device *dev, struct drm_plane *plane) snprintf(dpu_crtc->name, DPU_CRTC_NAME_SIZE, "crtc%u", crtc->base.id); /* initialize event handling */ - rc = _dpu_crtc_init_events(dpu_crtc); - if (rc) { - drm_crtc_cleanup(crtc); - kfree(dpu_crtc); - return ERR_PTR(rc); - } + spin_lock_init(&dpu_crtc->event_lock); dpu_crtc->phandle = &kms->phandle; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h index 4a97ba16735f2..e87109e608e9b 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h @@ -112,23 +112,6 @@ struct dpu_crtc_frame_event { u32 event; }; -/** - * struct dpu_crtc_event - event callback tracking structure - * @list: Linked list tracking node - * @kt_work: Kthread worker structure - * @dpu_crtc: Pointer to associated dpu_crtc structure - * @cb_func: Pointer to callback function - * @usr: Pointer to user data to be provided to the callback - */ -struct dpu_crtc_event { - struct list_head list; - struct kthread_work kt_work; - void *dpu_crtc; - - void (*cb_func)(struct drm_crtc *crtc, void *usr); - void *usr; -}; - /* * Maximum number of free event structures to cache */ @@ -172,8 +155,6 @@ struct dpu_crtc_event { * @frame_done_comp : for frame_event_done synchronization * @event_thread : Pointer to event handler thread * @event_worker : Event worker queue - * @event_cache : Local cache of event worker structures - * @event_free_list : List of available event structures * @event_lock : Spinlock around event handling code * @misr_enable : boolean entry indicates misr enable/disable status. * @misr_frame_count : misr frame count provided by client @@ -224,8 +205,6 @@ struct dpu_crtc { struct completion frame_done_comp; /* for handling internal event thread */ - struct dpu_crtc_event event_cache[DPU_CRTC_MAX_EVENT_COUNT]; - struct list_head event_free_list; spinlock_t event_lock; bool misr_enable; u32 misr_frame_count; @@ -441,44 +420,4 @@ static inline bool dpu_crtc_is_enabled(struct drm_crtc *crtc) return crtc ? crtc->enabled : false; } -/** - * dpu_crtc_event_queue - request event callback - * @crtc: Pointer to drm crtc structure - * @func: Pointer to callback function - * @usr: Pointer to user data to be passed to callback - * Returns: Zero on success - */ -int dpu_crtc_event_queue(struct drm_crtc *crtc, - void (*func)(struct drm_crtc *crtc, void *usr), void *usr); - -/** - * dpu_crtc_res_add - add given resource to resource pool in crtc state - * @state: Pointer to drm crtc state - * @type: Resource type - * @tag: Search tag for given resource - * @val: Resource handle - * @ops: Resource callback operations - * return: 0 if success; error code otherwise - */ -int dpu_crtc_res_add(struct drm_crtc_state *state, u32 type, u64 tag, - void *val, struct dpu_crtc_res_ops *ops); - -/** - * dpu_crtc_res_get - get given resource from resource pool in crtc state - * @state: Pointer to drm crtc state - * @type: Resource type - * @tag: Search tag for given resource - * return: Resource handle if success; pointer error or null otherwise - */ -void *dpu_crtc_res_get(struct drm_crtc_state *state, u32 type, u64 tag); - -/** - * dpu_crtc_res_put - return given resource to resource pool in crtc state - * @state: Pointer to drm crtc state - * @type: Resource type - * @tag: Search tag for given resource - * return: None - */ -void dpu_crtc_res_put(struct drm_crtc_state *state, u32 type, u64 tag); - #endif /* _DPU_CRTC_H_ */ -- GitLab From d9c7440dad0d85b29325d89956411e2c57e7d17a Mon Sep 17 00:00:00 2001 From: Jordan Crouse <jcrouse@codeaurora.org> Date: Thu, 26 Jul 2018 14:30:12 -0600 Subject: [PATCH 1422/1506] drm/msm/disp/dpu: Remove dpu_kms_utils None of the functions in dpu_kms_utils.c seem to be used so remove them all. Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/msm/Makefile | 1 - drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h | 112 ------------- drivers/gpu/drm/msm/disp/dpu1/dpu_kms_utils.c | 153 ------------------ 3 files changed, 266 deletions(-) delete mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_kms_utils.c diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index 1639ea8c0d132..7c773e0036631 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -68,7 +68,6 @@ msm-y := \ disp/dpu1/dpu_io_util.o \ disp/dpu1/dpu_irq.o \ disp/dpu1/dpu_kms.o \ - disp/dpu1/dpu_kms_utils.o \ disp/dpu1/dpu_mdss.o \ disp/dpu1/dpu_plane.o \ disp/dpu1/dpu_power_handle.o \ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h index 407c1ed27fe63..66d466628e2b9 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h @@ -270,118 +270,6 @@ void *dpu_debugfs_get_root(struct dpu_kms *dpu_kms); */ #define DPU_KMS_INFO_MAX_SIZE 4096 -/** - * struct dpu_kms_info - connector information structure container - * @data: Array of information character data - * @len: Current length of information data - * @staged_len: Temporary data buffer length, commit to - * len using dpu_kms_info_stop - * @start: Whether or not a partial data entry was just started - */ -struct dpu_kms_info { - char data[DPU_KMS_INFO_MAX_SIZE]; - uint32_t len; - uint32_t staged_len; - bool start; -}; - -/** - * DPU_KMS_INFO_DATA - Macro for accessing dpu_kms_info data bytes - * @S: Pointer to dpu_kms_info structure - * Returns: Pointer to byte data - */ -#define DPU_KMS_INFO_DATA(S) ((S) ? ((struct dpu_kms_info *)(S))->data : 0) - -/** - * DPU_KMS_INFO_DATALEN - Macro for accessing dpu_kms_info data length - * it adds an extra character length to count null. - * @S: Pointer to dpu_kms_info structure - * Returns: Size of available byte data - */ -#define DPU_KMS_INFO_DATALEN(S) ((S) ? ((struct dpu_kms_info *)(S))->len + 1 \ - : 0) - -/** - * dpu_kms_info_reset - reset dpu_kms_info structure - * @info: Pointer to dpu_kms_info structure - */ -void dpu_kms_info_reset(struct dpu_kms_info *info); - -/** - * dpu_kms_info_add_keyint - add integer value to 'dpu_kms_info' - * @info: Pointer to dpu_kms_info structure - * @key: Pointer to key string - * @value: Signed 64-bit integer value - */ -void dpu_kms_info_add_keyint(struct dpu_kms_info *info, - const char *key, - int64_t value); - -/** - * dpu_kms_info_add_keystr - add string value to 'dpu_kms_info' - * @info: Pointer to dpu_kms_info structure - * @key: Pointer to key string - * @value: Pointer to string value - */ -void dpu_kms_info_add_keystr(struct dpu_kms_info *info, - const char *key, - const char *value); - -/** - * dpu_kms_info_start - begin adding key to 'dpu_kms_info' - * Usage: - * dpu_kms_info_start(key) - * dpu_kms_info_append(val_1) - * ... - * dpu_kms_info_append(val_n) - * dpu_kms_info_stop - * @info: Pointer to dpu_kms_info structure - * @key: Pointer to key string - */ -void dpu_kms_info_start(struct dpu_kms_info *info, - const char *key); - -/** - * dpu_kms_info_append - append value string to 'dpu_kms_info' - * Usage: - * dpu_kms_info_start(key) - * dpu_kms_info_append(val_1) - * ... - * dpu_kms_info_append(val_n) - * dpu_kms_info_stop - * @info: Pointer to dpu_kms_info structure - * @str: Pointer to partial value string - */ -void dpu_kms_info_append(struct dpu_kms_info *info, - const char *str); - -/** - * dpu_kms_info_append_format - append format code string to 'dpu_kms_info' - * Usage: - * dpu_kms_info_start(key) - * dpu_kms_info_append_format(fourcc, modifier) - * ... - * dpu_kms_info_stop - * @info: Pointer to dpu_kms_info structure - * @pixel_format: FOURCC format code - * @modifier: 64-bit drm format modifier - */ -void dpu_kms_info_append_format(struct dpu_kms_info *info, - uint32_t pixel_format, - uint64_t modifier); - -/** - * dpu_kms_info_stop - finish adding key to 'dpu_kms_info' - * Usage: - * dpu_kms_info_start(key) - * dpu_kms_info_append(val_1) - * ... - * dpu_kms_info_append(val_n) - * dpu_kms_info_stop - * @info: Pointer to dpu_kms_info structure - */ -void dpu_kms_info_stop(struct dpu_kms_info *info); - /** * Vblank enable/disable functions */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms_utils.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms_utils.c deleted file mode 100644 index a80b3da5a9feb..0000000000000 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms_utils.c +++ /dev/null @@ -1,153 +0,0 @@ -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * 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. - */ - -#define pr_fmt(fmt) "dpu-kms_utils:[%s] " fmt, __func__ - -#include "dpu_kms.h" - -void dpu_kms_info_reset(struct dpu_kms_info *info) -{ - if (info) { - info->len = 0; - info->staged_len = 0; - } -} - -void dpu_kms_info_add_keyint(struct dpu_kms_info *info, - const char *key, - int64_t value) -{ - uint32_t len; - - if (info && key) { - len = snprintf(info->data + info->len, - DPU_KMS_INFO_MAX_SIZE - info->len, - "%s=%lld\n", - key, - value); - - /* check if snprintf truncated the string */ - if ((info->len + len) < DPU_KMS_INFO_MAX_SIZE) - info->len += len; - } -} - -void dpu_kms_info_add_keystr(struct dpu_kms_info *info, - const char *key, - const char *value) -{ - uint32_t len; - - if (info && key && value) { - len = snprintf(info->data + info->len, - DPU_KMS_INFO_MAX_SIZE - info->len, - "%s=%s\n", - key, - value); - - /* check if snprintf truncated the string */ - if ((info->len + len) < DPU_KMS_INFO_MAX_SIZE) - info->len += len; - } -} - -void dpu_kms_info_start(struct dpu_kms_info *info, - const char *key) -{ - uint32_t len; - - if (info && key) { - len = snprintf(info->data + info->len, - DPU_KMS_INFO_MAX_SIZE - info->len, - "%s=", - key); - - info->start = true; - - /* check if snprintf truncated the string */ - if ((info->len + len) < DPU_KMS_INFO_MAX_SIZE) - info->staged_len = info->len + len; - } -} - -void dpu_kms_info_append(struct dpu_kms_info *info, - const char *str) -{ - uint32_t len; - - if (info) { - len = snprintf(info->data + info->staged_len, - DPU_KMS_INFO_MAX_SIZE - info->staged_len, - "%s", - str); - - /* check if snprintf truncated the string */ - if ((info->staged_len + len) < DPU_KMS_INFO_MAX_SIZE) { - info->staged_len += len; - info->start = false; - } - } -} - -void dpu_kms_info_append_format(struct dpu_kms_info *info, - uint32_t pixel_format, - uint64_t modifier) -{ - uint32_t len; - - if (!info) - return; - - if (modifier) { - len = snprintf(info->data + info->staged_len, - DPU_KMS_INFO_MAX_SIZE - info->staged_len, - info->start ? - "%c%c%c%c/%llX/%llX" : " %c%c%c%c/%llX/%llX", - (pixel_format >> 0) & 0xFF, - (pixel_format >> 8) & 0xFF, - (pixel_format >> 16) & 0xFF, - (pixel_format >> 24) & 0xFF, - (modifier >> 56) & 0xFF, - modifier & ((1ULL << 56) - 1)); - } else { - len = snprintf(info->data + info->staged_len, - DPU_KMS_INFO_MAX_SIZE - info->staged_len, - info->start ? - "%c%c%c%c" : " %c%c%c%c", - (pixel_format >> 0) & 0xFF, - (pixel_format >> 8) & 0xFF, - (pixel_format >> 16) & 0xFF, - (pixel_format >> 24) & 0xFF); - } - - /* check if snprintf truncated the string */ - if ((info->staged_len + len) < DPU_KMS_INFO_MAX_SIZE) { - info->staged_len += len; - info->start = false; - } -} - -void dpu_kms_info_stop(struct dpu_kms_info *info) -{ - uint32_t len; - - if (info) { - /* insert final delimiter */ - len = snprintf(info->data + info->staged_len, - DPU_KMS_INFO_MAX_SIZE - info->staged_len, - "\n"); - - /* check if snprintf truncated the string */ - if ((info->staged_len + len) < DPU_KMS_INFO_MAX_SIZE) - info->len = info->staged_len + len; - } -} -- GitLab From f2c9a924c1acf42f692f2b5ac77531eea69460a3 Mon Sep 17 00:00:00 2001 From: Jordan Crouse <jcrouse@codeaurora.org> Date: Thu, 26 Jul 2018 14:30:13 -0600 Subject: [PATCH 1423/1506] drm/msm/disp/dpu: Remove unused functions from dpu_formats.c Remove dpu_format_get_block_size, dpu_format_get_framebuffer_size, dpu_set_scaler_v2 and dpu_copy_formats they are unused and unneeded. Signed-off-by: Jordan Crouse <jcrouse@codeauorora.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c | 41 ---------- drivers/gpu/drm/msm/disp/dpu1/dpu_formats.h | 31 -------- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c | 84 --------------------- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h | 10 --- 4 files changed, 166 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c index 8189539b06201..0cb00612f96f5 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c @@ -869,47 +869,6 @@ int dpu_format_get_plane_sizes( return _dpu_format_get_plane_sizes_linear(fmt, w, h, layout, pitches); } -int dpu_format_get_block_size(const struct dpu_format *fmt, - uint32_t *w, uint32_t *h) -{ - if (!fmt || !w || !h) { - DRM_ERROR("invalid pointer\n"); - return -EINVAL; - } - - /* TP10 is 96x96 and all others are 128x128 */ - if (DPU_FORMAT_IS_YUV(fmt) && DPU_FORMAT_IS_DX(fmt) && - (fmt->num_planes == 2) && fmt->unpack_tight) - *w = *h = 96; - else - *w = *h = 128; - - return 0; -} - -uint32_t dpu_format_get_framebuffer_size( - const uint32_t format, - const uint32_t width, - const uint32_t height, - const uint32_t *pitches, - const uint64_t modifiers) -{ - const struct dpu_format *fmt; - struct dpu_hw_fmt_layout layout; - - fmt = dpu_get_dpu_format_ext(format, modifiers); - if (!fmt) - return 0; - - if (!pitches) - return -EINVAL; - - if (dpu_format_get_plane_sizes(fmt, width, height, &layout, pitches)) - layout.total_size = 0; - - return layout.total_size; -} - static int _dpu_format_populate_addrs_ubwc( struct msm_gem_address_space *aspace, struct drm_framebuffer *fb, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.h index b55bfd13e2962..b3a6592f1a8a2 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.h @@ -72,19 +72,6 @@ int dpu_format_get_plane_sizes( struct dpu_hw_fmt_layout *layout, const uint32_t *pitches); -/** - * dpu_format_get_block_size - get block size of given format when - * operating in block mode - * @fmt: pointer to dpu_format - * @w: pointer to width of the block - * @h: pointer to height of the block - * - * Return: 0 if success; error oode otherwise - */ -int dpu_format_get_block_size(const struct dpu_format *fmt, - uint32_t *w, uint32_t *h); - -/** * dpu_format_check_modified_format - validate format and buffers for * dpu non-standard, i.e. modified format * @kms: kms driver @@ -115,22 +102,4 @@ int dpu_format_populate_layout( struct drm_framebuffer *fb, struct dpu_hw_fmt_layout *fmtl); -/** - * dpu_format_get_framebuffer_size - get framebuffer memory size - * @format: DRM pixel format - * @width: pixel width - * @height: pixel height - * @pitches: array of size [DPU_MAX_PLANES] to populate - * pitch for each plane - * @modifiers: drm modifier - * - * Return: memory size required for frame buffer - */ -uint32_t dpu_format_get_framebuffer_size( - const uint32_t format, - const uint32_t width, - const uint32_t height, - const uint32_t *pitches, - const uint64_t modifiers); - #endif /*_DPU_FORMATS_H */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c index 1ba571e94b328..4cabae480a7b4 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c @@ -92,59 +92,6 @@ u32 *dpu_hw_util_get_log_mask_ptr(void) return &dpu_hw_util_log_mask; } -void dpu_set_scaler_v2(struct dpu_hw_scaler3_cfg *cfg, - const struct dpu_drm_scaler_v2 *scale_v2) -{ - int i; - - cfg->enable = scale_v2->enable; - cfg->dir_en = scale_v2->dir_en; - - for (i = 0; i < DPU_MAX_PLANES; i++) { - cfg->init_phase_x[i] = scale_v2->init_phase_x[i]; - cfg->phase_step_x[i] = scale_v2->phase_step_x[i]; - cfg->init_phase_y[i] = scale_v2->init_phase_y[i]; - cfg->phase_step_y[i] = scale_v2->phase_step_y[i]; - - cfg->preload_x[i] = scale_v2->preload_x[i]; - cfg->preload_y[i] = scale_v2->preload_y[i]; - cfg->src_width[i] = scale_v2->src_width[i]; - cfg->src_height[i] = scale_v2->src_height[i]; - } - - cfg->dst_width = scale_v2->dst_width; - cfg->dst_height = scale_v2->dst_height; - - cfg->y_rgb_filter_cfg = scale_v2->y_rgb_filter_cfg; - cfg->uv_filter_cfg = scale_v2->uv_filter_cfg; - cfg->alpha_filter_cfg = scale_v2->alpha_filter_cfg; - cfg->blend_cfg = scale_v2->blend_cfg; - - cfg->lut_flag = scale_v2->lut_flag; - cfg->dir_lut_idx = scale_v2->dir_lut_idx; - cfg->y_rgb_cir_lut_idx = scale_v2->y_rgb_cir_lut_idx; - cfg->uv_cir_lut_idx = scale_v2->uv_cir_lut_idx; - cfg->y_rgb_sep_lut_idx = scale_v2->y_rgb_sep_lut_idx; - cfg->uv_sep_lut_idx = scale_v2->uv_sep_lut_idx; - - cfg->de.enable = scale_v2->de.enable; - cfg->de.sharpen_level1 = scale_v2->de.sharpen_level1; - cfg->de.sharpen_level2 = scale_v2->de.sharpen_level2; - cfg->de.clip = scale_v2->de.clip; - cfg->de.limit = scale_v2->de.limit; - cfg->de.thr_quiet = scale_v2->de.thr_quiet; - cfg->de.thr_dieout = scale_v2->de.thr_dieout; - cfg->de.thr_low = scale_v2->de.thr_low; - cfg->de.thr_high = scale_v2->de.thr_high; - cfg->de.prec_shift = scale_v2->de.prec_shift; - - for (i = 0; i < DPU_MAX_DE_CURVES; i++) { - cfg->de.adjust_a[i] = scale_v2->de.adjust_a[i]; - cfg->de.adjust_b[i] = scale_v2->de.adjust_b[i]; - cfg->de.adjust_c[i] = scale_v2->de.adjust_c[i]; - } -} - static void _dpu_hw_setup_scaler3_lut(struct dpu_hw_blk_reg_map *c, struct dpu_hw_scaler3_cfg *scaler3_cfg, u32 offset) { @@ -419,34 +366,3 @@ void dpu_hw_csc_setup(struct dpu_hw_blk_reg_map *c, DPU_REG_WRITE(c, csc_reg_off + 0x3c, data->csc_post_bv[1]); DPU_REG_WRITE(c, csc_reg_off + 0x40, data->csc_post_bv[2]); } - -/** - * _dpu_copy_formats - copy formats from src_list to dst_list - * @dst_list: pointer to destination list where to copy formats - * @dst_list_size: size of destination list - * @dst_list_pos: starting position on the list where to copy formats - * @src_list: pointer to source list where to copy formats from - * @src_list_size: size of source list - * Return: number of elements populated - */ -uint32_t dpu_copy_formats( - struct dpu_format_extended *dst_list, - uint32_t dst_list_size, - uint32_t dst_list_pos, - const struct dpu_format_extended *src_list, - uint32_t src_list_size) -{ - uint32_t cur_pos, i; - - if (!dst_list || !src_list || (dst_list_pos >= (dst_list_size - 1))) - return 0; - - for (i = 0, cur_pos = dst_list_pos; - (cur_pos < (dst_list_size - 1)) && (i < src_list_size) - && src_list[i].fourcc_format; ++i, ++cur_pos) - dst_list[cur_pos] = src_list[i]; - - dst_list[cur_pos].fourcc_format = 0; - - return i; -} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h index 42f1b228d342b..1240f505ca537 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h @@ -333,9 +333,6 @@ int dpu_reg_read(struct dpu_hw_blk_reg_map *c, u32 reg_off); void *dpu_hw_util_get_dir(void); -void dpu_set_scaler_v2(struct dpu_hw_scaler3_cfg *cfg, - const struct dpu_drm_scaler_v2 *scale_v2); - void dpu_hw_setup_scaler3(struct dpu_hw_blk_reg_map *c, struct dpu_hw_scaler3_cfg *scaler3_cfg, u32 scaler_offset, u32 scaler_version, @@ -348,11 +345,4 @@ void dpu_hw_csc_setup(struct dpu_hw_blk_reg_map *c, u32 csc_reg_off, struct dpu_csc_cfg *data, bool csc10); -uint32_t dpu_copy_formats( - struct dpu_format_extended *dst_list, - uint32_t dst_list_size, - uint32_t dst_list_pos, - const struct dpu_format_extended *src_list, - uint32_t src_list_size); - #endif /* _DPU_HW_UTIL_H */ -- GitLab From fba33cae6aa3eaa3627a603d62d4652f12308b8d Mon Sep 17 00:00:00 2001 From: Jordan Crouse <jcrouse@codeaurora.org> Date: Thu, 26 Jul 2018 14:30:14 -0600 Subject: [PATCH 1424/1506] drm/msm/disp/dpu: Mark a handful of functions as static Mark a number of static functions that are only unsed in the file that defines them and remove the prototypes from the headers where needed. Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 7 +++++-- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h | 6 ------ .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h | 14 -------------- .../drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c | 2 +- drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c | 2 +- drivers/gpu/drm/msm/disp/dpu1/dpu_formats.h | 17 ----------------- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c | 2 +- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c | 4 ++-- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c | 2 +- drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 2 +- drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c | 2 +- 11 files changed, 13 insertions(+), 47 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 5c0051af5e986..0bd3eda93e226 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -264,6 +264,9 @@ void dpu_encoder_helper_report_irq_timeout(struct dpu_encoder_phys *phys_enc, DPU_ENCODER_FRAME_EVENT_ERROR); } +static int dpu_encoder_helper_wait_event_timeout(int32_t drm_id, + int32_t hw_id, struct dpu_encoder_wait_info *info); + int dpu_encoder_helper_wait_for_irq(struct dpu_encoder_phys *phys_enc, enum dpu_intr_idx intr_idx, struct dpu_encoder_wait_info *wait_info) @@ -467,7 +470,7 @@ void dpu_encoder_get_hw_resources(struct drm_encoder *drm_enc, } } -void dpu_encoder_destroy(struct drm_encoder *drm_enc) +static void dpu_encoder_destroy(struct drm_encoder *drm_enc) { struct dpu_encoder_virt *dpu_enc = NULL; int i = 0; @@ -1516,7 +1519,7 @@ void dpu_encoder_helper_trigger_start(struct dpu_encoder_phys *phys_enc) } } -int dpu_encoder_helper_wait_event_timeout( +static int dpu_encoder_helper_wait_event_timeout( int32_t drm_id, int32_t hw_id, struct dpu_encoder_wait_info *info) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h index 204e538b0b745..60f809fc7c130 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h @@ -158,12 +158,6 @@ struct drm_encoder *dpu_encoder_init( int dpu_encoder_setup(struct drm_device *dev, struct drm_encoder *enc, struct msm_display_info *disp_info); -/** - * dpu_encoder_destroy - destroy previously initialized virtual encoder - * @drm_enc: Pointer to previously created drm encoder structure - */ -void dpu_encoder_destroy(struct drm_encoder *drm_enc); - /** * dpu_encoder_prepare_commit - prepare encoder at the very beginning of an * atomic commit, before any registers are written diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h index dacec1c8eeebb..c7df8aad66137 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h @@ -355,20 +355,6 @@ struct dpu_encoder_phys *dpu_encoder_phys_cmd_init( */ void dpu_encoder_helper_trigger_start(struct dpu_encoder_phys *phys_enc); -/** - * dpu_encoder_helper_wait_event_timeout - wait for event with timeout - * taking into account that jiffies may jump between reads leading to - * incorrectly detected timeouts. Prevent failure in this scenario by - * making sure that elapsed time during wait is valid. - * @drm_id: drm object id for logging - * @hw_id: hw instance id for logging - * @info: wait info structure - */ -int dpu_encoder_helper_wait_event_timeout( - int32_t drm_id, - int32_t hw_id, - struct dpu_encoder_wait_info *info); - /** * dpu_encoder_helper_hw_reset - issue ctl hw reset * This helper function may be optionally specified by physical diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c index e6d02c6947b4f..3084675ed4257 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c @@ -349,7 +349,7 @@ static int dpu_encoder_phys_cmd_control_vblank_irq( return ret; } -void dpu_encoder_phys_cmd_irq_control(struct dpu_encoder_phys *phys_enc, +static void dpu_encoder_phys_cmd_irq_control(struct dpu_encoder_phys *phys_enc, bool enable) { struct dpu_encoder_phys_cmd *cmd_enc; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c index 0cb00612f96f5..bfcd165e96dfe 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c @@ -846,7 +846,7 @@ static int _dpu_format_get_plane_sizes_linear( return 0; } -int dpu_format_get_plane_sizes( +static int dpu_format_get_plane_sizes( const struct dpu_format *fmt, const uint32_t w, const uint32_t h, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.h index b3a6592f1a8a2..a54451d8d0111 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.h @@ -55,23 +55,6 @@ uint32_t dpu_populate_formats( uint32_t pixel_formats_max); /** - * dpu_format_get_plane_sizes - calculate size and layout of given buffer format - * @fmt: pointer to dpu_format - * @w: width of the buffer - * @h: height of the buffer - * @layout: layout of the buffer - * @pitches: array of size [DPU_MAX_PLANES] to populate - * pitch for each plane - * - * Return: size of the buffer - */ -int dpu_format_get_plane_sizes( - const struct dpu_format *fmt, - const uint32_t w, - const uint32_t h, - struct dpu_hw_fmt_layout *layout, - const uint32_t *pitches); - * dpu_format_check_modified_format - validate format and buffers for * dpu non-standard, i.e. modified format * @kms: kms driver diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c index 1793cfd29a070..44ee06398b1dd 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c @@ -449,7 +449,7 @@ static struct dpu_perf_cfg sdm845_perf_data = { * sdm845_cfg_init(): populate sdm845 dpu sub-blocks reg offsets * and instance counts. */ -void sdm845_cfg_init(struct dpu_mdss_cfg *dpu_cfg) +static void sdm845_cfg_init(struct dpu_mdss_cfg *dpu_cfg) { *dpu_cfg = (struct dpu_mdss_cfg){ .caps = &sdm845_dpu_caps, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c index da6f0609be5f0..554874ba0c3b7 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c @@ -217,7 +217,7 @@ static int dpu_hw_cdm_setup_cdwn(struct dpu_hw_cdm *ctx, return 0; } -int dpu_hw_cdm_enable(struct dpu_hw_cdm *ctx, +static int dpu_hw_cdm_enable(struct dpu_hw_cdm *ctx, struct dpu_hw_cdm_cfg *cdm) { struct dpu_hw_blk_reg_map *c = &ctx->hw; @@ -249,7 +249,7 @@ int dpu_hw_cdm_enable(struct dpu_hw_cdm *ctx, return 0; } -void dpu_hw_cdm_disable(struct dpu_hw_cdm *ctx) +static void dpu_hw_cdm_disable(struct dpu_hw_cdm *ctx) { struct cdm_output_cfg cdm_cfg = { 0 }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c index 42fc72cf48dd0..db2798e862fcb 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c @@ -275,7 +275,7 @@ static void dpu_hw_get_safe_status(struct dpu_hw_mdp *mdp, status->sspp[SSPP_CURSOR1] = (value >> 26) & 0x1; } -void dpu_hw_reset_ubwc(struct dpu_hw_mdp *mdp, struct dpu_mdss_cfg *m) +static void dpu_hw_reset_ubwc(struct dpu_hw_mdp *mdp, struct dpu_mdss_cfg *m) { struct dpu_hw_blk_reg_map c; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index 1c0838801e784..7dd6bd2d6d378 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -819,7 +819,7 @@ static int dpu_kms_pm_resume(struct device *dev) return 0; } -void _dpu_kms_set_encoder_mode(struct msm_kms *kms, +static void _dpu_kms_set_encoder_mode(struct msm_kms *kms, struct drm_encoder *encoder, bool cmd_mode) { diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c index 6dfc26698a09b..9e533b86682c6 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c @@ -115,7 +115,7 @@ static int _dpu_mdss_irq_domain_add(struct dpu_mdss *dpu_mdss) return 0; } -int _dpu_mdss_irq_domain_fini(struct dpu_mdss *dpu_mdss) +static int _dpu_mdss_irq_domain_fini(struct dpu_mdss *dpu_mdss) { if (dpu_mdss->irq_controller.domain) { irq_domain_remove(dpu_mdss->irq_controller.domain); -- GitLab From 6b0a180ede4884ea5cdd30ca939ddf43ef11cdac Mon Sep 17 00:00:00 2001 From: Jeykumar Sankaran <jsanka@codeaurora.org> Date: Fri, 20 Jul 2018 16:42:52 -0400 Subject: [PATCH 1425/1506] dt-bindings: msm/dsi: Add mdp transfer time to msm dsi binding Adds mdp transfer time to msm dsi binding Changes in v3: - Added Rob's R-b Reviewed-by: Rob Herring <robh@kernel.org> Signed-off-by: Jeykumar Sankaran <jsanka@codeaurora.org> Signed-off-by: Rajesh Yadav <ryadav@codeaurora.org> Signed-off-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- .../devicetree/bindings/display/msm/dsi.txt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Documentation/devicetree/bindings/display/msm/dsi.txt b/Documentation/devicetree/bindings/display/msm/dsi.txt index 518e9cdf0d4bf..d22237a88eae7 100644 --- a/Documentation/devicetree/bindings/display/msm/dsi.txt +++ b/Documentation/devicetree/bindings/display/msm/dsi.txt @@ -121,6 +121,20 @@ Required properties: Optional properties: - qcom,dsi-phy-regulator-ldo-mode: Boolean value indicating if the LDO mode PHY regulator is wanted. +- qcom,mdss-mdp-transfer-time-us: Specifies the dsi transfer time for command mode + panels in microseconds. Driver uses this number to adjust + the clock rate according to the expected transfer time. + Increasing this value would slow down the mdp processing + and can result in slower performance. + Decreasing this value can speed up the mdp processing, + but this can also impact power consumption. + As a rule this time should not be higher than the time + that would be expected with the processing at the + dsi link rate since anyways this would be the maximum + transfer time that could be achieved. + If ping pong split is enabled, this time should not be higher + than two times the dsi link rate time. + If the property is not specified, then the default value is 14000 us. [1] Documentation/devicetree/bindings/clock/clock-bindings.txt [2] Documentation/devicetree/bindings/graph.txt @@ -171,6 +185,8 @@ Example: qcom,master-dsi; qcom,sync-dual-dsi; + qcom,mdss-mdp-transfer-time-us = <12000>; + pinctrl-names = "default", "sleep"; pinctrl-0 = <&dsi_active>; pinctrl-1 = <&dsi_suspend>; -- GitLab From a7663a79343658f9362dc0655f1a06723c7014e3 Mon Sep 17 00:00:00 2001 From: Jeykumar Sankaran <jsanka@codeaurora.org> Date: Fri, 20 Jul 2018 16:43:09 -0400 Subject: [PATCH 1426/1506] dt-bindings: msm/disp: Add bindings for Snapdragon 845 DPU Adds bindings for Snapdragon 845 display processing unit Changes in v2: - Use SoC specific compatibles for mdss and dpu (Rob Herring) - Use assigned-clocks to set initial clock frequency (Rob Herring) Changes in v3 (all suggested by Rob Herring): - Rename mdss_phys to mdss - Correct description for clocks/assigned-clocks - Rename mdp_phys to mdp - Rename vbif_phys to vbif - Remove redundant interrupt-parent from mdss_mdp - Fully specify 'ranges' and use relative reg address in mdss_mdp Cc: Rob Herring <robh+dt@kernel.org> Signed-off-by: Jeykumar Sankaran <jsanka@codeaurora.org> Signed-off-by: Rajesh Yadav <ryadav@codeaurora.org> Signed-off-by: Sean Paul <seanpaul@chromium.org> Reviewed-by: Rob Herring <robh@kernel.org> Signed-off-by: Rob Clark <robdclark@gmail.com> --- .../devicetree/bindings/display/msm/dpu.txt | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/msm/dpu.txt diff --git a/Documentation/devicetree/bindings/display/msm/dpu.txt b/Documentation/devicetree/bindings/display/msm/dpu.txt new file mode 100644 index 0000000000000..ad2e8830324e2 --- /dev/null +++ b/Documentation/devicetree/bindings/display/msm/dpu.txt @@ -0,0 +1,131 @@ +Qualcomm Technologies, Inc. DPU KMS + +Description: + +Device tree bindings for MSM Mobile Display Subsytem(MDSS) that encapsulates +sub-blocks like DPU display controller, DSI and DP interfaces etc. +The DPU display controller is found in SDM845 SoC. + +MDSS: +Required properties: +- compatible: "qcom,sdm845-mdss" +- reg: physical base address and length of contoller's registers. +- reg-names: register region names. The following region is required: + * "mdss" +- power-domains: a power domain consumer specifier according to + Documentation/devicetree/bindings/power/power_domain.txt +- clocks: list of clock specifiers for clocks needed by the device. +- clock-names: device clock names, must be in same order as clocks property. + The following clocks are required: + * "iface" + * "bus" + * "core" +- interrupts: interrupt signal from MDSS. +- interrupt-controller: identifies the node as an interrupt controller. +- #interrupt-cells: specifies the number of cells needed to encode an interrupt + source, should be 1. +- iommus: phandle of iommu device node. +- #address-cells: number of address cells for the MDSS children. Should be 1. +- #size-cells: Should be 1. +- ranges: parent bus address space is the same as the child bus address space. + +Optional properties: +- assigned-clocks: list of clock specifiers for clocks needing rate assignment +- assigned-clock-rates: list of clock frequencies sorted in the same order as + the assigned-clocks property. + +MDP: +Required properties: +- compatible: "qcom,sdm845-dpu" +- reg: physical base address and length of controller's registers. +- reg-names : register region names. The following region is required: + * "mdp" + * "vbif" +- clocks: list of clock specifiers for clocks needed by the device. +- clock-names: device clock names, must be in same order as clocks property. + The following clocks are required. + * "bus" + * "iface" + * "core" + * "vsync" +- interrupts: interrupt line from DPU to MDSS. +- ports: contains the list of output ports from DPU device. These ports connect + to interfaces that are external to the DPU hardware, such as DSI, DP etc. + + Each output port contains an endpoint that describes how it is connected to an + external interface. These are described by the standard properties documented + here: + Documentation/devicetree/bindings/graph.txt + Documentation/devicetree/bindings/media/video-interfaces.txt + + Port 0 -> DPU_INTF1 (DSI1) + Port 1 -> DPU_INTF2 (DSI2) + +Optional properties: +- assigned-clocks: list of clock specifiers for clocks needing rate assignment +- assigned-clock-rates: list of clock frequencies sorted in the same order as + the assigned-clocks property. + +Example: + + mdss: mdss@ae00000 { + compatible = "qcom,sdm845-mdss"; + reg = <0xae00000 0x1000>; + reg-names = "mdss"; + + power-domains = <&clock_dispcc 0>; + + clocks = <&gcc GCC_DISP_AHB_CLK>, <&gcc GCC_DISP_AXI_CLK>, + <&clock_dispcc DISP_CC_MDSS_MDP_CLK>; + clock-names = "iface", "bus", "core"; + + assigned-clocks = <&clock_dispcc DISP_CC_MDSS_MDP_CLK>; + assigned-clock-rates = <300000000>; + + interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>; + interrupt-controller; + #interrupt-cells = <1>; + + iommus = <&apps_iommu 0>; + + #address-cells = <2>; + #size-cells = <1>; + ranges = <0 0 0xae00000 0xb2008>; + + mdss_mdp: mdp@ae01000 { + compatible = "qcom,sdm845-dpu"; + reg = <0 0x1000 0x8f000>, <0 0xb0000 0x2008>; + reg-names = "mdp", "vbif"; + + clocks = <&clock_dispcc DISP_CC_MDSS_AHB_CLK>, + <&clock_dispcc DISP_CC_MDSS_AXI_CLK>, + <&clock_dispcc DISP_CC_MDSS_MDP_CLK>, + <&clock_dispcc DISP_CC_MDSS_VSYNC_CLK>; + clock-names = "iface", "bus", "core", "vsync"; + + assigned-clocks = <&clock_dispcc DISP_CC_MDSS_MDP_CLK>, + <&clock_dispcc DISP_CC_MDSS_VSYNC_CLK>; + assigned-clock-rates = <0 0 300000000 19200000>; + + interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dpu_intf1_out: endpoint { + remote-endpoint = <&dsi0_in>; + }; + }; + + port@1 { + reg = <1>; + dpu_intf2_out: endpoint { + remote-endpoint = <&dsi1_in>; + }; + }; + }; + }; + }; -- GitLab From 8456b99c16d193c4c3b7df305cf431e027f0189c Mon Sep 17 00:00:00 2001 From: Mikulas Patocka <mpatocka@redhat.com> Date: Sun, 3 Jun 2018 16:40:55 +0200 Subject: [PATCH 1427/1506] udl-kms: change down_interruptible to down If we leave urbs around, it causes not only leak, but also memory corruption. This patch fixes the function udl_free_urb_list, so that it always waits for all urbs that are in progress. Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Cc: stable@vger.kernel.org Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/udl/udl_main.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c index d518de8f496bc..1239decd46ffb 100644 --- a/drivers/gpu/drm/udl/udl_main.c +++ b/drivers/gpu/drm/udl/udl_main.c @@ -170,18 +170,13 @@ static void udl_free_urb_list(struct drm_device *dev) struct list_head *node; struct urb_node *unode; struct urb *urb; - int ret; unsigned long flags; DRM_DEBUG("Waiting for completes and freeing all render urbs\n"); /* keep waiting and freeing, until we've got 'em all */ while (count--) { - - /* Getting interrupted means a leak, but ok at shutdown*/ - ret = down_interruptible(&udl->urbs.limit_sem); - if (ret) - break; + down(&udl->urbs.limit_sem); spin_lock_irqsave(&udl->urbs.lock, flags); -- GitLab From 542bb9788a1f485eb1a2229178f665d8ea166156 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka <mpatocka@redhat.com> Date: Sun, 3 Jun 2018 16:40:56 +0200 Subject: [PATCH 1428/1506] udl-kms: handle allocation failure Allocations larger than PAGE_ALLOC_COSTLY_ORDER are unreliable and they may fail anytime. This patch fixes the udl kms driver so that when a large alloactions fails, it tries to do multiple smaller allocations. Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Cc: stable@vger.kernel.org Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/udl/udl_main.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c index 1239decd46ffb..7e9ad926926ae 100644 --- a/drivers/gpu/drm/udl/udl_main.c +++ b/drivers/gpu/drm/udl/udl_main.c @@ -200,17 +200,22 @@ static void udl_free_urb_list(struct drm_device *dev) static int udl_alloc_urb_list(struct drm_device *dev, int count, size_t size) { struct udl_device *udl = dev->dev_private; - int i = 0; struct urb *urb; struct urb_node *unode; char *buf; + size_t wanted_size = count * size; spin_lock_init(&udl->urbs.lock); +retry: udl->urbs.size = size; INIT_LIST_HEAD(&udl->urbs.list); - while (i < count) { + sema_init(&udl->urbs.limit_sem, 0); + udl->urbs.count = 0; + udl->urbs.available = 0; + + while (udl->urbs.count * size < wanted_size) { unode = kzalloc(sizeof(struct urb_node), GFP_KERNEL); if (!unode) break; @@ -226,11 +231,16 @@ static int udl_alloc_urb_list(struct drm_device *dev, int count, size_t size) } unode->urb = urb; - buf = usb_alloc_coherent(udl->udev, MAX_TRANSFER, GFP_KERNEL, + buf = usb_alloc_coherent(udl->udev, size, GFP_KERNEL, &urb->transfer_dma); if (!buf) { kfree(unode); usb_free_urb(urb); + if (size > PAGE_SIZE) { + size /= 2; + udl_free_urb_list(dev); + goto retry; + } break; } @@ -241,16 +251,14 @@ static int udl_alloc_urb_list(struct drm_device *dev, int count, size_t size) list_add_tail(&unode->entry, &udl->urbs.list); - i++; + up(&udl->urbs.limit_sem); + udl->urbs.count++; + udl->urbs.available++; } - sema_init(&udl->urbs.limit_sem, i); - udl->urbs.count = i; - udl->urbs.available = i; - - DRM_DEBUG("allocated %d %d byte urbs\n", i, (int) size); + DRM_DEBUG("allocated %d %d byte urbs\n", udl->urbs.count, (int) size); - return i; + return udl->urbs.count; } struct urb *udl_get_urb(struct drm_device *dev) -- GitLab From 09a00abe3a9941c2715ca83eb88172cd2f54d8fd Mon Sep 17 00:00:00 2001 From: Mikulas Patocka <mpatocka@redhat.com> Date: Sun, 3 Jun 2018 16:40:57 +0200 Subject: [PATCH 1429/1506] udl-kms: fix crash due to uninitialized memory We must use kzalloc when allocating the fb_deferred_io structure. Otherwise, the field first_io is undefined and it causes a crash. Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Cc: stable@vger.kernel.org Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/udl/udl_fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c index d5583190f3e44..c3f5867dac914 100644 --- a/drivers/gpu/drm/udl/udl_fb.c +++ b/drivers/gpu/drm/udl/udl_fb.c @@ -221,7 +221,7 @@ static int udl_fb_open(struct fb_info *info, int user) struct fb_deferred_io *fbdefio; - fbdefio = kmalloc(sizeof(struct fb_deferred_io), GFP_KERNEL); + fbdefio = kzalloc(sizeof(struct fb_deferred_io), GFP_KERNEL); if (fbdefio) { fbdefio->delay = DL_DEFIO_WRITE_DELAY; -- GitLab From 91ba11fb7d7ca0a3bbe8a512e65e666e2ec1e889 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka <mpatocka@redhat.com> Date: Sun, 3 Jun 2018 16:41:00 +0200 Subject: [PATCH 1430/1506] udl-kms: avoid division Division is slow, so it shouldn't be done by the pixel generating code. The driver supports only 2 or 4 bytes per pixel, so we can replace division with a shift. Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Cc: stable@vger.kernel.org Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/udl/udl_drv.h | 2 +- drivers/gpu/drm/udl/udl_fb.c | 15 +++++++----- drivers/gpu/drm/udl/udl_transfer.c | 39 +++++++++++++++--------------- 3 files changed, 30 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h index 55c0cc3091981..7588a9eb0ee03 100644 --- a/drivers/gpu/drm/udl/udl_drv.h +++ b/drivers/gpu/drm/udl/udl_drv.h @@ -112,7 +112,7 @@ udl_fb_user_fb_create(struct drm_device *dev, struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd); -int udl_render_hline(struct drm_device *dev, int bpp, struct urb **urb_ptr, +int udl_render_hline(struct drm_device *dev, int log_bpp, struct urb **urb_ptr, const char *front, char **urb_buf_ptr, u32 byte_offset, u32 device_byte_offset, u32 byte_width, int *ident_ptr, int *sent_ptr); diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c index c3f5867dac914..8746eeeec44d9 100644 --- a/drivers/gpu/drm/udl/udl_fb.c +++ b/drivers/gpu/drm/udl/udl_fb.c @@ -90,7 +90,10 @@ int udl_handle_damage(struct udl_framebuffer *fb, int x, int y, int bytes_identical = 0; struct urb *urb; int aligned_x; - int bpp = fb->base.format->cpp[0]; + int log_bpp; + + BUG_ON(!is_power_of_2(fb->base.format->cpp[0])); + log_bpp = __ffs(fb->base.format->cpp[0]); if (!fb->active_16) return 0; @@ -125,12 +128,12 @@ int udl_handle_damage(struct udl_framebuffer *fb, int x, int y, for (i = y; i < y + height ; i++) { const int line_offset = fb->base.pitches[0] * i; - const int byte_offset = line_offset + (x * bpp); - const int dev_byte_offset = (fb->base.width * bpp * i) + (x * bpp); - if (udl_render_hline(dev, bpp, &urb, + const int byte_offset = line_offset + (x << log_bpp); + const int dev_byte_offset = (fb->base.width * i + x) << log_bpp; + if (udl_render_hline(dev, log_bpp, &urb, (char *) fb->obj->vmapping, &cmd, byte_offset, dev_byte_offset, - width * bpp, + width << log_bpp, &bytes_identical, &bytes_sent)) goto error; } @@ -149,7 +152,7 @@ int udl_handle_damage(struct udl_framebuffer *fb, int x, int y, error: atomic_add(bytes_sent, &udl->bytes_sent); atomic_add(bytes_identical, &udl->bytes_identical); - atomic_add(width*height*bpp, &udl->bytes_rendered); + atomic_add((width * height) << log_bpp, &udl->bytes_rendered); end_cycles = get_cycles(); atomic_add(((unsigned int) ((end_cycles - start_cycles) >> 10)), /* Kcycles */ diff --git a/drivers/gpu/drm/udl/udl_transfer.c b/drivers/gpu/drm/udl/udl_transfer.c index b992644c17e6b..f3331d33547a1 100644 --- a/drivers/gpu/drm/udl/udl_transfer.c +++ b/drivers/gpu/drm/udl/udl_transfer.c @@ -83,12 +83,12 @@ static inline u16 pixel32_to_be16(const uint32_t pixel) ((pixel >> 8) & 0xf800)); } -static inline u16 get_pixel_val16(const uint8_t *pixel, int bpp) +static inline u16 get_pixel_val16(const uint8_t *pixel, int log_bpp) { - u16 pixel_val16 = 0; - if (bpp == 2) + u16 pixel_val16; + if (log_bpp == 1) pixel_val16 = *(const uint16_t *)pixel; - else if (bpp == 4) + else pixel_val16 = pixel32_to_be16(*(const uint32_t *)pixel); return pixel_val16; } @@ -125,8 +125,9 @@ static void udl_compress_hline16( const u8 *const pixel_end, uint32_t *device_address_ptr, uint8_t **command_buffer_ptr, - const uint8_t *const cmd_buffer_end, int bpp) + const uint8_t *const cmd_buffer_end, int log_bpp) { + const int bpp = 1 << log_bpp; const u8 *pixel = *pixel_start_ptr; uint32_t dev_addr = *device_address_ptr; uint8_t *cmd = *command_buffer_ptr; @@ -153,12 +154,12 @@ static void udl_compress_hline16( raw_pixels_count_byte = cmd++; /* we'll know this later */ raw_pixel_start = pixel; - cmd_pixel_end = pixel + min3(MAX_CMD_PIXELS + 1UL, - (unsigned long)(pixel_end - pixel) / bpp, - (unsigned long)(cmd_buffer_end - 1 - cmd) / 2) * bpp; + cmd_pixel_end = pixel + (min3(MAX_CMD_PIXELS + 1UL, + (unsigned long)(pixel_end - pixel) >> log_bpp, + (unsigned long)(cmd_buffer_end - 1 - cmd) / 2) << log_bpp); prefetch_range((void *) pixel, cmd_pixel_end - pixel); - pixel_val16 = get_pixel_val16(pixel, bpp); + pixel_val16 = get_pixel_val16(pixel, log_bpp); while (pixel < cmd_pixel_end) { const u8 *const start = pixel; @@ -170,7 +171,7 @@ static void udl_compress_hline16( pixel += bpp; while (pixel < cmd_pixel_end) { - pixel_val16 = get_pixel_val16(pixel, bpp); + pixel_val16 = get_pixel_val16(pixel, log_bpp); if (pixel_val16 != repeating_pixel_val16) break; pixel += bpp; @@ -179,10 +180,10 @@ static void udl_compress_hline16( if (unlikely(pixel > start + bpp)) { /* go back and fill in raw pixel count */ *raw_pixels_count_byte = (((start - - raw_pixel_start) / bpp) + 1) & 0xFF; + raw_pixel_start) >> log_bpp) + 1) & 0xFF; /* immediately after raw data is repeat byte */ - *cmd++ = (((pixel - start) / bpp) - 1) & 0xFF; + *cmd++ = (((pixel - start) >> log_bpp) - 1) & 0xFF; /* Then start another raw pixel span */ raw_pixel_start = pixel; @@ -192,14 +193,14 @@ static void udl_compress_hline16( if (pixel > raw_pixel_start) { /* finalize last RAW span */ - *raw_pixels_count_byte = ((pixel-raw_pixel_start) / bpp) & 0xFF; + *raw_pixels_count_byte = ((pixel - raw_pixel_start) >> log_bpp) & 0xFF; } else { /* undo unused byte */ cmd--; } - *cmd_pixels_count_byte = ((pixel - cmd_pixel_start) / bpp) & 0xFF; - dev_addr += ((pixel - cmd_pixel_start) / bpp) * 2; + *cmd_pixels_count_byte = ((pixel - cmd_pixel_start) >> log_bpp) & 0xFF; + dev_addr += ((pixel - cmd_pixel_start) >> log_bpp) * 2; } if (cmd_buffer_end <= MIN_RLX_CMD_BYTES + cmd) { @@ -222,19 +223,19 @@ static void udl_compress_hline16( * (that we can only write to, slowly, and can never read), and (optionally) * our shadow copy that tracks what's been sent to that hardware buffer. */ -int udl_render_hline(struct drm_device *dev, int bpp, struct urb **urb_ptr, +int udl_render_hline(struct drm_device *dev, int log_bpp, struct urb **urb_ptr, const char *front, char **urb_buf_ptr, u32 byte_offset, u32 device_byte_offset, u32 byte_width, int *ident_ptr, int *sent_ptr) { const u8 *line_start, *line_end, *next_pixel; - u32 base16 = 0 + (device_byte_offset / bpp) * 2; + u32 base16 = 0 + (device_byte_offset >> log_bpp) * 2; struct urb *urb = *urb_ptr; u8 *cmd = *urb_buf_ptr; u8 *cmd_end = (u8 *) urb->transfer_buffer + urb->transfer_buffer_length; - BUG_ON(!(bpp == 2 || bpp == 4)); + BUG_ON(!(log_bpp == 1 || log_bpp == 2)); line_start = (u8 *) (front + byte_offset); next_pixel = line_start; @@ -244,7 +245,7 @@ int udl_render_hline(struct drm_device *dev, int bpp, struct urb **urb_ptr, udl_compress_hline16(&next_pixel, line_end, &base16, - (u8 **) &cmd, (u8 *) cmd_end, bpp); + (u8 **) &cmd, (u8 *) cmd_end, log_bpp); if (cmd >= cmd_end) { int len = cmd - (u8 *) urb->transfer_buffer; -- GitLab From 58cba7c222e8c87bb6b61fcba21d1536145221b0 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka <mpatocka@redhat.com> Date: Sun, 3 Jun 2018 16:41:01 +0200 Subject: [PATCH 1431/1506] udl-kms: avoid prefetch Modern processors can detect linear memory accesses and prefetch data automatically, so there's no need to use prefetch. Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/udl/udl_transfer.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/gpu/drm/udl/udl_transfer.c b/drivers/gpu/drm/udl/udl_transfer.c index f3331d33547a1..ce87661e544f7 100644 --- a/drivers/gpu/drm/udl/udl_transfer.c +++ b/drivers/gpu/drm/udl/udl_transfer.c @@ -13,7 +13,6 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/fb.h> -#include <linux/prefetch.h> #include <asm/unaligned.h> #include <drm/drmP.h> @@ -51,9 +50,6 @@ static int udl_trim_hline(const u8 *bback, const u8 **bfront, int *width_bytes) int start = width; int end = width; - prefetch((void *) front); - prefetch((void *) back); - for (j = 0; j < width; j++) { if (back[j] != front[j]) { start = j; @@ -140,8 +136,6 @@ static void udl_compress_hline16( const u8 *cmd_pixel_start, *cmd_pixel_end = NULL; uint16_t pixel_val16; - prefetchw((void *) cmd); /* pull in one cache line at least */ - *cmd++ = 0xaf; *cmd++ = 0x6b; *cmd++ = (uint8_t) ((dev_addr >> 16) & 0xFF); @@ -158,7 +152,6 @@ static void udl_compress_hline16( (unsigned long)(pixel_end - pixel) >> log_bpp, (unsigned long)(cmd_buffer_end - 1 - cmd) / 2) << log_bpp); - prefetch_range((void *) pixel, cmd_pixel_end - pixel); pixel_val16 = get_pixel_val16(pixel, log_bpp); while (pixel < cmd_pixel_end) { -- GitLab From c2f53119b410047e5d97de2a5ec74157d2e58986 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka <mpatocka@redhat.com> Date: Sun, 3 Jun 2018 16:41:02 +0200 Subject: [PATCH 1432/1506] udl-kms: use spin_lock_irq instead of spin_lock_irqsave spin_lock_irqsave and spin_unlock_irqrestore is inteded to be called from a context where it is unknown if interrupts are enabled or disabled (such as interrupt handlers). From a process context, we should call spin_lock_irq and spin_unlock_irq, that avoids the costly pushf and popf instructions. Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/udl/udl_main.c | 10 ++++------ drivers/gpu/drm/udl/udl_modeset.c | 5 ++--- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c index 7e9ad926926ae..f455f095a1468 100644 --- a/drivers/gpu/drm/udl/udl_main.c +++ b/drivers/gpu/drm/udl/udl_main.c @@ -170,7 +170,6 @@ static void udl_free_urb_list(struct drm_device *dev) struct list_head *node; struct urb_node *unode; struct urb *urb; - unsigned long flags; DRM_DEBUG("Waiting for completes and freeing all render urbs\n"); @@ -178,12 +177,12 @@ static void udl_free_urb_list(struct drm_device *dev) while (count--) { down(&udl->urbs.limit_sem); - spin_lock_irqsave(&udl->urbs.lock, flags); + spin_lock_irq(&udl->urbs.lock); node = udl->urbs.list.next; /* have reserved one with sem */ list_del_init(node); - spin_unlock_irqrestore(&udl->urbs.lock, flags); + spin_unlock_irq(&udl->urbs.lock); unode = list_entry(node, struct urb_node, entry); urb = unode->urb; @@ -268,7 +267,6 @@ struct urb *udl_get_urb(struct drm_device *dev) struct list_head *entry; struct urb_node *unode; struct urb *urb = NULL; - unsigned long flags; /* Wait for an in-flight buffer to complete and get re-queued */ ret = down_timeout(&udl->urbs.limit_sem, GET_URB_TIMEOUT); @@ -279,14 +277,14 @@ struct urb *udl_get_urb(struct drm_device *dev) goto error; } - spin_lock_irqsave(&udl->urbs.lock, flags); + spin_lock_irq(&udl->urbs.lock); BUG_ON(list_empty(&udl->urbs.list)); /* reserved one with limit_sem */ entry = udl->urbs.list.next; list_del_init(entry); udl->urbs.available--; - spin_unlock_irqrestore(&udl->urbs.lock, flags); + spin_unlock_irq(&udl->urbs.lock); unode = list_entry(entry, struct urb_node, entry); urb = unode->urb; diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c index 5bcae76497959..98c6a58bcb079 100644 --- a/drivers/gpu/drm/udl/udl_modeset.c +++ b/drivers/gpu/drm/udl/udl_modeset.c @@ -366,7 +366,6 @@ static int udl_crtc_page_flip(struct drm_crtc *crtc, { struct udl_framebuffer *ufb = to_udl_fb(fb); struct drm_device *dev = crtc->dev; - unsigned long flags; struct drm_framebuffer *old_fb = crtc->primary->fb; if (old_fb) { @@ -377,10 +376,10 @@ static int udl_crtc_page_flip(struct drm_crtc *crtc, udl_handle_damage(ufb, 0, 0, fb->width, fb->height); - spin_lock_irqsave(&dev->event_lock, flags); + spin_lock_irq(&dev->event_lock); if (event) drm_crtc_send_vblank_event(crtc, event); - spin_unlock_irqrestore(&dev->event_lock, flags); + spin_unlock_irq(&dev->event_lock); crtc->primary->fb = fb; return 0; -- GitLab From 90991209837ab619555a46a97a88dead7a960d2d Mon Sep 17 00:00:00 2001 From: Mikulas Patocka <mpatocka@redhat.com> Date: Sun, 3 Jun 2018 16:41:03 +0200 Subject: [PATCH 1433/1506] udl-kms: dont spam the syslog with debug messages The udl kms driver writes messages to the syslog whenever some application opens or closes /dev/fb0 and whenever the user switches between the Xserver and the console. This patch changes the priority of these messages to debug. Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> --- drivers/gpu/drm/udl/udl_fb.c | 6 +++--- drivers/gpu/drm/udl/udl_modeset.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c index 8746eeeec44d9..dbb62f6eb48a5 100644 --- a/drivers/gpu/drm/udl/udl_fb.c +++ b/drivers/gpu/drm/udl/udl_fb.c @@ -178,7 +178,7 @@ static int udl_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) pos = (unsigned long)info->fix.smem_start + offset; - pr_notice("mmap() framebuffer addr:%lu size:%lu\n", + pr_debug("mmap() framebuffer addr:%lu size:%lu\n", pos, size); /* We don't want the framebuffer to be mapped encrypted */ @@ -236,7 +236,7 @@ static int udl_fb_open(struct fb_info *info, int user) } #endif - pr_notice("open /dev/fb%d user=%d fb_info=%p count=%d\n", + pr_debug("open /dev/fb%d user=%d fb_info=%p count=%d\n", info->node, user, info, ufbdev->fb_count); return 0; @@ -261,7 +261,7 @@ static int udl_fb_release(struct fb_info *info, int user) } #endif - pr_warn("released /dev/fb%d user=%d count=%d\n", + pr_debug("released /dev/fb%d user=%d count=%d\n", info->node, user, ufbdev->fb_count); return 0; diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c index 98c6a58bcb079..7e37765cf5acd 100644 --- a/drivers/gpu/drm/udl/udl_modeset.c +++ b/drivers/gpu/drm/udl/udl_modeset.c @@ -243,7 +243,7 @@ static int udl_crtc_write_mode_to_hw(struct drm_crtc *crtc) memcpy(buf, udl->mode_buf, udl->mode_buf_len); retval = udl_submit_urb(dev, urb, udl->mode_buf_len); - DRM_INFO("write mode info %d\n", udl->mode_buf_len); + DRM_DEBUG("write mode info %d\n", udl->mode_buf_len); return retval; } -- GitLab From 5c7e5a22c126e4d7839e6bdcc05b3c4dfa945a72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org> Date: Fri, 8 Dec 2017 20:37:34 +0100 Subject: [PATCH 1434/1506] drm/arm/hdlcd: Use drm_mode_config_helper_suspend/resume() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace driver's code with the generic helpers that do the same thing including the NULL check. Cc: Liviu Dudau <liviu.dudau@arm.com> Cc: Brian Starkey <brian.starkey@arm.com> Signed-off-by: Noralf Trønnes <noralf@tronnes.org> Signed-off-by: Liviu Dudau <liviu.dudau@arm.com> --- drivers/gpu/drm/arm/hdlcd_drv.c | 25 +++---------------------- drivers/gpu/drm/arm/hdlcd_drv.h | 1 - 2 files changed, 3 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/arm/hdlcd_drv.c b/drivers/gpu/drm/arm/hdlcd_drv.c index feaa8bc3d7b76..9800a9e388efe 100644 --- a/drivers/gpu/drm/arm/hdlcd_drv.c +++ b/drivers/gpu/drm/arm/hdlcd_drv.c @@ -27,6 +27,7 @@ #include <drm/drm_fb_cma_helper.h> #include <drm/drm_gem_cma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_modeset_helper.h> #include <drm/drm_of.h> #include "hdlcd_drv.h" @@ -427,35 +428,15 @@ MODULE_DEVICE_TABLE(of, hdlcd_of_match); static int __maybe_unused hdlcd_pm_suspend(struct device *dev) { struct drm_device *drm = dev_get_drvdata(dev); - struct hdlcd_drm_private *hdlcd = drm ? drm->dev_private : NULL; - if (!hdlcd) - return 0; - - drm_kms_helper_poll_disable(drm); - drm_fbdev_cma_set_suspend_unlocked(hdlcd->fbdev, 1); - - hdlcd->state = drm_atomic_helper_suspend(drm); - if (IS_ERR(hdlcd->state)) { - drm_fbdev_cma_set_suspend_unlocked(hdlcd->fbdev, 0); - drm_kms_helper_poll_enable(drm); - return PTR_ERR(hdlcd->state); - } - - return 0; + return drm_mode_config_helper_suspend(drm); } static int __maybe_unused hdlcd_pm_resume(struct device *dev) { struct drm_device *drm = dev_get_drvdata(dev); - struct hdlcd_drm_private *hdlcd = drm ? drm->dev_private : NULL; - - if (!hdlcd) - return 0; - drm_atomic_helper_resume(drm, hdlcd->state); - drm_fbdev_cma_set_suspend_unlocked(hdlcd->fbdev, 0); - drm_kms_helper_poll_enable(drm); + drm_mode_config_helper_resume(drm); return 0; } diff --git a/drivers/gpu/drm/arm/hdlcd_drv.h b/drivers/gpu/drm/arm/hdlcd_drv.h index 56f34dfff6406..58d75d7e1b205 100644 --- a/drivers/gpu/drm/arm/hdlcd_drv.h +++ b/drivers/gpu/drm/arm/hdlcd_drv.h @@ -12,7 +12,6 @@ struct hdlcd_drm_private { struct drm_fbdev_cma *fbdev; struct drm_crtc crtc; struct drm_plane *plane; - struct drm_atomic_state *state; #ifdef CONFIG_DEBUG_FS atomic_t buffer_underrun_count; atomic_t bus_error_count; -- GitLab From 1785dbc412c257879274e8807afd6dfdfe06c47b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org> Date: Fri, 8 Dec 2017 20:37:35 +0100 Subject: [PATCH 1435/1506] drm/arm/hdlcd: Use drm_fb_cma_fbdev_init/fini() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use drm_fb_cma_fbdev_init() and drm_fb_cma_fbdev_fini() which relies on the fact that drm_device holds a pointer to the drm_fb_helper structure. This means that the driver doesn't have to keep track of that. Also use the drm_fb_helper functions directly. Cc: Liviu Dudau <liviu.dudau@arm.com> Cc: Brian Starkey <brian.starkey@arm.com> Signed-off-by: Noralf Trønnes <noralf@tronnes.org> Acked-by: Liviu Dudau <liviu.dudau@arm.com> Signed-off-by: Liviu Dudau <liviu.dudau@arm.com> --- drivers/gpu/drm/arm/hdlcd_drv.c | 37 ++++++--------------------------- drivers/gpu/drm/arm/hdlcd_drv.h | 1 - 2 files changed, 6 insertions(+), 32 deletions(-) diff --git a/drivers/gpu/drm/arm/hdlcd_drv.c b/drivers/gpu/drm/arm/hdlcd_drv.c index 9800a9e388efe..fd5b8c44af144 100644 --- a/drivers/gpu/drm/arm/hdlcd_drv.c +++ b/drivers/gpu/drm/arm/hdlcd_drv.c @@ -101,16 +101,9 @@ static int hdlcd_load(struct drm_device *drm, unsigned long flags) return ret; } -static void hdlcd_fb_output_poll_changed(struct drm_device *drm) -{ - struct hdlcd_drm_private *hdlcd = drm->dev_private; - - drm_fbdev_cma_hotplug_event(hdlcd->fbdev); -} - static const struct drm_mode_config_funcs hdlcd_mode_config_funcs = { .fb_create = drm_gem_fb_create, - .output_poll_changed = hdlcd_fb_output_poll_changed, + .output_poll_changed = drm_fb_helper_output_poll_changed, .atomic_check = drm_atomic_helper_check, .atomic_commit = drm_atomic_helper_commit, }; @@ -125,13 +118,6 @@ static void hdlcd_setup_mode_config(struct drm_device *drm) drm->mode_config.funcs = &hdlcd_mode_config_funcs; } -static void hdlcd_lastclose(struct drm_device *drm) -{ - struct hdlcd_drm_private *hdlcd = drm->dev_private; - - drm_fbdev_cma_restore_mode(hdlcd->fbdev); -} - static irqreturn_t hdlcd_irq(int irq, void *arg) { struct drm_device *drm = arg; @@ -247,7 +233,7 @@ static struct drm_driver hdlcd_driver = { .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_ATOMIC, - .lastclose = hdlcd_lastclose, + .lastclose = drm_fb_helper_lastclose, .irq_handler = hdlcd_irq, .irq_preinstall = hdlcd_irq_preinstall, .irq_postinstall = hdlcd_irq_postinstall, @@ -322,14 +308,9 @@ static int hdlcd_drm_bind(struct device *dev) drm_mode_config_reset(drm); drm_kms_helper_poll_init(drm); - hdlcd->fbdev = drm_fbdev_cma_init(drm, 32, - drm->mode_config.num_connector); - - if (IS_ERR(hdlcd->fbdev)) { - ret = PTR_ERR(hdlcd->fbdev); - hdlcd->fbdev = NULL; + ret = drm_fb_cma_fbdev_init(drm, 32, 0); + if (ret) goto err_fbdev; - } ret = drm_dev_register(drm, 0); if (ret) @@ -338,10 +319,7 @@ static int hdlcd_drm_bind(struct device *dev) return 0; err_register: - if (hdlcd->fbdev) { - drm_fbdev_cma_fini(hdlcd->fbdev); - hdlcd->fbdev = NULL; - } + drm_fb_cma_fbdev_fini(drm); err_fbdev: drm_kms_helper_poll_fini(drm); err_vblank: @@ -367,10 +345,7 @@ static void hdlcd_drm_unbind(struct device *dev) struct hdlcd_drm_private *hdlcd = drm->dev_private; drm_dev_unregister(drm); - if (hdlcd->fbdev) { - drm_fbdev_cma_fini(hdlcd->fbdev); - hdlcd->fbdev = NULL; - } + drm_fb_cma_fbdev_fini(drm); drm_kms_helper_poll_fini(drm); component_unbind_all(dev, drm); of_node_put(hdlcd->crtc.port); diff --git a/drivers/gpu/drm/arm/hdlcd_drv.h b/drivers/gpu/drm/arm/hdlcd_drv.h index 58d75d7e1b205..fd438d177b644 100644 --- a/drivers/gpu/drm/arm/hdlcd_drv.h +++ b/drivers/gpu/drm/arm/hdlcd_drv.h @@ -9,7 +9,6 @@ struct hdlcd_drm_private { void __iomem *mmio; struct clk *clk; - struct drm_fbdev_cma *fbdev; struct drm_crtc crtc; struct drm_plane *plane; #ifdef CONFIG_DEBUG_FS -- GitLab From 8df24d57d34cd229e7094cfd1b927b585585202d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> Date: Wed, 17 Jan 2018 23:55:27 +0200 Subject: [PATCH 1436/1506] drm: arm: hdlcd: Don't destroy plane manually in hdlcd_setup_crtc() The top-level error handler calls drm_mode_config_cleanup() which will destroy all planes. There's no need to destroy them manually in lower error handlers. Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> Signed-off-by: Liviu Dudau <liviu.dudau@arm.com> --- drivers/gpu/drm/arm/hdlcd_crtc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/arm/hdlcd_crtc.c b/drivers/gpu/drm/arm/hdlcd_crtc.c index f3f08cd6e9efb..c36c75bef6d9d 100644 --- a/drivers/gpu/drm/arm/hdlcd_crtc.c +++ b/drivers/gpu/drm/arm/hdlcd_crtc.c @@ -334,10 +334,8 @@ int hdlcd_setup_crtc(struct drm_device *drm) ret = drm_crtc_init_with_planes(drm, &hdlcd->crtc, primary, NULL, &hdlcd_crtc_funcs, NULL); - if (ret) { - hdlcd_plane_destroy(primary); + if (ret) return ret; - } drm_crtc_helper_add(&hdlcd->crtc, &hdlcd_crtc_helper_funcs); return 0; -- GitLab From 9fd466f54f89fc3a2dc6f86fce2ea0b993ff83bd Mon Sep 17 00:00:00 2001 From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> Date: Wed, 17 Jan 2018 23:55:28 +0200 Subject: [PATCH 1437/1506] drm: arm: hdlcd: Use drm_atomic_helper_shutdown() to disable planes on removal The plane cleanup handler currently calls drm_plane_helper_disable(), which is a legacy helper function. Replace it with a call to drm_atomic_helper_shutdown() at removal time. The plane .destroy() handler now consisting only of a call to drm_plane_cleanup(), replace it with direct calls to that function. Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> Signed-off-by: Liviu Dudau <liviu.dudau@arm.com> --- drivers/gpu/drm/arm/hdlcd_crtc.c | 8 +------- drivers/gpu/drm/arm/hdlcd_drv.c | 1 + 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/arm/hdlcd_crtc.c b/drivers/gpu/drm/arm/hdlcd_crtc.c index c36c75bef6d9d..8978d82159e5c 100644 --- a/drivers/gpu/drm/arm/hdlcd_crtc.c +++ b/drivers/gpu/drm/arm/hdlcd_crtc.c @@ -280,16 +280,10 @@ static const struct drm_plane_helper_funcs hdlcd_plane_helper_funcs = { .atomic_update = hdlcd_plane_atomic_update, }; -static void hdlcd_plane_destroy(struct drm_plane *plane) -{ - drm_plane_helper_disable(plane, NULL); - drm_plane_cleanup(plane); -} - static const struct drm_plane_funcs hdlcd_plane_funcs = { .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, - .destroy = hdlcd_plane_destroy, + .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, diff --git a/drivers/gpu/drm/arm/hdlcd_drv.c b/drivers/gpu/drm/arm/hdlcd_drv.c index fd5b8c44af144..70fca288313a8 100644 --- a/drivers/gpu/drm/arm/hdlcd_drv.c +++ b/drivers/gpu/drm/arm/hdlcd_drv.c @@ -355,6 +355,7 @@ static void hdlcd_drm_unbind(struct device *dev) pm_runtime_put_sync(drm->dev); pm_runtime_disable(drm->dev); of_reserved_mem_device_release(drm->dev); + drm_atomic_helper_shutdown(drm); drm_mode_config_cleanup(drm); drm_dev_put(drm); drm->dev_private = NULL; -- GitLab From d664b851eb2bcdf84a3c063cf59457bb15bc6120 Mon Sep 17 00:00:00 2001 From: Liviu Dudau <Liviu.Dudau@arm.com> Date: Mon, 23 Jul 2018 12:05:53 +0100 Subject: [PATCH 1438/1506] drm/arm/hdlcd: Reject atomic commits that disable only the plane The HDLCD engine needs an active plane while the CRTC is active, as it will start scanning out data from HDLCD_REG_FB_BASE once it gets enabled. Make sure that the only available plane doesn't get disabled while the CRTC remains active, as this will scanout invalid data. Signed-off-by: Liviu Dudau <liviu.dudau@arm.com> --- drivers/gpu/drm/arm/hdlcd_crtc.c | 23 +++++++++++------------ drivers/gpu/drm/arm/hdlcd_drv.c | 13 ++++++++----- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/arm/hdlcd_crtc.c b/drivers/gpu/drm/arm/hdlcd_crtc.c index 8978d82159e5c..e4d67b70244d5 100644 --- a/drivers/gpu/drm/arm/hdlcd_crtc.c +++ b/drivers/gpu/drm/arm/hdlcd_crtc.c @@ -229,6 +229,8 @@ static const struct drm_crtc_helper_funcs hdlcd_crtc_helper_funcs = { static int hdlcd_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *state) { + int i; + struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; u32 src_h = state->src_h >> 16; @@ -238,20 +240,17 @@ static int hdlcd_plane_atomic_check(struct drm_plane *plane, return -EINVAL; } - if (!state->fb || !state->crtc) - return 0; - - crtc_state = drm_atomic_get_existing_crtc_state(state->state, - state->crtc); - if (!crtc_state) { - DRM_DEBUG_KMS("Invalid crtc state\n"); - return -EINVAL; + for_each_new_crtc_in_state(state->state, crtc, crtc_state, i) { + /* we cannot disable the plane while the CRTC is active */ + if (!state->fb && crtc_state->active) + return -EINVAL; + return drm_atomic_helper_check_plane_state(state, crtc_state, + DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_HELPER_NO_SCALING, + false, true); } - return drm_atomic_helper_check_plane_state(state, crtc_state, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, - false, true); + return 0; } static void hdlcd_plane_atomic_update(struct drm_plane *plane, diff --git a/drivers/gpu/drm/arm/hdlcd_drv.c b/drivers/gpu/drm/arm/hdlcd_drv.c index 70fca288313a8..0ed1cde98cf8c 100644 --- a/drivers/gpu/drm/arm/hdlcd_drv.c +++ b/drivers/gpu/drm/arm/hdlcd_drv.c @@ -325,6 +325,7 @@ static int hdlcd_drm_bind(struct device *dev) err_vblank: pm_runtime_disable(drm->dev); err_pm_active: + drm_atomic_helper_shutdown(drm); component_unbind_all(dev, drm); err_unload: of_node_put(hdlcd->crtc.port); @@ -350,16 +351,18 @@ static void hdlcd_drm_unbind(struct device *dev) component_unbind_all(dev, drm); of_node_put(hdlcd->crtc.port); hdlcd->crtc.port = NULL; - pm_runtime_get_sync(drm->dev); + pm_runtime_get_sync(dev); + drm_crtc_vblank_off(&hdlcd->crtc); drm_irq_uninstall(drm); - pm_runtime_put_sync(drm->dev); - pm_runtime_disable(drm->dev); - of_reserved_mem_device_release(drm->dev); drm_atomic_helper_shutdown(drm); + pm_runtime_put(dev); + if (pm_runtime_enabled(dev)) + pm_runtime_disable(dev); + of_reserved_mem_device_release(dev); drm_mode_config_cleanup(drm); - drm_dev_put(drm); drm->dev_private = NULL; dev_set_drvdata(dev, NULL); + drm_dev_put(drm); } static const struct component_master_ops hdlcd_master_ops = { -- GitLab From 2d227ec2c11c568910299e8f913bac2dda47397c Mon Sep 17 00:00:00 2001 From: Rex Zhu <rex.zhu@amd.com> Date: Fri, 20 Jul 2018 16:26:46 +0800 Subject: [PATCH 1439/1506] drm/amd/pp/Polaris12: Fix a chunk of registers missed to program DIDTConfig_Polaris12[] table missed a big chunk of data. Pointed by aidan.fabius <aidan.fabius@coreavi.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> Cc: stable@vger.kernel.org --- .../drm/amd/powerplay/hwmgr/smu7_powertune.c | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c index c952845833d72..5e19f5977eb19 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c @@ -403,6 +403,49 @@ static const struct gpu_pt_config_reg DIDTConfig_Polaris12[] = { { ixDIDT_SQ_CTRL1, DIDT_SQ_CTRL1__MAX_POWER_MASK, DIDT_SQ_CTRL1__MAX_POWER__SHIFT, 0xffff, GPU_CONFIGREG_DIDT_IND }, { ixDIDT_SQ_CTRL_OCP, DIDT_SQ_CTRL_OCP__UNUSED_0_MASK, DIDT_SQ_CTRL_OCP__UNUSED_0__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_CTRL_OCP, DIDT_SQ_CTRL_OCP__OCP_MAX_POWER_MASK, DIDT_SQ_CTRL_OCP__OCP_MAX_POWER__SHIFT, 0xffff, GPU_CONFIGREG_DIDT_IND }, + + { ixDIDT_SQ_CTRL2, DIDT_SQ_CTRL2__MAX_POWER_DELTA_MASK, DIDT_SQ_CTRL2__MAX_POWER_DELTA__SHIFT, 0x3853, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_CTRL2, DIDT_SQ_CTRL2__UNUSED_0_MASK, DIDT_SQ_CTRL2__UNUSED_0__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_CTRL2, DIDT_SQ_CTRL2__SHORT_TERM_INTERVAL_SIZE_MASK, DIDT_SQ_CTRL2__SHORT_TERM_INTERVAL_SIZE__SHIFT, 0x005a, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_CTRL2, DIDT_SQ_CTRL2__UNUSED_1_MASK, DIDT_SQ_CTRL2__UNUSED_1__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_CTRL2, DIDT_SQ_CTRL2__LONG_TERM_INTERVAL_RATIO_MASK, DIDT_SQ_CTRL2__LONG_TERM_INTERVAL_RATIO__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_CTRL2, DIDT_SQ_CTRL2__UNUSED_2_MASK, DIDT_SQ_CTRL2__UNUSED_2__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND }, + + { ixDIDT_SQ_STALL_CTRL, DIDT_SQ_STALL_CTRL__DIDT_STALL_CTRL_ENABLE_MASK, DIDT_SQ_STALL_CTRL__DIDT_STALL_CTRL_ENABLE__SHIFT, 0x0001, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_STALL_CTRL, DIDT_SQ_STALL_CTRL__DIDT_STALL_DELAY_HI_MASK, DIDT_SQ_STALL_CTRL__DIDT_STALL_DELAY_HI__SHIFT, 0x0001, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_STALL_CTRL, DIDT_SQ_STALL_CTRL__DIDT_STALL_DELAY_LO_MASK, DIDT_SQ_STALL_CTRL__DIDT_STALL_DELAY_LO__SHIFT, 0x0001, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_STALL_CTRL, DIDT_SQ_STALL_CTRL__DIDT_HI_POWER_THRESHOLD_MASK, DIDT_SQ_STALL_CTRL__DIDT_HI_POWER_THRESHOLD__SHIFT, 0x0ebb, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_STALL_CTRL, DIDT_SQ_STALL_CTRL__UNUSED_0_MASK, DIDT_SQ_STALL_CTRL__UNUSED_0__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND }, + + { ixDIDT_SQ_TUNING_CTRL, DIDT_SQ_TUNING_CTRL__DIDT_TUNING_ENABLE_MASK, DIDT_SQ_TUNING_CTRL__DIDT_TUNING_ENABLE__SHIFT, 0x0001, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_TUNING_CTRL, DIDT_SQ_TUNING_CTRL__MAX_POWER_DELTA_HI_MASK, DIDT_SQ_TUNING_CTRL__MAX_POWER_DELTA_HI__SHIFT, 0x3853, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_TUNING_CTRL, DIDT_SQ_TUNING_CTRL__MAX_POWER_DELTA_LO_MASK, DIDT_SQ_TUNING_CTRL__MAX_POWER_DELTA_LO__SHIFT, 0x3153, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_TUNING_CTRL, DIDT_SQ_TUNING_CTRL__UNUSED_0_MASK, DIDT_SQ_TUNING_CTRL__UNUSED_0__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND }, + + { ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__DIDT_CTRL_EN_MASK, DIDT_SQ_CTRL0__DIDT_CTRL_EN__SHIFT, 0x0001, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__USE_REF_CLOCK_MASK, DIDT_SQ_CTRL0__USE_REF_CLOCK__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__PHASE_OFFSET_MASK, DIDT_SQ_CTRL0__PHASE_OFFSET__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__DIDT_CTRL_RST_MASK, DIDT_SQ_CTRL0__DIDT_CTRL_RST__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__DIDT_CLK_EN_OVERRIDE_MASK, DIDT_SQ_CTRL0__DIDT_CLK_EN_OVERRIDE__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__DIDT_MAX_STALLS_ALLOWED_HI_MASK, DIDT_SQ_CTRL0__DIDT_MAX_STALLS_ALLOWED_HI__SHIFT, 0x0010, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__DIDT_MAX_STALLS_ALLOWED_LO_MASK, DIDT_SQ_CTRL0__DIDT_MAX_STALLS_ALLOWED_LO__SHIFT, 0x0010, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__UNUSED_0_MASK, DIDT_SQ_CTRL0__UNUSED_0__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND }, + + { ixDIDT_TD_WEIGHT0_3, DIDT_TD_WEIGHT0_3__WEIGHT0_MASK, DIDT_TD_WEIGHT0_3__WEIGHT0__SHIFT, 0x000a, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_TD_WEIGHT0_3, DIDT_TD_WEIGHT0_3__WEIGHT1_MASK, DIDT_TD_WEIGHT0_3__WEIGHT1__SHIFT, 0x0010, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_TD_WEIGHT0_3, DIDT_TD_WEIGHT0_3__WEIGHT2_MASK, DIDT_TD_WEIGHT0_3__WEIGHT2__SHIFT, 0x0017, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_TD_WEIGHT0_3, DIDT_TD_WEIGHT0_3__WEIGHT3_MASK, DIDT_TD_WEIGHT0_3__WEIGHT3__SHIFT, 0x002f, GPU_CONFIGREG_DIDT_IND }, + + { ixDIDT_TD_WEIGHT4_7, DIDT_TD_WEIGHT4_7__WEIGHT4_MASK, DIDT_TD_WEIGHT4_7__WEIGHT4__SHIFT, 0x0046, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_TD_WEIGHT4_7, DIDT_TD_WEIGHT4_7__WEIGHT5_MASK, DIDT_TD_WEIGHT4_7__WEIGHT5__SHIFT, 0x005d, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_TD_WEIGHT4_7, DIDT_TD_WEIGHT4_7__WEIGHT6_MASK, DIDT_TD_WEIGHT4_7__WEIGHT6__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_TD_WEIGHT4_7, DIDT_TD_WEIGHT4_7__WEIGHT7_MASK, DIDT_TD_WEIGHT4_7__WEIGHT7__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND }, + + { ixDIDT_TD_CTRL1, DIDT_TD_CTRL1__MIN_POWER_MASK, DIDT_TD_CTRL1__MIN_POWER__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_TD_CTRL1, DIDT_TD_CTRL1__MAX_POWER_MASK, DIDT_TD_CTRL1__MAX_POWER__SHIFT, 0xffff, GPU_CONFIGREG_DIDT_IND }, + + { ixDIDT_TD_CTRL_OCP, DIDT_TD_CTRL_OCP__UNUSED_0_MASK, DIDT_TD_CTRL_OCP__UNUSED_0__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND }, { ixDIDT_TD_CTRL_OCP, DIDT_TD_CTRL_OCP__OCP_MAX_POWER_MASK, DIDT_TD_CTRL_OCP__OCP_MAX_POWER__SHIFT, 0x00ff, GPU_CONFIGREG_DIDT_IND }, { ixDIDT_TD_CTRL2, DIDT_TD_CTRL2__MAX_POWER_DELTA_MASK, DIDT_TD_CTRL2__MAX_POWER_DELTA__SHIFT, 0x3fff, GPU_CONFIGREG_DIDT_IND }, -- GitLab From 90983631a6486f68c1e95bf30713a179ac0a083f Mon Sep 17 00:00:00 2001 From: Rex Zhu <rex.zhu@amd.com> Date: Fri, 20 Jul 2018 18:19:00 +0800 Subject: [PATCH 1440/1506] drm/amd/pp: Delete unused temp variables Only delete the dead temp variables in Polaris. Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../amd/powerplay/smumgr/polaris10_smumgr.c | 22 +++++-------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c index a4ce199af4758..1276f168ff68d 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c @@ -1204,7 +1204,6 @@ static int polaris10_populate_smc_acpi_level(struct pp_hwmgr *hwmgr, (struct phm_ppt_v1_information *)(hwmgr->pptable); SMIO_Pattern vol_level; uint32_t mvdd; - uint16_t us_mvdd; table->ACPILevel.Flags &= ~PPSMC_SWSTATE_FLAG_DC; @@ -1255,16 +1254,11 @@ static int polaris10_populate_smc_acpi_level(struct pp_hwmgr *hwmgr, "in Clock Dependency Table", ); - us_mvdd = 0; - if ((SMU7_VOLTAGE_CONTROL_NONE == data->mvdd_control) || - (data->mclk_dpm_key_disabled)) - us_mvdd = data->vbios_boot_state.mvdd_bootup_value; - else { - if (!polaris10_populate_mvdd_value(hwmgr, + if (!((SMU7_VOLTAGE_CONTROL_NONE == data->mvdd_control) || + (data->mclk_dpm_key_disabled))) + polaris10_populate_mvdd_value(hwmgr, data->dpm_table.mclk_table.dpm_levels[0].value, - &vol_level)) - us_mvdd = vol_level.Voltage; - } + &vol_level); if (0 == polaris10_populate_mvdd_value(hwmgr, 0, &vol_level)) table->MemoryACPILevel.MinMvdd = PP_HOST_TO_SMC_UL(vol_level.Voltage); @@ -1517,7 +1511,7 @@ static int polaris10_populate_clock_stretcher_data_table(struct pp_hwmgr *hwmgr) uint32_t ro, efuse, volt_without_cks, volt_with_cks, value, max, min; struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(hwmgr->smu_backend); - uint8_t i, stretch_amount, stretch_amount2, volt_offset = 0; + uint8_t i, stretch_amount, volt_offset = 0; struct phm_ppt_v1_information *table_info = (struct phm_ppt_v1_information *)(hwmgr->pptable); struct phm_ppt_v1_clock_voltage_dependency_table *sclk_table = @@ -1568,11 +1562,7 @@ static int polaris10_populate_clock_stretcher_data_table(struct pp_hwmgr *hwmgr) smu_data->smc_state_table.LdoRefSel = (table_info->cac_dtp_table->ucCKS_LDO_REFSEL != 0) ? table_info->cac_dtp_table->ucCKS_LDO_REFSEL : 6; /* Populate CKS Lookup Table */ - if (stretch_amount == 1 || stretch_amount == 2 || stretch_amount == 5) - stretch_amount2 = 0; - else if (stretch_amount == 3 || stretch_amount == 4) - stretch_amount2 = 1; - else { + if (stretch_amount == 0 || stretch_amount > 5) { phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_ClockStretcher); PP_ASSERT_WITH_CODE(false, -- GitLab From 8a50bb47a863c3cb8950a2e810448c9a82a9d446 Mon Sep 17 00:00:00 2001 From: Rex Zhu <rex.zhu@amd.com> Date: Wed, 25 Jul 2018 11:45:03 +0800 Subject: [PATCH 1441/1506] drm/amd/pp: Convert voltage unit in mV*4 to mV on CZ/ST the voltage showed in debugfs and hwmon should be in mV Reviewed-by: Evan Quan <evan.quan@amd.com> Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/powerplay/hwmgr/smu8_hwmgr.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu8_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu8_hwmgr.c index 288802f209dd9..0adfc5392cd37 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu8_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu8_hwmgr.c @@ -244,6 +244,7 @@ static int smu8_initialize_dpm_defaults(struct pp_hwmgr *hwmgr) return 0; } +/* convert form 8bit vid to real voltage in mV*4 */ static uint32_t smu8_convert_8Bit_index_to_voltage( struct pp_hwmgr *hwmgr, uint16_t voltage) { @@ -1702,13 +1703,13 @@ static int smu8_read_sensor(struct pp_hwmgr *hwmgr, int idx, case AMDGPU_PP_SENSOR_VDDNB: tmp = (cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixSMUSVI_NB_CURRENTVID) & CURRENT_NB_VID_MASK) >> CURRENT_NB_VID__SHIFT; - vddnb = smu8_convert_8Bit_index_to_voltage(hwmgr, tmp); + vddnb = smu8_convert_8Bit_index_to_voltage(hwmgr, tmp) / 4; *((uint32_t *)value) = vddnb; return 0; case AMDGPU_PP_SENSOR_VDDGFX: tmp = (cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixSMUSVI_GFX_CURRENTVID) & CURRENT_GFX_VID_MASK) >> CURRENT_GFX_VID__SHIFT; - vddgfx = smu8_convert_8Bit_index_to_voltage(hwmgr, (u16)tmp); + vddgfx = smu8_convert_8Bit_index_to_voltage(hwmgr, (u16)tmp) / 4; *((uint32_t *)value) = vddgfx; return 0; case AMDGPU_PP_SENSOR_UVD_VCLK: -- GitLab From ccf9ef0b0d10434dec5046bcfc4e834a7b1830fd Mon Sep 17 00:00:00 2001 From: Rex Zhu <rex.zhu@amd.com> Date: Wed, 25 Jul 2018 11:51:46 +0800 Subject: [PATCH 1442/1506] drm/amdgpu: fix a reversed condition This test was reversed so it would end up leading to vddnb value can't be read via hwmon on APU. Reviewed-by: Evan Quan <evan.quan@amd.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c index 15a1192c1ec54..23fc1d32b937e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c @@ -1185,7 +1185,7 @@ static ssize_t amdgpu_hwmon_show_vddnb(struct device *dev, int r, size = sizeof(vddnb); /* only APUs have vddnb */ - if (adev->flags & AMD_IS_APU) + if (!(adev->flags & AMD_IS_APU)) return -EINVAL; /* Can't get voltage when the card is off */ -- GitLab From 52c054caf83012fe9fe858ee86d90b4ea2cc3cca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Fri, 27 Jul 2018 15:32:04 +0200 Subject: [PATCH 1443/1506] drm/amdgpu: add proper error handling to amdgpu_bo_list_get MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Otherwise we silently don't use a BO list when the handle is invalid. Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Chunming Zhou <david1.zhou@amd.com> Reviewed-by: Huang Rui <ray.huang@amd.com> Reviewed-by: Michel Dänzer <michel.daenzer@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 4 +-- drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c | 28 ++++++++------------- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 11 +++++--- 3 files changed, 20 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 1f6345dda6ead..4d4d6697fbcec 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -713,8 +713,8 @@ struct amdgpu_bo_list { struct amdgpu_bo_list_entry *array; }; -struct amdgpu_bo_list * -amdgpu_bo_list_get(struct amdgpu_fpriv *fpriv, int id); +int amdgpu_bo_list_get(struct amdgpu_fpriv *fpriv, int id, + struct amdgpu_bo_list **result); void amdgpu_bo_list_get_list(struct amdgpu_bo_list *list, struct list_head *validated); void amdgpu_bo_list_put(struct amdgpu_bo_list *list); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c index 7679c068c89a8..944868e471198 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c @@ -180,27 +180,20 @@ static int amdgpu_bo_list_set(struct amdgpu_device *adev, return r; } -struct amdgpu_bo_list * -amdgpu_bo_list_get(struct amdgpu_fpriv *fpriv, int id) +int amdgpu_bo_list_get(struct amdgpu_fpriv *fpriv, int id, + struct amdgpu_bo_list **result) { - struct amdgpu_bo_list *result; - rcu_read_lock(); - result = idr_find(&fpriv->bo_list_handles, id); + *result = idr_find(&fpriv->bo_list_handles, id); - if (result) { - if (kref_get_unless_zero(&result->refcount)) { - rcu_read_unlock(); - mutex_lock(&result->lock); - } else { - rcu_read_unlock(); - result = NULL; - } - } else { + if (*result && kref_get_unless_zero(&(*result)->refcount)) { rcu_read_unlock(); + mutex_lock(&(*result)->lock); + return 0; } - return result; + rcu_read_unlock(); + return -ENOENT; } void amdgpu_bo_list_get_list(struct amdgpu_bo_list *list, @@ -335,9 +328,8 @@ int amdgpu_bo_list_ioctl(struct drm_device *dev, void *data, break; case AMDGPU_BO_LIST_OP_UPDATE: - r = -ENOENT; - list = amdgpu_bo_list_get(fpriv, handle); - if (!list) + r = amdgpu_bo_list_get(fpriv, handle, &list); + if (r) goto error_free; r = amdgpu_bo_list_set(adev, filp, list, info, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 533b2e7656c05..8a49c3b97bd43 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -572,11 +572,16 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, INIT_LIST_HEAD(&p->validated); /* p->bo_list could already be assigned if AMDGPU_CHUNK_ID_BO_HANDLES is present */ - if (!p->bo_list) - p->bo_list = amdgpu_bo_list_get(fpriv, cs->in.bo_list_handle); - else + if (p->bo_list) { mutex_lock(&p->bo_list->lock); + } else if (cs->in.bo_list_handle) { + r = amdgpu_bo_list_get(fpriv, cs->in.bo_list_handle, + &p->bo_list); + if (r) + return r; + } + if (p->bo_list) { amdgpu_bo_list_get_list(p->bo_list, &p->validated); if (p->bo_list->first_userptr != p->bo_list->num_entries) -- GitLab From ba7f47831ebdad141791be53a51049d6771156cd Mon Sep 17 00:00:00 2001 From: Masahiro Yamada <yamada.masahiro@socionext.com> Date: Fri, 6 Jul 2018 14:12:11 +0900 Subject: [PATCH 1444/1506] drm/sched: remove unneeded -Iinclude/drm compiler flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I refactored the include directives under include/drm/ some time ago. This flag is unneeded. Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com> Reviewed-by: Christian König <christian.koenig@amd.com> Acked-by: Nayan Deshmukh <nayan26deshmukh@gmail.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/scheduler/Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/scheduler/Makefile b/drivers/gpu/drm/scheduler/Makefile index bd0377c0d2eea..7665883f81d4b 100644 --- a/drivers/gpu/drm/scheduler/Makefile +++ b/drivers/gpu/drm/scheduler/Makefile @@ -20,7 +20,6 @@ # OTHER DEALINGS IN THE SOFTWARE. # # -ccflags-y := -Iinclude/drm gpu-sched-y := gpu_scheduler.o sched_fence.o obj-$(CONFIG_DRM_SCHED) += gpu-sched.o -- GitLab From 275105ce7be37a2cc80eb1b60e6526355f54df94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Mon, 30 Jul 2018 15:33:34 +0200 Subject: [PATCH 1445/1506] drm/amdgpu: fix total size calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit long might only be 32bit in size and we can easily use more than 4GB here. Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Chunming Zhou <david1.zhou@amd.com> Acked-by: Huang Rui <ray.huang@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c index 944868e471198..6728448167ba3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c @@ -105,9 +105,9 @@ static int amdgpu_bo_list_set(struct amdgpu_device *adev, struct amdgpu_bo *oa_obj = adev->gds.oa_gfx_bo; unsigned last_entry = 0, first_userptr = num_entries; + uint64_t total_size = 0; unsigned i; int r; - unsigned long total_size = 0; array = kvmalloc_array(num_entries, sizeof(struct amdgpu_bo_list_entry), GFP_KERNEL); if (!array) -- GitLab From 0cb7c1f03bfb3991120313c5927c1749041ef800 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Mon, 30 Jul 2018 16:18:54 +0200 Subject: [PATCH 1446/1506] drm/amdgpu: return error if both BOs and bo_list handle is given MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Return -EINVAL when both the BOs as well as a list handle is provided in the IOCTL. Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Chunming Zhou <david1.zhou@amd.com> Reviewed-by: Huang Rui <ray.huang@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 8a49c3b97bd43..d41cea78e4aa7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -572,14 +572,17 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, INIT_LIST_HEAD(&p->validated); /* p->bo_list could already be assigned if AMDGPU_CHUNK_ID_BO_HANDLES is present */ - if (p->bo_list) { - mutex_lock(&p->bo_list->lock); + if (cs->in.bo_list_handle) { + if (p->bo_list) + return -EINVAL; - } else if (cs->in.bo_list_handle) { r = amdgpu_bo_list_get(fpriv, cs->in.bo_list_handle, &p->bo_list); if (r) return r; + + } else if (p->bo_list) { + mutex_lock(&p->bo_list->lock); } if (p->bo_list) { -- GitLab From 8ab19ea619aeed8ca4a36c124e8edfd9b9491aba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Fri, 27 Jul 2018 16:56:34 +0200 Subject: [PATCH 1447/1506] drm/amdgpu: add new amdgpu_vm_bo_trace_cs() function v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows us to trace all VM ranges which should be valid inside a CS. v2: dump mappings without BO as well Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Chunming Zhou <david1.zhou@amd.com> Reviewed-and-tested-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> (v1) Reviewed-by: Huang Rui <ray.huang@amd.com> (v1) Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 2 ++ drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h | 5 ++++ drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 29 +++++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h | 1 + 4 files changed, 37 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index d41cea78e4aa7..0295666968dac 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -1223,6 +1223,7 @@ static void amdgpu_cs_post_dependencies(struct amdgpu_cs_parser *p) static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, union drm_amdgpu_cs *cs) { + struct amdgpu_fpriv *fpriv = p->filp->driver_priv; struct amdgpu_ring *ring = p->ring; struct drm_sched_entity *entity = &p->ctx->rings[ring->idx].entity; enum drm_sched_priority priority; @@ -1275,6 +1276,7 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, amdgpu_job_free_resources(job); trace_amdgpu_cs_ioctl(job); + amdgpu_vm_bo_trace_cs(&fpriv->vm, &p->ticket); priority = job->base.s_priority; drm_sched_entity_push_job(&job->base, entity); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h index 11f262f152007..7206a0025b17a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h @@ -314,6 +314,11 @@ DEFINE_EVENT(amdgpu_vm_mapping, amdgpu_vm_bo_mapping, TP_ARGS(mapping) ); +DEFINE_EVENT(amdgpu_vm_mapping, amdgpu_vm_bo_cs, + TP_PROTO(struct amdgpu_bo_va_mapping *mapping), + TP_ARGS(mapping) +); + TRACE_EVENT(amdgpu_vm_set_ptes, TP_PROTO(uint64_t pe, uint64_t addr, unsigned count, uint32_t incr, uint64_t flags), diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 5d7d7900ccabb..015613b4f98b6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -2343,6 +2343,35 @@ struct amdgpu_bo_va_mapping *amdgpu_vm_bo_lookup_mapping(struct amdgpu_vm *vm, return amdgpu_vm_it_iter_first(&vm->va, addr, addr); } +/** + * amdgpu_vm_bo_trace_cs - trace all reserved mappings + * + * @vm: the requested vm + * @ticket: CS ticket + * + * Trace all mappings of BOs reserved during a command submission. + */ +void amdgpu_vm_bo_trace_cs(struct amdgpu_vm *vm, struct ww_acquire_ctx *ticket) +{ + struct amdgpu_bo_va_mapping *mapping; + + if (!trace_amdgpu_vm_bo_cs_enabled()) + return; + + for (mapping = amdgpu_vm_it_iter_first(&vm->va, 0, U64_MAX); mapping; + mapping = amdgpu_vm_it_iter_next(mapping, 0, U64_MAX)) { + if (mapping->bo_va && mapping->bo_va->base.bo) { + struct amdgpu_bo *bo; + + bo = mapping->bo_va->base.bo; + if (READ_ONCE(bo->tbo.resv->lock.ctx) != ticket) + continue; + } + + trace_amdgpu_vm_bo_cs(mapping); + } +} + /** * amdgpu_vm_bo_rmv - remove a bo to a specific vm * diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h index d416f895233d3..67a15d439ac00 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h @@ -318,6 +318,7 @@ int amdgpu_vm_bo_clear_mappings(struct amdgpu_device *adev, uint64_t saddr, uint64_t size); struct amdgpu_bo_va_mapping *amdgpu_vm_bo_lookup_mapping(struct amdgpu_vm *vm, uint64_t addr); +void amdgpu_vm_bo_trace_cs(struct amdgpu_vm *vm, struct ww_acquire_ctx *ticket); void amdgpu_vm_bo_rmv(struct amdgpu_device *adev, struct amdgpu_bo_va *bo_va); void amdgpu_vm_adjust_size(struct amdgpu_device *adev, uint32_t vm_size, -- GitLab From 4a8c21a1e9b3c35b21c5a4a4c16a009a193389bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Mon, 30 Jul 2018 13:27:09 +0200 Subject: [PATCH 1448/1506] drm/amdgpu: move bo_list defines to amdgpu_bo_list.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Further demangle amdgpu.h Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Chunming Zhou <david1.zhou@amd.com> Acked-by: Huang Rui <ray.huang@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 40 +----------- drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h | 70 +++++++++++++++++++++ 2 files changed, 71 insertions(+), 39 deletions(-) create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 4d4d6697fbcec..447c4c7a36d68 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -74,6 +74,7 @@ #include "amdgpu_gart.h" #include "amdgpu_debugfs.h" #include "amdgpu_job.h" +#include "amdgpu_bo_list.h" /* * Modules parameters. @@ -689,45 +690,6 @@ struct amdgpu_fpriv { struct amdgpu_ctx_mgr ctx_mgr; }; -/* - * residency list - */ -struct amdgpu_bo_list_entry { - struct amdgpu_bo *robj; - struct ttm_validate_buffer tv; - struct amdgpu_bo_va *bo_va; - uint32_t priority; - struct page **user_pages; - int user_invalidated; -}; - -struct amdgpu_bo_list { - struct mutex lock; - struct rcu_head rhead; - struct kref refcount; - struct amdgpu_bo *gds_obj; - struct amdgpu_bo *gws_obj; - struct amdgpu_bo *oa_obj; - unsigned first_userptr; - unsigned num_entries; - struct amdgpu_bo_list_entry *array; -}; - -int amdgpu_bo_list_get(struct amdgpu_fpriv *fpriv, int id, - struct amdgpu_bo_list **result); -void amdgpu_bo_list_get_list(struct amdgpu_bo_list *list, - struct list_head *validated); -void amdgpu_bo_list_put(struct amdgpu_bo_list *list); -void amdgpu_bo_list_free(struct amdgpu_bo_list *list); -int amdgpu_bo_create_list_entry_array(struct drm_amdgpu_bo_list_in *in, - struct drm_amdgpu_bo_list_entry **info_param); - -int amdgpu_bo_list_create(struct amdgpu_device *adev, - struct drm_file *filp, - struct drm_amdgpu_bo_list_entry *info, - unsigned num_entries, - struct amdgpu_bo_list **list); - /* * GFX stuff */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h new file mode 100644 index 0000000000000..833f846bfdad1 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h @@ -0,0 +1,70 @@ +/* + * Copyright 2018 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ +#ifndef __AMDGPU_BO_LIST_H__ +#define __AMDGPU_BO_LIST_H__ + +#include <drm/ttm/ttm_execbuf_util.h> +#include <drm/amdgpu_drm.h> + +struct amdgpu_device; +struct amdgpu_bo; +struct amdgpu_bo_va; +struct amdgpu_fpriv; + +struct amdgpu_bo_list_entry { + struct amdgpu_bo *robj; + struct ttm_validate_buffer tv; + struct amdgpu_bo_va *bo_va; + uint32_t priority; + struct page **user_pages; + int user_invalidated; +}; + +struct amdgpu_bo_list { + struct mutex lock; + struct rcu_head rhead; + struct kref refcount; + struct amdgpu_bo *gds_obj; + struct amdgpu_bo *gws_obj; + struct amdgpu_bo *oa_obj; + unsigned first_userptr; + unsigned num_entries; + struct amdgpu_bo_list_entry *array; +}; + +int amdgpu_bo_list_get(struct amdgpu_fpriv *fpriv, int id, + struct amdgpu_bo_list **result); +void amdgpu_bo_list_get_list(struct amdgpu_bo_list *list, + struct list_head *validated); +void amdgpu_bo_list_put(struct amdgpu_bo_list *list); +void amdgpu_bo_list_free(struct amdgpu_bo_list *list); +int amdgpu_bo_create_list_entry_array(struct drm_amdgpu_bo_list_in *in, + struct drm_amdgpu_bo_list_entry **info_param); + +int amdgpu_bo_list_create(struct amdgpu_device *adev, + struct drm_file *filp, + struct drm_amdgpu_bo_list_entry *info, + unsigned num_entries, + struct amdgpu_bo_list **list); + +#endif -- GitLab From 81c6dabcc990c341793368db985ee8aca5713b16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Mon, 30 Jul 2018 13:46:04 +0200 Subject: [PATCH 1449/1506] drm/amdgpu: always recreate bo_list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The bo_list handle is allocated by OP_CREATE, so in OP_UPDATE here we just re-create the bo_list object and replace the handle. This way we don't need locking to protect the bo_list because it's always re-created when changed. Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Chunming Zhou <david1.zhou@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c | 23 +++++++++++---------- drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h | 1 - drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 3 --- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c index 6728448167ba3..556040e459316 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c @@ -50,7 +50,6 @@ static void amdgpu_bo_list_release_rcu(struct kref *ref) for (i = 0; i < list->num_entries; ++i) amdgpu_bo_unref(&list->array[i].robj); - mutex_destroy(&list->lock); kvfree(list->array); kfree_rcu(list, rhead); } @@ -70,7 +69,6 @@ int amdgpu_bo_list_create(struct amdgpu_device *adev, return -ENOMEM; /* initialize bo list*/ - mutex_init(&list->lock); kref_init(&list->refcount); r = amdgpu_bo_list_set(adev, filp, list, info, num_entries); if (r) { @@ -188,7 +186,6 @@ int amdgpu_bo_list_get(struct amdgpu_fpriv *fpriv, int id, if (*result && kref_get_unless_zero(&(*result)->refcount)) { rcu_read_unlock(); - mutex_lock(&(*result)->lock); return 0; } @@ -231,7 +228,6 @@ void amdgpu_bo_list_get_list(struct amdgpu_bo_list *list, void amdgpu_bo_list_put(struct amdgpu_bo_list *list) { - mutex_unlock(&list->lock); kref_put(&list->refcount, amdgpu_bo_list_release_rcu); } @@ -242,7 +238,6 @@ void amdgpu_bo_list_free(struct amdgpu_bo_list *list) for (i = 0; i < list->num_entries; ++i) amdgpu_bo_unref(&list->array[i].robj); - mutex_destroy(&list->lock); kvfree(list->array); kfree(list); } @@ -297,7 +292,7 @@ int amdgpu_bo_list_ioctl(struct drm_device *dev, void *data, union drm_amdgpu_bo_list *args = data; uint32_t handle = args->in.list_handle; struct drm_amdgpu_bo_list_entry *info = NULL; - struct amdgpu_bo_list *list; + struct amdgpu_bo_list *list, *old; int r; r = amdgpu_bo_create_list_entry_array(&args->in, &info); @@ -328,16 +323,22 @@ int amdgpu_bo_list_ioctl(struct drm_device *dev, void *data, break; case AMDGPU_BO_LIST_OP_UPDATE: - r = amdgpu_bo_list_get(fpriv, handle, &list); + r = amdgpu_bo_list_create(adev, filp, info, args->in.bo_number, + &list); if (r) goto error_free; - r = amdgpu_bo_list_set(adev, filp, list, info, - args->in.bo_number); - amdgpu_bo_list_put(list); - if (r) + mutex_lock(&fpriv->bo_list_lock); + old = idr_replace(&fpriv->bo_list_handles, list, handle); + mutex_unlock(&fpriv->bo_list_lock); + + if (IS_ERR(old)) { + amdgpu_bo_list_put(list); + r = PTR_ERR(old); goto error_free; + } + amdgpu_bo_list_put(old); break; default: diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h index 833f846bfdad1..89195fdcb1ef1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h @@ -41,7 +41,6 @@ struct amdgpu_bo_list_entry { }; struct amdgpu_bo_list { - struct mutex lock; struct rcu_head rhead; struct kref refcount; struct amdgpu_bo *gds_obj; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 0295666968dac..f7154f3ed8073 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -580,9 +580,6 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, &p->bo_list); if (r) return r; - - } else if (p->bo_list) { - mutex_lock(&p->bo_list->lock); } if (p->bo_list) { -- GitLab From a0f208453b97565dab8c334ff013aa5ab3c66d0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Mon, 30 Jul 2018 14:17:41 +0200 Subject: [PATCH 1450/1506] drm/amdgpu: nuke amdgpu_bo_list_free MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The RCU grace period is harmless and avoiding it is not worth the effort of doubling the implementation. Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Chunming Zhou <david1.zhou@amd.com> Reviewed-by: Huang Rui <ray.huang@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c | 13 +------------ drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h | 1 - drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 2 +- 3 files changed, 2 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c index 556040e459316..5335f1b5459f6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c @@ -231,17 +231,6 @@ void amdgpu_bo_list_put(struct amdgpu_bo_list *list) kref_put(&list->refcount, amdgpu_bo_list_release_rcu); } -void amdgpu_bo_list_free(struct amdgpu_bo_list *list) -{ - unsigned i; - - for (i = 0; i < list->num_entries; ++i) - amdgpu_bo_unref(&list->array[i].robj); - - kvfree(list->array); - kfree(list); -} - int amdgpu_bo_create_list_entry_array(struct drm_amdgpu_bo_list_in *in, struct drm_amdgpu_bo_list_entry **info_param) { @@ -310,7 +299,7 @@ int amdgpu_bo_list_ioctl(struct drm_device *dev, void *data, r = idr_alloc(&fpriv->bo_list_handles, list, 1, 0, GFP_KERNEL); mutex_unlock(&fpriv->bo_list_lock); if (r < 0) { - amdgpu_bo_list_free(list); + amdgpu_bo_list_put(list); return r; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h index 89195fdcb1ef1..0ce540203db1b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h @@ -56,7 +56,6 @@ int amdgpu_bo_list_get(struct amdgpu_fpriv *fpriv, int id, void amdgpu_bo_list_get_list(struct amdgpu_bo_list *list, struct list_head *validated); void amdgpu_bo_list_put(struct amdgpu_bo_list *list); -void amdgpu_bo_list_free(struct amdgpu_bo_list *list); int amdgpu_bo_create_list_entry_array(struct drm_amdgpu_bo_list_in *in, struct drm_amdgpu_bo_list_entry **info_param); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index dd2132fa2b896..bd98cc5fb97bc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -967,7 +967,7 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev, amdgpu_bo_unref(&pd); idr_for_each_entry(&fpriv->bo_list_handles, list, handle) - amdgpu_bo_list_free(list); + amdgpu_bo_list_put(list); idr_destroy(&fpriv->bo_list_handles); mutex_destroy(&fpriv->bo_list_lock); -- GitLab From 39f7f69a6054bb9777b47b6afdb5ce2fae30dbee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Mon, 30 Jul 2018 15:37:46 +0200 Subject: [PATCH 1451/1506] drm/amdgpu: add bo_list iterators MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add helpers to iterate over all entries in a bo_list. Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Chunming Zhou <david1.zhou@amd.com> Acked-by: Huang Rui <ray.huang@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c | 21 +++++---- drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h | 10 ++++ drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 51 +++++++++------------ 3 files changed, 43 insertions(+), 39 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c index 5335f1b5459f6..096bcf4a63341 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c @@ -43,12 +43,12 @@ static int amdgpu_bo_list_set(struct amdgpu_device *adev, static void amdgpu_bo_list_release_rcu(struct kref *ref) { - unsigned i; struct amdgpu_bo_list *list = container_of(ref, struct amdgpu_bo_list, refcount); + struct amdgpu_bo_list_entry *e; - for (i = 0; i < list->num_entries; ++i) - amdgpu_bo_unref(&list->array[i].robj); + amdgpu_bo_list_for_each_entry(e, list) + amdgpu_bo_unref(&e->robj); kvfree(list->array); kfree_rcu(list, rhead); @@ -103,6 +103,7 @@ static int amdgpu_bo_list_set(struct amdgpu_device *adev, struct amdgpu_bo *oa_obj = adev->gds.oa_gfx_bo; unsigned last_entry = 0, first_userptr = num_entries; + struct amdgpu_bo_list_entry *e; uint64_t total_size = 0; unsigned i; int r; @@ -156,7 +157,7 @@ static int amdgpu_bo_list_set(struct amdgpu_device *adev, trace_amdgpu_bo_list_set(list, entry->robj); } - for (i = 0; i < list->num_entries; ++i) + amdgpu_bo_list_for_each_entry(e, list) amdgpu_bo_unref(&list->array[i].robj); kvfree(list->array); @@ -201,6 +202,7 @@ void amdgpu_bo_list_get_list(struct amdgpu_bo_list *list, * concatenated in descending order. */ struct list_head bucket[AMDGPU_BO_LIST_NUM_BUCKETS]; + struct amdgpu_bo_list_entry *e; unsigned i; for (i = 0; i < AMDGPU_BO_LIST_NUM_BUCKETS; i++) @@ -211,14 +213,13 @@ void amdgpu_bo_list_get_list(struct amdgpu_bo_list *list, * in the list, the sort mustn't change the ordering of buffers * with the same priority, i.e. it must be stable. */ - for (i = 0; i < list->num_entries; i++) { - unsigned priority = list->array[i].priority; + amdgpu_bo_list_for_each_entry(e, list) { + unsigned priority = e->priority; - if (!list->array[i].robj->parent) - list_add_tail(&list->array[i].tv.head, - &bucket[priority]); + if (!e->robj->parent) + list_add_tail(&e->tv.head, &bucket[priority]); - list->array[i].user_pages = NULL; + e->user_pages = NULL; } /* Connect the sorted buckets in the output list. */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h index 0ce540203db1b..3d77abfcd4a62 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h @@ -65,4 +65,14 @@ int amdgpu_bo_list_create(struct amdgpu_device *adev, unsigned num_entries, struct amdgpu_bo_list **list); +#define amdgpu_bo_list_for_each_entry(e, list) \ + for (e = &(list)->array[0]; \ + e != &(list)->array[(list)->num_entries]; \ + ++e) + +#define amdgpu_bo_list_for_each_userptr_entry(e, list) \ + for (e = &(list)->array[(list)->first_userptr]; \ + e != &(list)->array[(list)->num_entries]; \ + ++e) + #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index f7154f3ed8073..1d7292ab2b62f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -563,10 +563,10 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, struct amdgpu_fpriv *fpriv = p->filp->driver_priv; struct amdgpu_bo_list_entry *e; struct list_head duplicates; - unsigned i, tries = 10; struct amdgpu_bo *gds; struct amdgpu_bo *gws; struct amdgpu_bo *oa; + unsigned tries = 10; int r; INIT_LIST_HEAD(&p->validated); @@ -596,7 +596,6 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, while (1) { struct list_head need_pages; - unsigned i; r = ttm_eu_reserve_buffers(&p->ticket, &p->validated, true, &duplicates); @@ -611,12 +610,8 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, break; INIT_LIST_HEAD(&need_pages); - for (i = p->bo_list->first_userptr; - i < p->bo_list->num_entries; ++i) { - struct amdgpu_bo *bo; - - e = &p->bo_list->array[i]; - bo = e->robj; + amdgpu_bo_list_for_each_userptr_entry(e, p->bo_list) { + struct amdgpu_bo *bo = e->robj; if (amdgpu_ttm_tt_userptr_invalidated(bo->tbo.ttm, &e->user_invalidated) && e->user_pages) { @@ -710,16 +705,14 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, if (p->bo_list) { struct amdgpu_vm *vm = &fpriv->vm; - unsigned i; + struct amdgpu_bo_list_entry *e; gds = p->bo_list->gds_obj; gws = p->bo_list->gws_obj; oa = p->bo_list->oa_obj; - for (i = 0; i < p->bo_list->num_entries; i++) { - struct amdgpu_bo *bo = p->bo_list->array[i].robj; - p->bo_list->array[i].bo_va = amdgpu_vm_bo_find(vm, bo); - } + amdgpu_bo_list_for_each_entry(e, p->bo_list) + e->bo_va = amdgpu_vm_bo_find(vm, e->robj); } else { gds = p->adev->gds.gds_gfx_bo; gws = p->adev->gds.gws_gfx_bo; @@ -753,10 +746,7 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, error_free_pages: if (p->bo_list) { - for (i = p->bo_list->first_userptr; - i < p->bo_list->num_entries; ++i) { - e = &p->bo_list->array[i]; - + amdgpu_bo_list_for_each_userptr_entry(e, p->bo_list) { if (!e->user_pages) continue; @@ -830,7 +820,7 @@ static int amdgpu_bo_vm_update_pte(struct amdgpu_cs_parser *p) struct amdgpu_vm *vm = &fpriv->vm; struct amdgpu_bo_va *bo_va; struct amdgpu_bo *bo; - int i, r; + int r; r = amdgpu_vm_clear_freed(adev, vm, NULL); if (r) @@ -861,15 +851,17 @@ static int amdgpu_bo_vm_update_pte(struct amdgpu_cs_parser *p) } if (p->bo_list) { - for (i = 0; i < p->bo_list->num_entries; i++) { + struct amdgpu_bo_list_entry *e; + + amdgpu_bo_list_for_each_entry(e, p->bo_list) { struct dma_fence *f; /* ignore duplicates */ - bo = p->bo_list->array[i].robj; + bo = e->robj; if (!bo) continue; - bo_va = p->bo_list->array[i].bo_va; + bo_va = e->bo_va; if (bo_va == NULL) continue; @@ -898,14 +890,15 @@ static int amdgpu_bo_vm_update_pte(struct amdgpu_cs_parser *p) return r; if (amdgpu_vm_debug && p->bo_list) { + struct amdgpu_bo_list_entry *e; + /* Invalidate all BOs to test for userspace bugs */ - for (i = 0; i < p->bo_list->num_entries; i++) { + amdgpu_bo_list_for_each_entry(e, p->bo_list) { /* ignore duplicates */ - bo = p->bo_list->array[i].robj; - if (!bo) + if (!e->robj) continue; - amdgpu_vm_bo_invalidate(adev, bo, false); + amdgpu_vm_bo_invalidate(adev, e->robj, false); } } @@ -1225,16 +1218,16 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, struct drm_sched_entity *entity = &p->ctx->rings[ring->idx].entity; enum drm_sched_priority priority; struct amdgpu_job *job; - unsigned i; uint64_t seq; int r; amdgpu_mn_lock(p->mn); if (p->bo_list) { - for (i = p->bo_list->first_userptr; - i < p->bo_list->num_entries; ++i) { - struct amdgpu_bo *bo = p->bo_list->array[i].robj; + struct amdgpu_bo_list_entry *e; + + amdgpu_bo_list_for_each_userptr_entry(e, p->bo_list) { + struct amdgpu_bo *bo = e->robj; if (amdgpu_ttm_tt_userptr_needs_pages(bo->tbo.ttm)) { amdgpu_mn_unlock(p->mn); -- GitLab From 920990cb080a44203bf6c8eb706e79ad23241ad3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Mon, 30 Jul 2018 16:16:01 +0200 Subject: [PATCH 1452/1506] drm/amdgpu: allocate the bo_list array after the list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This avoids multiple allocations for the head and the array. Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Chunming Zhou <david1.zhou@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c | 114 ++++++++------------ drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h | 17 ++- 2 files changed, 57 insertions(+), 74 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c index 096bcf4a63341..d472a2c8399fe 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c @@ -35,13 +35,15 @@ #define AMDGPU_BO_LIST_MAX_PRIORITY 32u #define AMDGPU_BO_LIST_NUM_BUCKETS (AMDGPU_BO_LIST_MAX_PRIORITY + 1) -static int amdgpu_bo_list_set(struct amdgpu_device *adev, - struct drm_file *filp, - struct amdgpu_bo_list *list, - struct drm_amdgpu_bo_list_entry *info, - unsigned num_entries); +static void amdgpu_bo_list_free_rcu(struct rcu_head *rcu) +{ + struct amdgpu_bo_list *list = container_of(rcu, struct amdgpu_bo_list, + rhead); + + kvfree(list); +} -static void amdgpu_bo_list_release_rcu(struct kref *ref) +static void amdgpu_bo_list_free(struct kref *ref) { struct amdgpu_bo_list *list = container_of(ref, struct amdgpu_bo_list, refcount); @@ -50,67 +52,36 @@ static void amdgpu_bo_list_release_rcu(struct kref *ref) amdgpu_bo_list_for_each_entry(e, list) amdgpu_bo_unref(&e->robj); - kvfree(list->array); - kfree_rcu(list, rhead); + call_rcu(&list->rhead, amdgpu_bo_list_free_rcu); } -int amdgpu_bo_list_create(struct amdgpu_device *adev, - struct drm_file *filp, - struct drm_amdgpu_bo_list_entry *info, - unsigned num_entries, - struct amdgpu_bo_list **list_out) +int amdgpu_bo_list_create(struct amdgpu_device *adev, struct drm_file *filp, + struct drm_amdgpu_bo_list_entry *info, + unsigned num_entries, struct amdgpu_bo_list **result) { + unsigned last_entry = 0, first_userptr = num_entries; + struct amdgpu_bo_list_entry *array; struct amdgpu_bo_list *list; + uint64_t total_size = 0; + size_t size; + unsigned i; int r; + if (num_entries > SIZE_MAX / sizeof(struct amdgpu_bo_list_entry)) + return -EINVAL; - list = kzalloc(sizeof(struct amdgpu_bo_list), GFP_KERNEL); + size = sizeof(struct amdgpu_bo_list); + size += num_entries * sizeof(struct amdgpu_bo_list_entry); + list = kvmalloc(size, GFP_KERNEL); if (!list) return -ENOMEM; - /* initialize bo list*/ kref_init(&list->refcount); - r = amdgpu_bo_list_set(adev, filp, list, info, num_entries); - if (r) { - kfree(list); - return r; - } - - *list_out = list; - return 0; -} - -static void amdgpu_bo_list_destroy(struct amdgpu_fpriv *fpriv, int id) -{ - struct amdgpu_bo_list *list; - - mutex_lock(&fpriv->bo_list_lock); - list = idr_remove(&fpriv->bo_list_handles, id); - mutex_unlock(&fpriv->bo_list_lock); - if (list) - kref_put(&list->refcount, amdgpu_bo_list_release_rcu); -} - -static int amdgpu_bo_list_set(struct amdgpu_device *adev, - struct drm_file *filp, - struct amdgpu_bo_list *list, - struct drm_amdgpu_bo_list_entry *info, - unsigned num_entries) -{ - struct amdgpu_bo_list_entry *array; - struct amdgpu_bo *gds_obj = adev->gds.gds_gfx_bo; - struct amdgpu_bo *gws_obj = adev->gds.gws_gfx_bo; - struct amdgpu_bo *oa_obj = adev->gds.oa_gfx_bo; - - unsigned last_entry = 0, first_userptr = num_entries; - struct amdgpu_bo_list_entry *e; - uint64_t total_size = 0; - unsigned i; - int r; + list->gds_obj = adev->gds.gds_gfx_bo; + list->gws_obj = adev->gds.gws_gfx_bo; + list->oa_obj = adev->gds.oa_gfx_bo; - array = kvmalloc_array(num_entries, sizeof(struct amdgpu_bo_list_entry), GFP_KERNEL); - if (!array) - return -ENOMEM; + array = amdgpu_bo_list_array_entry(list, 0); memset(array, 0, num_entries * sizeof(struct amdgpu_bo_list_entry)); for (i = 0; i < num_entries; ++i) { @@ -147,36 +118,41 @@ static int amdgpu_bo_list_set(struct amdgpu_device *adev, entry->tv.shared = !entry->robj->prime_shared_count; if (entry->robj->preferred_domains == AMDGPU_GEM_DOMAIN_GDS) - gds_obj = entry->robj; + list->gds_obj = entry->robj; if (entry->robj->preferred_domains == AMDGPU_GEM_DOMAIN_GWS) - gws_obj = entry->robj; + list->gws_obj = entry->robj; if (entry->robj->preferred_domains == AMDGPU_GEM_DOMAIN_OA) - oa_obj = entry->robj; + list->oa_obj = entry->robj; total_size += amdgpu_bo_size(entry->robj); trace_amdgpu_bo_list_set(list, entry->robj); } - amdgpu_bo_list_for_each_entry(e, list) - amdgpu_bo_unref(&list->array[i].robj); - - kvfree(list->array); - - list->gds_obj = gds_obj; - list->gws_obj = gws_obj; - list->oa_obj = oa_obj; list->first_userptr = first_userptr; - list->array = array; list->num_entries = num_entries; trace_amdgpu_cs_bo_status(list->num_entries, total_size); + + *result = list; return 0; error_free: while (i--) amdgpu_bo_unref(&array[i].robj); - kvfree(array); + kvfree(list); return r; + +} + +static void amdgpu_bo_list_destroy(struct amdgpu_fpriv *fpriv, int id) +{ + struct amdgpu_bo_list *list; + + mutex_lock(&fpriv->bo_list_lock); + list = idr_remove(&fpriv->bo_list_handles, id); + mutex_unlock(&fpriv->bo_list_lock); + if (list) + kref_put(&list->refcount, amdgpu_bo_list_free); } int amdgpu_bo_list_get(struct amdgpu_fpriv *fpriv, int id, @@ -229,7 +205,7 @@ void amdgpu_bo_list_get_list(struct amdgpu_bo_list *list, void amdgpu_bo_list_put(struct amdgpu_bo_list *list) { - kref_put(&list->refcount, amdgpu_bo_list_release_rcu); + kref_put(&list->refcount, amdgpu_bo_list_free); } int amdgpu_bo_create_list_entry_array(struct drm_amdgpu_bo_list_in *in, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h index 3d77abfcd4a62..61b089768e1ce 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h @@ -48,7 +48,6 @@ struct amdgpu_bo_list { struct amdgpu_bo *oa_obj; unsigned first_userptr; unsigned num_entries; - struct amdgpu_bo_list_entry *array; }; int amdgpu_bo_list_get(struct amdgpu_fpriv *fpriv, int id, @@ -65,14 +64,22 @@ int amdgpu_bo_list_create(struct amdgpu_device *adev, unsigned num_entries, struct amdgpu_bo_list **list); +static inline struct amdgpu_bo_list_entry * +amdgpu_bo_list_array_entry(struct amdgpu_bo_list *list, unsigned index) +{ + struct amdgpu_bo_list_entry *array = (void *)&list[1]; + + return &array[index]; +} + #define amdgpu_bo_list_for_each_entry(e, list) \ - for (e = &(list)->array[0]; \ - e != &(list)->array[(list)->num_entries]; \ + for (e = amdgpu_bo_list_array_entry(list, 0); \ + e != amdgpu_bo_list_array_entry(list, (list)->num_entries); \ ++e) #define amdgpu_bo_list_for_each_userptr_entry(e, list) \ - for (e = &(list)->array[(list)->first_userptr]; \ - e != &(list)->array[(list)->num_entries]; \ + for (e = amdgpu_bo_list_array_entry(list, (list)->first_userptr); \ + e != amdgpu_bo_list_array_entry(list, (list)->num_entries); \ ++e) #endif -- GitLab From 4a102ad4ba0daf886dcf0927ce2a7f6c3b3a615c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Mon, 30 Jul 2018 16:44:14 +0200 Subject: [PATCH 1453/1506] drm/amdgpu: create an empty bo_list if no handle is provided MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of having extra handling just create an empty bo_list when no handle is provided. Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Chunming Zhou <david1.zhou@amd.com> Reviewed-by: Huang Rui <ray.huang@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 111 ++++++++++--------------- 1 file changed, 46 insertions(+), 65 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 1d7292ab2b62f..502b94fb116a7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -561,6 +561,7 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, union drm_amdgpu_cs *cs) { struct amdgpu_fpriv *fpriv = p->filp->driver_priv; + struct amdgpu_vm *vm = &fpriv->vm; struct amdgpu_bo_list_entry *e; struct list_head duplicates; struct amdgpu_bo *gds; @@ -580,13 +581,17 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, &p->bo_list); if (r) return r; + } else if (!p->bo_list) { + /* Create a empty bo_list when no handle is provided */ + r = amdgpu_bo_list_create(p->adev, p->filp, NULL, 0, + &p->bo_list); + if (r) + return r; } - if (p->bo_list) { - amdgpu_bo_list_get_list(p->bo_list, &p->validated); - if (p->bo_list->first_userptr != p->bo_list->num_entries) - p->mn = amdgpu_mn_get(p->adev, AMDGPU_MN_TYPE_GFX); - } + amdgpu_bo_list_get_list(p->bo_list, &p->validated); + if (p->bo_list->first_userptr != p->bo_list->num_entries) + p->mn = amdgpu_mn_get(p->adev, AMDGPU_MN_TYPE_GFX); INIT_LIST_HEAD(&duplicates); amdgpu_vm_get_pd_bo(&fpriv->vm, &p->validated, &p->vm_pd); @@ -605,10 +610,6 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, goto error_free_pages; } - /* Without a BO list we don't have userptr BOs */ - if (!p->bo_list) - break; - INIT_LIST_HEAD(&need_pages); amdgpu_bo_list_for_each_userptr_entry(e, p->bo_list) { struct amdgpu_bo *bo = e->robj; @@ -703,21 +704,12 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, amdgpu_cs_report_moved_bytes(p->adev, p->bytes_moved, p->bytes_moved_vis); - if (p->bo_list) { - struct amdgpu_vm *vm = &fpriv->vm; - struct amdgpu_bo_list_entry *e; + gds = p->bo_list->gds_obj; + gws = p->bo_list->gws_obj; + oa = p->bo_list->oa_obj; - gds = p->bo_list->gds_obj; - gws = p->bo_list->gws_obj; - oa = p->bo_list->oa_obj; - - amdgpu_bo_list_for_each_entry(e, p->bo_list) - e->bo_va = amdgpu_vm_bo_find(vm, e->robj); - } else { - gds = p->adev->gds.gds_gfx_bo; - gws = p->adev->gds.gws_gfx_bo; - oa = p->adev->gds.oa_gfx_bo; - } + amdgpu_bo_list_for_each_entry(e, p->bo_list) + e->bo_va = amdgpu_vm_bo_find(vm, e->robj); if (gds) { p->job->gds_base = amdgpu_bo_gpu_offset(gds); @@ -745,15 +737,13 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, error_free_pages: - if (p->bo_list) { - amdgpu_bo_list_for_each_userptr_entry(e, p->bo_list) { - if (!e->user_pages) - continue; + amdgpu_bo_list_for_each_userptr_entry(e, p->bo_list) { + if (!e->user_pages) + continue; - release_pages(e->user_pages, - e->robj->tbo.ttm->num_pages); - kvfree(e->user_pages); - } + release_pages(e->user_pages, + e->robj->tbo.ttm->num_pages); + kvfree(e->user_pages); } return r; @@ -815,9 +805,10 @@ static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser, int error, static int amdgpu_bo_vm_update_pte(struct amdgpu_cs_parser *p) { - struct amdgpu_device *adev = p->adev; struct amdgpu_fpriv *fpriv = p->filp->driver_priv; + struct amdgpu_device *adev = p->adev; struct amdgpu_vm *vm = &fpriv->vm; + struct amdgpu_bo_list_entry *e; struct amdgpu_bo_va *bo_va; struct amdgpu_bo *bo; int r; @@ -850,31 +841,26 @@ static int amdgpu_bo_vm_update_pte(struct amdgpu_cs_parser *p) return r; } - if (p->bo_list) { - struct amdgpu_bo_list_entry *e; - - amdgpu_bo_list_for_each_entry(e, p->bo_list) { - struct dma_fence *f; - - /* ignore duplicates */ - bo = e->robj; - if (!bo) - continue; + amdgpu_bo_list_for_each_entry(e, p->bo_list) { + struct dma_fence *f; - bo_va = e->bo_va; - if (bo_va == NULL) - continue; + /* ignore duplicates */ + bo = e->robj; + if (!bo) + continue; - r = amdgpu_vm_bo_update(adev, bo_va, false); - if (r) - return r; + bo_va = e->bo_va; + if (bo_va == NULL) + continue; - f = bo_va->last_pt_update; - r = amdgpu_sync_fence(adev, &p->job->sync, f, false); - if (r) - return r; - } + r = amdgpu_vm_bo_update(adev, bo_va, false); + if (r) + return r; + f = bo_va->last_pt_update; + r = amdgpu_sync_fence(adev, &p->job->sync, f, false); + if (r) + return r; } r = amdgpu_vm_handle_moved(adev, vm); @@ -889,9 +875,7 @@ static int amdgpu_bo_vm_update_pte(struct amdgpu_cs_parser *p) if (r) return r; - if (amdgpu_vm_debug && p->bo_list) { - struct amdgpu_bo_list_entry *e; - + if (amdgpu_vm_debug) { /* Invalidate all BOs to test for userspace bugs */ amdgpu_bo_list_for_each_entry(e, p->bo_list) { /* ignore duplicates */ @@ -1217,22 +1201,19 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, struct amdgpu_ring *ring = p->ring; struct drm_sched_entity *entity = &p->ctx->rings[ring->idx].entity; enum drm_sched_priority priority; + struct amdgpu_bo_list_entry *e; struct amdgpu_job *job; uint64_t seq; int r; amdgpu_mn_lock(p->mn); - if (p->bo_list) { - struct amdgpu_bo_list_entry *e; + amdgpu_bo_list_for_each_userptr_entry(e, p->bo_list) { + struct amdgpu_bo *bo = e->robj; - amdgpu_bo_list_for_each_userptr_entry(e, p->bo_list) { - struct amdgpu_bo *bo = e->robj; - - if (amdgpu_ttm_tt_userptr_needs_pages(bo->tbo.ttm)) { - amdgpu_mn_unlock(p->mn); - return -ERESTARTSYS; - } + if (amdgpu_ttm_tt_userptr_needs_pages(bo->tbo.ttm)) { + amdgpu_mn_unlock(p->mn); + return -ERESTARTSYS; } } -- GitLab From 43bce41cf48eb51eab5ad9e0d40ed382a7bb61d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Thu, 26 Jul 2018 13:43:49 +0200 Subject: [PATCH 1454/1506] drm/scheduler: only kill entity if last user is killed v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Note which task is using the entity and only kill it if the last user of the entity is killed. This should prevent problems when entities are leaked to child processes. v2: add missing kernel doc Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com> Acked-by: Nayan Deshmukh <nayan26deshmukh@gmail.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/scheduler/gpu_scheduler.c | 6 +++++- include/drm/gpu_scheduler.h | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/scheduler/gpu_scheduler.c b/drivers/gpu/drm/scheduler/gpu_scheduler.c index 3f2fc5e8242ab..f563e4fbb4b68 100644 --- a/drivers/gpu/drm/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/scheduler/gpu_scheduler.c @@ -275,6 +275,7 @@ static void drm_sched_entity_kill_jobs_cb(struct dma_fence *f, long drm_sched_entity_flush(struct drm_sched_entity *entity, long timeout) { struct drm_gpu_scheduler *sched; + struct task_struct *last_user; long ret = timeout; sched = entity->rq->sched; @@ -295,7 +296,9 @@ long drm_sched_entity_flush(struct drm_sched_entity *entity, long timeout) /* For killed process disable any more IBs enqueue right now */ - if ((current->flags & PF_EXITING) && (current->exit_code == SIGKILL)) + last_user = cmpxchg(&entity->last_user, current->group_leader, NULL); + if ((!last_user || last_user == current->group_leader) && + (current->flags & PF_EXITING) && (current->exit_code == SIGKILL)) drm_sched_entity_set_rq(entity, NULL); return ret; @@ -541,6 +544,7 @@ void drm_sched_entity_push_job(struct drm_sched_job *sched_job, trace_drm_sched_job(sched_job, entity); + WRITE_ONCE(entity->last_user, current->group_leader); first = spsc_queue_push(&entity->job_queue, &sched_job->queue_node); /* first job wakes up scheduler */ diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h index 091b9afcd184c..21c648b0b2a16 100644 --- a/include/drm/gpu_scheduler.h +++ b/include/drm/gpu_scheduler.h @@ -66,6 +66,7 @@ enum drm_sched_priority { * @guilty: points to ctx's guilty. * @fini_status: contains the exit status in case the process was signalled. * @last_scheduled: points to the finished fence of the last scheduled job. + * @last_user: last group leader pushing a job into the entity. * * Entities will emit jobs in order to their corresponding hardware * ring, and the scheduler will alternate between entities based on @@ -85,6 +86,7 @@ struct drm_sched_entity { struct dma_fence_cb cb; atomic_t *guilty; struct dma_fence *last_scheduled; + struct task_struct *last_user; }; /** -- GitLab From a875f58e237a0009c337dd140e4f92a7cffab7af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com> Date: Mon, 30 Jul 2018 11:40:06 +0200 Subject: [PATCH 1455/1506] drm/scheduler: stop setting rq to NULL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We removed the redundancy of having an extra scheduler field, so we can't set the rq to NULL any more or otherwise won't know which scheduler to use for the cleanup. Just remove the entity from the scheduling list instead. Signed-off-by: Christian König <christian.koenig@amd.com> Acked-by: Nayan Deshmukh <nayan26deshmukh@gmail.com> Bug: https://bugs.freedesktop.org/show_bug.cgi?id=107367 Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/scheduler/gpu_scheduler.c | 35 ++++++----------------- 1 file changed, 8 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/scheduler/gpu_scheduler.c b/drivers/gpu/drm/scheduler/gpu_scheduler.c index f563e4fbb4b68..1b733229201ed 100644 --- a/drivers/gpu/drm/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/scheduler/gpu_scheduler.c @@ -198,21 +198,6 @@ int drm_sched_entity_init(struct drm_sched_entity *entity, } EXPORT_SYMBOL(drm_sched_entity_init); -/** - * drm_sched_entity_is_initialized - Query if entity is initialized - * - * @sched: Pointer to scheduler instance - * @entity: The pointer to a valid scheduler entity - * - * return true if entity is initialized, false otherwise -*/ -static bool drm_sched_entity_is_initialized(struct drm_gpu_scheduler *sched, - struct drm_sched_entity *entity) -{ - return entity->rq != NULL && - entity->rq->sched == sched; -} - /** * drm_sched_entity_is_idle - Check if entity is idle * @@ -224,7 +209,8 @@ static bool drm_sched_entity_is_idle(struct drm_sched_entity *entity) { rmb(); - if (!entity->rq || spsc_queue_peek(&entity->job_queue) == NULL) + if (list_empty(&entity->list) || + spsc_queue_peek(&entity->job_queue) == NULL) return true; return false; @@ -279,8 +265,6 @@ long drm_sched_entity_flush(struct drm_sched_entity *entity, long timeout) long ret = timeout; sched = entity->rq->sched; - if (!drm_sched_entity_is_initialized(sched, entity)) - return ret; /** * The client will not queue more IBs during this fini, consume existing * queued IBs or discard them on SIGKILL @@ -299,7 +283,7 @@ long drm_sched_entity_flush(struct drm_sched_entity *entity, long timeout) last_user = cmpxchg(&entity->last_user, current->group_leader, NULL); if ((!last_user || last_user == current->group_leader) && (current->flags & PF_EXITING) && (current->exit_code == SIGKILL)) - drm_sched_entity_set_rq(entity, NULL); + drm_sched_rq_remove_entity(entity->rq, entity); return ret; } @@ -320,7 +304,7 @@ void drm_sched_entity_fini(struct drm_sched_entity *entity) struct drm_gpu_scheduler *sched; sched = entity->rq->sched; - drm_sched_entity_set_rq(entity, NULL); + drm_sched_rq_remove_entity(entity->rq, entity); /* Consumption of existing IBs wasn't completed. Forcefully * remove them here. @@ -416,15 +400,12 @@ void drm_sched_entity_set_rq(struct drm_sched_entity *entity, if (entity->rq == rq) return; - spin_lock(&entity->rq_lock); - - if (entity->rq) - drm_sched_rq_remove_entity(entity->rq, entity); + BUG_ON(!rq); + spin_lock(&entity->rq_lock); + drm_sched_rq_remove_entity(entity->rq, entity); entity->rq = rq; - if (rq) - drm_sched_rq_add_entity(rq, entity); - + drm_sched_rq_add_entity(rq, entity); spin_unlock(&entity->rq_lock); } EXPORT_SYMBOL(drm_sched_entity_set_rq); -- GitLab From 71d5ef11273b3dbdb57be7d2940dcee70007ae84 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann <tzimmermann@suse.de> Date: Tue, 31 Jul 2018 09:12:35 +0200 Subject: [PATCH 1456/1506] drm/amdgpu: Replace ttm_bo_reference with ttm_bo_get MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function ttm_bo_get acquires a reference on a TTM buffer object. The function's name is more aligned to the Linux kernel convention of naming ref-counting function _get and _put. v2: * changed prefix to drm/amdgpu Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 21bfa2d8039e0..f7ac9abf9cc11 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -825,7 +825,7 @@ struct amdgpu_bo *amdgpu_bo_ref(struct amdgpu_bo *bo) if (bo == NULL) return NULL; - ttm_bo_reference(&bo->tbo); + ttm_bo_get(&bo->tbo); return bo; } -- GitLab From fea872b279c8cd9433a3c9bb91949643cf645e07 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann <tzimmermann@suse.de> Date: Tue, 31 Jul 2018 09:12:36 +0200 Subject: [PATCH 1457/1506] drm/amdgpu: Replace ttm_bo_unref with ttm_bo_put MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function ttm_bo_put releases a reference to a TTM buffer object. The function's name is more aligned to the Linux kernel convention of naming ref-counting function _get and _put. A call to ttm_bo_unref takes the address of the TTM BO object's pointer and clears the pointer's value to NULL. This is not necessary in most cases and sometimes even worked around by the calling code. A call to ttm_bo_put only releases the reference without clearing the pointer. The current behaviour of cleaning the pointer is kept in the calling code, but should be removed if not required in a later patch. v2: * set prefix to drm/amdgpu Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index f7ac9abf9cc11..b0e14a3d54efd 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -843,9 +843,8 @@ void amdgpu_bo_unref(struct amdgpu_bo **bo) return; tbo = &((*bo)->tbo); - ttm_bo_unref(&tbo); - if (tbo == NULL) - *bo = NULL; + ttm_bo_put(tbo); + *bo = NULL; } /** -- GitLab From 269a8b6e342501fa221a398dd2730b7af7e94a5d Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann <tzimmermann@suse.de> Date: Tue, 31 Jul 2018 08:16:58 +0200 Subject: [PATCH 1458/1506] drm/radeon: Replace ttm_bo_reference with ttm_bo_get MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function ttm_bo_get acquires a reference on a TTM buffer object. The function's name is more aligned to the Linux kernel convention of naming ref-counting function _get and _put. Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/radeon/radeon_object.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index edbb4cd519fd6..1a9d4f547024f 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -307,7 +307,7 @@ struct radeon_bo *radeon_bo_ref(struct radeon_bo *bo) if (bo == NULL) return NULL; - ttm_bo_reference(&bo->tbo); + ttm_bo_get(&bo->tbo); return bo; } -- GitLab From 77605e43701578892e98a39383071f1a8503ff8f Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann <tzimmermann@suse.de> Date: Tue, 31 Jul 2018 08:16:59 +0200 Subject: [PATCH 1459/1506] drm/radeon: Replace ttm_bo_unref with ttm_bo_put MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function ttm_bo_put releases a reference to a TTM buffer object. The function's name is more aligned to the Linux kernel convention of naming ref-counting function _get and _put. A call to ttm_bo_unref takes the address of the TTM BO object's pointer and clears the pointer's value to NULL. This is not necessary in most cases and sometimes even worked around by the calling code. A call to ttm_bo_put only releases the reference without clearing the pointer. The current behaviour of cleaning the pointer is kept in the calling code, but should be removed if not required in a later patch. Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/radeon/radeon_object.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 1a9d4f547024f..ba2fd295697fe 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -320,9 +320,8 @@ void radeon_bo_unref(struct radeon_bo **bo) return; rdev = (*bo)->rdev; tbo = &((*bo)->tbo); - ttm_bo_unref(&tbo); - if (tbo == NULL) - *bo = NULL; + ttm_bo_put(tbo); + *bo = NULL; } int radeon_bo_pin_restricted(struct radeon_bo *bo, u32 domain, u64 max_offset, -- GitLab From 7ac7aebe85d3b3b57a58efefcdde2bd5d398550d Mon Sep 17 00:00:00 2001 From: Colin Ian King <colin.king@canonical.com> Date: Tue, 31 Jul 2018 11:42:54 +0100 Subject: [PATCH 1460/1506] drm/amd/display: add missing void parameter to dc_create_transfer_func Add a missing void parameter to function dc_create_transfer_func, fixes sparse warning: warning: non-ANSI function declaration of function 'dc_create_transfer_func' Signed-off-by: Colin Ian King <colin.king@canonical.com> Reviewed-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/core/dc_surface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_surface.c b/drivers/gpu/drm/amd/display/dc/core/dc_surface.c index 815dfb50089b8..8fb3aefd195ca 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_surface.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_surface.c @@ -192,7 +192,7 @@ void dc_transfer_func_release(struct dc_transfer_func *tf) kref_put(&tf->refcount, dc_transfer_func_free); } -struct dc_transfer_func *dc_create_transfer_func() +struct dc_transfer_func *dc_create_transfer_func(void) { struct dc_transfer_func *tf = kvzalloc(sizeof(*tf), GFP_KERNEL); -- GitLab From ddf74e79a54070f277ae520722d3bab7f7a6c67a Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" <gustavo@embeddedor.com> Date: Mon, 23 Jul 2018 11:32:32 -0500 Subject: [PATCH 1461/1506] drm/amdgpu/pm: Fix potential Spectre v1 idx can be indirectly controlled by user-space, hence leading to a potential exploitation of the Spectre variant 1 vulnerability. This issue was detected with the help of Smatch: drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c:408 amdgpu_set_pp_force_state() warn: potential spectre issue 'data.states' Fix this by sanitizing idx before using it to index data.states Notice that given that speculation windows are large, the policy is to kill the speculation on the first load and not worry if it can be completed with a dependent load/store [1]. [1] https://marc.info/?l=linux-kernel&m=152449131114778&w=2 Cc: stable@vger.kernel.org Signed-off-by: Gustavo A. R. Silva <gustavo@embeddedor.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c index 23fc1d32b937e..8f98629fbe593 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c @@ -31,7 +31,7 @@ #include <linux/power_supply.h> #include <linux/hwmon.h> #include <linux/hwmon-sysfs.h> - +#include <linux/nospec.h> static int amdgpu_debugfs_pm_init(struct amdgpu_device *adev); @@ -403,6 +403,7 @@ static ssize_t amdgpu_set_pp_force_state(struct device *dev, count = -EINVAL; goto fail; } + idx = array_index_nospec(idx, ARRAY_SIZE(data.states)); amdgpu_dpm_get_pp_num_states(adev, &data); state = data.states[idx]; -- GitLab From 64f2cafc3da77da7b176f2cdc3eb3fdb031c639f Mon Sep 17 00:00:00 2001 From: Souptick Joarder <jrdr.linux@gmail.com> Date: Wed, 1 Aug 2018 00:58:33 +0530 Subject: [PATCH 1462/1506] drm/imx: Convert drm_atomic_helper_suspend/resume() convert drm_atomic_helper_suspend/resume() to use drm_mode_config_helper_suspend/resume(). with this conversion, the remaining member of struct imx_drm_device, state, will be no more useful and it could be removed forever. Signed-off-by: Souptick Joarder <jrdr.linux@gmail.com> Signed-off-by: Ajit Negi <ajitn.linux@gmail.com> [p.zabel@pengutronix.de: rebased onto drm-next, updated commit message] Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de> --- drivers/gpu/drm/imx/imx-drm-core.c | 42 ++---------------------------- 1 file changed, 2 insertions(+), 40 deletions(-) diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c index f0122afcf2a88..5ea0c82f99577 100644 --- a/drivers/gpu/drm/imx/imx-drm-core.c +++ b/drivers/gpu/drm/imx/imx-drm-core.c @@ -35,11 +35,6 @@ #define MAX_CRTC 4 -struct imx_drm_device { - struct drm_device *drm; - struct drm_atomic_state *state; -}; - #if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION) static int legacyfb_depth = 16; module_param(legacyfb_depth, int, 0444); @@ -218,22 +213,12 @@ static int compare_of(struct device *dev, void *data) static int imx_drm_bind(struct device *dev) { struct drm_device *drm; - struct imx_drm_device *imxdrm; int ret; drm = drm_dev_alloc(&imx_drm_driver, dev); if (IS_ERR(drm)) return PTR_ERR(drm); - imxdrm = devm_kzalloc(dev, sizeof(*imxdrm), GFP_KERNEL); - if (!imxdrm) { - ret = -ENOMEM; - goto err_put; - } - - imxdrm->drm = drm; - drm->dev_private = imxdrm; - /* * enable drm irq mode. * - with irq_enabled = true, we can use the vblank feature. @@ -305,7 +290,6 @@ static int imx_drm_bind(struct device *dev) component_unbind_all(drm->dev, drm); err_kms: drm_mode_config_cleanup(drm); -err_put: drm_dev_put(drm); return ret; @@ -354,37 +338,15 @@ static int imx_drm_platform_remove(struct platform_device *pdev) static int imx_drm_suspend(struct device *dev) { struct drm_device *drm_dev = dev_get_drvdata(dev); - struct imx_drm_device *imxdrm; - - /* The drm_dev is NULL before .load hook is called */ - if (drm_dev == NULL) - return 0; - - drm_kms_helper_poll_disable(drm_dev); - imxdrm = drm_dev->dev_private; - imxdrm->state = drm_atomic_helper_suspend(drm_dev); - if (IS_ERR(imxdrm->state)) { - drm_kms_helper_poll_enable(drm_dev); - return PTR_ERR(imxdrm->state); - } - - return 0; + return drm_mode_config_helper_suspend(drm_dev); } static int imx_drm_resume(struct device *dev) { struct drm_device *drm_dev = dev_get_drvdata(dev); - struct imx_drm_device *imx_drm; - if (drm_dev == NULL) - return 0; - - imx_drm = drm_dev->dev_private; - drm_atomic_helper_resume(drm_dev, imx_drm->state); - drm_kms_helper_poll_enable(drm_dev); - - return 0; + return drm_mode_config_helper_resume(drm_dev); } #endif -- GitLab From fe710322b81343601ca1759a9f3d4b694ed72fca Mon Sep 17 00:00:00 2001 From: Huang Rui <ray.huang@amd.com> Date: Wed, 1 Aug 2018 13:49:31 +0800 Subject: [PATCH 1463/1506] drm/ttm: fix missed conversion of set_pages_array_uc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch fixed the error when do not configure CONFIG_X86, otherwise, below error will be encountered. All errors (new ones prefixed by >>): drivers/gpu/drm/ttm/ttm_page_alloc_dma.c: In function 'ttm_set_pages_caching': >> drivers/gpu/drm/ttm/ttm_page_alloc_dma.c:272:7: error: implicit declaration of function 'set_pages_array_uc'; did you mean +'ttm_set_pages_array_uc'? [-Werror=implicit-function-declaration] r = set_pages_array_uc(pages, cpages); ^~~~~~~~~~~~~~~~~~ ttm_set_pages_array_uc cc1: some warnings being treated as errors Reported-by: kbuild test robot <lkp@intel.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Huang Rui <ray.huang@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/ttm/ttm_page_alloc_dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c b/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c index 8304917294a2e..507be7ac11655 100644 --- a/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c +++ b/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c @@ -269,7 +269,7 @@ static int ttm_set_pages_caching(struct dma_pool *pool, int r = 0; /* Set page caching */ if (pool->type & IS_UC) { - r = set_pages_array_uc(pages, cpages); + r = ttm_set_pages_array_uc(pages, cpages); if (r) pr_err("%s: Failed to set %d pages to uc!\n", pool->dev_name, cpages); -- GitLab From dceb219fc60766006bfe8e53afa62816b94fcb11 Mon Sep 17 00:00:00 2001 From: Huang Rui <ray.huang@amd.com> Date: Wed, 1 Aug 2018 13:49:32 +0800 Subject: [PATCH 1464/1506] drm/ttm: Add ttm_set_pages_wc and ttm_set_pages_uc helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These two helpers will be used on set page caching. Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Huang Rui <ray.huang@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- include/drm/ttm/ttm_set_memory.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/include/drm/ttm/ttm_set_memory.h b/include/drm/ttm/ttm_set_memory.h index a70723cf208b2..7c492b49e38cd 100644 --- a/include/drm/ttm/ttm_set_memory.h +++ b/include/drm/ttm/ttm_set_memory.h @@ -57,6 +57,18 @@ static inline int ttm_set_pages_wb(struct page *page, int numpages) return set_pages_wb(page, numpages); } +static inline int ttm_set_pages_wc(struct page *page, int numpages) +{ + unsigned long addr = (unsigned long)page_address(page); + + return set_memory_wc(addr, numpages); +} + +static inline int ttm_set_pages_uc(struct page *page, int numpages) +{ + return set_pages_uc(page, numpages); +} + #else /* for CONFIG_X86 */ #if IS_ENABLED(CONFIG_AGP) @@ -123,6 +135,16 @@ static inline int ttm_set_pages_wb(struct page *page, int numpages) #endif /* for CONFIG_AGP */ +static inline int ttm_set_pages_wc(struct page *page, int numpages) +{ + return 0; +} + +static inline int ttm_set_pages_uc(struct page *page, int numpages) +{ + return 0; +} + #endif /* for CONFIG_X86 */ #endif -- GitLab From df36b2fb8390d98453fff1aae3927095fe9ff36c Mon Sep 17 00:00:00 2001 From: Huang Rui <ray.huang@amd.com> Date: Wed, 1 Aug 2018 13:49:33 +0800 Subject: [PATCH 1465/1506] drm/ttm: clean up non-x86 definitions on ttm_tt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All non-x86 definitions are moved to ttm_set_memory header, so remove it from ttm_tt.c. Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Huang Rui <ray.huang@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/ttm/ttm_tt.c | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index a1e543972ca7b..e3a0691582ffd 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -38,9 +38,7 @@ #include <drm/drm_cache.h> #include <drm/ttm/ttm_bo_driver.h> #include <drm/ttm/ttm_page_alloc.h> -#ifdef CONFIG_X86 -#include <asm/set_memory.h> -#endif +#include <drm/ttm/ttm_set_memory.h> /** * Allocates a ttm structure for the given BO. @@ -115,10 +113,9 @@ static int ttm_sg_tt_alloc_page_directory(struct ttm_dma_tt *ttm) return 0; } -#ifdef CONFIG_X86 -static inline int ttm_tt_set_page_caching(struct page *p, - enum ttm_caching_state c_old, - enum ttm_caching_state c_new) +static int ttm_tt_set_page_caching(struct page *p, + enum ttm_caching_state c_old, + enum ttm_caching_state c_new) { int ret = 0; @@ -129,26 +126,18 @@ static inline int ttm_tt_set_page_caching(struct page *p, /* p isn't in the default caching state, set it to * writeback first to free its current memtype. */ - ret = set_pages_wb(p, 1); + ret = ttm_set_pages_wb(p, 1); if (ret) return ret; } if (c_new == tt_wc) - ret = set_memory_wc((unsigned long) page_address(p), 1); + ret = ttm_set_pages_wc(p, 1); else if (c_new == tt_uncached) - ret = set_pages_uc(p, 1); + ret = ttm_set_pages_uc(p, 1); return ret; } -#else /* CONFIG_X86 */ -static inline int ttm_tt_set_page_caching(struct page *p, - enum ttm_caching_state c_old, - enum ttm_caching_state c_new) -{ - return 0; -} -#endif /* CONFIG_X86 */ /* * Change caching policy for the linear kernel map -- GitLab From b1eb4f844f8c35e252eebfacacc438644d9f9ba8 Mon Sep 17 00:00:00 2001 From: Peter Rosin <peda@axentia.se> Date: Thu, 2 Aug 2018 10:25:19 +0100 Subject: [PATCH 1466/1506] drm/i2c: tda998x: find the drm_device via the drm_connector This prepares for being a drm_bridge which will not register the encoder. That makes the connector the better choice. Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Peter Rosin <peda@axentia.se> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/i2c/tda998x_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index 0038c976536ac..c39f7c36ba246 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -762,7 +762,7 @@ static void tda998x_detect_work(struct work_struct *work) { struct tda998x_priv *priv = container_of(work, struct tda998x_priv, detect_work); - struct drm_device *dev = priv->encoder.dev; + struct drm_device *dev = priv->connector.dev; if (dev) drm_kms_helper_hotplug_event(dev); -- GitLab From 2c6e758332a4fdf0d2b1c76adba10961afdabc8a Mon Sep 17 00:00:00 2001 From: Peter Rosin <peda@axentia.se> Date: Thu, 2 Aug 2018 10:25:19 +0100 Subject: [PATCH 1467/1506] drm/i2c: tda998x: split tda998x_encoder_dpms into enable/disable This fits better with the drm_bridge callbacks for when this driver becomes a drm_bridge. Suggested-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Peter Rosin <peda@axentia.se> [edited by rmk to just split the tda998x_encoder_dpms() function and restore the double-disable protection we originally had, preserving original behaviour.] Tested-by: Peter Rosin <peda@axentia.se> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/i2c/tda998x_drv.c | 37 +++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index c39f7c36ba246..f9a9fb6b97d0c 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -1308,18 +1308,9 @@ static int tda998x_connector_init(struct tda998x_priv *priv, /* DRM encoder functions */ -static void tda998x_encoder_dpms(struct drm_encoder *encoder, int mode) +static void tda998x_enable(struct tda998x_priv *priv) { - struct tda998x_priv *priv = enc_to_tda998x_priv(encoder); - bool on; - - /* we only care about on or off: */ - on = mode == DRM_MODE_DPMS_ON; - - if (on == priv->is_on) - return; - - if (on) { + if (!priv->is_on) { /* enable video ports, audio will be enabled later */ reg_write(priv, REG_ENA_VP_0, 0xff); reg_write(priv, REG_ENA_VP_1, 0xff); @@ -1330,7 +1321,12 @@ static void tda998x_encoder_dpms(struct drm_encoder *encoder, int mode) reg_write(priv, REG_VIP_CNTRL_2, priv->vip_cntrl_2); priv->is_on = true; - } else { + } +} + +static void tda998x_disable(struct tda998x_priv *priv) +{ + if (priv->is_on) { /* disable video ports */ reg_write(priv, REG_ENA_VP_0, 0x00); reg_write(priv, REG_ENA_VP_1, 0x00); @@ -1340,6 +1336,23 @@ static void tda998x_encoder_dpms(struct drm_encoder *encoder, int mode) } } +static void tda998x_encoder_dpms(struct drm_encoder *encoder, int mode) +{ + struct tda998x_priv *priv = enc_to_tda998x_priv(encoder); + bool on; + + /* we only care about on or off: */ + on = mode == DRM_MODE_DPMS_ON; + + if (on == priv->is_on) + return; + + if (on) + tda998x_enable(priv); + else + tda998x_disable(priv); +} + static void tda998x_encoder_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, -- GitLab From 6c1187aaa2912fad40119140286160cfd9f4ac2f Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Thu, 2 Aug 2018 10:25:19 +0100 Subject: [PATCH 1468/1506] drm/i2c: tda998x: move tda998x_set_config() into tda998x_create() Move the non-DT configuration of the TDA998x into tda998x_create() so that we do all setup in one place. Tested-by: Peter Rosin <peda@axentia.se> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/i2c/tda998x_drv.c | 73 +++++++++++++++---------------- 1 file changed, 35 insertions(+), 38 deletions(-) diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index f9a9fb6b97d0c..c35b52a830011 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -1630,6 +1630,25 @@ static int tda998x_get_audio_ports(struct tda998x_priv *priv, return 0; } +static void tda998x_set_config(struct tda998x_priv *priv, + const struct tda998x_encoder_params *p) +{ + priv->vip_cntrl_0 = VIP_CNTRL_0_SWAP_A(p->swap_a) | + (p->mirr_a ? VIP_CNTRL_0_MIRR_A : 0) | + VIP_CNTRL_0_SWAP_B(p->swap_b) | + (p->mirr_b ? VIP_CNTRL_0_MIRR_B : 0); + priv->vip_cntrl_1 = VIP_CNTRL_1_SWAP_C(p->swap_c) | + (p->mirr_c ? VIP_CNTRL_1_MIRR_C : 0) | + VIP_CNTRL_1_SWAP_D(p->swap_d) | + (p->mirr_d ? VIP_CNTRL_1_MIRR_D : 0); + priv->vip_cntrl_2 = VIP_CNTRL_2_SWAP_E(p->swap_e) | + (p->mirr_e ? VIP_CNTRL_2_MIRR_E : 0) | + VIP_CNTRL_2_SWAP_F(p->swap_f) | + (p->mirr_f ? VIP_CNTRL_2_MIRR_F : 0); + + priv->audio_params = p->audio_params; +} + static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv) { struct device_node *np = client->dev.of_node; @@ -1781,23 +1800,24 @@ static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv) /* enable EDID read irq: */ reg_set(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD); - if (!np) - return 0; /* non-DT */ + if (np) { + /* get the device tree parameters */ + ret = of_property_read_u32(np, "video-ports", &video); + if (ret == 0) { + priv->vip_cntrl_0 = video >> 16; + priv->vip_cntrl_1 = video >> 8; + priv->vip_cntrl_2 = video; + } - /* get the device tree parameters */ - ret = of_property_read_u32(np, "video-ports", &video); - if (ret == 0) { - priv->vip_cntrl_0 = video >> 16; - priv->vip_cntrl_1 = video >> 8; - priv->vip_cntrl_2 = video; - } + ret = tda998x_get_audio_ports(priv, np); + if (ret) + goto fail; - ret = tda998x_get_audio_ports(priv, np); - if (ret) - goto fail; - - if (priv->audio_port[0].format != AFMT_UNUSED) - tda998x_audio_codec_init(priv, &client->dev); + if (priv->audio_port[0].format != AFMT_UNUSED) + tda998x_audio_codec_init(priv, &client->dev); + } else if (client->dev.platform_data) { + tda998x_set_config(priv, client->dev.platform_data); + } return 0; @@ -1843,28 +1863,8 @@ static const struct drm_encoder_funcs tda998x_encoder_funcs = { .destroy = tda998x_encoder_destroy, }; -static void tda998x_set_config(struct tda998x_priv *priv, - const struct tda998x_encoder_params *p) -{ - priv->vip_cntrl_0 = VIP_CNTRL_0_SWAP_A(p->swap_a) | - (p->mirr_a ? VIP_CNTRL_0_MIRR_A : 0) | - VIP_CNTRL_0_SWAP_B(p->swap_b) | - (p->mirr_b ? VIP_CNTRL_0_MIRR_B : 0); - priv->vip_cntrl_1 = VIP_CNTRL_1_SWAP_C(p->swap_c) | - (p->mirr_c ? VIP_CNTRL_1_MIRR_C : 0) | - VIP_CNTRL_1_SWAP_D(p->swap_d) | - (p->mirr_d ? VIP_CNTRL_1_MIRR_D : 0); - priv->vip_cntrl_2 = VIP_CNTRL_2_SWAP_E(p->swap_e) | - (p->mirr_e ? VIP_CNTRL_2_MIRR_E : 0) | - VIP_CNTRL_2_SWAP_F(p->swap_f) | - (p->mirr_f ? VIP_CNTRL_2_MIRR_F : 0); - - priv->audio_params = p->audio_params; -} - static int tda998x_bind(struct device *dev, struct device *master, void *data) { - struct tda998x_encoder_params *params = dev->platform_data; struct i2c_client *client = to_i2c_client(dev); struct drm_device *drm = data; struct tda998x_priv *priv; @@ -1892,9 +1892,6 @@ static int tda998x_bind(struct device *dev, struct device *master, void *data) if (ret) return ret; - if (!dev->of_node && params) - tda998x_set_config(priv, params); - drm_encoder_helper_add(&priv->encoder, &tda998x_encoder_helper_funcs); ret = drm_encoder_init(drm, &priv->encoder, &tda998x_encoder_funcs, DRM_MODE_ENCODER_TMDS, NULL); -- GitLab From 5c41bb6071257ba668a2b8933a8654e69aea1cee Mon Sep 17 00:00:00 2001 From: Philipp Zabel <p.zabel@pengutronix.de> Date: Thu, 2 Aug 2018 10:40:33 +0200 Subject: [PATCH 1469/1506] gpu: ipu-v3: add support for XRGB32 and XBGR32 V4L2 pixel formats These should be used instead of the ill-defined deprecated RGB32 and BGR32 V4L2 pixel formats. Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de> --- drivers/gpu/ipu-v3/ipu-common.c | 4 ++++ drivers/gpu/ipu-v3/ipu-cpmem.c | 8 ++++++++ drivers/gpu/ipu-v3/ipu-image-convert.c | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c index 48685cddbad1b..66e9405faedc7 100644 --- a/drivers/gpu/ipu-v3/ipu-common.c +++ b/drivers/gpu/ipu-v3/ipu-common.c @@ -122,6 +122,8 @@ enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat) case V4L2_PIX_FMT_NV16: case V4L2_PIX_FMT_NV61: return IPUV3_COLORSPACE_YUV; + case V4L2_PIX_FMT_XRGB32: + case V4L2_PIX_FMT_XBGR32: case V4L2_PIX_FMT_RGB32: case V4L2_PIX_FMT_BGR32: case V4L2_PIX_FMT_RGB24: @@ -190,6 +192,8 @@ int ipu_stride_to_bytes(u32 pixel_stride, u32 pixelformat) return (24 * pixel_stride) >> 3; case V4L2_PIX_FMT_BGR32: case V4L2_PIX_FMT_RGB32: + case V4L2_PIX_FMT_XBGR32: + case V4L2_PIX_FMT_XRGB32: return (32 * pixel_stride) >> 3; default: break; diff --git a/drivers/gpu/ipu-v3/ipu-cpmem.c b/drivers/gpu/ipu-v3/ipu-cpmem.c index 125721a7f8b6d..0f1155ea0fbd2 100644 --- a/drivers/gpu/ipu-v3/ipu-cpmem.c +++ b/drivers/gpu/ipu-v3/ipu-cpmem.c @@ -188,6 +188,12 @@ static int v4l2_pix_fmt_to_drm_fourcc(u32 pixelformat) case V4L2_PIX_FMT_RGB32: /* R G B A <=> [32:0] A:B:G:R */ return DRM_FORMAT_XBGR8888; + case V4L2_PIX_FMT_XBGR32: + /* B G R X <=> [32:0] X:R:G:B */ + return DRM_FORMAT_XRGB8888; + case V4L2_PIX_FMT_XRGB32: + /* X R G B <=> [32:0] B:G:R:X */ + return DRM_FORMAT_BGRX8888; case V4L2_PIX_FMT_UYVY: return DRM_FORMAT_UYVY; case V4L2_PIX_FMT_YUYV: @@ -787,6 +793,8 @@ int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image) break; case V4L2_PIX_FMT_RGB32: case V4L2_PIX_FMT_BGR32: + case V4L2_PIX_FMT_XRGB32: + case V4L2_PIX_FMT_XBGR32: offset = image->rect.left * 4 + image->rect.top * pix->bytesperline; break; diff --git a/drivers/gpu/ipu-v3/ipu-image-convert.c b/drivers/gpu/ipu-v3/ipu-image-convert.c index 524a717ab28e4..f4081962784cc 100644 --- a/drivers/gpu/ipu-v3/ipu-image-convert.c +++ b/drivers/gpu/ipu-v3/ipu-image-convert.c @@ -226,6 +226,12 @@ static const struct ipu_image_pixfmt image_convert_formats[] = { }, { .fourcc = V4L2_PIX_FMT_BGR32, .bpp = 32, + }, { + .fourcc = V4L2_PIX_FMT_XRGB32, + .bpp = 32, + }, { + .fourcc = V4L2_PIX_FMT_XBGR32, + .bpp = 32, }, { .fourcc = V4L2_PIX_FMT_YUYV, .bpp = 16, -- GitLab From 9f0ba3d92fe63fa72f88238d9dde47a38a7d8f40 Mon Sep 17 00:00:00 2001 From: Steve Longerbeam <slongerbeam@gmail.com> Date: Wed, 1 Aug 2018 12:12:17 -0700 Subject: [PATCH 1470/1506] gpu: ipu-v3: Fix U/V offset macros for planar 4:2:0 The U and V offset macros for planar 4:2:0 (U_OFFSET, V_OFFSET, and UV_OFFSET), are not correct. The height component to the offset was calculated as: (pix->width * y / 4) But this does not produce correct offsets for odd values of y (luma line #). The luma line # must be decimated by two to produce the correct U/V line #, so the correct formula is: (pix->width * (y / 2) / 2) Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com> Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de> --- drivers/gpu/ipu-v3/ipu-cpmem.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/ipu-v3/ipu-cpmem.c b/drivers/gpu/ipu-v3/ipu-cpmem.c index 9f2d9ec42add6..e68e4734f052f 100644 --- a/drivers/gpu/ipu-v3/ipu-cpmem.c +++ b/drivers/gpu/ipu-v3/ipu-cpmem.c @@ -530,17 +530,17 @@ static const struct ipu_rgb def_bgra_16 = { #define Y_OFFSET(pix, x, y) ((x) + pix->width * (y)) #define U_OFFSET(pix, x, y) ((pix->width * pix->height) + \ - (pix->width * (y) / 4) + (x) / 2) + (pix->width * ((y) / 2) / 2) + (x) / 2) #define V_OFFSET(pix, x, y) ((pix->width * pix->height) + \ (pix->width * pix->height / 4) + \ - (pix->width * (y) / 4) + (x) / 2) + (pix->width * ((y) / 2) / 2) + (x) / 2) #define U2_OFFSET(pix, x, y) ((pix->width * pix->height) + \ (pix->width * (y) / 2) + (x) / 2) #define V2_OFFSET(pix, x, y) ((pix->width * pix->height) + \ (pix->width * pix->height / 2) + \ (pix->width * (y) / 2) + (x) / 2) #define UV_OFFSET(pix, x, y) ((pix->width * pix->height) + \ - (pix->width * (y) / 2) + (x)) + (pix->width * ((y) / 2)) + (x)) #define UV2_OFFSET(pix, x, y) ((pix->width * pix->height) + \ (pix->width * y) + (x)) -- GitLab From 2d87e6c1b99c402360fdfe19ce4f579ab2f96adf Mon Sep 17 00:00:00 2001 From: Philipp Zabel <p.zabel@pengutronix.de> Date: Thu, 21 Jun 2018 21:13:38 +0200 Subject: [PATCH 1471/1506] gpu: ipu-v3: default to id 0 on missing OF alias This is better than storing -ENODEV in the id number. This fixes SoCs with only one IPU that don't specify an IPU alias in the device tree. Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de> --- drivers/gpu/ipu-v3/ipu-common.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c index 48685cddbad1b..c73bd003f845d 100644 --- a/drivers/gpu/ipu-v3/ipu-common.c +++ b/drivers/gpu/ipu-v3/ipu-common.c @@ -1401,6 +1401,8 @@ static int ipu_probe(struct platform_device *pdev) return -ENODEV; ipu->id = of_alias_get_id(np, "ipu"); + if (ipu->id < 0) + ipu->id = 0; if (of_device_is_compatible(np, "fsl,imx6qp-ipu") && IS_ENABLED(CONFIG_DRM)) { -- GitLab From 01dc285d5cd89b77686d8baef8482c58d7dc3ead Mon Sep 17 00:00:00 2001 From: Harry Wentland <harry.wentland@amd.com> Date: Wed, 1 Aug 2018 10:48:23 -0400 Subject: [PATCH 1472/1506] drm/amd/display: Report non-DP display as disconnected without EDID [Why] Some boards seem to have a problem where HPD is high on HDMI even though no display is connected. We don't want to report these as connected. DP spec still requires us to report DP displays as connected when HPD is high but we can't read the EDID in order to go to fail-safe mode. [How] If connector_signal is not DP abort detection if we can't retrieve the EDID. v2: Add Bugzilla and stable Bugzilla: https://bugs.freedesktop.org/107390 Bugzilla: https://bugs.freedesktop.org/106846 Cc: stable@vger.kernel.org Signed-off-by: Harry Wentland <harry.wentland@amd.com> Acked-by: Alex Deucher <alexander.deucher@amd.com> Reviewed-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 11 +++++++++++ 1 file changed, 11 insertions(+) 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 966d2f9c8c995..31cebb645fca6 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -744,6 +744,17 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) break; case EDID_NO_RESPONSE: DC_LOG_ERROR("No EDID read.\n"); + + /* + * Abort detection for non-DP connectors if we have + * no EDID + * + * DP needs to report as connected if HDP is high + * even if we have no EDID in order to go to + * fail-safe mode + */ + if (!dc_is_dp_signal(link->connector_signal)) + return false; default: break; } -- GitLab From 16196776185cb19bb8c2318ebd1dbbefb5350d6a Mon Sep 17 00:00:00 2001 From: Harry Wentland <harry.wentland@amd.com> Date: Thu, 2 Aug 2018 15:32:01 -0400 Subject: [PATCH 1473/1506] drm/amd/display: Only require EDID read for HDMI and DVI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [Why] VGA sometimes has trouble retrieving the EDID on very long cables, KVM switches, or old displays. [How] Only require EDID read for HDMI and DVI and exempt other types (DP, VGA). We currently don't support VGA but if anyone adds support in the future this might get overlooked. Signed-off-by: Harry Wentland <harry.wentland@amd.com> Suggested-by: Michel Dänzer <michel@daenzer.net> Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 31cebb645fca6..89d7c1e99168c 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -753,7 +753,8 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) * even if we have no EDID in order to go to * fail-safe mode */ - if (!dc_is_dp_signal(link->connector_signal)) + if (dc_is_hdmi_signal(link->connector_signal) || + dc_is_dvi_signal(link->connector_signal)) return false; default: break; -- GitLab From 6ae9c84ff249f2756086e71405375fd06124cf1f Mon Sep 17 00:00:00 2001 From: Philipp Zabel <p.zabel@pengutronix.de> Date: Tue, 15 May 2018 16:09:15 +0200 Subject: [PATCH 1474/1506] drm/etnaviv: mmuv2: use memset32 to init scratch page Replace the open-coded scratch page initialization loop with memset32 Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de> Signed-off-by: Lucas Stach <l.stach@pengutronix.de> --- drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c b/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c index 71fbc1f96cb63..f1c88d8ad5ba8 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c @@ -119,8 +119,7 @@ static size_t etnaviv_iommuv2_unmap(struct etnaviv_iommu_domain *domain, static int etnaviv_iommuv2_init(struct etnaviv_iommuv2_domain *etnaviv_domain) { - u32 *p; - int ret, i; + int ret; /* allocate scratch page */ etnaviv_domain->base.bad_page_cpu = @@ -131,9 +130,9 @@ static int etnaviv_iommuv2_init(struct etnaviv_iommuv2_domain *etnaviv_domain) ret = -ENOMEM; goto fail_mem; } - p = etnaviv_domain->base.bad_page_cpu; - for (i = 0; i < SZ_4K / 4; i++) - *p++ = 0xdead55aa; + + memset32(etnaviv_domain->base.bad_page_cpu, 0xdead55aa, + SZ_4K / sizeof(u32)); etnaviv_domain->pta_cpu = dma_alloc_wc(etnaviv_domain->base.dev, SZ_4K, &etnaviv_domain->pta_dma, -- GitLab From a0780bb1df60f00e4573db7bd53e7039e9eee1cb Mon Sep 17 00:00:00 2001 From: Lucas Stach <l.stach@pengutronix.de> Date: Fri, 25 May 2018 16:51:25 +0200 Subject: [PATCH 1475/1506] drm/etnaviv: protect sched job submission with fence mutex The documentation of drm_sched_job_init and drm_sched_entity_push_job has been clarified. Both functions should be called under a shared lock, to avoid jobs getting pushed into the scheduler queue in a different order than their sched_fence seqnos, which will confuse checks that are looking at the seqnos to infer information about completion order. Signed-off-by: Lucas Stach <l.stach@pengutronix.de> --- drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c | 4 ++-- drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 2 +- drivers/gpu/drm/etnaviv/etnaviv_gpu.h | 2 +- drivers/gpu/drm/etnaviv/etnaviv_sched.c | 24 ++++++++++++++------ 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c index 46ecd3e66ac98..983e67f19e450 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c @@ -388,9 +388,9 @@ static void submit_cleanup(struct kref *kref) dma_fence_put(submit->in_fence); if (submit->out_fence) { /* first remove from IDR, so fence can not be found anymore */ - mutex_lock(&submit->gpu->fence_idr_lock); + mutex_lock(&submit->gpu->fence_lock); idr_remove(&submit->gpu->fence_idr, submit->out_fence_id); - mutex_unlock(&submit->gpu->fence_idr_lock); + mutex_unlock(&submit->gpu->fence_lock); dma_fence_put(submit->out_fence); } kfree(submit->pmrs); diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index 686f6552db48d..18c2224ba0b80 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -1733,7 +1733,7 @@ static int etnaviv_gpu_platform_probe(struct platform_device *pdev) gpu->dev = &pdev->dev; mutex_init(&gpu->lock); - mutex_init(&gpu->fence_idr_lock); + mutex_init(&gpu->fence_lock); /* Map registers: */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h index 90f17ff7888e7..9a75a6937268e 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h @@ -118,7 +118,7 @@ struct etnaviv_gpu { u32 idle_mask; /* Fencing support */ - struct mutex fence_idr_lock; + struct mutex fence_lock; struct idr fence_idr; u32 next_fence; u32 active_fence; diff --git a/drivers/gpu/drm/etnaviv/etnaviv_sched.c b/drivers/gpu/drm/etnaviv/etnaviv_sched.c index 50d6b88cb7aab..b267d9c4d91ce 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_sched.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_sched.c @@ -140,28 +140,38 @@ static const struct drm_sched_backend_ops etnaviv_sched_ops = { int etnaviv_sched_push_job(struct drm_sched_entity *sched_entity, struct etnaviv_gem_submit *submit) { - int ret; + int ret = 0; + + /* + * Hold the fence lock across the whole operation to avoid jobs being + * pushed out of order with regard to their sched fence seqnos as + * allocated in drm_sched_job_init. + */ + mutex_lock(&submit->gpu->fence_lock); ret = drm_sched_job_init(&submit->sched_job, &submit->gpu->sched, sched_entity, submit->cmdbuf.ctx); if (ret) - return ret; + goto out_unlock; submit->out_fence = dma_fence_get(&submit->sched_job.s_fence->finished); - mutex_lock(&submit->gpu->fence_idr_lock); submit->out_fence_id = idr_alloc_cyclic(&submit->gpu->fence_idr, submit->out_fence, 0, INT_MAX, GFP_KERNEL); - mutex_unlock(&submit->gpu->fence_idr_lock); - if (submit->out_fence_id < 0) - return -ENOMEM; + if (submit->out_fence_id < 0) { + ret = -ENOMEM; + goto out_unlock; + } /* the scheduler holds on to the job now */ kref_get(&submit->refcount); drm_sched_entity_push_job(&submit->sched_job, sched_entity); - return 0; +out_unlock: + mutex_unlock(&submit->gpu->fence_lock); + + return ret; } int etnaviv_sched_init(struct etnaviv_gpu *gpu) -- GitLab From cfad05a24dcb2bf09ba6438e0843c6a0ed90381c Mon Sep 17 00:00:00 2001 From: Souptick Joarder <jrdr.linux@gmail.com> Date: Tue, 29 May 2018 19:17:27 +0530 Subject: [PATCH 1476/1506] drm/etnaviv: change return type to vm_fault_t Use new return type vm_fault_t for fault handler. For now, this is just documenting that the function returns a VM_FAULT value rather than an errno. Once all instances are converted, vm_fault_t will become a distinct type. Ref- commit 1c8f422059ae ("mm: change return type to vm_fault_t") Previously vm_insert_page() returns err which driver mapped into VM_FAULT_* type. The new function vmf_insert_page() will replace this inefficiency by returning VM_FAULT_* type. vmf_error() is the newly introduce inline function in 4.17-rc6. Signed-off-by: Souptick Joarder <jrdr.linux@gmail.com> Reviewed-by: Matthew Wilcox <mawilcox@microsoft.com> Signed-off-by: Lucas Stach <l.stach@pengutronix.de> --- drivers/gpu/drm/etnaviv/etnaviv_drv.h | 3 ++- drivers/gpu/drm/etnaviv/etnaviv_gem.c | 37 +++++++-------------------- 2 files changed, 11 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.h b/drivers/gpu/drm/etnaviv/etnaviv_drv.h index d36c7bbe66db4..8d02d1b7dcf5a 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.h @@ -18,6 +18,7 @@ #include <linux/time64.h> #include <linux/types.h> #include <linux/sizes.h> +#include <linux/mm_types.h> #include <drm/drmP.h> #include <drm/drm_crtc_helper.h> @@ -53,7 +54,7 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, struct drm_file *file); int etnaviv_gem_mmap(struct file *filp, struct vm_area_struct *vma); -int etnaviv_gem_fault(struct vm_fault *vmf); +vm_fault_t etnaviv_gem_fault(struct vm_fault *vmf); int etnaviv_gem_mmap_offset(struct drm_gem_object *obj, u64 *offset); struct sg_table *etnaviv_gem_prime_get_sg_table(struct drm_gem_object *obj); void *etnaviv_gem_prime_vmap(struct drm_gem_object *obj); diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c b/drivers/gpu/drm/etnaviv/etnaviv_gem.c index 209ef1274b806..1fa74226db91f 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c @@ -169,31 +169,30 @@ int etnaviv_gem_mmap(struct file *filp, struct vm_area_struct *vma) return obj->ops->mmap(obj, vma); } -int etnaviv_gem_fault(struct vm_fault *vmf) +vm_fault_t etnaviv_gem_fault(struct vm_fault *vmf) { struct vm_area_struct *vma = vmf->vma; struct drm_gem_object *obj = vma->vm_private_data; struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj); struct page **pages, *page; pgoff_t pgoff; - int ret; + int err; /* * Make sure we don't parallel update on a fault, nor move or remove - * something from beneath our feet. Note that vm_insert_page() is + * something from beneath our feet. Note that vmf_insert_page() is * specifically coded to take care of this, so we don't have to. */ - ret = mutex_lock_interruptible(&etnaviv_obj->lock); - if (ret) - goto out; - + err = mutex_lock_interruptible(&etnaviv_obj->lock); + if (err) + return VM_FAULT_NOPAGE; /* make sure we have pages attached now */ pages = etnaviv_gem_get_pages(etnaviv_obj); mutex_unlock(&etnaviv_obj->lock); if (IS_ERR(pages)) { - ret = PTR_ERR(pages); - goto out; + err = PTR_ERR(pages); + return vmf_error(err); } /* We don't use vmf->pgoff since that has the fake offset: */ @@ -204,25 +203,7 @@ int etnaviv_gem_fault(struct vm_fault *vmf) VERB("Inserting %p pfn %lx, pa %lx", (void *)vmf->address, page_to_pfn(page), page_to_pfn(page) << PAGE_SHIFT); - ret = vm_insert_page(vma, vmf->address, page); - -out: - switch (ret) { - case -EAGAIN: - case 0: - case -ERESTARTSYS: - case -EINTR: - case -EBUSY: - /* - * EBUSY is ok: this just means that another thread - * already did the job. - */ - return VM_FAULT_NOPAGE; - case -ENOMEM: - return VM_FAULT_OOM; - default: - return VM_FAULT_SIGBUS; - } + return vmf_insert_page(vma, vmf->address, page); } int etnaviv_gem_mmap_offset(struct drm_gem_object *obj, u64 *offset) -- GitLab From 5b147465532365dc4e2fee8499d6ca1f52dd0d16 Mon Sep 17 00:00:00 2001 From: Lucas Stach <l.stach@pengutronix.de> Date: Mon, 23 Jul 2018 14:27:23 +0200 Subject: [PATCH 1477/1506] drm/etnaviv: fix crash in GPU suspend when init failed due to buffer placement When the suballocator was unable to provide a suitable buffer for the MMUv1 linear window, we roll back the GPU initialization. As the GPU is runtime resumed at that point we need to clear the kernel cmdbuf suballoc entry to properly skip any attempt to manipulate the cmdbuf when the GPU gets shut down in the runtime suspend later on. Signed-off-by: Lucas Stach <l.stach@pengutronix.de> --- drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index 18c2224ba0b80..ab8dfe7f69d6c 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -799,6 +799,7 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu) free_buffer: etnaviv_cmdbuf_free(&gpu->buffer); + gpu->buffer.suballoc = NULL; destroy_iommu: etnaviv_iommu_destroy(gpu->mmu); gpu->mmu = NULL; -- GitLab From 656921a51244b72cd1105df61b0af15825bddb72 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi <rodrigo.vivi@intel.com> Date: Thu, 19 Jul 2018 17:31:55 -0700 Subject: [PATCH 1478/1506] drm/i915: Fix psr sink status report. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit First of all don't try to read dpcd if PSR is not even supported. But also, if read failed return -EIO instead of reporting via a backchannel. v2: fix dev_priv: At this level m->private is the connector. (CI/DK) don't convert dpcd read errors to EIO. (DK) Fixes: 5b7b30864d1d ("drm/i915/psr: Split sink status into a separate debugfs node") Cc: Chris Wilson <chris@chris-wilson.co.uk> Cc: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Cc: José Roberto de Souza <jose.souza@intel.com> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Reviewed-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180720003155.16290-1-rodrigo.vivi@intel.com (cherry picked from commit 7a72c78bdd0a1ea1d879610542679cc680398220) Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com> --- drivers/gpu/drm/i915/i915_debugfs.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index b3aefd6235570..59dc0610ea44f 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2606,13 +2606,22 @@ static int i915_psr_sink_status_show(struct seq_file *m, void *data) "sink internal error", }; struct drm_connector *connector = m->private; + struct drm_i915_private *dev_priv = to_i915(connector->dev); struct intel_dp *intel_dp = enc_to_intel_dp(&intel_attached_encoder(connector)->base); + int ret; + + if (!CAN_PSR(dev_priv)) { + seq_puts(m, "PSR Unsupported\n"); + return -ENODEV; + } if (connector->status != connector_status_connected) return -ENODEV; - if (drm_dp_dpcd_readb(&intel_dp->aux, DP_PSR_STATUS, &val) == 1) { + ret = drm_dp_dpcd_readb(&intel_dp->aux, DP_PSR_STATUS, &val); + + if (ret == 1) { const char *str = "unknown"; val &= DP_PSR_SINK_STATE_MASK; @@ -2620,7 +2629,7 @@ static int i915_psr_sink_status_show(struct seq_file *m, void *data) str = sink_status[val]; seq_printf(m, "Sink PSR status: 0x%x [%s]\n", val, str); } else { - DRM_ERROR("dpcd read (at %u) failed\n", DP_PSR_STATUS); + return ret; } return 0; -- GitLab From 027063b1606fea6df15c270e5f2a072d1dfa8fef Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Tue, 31 Jul 2018 14:26:29 +0100 Subject: [PATCH 1479/1506] drm/i915: Interactive RPS mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RPS provides a feedback loop where we use the load during the previous evaluation interval to decide whether to up or down clock the GPU frequency. Our responsiveness is split into 3 regimes, a high and low plateau with the intent to keep the gpu clocked high to cover occasional stalls under high load, and low despite occasional glitches under steady low load, and inbetween. However, we run into situations like kodi where we want to stay at low power (video decoding is done efficiently inside the fixed function HW and doesn't need high clocks even for high bitrate streams), but just occasionally the pipeline is more complex than a video decode and we need a smidgen of extra GPU power to present on time. In the high power regime, we sample at sub frame intervals with a bias to upclocking, and conversely at low power we sample over a few frames worth to provide what we consider to be the right levels of responsiveness respectively. At low power, we more or less expect to be kicked out to high power at the start of a busy sequence by waitboosting. Prior to commit e9af4ea2b9e7 ("drm/i915: Avoid waitboosting on the active request") whenever we missed the frame or stalled, we would immediate go full throttle and upclock the GPU to max. But in commit e9af4ea2b9e7, we relaxed the waitboosting to only apply if the pipeline was deep to avoid over-committing resources for a near miss. Sadly though, a near miss is still a miss, and perceptible as jitter in the frame delivery. To try and prevent the near miss before having to resort to boosting after the fact, we use the pageflip queue as an indication that we are in an "interactive" regime and so should sample the load more frequently to provide power before the frame misses it vblank. This will make us more favorable to providing a small power increase (one or two bins) as required rather than going all the way to maximum and then having to work back down again. (We still keep the waitboosting mechanism around just in case a dramatic change in system load requires urgent uplocking, faster than we can provide in a few evaluation intervals.) v2: Reduce rps_set_interactive to a boolean parameter to avoid the confusion of what if they wanted a new power mode after pinning to a different mode (which to choose?) v3: Only reprogram RPS while the GT is awake, it will be set when we wake the GT, and while off warns about being used outside of rpm. v4: Fix deferred application of interactive mode v5: s/state/interactive/ v6: Group the mutex with its principle in a substruct Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=107111 Fixes: e9af4ea2b9e7 ("drm/i915: Avoid waitboosting on the active request") Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Cc: Radoslaw Szwichtenberg <radoslaw.szwichtenberg@intel.com> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180731132629.3381-1-chris@chris-wilson.co.uk (cherry picked from commit 60548c554be2830d29d2533dad0ac8133347ee51) Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com> --- drivers/gpu/drm/i915/i915_debugfs.c | 13 ++-- drivers/gpu/drm/i915/i915_drv.h | 16 +++-- drivers/gpu/drm/i915/i915_irq.c | 4 +- drivers/gpu/drm/i915/intel_display.c | 20 ++++++ drivers/gpu/drm/i915/intel_drv.h | 2 + drivers/gpu/drm/i915/intel_pm.c | 101 ++++++++++++++++++--------- 6 files changed, 111 insertions(+), 45 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 59dc0610ea44f..f9ce35da4123e 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1218,7 +1218,8 @@ static int i915_frequency_info(struct seq_file *m, void *unused) rpcurup, GT_PM_INTERVAL_TO_US(dev_priv, rpcurup)); seq_printf(m, "RP PREV UP: %d (%dus)\n", rpprevup, GT_PM_INTERVAL_TO_US(dev_priv, rpprevup)); - seq_printf(m, "Up threshold: %d%%\n", rps->up_threshold); + seq_printf(m, "Up threshold: %d%%\n", + rps->power.up_threshold); seq_printf(m, "RP CUR DOWN EI: %d (%dus)\n", rpdownei, GT_PM_INTERVAL_TO_US(dev_priv, rpdownei)); @@ -1226,7 +1227,8 @@ static int i915_frequency_info(struct seq_file *m, void *unused) rpcurdown, GT_PM_INTERVAL_TO_US(dev_priv, rpcurdown)); seq_printf(m, "RP PREV DOWN: %d (%dus)\n", rpprevdown, GT_PM_INTERVAL_TO_US(dev_priv, rpprevdown)); - seq_printf(m, "Down threshold: %d%%\n", rps->down_threshold); + seq_printf(m, "Down threshold: %d%%\n", + rps->power.down_threshold); max_freq = (IS_GEN9_LP(dev_priv) ? rp_state_cap >> 0 : rp_state_cap >> 16) & 0xff; @@ -2218,6 +2220,7 @@ static int i915_rps_boost_info(struct seq_file *m, void *data) seq_printf(m, "CPU waiting? %d\n", count_irq_waiters(dev_priv)); seq_printf(m, "Boosts outstanding? %d\n", atomic_read(&rps->num_waiters)); + seq_printf(m, "Interactive? %d\n", READ_ONCE(rps->power.interactive)); seq_printf(m, "Frequency requested %d\n", intel_gpu_freq(dev_priv, rps->cur_freq)); seq_printf(m, " min hard:%d, soft:%d; max soft:%d, hard:%d\n", @@ -2261,13 +2264,13 @@ static int i915_rps_boost_info(struct seq_file *m, void *data) intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL); seq_printf(m, "\nRPS Autotuning (current \"%s\" window):\n", - rps_power_to_str(rps->power)); + rps_power_to_str(rps->power.mode)); seq_printf(m, " Avg. up: %d%% [above threshold? %d%%]\n", rpup && rpupei ? 100 * rpup / rpupei : 0, - rps->up_threshold); + rps->power.up_threshold); seq_printf(m, " Avg. down: %d%% [below threshold? %d%%]\n", rpdown && rpdownei ? 100 * rpdown / rpdownei : 0, - rps->down_threshold); + rps->power.down_threshold); } else { seq_puts(m, "\nRPS Autotuning inactive\n"); } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 0f49f9988dfae..4aca5344863d6 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -779,11 +779,17 @@ struct intel_rps { u8 rp0_freq; /* Non-overclocked max frequency. */ u16 gpll_ref_freq; /* vlv/chv GPLL reference frequency */ - u8 up_threshold; /* Current %busy required to uplock */ - u8 down_threshold; /* Current %busy required to downclock */ - int last_adj; - enum { LOW_POWER, BETWEEN, HIGH_POWER } power; + + struct { + struct mutex mutex; + + enum { LOW_POWER, BETWEEN, HIGH_POWER } mode; + unsigned int interactive; + + u8 up_threshold; /* Current %busy required to uplock */ + u8 down_threshold; /* Current %busy required to downclock */ + } power; bool enabled; atomic_t num_waiters; @@ -3422,6 +3428,8 @@ extern void i915_redisable_vga_power_on(struct drm_i915_private *dev_priv); extern bool ironlake_set_drps(struct drm_i915_private *dev_priv, u8 val); extern void intel_init_pch_refclk(struct drm_i915_private *dev_priv); extern int intel_set_rps(struct drm_i915_private *dev_priv, u8 val); +extern void intel_rps_mark_interactive(struct drm_i915_private *i915, + bool interactive); extern bool intel_set_memory_cxsr(struct drm_i915_private *dev_priv, bool enable); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 5dadefca2ad22..90628a47ae17f 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1265,9 +1265,9 @@ static u32 vlv_wa_c0_ei(struct drm_i915_private *dev_priv, u32 pm_iir) c0 = max(render, media); c0 *= 1000 * 100 << 8; /* to usecs and scale to threshold% */ - if (c0 > time * rps->up_threshold) + if (c0 > time * rps->power.up_threshold) events = GEN6_PM_RP_UP_THRESHOLD; - else if (c0 < time * rps->down_threshold) + else if (c0 < time * rps->power.down_threshold) events = GEN6_PM_RP_DOWN_THRESHOLD; } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 87e4cfbfd096c..ed3fa1c8a9834 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13104,6 +13104,19 @@ intel_prepare_plane_fb(struct drm_plane *plane, add_rps_boost_after_vblank(new_state->crtc, new_state->fence); } + /* + * We declare pageflips to be interactive and so merit a small bias + * towards upclocking to deliver the frame on time. By only changing + * the RPS thresholds to sample more regularly and aim for higher + * clocks we can hopefully deliver low power workloads (like kodi) + * that are not quite steady state without resorting to forcing + * maximum clocks following a vblank miss (see do_rps_boost()). + */ + if (!intel_state->rps_interactive) { + intel_rps_mark_interactive(dev_priv, true); + intel_state->rps_interactive = true; + } + return 0; } @@ -13120,8 +13133,15 @@ void intel_cleanup_plane_fb(struct drm_plane *plane, struct drm_plane_state *old_state) { + struct intel_atomic_state *intel_state = + to_intel_atomic_state(old_state->state); struct drm_i915_private *dev_priv = to_i915(plane->dev); + if (intel_state->rps_interactive) { + intel_rps_mark_interactive(dev_priv, false); + intel_state->rps_interactive = false; + } + /* Should only be called after a successful intel_prepare_plane_fb()! */ mutex_lock(&dev_priv->drm.struct_mutex); intel_plane_unpin_fb(to_intel_plane_state(old_state)); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index c275f91244a6c..17af06d8a43ea 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -484,6 +484,8 @@ struct intel_atomic_state { */ bool skip_intermediate_wm; + bool rps_interactive; + /* Gen9+ only */ struct skl_ddb_values wm_results; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 7312ecb734151..43ae9de12ba3e 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -6264,42 +6264,15 @@ static u32 intel_rps_limits(struct drm_i915_private *dev_priv, u8 val) return limits; } -static void gen6_set_rps_thresholds(struct drm_i915_private *dev_priv, u8 val) +static void rps_set_power(struct drm_i915_private *dev_priv, int new_power) { struct intel_rps *rps = &dev_priv->gt_pm.rps; - int new_power; u32 threshold_up = 0, threshold_down = 0; /* in % */ u32 ei_up = 0, ei_down = 0; - new_power = rps->power; - switch (rps->power) { - case LOW_POWER: - if (val > rps->efficient_freq + 1 && - val > rps->cur_freq) - new_power = BETWEEN; - break; - - case BETWEEN: - if (val <= rps->efficient_freq && - val < rps->cur_freq) - new_power = LOW_POWER; - else if (val >= rps->rp0_freq && - val > rps->cur_freq) - new_power = HIGH_POWER; - break; + lockdep_assert_held(&rps->power.mutex); - case HIGH_POWER: - if (val < (rps->rp1_freq + rps->rp0_freq) >> 1 && - val < rps->cur_freq) - new_power = BETWEEN; - break; - } - /* Max/min bins are special */ - if (val <= rps->min_freq_softlimit) - new_power = LOW_POWER; - if (val >= rps->max_freq_softlimit) - new_power = HIGH_POWER; - if (new_power == rps->power) + if (new_power == rps->power.mode) return; /* Note the units here are not exactly 1us, but 1280ns. */ @@ -6362,12 +6335,71 @@ static void gen6_set_rps_thresholds(struct drm_i915_private *dev_priv, u8 val) GEN6_RP_DOWN_IDLE_AVG); skip_hw_write: - rps->power = new_power; - rps->up_threshold = threshold_up; - rps->down_threshold = threshold_down; + rps->power.mode = new_power; + rps->power.up_threshold = threshold_up; + rps->power.down_threshold = threshold_down; +} + +static void gen6_set_rps_thresholds(struct drm_i915_private *dev_priv, u8 val) +{ + struct intel_rps *rps = &dev_priv->gt_pm.rps; + int new_power; + + new_power = rps->power.mode; + switch (rps->power.mode) { + case LOW_POWER: + if (val > rps->efficient_freq + 1 && + val > rps->cur_freq) + new_power = BETWEEN; + break; + + case BETWEEN: + if (val <= rps->efficient_freq && + val < rps->cur_freq) + new_power = LOW_POWER; + else if (val >= rps->rp0_freq && + val > rps->cur_freq) + new_power = HIGH_POWER; + break; + + case HIGH_POWER: + if (val < (rps->rp1_freq + rps->rp0_freq) >> 1 && + val < rps->cur_freq) + new_power = BETWEEN; + break; + } + /* Max/min bins are special */ + if (val <= rps->min_freq_softlimit) + new_power = LOW_POWER; + if (val >= rps->max_freq_softlimit) + new_power = HIGH_POWER; + + mutex_lock(&rps->power.mutex); + if (rps->power.interactive) + new_power = HIGH_POWER; + rps_set_power(dev_priv, new_power); + mutex_unlock(&rps->power.mutex); rps->last_adj = 0; } +void intel_rps_mark_interactive(struct drm_i915_private *i915, bool interactive) +{ + struct intel_rps *rps = &i915->gt_pm.rps; + + if (INTEL_GEN(i915) < 6) + return; + + mutex_lock(&rps->power.mutex); + if (interactive) { + if (!rps->power.interactive++ && READ_ONCE(i915->gt.awake)) + rps_set_power(i915, HIGH_POWER); + } else { + GEM_BUG_ON(!rps->power.interactive); + rps->power.interactive--; + } + mutex_unlock(&rps->power.mutex); +} + static u32 gen6_rps_pm_mask(struct drm_i915_private *dev_priv, u8 val) { struct intel_rps *rps = &dev_priv->gt_pm.rps; @@ -6780,7 +6812,7 @@ static void reset_rps(struct drm_i915_private *dev_priv, u8 freq = rps->cur_freq; /* force a reset */ - rps->power = -1; + rps->power.mode = -1; rps->cur_freq = -1; if (set(dev_priv, freq)) @@ -9604,6 +9636,7 @@ int intel_freq_opcode(struct drm_i915_private *dev_priv, int val) void intel_pm_setup(struct drm_i915_private *dev_priv) { mutex_init(&dev_priv->pcu_lock); + mutex_init(&dev_priv->gt_pm.rps.power.mutex); atomic_set(&dev_priv->gt_pm.rps.num_waiters, 0); -- GitLab From 497bfb706844892d07495f2ed5dff977fede5e25 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala <mika.kuoppala@linux.intel.com> Date: Mon, 30 Jul 2018 15:06:36 +0300 Subject: [PATCH 1480/1506] Revert "drm/i915/icl: WaEnableFloatBlendOptimization" The register for 0xe420 is unable to hold any value, including this bit. The documentation is also mixed between having a register bit for toggle and having a state command setup for it. Apparently the register toggle is deprecated. Remove the register toggle as evidence shows it's futile. The thing remaining is an apology and humble request for Mesa folks to resurrect their state setup for this as they were on right track from start. This reverts commit 0bf059f3532bb39c52d917142206a8554fc2f1c5. Fixes: 0bf059f3532b ("drm/i915/icl: WaEnableFloatBlendOptimization") References: HSDES#1406393558 Cc: Oscar Mateo <oscar.mateo@intel.com> Cc: Anuj Phogat <anuj.phogat@gmail.com> Cc: Chris Wilson <chris@chris-wilson.co.uk> Cc: Lionel Landwerlin <lionel.g.landwerlin@intel.com> Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Acked-by: Chris Wilson <chris@chris-wilson.co.uk> Link: https://patchwork.freedesktop.org/patch/msgid/20180730120636.26958-1-mika.kuoppala@linux.intel.com (cherry picked from commit c358514ba8da9e235876db1628cedd19a35803c6) Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com> --- drivers/gpu/drm/i915/i915_reg.h | 3 --- drivers/gpu/drm/i915/intel_workarounds.c | 3 --- 2 files changed, 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 8af945d8a9959..91e7483228e11 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2780,9 +2780,6 @@ enum i915_power_well_id { #define GEN8_4x4_STC_OPTIMIZATION_DISABLE (1 << 6) #define GEN9_PARTIAL_RESOLVE_IN_VC_DISABLE (1 << 1) -#define GEN10_CACHE_MODE_SS _MMIO(0xe420) -#define FLOAT_BLEND_OPTIMIZATION_ENABLE (1 << 4) - #define GEN6_BLITTER_ECOSKPD _MMIO(0x221d0) #define GEN6_BLITTER_LOCK_SHIFT 16 #define GEN6_BLITTER_FBC_NOTIFY (1 << 3) diff --git a/drivers/gpu/drm/i915/intel_workarounds.c b/drivers/gpu/drm/i915/intel_workarounds.c index f8bb32e974f65..4bcdeaf8d98fa 100644 --- a/drivers/gpu/drm/i915/intel_workarounds.c +++ b/drivers/gpu/drm/i915/intel_workarounds.c @@ -508,9 +508,6 @@ static int icl_ctx_workarounds_init(struct drm_i915_private *dev_priv) WA_SET_BIT_MASKED(GEN11_COMMON_SLICE_CHICKEN3, GEN11_BLEND_EMB_FIX_DISABLE_IN_RCC); - /* WaEnableFloatBlendOptimization:icl */ - WA_SET_BIT_MASKED(GEN10_CACHE_MODE_SS, FLOAT_BLEND_OPTIMIZATION_ENABLE); - return 0; } -- GitLab From 75eef0f1ed478284911b8723a5bdb659499a7aac Mon Sep 17 00:00:00 2001 From: Chris Wilson <chris@chris-wilson.co.uk> Date: Thu, 2 Aug 2018 15:04:16 +0100 Subject: [PATCH 1481/1506] drm/i915/lpe: Mark LPE audio runtime pm as "no callbacks" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The LPE audio is a child device of i915, it is powered up and down alongside the igfx and presents no independent runtime interface. This aptly fulfils the description of a "No-Callback" Device, so mark it thus. Fixes: 183c00350ccd ("drm/i915: Fix runtime PM for LPE audio") Testcase: igt/pm_rpm/basic-pci-d3-state Testcase: igt/pm_rpm/basic-rte Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Takashi Iwai <tiwai@suse.de> Cc: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Cc: stable@vger.kernel.org Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180802140416.6062-1-chris@chris-wilson.co.uk (cherry picked from commit 46e831abe864a6b59fa3de253a681c0f2ee1bf2f) Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com> --- drivers/gpu/drm/i915/intel_lpe_audio.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lpe_audio.c b/drivers/gpu/drm/i915/intel_lpe_audio.c index 6269750e2b547..430732720e656 100644 --- a/drivers/gpu/drm/i915/intel_lpe_audio.c +++ b/drivers/gpu/drm/i915/intel_lpe_audio.c @@ -126,9 +126,7 @@ lpe_audio_platdev_create(struct drm_i915_private *dev_priv) return platdev; } - pm_runtime_forbid(&platdev->dev); - pm_runtime_set_active(&platdev->dev); - pm_runtime_enable(&platdev->dev); + pm_runtime_no_callbacks(&platdev->dev); return platdev; } -- GitLab From 3237c0dbe21f8d2ca2feaa3891aff3619873cd30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Winiarski?= <michal.winiarski@intel.com> Date: Thu, 12 Jul 2018 17:53:30 +0200 Subject: [PATCH 1482/1506] drm/i915/kvmgt: Fix compilation error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gvt_pin_guest_page extracted some of the gvt_dma_map_page functionality: commit 79e542f5af79 ("drm/i915/kvmgt: Support setting dma map for huge pages") And yet, part of it was reintroduced in: commit 39b4cbadb9a9 ("drm/i915/kvmgt: Check the pfn got from vfio_pin_pages") Causing kvmgt part to no longer build. Let's remove it. Reported-by: Tomasz Lis <tomasz.lis@intel.com> Signed-off-by: MichaÅ‚ Winiarski <michal.winiarski@intel.com> Cc: Changbin Du <changbin.du@intel.com> Cc: Zhenyu Wang <zhenyuw@linux.intel.com> Acked-by: Zhenyu Wang <zhenyuw@linux.intel.com> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180712155330.32055-1-michal.winiarski@intel.com (cherry picked from commit 4eaf317a60fbea0555b936035002ca9bd9b9105d) Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com> --- drivers/gpu/drm/i915/gvt/kvmgt.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c index 718ab307a5004..4d2f53ae9f0f2 100644 --- a/drivers/gpu/drm/i915/gvt/kvmgt.c +++ b/drivers/gpu/drm/i915/gvt/kvmgt.c @@ -185,12 +185,6 @@ static int gvt_dma_map_page(struct intel_vgpu *vgpu, unsigned long gfn, if (ret) return ret; - if (!pfn_valid(pfn)) { - gvt_vgpu_err("pfn 0x%lx is not mem backed\n", pfn); - vfio_unpin_pages(mdev_dev(vgpu->vdev.mdev), &gfn, 1); - return -EINVAL; - } - /* Setup DMA mapping. */ *dma_addr = dma_map_page(dev, page, 0, size, PCI_DMA_BIDIRECTIONAL); ret = dma_mapping_error(dev, *dma_addr); -- GitLab From e11d41472a50742c16d53c968e143fb498fa482f Mon Sep 17 00:00:00 2001 From: "Leo (Sunpeng) Li" <sunpeng.li@amd.com> Date: Thu, 19 Jul 2018 08:22:16 -0400 Subject: [PATCH 1483/1506] drm/amd/display: Use requested HDMI aspect ratio [Why] The DRM mode's HDMI picture aspect ratio field was never saved in dc_stream's timing struct. This causes us to mistake a new stream to have the same timings as the old, even though the user has requested a different aspect ratio. [How] Save DRM's aspect ratio field within dc_stream's timing struct. Bug: https://bugs.freedesktop.org/show_bug.cgi?id=107153 Signed-off-by: Leo (Sunpeng) Li <sunpeng.li@amd.com> Reviewed-by: Mikita Lipski <Mikita.Lipski@amd.com> Acked-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) 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 45e062022461b..c1631d61336e1 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -2109,13 +2109,8 @@ convert_color_depth_from_display_info(const struct drm_connector *connector) static enum dc_aspect_ratio get_aspect_ratio(const struct drm_display_mode *mode_in) { - int32_t width = mode_in->crtc_hdisplay * 9; - int32_t height = mode_in->crtc_vdisplay * 16; - - if ((width - height) < 10 && (width - height) > -10) - return ASPECT_RATIO_16_9; - else - return ASPECT_RATIO_4_3; + /* 1-1 mapping, since both enums follow the HDMI spec. */ + return (enum dc_aspect_ratio) mode_in->picture_aspect_ratio; } static enum dc_color_space -- GitLab From 0301ccbaf67d3d9aea97156c5eb85233bb5a5178 Mon Sep 17 00:00:00 2001 From: abdoulaye berthe <abdoulaye.berthe@amd.com> Date: Thu, 19 Jul 2018 15:39:55 -0400 Subject: [PATCH 1484/1506] drm/amd/display: DP Compliance 400.1.1 failure [Why] 400.1.1 is failing because we are not performing link training when we get an HPD pulse for the same display. This is breaking DP compliance [How] Always perform link training after HPD pulse if the detection reason is not DETECT_REASON_HPDRX. Signed-off-by: abdoulaye berthe <abdoulaye.berthe@amd.com> Reviewed-by: Wenjing Liu <Wenjing.Liu@amd.com> Acked-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 54 ++++++++++--------- 1 file changed, 28 insertions(+), 26 deletions(-) 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 89d7c1e99168c..ce65b4d5062ec 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -764,39 +764,41 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) if ((prev_sink != NULL) && ((edid_status == EDID_THE_SAME) || (edid_status == EDID_OK))) same_edid = is_same_edid(&prev_sink->dc_edid, &sink->dc_edid); - // If both edid and dpcd are the same, then discard new sink and revert back to original sink - if ((same_edid) && (same_dpcd)) { - link_disconnect_remap(prev_sink, link); - sink = prev_sink; - prev_sink = NULL; - } else { - if (link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT && - sink_caps.transaction_type == - DDC_TRANSACTION_TYPE_I2C_OVER_AUX) { - /* - * TODO debug why Dell 2413 doesn't like - * two link trainings - */ + if (link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT && + sink_caps.transaction_type == DDC_TRANSACTION_TYPE_I2C_OVER_AUX && + reason != DETECT_REASON_HPDRX) { + /* + * TODO debug why Dell 2413 doesn't like + * two link trainings + */ - /* deal with non-mst cases */ - for (i = 0; i < LINK_TRAINING_MAX_VERIFY_RETRY; i++) { - int fail_count = 0; + /* deal with non-mst cases */ + for (i = 0; i < LINK_TRAINING_MAX_VERIFY_RETRY; i++) { + int fail_count = 0; - dp_verify_link_cap(link, - &link->reported_link_cap, - &fail_count); + dp_verify_link_cap(link, + &link->reported_link_cap, + &fail_count); - if (fail_count == 0) - break; - } + if (fail_count == 0) + break; } - /* HDMI-DVI Dongle */ - if (sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A && - !sink->edid_caps.edid_hdmi) - sink->sink_signal = SIGNAL_TYPE_DVI_SINGLE_LINK; + } else { + // If edid is the same, then discard new sink and revert back to original sink + if (same_edid) { + link_disconnect_remap(prev_sink, link); + sink = prev_sink; + prev_sink = NULL; + + } } + /* HDMI-DVI Dongle */ + if (sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A && + !sink->edid_caps.edid_hdmi) + sink->sink_signal = SIGNAL_TYPE_DVI_SINGLE_LINK; + /* Connectivity log: detection */ for (i = 0; i < sink->dc_edid.length / EDID_BLOCK_SIZE; i++) { CONN_DATA_DETECT(link, -- GitLab From 620a0d27b211aa03d3f99accfdd58b88e6e0504c Mon Sep 17 00:00:00 2001 From: David Francis <David.Francis@amd.com> Date: Thu, 19 Jul 2018 11:25:05 -0400 Subject: [PATCH 1485/1506] drm/amd/display: Implement backlight_ops.get_brightness [Why] This hook that is supposed to read the actual backlight value is used in a few places throughout the kernel to setup or force update on backlight [How] Create a dc function that calls the existing abm function, and call that function from amdgpu Signed-off-by: David Francis <David.Francis@amd.com> Reviewed-by: Harry Wentland <Harry.Wentland@amd.com> Acked-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 7 ++++++- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 9 +++++++++ drivers/gpu/drm/amd/display/dc/dc_link.h | 2 ++ 3 files changed, 17 insertions(+), 1 deletion(-) 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 c1631d61336e1..dcae658fbc50f 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -1320,7 +1320,12 @@ static int amdgpu_dm_backlight_update_status(struct backlight_device *bd) static int amdgpu_dm_backlight_get_brightness(struct backlight_device *bd) { - return bd->props.brightness; + struct amdgpu_display_manager *dm = bl_get_data(bd); + int ret = dc_link_get_backlight_level(dm->backlight_link); + + if (ret == DC_ERROR_UNEXPECTED) + return bd->props.brightness; + return ret; } static const struct backlight_ops amdgpu_dm_backlight_ops = { 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 ce65b4d5062ec..9a6448e2089c5 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -2026,6 +2026,15 @@ enum dc_status dc_link_validate_mode_timing( return DC_OK; } +int dc_link_get_backlight_level(const struct dc_link *link) +{ + struct abm *abm = link->ctx->dc->res_pool->abm; + + if (abm == NULL || abm->funcs->get_current_backlight_8_bit == NULL) + return DC_ERROR_UNEXPECTED; + + return (int) abm->funcs->get_current_backlight_8_bit(abm); +} bool dc_link_set_backlight_level(const struct dc_link *link, uint32_t level, uint32_t frame_ramp, const struct dc_stream_state *stream) diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h index 070a56926308a..22f4ddd219d1d 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_link.h +++ b/drivers/gpu/drm/amd/display/dc/dc_link.h @@ -141,6 +141,8 @@ static inline struct dc_link *dc_get_link_at_index(struct dc *dc, uint32_t link_ bool dc_link_set_backlight_level(const struct dc_link *dc_link, uint32_t level, uint32_t frame_ramp, const struct dc_stream_state *stream); +int dc_link_get_backlight_level(const struct dc_link *dc_link); + bool dc_link_set_abm_disable(const struct dc_link *dc_link); bool dc_link_set_psr_enable(const struct dc_link *dc_link, bool enable, bool wait); -- GitLab From 53a53f8687faf492df2644d8c18ff0217fc18730 Mon Sep 17 00:00:00 2001 From: David Francis <David.Francis@amd.com> Date: Wed, 18 Jul 2018 16:03:30 -0400 Subject: [PATCH 1486/1506] drm/amd/display: Read back max backlight value at boot [Why] If there is no program explicitly setting the backlight brightness (for example, during a minimal install of linux), the hardware defaults to maximum brightness but the backlight_device defaults to 0 value. Thus, settings displays the wrong brightness value. [How] When creating the backlight device, set brightness to max Signed-off-by: David Francis <David.Francis@amd.com> Reviewed-by: Harry Wentland <Harry.Wentland@amd.com> Acked-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 1 + 1 file changed, 1 insertion(+) 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 dcae658fbc50f..34f34823bab5f 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -1340,6 +1340,7 @@ amdgpu_dm_register_backlight_device(struct amdgpu_display_manager *dm) struct backlight_properties props = { 0 }; props.max_brightness = AMDGPU_MAX_BL_LEVEL; + props.brightness = AMDGPU_MAX_BL_LEVEL; props.type = BACKLIGHT_RAW; snprintf(bl_name, sizeof(bl_name), "amdgpu_bl%d", -- GitLab From d90e9a3bf5e747f0e3b0c8bec96d8699493f63ab Mon Sep 17 00:00:00 2001 From: David Francis <David.Francis@amd.com> Date: Thu, 19 Jul 2018 15:48:24 -0400 Subject: [PATCH 1487/1506] drm/amd/display: Destroy aux_engines only once [Why] In the dce112 function to destroy the resource pool, engines (the aux engines) is destroyed twice. This has no ill effects but is a tad redundant. [How] Remove the redundant call Signed-off-by: David Francis <David.Francis@amd.com> Reviewed-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c index 84a05ff2d6748..288129343c778 100644 --- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c @@ -677,9 +677,6 @@ static void destruct(struct dce110_resource_pool *pool) pool->base.timing_generators[i] = NULL; } - if (pool->base.engines[i] != NULL) - dce110_engine_destroy(&pool->base.engines[i]); - } for (i = 0; i < pool->base.stream_enc_count; i++) { -- GitLab From 78e4405cec6cb0780b27b222685dde33934b38e4 Mon Sep 17 00:00:00 2001 From: David Francis <David.Francis@amd.com> Date: Thu, 12 Jul 2018 15:46:41 -0400 Subject: [PATCH 1488/1506] drm/amd/display: Implement custom degamma lut on dcn [Why] Custom degamma lut functions are a feature we would like to support on compatible hardware [How] In atomic check, convert from array of drm_color_lut to dc_transfer_func. On hardware commit, allow for possibility of custom degamma. Both are based on the equivalent regamma pipeline. Signed-off-by: David Francis <David.Francis@amd.com> Reviewed-by: Krunoslav Kovac <Krunoslav.Kovac@amd.com> Acked-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 42 ++++++++++++++----- drivers/gpu/drm/amd/display/dc/dc_hw_types.h | 2 + .../amd/display/dc/dcn10/dcn10_hw_sequencer.c | 7 +++- .../amd/display/modules/color/color_gamma.c | 10 +++-- 4 files changed, 46 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c index b329393307e59..326f6fb7e0bc4 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -231,18 +231,21 @@ void amdgpu_dm_set_ctm(struct dm_crtc_state *crtc) * preparation for hardware commit. If no lut is specified by user, we default * to SRGB degamma. * - * Currently, we only support degamma bypass, or preprogrammed SRGB degamma. - * Programmable degamma is not supported, and an attempt to do so will return - * -EINVAL. + * We support degamma bypass, predefined SRGB, and custom degamma * * RETURNS: - * 0 on success, -EINVAL if custom degamma curve is given. + * 0 on success + * -EINVAL if crtc_state has a degamma_lut of invalid size + * -ENOMEM if gamma allocation fails */ int amdgpu_dm_set_degamma_lut(struct drm_crtc_state *crtc_state, struct dc_plane_state *dc_plane_state) { struct drm_property_blob *blob = crtc_state->degamma_lut; struct drm_color_lut *lut; + uint32_t lut_size; + struct dc_gamma *gamma; + bool ret; if (!blob) { /* Default to SRGB */ @@ -258,11 +261,30 @@ int amdgpu_dm_set_degamma_lut(struct drm_crtc_state *crtc_state, return 0; } - /* Otherwise, assume SRGB, since programmable degamma is not - * supported. - */ - dc_plane_state->in_transfer_func->type = TF_TYPE_PREDEFINED; - dc_plane_state->in_transfer_func->tf = TRANSFER_FUNCTION_SRGB; - return -EINVAL; + gamma = dc_create_gamma(); + if (!gamma) + return -ENOMEM; + + lut_size = blob->length / sizeof(struct drm_color_lut); + gamma->num_entries = lut_size; + if (gamma->num_entries == MAX_COLOR_LUT_ENTRIES) + gamma->type = GAMMA_CUSTOM; + else { + dc_gamma_release(&gamma); + return -EINVAL; + } + + __drm_lut_to_dc_gamma(lut, gamma, false); + + dc_plane_state->in_transfer_func->type = TF_TYPE_DISTRIBUTED_POINTS; + ret = mod_color_calculate_degamma_params(dc_plane_state->in_transfer_func, gamma, true); + dc_gamma_release(&gamma); + if (!ret) { + dc_plane_state->in_transfer_func->type = TF_TYPE_BYPASS; + DRM_ERROR("Out of memory when calculating degamma params\n"); + return -ENOMEM; + } + + return 0; } diff --git a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h index 1d1f2d5ece519..b789cb2b354b6 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h @@ -417,6 +417,7 @@ enum { GAMMA_RGB_256_ENTRIES = 256, GAMMA_RGB_FLOAT_1024_ENTRIES = 1024, GAMMA_CS_TFM_1D_ENTRIES = 4096, + GAMMA_CUSTOM_ENTRIES = 4096, GAMMA_MAX_ENTRIES = 4096 }; @@ -424,6 +425,7 @@ enum dc_gamma_type { GAMMA_RGB_256 = 1, GAMMA_RGB_FLOAT_1024 = 2, GAMMA_CS_TFM_1D = 3, + GAMMA_CUSTOM = 4, }; struct dc_csc_transform { 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 c87f6e603055a..f5d8242eb0475 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 @@ -1213,8 +1213,11 @@ static bool dcn10_set_input_transfer_func(struct pipe_ctx *pipe_ctx, } else if (tf->type == TF_TYPE_BYPASS) { dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_BYPASS); } else { - /*TF_TYPE_DISTRIBUTED_POINTS*/ - result = false; + cm_helper_translate_curve_to_degamma_hw_format(tf, + &dpp_base->degamma_params); + dpp_base->funcs->dpp_program_degamma_pwl(dpp_base, + &dpp_base->degamma_params); + result = true; } return result; diff --git a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c index ee69c949bfbf2..bf29733958c37 100644 --- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c +++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c @@ -997,7 +997,9 @@ static void scale_user_regamma_ramp(struct pwl_float_data *pwl_rgb, * norm_y = 4095*regamma_y, and index is just truncating to nearest integer * lut1 = lut1D[index], lut2 = lut1D[index+1] * - *adjustedY is then linearly interpolating regamma Y between lut1 and lut2 + * adjustedY is then linearly interpolating regamma Y between lut1 and lut2 + * + * Custom degamma on Linux uses the same interpolation math, so is handled here */ static void apply_lut_1d( const struct dc_gamma *ramp, @@ -1018,7 +1020,7 @@ static void apply_lut_1d( struct fixed31_32 delta_lut; struct fixed31_32 delta_index; - if (ramp->type != GAMMA_CS_TFM_1D) + if (ramp->type != GAMMA_CS_TFM_1D && ramp->type != GAMMA_CUSTOM) return; // this is not expected for (i = 0; i < num_hw_points; i++) { @@ -1636,7 +1638,9 @@ bool mod_color_calculate_degamma_params(struct dc_transfer_func *input_tf, map_regamma_hw_to_x_user(ramp, coeff, rgb_user, coordinates_x, axix_x, curve, MAX_HW_POINTS, tf_pts, - mapUserRamp); + mapUserRamp && ramp->type != GAMMA_CUSTOM); + if (ramp->type == GAMMA_CUSTOM) + apply_lut_1d(ramp, MAX_HW_POINTS, tf_pts); ret = true; -- GitLab From 5ae6fe572929587a304471bf4a641361a45152b5 Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com> Date: Mon, 23 Jul 2018 14:13:23 -0400 Subject: [PATCH 1489/1506] drm/amd/display: Use calculated disp_clk_khz value for dce110 [Why] The calculated values for actual disp_clk_khz were ignored when notifying pplib of the new display requirements. In order to honor DFS bypass clocks from the hardware, the calculated value should be used. [How] The return value for set_dispclk is now assigned back into new_clocks and correctly carried through into dccg->clks.phyclk_khz. When notifying pplib of new display requirements dccg->clks.phyclk_khz is used instead of dce.dispclk_khz. The value of dce.dispclk_khz was never explicitly set to anything before. A 15% higher display clock value than calculated is no longer requested for dce110 since it now makes use of the calculated value. Since dce112 makes use of dce110's set_bandwidth but not its update_clocks it needs to have the value correctly carried through. Signed-off-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com> Reviewed-by: Harry Wentland <Harry.Wentland@amd.com> Reviewed-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Acked-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c | 4 ++-- drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c index 0db8d1da3d0ec..f17677971d0f2 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c @@ -463,7 +463,7 @@ static void dce12_update_clocks(struct dccg *dccg, if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, dccg->clks.dispclk_khz)) { clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DISPLAY_CLK; clock_voltage_req.clocks_in_khz = new_clocks->dispclk_khz; - dccg->funcs->set_dispclk(dccg, new_clocks->dispclk_khz); + new_clocks->dispclk_khz = dccg->funcs->set_dispclk(dccg, new_clocks->dispclk_khz); dccg->clks.dispclk_khz = new_clocks->dispclk_khz; dm_pp_apply_clock_for_voltage_request(dccg->ctx, &clock_voltage_req); @@ -661,7 +661,7 @@ static void dce_update_clocks(struct dccg *dccg, } if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, dccg->clks.dispclk_khz)) { - dccg->funcs->set_dispclk(dccg, new_clocks->dispclk_khz); + new_clocks->dispclk_khz = dccg->funcs->set_dispclk(dccg, new_clocks->dispclk_khz); dccg->clks.dispclk_khz = new_clocks->dispclk_khz; } } 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 1149c413f6d23..1d98e3678b04c 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 @@ -2530,7 +2530,7 @@ static void pplib_apply_display_requirements( /* TODO: dce11.2*/ pp_display_cfg->avail_mclk_switch_time_in_disp_active_us = 0; - pp_display_cfg->disp_clk_khz = context->bw.dce.dispclk_khz; + pp_display_cfg->disp_clk_khz = dc->res_pool->dccg->clks.dispclk_khz; dce110_fill_display_configs(context, pp_display_cfg); @@ -2559,7 +2559,7 @@ void dce110_set_bandwidth( { struct dc_clocks req_clks; - req_clks.dispclk_khz = context->bw.dce.dispclk_khz * 115 / 100; + req_clks.dispclk_khz = context->bw.dce.dispclk_khz; req_clks.phyclk_khz = get_max_pixel_clock_for_all_paths(dc, context); if (decrease_allowed) -- GitLab From 9315e2399a2cdc236e8d42c1a21fb1071cdad03d Mon Sep 17 00:00:00 2001 From: Hersen Wu <hersenxs.wu@amd.com> Date: Mon, 16 Jul 2018 11:21:12 -0400 Subject: [PATCH 1490/1506] drm/amd/display: Fix DP HBR2 Eye Diagram Pattern on Carrizo [why] dp hbr2 eye diagram pattern for raven asic is not stabled. workaround is to use tp4 pattern. But this should not be applied to asic before raven. [how] add new bool varilable in asic caps. for raven asic, use the workaround. for carrizo, vega, do not use workaround. Signed-off-by: Hersen Wu <hersenxs.wu@amd.com> Reviewed-by: Harry Wentland <Harry.Wentland@amd.com> Acked-by: Leo Li <sunpeng.li@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c | 8 +++----- drivers/gpu/drm/amd/display/dc/dc.h | 1 + drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c | 2 ++ 3 files changed, 6 insertions(+), 5 deletions(-) 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 58ee9aad13fb6..160841da72a75 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 @@ -1784,12 +1784,10 @@ static void dp_test_send_link_training(struct dc_link *link) dp_retrain_link_dp_test(link, &link_settings, false); } -/* TODO hbr2 compliance eye output is unstable +/* TODO Raven hbr2 compliance eye output is unstable * (toggling on and off) with debugger break * This caueses intermittent PHY automation failure * Need to look into the root cause */ -static uint8_t force_tps4_for_cp2520 = 1; - static void dp_test_send_phy_test_pattern(struct dc_link *link) { union phy_test_pattern dpcd_test_pattern; @@ -1849,13 +1847,13 @@ static void dp_test_send_phy_test_pattern(struct dc_link *link) break; case PHY_TEST_PATTERN_CP2520_1: /* CP2520 pattern is unstable, temporarily use TPS4 instead */ - test_pattern = (force_tps4_for_cp2520 == 1) ? + test_pattern = (link->dc->caps.force_dp_tps4_for_cp2520 == 1) ? DP_TEST_PATTERN_TRAINING_PATTERN4 : DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE; break; case PHY_TEST_PATTERN_CP2520_2: /* CP2520 pattern is unstable, temporarily use TPS4 instead */ - test_pattern = (force_tps4_for_cp2520 == 1) ? + test_pattern = (link->dc->caps.force_dp_tps4_for_cp2520 == 1) ? DP_TEST_PATTERN_TRAINING_PATTERN4 : DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE; break; diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index c2d390fba0bf0..55bcc3bdc6a3b 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -77,6 +77,7 @@ struct dc_caps { bool is_apu; bool dual_link_dvi; bool post_blend_color_processing; + bool force_dp_tps4_for_cp2520; }; struct dc_dcc_surface_param { diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c index 5d169f07d745f..6b44ed3697a4f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c @@ -1127,6 +1127,8 @@ static bool construct( dc->caps.max_slave_planes = 1; dc->caps.is_apu = true; dc->caps.post_blend_color_processing = false; + /* Raven DP PHY HBR2 eye diagram pattern is not stable. Use TP4 */ + dc->caps.force_dp_tps4_for_cp2520 = true; if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV) dc->debug = debug_defaults_drv; -- GitLab From 3e27e10e2ecee0d3a0083f8ae76354ac9c6ad15c Mon Sep 17 00:00:00 2001 From: Mikita Lipski <mikita.lipski@amd.com> Date: Thu, 12 Jul 2018 16:44:05 -0400 Subject: [PATCH 1491/1506] drm/amd/display: Don't share clk source between DP and HDMI [why] Prevent clock source sharing between HDMI and DP connectors. DP shouldn't be sharing its ref clock with phy clock, which caused an issue of older ASICS booting up with multiple diplays plugged in. [how] Add an extra check that would prevent HDMI and DP sharing clk. Signed-off-by: Mikita Lipski <mikita.lipski@amd.com> Reviewed-by: Hersen Wu <hersenxs.wu@amd.com> Acked-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> Cc: stable@vger.kernel.org --- .../gpu/drm/amd/display/dc/core/dc_resource.c | 22 ++++++++++++++++++- drivers/gpu/drm/amd/display/dc/dc.h | 1 + .../amd/display/dc/dce100/dce100_resource.c | 2 +- .../drm/amd/display/dc/dce80/dce80_resource.c | 3 +++ 4 files changed, 26 insertions(+), 2 deletions(-) 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 2e65715f76a1c..4ca41d6e3bcf2 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -330,6 +330,9 @@ bool resource_are_streams_timing_synchronizable( != stream2->timing.pix_clk_khz) return false; + if (stream1->clamping.c_depth != stream2->clamping.c_depth) + return false; + if (stream1->phy_pix_clk != stream2->phy_pix_clk && (!dc_is_dp_signal(stream1->signal) || !dc_is_dp_signal(stream2->signal))) @@ -337,6 +340,20 @@ bool resource_are_streams_timing_synchronizable( return true; } +static bool is_dp_and_hdmi_sharable( + struct dc_stream_state *stream1, + struct dc_stream_state *stream2) +{ + if (stream1->ctx->dc->caps.disable_dp_clk_share) + return false; + + if (stream1->clamping.c_depth != COLOR_DEPTH_888 || + stream2->clamping.c_depth != COLOR_DEPTH_888) + return false; + + return true; + +} static bool is_sharable_clk_src( const struct pipe_ctx *pipe_with_clk_src, @@ -348,7 +365,10 @@ static bool is_sharable_clk_src( if (pipe_with_clk_src->stream->signal == SIGNAL_TYPE_VIRTUAL) return false; - if (dc_is_dp_signal(pipe_with_clk_src->stream->signal)) + if (dc_is_dp_signal(pipe_with_clk_src->stream->signal) || + (dc_is_dp_signal(pipe->stream->signal) && + !is_dp_and_hdmi_sharable(pipe_with_clk_src->stream, + pipe->stream))) return false; if (dc_is_hdmi_signal(pipe_with_clk_src->stream->signal) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 55bcc3bdc6a3b..3ecd2d614f416 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -78,6 +78,7 @@ struct dc_caps { bool dual_link_dvi; bool post_blend_color_processing; bool force_dp_tps4_for_cp2520; + bool disable_dp_clk_share; }; struct dc_dcc_surface_param { diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c index fd2bdae4dcec7..3f76e6019546f 100644 --- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c @@ -919,7 +919,7 @@ static bool construct( dc->caps.i2c_speed_in_khz = 40; dc->caps.max_cursor_size = 128; dc->caps.dual_link_dvi = true; - + dc->caps.disable_dp_clk_share = true; for (i = 0; i < pool->base.pipe_count; i++) { pool->base.timing_generators[i] = dce100_timing_generator_create( diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c index dc9f3e9afc338..604c62969ead7 100644 --- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c @@ -946,6 +946,7 @@ static bool dce80_construct( } dc->caps.max_planes = pool->base.pipe_count; + dc->caps.disable_dp_clk_share = true; if (!resource_construct(num_virtual_links, dc, &pool->base, &res_create_funcs)) @@ -1131,6 +1132,7 @@ static bool dce81_construct( } dc->caps.max_planes = pool->base.pipe_count; + dc->caps.disable_dp_clk_share = true; if (!resource_construct(num_virtual_links, dc, &pool->base, &res_create_funcs)) @@ -1312,6 +1314,7 @@ static bool dce83_construct( } dc->caps.max_planes = pool->base.pipe_count; + dc->caps.disable_dp_clk_share = true; if (!resource_construct(num_virtual_links, dc, &pool->base, &res_create_funcs)) -- GitLab From ad830e7ab1847f4a014c04496b2581a7497b204f Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Date: Wed, 18 Jul 2018 15:25:34 -0400 Subject: [PATCH 1492/1506] drm/amd/display: add vbios table check for enabling dp ss Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Reviewed-by: Eric Bernstein <Eric.Bernstein@amd.com> Acked-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 1 + drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c | 5 ++++- drivers/gpu/drm/amd/display/dc/dc_link.h | 1 + drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h | 2 ++ 4 files changed, 8 insertions(+), 1 deletion(-) 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 9a6448e2089c5..016587675da4c 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -1038,6 +1038,7 @@ static bool construct( link->link_index = init_params->link_index; link->link_id = bios->funcs->get_connector_id(bios, init_params->connector_index); + link->dp_ss_off = !!dc_ctx->dc_bios->integrated_info->dp_ss_control;; if (link->link_id.type != OBJECT_TYPE_CONNECTOR) { dm_error("%s: Invalid Connector ObjectID from Adapter Service for connector index:%d! type %d expected %d\n", 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 160841da72a75..a7553b6d59c28 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 @@ -953,7 +953,10 @@ enum link_training_result dc_link_dp_perform_link_training( * LINK_SPREAD_05_DOWNSPREAD_30KHZ : * LINK_SPREAD_DISABLED; */ - lt_settings.link_settings.link_spread = LINK_SPREAD_05_DOWNSPREAD_30KHZ; + if (link->dp_ss_off) + lt_settings.link_settings.link_spread = LINK_SPREAD_DISABLED; + else + lt_settings.link_settings.link_spread = LINK_SPREAD_05_DOWNSPREAD_30KHZ; /* 1. set link rate, lane count and spread*/ dpcd_set_link_settings(link, <_settings); diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h index 22f4ddd219d1d..d43cefbc43d3b 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_link.h +++ b/drivers/gpu/drm/amd/display/dc/dc_link.h @@ -73,6 +73,7 @@ struct dc_link { enum dc_irq_source irq_source_hpd; enum dc_irq_source irq_source_hpd_rx;/* aka DP Short Pulse */ bool is_hpd_filter_disabled; + bool dp_ss_off; /* caps is the same as reported_link_cap. link_traing use * reported_link_cap. Will clean up. TODO diff --git a/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h b/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h index 36bbad5942674..f312834fef505 100644 --- a/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h +++ b/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h @@ -395,6 +395,8 @@ struct integrated_info { struct i2c_reg_info dp3_ext_hdmi_reg_settings[9]; unsigned char dp3_ext_hdmi_6g_reg_num; struct i2c_reg_info dp3_ext_hdmi_6g_reg_settings[3]; + /* V11 */ + uint32_t dp_ss_control; }; /** -- GitLab From fb7b11e1633e50b9a6b3fffe5cd151474aee9802 Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com> Date: Mon, 30 Jul 2018 12:27:23 -0400 Subject: [PATCH 1493/1506] drm/amd/display: Add NULL check for enabling dp ss [Why] The pointer for integrated_info can be NULL which causes the system to do a null pointer deference and hang on boot. [How] Add a check to ensure that integrated_info is not null before enabling DP ss. Signed-off-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com> Reviewed-by: Sun peng Li <Sunpeng.Li@amd.com> Acked-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 016587675da4c..a38e7ad36a7e9 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -1038,7 +1038,9 @@ static bool construct( link->link_index = init_params->link_index; link->link_id = bios->funcs->get_connector_id(bios, init_params->connector_index); - link->dp_ss_off = !!dc_ctx->dc_bios->integrated_info->dp_ss_control;; + + if (dc_ctx->dc_bios->integrated_info) + link->dp_ss_off = !!dc_ctx->dc_bios->integrated_info->dp_ss_control; if (link->link_id.type != OBJECT_TYPE_CONNECTOR) { dm_error("%s: Invalid Connector ObjectID from Adapter Service for connector index:%d! type %d expected %d\n", -- GitLab From 99326ee3624b90d176a8f7e2aa3d15dfaa59c8f1 Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Date: Thu, 26 Jul 2018 12:17:58 -0400 Subject: [PATCH 1494/1506] drm/amd/display: program display clock on cache match [Why] We seem to have an issue where high enough display clock will not get set properly during S3 resume if we only call vbios once [How] Expand condition of display clock programming to happen even when cached display clock matches requested display clock Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Acked-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c | 4 +++- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c index f17677971d0f2..684da3db75686 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c @@ -625,7 +625,9 @@ static void dcn1_update_clocks(struct dccg *dccg, } /* dcn1 dppclk is tied to dispclk */ - if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, dccg->clks.dispclk_khz)) { + /* program dispclk on = as a w/a for sleep resume clock ramping issues */ + if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, dccg->clks.dispclk_khz) + || new_clocks->dispclk_khz == dccg->clks.dispclk_khz) { dcn1_ramp_up_dispclk_with_dpp(dccg, new_clocks); dccg->clks.dispclk_khz = new_clocks->dispclk_khz; 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 f5d8242eb0475..cfcc54f2ce653 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 @@ -1089,6 +1089,8 @@ static void dcn10_init_hw(struct dc *dc) } enable_power_gating_plane(dc->hwseq, true); + + memset(&dc->res_pool->dccg->clks, 0, sizeof(dc->res_pool->dccg->clks)); } static void reset_hw_ctx_wrap( -- GitLab From 81aca8e75c1b046865fb2badef95a0dcff6f73de Mon Sep 17 00:00:00 2001 From: Mikita Lipski <mikita.lipski@amd.com> Date: Fri, 13 Jul 2018 09:07:35 -0400 Subject: [PATCH 1495/1506] drm/amd/display: update clk for various HDMI color depths [why] When programming tonga's connector's backend we didn't take in account that HDMI's colour depth might be more than 8bpc therefore we need to add a switch statement that would adjust the pixel clock accordingly. [how] Add a switch statement updating clock by its appropriate coefficient. Signed-off-by: Mikita Lipski <mikita.lipski@amd.com> Reviewed-by: Charlene Liu <Charlene.Liu@amd.com> Acked-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> Cc: stable@vger.kernel.org --- .../drm/amd/display/dc/bios/command_table.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table.c b/drivers/gpu/drm/amd/display/dc/bios/command_table.c index 651e1fd4622f9..a558bfaa0c468 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table.c +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table.c @@ -808,6 +808,24 @@ static enum bp_result transmitter_control_v1_5( * (=1: 8bpp, =1.25: 10bpp, =1.5:12bpp, =2: 16bpp) * LVDS mode: usPixelClock = pixel clock */ + if (cntl->signal == SIGNAL_TYPE_HDMI_TYPE_A) { + switch (cntl->color_depth) { + case COLOR_DEPTH_101010: + params.usSymClock = + cpu_to_le16((le16_to_cpu(params.usSymClock) * 30) / 24); + break; + case COLOR_DEPTH_121212: + params.usSymClock = + cpu_to_le16((le16_to_cpu(params.usSymClock) * 36) / 24); + break; + case COLOR_DEPTH_161616: + params.usSymClock = + cpu_to_le16((le16_to_cpu(params.usSymClock) * 48) / 24); + break; + default: + break; + } + } if (EXEC_BIOS_CMD_TABLE(UNIPHYTransmitterControl, params)) result = BP_RESULT_OK; -- GitLab From 1e1dbd6fd10031bf46d9e44b6ad423e2ee39e2a7 Mon Sep 17 00:00:00 2001 From: Hersen Wu <hersenxs.wu@amd.com> Date: Fri, 27 Jul 2018 14:52:37 -0400 Subject: [PATCH 1496/1506] drm/amd/display: display connected to dp-1 does not light up [why] for vega, dp set_panel_mode is handled by psp firmware. dal should not program the register again. [how] dal does not program panel mode. Signed-off-by: Hersen Wu <hersenxs.wu@amd.com> Reviewed-by: Charlene Liu <Charlene.Liu@amd.com> Acked-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/display/dc/dc.h | 1 + drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c | 5 +++++ drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c | 1 + 3 files changed, 7 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 3ecd2d614f416..e2f033d420a05 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -79,6 +79,7 @@ struct dc_caps { bool post_blend_color_processing; bool force_dp_tps4_for_cp2520; bool disable_dp_clk_share; + bool psp_setup_panel_mode; }; struct dc_dcc_surface_param { diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c index 60e3c6a73d370..752b3d62e793d 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c @@ -256,6 +256,11 @@ static void setup_panel_mode( enum dp_panel_mode panel_mode) { uint32_t value; + struct dc_context *ctx = enc110->base.ctx; + + /* if psp set panel mode, dal should be program it */ + if (ctx->dc->caps.psp_setup_panel_mode) + return; ASSERT(REG(DP_DPHY_INTERNAL_CTRL)); value = REG_READ(DP_DPHY_INTERNAL_CTRL); diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c index 61d8e22d23c95..d43f37d99c7d9 100644 --- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c @@ -883,6 +883,7 @@ static bool construct( dc->caps.i2c_speed_in_khz = 100; dc->caps.max_cursor_size = 128; dc->caps.dual_link_dvi = true; + dc->caps.psp_setup_panel_mode = true; dc->debug = debug_defaults; -- GitLab From 4823e5da2ea9061011242db81334d6ebbd2ed0a5 Mon Sep 17 00:00:00 2001 From: Lucas Stach <l.stach@pengutronix.de> Date: Mon, 6 Aug 2018 15:12:48 +0200 Subject: [PATCH 1497/1506] drm/scheduler: fix timeout worker setup for out of order job completions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drm_sched_job_finish() is a work item scheduled for each finished job on a unbound system workqueue. This means the workers can execute out of order with regard to the real hardware job completions. If this happens queueing a timeout worker for the first job on the ring mirror list is wrong, as this may be a job which has already finished executing. Fix this by reorganizing the code to always queue the worker for the next job on the list, if this job hasn't finished yet. This is robust against a potential reordering of the finish workers. Also move out the timeout worker cancelling, so that we don't need to take the job list lock twice. As a small optimization list_del is used to remove the job from the ring mirror list, as there is no need to reinit the list head in the job we are about to free. Signed-off-by: Lucas Stach <l.stach@pengutronix.de> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/scheduler/gpu_scheduler.c | 30 +++++++++++++---------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/scheduler/gpu_scheduler.c b/drivers/gpu/drm/scheduler/gpu_scheduler.c index 1b733229201ed..a70c7f7fd6fec 100644 --- a/drivers/gpu/drm/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/scheduler/gpu_scheduler.c @@ -552,24 +552,28 @@ static void drm_sched_job_finish(struct work_struct *work) finish_work); struct drm_gpu_scheduler *sched = s_job->sched; - /* remove job from ring_mirror_list */ - spin_lock(&sched->job_list_lock); - list_del_init(&s_job->node); - if (sched->timeout != MAX_SCHEDULE_TIMEOUT) { - struct drm_sched_job *next; - - spin_unlock(&sched->job_list_lock); - cancel_delayed_work_sync(&s_job->work_tdr); - spin_lock(&sched->job_list_lock); + /* + * Canceling the timeout without removing our job from the ring mirror + * list is safe, as we will only end up in this worker if our jobs + * finished fence has been signaled. So even if some another worker + * manages to find this job as the next job in the list, the fence + * signaled check below will prevent the timeout to be restarted. + */ + cancel_delayed_work_sync(&s_job->work_tdr); - /* queue TDR for next job */ - next = list_first_entry_or_null(&sched->ring_mirror_list, - struct drm_sched_job, node); + spin_lock(&sched->job_list_lock); + /* queue TDR for next job */ + if (sched->timeout != MAX_SCHEDULE_TIMEOUT && + !list_is_last(&s_job->node, &sched->ring_mirror_list)) { + struct drm_sched_job *next = list_next_entry(s_job, node); - if (next) + if (!dma_fence_is_signaled(&next->s_fence->finished)) schedule_delayed_work(&next->work_tdr, sched->timeout); } + /* remove job from ring_mirror_list */ + list_del(&s_job->node); spin_unlock(&sched->job_list_lock); + dma_fence_put(&s_job->s_fence->finished); sched->ops->free_job(s_job); } -- GitLab From 30bd8b862f5466fe5aee9a9fcdaea5a4fad83f91 Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Thu, 2 Aug 2018 10:25:19 +0100 Subject: [PATCH 1498/1506] drm/i2c: tda998x: convert to bridge driver Convert tda998x to a bridge driver with built-in encoder support for compatibility with existing component drivers. Tested-by: Peter Rosin <peda@axentia.se> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/i2c/tda998x_drv.c | 156 ++++++++++++++++-------------- 1 file changed, 81 insertions(+), 75 deletions(-) diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index c35b52a830011..999810d8e3d08 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -69,6 +69,7 @@ struct tda998x_priv { bool edid_delay_active; struct drm_encoder encoder; + struct drm_bridge bridge; struct drm_connector connector; struct tda998x_audio_port audio_port[2]; @@ -79,9 +80,10 @@ struct tda998x_priv { #define conn_to_tda998x_priv(x) \ container_of(x, struct tda998x_priv, connector) - #define enc_to_tda998x_priv(x) \ container_of(x, struct tda998x_priv, encoder) +#define bridge_to_tda998x_priv(x) \ + container_of(x, struct tda998x_priv, bridge) /* The TDA9988 series of devices use a paged register scheme.. to simplify * things we encode the page # in upper bits of the register #. To read/ @@ -1271,7 +1273,7 @@ tda998x_connector_best_encoder(struct drm_connector *connector) { struct tda998x_priv *priv = conn_to_tda998x_priv(connector); - return &priv->encoder; + return priv->bridge.encoder; } static @@ -1301,15 +1303,32 @@ static int tda998x_connector_init(struct tda998x_priv *priv, if (ret) return ret; - drm_mode_connector_attach_encoder(&priv->connector, &priv->encoder); + drm_mode_connector_attach_encoder(&priv->connector, + priv->bridge.encoder); return 0; } -/* DRM encoder functions */ +/* DRM bridge functions */ + +static int tda998x_bridge_attach(struct drm_bridge *bridge) +{ + struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge); + + return tda998x_connector_init(priv, bridge->dev); +} + +static void tda998x_bridge_detach(struct drm_bridge *bridge) +{ + struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge); + + drm_connector_cleanup(&priv->connector); +} -static void tda998x_enable(struct tda998x_priv *priv) +static void tda998x_bridge_enable(struct drm_bridge *bridge) { + struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge); + if (!priv->is_on) { /* enable video ports, audio will be enabled later */ reg_write(priv, REG_ENA_VP_0, 0xff); @@ -1324,8 +1343,10 @@ static void tda998x_enable(struct tda998x_priv *priv) } } -static void tda998x_disable(struct tda998x_priv *priv) +static void tda998x_bridge_disable(struct drm_bridge *bridge) { + struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge); + if (priv->is_on) { /* disable video ports */ reg_write(priv, REG_ENA_VP_0, 0x00); @@ -1336,29 +1357,11 @@ static void tda998x_disable(struct tda998x_priv *priv) } } -static void tda998x_encoder_dpms(struct drm_encoder *encoder, int mode) -{ - struct tda998x_priv *priv = enc_to_tda998x_priv(encoder); - bool on; - - /* we only care about on or off: */ - on = mode == DRM_MODE_DPMS_ON; - - if (on == priv->is_on) - return; - - if (on) - tda998x_enable(priv); - else - tda998x_disable(priv); -} - -static void -tda998x_encoder_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +static void tda998x_bridge_mode_set(struct drm_bridge *bridge, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) { - struct tda998x_priv *priv = enc_to_tda998x_priv(encoder); + struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge); u16 ref_pix, ref_line, n_pix, n_line; u16 hs_pix_s, hs_pix_e; u16 vs1_pix_s, vs1_pix_e, vs1_line_s, vs1_line_e; @@ -1565,8 +1568,18 @@ tda998x_encoder_mode_set(struct drm_encoder *encoder, mutex_unlock(&priv->audio_mutex); } +static const struct drm_bridge_funcs tda998x_bridge_funcs = { + .attach = tda998x_bridge_attach, + .detach = tda998x_bridge_detach, + .disable = tda998x_bridge_disable, + .mode_set = tda998x_bridge_mode_set, + .enable = tda998x_bridge_enable, +}; + static void tda998x_destroy(struct tda998x_priv *priv) { + drm_bridge_remove(&priv->bridge); + /* disable all IRQs and free the IRQ handler */ cec_write(priv, REG_CEC_RXSHPDINTENA, 0); reg_clear(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD); @@ -1659,6 +1672,7 @@ static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv) mutex_init(&priv->mutex); /* protect the page access */ mutex_init(&priv->audio_mutex); /* protect access from audio thread */ mutex_init(&priv->edid_mutex); + INIT_LIST_HEAD(&priv->bridge.list); init_waitqueue_head(&priv->edid_delay_waitq); timer_setup(&priv->edid_delay_timer, tda998x_edid_delay_done, 0); INIT_WORK(&priv->detect_work, tda998x_detect_work); @@ -1819,43 +1833,25 @@ static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv) tda998x_set_config(priv, client->dev.platform_data); } + priv->bridge.funcs = &tda998x_bridge_funcs; +#ifdef CONFIG_OF + priv->bridge.of_node = dev->of_node; +#endif + + drm_bridge_add(&priv->bridge); + return 0; fail: - /* if encoder_init fails, the encoder slave is never registered, - * so cleanup here: - */ - i2c_unregister_device(priv->cec); - if (priv->cec_notify) - cec_notifier_put(priv->cec_notify); - if (client->irq) - free_irq(client->irq, priv); + tda998x_destroy(priv); err_irq: return ret; } -static void tda998x_encoder_prepare(struct drm_encoder *encoder) -{ - tda998x_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); -} - -static void tda998x_encoder_commit(struct drm_encoder *encoder) -{ - tda998x_encoder_dpms(encoder, DRM_MODE_DPMS_ON); -} - -static const struct drm_encoder_helper_funcs tda998x_encoder_helper_funcs = { - .dpms = tda998x_encoder_dpms, - .prepare = tda998x_encoder_prepare, - .commit = tda998x_encoder_commit, - .mode_set = tda998x_encoder_mode_set, -}; +/* DRM encoder functions */ static void tda998x_encoder_destroy(struct drm_encoder *encoder) { - struct tda998x_priv *priv = enc_to_tda998x_priv(encoder); - - tda998x_destroy(priv); drm_encoder_cleanup(encoder); } @@ -1863,20 +1859,12 @@ static const struct drm_encoder_funcs tda998x_encoder_funcs = { .destroy = tda998x_encoder_destroy, }; -static int tda998x_bind(struct device *dev, struct device *master, void *data) +static int tda998x_encoder_init(struct device *dev, struct drm_device *drm) { - struct i2c_client *client = to_i2c_client(dev); - struct drm_device *drm = data; - struct tda998x_priv *priv; + struct tda998x_priv *priv = dev_get_drvdata(dev); u32 crtcs = 0; int ret; - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - dev_set_drvdata(dev, priv); - if (dev->of_node) crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); @@ -1888,35 +1876,53 @@ static int tda998x_bind(struct device *dev, struct device *master, void *data) priv->encoder.possible_crtcs = crtcs; - ret = tda998x_create(client, priv); - if (ret) - return ret; - - drm_encoder_helper_add(&priv->encoder, &tda998x_encoder_helper_funcs); ret = drm_encoder_init(drm, &priv->encoder, &tda998x_encoder_funcs, DRM_MODE_ENCODER_TMDS, NULL); if (ret) goto err_encoder; - ret = tda998x_connector_init(priv, drm); + ret = drm_bridge_attach(&priv->encoder, &priv->bridge, NULL); if (ret) - goto err_connector; + goto err_bridge; return 0; -err_connector: +err_bridge: drm_encoder_cleanup(&priv->encoder); err_encoder: - tda998x_destroy(priv); return ret; } +static int tda998x_bind(struct device *dev, struct device *master, void *data) +{ + struct i2c_client *client = to_i2c_client(dev); + struct drm_device *drm = data; + struct tda998x_priv *priv; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + dev_set_drvdata(dev, priv); + + ret = tda998x_create(client, priv); + if (ret) + return ret; + + ret = tda998x_encoder_init(dev, drm); + if (ret) { + tda998x_destroy(priv); + return ret; + } + return 0; +} + static void tda998x_unbind(struct device *dev, struct device *master, void *data) { struct tda998x_priv *priv = dev_get_drvdata(dev); - drm_connector_cleanup(&priv->connector); drm_encoder_cleanup(&priv->encoder); tda998x_destroy(priv); } -- GitLab From 2143adb04b357e192a9717a42554b1fd65c60fd2 Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Thu, 2 Aug 2018 10:25:19 +0100 Subject: [PATCH 1499/1506] drm/i2c: tda998x: allocate tda998x_priv inside tda998x_create() Move the tda998x_priv allocation inside tda998x_create() and simplify the tda998x_create()'s arguments. Pass the same to tda998x_destroy(). Tested-by: Peter Rosin <peda@axentia.se> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/i2c/tda998x_drv.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index 999810d8e3d08..74c2e5e59922b 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -1576,8 +1576,10 @@ static const struct drm_bridge_funcs tda998x_bridge_funcs = { .enable = tda998x_bridge_enable, }; -static void tda998x_destroy(struct tda998x_priv *priv) +static void tda998x_destroy(struct device *dev) { + struct tda998x_priv *priv = dev_get_drvdata(dev); + drm_bridge_remove(&priv->bridge); /* disable all IRQs and free the IRQ handler */ @@ -1662,13 +1664,21 @@ static void tda998x_set_config(struct tda998x_priv *priv, priv->audio_params = p->audio_params; } -static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv) +static int tda998x_create(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct device_node *np = client->dev.of_node; struct i2c_board_info cec_info; + struct tda998x_priv *priv; u32 video; int rev_lo, rev_hi, ret; + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + dev_set_drvdata(dev, priv); + mutex_init(&priv->mutex); /* protect the page access */ mutex_init(&priv->audio_mutex); /* protect access from audio thread */ mutex_init(&priv->edid_mutex); @@ -1843,7 +1853,7 @@ static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv) return 0; fail: - tda998x_destroy(priv); + tda998x_destroy(dev); err_irq: return ret; } @@ -1895,24 +1905,16 @@ static int tda998x_encoder_init(struct device *dev, struct drm_device *drm) static int tda998x_bind(struct device *dev, struct device *master, void *data) { - struct i2c_client *client = to_i2c_client(dev); struct drm_device *drm = data; - struct tda998x_priv *priv; int ret; - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - dev_set_drvdata(dev, priv); - - ret = tda998x_create(client, priv); + ret = tda998x_create(dev); if (ret) return ret; ret = tda998x_encoder_init(dev, drm); if (ret) { - tda998x_destroy(priv); + tda998x_destroy(dev); return ret; } return 0; @@ -1924,7 +1926,7 @@ static void tda998x_unbind(struct device *dev, struct device *master, struct tda998x_priv *priv = dev_get_drvdata(dev); drm_encoder_cleanup(&priv->encoder); - tda998x_destroy(priv); + tda998x_destroy(dev); } static const struct component_ops tda998x_ops = { -- GitLab From 76767fdabadbea7dec2cdd741c0177e4fab3c75a Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Thu, 2 Aug 2018 10:25:19 +0100 Subject: [PATCH 1500/1506] drm/i2c: tda998x: cleanup from previous changes Cleanup the code a little from the effects of the previous changes: - Move tda998x_destroy() to be above tda998x_create() - Use 'dev' directly in tda998x_create() where appropriate. Tested-by: Peter Rosin <peda@axentia.se> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/i2c/tda998x_drv.c | 76 +++++++++++++++---------------- 1 file changed, 37 insertions(+), 39 deletions(-) diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index 74c2e5e59922b..f486d85ac5759 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -1576,31 +1576,6 @@ static const struct drm_bridge_funcs tda998x_bridge_funcs = { .enable = tda998x_bridge_enable, }; -static void tda998x_destroy(struct device *dev) -{ - struct tda998x_priv *priv = dev_get_drvdata(dev); - - drm_bridge_remove(&priv->bridge); - - /* disable all IRQs and free the IRQ handler */ - cec_write(priv, REG_CEC_RXSHPDINTENA, 0); - reg_clear(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD); - - if (priv->audio_pdev) - platform_device_unregister(priv->audio_pdev); - - if (priv->hdmi->irq) - free_irq(priv->hdmi->irq, priv); - - del_timer_sync(&priv->edid_delay_timer); - cancel_work_sync(&priv->detect_work); - - i2c_unregister_device(priv->cec); - - if (priv->cec_notify) - cec_notifier_put(priv->cec_notify); -} - /* I2C driver functions */ static int tda998x_get_audio_ports(struct tda998x_priv *priv, @@ -1664,6 +1639,31 @@ static void tda998x_set_config(struct tda998x_priv *priv, priv->audio_params = p->audio_params; } +static void tda998x_destroy(struct device *dev) +{ + struct tda998x_priv *priv = dev_get_drvdata(dev); + + drm_bridge_remove(&priv->bridge); + + /* disable all IRQs and free the IRQ handler */ + cec_write(priv, REG_CEC_RXSHPDINTENA, 0); + reg_clear(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD); + + if (priv->audio_pdev) + platform_device_unregister(priv->audio_pdev); + + if (priv->hdmi->irq) + free_irq(priv->hdmi->irq, priv); + + del_timer_sync(&priv->edid_delay_timer); + cancel_work_sync(&priv->detect_work); + + i2c_unregister_device(priv->cec); + + if (priv->cec_notify) + cec_notifier_put(priv->cec_notify); +} + static int tda998x_create(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); @@ -1705,13 +1705,13 @@ static int tda998x_create(struct device *dev) /* read version: */ rev_lo = reg_read(priv, REG_VERSION_LSB); if (rev_lo < 0) { - dev_err(&client->dev, "failed to read version: %d\n", rev_lo); + dev_err(dev, "failed to read version: %d\n", rev_lo); return rev_lo; } rev_hi = reg_read(priv, REG_VERSION_MSB); if (rev_hi < 0) { - dev_err(&client->dev, "failed to read version: %d\n", rev_hi); + dev_err(dev, "failed to read version: %d\n", rev_hi); return rev_hi; } @@ -1722,20 +1722,19 @@ static int tda998x_create(struct device *dev) switch (priv->rev) { case TDA9989N2: - dev_info(&client->dev, "found TDA9989 n2"); + dev_info(dev, "found TDA9989 n2"); break; case TDA19989: - dev_info(&client->dev, "found TDA19989"); + dev_info(dev, "found TDA19989"); break; case TDA19989N2: - dev_info(&client->dev, "found TDA19989 n2"); + dev_info(dev, "found TDA19989 n2"); break; case TDA19988: - dev_info(&client->dev, "found TDA19988"); + dev_info(dev, "found TDA19988"); break; default: - dev_err(&client->dev, "found unsupported device: %04x\n", - priv->rev); + dev_err(dev, "found unsupported device: %04x\n", priv->rev); return -ENXIO; } @@ -1778,8 +1777,7 @@ static int tda998x_create(struct device *dev) tda998x_irq_thread, irq_flags, "tda998x", priv); if (ret) { - dev_err(&client->dev, - "failed to request IRQ#%u: %d\n", + dev_err(dev, "failed to request IRQ#%u: %d\n", client->irq, ret); goto err_irq; } @@ -1788,13 +1786,13 @@ static int tda998x_create(struct device *dev) cec_write(priv, REG_CEC_RXSHPDINTENA, CEC_RXSHPDLEV_HPD); } - priv->cec_notify = cec_notifier_get(&client->dev); + priv->cec_notify = cec_notifier_get(dev); if (!priv->cec_notify) { ret = -ENOMEM; goto fail; } - priv->cec_glue.parent = &client->dev; + priv->cec_glue.parent = dev; priv->cec_glue.data = priv; priv->cec_glue.init = tda998x_cec_hook_init; priv->cec_glue.exit = tda998x_cec_hook_exit; @@ -1839,8 +1837,8 @@ static int tda998x_create(struct device *dev) if (priv->audio_port[0].format != AFMT_UNUSED) tda998x_audio_codec_init(priv, &client->dev); - } else if (client->dev.platform_data) { - tda998x_set_config(priv, client->dev.platform_data); + } else if (dev->platform_data) { + tda998x_set_config(priv, dev->platform_data); } priv->bridge.funcs = &tda998x_bridge_funcs; -- GitLab From 5a03f5346fedc8b5f1a8601aa46a0930ba56a7ae Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Thu, 2 Aug 2018 10:25:19 +0100 Subject: [PATCH 1501/1506] drm/i2c: tda998x: register bridge outside of component helper Register the bridge outside of the component helper as we have drivers that wish to use the tda998x without its encoder. Tested-by: Peter Rosin <peda@axentia.se> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/i2c/tda998x_drv.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index f486d85ac5759..a7a4307f7fcb4 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -1904,18 +1904,8 @@ static int tda998x_encoder_init(struct device *dev, struct drm_device *drm) static int tda998x_bind(struct device *dev, struct device *master, void *data) { struct drm_device *drm = data; - int ret; - - ret = tda998x_create(dev); - if (ret) - return ret; - ret = tda998x_encoder_init(dev, drm); - if (ret) { - tda998x_destroy(dev); - return ret; - } - return 0; + return tda998x_encoder_init(dev, drm); } static void tda998x_unbind(struct device *dev, struct device *master, @@ -1924,7 +1914,6 @@ static void tda998x_unbind(struct device *dev, struct device *master, struct tda998x_priv *priv = dev_get_drvdata(dev); drm_encoder_cleanup(&priv->encoder); - tda998x_destroy(dev); } static const struct component_ops tda998x_ops = { @@ -1935,16 +1924,27 @@ static const struct component_ops tda998x_ops = { static int tda998x_probe(struct i2c_client *client, const struct i2c_device_id *id) { + int ret; + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { dev_warn(&client->dev, "adapter does not support I2C\n"); return -EIO; } - return component_add(&client->dev, &tda998x_ops); + + ret = tda998x_create(&client->dev); + if (ret) + return ret; + + ret = component_add(&client->dev, &tda998x_ops); + if (ret) + tda998x_destroy(&client->dev); + return ret; } static int tda998x_remove(struct i2c_client *client) { component_del(&client->dev, &tda998x_ops); + tda998x_destroy(&client->dev); return 0; } -- GitLab From b073a70ecd37bc6e7c25a47315cd8d65e7b313fd Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Thu, 2 Aug 2018 10:27:15 +0100 Subject: [PATCH 1502/1506] drm/i2c: tda998x: move mode_valid() to bridge Move the mode_valid() implementation to the bridge instead of the connector, as we're checking the bridge's capabilities. Tested-by: Peter Rosin <peda@axentia.se> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/i2c/tda998x_drv.c | 32 +++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index a7a4307f7fcb4..6308e8ec25dfb 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -1253,21 +1253,6 @@ static int tda998x_connector_get_modes(struct drm_connector *connector) return n; } -static enum drm_mode_status tda998x_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) -{ - /* TDA19988 dotclock can go up to 165MHz */ - struct tda998x_priv *priv = conn_to_tda998x_priv(connector); - - if (mode->clock > ((priv->rev == TDA19988) ? 165000 : 150000)) - return MODE_CLOCK_HIGH; - if (mode->htotal >= BIT(13)) - return MODE_BAD_HVALUE; - if (mode->vtotal >= BIT(11)) - return MODE_BAD_VVALUE; - return MODE_OK; -} - static struct drm_encoder * tda998x_connector_best_encoder(struct drm_connector *connector) { @@ -1279,7 +1264,6 @@ tda998x_connector_best_encoder(struct drm_connector *connector) static const struct drm_connector_helper_funcs tda998x_connector_helper_funcs = { .get_modes = tda998x_connector_get_modes, - .mode_valid = tda998x_connector_mode_valid, .best_encoder = tda998x_connector_best_encoder, }; @@ -1325,6 +1309,21 @@ static void tda998x_bridge_detach(struct drm_bridge *bridge) drm_connector_cleanup(&priv->connector); } +static enum drm_mode_status tda998x_bridge_mode_valid(struct drm_bridge *bridge, + const struct drm_display_mode *mode) +{ + /* TDA19988 dotclock can go up to 165MHz */ + struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge); + + if (mode->clock > ((priv->rev == TDA19988) ? 165000 : 150000)) + return MODE_CLOCK_HIGH; + if (mode->htotal >= BIT(13)) + return MODE_BAD_HVALUE; + if (mode->vtotal >= BIT(11)) + return MODE_BAD_VVALUE; + return MODE_OK; +} + static void tda998x_bridge_enable(struct drm_bridge *bridge) { struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge); @@ -1571,6 +1570,7 @@ static void tda998x_bridge_mode_set(struct drm_bridge *bridge, static const struct drm_bridge_funcs tda998x_bridge_funcs = { .attach = tda998x_bridge_attach, .detach = tda998x_bridge_detach, + .mode_valid = tda998x_bridge_mode_valid, .disable = tda998x_bridge_disable, .mode_set = tda998x_bridge_mode_set, .enable = tda998x_bridge_enable, -- GitLab From a3d335f5de7cdd714737a9f8bdcc7b205b0f8d5e Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Thu, 2 Aug 2018 10:27:15 +0100 Subject: [PATCH 1503/1506] drm/i2c: tda998x: get rid of private fill_modes function We can achieve the same effect via the get_modes() method, rather than wrapping the fill_modes helper. Tested-by: Peter Rosin <peda@axentia.se> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/i2c/tda998x_drv.c | 30 ++++++------------------------ 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index 6308e8ec25dfb..7313ff835f351 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -1106,29 +1106,6 @@ static int tda998x_audio_codec_init(struct tda998x_priv *priv, /* DRM connector functions */ -static int tda998x_connector_fill_modes(struct drm_connector *connector, - uint32_t maxX, uint32_t maxY) -{ - struct tda998x_priv *priv = conn_to_tda998x_priv(connector); - int ret; - - mutex_lock(&priv->audio_mutex); - ret = drm_helper_probe_single_connector_modes(connector, maxX, maxY); - - if (connector->edid_blob_ptr) { - struct edid *edid = (void *)connector->edid_blob_ptr->data; - - cec_notifier_set_phys_addr_from_edid(priv->cec_notify, edid); - - priv->sink_has_audio = drm_detect_monitor_audio(edid); - } else { - priv->sink_has_audio = false; - } - mutex_unlock(&priv->audio_mutex); - - return ret; -} - static enum drm_connector_status tda998x_connector_detect(struct drm_connector *connector, bool force) { @@ -1147,7 +1124,7 @@ static void tda998x_connector_destroy(struct drm_connector *connector) static const struct drm_connector_funcs tda998x_connector_funcs = { .dpms = drm_helper_connector_dpms, .reset = drm_atomic_helper_connector_reset, - .fill_modes = tda998x_connector_fill_modes, + .fill_modes = drm_helper_probe_single_connector_modes, .detect = tda998x_connector_detect, .destroy = tda998x_connector_destroy, .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, @@ -1246,7 +1223,12 @@ static int tda998x_connector_get_modes(struct drm_connector *connector) } drm_mode_connector_update_edid_property(connector, edid); + cec_notifier_set_phys_addr_from_edid(priv->cec_notify, edid); + + mutex_lock(&priv->audio_mutex); n = drm_add_edid_modes(connector, edid); + priv->sink_has_audio = drm_detect_monitor_audio(edid); + mutex_unlock(&priv->audio_mutex); kfree(edid); -- GitLab From 926a299c42e38bbe8bb909eae0146e676b66afe4 Mon Sep 17 00:00:00 2001 From: Russell King <rmk+kernel@armlinux.org.uk> Date: Thu, 2 Aug 2018 10:27:15 +0100 Subject: [PATCH 1504/1506] drm/i2c: tda998x: correct PLL divider calculation The serializer PLL divider is a power-of-two divider, so our calculation which assumes that it's a numerical divider is incorrect. Replace it with one that results in a power-of-two divider value instead. Tested with all supported modes with a Samsung S24C750. Tested-by: Peter Rosin <peda@axentia.se> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> --- drivers/gpu/drm/i2c/tda998x_drv.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index 7313ff835f351..0df86e9281913 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -1343,6 +1343,7 @@ static void tda998x_bridge_mode_set(struct drm_bridge *bridge, struct drm_display_mode *adjusted_mode) { struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge); + unsigned long tmds_clock; u16 ref_pix, ref_line, n_pix, n_line; u16 hs_pix_s, hs_pix_e; u16 vs1_pix_s, vs1_pix_e, vs1_line_s, vs1_line_e; @@ -1413,12 +1414,19 @@ static void tda998x_bridge_mode_set(struct drm_bridge *bridge, (mode->vsync_end - mode->vsync_start)/2; } - div = 148500 / mode->clock; - if (div != 0) { - div--; - if (div > 3) - div = 3; - } + tmds_clock = mode->clock; + + /* + * The divisor is power-of-2. The TDA9983B datasheet gives + * this as ranges of Msample/s, which is 10x the TMDS clock: + * 0 - 800 to 1500 Msample/s + * 1 - 400 to 800 Msample/s + * 2 - 200 to 400 Msample/s + * 3 - as 2 above + */ + for (div = 0; div < 3; div++) + if (80000 >> div <= tmds_clock) + break; mutex_lock(&priv->audio_mutex); -- GitLab From 275e6fa8ecfd8ec1eb36a865d6dafc64f4bed462 Mon Sep 17 00:00:00 2001 From: Nayan Deshmukh <nayan26deshmukh@gmail.com> Date: Thu, 9 Aug 2018 15:18:12 +0530 Subject: [PATCH 1505/1506] drm/scheduler: fix param documentation We no longer have sched parameter so remove its description as well Signed-off-by: Nayan Deshmukh <nayan26deshmukh@gmail.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/scheduler/gpu_scheduler.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/gpu/drm/scheduler/gpu_scheduler.c b/drivers/gpu/drm/scheduler/gpu_scheduler.c index a70c7f7fd6fec..4fc211e19d6e5 100644 --- a/drivers/gpu/drm/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/scheduler/gpu_scheduler.c @@ -249,7 +249,6 @@ static void drm_sched_entity_kill_jobs_cb(struct dma_fence *f, /** * drm_sched_entity_flush - Flush a context entity * - * @sched: scheduler instance * @entity: scheduler entity * @timeout: time to wait in for Q to become empty in jiffies. * @@ -292,7 +291,6 @@ EXPORT_SYMBOL(drm_sched_entity_flush); /** * drm_sched_entity_cleanup - Destroy a context entity * - * @sched: scheduler instance * @entity: scheduler entity * * This should be called after @drm_sched_entity_do_release. It goes over the @@ -356,7 +354,6 @@ EXPORT_SYMBOL(drm_sched_entity_fini); /** * drm_sched_entity_fini - Destroy a context entity * - * @sched: scheduler instance * @entity: scheduler entity * * Calls drm_sched_entity_do_release() and drm_sched_entity_cleanup() @@ -719,7 +716,6 @@ EXPORT_SYMBOL(drm_sched_job_recovery); * drm_sched_job_init - init a scheduler job * * @job: scheduler job to init - * @sched: scheduler instance * @entity: scheduler entity to use * @owner: job owner for debugging * -- GitLab From b045d3af7d1f443dd5209a096568e0ce983127e9 Mon Sep 17 00:00:00 2001 From: Emily Deng <Emily.Deng@amd.com> Date: Thu, 9 Aug 2018 10:03:04 +0800 Subject: [PATCH 1506/1506] drm/amdgpu/sriov: give 8s for recover vram under RUNTIME Extend the timeout for recovering vram bos from shadows on sr-iov to cover the worst case scenario for timeslices and VFs Under runtime, the wait fence time could be quite long when other VFs are in exclusive mode. For example, for 4 VF, every VF's exclusive timeout time is set to 3s, then the worst case is 9s. If the VF number is more than 4,then the worst case time will be longer. The 8s is the test data, with setting to 8s, it will pass the TDR test for 1000 times. SWDEV-161490 Signed-off-by: Monk Liu <Monk.Liu@amd.com> Signed-off-by: Emily Deng <Emily.Deng@amd.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index ec53d8f96d063..3ef34df8937be 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -3105,7 +3105,7 @@ static int amdgpu_device_handle_vram_lost(struct amdgpu_device *adev) long tmo; if (amdgpu_sriov_runtime(adev)) - tmo = msecs_to_jiffies(amdgpu_lockup_timeout); + tmo = msecs_to_jiffies(8000); else tmo = msecs_to_jiffies(100); -- GitLab